30 Commits
Author SHA1 Message Date
jiantw83andClaude Opus 5 61f4a2dbc7 fix(assistant): 提醒佇列把內建項標成另一種列
實測踩到:這台機器的佇列八筆全是委派清單種入的內建項,動作是只提醒、
還沒有執行入口,所以每一輪都到期。於是每一個工作階段開頭固定吐八行
一模一樣的東西。

那不是提醒,是噪音——而讀佇列那一支自己的註解裡就寫著「對著一個刻意的
決定每個工作階段催一次,那是噪音不是提醒」。這一批就犯了那一條,只是
換成另一種來源。

分法照該有的處置切:使用者自己登錄的那一筆,人看到就做得了;內建項那
幾筆等的是接線,不是人。所以佇列的第一欄多一種值 builtin,讀的那一端
把前兩種逐筆點名、第三種收成一行總數。

種類在這一邊判,不在讀的那一邊:spec_key 只有這裡讀得到,而讀的那一端
的規則是只印不判。收尾多印一個 reminders_builtin=。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 13:39:45 +08:00
jiantw83andClaude Opus 5 2265dcd59c fix(schedule): 條目長度那道警告本來說不出話
新加的長度閘門用了 warn 來報「距離上限不到 100」,而這一支只定義 note。
殼回一句「warn: not found」到 stderr,那句提醒一次都沒印出來。

一道說不出話的檢核,跟沒有那道檢核是同一件事——而且它連自己壞了都只在
stderr 留一行,正常輸出上看不出任何異常。

修掉之後它第一次開口就說出一件要處理的事:這台機器的條目有 973 個位元組,
距上限只剩 27。長度大半來自 wiki 存取庫那一系列變數的快照,一支約 40 個
位元組——再多一支頁型變數就裝不起來,而那一次只會回 command too long。
所以訊息裡把這個來源講出來,人才知道要縮哪裡。

這一支之前就踩過同一個坑(另一段檢核也寫了 warn),所以註解裡寫明它只有
note,沒有 warn。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 12:52:23 +08:00
jiantw83andClaude Opus 5 932bfa826a feat(assistant): 一輪算完就寫提醒佇列
助理算得出哪幾筆到期、哪幾筆逾期,但那些結果只留在監控頁上。這一批讓
每一輪把「要送到人面前」的那幾筆寫成一份佇列檔,位置固定在助理狀態目錄
底下,讀的那一端只印、不判。

判定不放在讀的那一邊,理由是漂移:讓讀的人自己拿 due 欄與 next_run 去跟
現在比,就是第二套到期判定,跟這裡那一套遲早對不上,而對不上的那一天
兩邊都說自己是對的。

這樣換來一個新的失效模式,所以檔頭寫足四個值:輪次代號、UTC 時間戳、
連續失敗筆數、待辦總筆數,再加同一刻的 epoch 秒。助理沒在跑的時候佇列
不會更新,而一份舊佇列讀起來跟新的一模一樣——讀的那一端要算得出它多舊,
「沒有提醒」與「沒有人算提醒」不可以長得一樣。epoch 是為了讓讀的那一端
不必自己解 ISO 字串:那等於在每一個讀取端各放一份日期解析。

同一筆待辦既到期又逾期時只列逾期那一行。同一批提醒裡出現兩行會被讀成
兩件事,而「逾期五天」比「排定點過了」講得更清楚。

逾期那幾行的「逾期多久」直接取判定那一支算好的寫法,不在這裡再寫一個
時間長度格式化——同一個秒數在兩個地方就會印出兩種說法。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 11:16:57 +08:00
jiantw83andClaude Opus 5 465bd9d40a feat(assistant): 逾期判定接上來,逾期與連續失敗每一輪都提
逾期本來沒實作,監控頁上就寫著「上面的判定只講到期,不講逾期」。

到期與逾期分兩欄,不合成一個判定:到期是「該跑了」,逾期是「due 欄那個
截止時間過了」。一筆七天一次的檢查項天天都可能到期,卻永遠不會逾期;
一筆有截止時間的交辦可能早就逾期,卻因為排定點還沒到而判成還沒到。
合成一個值就把兩種情況混成同一格。

due.sh 多第十二欄 overdue,值是減號(沒有截止時間)、no、逾期的秒數,
或 bad。bad 算成欄位不合法回 2——一個解不開的截止時間跟沒有截止時間
在畫面上長得一模一樣,而前者是登錄的時候就填錯了。done 那幾筆不算逾期;
被暫停的那幾筆照算,因為暫停中止的是到期判定,不是日曆,而一筆被暫停
又逾期的交辦正好是最容易被忘掉的那一種。

另加唯讀子命令 due.sh overdue 給狀態查詢那一路走。走 scan 會推進快照,
那一輪之後的事件判定會全部落空;走 events 又判不到逾期;讓呼叫端自己
拿 due 欄去比更糟,那是第二套判定,漂移的那一天兩邊都說自己對。

patrol.sh 在逾期或連續失敗筆數大於 0 時各列一筆待人處理,每一輪都列。
兩種都不會自己好:截止時間過了不會因為過更久就不逾期,連續失敗的項目
每一輪都會再試一次然後再失敗一次。「提過了」不是「處理過了」,而助理
不替人按暫停,那個狀態留給人設。

監控頁那一節逐筆點名連續失敗的那幾筆——id、失敗幾次、最後一次執行、
標題。原本只印一個總數,而失敗次數這個欄位存在的理由是指出「有一筆壞掉
的項目每輪重試而沒人知道」,不說出是哪一筆,那個理由只完成一半。

目錄頁刻意不加欄位。那一頁一台機器一個區塊、各自那一輪寫,新加一條只有
跑到新版的機器寫得出來,讀的人分不出「這台沒有逾期」與「這台還沒寫這
一條」——理由與當初把「本輪非 ok 事件數」擋在那一頁外面的一樣。

欄位數從 11 變 12,run-due.sh 那道欄位數檢核跟著改成 12。那道檢核擋的
不是第 12 欄本身,是「兩支不是同一版」——版本不同的時候,前 11 欄的
順序也不能假設還是原來那樣。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 10:53:00 +08:00
jiantw83andClaude Opus 5 205da9b61f fix(assistant): 判定是不是存取庫交給 git 自己回答
原本看 .git 在不在。這台機器的工作目錄底下剛好有一個目錄的 .git 只剩
一個空的 info/,git 一句「not a git repository」——而掃描把它算成一個
存取庫,還印成「沒有 origin」。那個說法讀起來像「這個存取庫還沒接遠端」,
不像「這裡根本不是存取庫」,兩件事的處置完全不同。

改成由 git 回答,並核對它認定的頂層就是那個目錄:只問「是不是在工作樹裡」
不夠,git 會從那裡往上找,.git 壞掉時它會找到上一層的存取庫然後答「是」。
兩邊都解成實體路徑再比,掃描起點帶符號連結那一段時字串才對得上。

多一個 not_a_repo= 判定行與收尾計數,執行那一支照樣原樣轉出。
存取庫數從 19 個變 18 個。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 10:39:43 +08:00
jiantw83andClaude Opus 5 e53bb23f8e feat(assistant): 存取庫掃描接上 {repo} 代入點
新增 tools/scan-repos.sh:掃出工作目錄底下的存取庫,交出 {repo} 要代的
那份清單,順便對出每一個存取庫的 REPO_{HASH} 盤點頁頁名(雜湊規則與
盤點頁那一支相同,實測值一致)。

掃描起點刻意沒有預設值。給一個預設就等於猜,而猜錯的後果不是掃不到,
是在猜錯的那些目錄底下跑指令——往上一層是家目錄、再往上是整台機器,
而那一輪沒有人看得到它跑到哪裡去了。沒設就回 3 並說要設哪一個變數。
深度預設一層、上限三層;點開頭的目錄、符號連結、路徑帶空白或殼層特殊
字元的三種一律不交出去,但逐個印出來——那是真的存在卻沒被盤點到的
存取庫,只印一個總數會讀成整批都掃過了。

run-due.sh 改成兩個代入點都代:{cli} 取偵測到的 CLI 代號、{repo} 取
掃到的存取庫,兩個都帶的那一筆目標數是乘積。待辦簿那一筆的 repo 欄
有值時只代那一個,值可以是路徑也可以是 {owner}/{repo};對不出來就
印 held=,不退回全部存取庫——那一筆指名了一個目標。代入之後再驗一次
禁止字元,因為代進去的值是這一輪現場算出來的。

schedule.sh 把 JSC_ASSIST_SCAN_ROOT 與 JSC_ASSIST_SCAN_EXCLUDE 快照進
排程條目。少了掃描起點,帶 {repo} 的內建項每一輪都代不出目標,而那一輪
只印一行 held=,看起來像這一批還沒接上、不像一個變數沒進條目。

同時補兩個只有真的執行才發現得了的缺陷:

一、cron 一行的長度上限只在寫入那一刻由 crontab 自己擋,--dry-run 那一路
根本不碰它,所以預演每一次都過。實測踩過一次:整條 PATH 快照進條目那一批
預演全綠、安裝回結束碼 4。改成建好條目就量,兩個模式都印 entry_len= 與
上限,達到上限當場拒絕並指出長度是從哪幾個快照變數來的。

二、run-due.sh 截錯誤訊息用的 cut -c 數的是位元組不是字元,中文字剛好被
截在中間就在報告上留下一個替代字元。改成截完再過一次 iconv -c 丟掉那個
不完整的序列。這一種不會有人來報:亂碼不影響結束碼。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 10:36:26 +08:00
jiantw83andClaude Opus 5 98dd0761fa docs(assistant): 被權限擋下的指令,回報要帶完整指令列
實測踩到一輪:它報「寫入監控頁失敗——系統的核准機制擋下這個寫入指令,重試
一次仍被擋下,不是 Gitea 回傳的錯誤碼」,然後照規則中止、釋放鎖、不寫心跳。
中止的行為完全正確,寫不成頁就不該假裝跑完。

但那一輪沒說是哪一支工具、哪一條指令。事後把明顯的嫌疑一個一個排除——那一支
腳本實測在無人值守下放行、暫存檔路徑落在檔案規則的範圍內、條目也帶著寫入
確認旗標——真正被擋的那一條始終沒找到。那一輪到現在還是原因不明。

問題在於「擋下」不是工具回的錯誤:沒有結束碼、沒有 stderr、工具自己的日誌上
也沒有痕跡。指令字面是唯一的證據,也是唯一能拿去對允許清單的東西,而清單
比對的是還沒展開的指令字面。所以少了那一行,事後就只能猜。

兩處都加:寫監控頁那一步的失敗分流加一條,界線那一段再加一條通則,涵蓋整輪
任何一次被擋。要求含環境變數前綴——那算指令字面的一部分,今天量過。

三份 manifest 版號從 0.2.9 升到 0.3.1。原本寫 0.2.10,同步 manifest 那一支
把它正規化掉了——那一支不收兩位數的修訂號。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 10:13:31 +08:00
jiantw83andClaude Opus 5 633f56e7ea docs(assistant): 收尾回報要讀 cli_missing 那一行
巡檢步驟五的記錄清單補上那個欄位,並寫明它是唯一看得出「少跑一支」的地方
——每一支偵測到的目標都跑過、都通過,那一輪也照樣回報都跑過了。

回報要求也寫進去:點名少了哪幾支、講明乾淨通過不等於完整通過、指出重跑排程
安裝才會重新拍快照。

三份 manifest 版號 0.2.8 升到 0.2.9。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 09:40:00 +08:00
jiantw83andClaude Opus 5 4562da2bea docs(assistant): 執行那一步要把同一輪的到期清單路徑餵進去
巡檢步驟五改成帶 --rows,值取步驟一印的那個新欄位,並寫明那不是選用的、
也沒有預設值。步驟一的記錄清單跟著補上那個欄位,並註明它是空的時候代表判到期
那一步沒有產出清單,步驟五就沒有東西可動,要照實說而不是退回任何預設。

會把「為什麼不能有預設」寫進本文,是因為這個缺陷的形狀值得留下來:預設值指向
的位置在單機手動跑過一次之後就會有檔案,而那個檔案讀起來跟新的一模一樣。

三份 manifest 版號 0.2.7 升到 0.2.8。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-07 08:59:43 +08:00
jiantw83andClaude Opus 5 a050404a77 docs(assistant): 組頁那一步改成叫 rebuild,不再由呼叫端自己接
技能本文原本把三塊的接法描述給呼叫端,現在改成叫那一個子命令,並把「為什麼
不留給呼叫端接」寫進去——一個只有一種對的形狀的步驟,不該放在提示裡。

舊格式頁的處置本來在本文裡寫了一遍,現在由腳本自己認並印出來,所以那一段
刪掉,免得兩份文件對同一件事各講一次而漂移。

三份 manifest 版號 0.2.6 升到 0.2.7。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 17:42:54 +08:00
jiantw83andClaude Opus 5 ffe9a20178 fix(schedule): 條目只帶放得下 CLI 執行檔的那幾個目錄,不快照整條 PATH
上一版把整條 PATH 快照進條目,實測直接裝不起來:crontab 一行有長度上限,
回的是 command too long,結束碼 4。這台機器的 PATH 是 2160 字元,去重又去掉
不存在的那幾段之後還有 1332 字元,仍然超過。

改成只帶放得下 CLI 執行檔的那幾個目錄,這台機器實測兩個、合起來 70 字元,
整行降到 685 字元。夠用的理由是這一條要解決的問題很窄:cron 只給 /usr/bin
與 /bin,而偵測 CLI 那一支靠 PATH 找執行檔,找不到就回結束碼 0 加一份空清單
——看起來像「這台機器沒裝 CLI」。巡檢要跑的指令本身走字面絕對路徑,不靠它。

收尾接上 cron 本來就會給的那兩段,免得只剩自訂目錄而找不到系統工具。

一個代價寫進註解:有些 CLI 裝在會過期的目錄底下,例如帶行程編號的多殼層
目錄,那種路徑下一次開機就不在了。不特別過濾——過濾要認得每一種安裝方式,
那份名單會過期得比路徑還快。重跑一次 install 就重新拍一份,而條目本來就是
安裝當下的快照。

實測:拿條目會帶的那條 PATH 在清空環境裡跑,五支 CLI 全解得出來;真的裝一次
回結束碼 0,服務在跑,連結檢查通過。

三份 manifest 版號 0.2.5 升到 0.2.6。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 15:12:04 +08:00
jiantw83andClaude Opus 5 044676b1fc fix(schedule): 排程條目把 PATH 一起快照進去
cron 給的 PATH 只有 /usr/bin 與 /bin,而這台機器的 CLI 執行檔裝在家目錄底下。
於是無人值守那一輪偵測 CLI 一支都找不到——而且是回結束碼 0 加一份空清單,
不是失敗。看起來像「這台機器沒裝 CLI」,實際上是 PATH 上找不到。

實測踩到:那一輪印出 clis=0,帶 CLI 代入點的內建項全部代不出目標而被擋下,
同一支腳本在有人的 shell 裡回五支。

修在條目這一層,不是讓偵測那一支自己去猜安裝路徑:猜就要維護一份常見路徑
清單,而清單會過期,過期的方式跟今天修掉的那幾個一模一樣。條目本來就快照
十個環境變數,多這一個等於把「這台機器的執行檔裝在哪」交給安裝當下的環境
回答,不必任何人維護。

巡檢那一輪要跑的指令本身走的是字面絕對路徑、不靠 PATH;靠 PATH 的是那幾支
腳本自己呼叫的外部程式,所以這一條補的是後者。

實測:拿條目會帶的那條 PATH 在清空環境裡跑,五支 CLI 全解得出來;對照組用
cron 預設的 PATH,零支。

三份 manifest 版號 0.2.4 升到 0.2.5。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 14:41:31 +08:00
jiantw83andClaude Opus 5 3784cb51be fix(schedule): 補印執行那一支的允許規則,並回頭比對本文叫得到的每一支
巡檢多了執行到期內建項那一步,而印允許規則的清單是寫死的、沒跟著加。少一條
的代價不是報錯:那一輪停在權限詢問,鎖已經握在手上,接下來每一輪都讓開到鎖
逾時為止,而外面只看得到「心跳過期」。

補上那一條之後順手做掉根因。清單寫死,技能本文哪天多叫一支腳本這裡不會自己
知道,所以印完回頭掃一次本文,把它叫的每一支跟印過的比對,缺的逐支點名。

三個實作決定都是被自己踩出來的:

只掃 patrol 那一節,不掃整份。start 與 status 兩個操作都有人在現場,它們叫的
腳本跳一次權限詢問有人按得掉。整份掃會讓那幾支每次都被報成缺規則,而一份
每次都有雜訊的警告,看的人第二次就會跳過它——那時候真的漏一支就沒有人看得到。

技能本文的目錄名兩種版面都找:安裝版面帶 jsc- 前綴,開發用的並排工作目錄
版面不帶。原本只認一種,於是在另一種版面底下這道檢核被檔案存在檢查靜靜跳過
——一道「找不到就當通過」的檢核,跟沒有那道檢核是同一件事。找不到就明說這
一次沒有比對過,不要不出聲。

只警告不中止。比對規則有可能跟不上本文的寫法,那時候不該連排程都裝不起來。

三份 manifest 版號 0.2.3 升到 0.2.4。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 14:15:43 +08:00
jiantw83andClaude Opus 5 7d40c9dded feat(assistant): 巡檢那一輪接上執行到期內建項
檢核腳本沒人叫等於不存在,所以同一批把它接進巡檢的步驟五,擺在寫心跳之前
——跑過的結果要進得了這一輪的紀錄。任何一個結束碼都不中止那一輪:一支指令
失敗是發現,不是壞掉的一輪。

界線那一段補了一條,把兩件事分開:不對發現動手,跟跑自己排定的工作,不是
同一件事。待人處理那幾列是關於別人機器狀態的發現,跑那幾列等於一輪自己決定
別人的工作該怎麼做;到期的內建項是助理自己被交付的工作,來源是要走 PR 審查
的委派清單。並且寫明:哪天那一欄出現會寫入的指令,要重新吵這一段,不是悄悄
把它放寬。

收尾回報多一個區塊,因為那是待辦簿自己的工作唯一被交代的地方,並要求把
「跳過那幾筆的歷史沒有被動過」講明。

三份 manifest 版號 0.2.2 升到 0.2.3。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 13:58:16 +08:00
jiantw83andClaude Opus 5 c76e8489a6 fix(schedule): 排程條目不再寫死工作階段代號,CLI 判定跟上共用函式
兩個坑,都在同一支腳本,都讓無人值守那一輪看起來正常卻不正常。

一、條目寫死了工作階段代號。那一輪的兩半因此落在不同的值上:start 由 hook
寫,它從 hook 的標準輸入 JSON 讀得到 CLI 真正的代號;end 由工具腳本寫,沒有
那份 JSON,只能讀環境變數,於是讀到寫死的那個字串。配對的判準是工作階段
代號加技能名,兩半的代號不同就永遠配不起來。

這台機器上實測累積了 91 筆假的「只有 start 沒有 end」,其中 90 筆是同一支
每輪都會被叫用的技能。逐個工作階段數下來:92 個是一個 start 零個 end,另有
一個工作階段收著 29 個 end 卻一個 start 都沒有——那一個就是寫死的代號。

代價不只是數字難看。那一節存在的理由正是「只有 start 沒有 end 是一支技能
中止的唯一證據」,而這批假訊號只增不減,遲早把真的中止蓋掉。不設這個變數,
兩半就都落在 CLI 自己給的代號上,實測驗過確實配得起來。

二、CLI 判定抄了一份較窄的。共用函式認三個環境標記,這一份只認第一個,而
工具腳本被叫用時那一個不會設。於是每一次不帶 --cli 的安裝都回用法錯誤——
技能本文的啟動步驟叫的正是不帶 --cli 那一種,這台機器上一定裝不起來。同一個
判斷寫兩份就是這樣漂走的:共用函式後來補了兩個標記,這一份沒跟上,而漂移
的代價是一個看起來像「這台機器沒裝 CLI」的錯誤。

殘留的那 91 筆不必手動清,那一支本來就會把開超過一天的丟掉,一天內收斂。

三份 manifest 版號 0.2.1 升到 0.2.2。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 12:29:20 +08:00
jiantw83andClaude Opus 5 85a0ce9e10 fix(assistant): 人在現場那一路的根目錄解析帶上文件記載的預設值
技能本文寫著那一行「涵蓋了文件記載的 ~/.jsc 退讓」,實際上沒有。JSC_HOME
沒設時 $JSC_HOME/current 展開成 /current,不是退讓到任何地方——殼並不知道
那個變數的文件預設值是什麼。解析式現在自己帶預設,退讓才真的發生。

這台機器從頭到尾沒設過那個變數,所以每一次人在現場叫用都停在第 0 步,而且
守衛開的藥方指向不相干的地方:它說根目錄不見了、叫人跑部署,但根目錄好好
的,壞的是解析式自己。排程那一路不受影響,條目自己帶著變數值。

目錄檢查留著,理由改寫進本文:解析式交出一條看起來合理卻不存在的路徑,
不是只有變數沒設一種成因——變數指到已經刪掉的目錄、精簡環境裡連家目錄都
沒設、連結農場根本還沒部署,三種都一樣過得了前三道關。

行為清單那一份早就寫對了,是技能本文漂走。這一次把兩份對齊,並把事故記述
改成過去式,免得下一輪有人照著它重寫回錯的形狀。

實測表第四列不動:那是量到的結果,而且新寫法一樣帶變數、無人值守一樣被擋,
另外加一段講明預設值改的是解析出哪條路徑,不是誰可以跑它。

三份 manifest 版號 0.2.0 升到 0.2.1。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 11:53:10 +08:00
jiantw83andClaude Opus 5 28f453176e feat(seed): 種入內建項時改讀委派清單的唯讀盤點指令欄
委派清單補上第十二欄 probe 之後,這一支不再把所有非 invoke 的列一律推成
只提醒:填了指令的四列改成把那一行指令代好代入點寫進動作欄,寫著
pending 的七列照舊只提醒但另外印出來,讓「入口還沒接上」跟「本來就只提醒」
在回報上分得開。

三個判斷刻意寫死:

一、way 含 invoke 的列連看都不看 probe。填了指令會讓整支技能的交出變成
只跑一支腳本,那支技能該寫的頁一頁都不會寫,而且看起來完全正常。

二、probe 代不進去一律退回只提醒並照樣種入。不種入在 apply 那一路等於
移除,於是上游一格填錯就會刪掉一筆帶著 last_run 與 fail_count 的內建項。
金錢符號與波浪號擋在種入這一刻,那兩種寫法在無人值守那一輪解不出來、
也進不了允許清單,會被靜靜擋掉。

三、{cli} 與 {repo} 留在值裡不展開。種入的當下還不知道要代什麼,展開成
多筆會讓同一個 spec_key 有好幾個檔案,一致化整個垮掉。展開由執行那一步
負責,而動作欄裡出現大括號就是還沒代好,一律不得原樣拿去執行。

清單只有十一欄時整份先數一次欄位數,全部照舊推成只提醒、只印一行說明,
行為與加這一欄之前一模一樣。第十三欄以後另接一個收尾變數,免得上游哪天
加一欄就把多出來的值黏進 probe,代入點檢查全過得了關、最後執行的卻是
一行誰都沒寫過的指令。

相依下限刻意不動。清單那一欄晚一步到也照常跑得完,把下限拉到有那一欄的
版本等於逼兩個存放庫排合併順序,而排順序正是這一段程式碼要免掉的事。

三份 manifest 的版號從 0.1.9 升到 0.2.0。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-04 10:16:13 +08:00
jiantw83 a168c5904c feat(seed): 依委派清單種入與重建助理的內建定期檢查項
待辦簿做好了但是空的,也沒有東西會去填它。內建的定期檢查項該排哪些、什麼時候排、多久一次,這些資料就在委派清單裡——每一支非不交的技能都有時間點與週期兩欄。這一輪把清單接成待辦簿的資料來源。

反查靠新增的一個欄位,它非有不可。清單移除一支之後要刪掉對應那筆,但待辦簿的識別碼是建立時間加標題的雜湊,跟技能名無關。拿標題當鍵等於把措辭變成介面,改一個字舊那筆就再也認不出來,於是每次重建都刪不掉舊的又加一筆新的,同一個檢查每輪做兩次。拿動作當鍵,提醒類那十一筆全是同一個字、一支都分不出來,而觸發類那幾筆會撞上使用者自己交辦、動作剛好是同一支技能的那一筆——撞上就是把使用者交辦的事當成內建項刪掉。所以另立一欄記那一筆對應哪一支技能。

因為要加欄位,寫入端只能改存放那一支——它是唯一寫得出待辦檔的入口,這一輪沒有自己寫檔。連帶補上移除那個操作:規格要求不留孤兒,而原本六個操作一個都刪不掉。它對使用者交辦的那幾筆一律擋下、除非人親自帶強制旗標,而種入這一支一次都不帶。擋在單一寫入者這裡最省,那條規定寫在呼叫端的話,呼叫端每多一個就要各自再實作一次。

交出方式與動作是兩套詞彙,對映是這一輪的重點。含觸發就取技能名,其餘一律取提醒。觸發的定義就是呼叫既有技能、內容照那支技能自己的流程走,所以填技能名等於照判定結果做。巡檢與提醒那兩種沒有獨立入口——沒有任何腳本或技能名代表得了某一支技能的唯讀切片——這時候填技能名,助理下一輪就會把整支技能一路跑完,那正是切片交要防的事。所以填提醒:照時程提醒、指出入口,不動手。實測十六筆裡五筆是技能名、十一筆是提醒。

條件式交的三支一律不種入,但逐支吵出來。條件本身是散文,清單裡沒有機器讀得懂的條件欄位,所以條件成立了沒有現在只有人答得出來。種進去的代價有現成例子:其中一支的條件明寫要等它自家路徑不再帶版本號,而那個條件現在不成立,種進去助理每輪都會叫它、每輪停在第一支自家腳本,沒有錯誤、沒有輸出、心跳照寫,看起來完全正常。一個會無聲卡死的項目比一個缺掉的項目難查得多。不種入的代價是看不出為什麼少了它,用逐支印一行保留原因補掉。人確認過某一支條件成立就一支一支帶旗標放行,不給全部放行的旗標,那等於用一個決定蓋掉三個不同的條件。

種入與重建是同一段程式,啟動時每次都跑。不記跑過沒有,也沒有第一次旗標,要不要動手完全由現況決定。分成兩段的話,兩段各自回答該有哪幾筆這同一個問題,等其中一段改了判準就會一邊加一邊刪同一筆,每輪反覆。啟動時跑實際套用、查現況時跑唯讀預覽,巡檢那一輪兩個都不跑——無人值守那一輪移除一筆會把那一筆的執行紀錄與失敗次數一起弄丟,而清單同步到一半就會刪錯,破壞性清理留給人。

清單讀不到的三種情況一筆都不移除。讀不到時,清單上沒有與這台機器沒裝那個外掛分不出來,照字面跑會把所有內建項一次刪光,而且結束碼看起來完全成功。

清單上還在、還可交,只是時間點或週期換了值的那種情況,規格三條規則一條都沒講到。處置是預設只報差異不改:存放那一支刻意沒有編輯操作,改值只能移除再重登,那會換識別碼、把執行紀錄與失敗次數歸零,一個已經連續失敗五次的項目會看起來像全新的。人要換就帶旗標。

跨外掛相依宣告到清單所在的那個外掛,版本下限取現行的發行版——那是清單與它的欄位說明都已經在上面的版本。寫更低的下限會讓一台裝著舊版、清單還不存在或欄位不同的機器通過相依檢查,然後在讀清單那一步才失敗。清單路徑照今天剛改的規則走,由叫用時餵進來的根目錄組成,那一支自己不解。

三份 manifest 的版號一併從 0.1.8 升到 0.1.9,並在相依欄加上清單所在的那個外掛。這一次沒有把版號分成獨立一筆:相依宣告與版號是同一個決定的兩半,宣告了新相依卻不升版,安裝端不會知道要重新檢查相依。
2026-09-03 19:05:07 +08:00
jiantw83 1d220bf03f chore(manifest): 三份 manifest 升版至 0.1.8
事件偵測與到期判定要靠版號才傳得到機器端。

三份 manifest 由 sync-skill-manifest.sh 同步,只動版本欄位。
2026-09-03 16:37:44 +08:00
jiantw83 e7edfcbec0 chore(manifest): 三份 manifest 升版至 0.1.7
待辦簿工具要靠版號才傳得到機器端。

三份 manifest 由 sync-skill-manifest.sh 同步,只動版本欄位。
2026-09-03 15:46:09 +08:00
jiantw83 e4a3d3ae12 chore(manifest): 三份 manifest 升版至 0.1.6
三份 manifest 的版本從 0.1.5 升到 0.1.6,由 sync-skill-manifest.sh 同步。

助理技能的路徑守則與排程條目的內容都改過,安裝端要靠版號才認得出該更新,不升版的話舊條目會一直留在機器上。

版號與主變更分開成一筆,是因為這三個檔案只帶版號、不帶行為,混進主變更會讓那一筆的 diff 夾雜非行為變更;分開之後回溯哪一版對應哪一次變更也看得清楚。
2026-09-03 10:10:02 +08:00
jiantw83 8053c15425 chore(manifest): 三份 manifest 升版至 0.1.5
三份外掛清單的版號一起往上推一版。

目錄頁的版面與巡檢輸出檔名都變了,呼叫端要靠版號才判得出手上這一份是新的
還是舊的。版號不動,版本閘門就不會提示更新,機器上會留著舊版工具去讀新版
範本。

三份清單各自被不同的 CLI 讀,值必須一致,所以一起改、一起提交。

範圍是外掛清單的版號宣告。
2026-09-02 17:21:23 +08:00
jiantw83 ed624e0743 chore(plugin 版本): 三份 manifest 升版至 0.1.4 2026-09-02 16:01:13 +08:00
jiantw83 f2d30925f6 chore(plugin 版本): 三份 manifest 升版至 0.1.3 2026-09-02 14:27:18 +08:00
jiantw83 4bf99dde76 feat(wiki): 監控目錄頁改走專用存取庫,比對鍵改用裸 HASH
What:MONITOR_CONTENTS 改由 wiki-repo CONTENTS 解析並透過 wiki-contents.sh
upsert 寫入,MONITOR_{HASH} 仍走 wiki-repo MONITOR。目錄頁新增一欄裸 HASH 當
比對鍵,第一欄的絕對網址連結留給人看。主機名一律取短名。

Why:目錄頁集中之後兩頁不再同庫,[[...]] 只在同一個 wiki 內解析,連結必須改絕對
網址。比對鍵原本是含網址的儲存格,換主機、換存取庫或 URL 編碼有差就比對不到,
巡檢每 15 分鐘寫一次,重複列會累積得很快。

How:目錄頁解不出存取庫時不再中止巡檢——那一頁只是索引,內容頁寫成就照樣寫心跳。
內容頁寫不成仍然中止且不寫心跳,自咬環的前提沒有鬆動。

Who:jsc-assist
2026-09-02 11:01:51 +08:00
jiantw83 2af9dda7a6 chore(manifest): 三份外掛清單升到 0.1.1
三份外掛清單的版本從 0.1.0 改成 0.1.1。

這一輪改了排程條目的組法、監控頁的格式與技能的工具路徑,三件都會影響
已經裝在機器上的那一份。版本不動,版本閘門就看不出哪台機器裝的是舊的
那一版,也提不出重啟要求,舊條目會繼續空轉到有人自己發現。

三份檔案只動 version 一欄,其餘不碰,三份保持同一個號碼,這樣不管從哪
一支 CLI 讀到的都是同一個答案。功能範圍是外掛的版本宣告。
2026-09-01 18:28:04 +08:00
jiantw83 fbf3e5a605 feat(assistant): 助理主體收攏 start、status、stop 三個操作
What:
- 新增 assistant 技能,提供啟動、查現況、停止三個操作。
- 刪掉原本獨立的 status 技能,行為清單與 README 的技能目錄一起改。
- 三份 manifest 的版本一起提升,對 jsc-hooks 的下限提到含心跳腳本的那一版。

Why:
- 助理的生命週期是一件事,拆在兩支技能裡,靠描述自動觸發的 CLI 等於擲骰子挑一支。準則也明寫技能目標不得重複。
- 刪除的代價這時候最低:這個 domain 才剛落地,status 是它唯一一支技能,除了自己的文件沒有別的東西指向它。晚一步等各處都引用了再收攏,成本差很多。

How:
- 心跳的判定一律交給 jsc-hooks 的心跳腳本,三個操作都讀它的回報,不自己解析心跳檔。判定有兩份就會漂移,狀態與訊息就會對不上。
- 那支腳本的每一個結束碼都在技能裡有明確處置,包含「腳本自己沒跑起來」那一種——那時候既不能說助理在跑,也不能說助理停了。
- 時間戳壞掉一律當成不新鮮,絕不退回判成新鮮。
- 異常結束不需要額外的清理機制:心跳是時間戳,過了門檻自動失效。反過來說,stop 以外的任何路徑都不該寫心跳,否則就是留一個假心跳。
- stop 清心跳是它的職責,不算助理界線裡「不刪狀態檔」那一條。技能內文把這個例外寫明白,免得日後照界線把 stop 砍掉。
- stop 的收尾同時講兩件事:心跳清掉之後閘門會擋下技能呼叫,以及閘門目前還沒接線所以這一刻擋不到誰。前者是設計後果,停助理的人一定要知道;後者不講就是說一件還沒成真的事。
- 排程這一輪不做,start 只寫第一次心跳,並講明心跳不會自動更新。

Who:
助理落地的第二塊:心跳有了,接著要有人寫它、讀它、清它。
2026-09-01 14:19:24 +08:00
jiantw83 e7e9b8ce18 feat(templates): 新增監控頁的目錄頁與內容頁範本
What:
- 新增 templates/monitor-contents.md 與 templates/monitor-page.md。
- README 的「參考與工具」表補上這兩份範本,說明欄寫出兩者相反的寫入語意。
- 三份 manifest 的版本一起提升。

Why:
- 監控頁是助理巡檢結果的落點。沒有範本,每次巡檢寫出來的格式都不一樣,累積久了看不出趨勢,也對不起來。
- 兩份範本的寫入語意剛好相反,必須各自寫明白。目錄頁是共用的,一列代表一台機器,整頁覆蓋會刪掉別台機器的紀錄;內容頁只屬於一台機器,記的是歷次巡檢的軌跡,所以附加不覆寫。

How:
- 目錄頁範本帶欄位說明與寫入規則:比對主機與帳號兩欄,只更新自己那一列,讀不到舊內容就中止,不硬寫。
- 內容頁範本一次巡檢附加一節,節標題帶時間戳,涵蓋心跳與閘門、使用統計、hook 錯誤、版本落差、階段鎖與工作包鎖、待辦簿到期與逾期六類結果。
- 連續失敗的項目一定要標「已連續失敗 N 次」。待辦簿的項目失敗不會自動暫停,會每輪重試,不標出來就是一個壞掉的項目一直重試而沒人知道。
- 內容以圖表優先,流程用 mermaid、結果用表格,純文字每節最多三句。

Who:
技能助理落地帶出來的頁型別需求,四個存放庫同一批改。
2026-09-01 12:11:26 +08:00
jiantw83 6e18a373f3 feat(assist): 樣板改成 jsc-assist domain,加上 status 技能
What:
- 三份 manifest 的 name 由 jsc-template 改成 jsc-assist,version 設為 0.0.1,description 改寫成助理的定位,並加上 jsc.requires 宣告對 jsc-cli、jsc-gitea、jsc-hooks、jsc-log 的最低版本。
- README.md 與 AGENTS.md 依 meta domain 的格式重寫,AGENTS.md 多一節「助理的界線」。
- 刪掉樣板的 hello 技能,新增 status 技能與 references/behaviors.md 行為清單。

Why:
- 這個存取庫原本整份是 template 的樣板,四份 manifest 都還叫 jsc-template。名字沒改,marketplace 認不出它是獨立的 domain,各 CLI 也裝不上。
- 助理的閘門、心跳與巡檢要有落點,前提是存取庫先認得出自己。
- 樣板的 hello 技能只是安裝驗證用,留著會讓助理的技能清單從第一天就帶著一支沒有用途的技能。換成唯讀的 status,行為檢查與 frontmatter 檢查也才有掃描對象。

How:
- status 全程唯讀:讀心跳檔判斷助理在不在跑,判準只看時間戳距現在是否不到 300 秒,不看 pid 存活——五支 CLI 與容器裡的行程互相看不到彼此的 pid。
- 心跳檔不存在時印「助理未運行」,這是正常結果,不以非 0 結束。
- 這支不新增 tools/ 腳本。讀兩個路徑印一張表還不到抽腳本的門檻,助理主體落地時再一併評估。
- 三份 manifest 的 version 由 sync-skill-manifest.sh 同步,README 的技能目錄區塊一起更新。

Who:
助理 domain 落地的第一步,後續的閘門、心跳與排程都接在這個基礎上。
2026-09-01 11:20:52 +08:00
jiantw83 7790283920 Initial commit 2026-08-31 09:49:28 +00:00