Files
assist/README.md
T
jiantw83 311cdc611a feat(wiki): 巡檢目錄頁改成一台機器一個大標題區塊
巡檢目錄頁的版面從 markdown 表格換成「大標題加條列」:一台機器一個大標題
區塊,標題就是那一台機器監控頁的實際頁名,欄位改成標題底下的一層條列。
範本、技能敘述、行為清單與說明文件一併跟上,目錄頁上不再留任何表格。

表格的欄位組合是整頁共用的,表頭跟著建頁那一台機器走,之後每一台只改自己
那一列。欄位一增減,只有跑到新版的機器寫得出新的格數,同一張表就混著兩種
格數,多出來的那一格對不到任何欄名,而目錄頁又沒有整頁改寫的路可以走——
整頁覆蓋等於刪掉別台機器的紀錄。條列一筆一個區塊,欄位各自獨立,加一條只
動到自己那一個區塊。

比對鍵從裸雜湊那一格改成大標題本身,標題寫成監控頁的實際頁名。頁名只由
主機名與登入帳號決定,換主機位址、換專用存取庫或換一種頁名編碼都動不到
它;含網址的那一條連結照樣留著給人點,但不當鍵。呼叫改成拿頁名當鍵,欄號
那個參數只在舊表格頁轉檔時用得到。範本原本用二階標題寫的說明區段全部搬進
引言,否則轉檔後會被當成一筆真紀錄讀進去。

範圍是助理的巡檢目錄頁與 assistant 技能的敘述。
2026-09-02 17:21:12 +08:00

71 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# jsc-assist — 技能助理
jsc 技能組的 assist domain:技能與 hook 每跑一次就留下事件,助理負責把事件收攏、判斷健康狀態、寫進 wiki 的監控頁(`MONITOR_{HASH}`)。
助理只做三件事:**觸發**既有技能、**巡檢**既有的唯讀腳本與狀態檔、把結果**提醒**給前景會話。它不做決策、不改程式碼、不覆寫 wiki。完整界線見 `AGENTS.md` 的「助理的界線」。
## 安裝、更新、移除
Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安裝 token 為 `jsc-assist@jsc`。每個指令一行:
| CLI | 安裝 | 更新 | 移除 |
| --- | --- | --- | --- |
| claude | `claude plugin marketplace add https://gitea.jsc.idv.tw/plugins/meta.git && claude plugin install jsc-assist@jsc` | `claude plugin marketplace update jsc && claude plugin update jsc-assist@jsc` | `claude plugin uninstall jsc-assist@jsc` |
| codex | `codex plugin marketplace add https://gitea.jsc.idv.tw/plugins/meta.git && codex plugin add jsc-assist@jsc` | `codex plugin marketplace upgrade jsc` | `codex plugin remove jsc-assist@jsc` |
| copilot | `copilot plugin marketplace add https://gitea.jsc.idv.tw/plugins/meta.git && copilot plugin install jsc-assist@jsc` | `copilot plugin marketplace update jsc && copilot plugin update jsc-assist@jsc` | `copilot plugin uninstall jsc-assist@jsc` |
| antigravity | `git clone https://gitea.jsc.idv.tw/plugins/assist.git ~/plugins/assist && agy plugin install ~/plugins/assist` | `git -C ~/plugins/assist pull && agy plugin uninstall jsc-assist && agy plugin install ~/plugins/assist` | `agy plugin uninstall jsc-assist` |
| kiro | `kiro-cli plugin marketplace add https://gitea.jsc.idv.tw/plugins/meta.git && kiro-cli plugin install jsc-assist@jsc` | `kiro-cli plugin marketplace update jsc && kiro-cli plugin update jsc-assist@jsc` | `kiro-cli plugin uninstall jsc-assist@jsc` |
> antigravity 不支援 gitea URL 安裝,改用本地 clone 路徑。批次操作五個 CLI:使用 `/jsc-cli:deploy`。
## Skills 目錄
呼叫方式:Claude / Antigravity `/jsc-assist:{name}`;Codex `${name}`;Copilot / Kiro 描述需求自動觸發。
<!-- JSC-SKILLS:START -->
### `assistant`
助理主體,四個操作:`start` 啟動、`status` 查現況、`patrol` 跑一輪巡檢、`stop` 停止。心跳的寫入、判定與清除一律交給 `jsc-hooks` 的 `hooks/heartbeat.sh`,判定只有那一份;系統排程一律交給 `tools/schedule.sh`;一輪巡檢的流程交給 `tools/patrol.sh`。工具一律用 `$JSC_HOME/current/{外掛名}` 那一組不帶版本的路徑叫,不用技能提示給的快取基底目錄——權限只放行 current 那一組。**心跳由巡檢寫,而且只由巡檢寫**:一輪跑完、結果寫上監控頁了,才寫那一次心跳,所以心跳新鮮等於「上一輪巡檢真的做完了」。`start` 先跑一輪巡檢,再裝上巡檢那一筆排程;巡檢週期由心跳的過期門檻算出來,兩個數字綁在一起。`patrol` 讀五項來源(使用統計、版本與重啟閘門、SDLC 階段鎖與工作包鎖、心跳自述、執行狀態事件),各項各自獨立,一項掛掉其餘各項照跑、照記,結果寫上 `MONITOR_{HASH}`:那頁固定三塊,基本資料不動、最新一輪整塊換掉、摘要表保留近 24 輪,一輪一列。目錄頁 `MONITOR_CONTENTS` 在另一個存取庫(`JSC_WIKI_REPO_CONTENTS`),一台機器一個 H2 區塊,只更新自己那一個區塊,交給 `jsc-gitea/tools/wiki-contents.sh upsert` 寫,連結用絕對網址;那個存取庫沒設定時只少一筆索引,這一輪照樣算跑完、照樣寫心跳。`status` 全程唯讀,讀心跳、排程與待辦簿,印成三塊;助理沒在跑就印「助理未運行」,不當成錯誤。`stop` 先移除排程再清掉心跳,順序不能反。這支不參與閘門判定、不做決策、巡檢那一路全程不問人。
<!-- JSC-SKILLS:END -->
## 相依
| Plugin | 最低版本 | 用途 |
| --- | --- | --- |
| `jsc-cli` | `>=0.2.7` | CLI 偵測與委派 |
| `jsc-gitea` | `>=0.2.0` | 監控頁的所有 wiki 讀寫,一律經 `tools/gitea.sh`;目錄頁那一個區塊走 `tools/wiki-contents.sh upsert`,頁名雜湊走 `tools/hash-id`,兩頁要放進去的連結一律先過 `tools/link-check.sh` |
| `jsc-hooks` | `>=0.3.7` | 心跳、閘門與事件來源(`$JSC_HOME` 底下的狀態檔)。心跳的寫入、判定與清除一律走 `hooks/heartbeat.sh`,那支腳本是 `0.3.7` 才有的 |
| `jsc-log` | `>=0.1.4` | 使用統計與工作日誌的資料來源 |
## 參考與工具
| 檔案 | 用途 |
| --- | --- |
| `tools/schedule.sh` | 助理系統排程的安裝、移除與查現況。三個子命令 `install`、`remove`、`status`,只裝 `patrol` 這一筆——心跳由巡檢自己寫,`install heartbeat` 一律回 6,舊版遺留的心跳條目由 `install patrol` 順手清掉。巡檢週期由心跳的過期門檻算出來(`2 × 週期 × 60 < 門檻`,再取能整除一小時的分鐘數):門檻 300 秒是每 2 分鐘一輪,門檻 1800 秒是每 12 分鐘一輪。Linux、WSL 與 macOS 走 crontab,Windows 走 schtasks。條目行尾帶固定標記 `# jsc-assist:assistant {工作}`,只動自己那一筆,別人的排程一行都不碰。條目自己把環境帶齊:CLI 用 `command -v` 解成絕對路徑、安裝當下把 `GITEA_HOST`、`GITEA_TOKEN`、`JSC_HOME`、`JSC_ASSISTANT_HEARTBEAT_TTL` 與已設定的 `JSC_WIKI_REPO` 系列快照進條目、自帶 `JSC_GITEA_CONFIRM=yes`。`JSC_WIKI_REPO` 系列含內容頁的 `JSC_WIKI_REPO_MONITOR` 與目錄頁的 `JSC_WIKI_REPO_CONTENTS`:監控頁 `MONITOR_{HASH}` 與目錄頁 `MONITOR_CONTENTS` 分屬不同存取庫,兩支變數都要帶。名單是安裝當下從環境撈出所有已設定的,不寫死,所以新增的頁型變數自動涵蓋,這支不必跟著改——cron 的 PATH 很短、不讀設定檔、也沒有 tty。印出條目時金鑰一律遮掉,條目本身含金鑰快照,crontab 檔案要保持只有本人讀得到,變數改過要重跑一次 install。裝完會檢查排程服務在不在跑,沒跑就回 1——WSL 預設不啟動 cron;也會檢查 `$JSC_HOME/current` 那組連結在不在、印出這一輪要開的 allow 規則,連結不在只警告、不代建。`--dry-run` 只印組出來的條目與寫回後的內容,什麼都不動 |
| `tools/patrol.sh` | 一輪巡檢的收攏與收口。三個子命令:`collect` 取鎖、讀五項來源、組出監控頁的「最新一輪」與「近 24 輪摘要」兩塊、本輪的摘要列與目錄頁那一個區塊(區塊的 H2 標題是內容頁頁名 `MONITOR_{HASH}`,upsert 拿標題當鍵;「監控頁」那一條是連結,網址留佔位,等監控頁寫成之後由呼叫端用 `gitea.sh wiki-url` 的絕對網址換掉);`finish` 在監控頁寫成之後才寫心跳、換上用量快照、放掉鎖;`abort` 只放掉鎖,不寫心跳。各項來源各自獨立,一項失敗其餘各項照跑,失敗那一項在頁上寫明是「這一項失敗」而不是沒資料。執行狀態事件那一項由 `collect` 自己叫 `jsc-hooks/tools/report-status.sh` 排空再輪替,把非 ok 的事件與「有 start 沒有配對 end」的技能彙整成頁上那一節;`drain` 是消耗性讀取,所以只由這支跑,且它失敗一律不中止那一輪。整輪拿一把目錄鎖,上一輪還在跑就回 4 讓開;鎖逾時(門檻取心跳門檻)會被下一輪搶回來,並在頁上記一筆。`version-guard.sh report` 回「查詢失敗」時照原字抄,不補查、不美化 |
| `references/behaviors.md` | 本 domain 的技能行為清單:一支技能一節,五列記下觸發時機、關鍵步驟、外部呼叫、完成條件、可驗證跡象,供稽核與驗證比對。格式合約見 `plugins/meta` 的 `references/guidelines.md`「技能行為清單」 |
| `templates/monitor-contents.md` | 目錄頁 `MONITOR_CONTENTS` 的範本,這一頁落在 `JSC_WIKI_REPO_CONTENTS` 解出的專用存取庫,和監控頁不同庫。版面是 H1、`>` 引言,然後一台機器一個 H2 區塊,欄位在標題底下一行一條 `- {欄位名}:{值}`,頁上不放 markdown 表格。H2 標題就是內容頁頁名 `MONITOR_{HASH}`,雜湊來源是 `{主機名}/{登入帳號}`,主機名取短的那一段。寫入一律走 `jsc-gitea/tools/wiki-contents.sh upsert`,比對鍵是 H2 標題:**只更新自己那一個區塊**,別台機器的區塊原樣保留,禁止整頁覆蓋。「監控頁」那一條的連結一律寫成 `[{頁名}]({絕對網址})`,網址取 `gitea.sh wiki-url` 印的那一個,寫入前先過 `jsc-gitea/tools/link-check.sh`、結束碼 0 才寫;但那一條含主機位址與網址編碼,會變,所以不當鍵 |
| `templates/monitor-page.md` | 內容頁 `MONITOR_{HASH}` 的範本。記的是這台機器的巡檢軌跡。頁面固定三塊:本頁基本資料建頁時寫一次就不動、最新一輪每輪整塊換掉、近 24 輪摘要一輪一列且最新的在最上面。軌跡留在摘要表,完整內容只留最新一輪,頁面才讀得完 |
## 助理的狀態檔
全部放在 `$JSC_HOME/assistant/` 底下,一律純文字 key=value:
| 路徑 | 內容 |
| --- | --- |
| `heartbeat` | 心跳檔,欄位 `ts`、`pid`、`cli`、`session`。只由 `tools/patrol.sh finish` 寫,也就是一輪巡檢跑完、結果記下來之後才寫。判準只看 `ts`,不看 pid 存活——五支 CLI 與容器裡的行程互相看不到彼此的 pid |
| `tasks/{id}` | 待辦簿,一筆一檔。一筆一檔是為了讓並行寫入不互相覆寫 |
| `schedule.log` | 排程條目的輸出。刻意放在存取庫外面:寫進專案會多出未追蹤檔,污染別人的變更盤點 |
| `patrol.lock/` | 一輪巡檢的鎖,是目錄——`mkdir` 是原子操作,搶不到就是別人在跑。裡面的 `info` 記 `round`、`pid`、`started` |
| `patrol/` | 本輪巡檢的暫存檔:`latest.md` 是「最新一輪」那一塊,`summary.md` 是摘要那一塊、裡面已經放好本輪這一列,`summary-row.md` 只有那一列,`newpage.md` 是頁不存在時要建的整頁,`contents-entry.md` 是目錄頁那一個 H2 區塊 |
| `usage-prev.tsv` | 上一輪記下來的累計用量。有了它,下一輪的「本輪次數」才算得出來;沒有它的第一輪一律寫「-」,不拿累計冒充本輪 |
## 相關 domain
- [`jsc-hooks`](https://gitea.jsc.idv.tw/plugins/hooks):閘門與心跳,跟 hook 一起裝
- [`jsc-gitea`](https://gitea.jsc.idv.tw/plugins/gitea):wiki 讀寫的唯一入口
- [`jsc-log`](https://gitea.jsc.idv.tw/plugins/log):使用統計與工作日誌
- [`jsc-cli`](https://gitea.jsc.idv.tw/plugins/cli):環境健檢與跨 CLI 委派