T3: collector 骨架——watch→轉檔→git commit/push(design §4)

Node 單檔服務(非 arcrun workflow,跑客戶端機器):chokidar watch 事件驅動、debounce
合併批次 commit、.md passthrough(非 md 格式誠實丟 NotImplemented 待 T4 Markitdown)、
刪檔→target repo 移除對應檔(deprecated 標記留給 ingest workflow,collector 只管檔案鏡像)。

已驗(雲端 sandbox scratch 環境,非真實客戶環境):node --check 全過;起 scratch watch dir
+ scratch git repo + bare remote,實測 add/change/delete 三種事件皆正確偵測、debounce 正確
合併成一次 commit、git push 真的送達 remote(git log 驗證)、非 md 格式正確跳過並警告。

端到端待本機/客戶環境驗(README.md 已列):真實 NAS/VM watch、真實 Gitea remote+憑證、
Gitea push webhook 真觸發 ingest、systemd 常駐穩定性。
This commit is contained in:
2026-07-07 21:08:21 +00:00
commit 4ca94c17ca
8 changed files with 483 additions and 0 deletions
+83
View File
@@ -0,0 +1,83 @@
# collector — 收集端骨架(rag-wave1 T3
> design.md §4;跑在**客戶端機器**(NAS/VM,或導入者代管的 VPS),不是 arcrun workflowarcrun 零件禁檔案系統,見 CLAUDE.md 紅線)。
> ⚠️ **本骨架端到端(真實 NAS/VM + 真實 Gitea remote + systemd 常駐)需在本機/客戶環境驗,雲端 sandbox 沒有這些條件**——這裡只做得到:程式邏輯本身可跑、對本機臨時目錄的煙測(見下方「已驗證」)。
## 做什麼
```
watch 知識資料夾 ──(新增/修改)──► transformMarkitdownT4 補)──► 寫入 target repo 工作目錄
──(刪除) ──► target repo 移除對應檔
git add/commit/push
Gitea push webhook(既有機制,非本骨架自建)
arcrun ingest workflow(另案,如 km_wiki_ingest_drain 同款模式)
```
**關鍵設計判斷**collector 的責任止於「commit + push」。design.md §4 說的「打 ingest webhook」= Gitea 自己的 push webhook 機制(同 `Leo/Arcrun` `registry/examples/km-wiki-ingest` 已驗證的模式:Gitea push webhook → arcrun workflow),**不是** collector 自己再打一支 HTTP webhook。collector 不需要知道 ingest 的內部細節(哪個 workflow、哪個 KBDB),它只管「客戶檔案的忠實鏡像」進 Gitea repo。
## 事件驅動、不輪詢
`chokidar`Nodewatch 檔案系統事件(inotify/FSEvents,非 polling),對齊「單一 repo、事件驅動」的鐵律。debounce 視窗(預設 3 秒)把同一批變更合併成一次 commit,避免每個檔案獨立 commit 洗歷史。
## 刪檔語意
檔案在來源資料夾被刪除 → collector 在 target repo 對應路徑也 `git rm` → commit → push。**deprecated 標記不是 collector 的責任**——ingest workflow 收到 Gitea push event 裡的 `removed` 檔案清單後,自己去 KBDB 把對應 entry 標 `status: deprecated`append-only,不物理刪,見 km-wiki-ingest description.md 冪等設計)。collector 只管檔案鏡像忠實,不碰 KBDB。
## 轉檔(T4,依賴本骨架)
`transform.js` 目前只處理 `.md`(直接複製,frontmatter 補 `source_path` 溯源欄位)。非 md 格式(docx/pptx/pdf)丟 `NotImplementedError` 並記警告日誌——**這是刻意的**T4Markitdown adapter)要接手這段,本骨架先把「watch→轉檔→寫入→commit」的骨架打通,轉檔本體留給 T4 填。
## 檔案
| 檔案 | 職責 |
|---|---|
| `index.js` | 進入點:watchdebounce+事件分派 |
| `transform.js` | 檔案 → md 轉換(T4 填 Markitdown 邏輯;現只認 `.md` passthrough |
| `git-sync.js` | target repo 的 git add/commit/push 封裝 |
| `config.js` | 環境變數讀取(`WATCH_DIR`/`TARGET_REPO_DIR`/`DEBOUNCE_MS` |
## 設定(環境變數)
| 變數 | 說明 | 預設 |
|---|---|---|
| `WATCH_DIR` | 客戶知識資料夾(來源) | 必填 |
| `TARGET_REPO_DIR` | 已 clone 好、有 push 權限的 Gitea repo 工作目錄(去向) | 必填 |
| `TARGET_SUBDIR` | 在 target repo 內落地的子目錄 | `collected/` |
| `DEBOUNCE_MS` | 合併變更的等待視窗 | `3000` |
| `GIT_AUTHOR_NAME` / `GIT_AUTHOR_EMAIL` | commit 署名 | `collector` / `collector@localhost` |
## 部署(客戶端機器,設計稿——本輪未實際跑 systemd)
```ini
# /etc/systemd/system/arcrun-rag-collector.service(範本,未部署未測)
[Unit]
Description=arcrun-rag collector
After=network.target
[Service]
Environment=WATCH_DIR=/mnt/knowledge
Environment=TARGET_REPO_DIR=/opt/collector-repo
ExecStart=/usr/bin/node /opt/arcrun-rag/collector/index.js
Restart=always
User=collector
[Install]
WantedBy=multi-user.target
```
`TARGET_REPO_DIR` 需事先 `git clone`+設好有 push 權限的 remotecredential 用該機器的 git credential helper 或 SSH key,不是本骨架管的事)。
## 已驗證(雲端 sandbox 能做到的部分)
- `node --check` 語法檢查全過。
- 本機臨時目錄煙測(非真實客戶環境):起一個 scratch git repo 當 target、一個 scratch 資料夾當 watch 來源,新增/修改/刪除 `.md` 檔案 → collector 正確偵測、寫入/移除、debounce 後產生一次 commit`git log` 驗到 commit 內容與變更一致。**不含**:真實 Gitea remote push(需真實 token+repo)、Markitdown 轉檔(T4 未做)、systemd 常駐、NAS/VM 環境。
## 待本機/客戶環境驗(端到端)
1. 真實客戶知識資料夾 watch(非 md 格式檔案觸發 T4 Markitdown)。
2. 真實 Gitea remote push(含憑證管理)。
3. push 後確認 Gitea push webhook 真觸發 ingest workflow(另案)。
4. systemd 常駐穩定性(重開機自動起、崩潰自動重啟)。