fix(daemon-beta t3): 真機 e2e 抓到 /wiki-extract 拒非 vault 資料夾——新增 daemon 專用 /rag-extract-file 命令(template overlay,prompt 活在 skill 檔),claude 路改呼叫它

This commit is contained in:
2026-07-24 12:27:15 +08:00
parent 058d19b743
commit 18a873001b
3 changed files with 40 additions and 6 deletions
+4 -4
View File
@@ -1,7 +1,7 @@
// extract.go — 可插拔本地萃取器(daemon-beta task 3/4,四步定稿第 3 步)。
//
// leo 定稿:「由現在的 gemma4 幫你本地萃,或是用你自己的訂閱帳號,例如叫起 claude 幫你萃。」
// - claude 路(task 3):執行 `claude -p "/wiki-capture <檔>"`cwd=監看根——
// - claude 路(task 3):執行 `claude -p "/rag-extract-file <檔>"`cwd=監看根——
// template 既有萃取流**原樣重用**(prompt 都不搬),卡片由 CC 寫進 system-dev/wiki/cards/。
// 用戶自己的訂閱=我們零 API 成本。
// - gemma 路(task 4):Go 內直呼 Gemini API,卡片由 daemon 自己寫進 cards/。
@@ -54,7 +54,7 @@ func diffCards(before, after map[string]fileState) []string {
// claudeExtractTimeout:單檔萃取上限。CC 冷啟+讀檔+寫卡實測分鐘級,給足裕度。
const claudeExtractTimeout = 10 * time.Minute
// ExtractWithClaude 叫起用戶自己的 claude 跑 template 的 /wiki-capturetask 3)。
// ExtractWithClaude 叫起用戶自己的 claude 跑 template 的 /rag-extract-filetask 3)。
// binPath 空="claude"PATH 尋找)。回傳本次產出的卡片相對路徑。
func ExtractWithClaude(binPath, absRoot, relPath string) ([]string, error) {
if binPath == "" {
@@ -67,8 +67,8 @@ func ExtractWithClaude(binPath, absRoot, relPath string) ([]string, error) {
ctx, cancel := context.WithTimeout(context.Background(), claudeExtractTimeout)
defer cancel()
// /wiki-capturetemplate 既有萃取 skillcwd=監看根(template 已代裝,skill 就在 .claude/commands/)。
cmd := exec.CommandContext(ctx, binPath, "-p", fmt.Sprintf("/wiki-capture %s", relPath))
// /rag-extract-filetemplate 既有萃取 skillcwd=監看根(template 已代裝,skill 就在 .claude/commands/)。
cmd := exec.CommandContext(ctx, binPath, "-p", fmt.Sprintf("/rag-extract-file %s", relPath))
cmd.Dir = absRoot
out, err := cmd.CombinedOutput()
if ctx.Err() == context.DeadlineExceeded {
+2 -2
View File
@@ -22,7 +22,7 @@ func writeStubClaude(t *testing.T, dir string, script string) string {
return p
}
// 正常路:stub 收到 -p "/wiki-capture <檔>"、cwd=監看根,寫卡後被 diff 偵測到。
// 正常路:stub 收到 -p "/rag-extract-file <檔>"、cwd=監看根,寫卡後被 diff 偵測到。
func TestExtractWithClaudeHappyPath(t *testing.T) {
root := t.TempDir()
if err := os.MkdirAll(filepath.Join(root, "system-dev", "wiki", "cards"), 0o755); err != nil {
@@ -30,7 +30,7 @@ func TestExtractWithClaudeHappyPath(t *testing.T) {
}
stub := writeStubClaude(t, t.TempDir(), fmt.Sprintf(`
[ "$1" = "-p" ] || { echo "第一參數應為 -pgot $1" >&2; exit 9; }
case "$2" in "/wiki-capture 我的筆記.md") ;; *) echo "prompt 錯:$2" >&2; exit 9;; esac
case "$2" in "/rag-extract-file 我的筆記.md") ;; *) echo "prompt 錯:$2" >&2; exit 9;; esac
[ "$(pwd)" = "%s" ] || { echo "cwd 錯:$(pwd)" >&2; exit 9; }
mkdir -p system-dev/wiki/cards
printf '# 我的筆記\n\n## 摘要\nstub 卡\n' > "system-dev/wiki/cards/我的筆記.md"
@@ -0,0 +1,34 @@
# /rag-extract-file — 把單一原稿萃成知識卡(Arcrun RAG daemon 專用)
> 本命令由 Arcrun RAG daemon 的 template 代裝一併鋪入(daemon-beta task 3)。
> 與 `/wiki-extract` 的差別:**不要求 vault**(一般資料夾即可)、一次只萃**一個指定檔**、
> 由 daemon 以 `claude -p "/rag-extract-file <相對路徑>"` 呼叫。人也可以手動用。
## 任務
參數=原稿的相對路徑(相對於目前資料夾)。把它萃成**一張**定稿知識卡:
1. 讀取該原稿(**唯讀**——絕不修改、移動、刪除原稿)。
2. 寫卡到 `system-dev/wiki/cards/<頁名>.md`,頁名=檔名去副檔名。同名卡已存在=覆寫(原稿變了卡就該更新)。
3. **只寫這一個檔**。不碰 KBDB、不拉三元組、不動其他任何檔案——上傳/入庫是 daemon 的事,不是你的事。
## 卡片格式(段名一字不差,下游機械解析吃這個結構)
```markdown
# <頁名>
## 一句話定義
(一行)
## 要點
- 3-12 條,具體、含數字條件)
## 關鍵實體
- **實體名** — 一句說明
## 關聯
- 實體A >> 謂詞 >> 實體B(3-8 行,端點用上面「關鍵實體」的正規名)
```
## 鐵律
- 正體中文;技術名詞可留英文。
- 萃「知識點」成自包含原子卡,不地毯複製原文全文。
- 機敏值(密碼/API key/個資)**不得**寫入卡片;原稿含機敏值時該段落改寫成描述。
- 原稿讀不懂或是空檔=誠實說明並**不寫卡**(寧缺勿假)。