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

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

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

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

17 KiB
Raw Blame History

jsc-assist 技能行為清單

本頁記錄 jsc-assist 每支技能的行為基準,供技能驗證比對。技能異動時,在同一個 PR 內一起更新這一頁。

assistant

項目 內容
觸發時機 要啟動助理、要停止助理、要跑一輪巡檢,或要問助理現在還在不在跑、待辦簿剩下哪幾筆時用。四個操作 start、status、patrol、stop 都走這一支。排程每一輪叫起來的也是這一支的 patrol。執行環境健檢不走這支,走 jsc-cli:doctor。技能使用次數不走這支,走 jsc-log:stats
關鍵步驟 先認出使用者要的是哪一個操作,patrol 那一路全程不問人。start:先照 patrol 的每一步跑完一輪巡檢,第一次心跳由那一輪寫、不另外寫、跑不完就不算啟動、跑 heartbeat.sh report 確認 state=fresh、跑 tools/schedule.sh install patrol 裝巡檢那一筆排程、把它印的 allow_rule= 每一行、環境快照提醒與 current 連結缺漏的警告原樣轉給人、依結束碼選一段收尾訊息印出——排程接上、排程寫進去了但 cron 沒在跑、排程沒接上三種各一段。心跳那一筆不裝了,install heartbeat 一律回 6。patrol:跑 tools/patrol.sh collect 取鎖並讀五項來源(第五項是執行狀態事件:collect 自己叫 jsc-hooks/tools/report-status.sh drain 排空,緊接著跑 rotate,再把非 ok 的事件與「有 start 沒有配對 end」的技能彙整成監控頁那一節;技能本文一律不自己再跑一次 drain)、結束碼 4 就讓開不寫任何東西、結束碼 1 與 3 照樣把這一輪寫上監控頁、hash 是空的就 abort、經 jsc-gitea:wiki 讀回 MONITOR_{HASH} 舊頁、基本資料原樣留著、最新一輪那一塊整塊換成 latest_file、summary_file 的本輪那一列擺最上面(五欄:巡檢時間、本輪判定、各項成敗、待人處理、警示來源)、舊的資料列接在下面並截到 24 列、三塊重組成整頁、寫回之前先把這一頁要放進去的每一個連結交給 jsc-gitea/tools/link-check.sh(結束碼 0 才整頁寫回,結束碼 1 就把 DEAD 那幾筆原樣回報並 abort,2、3、7 同樣 abort,一個連結都沒有就跳過這一次驗證並照實說明)、頁不存在(唯有結束碼 4)才用 newpage_file 建頁、讀不回舊頁就不寫、監控頁寫成之後跑 gitea.sh wiki-url 取那一頁的絕對網址並依結束碼分流(4 回步驟三重寫、5 沒有 html_url、7 與 8 走 abort,其餘非 0 也走 abort,網址取不到就不寫那一個區塊)、換掉 contents_file 那個 H2 區塊裡 {監控頁絕對網址} 那個佔位、換完再用 link-check.sh 驗那一個網址(結束碼 0 才寫那一個區塊;非 0 一律不寫,比照目錄頁結束碼 3 當成那一個區塊沒更新、這一輪照樣往下寫心跳,並把連不到的那一筆列進待人處理)、用 jsc-gitea/tools/wiki-contents.sh upsert MONITOR 1 "MONITOR_{HASH}" {區塊檔} 以 H2 標題(也就是內容頁頁名,取 collect 印的 page=)當鍵更新 MONITOR_CONTENTS 自己那一個區塊並一律帶上 templates/monitor-contents.md 當範本(第三個參數 1 是 key-col,只在舊頁還是 markdown 表格時用得到:舊表格第 1 欄「監控頁」持有身分,那一格是 [MONITOR_{HASH}](網址),轉檔時只取文字當標題;頁面已經是條列格式時這個參數被忽略,照樣固定給 1)、目錄頁回 3(CONTENTS 存取庫沒設定)不中止這一輪,照樣往下寫心跳,並把「設 JSC_WIKI_REPO_CONTENTS 或 JSC_WIKI_REPO」列進待人處理、監控頁任一失敗或目錄頁其餘非 0 才 abort 且不寫心跳、跑 tools/patrol.sh finish 寫心跳、最後印出各項結果、本輪事件數與非 ok 事件數、非 ok 事件的明細(kind、name、status、exit、detail)、以及有 start 沒有配對 end 的那幾支技能(單獨列,那代表那一輪中止了)、兩次寫入各自的連結驗證結果(通過、無連結而跳過、或被擋下並附結束碼與 DEAD 明細)、判成警示時的警示來源與待人處理列。status:跑 heartbeat.sh report 取心跳現況、把 state 對映成新鮮、過期、心跳檔損壞、不存在、不自己解析心跳檔也不自己判定、從 file= 解出助理目錄後列出 tasks/ 底下每一個檔案並解析 state、title、next_run、fail_count、跑 tools/schedule.sh status 取排程現況與週期、印成心跳、排程、待辦三塊、fail_count 大於 0 的列標上「已連續失敗 N 次」、心跳與排程兜起來會誤讀的四種組合各補一句話。stop:先跑 heartbeat.sh report 留下原本的狀態、再跑 tools/schedule.sh remove all 移除排程與舊版遺留的心跳條目、最後才跑 heartbeat.sh clear 清掉心跳、印出停止訊息並說明心跳清掉之後閘門會擋人、同時說明閘門還沒接線所以現在擋不到人。四個操作最後都一樣:回報印完之後跑一次 jsc-hooks/tools/report-status.sh skill-end jsc-assist:assistant {status} {結束碼},start 由 hook 記、end 由這裡寫,不寫就等於這一次自己看起來中止了
外部呼叫 工具一律走 $JSC_HOME/current/{外掛名} 那一組不帶版本的路徑:current/jsc-assist/tools/patrol.sh、current/jsc-assist/tools/schedule.sh、current/jsc-hooks/hooks/heartbeat.sh,wiki 那一支是 current/jsc-gitea/tools/gitea.sh,連結驗證那一支是 current/jsc-gitea/tools/link-check.sh,執行狀態事件那一支是 current/jsc-hooks/tools/report-status.sh,$JSC_HOME 沒設就退回 ~/.jsc;不拿技能提示給的快取基底目錄組工具路徑——權限只放行 current 那一組,用錯路徑會被靜靜擋掉。jsc-hooks/hooks/heartbeat.sh 的 write、report、clear 三個子命令,六個結束碼各有處置:0 往下走、1 與 3 印「助理未運行」、2 回報判不出狀態並停下、4 當成不新鮮並回報心跳檔損壞、5 是嚴重狀況要吵出來且不得回報成功、6 是呼叫寫錯要更正後重跑。write 只由 tools/patrol.sh finish 呼叫,技能自己不呼叫。本 domain 的 tools/schedule.sh 的 install、remove、status 三個子命令:install 會查 $JSC_HOME/current/jsc-assist 與 $JSC_HOME/current/jsc-gitea 兩個連結在不在、不在就警告且不代建,會把巡檢的 CLI 用 command -v 解成絕對路徑、把 GITEA_HOST、GITEA_TOKEN、JSC_HOME、JSC_ASSISTANT_HEARTBEAT_TTL 與所有已設定的 JSC_WIKI_REPO 系列快照進條目(含內容頁的 JSC_WIKI_REPO_MONITOR 與目錄頁的 JSC_WIKI_REPO_CONTENTS,名單當下從環境撈、不寫死,新頁型自動涵蓋)、條目自帶 JSC_GITEA_CONFIRM=yes、並印出這一輪要開的 allow_rule= 規則(七支腳本各三種呼叫形式,含 gitea.sh、wiki-contents.sh、link-check.sh 與 jsc-hooks/tools/report-status.sh——Skill(jsc-gitea:wiki) 只放行叫用技能,技能內部的 Bash 呼叫仍各自受檢;路徑是 current 那一組確切路徑,不用萬用字元);七個結束碼各有處置:0 往下走、1 是條目裝了但 cron 沒在跑要照實講不會執行、2 是缺 jsc-hooks 導致門檻讀不到、3 是這台機器沒有排程機制、4 是排程操作失敗要原樣引用 stderr、5 是回讀驗證失敗要叫人自己去看 crontab -l、6 是呼叫寫錯,含 install heartbeat、週期塞不進門檻、判不出 CLI,以及那一支 CLI 的執行檔不在 PATH 上。本 domain 的 tools/patrol.sh 的 collect、finish、abort 三個子命令,七個結束碼各有處置:0 往下走、1 部分失敗照樣寫頁、2 是 finish 找不到 heartbeat.sh 要回報「記下來了但沒有心跳」、3 是各項全失敗照樣寫頁且判定異常、4 是讓開或鎖被搶走一律不寫心跳、5 是檔案系統失敗要吵出來、6 是呼叫寫錯。巡檢那五項讀 jsc-log/tools/usage-stats.sh、jsc-hooks/hooks/version-guard.sh report、jsc-hooks/hooks/restart-gate.sh report、$JSC_HOME/sessions/*.stage、$JSC_HOME/wp/*.pr、heartbeat.sh report、jsc-hooks/tools/report-status.sh drain 與 rotate,除了排空會把事件流的位移往前推之外全部只讀,任一項失敗不影響其餘各項。report-status.sh 三個結束碼各有處置:0 是排空到新事件、3 是沒有新事件(正常狀態,不是失敗)、2 是呼叫寫錯;找不到這一支、drain 回 0 與 3 以外的碼、或 rotate 回非 0,都只讓這一項標成失敗或記一筆警示,一律不中止那一輪——回報鏈自己壞掉不可以把被回報的那一輪拖下去。rotate 只在 drain 成功時緊接著跑:中間隔越久,那段時間新寫進來的事件被搬進備份檔而從此排不到的機會越大;排空失敗時位移狀態未知,這時候輪替會直接吃掉還沒排空的那一批。配對以 session 加 name 為鍵,不只看 name:五支 CLI 併發時同一支技能會有好幾個工作階段同時在跑。沒配對到的 start 留在 $JSC_HOME/assistant/events-open.tsv 跨輪繼續配對,開超過心跳門檻才算疑似中止,未達門檻的算還在跑,超過一天沒配對到就丟掉。wiki 讀寫一律經 jsc-gitea:wiki,技能自己不拼 API 呼叫;只有目錄頁那一個 H2 區塊例外,走 jsc-gitea/tools/wiki-contents.sh upsert,它自己解 CONTENTS 存取庫、自己讀回整頁比對標題,舊頁還是 markdown 表格時自己先整頁轉成 H2 區塊再寫,七個結束碼各有處置:0 已更新或已新增、1 組不出頁面內容或寫入失敗要 abort(找不到同名標題不算錯,那是附加)、2 參數錯就改正重跑(範本路徑不存在也回這一碼,代表 plugin 沒裝齊)、3 是 CONTENTS 存取庫未設定且不中止這一輪、4 是頁不存在又沒給範本,本技能一律帶第五個參數所以不會出現、7 金鑰失效要 abort、8 其他 API 失敗要 abort。比對鍵取 H2 標題,也就是內容頁頁名 MONITOR_{HASH},不取「監控頁」那一條的連結:連結含 GITEA_HOST 與頁名的網址編碼,那三樣一變鍵就對不上,同一台機器每輪多附一個區塊;頁名只由 {主機名}/{登入帳號} 決定,那三樣都動不到它。連結一律寫成 [{文字}]({絕對網址}),網址只取 gitea.sh wiki-url 印的那一個、不自己組路徑,那一支的結束碼 4、5、7、8 與其餘非 0 各有處置;每一個要放進頁面的連結在寫入前先過 jsc-gitea/tools/link-check.sh,它每個網址印一行 `{OK
完成條件 start 要那一輪巡檢的 finish 回 0 且 report 回 state=fresh,才算啟動成功;巡檢沒寫成心跳一律回報失敗並停下,不得宣稱啟動;schedule.sh install patrol 回 1 要講明條目不會被執行與 sudo service cron start,不得宣稱排程會定時執行;回 0 或 1 都要把 allow_rule= 各行、「條目含金鑰快照、變數改了要重裝」這句提醒,以及 current 連結缺漏的警告轉出去。patrol 要五項各自有 status、執行狀態事件那一項要印出本輪事件數、非 ok 事件數與未配對的 start(drain 回 3 是沒有新事件,照樣算這一項讀到底)、監控頁那一頁要放的連結全部通過 link-check.sh(或整頁本來就沒有連結)、監控頁三塊重組寫成、目錄頁那一個 H2 區塊的網址通過 link-check.sh 後更新成功,或以目錄頁結束碼 3、或以連結驗證非 0 回報成沒更新、finish 回 0,才算一輪跑完;collect 回 4 是讓開,不算失敗也不寫任何東西;舊頁讀不回來就不寫,回報「這一輪沒有結果」;連結驗證沒過就不寫那一頁,監控頁沒寫成就 abort,心跳一定不寫;目錄頁除了結束碼 3 之外的非 0 也一樣 abort,結束碼 3 只少一筆索引,那一輪的結果已經在監控頁上,照樣寫心跳並把缺的變數列進待人處理;目錄頁那一個區塊的連結驗不過同樣只少一筆索引,照樣寫心跳並把那一筆列進待人處理。status 要印出現況表,或印出「助理未運行」並說明原因;心跳不存在、待辦簿目錄不存在、待辦簿零筆、排程沒裝,四種都算正常結束。stop 要 schedule.sh remove all 先回 0、clear 再回 0,並印出帶三段話的停止訊息;remove 非 0 就回報排程還在、助理停不掉,不清心跳也不印停止訊息;clear 回 5 就回報心跳檔還在、助理沒有確實停掉,不印停止訊息。四個操作都要在回報之後寫一筆 skill-end,status 取 ok、blocked、failed、degraded、aborted 五選一,要與回報出去的結果一致;那一支回非 0 只回報成回報鏈的缺陷,不改寫這一次操作的成敗
可驗證跡象 start 之後 $JSC_HOME/assistant/heartbeat 存在,ts 是剛才那一輪的時間,crontab -l 找得到一筆帶 # jsc-assist:assistant patrol 的條目,而且只有一筆,帶 # jsc-assist:assistant heartbeat 的舊條目一筆都不剩;那一筆條目裡的 CLI 是絕對路徑,前面帶著 JSC_GITEA_CONFIRM=yes 與環境變數快照;install 印出的 allow_rule= 都是 $JSC_HOME/current 那一組確切路徑,沒有萬用字元,也沒有 Write(...),而且 jsc-gitea/tools/link-check.sh 與 jsc-hooks/tools/report-status.sh 那三種呼叫形式都在裡面。patrol 跑完之後 wiki 的 MONITOR_{HASH} 只有三塊:基本資料一字未改、最新一輪換成本輪、摘要表最上面一列是本輪且總列數不超過 24,頁名的 {HASH} 是 40 碼大寫十六進位,雜湊來源那一列寫的是不含網域的短主機名;CONTENTS 存取庫裡的 MONITOR_CONTENTS 只有自己那一個 H2 區塊變動,同一台機器從頭到尾只有一個區塊,標題是 MONITOR_ 接 40 碼大寫十六進位、標題上不帶連結也不帶網址,區塊裡「監控頁」那一條是 [{頁名}]({絕對網址}) 這種連結、點下去開得起那一頁,「HASH」那一條是裸 HASH、40 碼大寫十六進位、不帶連結,八條欄位一條都不缺、格式是 - {欄位名}:{值},頁上一個 markdown 表格都不剩,兩頁上點得到的連結沒有一個是死的——把頁上的網址抓出來重跑一次 link-check.sh,應該全部是 OK、結束碼 0,別台機器的區塊一字不動,$JSC_HOME/assistant/patrol/ 底下有本輪的 latest.md、summary.md、summary-row.md、newpage.md、contents-entry.md,摘要列是五欄、警示來源那一欄有值或寫「無」;兩支腳本不是從 $JSC_HOME/current 跑起來時,stderr 會有一行 [WARN] 點出實際路徑與應該用的路徑,$JSC_HOME/assistant/usage-prev.tsv 換成本輪的累計數,$JSC_HOME/assistant/patrol.lock 已經放掉;監控頁的最新一輪有「執行狀態事件」那一節,節裡有本輪事件數、非 ok 事件數,以及非 ok 明細與未配對 start 兩張表(一筆都沒有時寫明「沒有」,不留空表格);$JSC_HOME/usage/scan-state/events.offset 的數字往前推到本輪排空的位置,$JSC_HOME/assistant/events-open.tsv 只剩下還沒配對到 end 的那幾筆。讓開的那一輪沒有任何寫入跡象。stop 之後心跳路徑不存在,crontab -l 找不到任何 # jsc-assist:assistant 條目。以上都不動別人的排程條目,條目數量前後相同。status 無寫入跡象,只有回報內容。四個操作跑完,$JSC_HOME/usage/events.jsonl 最後都多一筆 name 是 jsc-assist:assistant、phase 是 end 的事件,status 與回報出去的結果一致,而且同一個 session 下它與 hook 記的那一筆 phase=start 配得起來。四個操作都不動 tasks/ 底下的檔案,也不動 worktree 與程式碼存取庫。排程的 log 一律在 $JSC_HOME/assistant/schedule.log,不落在任何存取庫