Compare commits
24
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f047bdd49d | ||
|
|
b8b5737bc3 | ||
|
|
fd6aa6f45c | ||
|
|
5fcfc16dd1 | ||
|
|
58413ab808 | ||
|
|
9df303a377 | ||
|
|
619800e10c | ||
|
|
2ab643c6bd | ||
|
|
4fd9a52559 | ||
|
|
07d04c4d0c | ||
|
|
99871cd24f | ||
|
|
763709ed7b | ||
|
|
e47da3104c | ||
|
|
5a86f33d02 | ||
|
|
f2332f965c | ||
|
|
54e77a8da9 | ||
|
|
cb8123faa0 | ||
|
|
d6bd022920 | ||
|
|
9877e19bbd | ||
|
|
f1825fd653 | ||
|
|
1a34529231 | ||
|
|
737e3560f3 | ||
|
|
ca062e37a8 | ||
|
|
8bb1effb93 |
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jsc-meta",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.8",
|
||||
"description": "技能組自我管理:新建、更新、刪除技能與技能準則",
|
||||
"skills": "./skills",
|
||||
"author": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jsc-meta",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.8",
|
||||
"description": "技能組自我管理:新建、更新、刪除技能與技能準則",
|
||||
"skills": "./skills",
|
||||
"jsc": {
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jsc-meta",
|
||||
"version": "0.3.1",
|
||||
"version": "0.3.8",
|
||||
"description": "技能組自我管理:新建、更新、刪除技能與技能準則",
|
||||
"skills": "./skills/",
|
||||
"jsc": {
|
||||
|
||||
+20
-20
@@ -7,50 +7,50 @@
|
||||
| 項目 | 內容 |
|
||||
| --- | --- |
|
||||
| 觸發時機 | 手上沒有異動需求,要對整組技能做例行或臨時稽核時用。帶著異動需求要改多支技能走 skillset-update、只改一支走 skill-update |
|
||||
| 關鍵步驟 | 先跑 sync-domains.sh 同步全部 domain 存取庫、再平行跑三組審查(第一組平行跑腳本檢查、frontmatter 檢查、行為清單檢查、語言檢查、連結寫法檢查、wiki 規則檢查、頁名樣式檢查與 hook smoke,第二組以 sub agent 逐 domain 對 guidelines 檢查清單稽核,第三組先用 wiki-repo SKILLSET 與 hash-id 讀回各 domain SKILLSET_{HASH} 上已決議的優化建議再以 sub agent 分六個面向審查流程與成本;讀取回 7、8 或存取庫解不出來時只停掉該 domain 的第三組,第一組、第二組與後續步驟照跑)、合併三組結果並用決策樹逐項確認(第二組留白的九項由第一組的結論補上,其中頁名樣式與 wiki 規則兩項是整輪一份,同一個結論填進每個 domain;優化建議記下決議與決議日期)、以平行 sub agent 套用確認過的修正並跑 sync-skill-manifest.sh、跑 sync-marketplace.sh 同步兩份正本 marketplace、重跑三組驗證直到接受的修正全通過、每個受影響存取庫各開一條 PR、最後以平行 sub agent 逐 domain 把本輪稽核結果附加到 SKILLSET_{HASH},再取 wiki-url 的絕對網址、把頁上與列上的每個連結交給 link-check.sh 驗證、退出 0 才用 wiki-contents.sh upsert SKILLSET 2 "SKILLSET_{HASH}" 把自己那一個 H2 區塊寫進 CONTENTS 存取庫的 SKILLSET_CONTENTS(目錄頁一律大標題加條列,鍵是 H2 標題也就是內容頁頁名,第四個參數是區塊檔),最後呼叫 jsc-hooks/tools/report-status.sh skill-end jsc-meta:skill-check 寫一筆收尾事件(五種 status 依本輪實際結果選,中途停下的輪次也要寫;腳本不在就安靜跳過,不影響本輪結局) |
|
||||
| 外部呼叫 | tools/sync-domains.sh、jsc-hooks/tools/report-status.sh skill-end、tools/lint-scripts.sh、tools/lint-frontmatter.sh、tools/check-behaviors.sh、tools/ste100-lint.sh、tools/check-link-format.sh、tools/check-page-name.sh、tools/sync-skill-manifest.sh、tools/sync-marketplace.sh、jsc-gitea/tools/check-wiki-rules.sh、jsc-gitea/tools/link-check.sh、jsc-gitea/tools/gitea.sh 的 wiki-repo、hash-id 與 wiki-url、jsc-gitea/tools/wiki-contents.sh upsert(目錄頁自己那個區塊)、jsc-cli/tools/detect-clis.sh、jsc-hooks/tools/wire-cli.sh smoke、jsc-ask:ask、jsc-git:pr、jsc-gitea:wiki、templates/skillset-page.md、templates/skillset-contents.md |
|
||||
| 完成條件 | 每個 domain 都有腳本檢查、frontmatter 檢查、行為清單檢查、語言檢查與連結寫法檢查的結論(連結寫法檢查退出 3 是「什麼都沒掃」,不算通過),wiki 規則檢查與頁名樣式檢查各有一次結論(frontmatter 檢查退出 3 是「什麼都沒掃」、頁名樣式檢查退出 3 是「什麼都沒查」,都不算通過)、每個 domain 的檢查清單在合併後補齊且那兩項整輪一份的結論在每個 domain 都填上同一個值、讀不到已決議清單的 domain 記成「本輪未取得已決議清單,優化建議暫不提出」、每項不合規與每項優化建議都有決策紀錄且優化建議帶決議日期、接受的修正重驗通過、每個受影響存取庫都拿到 PR 網址、寫進 wiki 的每個連結都先經 link-check.sh 退出 0、每個受影響 domain 的 wiki 頁都寫成功,或列為未寫入並附完整內容、本輪的 skill-end 事件已寫入,或據實記成腳本不在這台機器上 |
|
||||
| 可驗證跡象 | $JSC_HOME/usage/events.jsonl 多一行 kind=skill、phase=end、name=jsc-meta:skill-check 的 skill-end 事件(本輪唯一必留的跡象,腳本不在時才沒有)、受影響存取庫留下檔案改動、改到行為的技能連帶改寫該存取庫的 references/behaviors.md、每個 domain 的 lint-frontmatter.sh、ste100-lint.sh 與 check-link-format.sh 退出 0、check-page-name.sh 退出 0、README 的「Skills 目錄」重寫、三份 manifest 版本號提升、兩份 marketplace 檔逐位元一致、每個受影響存取庫一條 PR、每個受影響 domain 的 SKILLSET_{HASH} 各附加一節,並由 wiki-contents.sh upsert 退出 0 在 SKILLSET_CONTENTS 留下自己那一個 `## SKILLSET_{HASH}` 區塊、區塊裡以 `- 異動頁:[SKILLSET_{HASH}]({連結})` 的絕對網址指向該內容頁;本輪無 domain 被改動時,改成 plugins/meta 那一頁記「本輪無發現」 |
|
||||
| 關鍵步驟 | 先跑 sync-domains.sh 同步全部 domain 存取庫、再平行跑三組審查(第一組平行跑腳本檢查、frontmatter 檢查、行為清單檢查、語言檢查、連結寫法檢查、腳本路徑檢查、wiki 規則檢查、頁名樣式檢查、委派清單檢查與 hook smoke,其中委派清單檢查跑 check-delegate.sh 整輪一次、不逐 domain 跑,退出 0 時 stdout 上的 seed 與版本落後只是提示、不算不合規,退出 1 的缺列多列空欄、死掉的 next 與填錯的 probe 逐項當不合規報,退出 3 記成「無委派清單可查」也不算通過,第二組以 sub agent 逐 domain 對 guidelines 檢查清單稽核,第三組先用 wiki-repo SKILLSET 與 hash-id 讀回各 domain SKILLSET_{HASH} 上已決議的優化建議再以 sub agent 分六個面向審查流程與成本;讀取回 7、8 或存取庫解不出來時只停掉該 domain 的第三組,第一組、第二組與後續步驟照跑)、合併三組結果並用決策樹逐項確認(第二組留白的九項由第一組的結論補上,其中頁名樣式與 wiki 規則兩項是整輪一份,同一個結論填進每個 domain;委派清單檢查不是檢查清單那九項之一,整輪自成一條結論,只有它的不合規進決策樹、提示不進;優化建議記下決議與決議日期)、以平行 sub agent 套用確認過的修正並跑 sync-skill-manifest.sh、由主 agent 自己改 delegate-spec.tsv 補上或刪掉判定列(缺列先用 delegate-criteria.md 的決策樹問過再寫,origin 記 judged,填錯的 probe 回該技能的存取庫核對過再改寫,切不出唯讀入口就寫成 pending;那個檔整組技能共用一份,交給平行 sub agent 寫會互相蓋掉)、跑 sync-marketplace.sh 同步兩份正本 marketplace、重跑三組驗證直到接受的修正全通過、每個受影響存取庫各開一條 PR、最後以平行 sub agent 逐 domain 把本輪稽核結果附加到 SKILLSET_{HASH},再取 wiki-url 的絕對網址、把頁上與列上的每個連結交給 link-check.sh 驗證、退出 0 才用 wiki-contents.sh upsert SKILLSET 2 "SKILLSET_{HASH}" 把自己那一個 H2 區塊寫進 CONTENTS 存取庫的 SKILLSET_CONTENTS(目錄頁一律大標題加條列,鍵是 H2 標題也就是內容頁頁名,第四個參數是區塊檔),最後呼叫 jsc-hooks/tools/report-status.sh skill-end jsc-meta:skill-check 寫一筆收尾事件(五種 status 依本輪實際結果選,中途停下的輪次也要寫;腳本不在就安靜跳過,不影響本輪結局) |
|
||||
| 外部呼叫 | tools/sync-domains.sh、jsc-hooks/tools/report-status.sh skill-end、tools/lint-scripts.sh、tools/lint-frontmatter.sh、tools/check-behaviors.sh、tools/ste100-lint.sh、tools/check-link-format.sh、tools/check-skill-paths.sh、tools/check-page-name.sh、tools/check-delegate.sh、tools/sync-skill-manifest.sh、tools/sync-marketplace.sh、jsc-gitea/tools/check-wiki-rules.sh、jsc-gitea/tools/link-check.sh、jsc-gitea/tools/gitea.sh 的 wiki-repo、hash-id 與 wiki-url、jsc-gitea/tools/wiki-contents.sh upsert(目錄頁自己那個區塊)、jsc-cli/tools/detect-clis.sh、jsc-hooks/tools/wire-cli.sh smoke、jsc-ask:ask、jsc-git:pr、jsc-gitea:wiki、templates/skillset-page.md、templates/skillset-contents.md |
|
||||
| 完成條件 | 每個 domain 都有腳本檢查、frontmatter 檢查、行為清單檢查、語言檢查與連結寫法檢查的結論(連結寫法檢查退出 3 是「什麼都沒掃」,不算通過),wiki 規則檢查、頁名樣式檢查與委派清單檢查各有一次結論(frontmatter 檢查退出 3 是「什麼都沒掃」、頁名樣式檢查退出 3 是「什麼都沒查」、委派清單檢查退出 3 是「無委派清單可查」,都不算通過;委派清單檢查退出 0 時的提示要與不合規分開記)、每個 domain 的檢查清單在合併後補齊且那兩項整輪一份的結論在每個 domain 都填上同一個值、讀不到已決議清單的 domain 記成「本輪未取得已決議清單,優化建議暫不提出」、每項不合規與每項優化建議都有決策紀錄且優化建議帶決議日期、接受的修正重驗通過、每個受影響存取庫都拿到 PR 網址、寫進 wiki 的每個連結都先經 link-check.sh 退出 0、每個受影響 domain 的 wiki 頁都寫成功,或列為未寫入並附完整內容、本輪的 skill-end 事件已寫入,或據實記成腳本不在這台機器上 |
|
||||
| 可驗證跡象 | $JSC_HOME/usage/events.jsonl 多一行 kind=skill、phase=end、name=jsc-meta:skill-check 的 skill-end 事件(本輪唯一必留的跡象,腳本不在時才沒有)、受影響存取庫留下檔案改動、改到行為的技能連帶改寫該存取庫的 references/behaviors.md、每個 domain 的 lint-frontmatter.sh、ste100-lint.sh 與 check-link-format.sh 退出 0、check-skill-paths.sh 退出 0(unrooted 與 unknown 只是提示)、check-page-name.sh 退出 0、check-delegate.sh 退出 0、本輪修過的判定列留在 plugins/meta 的 tools/delegate-spec.tsv、README 的「Skills 目錄」重寫、三份 manifest 版本號提升、兩份 marketplace 檔逐位元一致、每個受影響存取庫一條 PR、每個受影響 domain 的 SKILLSET_{HASH} 各附加一節,並由 wiki-contents.sh upsert 退出 0 在 SKILLSET_CONTENTS 留下自己那一個 `## SKILLSET_{HASH}` 區塊、區塊裡以 `- 異動頁:[SKILLSET_{HASH}]({連結})` 的絕對網址指向該內容頁;本輪無 domain 被改動時,改成 plugins/meta 那一頁記「本輪無發現」 |
|
||||
|
||||
## skill-delete
|
||||
|
||||
| 項目 | 內容 |
|
||||
| --- | --- |
|
||||
| 觸發時機 | 要把一支技能從技能組移除時用。改名不走這支,走 skill-update |
|
||||
| 關鍵步驟 | 跑 sync-domains.sh 同步、跑 list-skills.sh 列出全部技能、讓使用者挑一支確認刪除、跑 find-skill-refs.sh 盤點所有引用檔案、以平行 sub agent 逐檔修正到檢查清單全過、刪掉 skills/{name}/ 目錄、移除 references/behaviors.md 對應那一節、跑 sync-skill-manifest.sh、開 PR、依 deploy-verify.md 部署、用新的 CLI 行程驗證、跑 verify-skill-removed.sh 查磁碟殘留、用 wiki-repo SKILLSET 解出存取庫並依 templates/skillset-page.md 把異動報告附加到 SKILLSET_{HASH}、再取 wiki-url 的絕對網址、把頁上與列上的每個連結交給 link-check.sh 驗證、退出 0 才用 wiki-contents.sh upsert SKILLSET 2 "SKILLSET_{HASH}" 把自己那一個 H2 區塊寫進 CONTENTS 存取庫的 SKILLSET_CONTENTS(目錄頁一律大標題加條列,鍵是 H2 標題也就是內容頁頁名,第四個參數是區塊檔) 並依 0、1、2、3、4、7、8 各自分流,最後呼叫 jsc-hooks/tools/report-status.sh skill-end jsc-meta:skill-delete 寫一筆收尾事件(五種 status 依本次實際結果選,中途停下也要寫;腳本不在就安靜跳過,不影響本次結局) |
|
||||
| 外部呼叫 | tools/sync-domains.sh、jsc-hooks/tools/report-status.sh skill-end、tools/list-skills.sh、tools/find-skill-refs.sh、tools/check-behaviors.sh、tools/sync-skill-manifest.sh、tools/deploy-route.sh、tools/verify-skill-removed.sh、jsc-gitea/tools/link-check.sh、jsc-gitea/tools/gitea.sh 的 wiki-repo、hash-id 與 wiki-url、jsc-gitea/tools/wiki-contents.sh upsert(目錄頁自己那個區塊)、jsc-ask:ask、jsc-git:pr、jsc-gitea:wiki、templates/skillset-page.md、templates/skillset-contents.md |
|
||||
| 完成條件 | 盤點清單每一檔都有「已修正」或「無需修正」的結論、技能目錄與行為清單那一節都不存在、list-skills.sh 查不到那一列、殘留檢查退出 0 或據實記成「無處可查」並帶進報告、PR 網址到手、寫進頁與列的每個連結都經 link-check.sh 退出 0、SKILLSET_{HASH} 附加一節且舊節原樣留著、wiki-contents.sh upsert 退出 0、本次的 skill-end 事件已寫入,或據實記成腳本不在這台機器上 |
|
||||
| 可驗證跡象 | $JSC_HOME/usage/events.jsonl 多一行 kind=skill、phase=end、name=jsc-meta:skill-delete 的 skill-end 事件(本次唯一必留的跡象,腳本不在時才沒有)、skills/{name}/ 目錄消失、references/behaviors.md 少一節、README 與三份 manifest 更新、一條 PR、wiki SKILLSET_{HASH} 附加一節,並在 CONTENTS 存取庫的 SKILLSET_CONTENTS 留下自己那一個 `## SKILLSET_{HASH}` 區塊、區塊裡以 `- 異動頁:[SKILLSET_{HASH}]({連結})` 的絕對網址指向該內容頁 |
|
||||
| 關鍵步驟 | 跑 sync-domains.sh 同步、跑 list-skills.sh 列出全部技能、讓使用者挑一支確認刪除、跑 find-skill-refs.sh 盤點所有引用檔案、以平行 sub agent 逐檔修正到檢查清單全過(盤點裡的 delegate-spec.tsv 那一列留到刪除那一步一起處理,不在逐檔迴圈裡改)、刪掉 skills/{name}/ 目錄、移除 references/behaviors.md 對應那一節、刪掉 plugins/meta 的 tools/delegate-spec.tsv 那一列、把其他列指向這支的 next 改掉,並檢查有沒有別列的 probe 指到這次一起刪掉的腳本、跑 sync-skill-manifest.sh、跑 check-delegate.sh 整輪一次確認清單裡不再有這支(退出 0 時 stdout 的 seed 與版本落後只是提示、不擋收尾,退出 1 逐項修,退出 3 不算通過)、開 PR(技能不在 meta 時,清單那一筆改的是 plugins/meta,另開一條 PR)、依 deploy-verify.md 部署、用新的 CLI 行程驗證、跑 verify-skill-removed.sh 查磁碟殘留、用 wiki-repo SKILLSET 解出存取庫並依 templates/skillset-page.md 把異動報告附加到 SKILLSET_{HASH}、再取 wiki-url 的絕對網址、把頁上與列上的每個連結交給 link-check.sh 驗證、退出 0 才用 wiki-contents.sh upsert SKILLSET 2 "SKILLSET_{HASH}" 把自己那一個 H2 區塊寫進 CONTENTS 存取庫的 SKILLSET_CONTENTS(目錄頁一律大標題加條列,鍵是 H2 標題也就是內容頁頁名,第四個參數是區塊檔) 並依 0、1、2、3、4、7、8 各自分流,最後呼叫 jsc-hooks/tools/report-status.sh skill-end jsc-meta:skill-delete 寫一筆收尾事件(五種 status 依本次實際結果選,中途停下也要寫;腳本不在就安靜跳過,不影響本次結局) |
|
||||
| 外部呼叫 | tools/sync-domains.sh、jsc-hooks/tools/report-status.sh skill-end、tools/list-skills.sh、tools/find-skill-refs.sh、tools/check-behaviors.sh、tools/check-delegate.sh、tools/sync-skill-manifest.sh、tools/deploy-route.sh、tools/verify-skill-removed.sh、jsc-gitea/tools/link-check.sh、jsc-gitea/tools/gitea.sh 的 wiki-repo、hash-id 與 wiki-url、jsc-gitea/tools/wiki-contents.sh upsert(目錄頁自己那個區塊)、jsc-ask:ask、jsc-git:pr、jsc-gitea:wiki、templates/skillset-page.md、templates/skillset-contents.md |
|
||||
| 完成條件 | 盤點清單每一檔都有「已修正」「無需修正」或「留到刪除那一步處理」的結論、技能目錄與行為清單那一節都不存在、委派清單沒有那一列也沒有別列的 next 指著它且 check-delegate.sh 退出 0、list-skills.sh 查不到那一列、殘留檢查退出 0 或據實記成「無處可查」並帶進報告、待辦簿引用那一半據實記成尚未接線、本次動到的每個存取庫都有 PR 網址、寫進頁與列的每個連結都經 link-check.sh 退出 0、SKILLSET_{HASH} 附加一節且舊節原樣留著、wiki-contents.sh upsert 退出 0、本次的 skill-end 事件已寫入,或據實記成腳本不在這台機器上 |
|
||||
| 可驗證跡象 | $JSC_HOME/usage/events.jsonl 多一行 kind=skill、phase=end、name=jsc-meta:skill-delete 的 skill-end 事件(本次唯一必留的跡象,腳本不在時才沒有)、skills/{name}/ 目錄消失、references/behaviors.md 少一節、plugins/meta 的 tools/delegate-spec.tsv 少一列、README 與三份 manifest 更新、動到的每個存取庫各一條 PR、wiki SKILLSET_{HASH} 附加一節,並在 CONTENTS 存取庫的 SKILLSET_CONTENTS 留下自己那一個 `## SKILLSET_{HASH}` 區塊、區塊裡以 `- 異動頁:[SKILLSET_{HASH}]({連結})` 的絕對網址指向該內容頁 |
|
||||
|
||||
## skill-new
|
||||
|
||||
| 項目 | 內容 |
|
||||
| --- | --- |
|
||||
| 觸發時機 | 要在技能組新增一支技能時用。改既有技能走 skill-update |
|
||||
| 關鍵步驟 | 平行跑 list-skills.sh 與 sync-domains.sh 預取技能清單與 domain 清單、用決策樹問出目標、觸發時機、輸入輸出與所屬 domain、domain 未註冊就先確認存取庫在不在、依 template 結構補齊內容再跑 sync-marketplace.sh 註冊、以 sub agent 產生 skills/{name}/SKILL.md、在 references/behaviors.md 依字典序插入該技能一節、跑 sync-skill-manifest.sh、自查 guidelines 檢查清單並跑 check-behaviors.sh、開 PR、依 deploy-verify.md 部署並用新的 CLI 行程驗證、用 wiki-repo SKILLSET 解出存取庫並依 templates/skillset-page.md 把異動報告附加到 SKILLSET_{HASH}、再取 wiki-url 的絕對網址、把頁上與列上的每個連結交給 link-check.sh 驗證、退出 0 才用 wiki-contents.sh upsert SKILLSET 2 "SKILLSET_{HASH}" 把自己那一個 H2 區塊寫進 CONTENTS 存取庫的 SKILLSET_CONTENTS(目錄頁一律大標題加條列,鍵是 H2 標題也就是內容頁頁名,第四個參數是區塊檔) 並依 0、1、2、3、4、7、8 各自分流,最後呼叫 jsc-hooks/tools/report-status.sh skill-end jsc-meta:skill-new 寫一筆收尾事件(五種 status 依本次實際結果選,中途停下也要寫;腳本不在就安靜跳過,不影響本次結局) |
|
||||
| 外部呼叫 | tools/list-skills.sh、tools/sync-domains.sh、jsc-hooks/tools/report-status.sh skill-end、tools/sync-marketplace.sh、tools/check-behaviors.sh、tools/sync-skill-manifest.sh、tools/deploy-route.sh、jsc-gitea/tools/link-check.sh、jsc-gitea/tools/gitea.sh 的 clone-url、api、wiki-repo、hash-id 與 wiki-url、jsc-gitea/tools/wiki-contents.sh upsert(目錄頁自己那個區塊)、jsc-ask:ask、jsc-git:pr、jsc-gitea:wiki、templates/skillset-page.md、templates/skillset-contents.md |
|
||||
| 完成條件 | 四項提問都有紀錄、SKILL.md 與行為清單那一節都在、README 與三份 manifest 同步、檢查清單全過且 check-behaviors.sh 退出 0、PR 網址到手、deploy-verify.md 第 1 到第 5 節的完成條件全數成立、寫進頁與列的每個連結都經 link-check.sh 退出 0、SKILLSET_{HASH} 附加一節且舊節原樣留著、wiki-contents.sh upsert 退出 0、本次的 skill-end 事件已寫入,或據實記成腳本不在這台機器上 |
|
||||
| 可驗證跡象 | $JSC_HOME/usage/events.jsonl 多一行 kind=skill、phase=end、name=jsc-meta:skill-new 的 skill-end 事件(本次唯一必留的跡象,腳本不在時才沒有)、新增 skills/{name}/SKILL.md、references/behaviors.md 多一節、README 與三份 manifest 更新、新 domain 時兩份 marketplace 檔多一筆 plugin 條目並同步到每個 domain 存取庫、一條 PR、wiki SKILLSET_{HASH} 附加一節,並在 CONTENTS 存取庫的 SKILLSET_CONTENTS 留下自己那一個 `## SKILLSET_{HASH}` 區塊、區塊裡以 `- 異動頁:[SKILLSET_{HASH}]({連結})` 的絕對網址指向該內容頁 |
|
||||
| 關鍵步驟 | 平行跑 list-skills.sh 與 sync-domains.sh 預取技能清單與 domain 清單、用決策樹問出目標、觸發時機、輸入輸出、所屬 domain,以及依 delegate-criteria.md 五題加 next 與 probe 兩題問出的委派判定、domain 未註冊就先確認存取庫在不在、依 template 結構補齊內容再跑 sync-marketplace.sh 註冊、以 sub agent 產生 skills/{name}/SKILL.md、在 references/behaviors.md 依字典序插入該技能一節、在 plugins/meta 的 tools/delegate-spec.tsv 補上這支的十二欄判定列(用不到的欄位填減號,origin 記 judged,probe 的路徑以 {root}/jsc-{domain}/ 開頭且不帶變數,沒有這一列不算建立完成)、跑 sync-skill-manifest.sh、自查 guidelines 檢查清單並跑 check-behaviors.sh 與整輪一次的 check-delegate.sh(退出 0 時 stdout 的 seed 與版本落後只是提示、不算缺失,退出 1 逐項修,退出 3 不算通過)、開 PR(技能不在 meta 時,判定列那一筆改的是 plugins/meta,另開一條 PR)、依 deploy-verify.md 部署並用新的 CLI 行程驗證、用 wiki-repo SKILLSET 解出存取庫並依 templates/skillset-page.md 把異動報告附加到 SKILLSET_{HASH}、再取 wiki-url 的絕對網址、把頁上與列上的每個連結交給 link-check.sh 驗證、退出 0 才用 wiki-contents.sh upsert SKILLSET 2 "SKILLSET_{HASH}" 把自己那一個 H2 區塊寫進 CONTENTS 存取庫的 SKILLSET_CONTENTS(目錄頁一律大標題加條列,鍵是 H2 標題也就是內容頁頁名,第四個參數是區塊檔) 並依 0、1、2、3、4、7、8 各自分流,最後呼叫 jsc-hooks/tools/report-status.sh skill-end jsc-meta:skill-new 寫一筆收尾事件(五種 status 依本次實際結果選,中途停下也要寫;腳本不在就安靜跳過,不影響本次結局) |
|
||||
| 外部呼叫 | tools/list-skills.sh、tools/sync-domains.sh、jsc-hooks/tools/report-status.sh skill-end、tools/sync-marketplace.sh、tools/check-behaviors.sh、tools/check-delegate.sh、tools/sync-skill-manifest.sh、tools/deploy-route.sh、jsc-gitea/tools/link-check.sh、jsc-gitea/tools/gitea.sh 的 clone-url、api、wiki-repo、hash-id 與 wiki-url、jsc-gitea/tools/wiki-contents.sh upsert(目錄頁自己那個區塊)、jsc-ask:ask、jsc-git:pr、jsc-gitea:wiki、templates/skillset-page.md、templates/skillset-contents.md |
|
||||
| 完成條件 | 五項提問都有紀錄(含委派判定與 next 欄)、SKILL.md、行為清單那一節與委派判定列都在且該填的欄位都不空、README 與三份 manifest 同步、檢查清單全過且 check-behaviors.sh 與 check-delegate.sh 都退出 0、本次動到的每個存取庫都有 PR 網址、deploy-verify.md 第 1 到第 5 節的完成條件全數成立、寫進頁與列的每個連結都經 link-check.sh 退出 0、SKILLSET_{HASH} 附加一節且舊節原樣留著、wiki-contents.sh upsert 退出 0、本次的 skill-end 事件已寫入,或據實記成腳本不在這台機器上 |
|
||||
| 可驗證跡象 | $JSC_HOME/usage/events.jsonl 多一行 kind=skill、phase=end、name=jsc-meta:skill-new 的 skill-end 事件(本次唯一必留的跡象,腳本不在時才沒有)、新增 skills/{name}/SKILL.md、references/behaviors.md 多一節、plugins/meta 的 tools/delegate-spec.tsv 多一列、README 與三份 manifest 更新、新 domain 時兩份 marketplace 檔多一筆 plugin 條目並同步到每個 domain 存取庫、動到的每個存取庫各一條 PR、wiki SKILLSET_{HASH} 附加一節,並在 CONTENTS 存取庫的 SKILLSET_CONTENTS 留下自己那一個 `## SKILLSET_{HASH}` 區塊、區塊裡以 `- 異動頁:[SKILLSET_{HASH}]({連結})` 的絕對網址指向該內容頁 |
|
||||
|
||||
## skill-update
|
||||
|
||||
| 項目 | 內容 |
|
||||
| --- | --- |
|
||||
| 觸發時機 | 要改一支既有技能時用。新增走 skill-new、刪除走 skill-delete、一次改多支或跨 domain 走 skillset-update |
|
||||
| 關鍵步驟 | 跑 sync-domains.sh 同步、跑 list-skills.sh 列出全部技能、讓使用者挑一支、用決策樹問出改動細節、以 sub agent 改 SKILL.md 與相關檔案、同步更新 references/behaviors.md 該技能那一節、跑 sync-skill-manifest.sh、對 guidelines 檢查清單逐項自查並跑 check-behaviors.sh、開 PR、依 deploy-verify.md 部署並用新的 CLI 行程驗證、用 wiki-repo SKILLSET 解出存取庫並依 templates/skillset-page.md 把異動報告附加到 SKILLSET_{HASH}、再取 wiki-url 的絕對網址、把頁上與列上的每個連結交給 link-check.sh 驗證、退出 0 才用 wiki-contents.sh upsert SKILLSET 2 "SKILLSET_{HASH}" 把自己那一個 H2 區塊寫進 CONTENTS 存取庫的 SKILLSET_CONTENTS(目錄頁一律大標題加條列,鍵是 H2 標題也就是內容頁頁名,第四個參數是區塊檔) 並依 0、1、2、3、4、7、8 各自分流,最後呼叫 jsc-hooks/tools/report-status.sh skill-end jsc-meta:skill-update 寫一筆收尾事件(五種 status 依本次實際結果選,中途停下也要寫;腳本不在就安靜跳過,不影響本次結局) |
|
||||
| 外部呼叫 | tools/sync-domains.sh、jsc-hooks/tools/report-status.sh skill-end、tools/list-skills.sh、tools/check-behaviors.sh、tools/sync-skill-manifest.sh、tools/deploy-route.sh、jsc-gitea/tools/link-check.sh、jsc-gitea/tools/gitea.sh 的 wiki-repo、hash-id 與 wiki-url、jsc-gitea/tools/wiki-contents.sh upsert(目錄頁自己那個區塊)、jsc-ask:ask、jsc-git:pr、jsc-gitea:wiki、templates/skillset-page.md、templates/skillset-contents.md |
|
||||
| 完成條件 | 每個提問都有紀錄、技能檔案帶著改動、行為清單那一節與新行為一致且 check-behaviors.sh 退出 0、三份 manifest 同版、檢查清單全過、PR 網址到手、deploy-verify.md 第 1 到第 5 節的完成條件全數成立、寫進頁與列的每個連結都經 link-check.sh 退出 0、SKILLSET_{HASH} 附加一節且舊節原樣留著、wiki-contents.sh upsert 退出 0、本次的 skill-end 事件已寫入,或據實記成腳本不在這台機器上 |
|
||||
| 可驗證跡象 | $JSC_HOME/usage/events.jsonl 多一行 kind=skill、phase=end、name=jsc-meta:skill-update 的 skill-end 事件(本次唯一必留的跡象,腳本不在時才沒有)、該技能的 SKILL.md 與相關檔案改動、references/behaviors.md 對應節改寫、README 與三份 manifest 更新、一條 PR、wiki SKILLSET_{HASH} 附加一節,並在 CONTENTS 存取庫的 SKILLSET_CONTENTS 留下自己那一個 `## SKILLSET_{HASH}` 區塊、區塊裡以 `- 異動頁:[SKILLSET_{HASH}]({連結})` 的絕對網址指向該內容頁 |
|
||||
| 關鍵步驟 | 跑 sync-domains.sh 同步、跑 list-skills.sh 列出全部技能、讓使用者挑一支、用決策樹問出改動細節,並在同一棵樹裡定案委派判定(動到流程或 description 就照 delegate-criteria.md 重跑五題加 next 與 probe 兩題,只改文案不動行為才可以沿用舊結論,但 probe 一律回存取庫核對過)、以 sub agent 改 SKILL.md 與相關檔案、同步更新 references/behaviors.md 該技能那一節、改 plugins/meta 的 tools/delegate-spec.tsv 那一列(重判就整列改寫並把 origin 記成 judged,沿用就只動 version 並照樣核對 probe;改名時連別列指過來的 next 一起改;沿用這件事寫進 PR 描述與 wiki 那一節,清單沒有備註欄)、跑 sync-skill-manifest.sh、對 guidelines 檢查清單逐項自查並跑 check-behaviors.sh 與整輪一次的 check-delegate.sh(退出 0 時 stdout 的 seed 與版本落後只是提示、不算缺失,只有指名本次改到那支的版本落後要回去補,退出 1 逐項修,退出 3 不算通過)、開 PR(技能不在 meta 時,判定列那一筆改的是 plugins/meta,另開一條 PR)、依 deploy-verify.md 部署並用新的 CLI 行程驗證、用 wiki-repo SKILLSET 解出存取庫並依 templates/skillset-page.md 把異動報告附加到 SKILLSET_{HASH}、再取 wiki-url 的絕對網址、把頁上與列上的每個連結交給 link-check.sh 驗證、退出 0 才用 wiki-contents.sh upsert SKILLSET 2 "SKILLSET_{HASH}" 把自己那一個 H2 區塊寫進 CONTENTS 存取庫的 SKILLSET_CONTENTS(目錄頁一律大標題加條列,鍵是 H2 標題也就是內容頁頁名,第四個參數是區塊檔) 並依 0、1、2、3、4、7、8 各自分流,最後呼叫 jsc-hooks/tools/report-status.sh skill-end jsc-meta:skill-update 寫一筆收尾事件(五種 status 依本次實際結果選,中途停下也要寫;腳本不在就安靜跳過,不影響本次結局) |
|
||||
| 外部呼叫 | tools/sync-domains.sh、jsc-hooks/tools/report-status.sh skill-end、tools/list-skills.sh、tools/check-behaviors.sh、tools/check-delegate.sh、tools/sync-skill-manifest.sh、tools/deploy-route.sh、jsc-gitea/tools/link-check.sh、jsc-gitea/tools/gitea.sh 的 wiki-repo、hash-id 與 wiki-url、jsc-gitea/tools/wiki-contents.sh upsert(目錄頁自己那個區塊)、jsc-ask:ask、jsc-git:pr、jsc-gitea:wiki、templates/skillset-page.md、templates/skillset-contents.md |
|
||||
| 完成條件 | 每個提問都有紀錄、技能檔案帶著改動、行為清單那一節與新行為一致且 check-behaviors.sh 退出 0、委派判定列帶著重判結果或帶著沿用結論與更新過的 version 且 check-delegate.sh 退出 0、三份 manifest 同版、檢查清單全過、本次動到的每個存取庫都有 PR 網址、deploy-verify.md 第 1 到第 5 節的完成條件全數成立、寫進頁與列的每個連結都經 link-check.sh 退出 0、SKILLSET_{HASH} 附加一節且舊節原樣留著、wiki-contents.sh upsert 退出 0、本次的 skill-end 事件已寫入,或據實記成腳本不在這台機器上 |
|
||||
| 可驗證跡象 | $JSC_HOME/usage/events.jsonl 多一行 kind=skill、phase=end、name=jsc-meta:skill-update 的 skill-end 事件(本次唯一必留的跡象,腳本不在時才沒有)、該技能的 SKILL.md 與相關檔案改動、references/behaviors.md 對應節改寫、plugins/meta 的 tools/delegate-spec.tsv 那一列改寫、README 與三份 manifest 更新、動到的每個存取庫各一條 PR、wiki SKILLSET_{HASH} 附加一節,並在 CONTENTS 存取庫的 SKILLSET_CONTENTS 留下自己那一個 `## SKILLSET_{HASH}` 區塊、區塊裡以 `- 異動頁:[SKILLSET_{HASH}]({連結})` 的絕對網址指向該內容頁 |
|
||||
|
||||
## skillset-update
|
||||
|
||||
| 項目 | 內容 |
|
||||
| --- | --- |
|
||||
| 觸發時機 | 一個異動需求橫跨多支技能或多個 domain,要一次做完時用。只改一支走 skill-update、手上沒有異動需求的例行稽核走 skill-check |
|
||||
| 關鍵步驟 | 平行啟動 sync-domains.sh 與異動細節決策樹、問清楚改哪一條規則、影響哪些技能與 domain,並補問工具化、sub agent、環境變數三項塑形檢查、以每個 domain 一個 sub agent 平行套用改動、同步更新每個受影響 domain 的 references/behaviors.md、逐存取庫跑 sync-skill-manifest.sh、以平行 sub agent 重跑 guidelines 檢查清單與 check-behaviors.sh 直到全過、每個受影響存取庫各開一條 PR、依 deploy-verify.md 部署並用新的 CLI 行程驗證、以平行 sub agent 逐存取庫用 wiki-repo SKILLSET 解出存取庫並依 templates/skillset-page.md 把異動報告附加到 SKILLSET_{HASH}、再取 wiki-url 的絕對網址、把頁上與列上的每個連結交給 link-check.sh 驗證、退出 0 才用 wiki-contents.sh upsert SKILLSET 2 "SKILLSET_{HASH}" 把自己那一個 H2 區塊寫進 CONTENTS 存取庫的 SKILLSET_CONTENTS(目錄頁一律大標題加條列,鍵是 H2 標題也就是內容頁頁名,第四個參數是區塊檔) 並依 0、1、2、3、4、7、8 各自分流,最後由主 agent 呼叫一次 jsc-hooks/tools/report-status.sh skill-end jsc-meta:skillset-update 寫一筆收尾事件(整批一筆,不逐 domain 寫;五種 status 依本次實際結果選,中途停下也要寫;腳本不在就安靜跳過,不影響本次結局) |
|
||||
| 外部呼叫 | tools/sync-domains.sh、jsc-hooks/tools/report-status.sh skill-end、tools/check-behaviors.sh、tools/sync-skill-manifest.sh、tools/deploy-route.sh、tools/list-skills.sh、jsc-gitea/tools/link-check.sh、jsc-gitea/tools/gitea.sh 的 wiki-repo、hash-id 與 wiki-url、jsc-gitea/tools/wiki-contents.sh upsert(目錄頁自己那個區塊)、jsc-ask:ask、jsc-git:pr、jsc-gitea:wiki、templates/skillset-page.md、templates/skillset-contents.md |
|
||||
| 完成條件 | 受影響技能清單與三項塑形檢查都跟使用者談定、每個受影響存取庫都帶著改動、README 同步與 manifest 提升、每支動過的技能檢查清單全過且該 domain 的 check-behaviors.sh 退出 0、每個受影響存取庫都有 PR 網址、deploy-verify.md 第 1 到第 5 節對每個存取庫都成立、每個存取庫寫進頁與列的每個連結都經 link-check.sh 退出 0、每個存取庫的 SKILLSET_{HASH} 都附加一節且舊節原樣留著、每個存取庫的 wiki-contents.sh upsert 都退出 0、本次整批一筆的 skill-end 事件已寫入,或據實記成腳本不在這台機器上 |
|
||||
| 可驗證跡象 | $JSC_HOME/usage/events.jsonl 多一行 kind=skill、phase=end、name=jsc-meta:skillset-update 的 skill-end 事件(整批只有一行,本次唯一必留的跡象,腳本不在時才沒有)、每個受影響存取庫的技能檔案改動、各自的 references/behaviors.md 更新、README 與三份 manifest 更新、每個存取庫一條 PR、每個存取庫的 wiki SKILLSET_{HASH} 各附加一節,並在 CONTENTS 存取庫的 SKILLSET_CONTENTS 各留下自己那一個 `## SKILLSET_{HASH}` 區塊、區塊裡以 `- 異動頁:[SKILLSET_{HASH}]({連結})` 的絕對網址指向該內容頁 |
|
||||
| 關鍵步驟 | 平行啟動 sync-domains.sh 與異動細節決策樹、問清楚改哪一條規則、影響哪些技能與 domain,並補問工具化、sub agent、環境變數三項塑形檢查、以每個 domain 一個 sub agent 平行套用改動、同步更新每個受影響 domain 的 references/behaviors.md、每個 sub agent 對自己動到的每一支技能逐支重跑 delegate-criteria.md 的決策樹(一支都不跳,五題加 next 與 probe 兩題,只改文案不動行為的才可以沿用並只動 version,probe 一律回自己存取庫核對過)但不自己寫檔,把判定列交回主 agent 一次併進 plugins/meta 的 tools/delegate-spec.tsv(那個檔整組共用一份,平行寫會互相蓋掉)、逐存取庫跑 sync-skill-manifest.sh、以平行 sub agent 重跑 guidelines 檢查清單與 check-behaviors.sh 直到全過、由主 agent 跑整批一次的 check-delegate.sh(退出 0 時 stdout 的 seed 與版本落後只是提示、不算缺失,只有指名本批動到那幾支的版本落後要回去補,退出 1 逐項修,退出 3 不算通過)、每個受影響存取庫各開一條 PR,判定列落在 plugins/meta 而 meta 不在受影響清單裡時另開一條、依 deploy-verify.md 部署並用新的 CLI 行程驗證、以平行 sub agent 逐存取庫用 wiki-repo SKILLSET 解出存取庫並依 templates/skillset-page.md 把異動報告附加到 SKILLSET_{HASH}、再取 wiki-url 的絕對網址、把頁上與列上的每個連結交給 link-check.sh 驗證、退出 0 才用 wiki-contents.sh upsert SKILLSET 2 "SKILLSET_{HASH}" 把自己那一個 H2 區塊寫進 CONTENTS 存取庫的 SKILLSET_CONTENTS(目錄頁一律大標題加條列,鍵是 H2 標題也就是內容頁頁名,第四個參數是區塊檔) 並依 0、1、2、3、4、7、8 各自分流,最後由主 agent 呼叫一次 jsc-hooks/tools/report-status.sh skill-end jsc-meta:skillset-update 寫一筆收尾事件(整批一筆,不逐 domain 寫;五種 status 依本次實際結果選,中途停下也要寫;腳本不在就安靜跳過,不影響本次結局) |
|
||||
| 外部呼叫 | tools/sync-domains.sh、jsc-hooks/tools/report-status.sh skill-end、tools/check-behaviors.sh、tools/check-delegate.sh、tools/sync-skill-manifest.sh、tools/deploy-route.sh、tools/list-skills.sh、jsc-gitea/tools/link-check.sh、jsc-gitea/tools/gitea.sh 的 wiki-repo、hash-id 與 wiki-url、jsc-gitea/tools/wiki-contents.sh upsert(目錄頁自己那個區塊)、jsc-ask:ask、jsc-git:pr、jsc-gitea:wiki、templates/skillset-page.md、templates/skillset-contents.md |
|
||||
| 完成條件 | 受影響技能清單與三項塑形檢查都跟使用者談定、每個受影響存取庫都帶著改動、README 同步與 manifest 提升、每支動過的技能檢查清單全過且該 domain 的 check-behaviors.sh 退出 0、每支動過的技能都有本批的委派判定(重判或據實記成沿用)併進委派清單且整批一次的 check-delegate.sh 退出 0、每個受影響存取庫都有 PR 網址、deploy-verify.md 第 1 到第 5 節對每個存取庫都成立、每個存取庫寫進頁與列的每個連結都經 link-check.sh 退出 0、每個存取庫的 SKILLSET_{HASH} 都附加一節且舊節原樣留著、每個存取庫的 wiki-contents.sh upsert 都退出 0、本次整批一筆的 skill-end 事件已寫入,或據實記成腳本不在這台機器上 |
|
||||
| 可驗證跡象 | $JSC_HOME/usage/events.jsonl 多一行 kind=skill、phase=end、name=jsc-meta:skillset-update 的 skill-end 事件(整批只有一行,本次唯一必留的跡象,腳本不在時才沒有)、每個受影響存取庫的技能檔案改動、各自的 references/behaviors.md 更新、plugins/meta 的 tools/delegate-spec.tsv 上每支動過的技能各一列判定、README 與三份 manifest 更新、每個存取庫一條 PR、每個存取庫的 wiki SKILLSET_{HASH} 各附加一節,並在 CONTENTS 存取庫的 SKILLSET_CONTENTS 各留下自己那一個 `## SKILLSET_{HASH}` 區塊、區塊裡以 `- 異動頁:[SKILLSET_{HASH}]({連結})` 的絕對網址指向該內容頁 |
|
||||
|
||||
## ste100-sync
|
||||
|
||||
|
||||
@@ -0,0 +1,149 @@
|
||||
# 技能委派判準
|
||||
|
||||
本文件是「一支技能能不能交給背景助理」的唯一判準來源。`skill-new`、`skill-update`、`skill-delete`、`skillset-update` 四支技能異動技能共用這一份,不各自抄一套。
|
||||
|
||||
判定結果一律寫進 [`tools/delegate-spec.tsv`](../tools/delegate-spec.tsv),由 [`tools/check-delegate.sh`](../tools/check-delegate.sh) 檢核。本文件只寫判準,不放判定結果。
|
||||
|
||||
## 交出方式只有三種
|
||||
|
||||
超出這三種的一律不交。
|
||||
|
||||
| 代號 | 方式 | 邊界 |
|
||||
| --- | --- | --- |
|
||||
| `invoke` | 觸發 | 呼叫既有技能,內容照那支技能自己的流程走。助理只決定「什麼時候跑」,不改那支技能的判斷 |
|
||||
| `patrol` | 巡檢 | 跑既有的唯讀腳本或讀既有狀態,產出現況。一個字都不改,讀完寫進監控頁 |
|
||||
| `remind` | 提醒 | 把巡檢結果留到前景會話提出來。不代替使用者決定,也不自己動手 |
|
||||
|
||||
一支技能可以同時用多種方式,例如先巡檢再提醒。
|
||||
|
||||
## 判定決策樹
|
||||
|
||||
一支技能照順序回答五個問題,答完就得到結論。
|
||||
|
||||
| 題號 | 問題 | 答「是」往哪走 |
|
||||
| --- | --- | --- |
|
||||
| 一 | 本體會改檔案,或對外不可逆? | 是就跳到第四題 |
|
||||
| 二 | 本體需要使用者決策? | 需要就跳到第四題 |
|
||||
| 三 | 輸出穩定,跑兩次結果一致? | 是就結論「全交」,方式填觸發 |
|
||||
| 四 | 切得出唯讀盤點或提醒的一段? | 切得出就結論「切片交」 |
|
||||
| 五 | 要加條件才切得出? | 是就結論「條件式交」,切不出就結論「不交」 |
|
||||
|
||||
```mermaid
|
||||
flowchart TD
|
||||
S[一支技能] --> Q1{本體會改檔案,<br/>或對外不可逆?}
|
||||
Q1 -->|會| Q4
|
||||
Q1 -->|不會| Q2{本體需要使用者決策?}
|
||||
Q2 -->|需要| Q4
|
||||
Q2 -->|不需要| Q3{輸出穩定、跑兩次結果一致?}
|
||||
Q3 -->|是| R1[全交:觸發]
|
||||
Q3 -->|否| Q4
|
||||
Q4{切得出唯讀盤點<br/>或提醒的一段?} -->|切得出| R2[切片交]
|
||||
Q4 -->|要加條件才切得出| R3[條件式交]
|
||||
Q4 -->|切不出| R4[不交]
|
||||
```
|
||||
|
||||
結論之外還要多填兩項。
|
||||
|
||||
一是**這支技能跑完之後建議接哪一支**,寫進清單的 `next` 欄。不交的技能也要填——不交講的是助理不代跑,跟「跑完之後該接什麼」無關。
|
||||
|
||||
二是**那一段唯讀盤點實際要跑哪一個指令**,寫進清單的 `probe` 欄。只有交出方式是巡檢或提醒的那幾列要填:那幾列在待辦簿上的動作原本一律退回只提醒,有指令才有事情做。交出方式含觸發的列與不交的列一律填減號,理由見下一節。
|
||||
|
||||
## 四種結論,每一種都要留一列
|
||||
|
||||
| 結論 | `verdict` | 要記什麼 |
|
||||
| --- | --- | --- |
|
||||
| 全交 | `full` | 交出方式、預設 `trigger` 與 `recur` |
|
||||
| 切片交 | `slice` | 交出的那一段、方式、**留在人手上的那一半** |
|
||||
| 條件式交 | `cond` | 條件講清楚,連同條件不成立時的行為 |
|
||||
| 不交 | `none` | 不交的理由。不交也要留一列,否則下次分不出「判過決定不交」與「還沒判」 |
|
||||
|
||||
「留在人手上的那一半」是切片交的必填欄位。少了它,助理下一輪會把整支技能當成可交的一路跑完。
|
||||
|
||||
## 每種結論的必填欄位
|
||||
|
||||
`-` 代表這一格填一個減號,不是留白。TSV 沒有空格這種值,留白會被檢核判成缺欄位。
|
||||
|
||||
| 欄位 | 全交 | 切片交 | 條件式交 | 不交 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `way` | 必填 | 必填 | 必填 | `-` |
|
||||
| `slice` | `-` | 必填 | 必填,條件寫在這裡 | `-` |
|
||||
| `human` | `-` | 必填 | 必填 | 必填,寫不交的理由 |
|
||||
| `trigger` | 必填 | 必填 | 必填 | `-` |
|
||||
| `recur` | 必填 | 必填 | 必填 | `-` |
|
||||
| `next` | 必填 | 必填 | 必填 | 必填 |
|
||||
| `version` | 必填 | 必填 | 必填 | 必填 |
|
||||
| `origin` | 必填 | 必填 | 必填 | 必填 |
|
||||
| `probe` | `-` | `way` 不含 `invoke` 才必填 | 同左 | `-` |
|
||||
|
||||
`trigger` 與 `recur` 是兩個獨立欄位,四種組合都成立,登錄時不可以壓成兩種。
|
||||
|
||||
| 欄位 | 可填值 |
|
||||
| --- | --- |
|
||||
| `trigger` | `at:{ISO 時間}`,立刻要做寫 `at:now`;或 `after:{事件名}` |
|
||||
| `recur` | `once`、`every:{間隔}`、`cron:{式子}` |
|
||||
| `probe` | 一行指令、`pending:{理由}`,或 `-` |
|
||||
|
||||
事件名只認固定詞彙表:`worklog-written`、`wp-merged`、`stage-entered`、`analyze-completed`、`hook-error`、`session-start`、`session-end`。填一個永遠不會發生的事件名,那一筆就永遠不到期,而且看不出壞在哪。
|
||||
|
||||
## 唯讀指令欄怎麼填
|
||||
|
||||
`probe` 記的是「那一段唯讀盤點實際要跑什麼」。助理拿它當待辦簿上的動作,所以它是一個指令,不是說明文字。
|
||||
|
||||
| 寫法 | 什麼時候用 |
|
||||
| --- | --- |
|
||||
| 一行指令 | 那一段有現成的唯讀入口,跑起來一個字都不改 |
|
||||
| `pending:{理由}` | 那一段切得出唯讀盤點,入口還沒接上。冒號後面寫不接的理由,不可以留白 |
|
||||
| `-` | 這一列沒有唯讀盤點入口 |
|
||||
|
||||
指令的路徑一律寫成 `{root}/jsc-{domain}/…` 開頭。三個代入點由助理代入,別的大括號一律算填錯:
|
||||
|
||||
| 代入點 | 代入什麼 |
|
||||
| --- | --- |
|
||||
| `{root}` | 種入那一支拿到的字面絕對根目錄 |
|
||||
| `{cli}` | 助理偵測到的 CLI 代號,一支跑一次 |
|
||||
| `{repo}` | 助理掃到的存取庫工作目錄,一個跑一次 |
|
||||
|
||||
指令裡不可以出現金錢符號或波浪號:那兩種寫法在無人值守那一輪解不出來,也進不了允許清單,會被靜靜擋掉。要帶環境變數就寫在指令最前面。
|
||||
|
||||
**唯讀旗標帶不帶,逐支確認,不要照抄別列。** 有些腳本靠環境變數才進唯讀模式,例如接線那一支設了 `JSC_READONLY=1` 會讓它的破壞性子命令回結束碼 6;那一列就要把旗標寫進指令。沒有唯讀模式的腳本不要憑空補一個變數名,補了不會生效,卻讓下一個人以為有護欄。巡檢那一輪是無人值守的,帶錯旗標會讓唯讀盤點變成實際動手。
|
||||
|
||||
**交出方式含觸發的列一律填 `-`。** 觸發的意思是呼叫整支技能,內容照那支技能自己的流程走。這一欄填了指令,助理會改拿指令當動作,於是整支交出變成只跑一支腳本,那支技能該寫的頁一頁都不會寫,而且看起來完全正常。
|
||||
|
||||
**要連網的先寫 `pending`。** 連網要金鑰,金鑰一過期就讓那一項每輪失敗,或每輪靜靜回報沒事——後者更難查。純本機讀取本來一輪都不會失敗。先填會連網的那一種,等於用一批每輪報錯的項目把真的發現蓋掉。等入口與金鑰都有著落再換成指令。
|
||||
|
||||
檢核怎麼看:`pending` 只印成待接線提示,不算缺失,判準同 `origin=seed`——它是「判過、知道還沒接」,不是漏填。填錯欄位、指到不存在的腳本、用了認不得的代入點,都算缺失。
|
||||
|
||||
## 判定結果放哪裡
|
||||
|
||||
真實來源是 [`tools/delegate-spec.tsv`](../tools/delegate-spec.tsv),一支技能一列。作法沿用 `jsc-cli/tools/config-spec.tsv` 那套:TSV 加一支檢核腳本,能被腳本比對,不靠人讀。
|
||||
|
||||
判定結果**不寫進 `SKILL.md` 的 frontmatter**。`name` 與 `description` 之外的自訂欄位有被各 CLI 的技能驗證擋掉的風險。
|
||||
|
||||
「過舊」的判準是比 plugin 版本號:清單上記的版本號落後該 domain 現行版本,就是要複判。版本號是 domain 層級,所以同 domain 改一支技能,其餘技能也會被標成要複判——**這只是提示,不算稽核缺失**。當成缺失的話,每次發版整個 domain 都亮紅,提示很快就被當雜訊忽略。
|
||||
|
||||
`origin` 欄記這一列怎麼來的:
|
||||
|
||||
| 值 | 意思 | 檢核怎麼看 |
|
||||
| --- | --- | --- |
|
||||
| `seed` | 依既有盤點種入,還沒正式走過決策樹 | 印成待複核提示,不算缺失 |
|
||||
| `judged` | 正式走過決策樹判定 | 不印 |
|
||||
|
||||
種入的那一批先掛 `seed`。之後那支技能有異動時就地走一次決策樹,把它轉成 `judged`。
|
||||
|
||||
## 各種異動要做的事
|
||||
|
||||
| 異動 | 技能 | 要做的事 | 沒做的後果 |
|
||||
| --- | --- | --- | --- |
|
||||
| 新增技能 | `skill-new` | 決策樹五題、`next` 欄那一題,再加 `probe` 欄那一題,全部照 `jsc-ask:ask` 問過,產出判定結果並寫進清單。**沒有判定結果不算建立完成** | 清單缺列,助理永遠不知道這支技能存在,也建議不到它 |
|
||||
| 修改技能 | `skill-update` | 動到流程或 `description` 就重判,`probe` 一併重確認——技能換了呼叫的腳本,那一欄就指到不存在的東西;只改文案不動行為可沿用舊結論,但要更新清單上的版本號並註明沿用 | 技能從唯讀變成會寫檔,助理還照舊觸發它 |
|
||||
| 刪除技能 | `skill-delete` | 刪掉清單那一列、把指到它的 `next` 改指別支,並檢查有沒有別列的 `probe` 指到這次一起刪掉的腳本;另移除待辦簿裡引用它的內建項 | 助理會去觸發一支不存在的技能,而且失敗不會自動暫停,會一路重試 |
|
||||
| 一次改多支 | `skillset-update` | 逐支重判,一支都不能跳 | 同上,而且範圍更大 |
|
||||
| 例行稽核 | `skill-check` | 跑 `tools/check-delegate.sh`,檢查清單與實際技能一一對應。缺列、多列與 `probe` 填錯算缺失;版本號落後、`seed` 與 `probe` 的 `pending` 只列成提示 | 清單慢慢與實際脫節,回到手工盤點會過期的老問題 |
|
||||
|
||||
## 助理要跟著更新
|
||||
|
||||
清單改動之後,助理的內建定期檢查項要重建一次。
|
||||
|
||||
- 清單新增可交項目,待辦簿加一筆,來源標成助理內建。
|
||||
- 清單移除或改成不交,待辦簿移除對應那筆,不留孤兒。
|
||||
- 使用者自己交辦的項目一律不動。助理不會因為一支技能改判就把使用者交辦的事刪掉。
|
||||
@@ -0,0 +1,188 @@
|
||||
# 十項定案規格
|
||||
|
||||
這份文件收錄分析頁裡十項技術裁定的定案內容,每項附出處與具體例子,供後續工作包直接引用,不必回頭翻找分析頁全文。
|
||||
|
||||
## N-01:雜湊輸入分隔符
|
||||
|
||||
**裁決**:多個欄位(例如計畫名稱與存取庫路徑)要接成一個雜湊輸入字串時,固定用直線號 `|` 當分隔符。組法收在 `hash-id` 的 `key` 子命令這個單一入口,各技能不再自己接字串。
|
||||
|
||||
**出處**:「工作分解結構(WBS)」層1 共用腳本表格,工作包名稱「hash-id 加 key 子命令:分隔符 `|`、四道正規化、組法收單一入口」;測試計畫「雜湊組法收單一入口」小節第一個 TDD 循環,斷言 `hash-id key "我的計畫" "plugins/sdlc"` 與 `hash-id "我的計畫|plugins/sdlc"` 輸出同一個 40 碼雜湊。
|
||||
|
||||
**例外**:本份分析頁自己的雜湊輸入不吃 `{owner}/{repo}`,只用計畫名稱,理由是這一輪盤點橫跨 11 個存取庫,綁任一個存取庫都是錯的。這是單一頁面的特例,不是分隔符定案本身跟著變。
|
||||
|
||||
**例子**:
|
||||
```
|
||||
hash-id key "我的計畫" "plugins/sdlc"
|
||||
# 與下面這行輸出同一個 40 碼大寫 SHA-1
|
||||
hash-id "我的計畫|plugins/sdlc"
|
||||
```
|
||||
|
||||
## N-02:計畫名稱正規化規則
|
||||
|
||||
**裁決**:計畫名稱進雜湊前,固定套四道正規化,依序是:
|
||||
|
||||
1. Unicode NFC 正規化
|
||||
2. 去除頭尾空白
|
||||
3. 內部連續空白壓成一個半形空白
|
||||
4. 英數字元全形轉半形
|
||||
|
||||
大小寫不在正規化範圍內,維持原樣、視為不同名稱。
|
||||
|
||||
**出處**:測試計畫「雜湊組法收單一入口」小節第二個 TDD 循環,斷言「我的 計畫」「我的 計畫」「我的計畫 」三種輸入正規化後相同,而「ABC 計畫」與「abc 計畫」不同;最小實作寫明四道正規化內容。
|
||||
|
||||
**例子**:
|
||||
- `我的 計畫`、`我的 計畫`(全形空白)、`我的 計畫`(兩個半形空白)→ 正規化後同一個結果,雜湊相同,第二次建立同名計畫會被擋下
|
||||
- `ABC 計畫` 與 `abc 計畫` → 正規化後仍不同,雜湊不同,兩者當成不同計畫
|
||||
|
||||
可直接貼進測試檔的指令:
|
||||
```
|
||||
hash-id key "我的 計畫" "plugins/sdlc"
|
||||
hash-id key "我的 計畫" "plugins/sdlc"
|
||||
hash-id key "我的 計畫" "plugins/sdlc"
|
||||
# 三行輸出同一個 40 碼雜湊
|
||||
|
||||
hash-id key "ABC 計畫" "plugins/sdlc"
|
||||
hash-id key "abc 計畫" "plugins/sdlc"
|
||||
# 兩行輸出不同雜湊,這是反例,證明大小寫不會被正規化抹掉
|
||||
```
|
||||
|
||||
## N-05:跨存取庫工作包編號起算
|
||||
|
||||
**裁決**:每一份分析頁的工作包編號各自從 `WP-01` 起算,不跨頁連號。因此鎖定工作包不能只看編號,要在前面加上該分析頁自己的雜湊當複合鍵,兩份不同分析頁裡同編號的工作包才不會互搶同一把鎖。
|
||||
|
||||
**出處**:「工作分解結構(WBS)」層2 技能行為表格,處理 analyze 頁名與跨庫的工作包名稱寫明「各頁 WP-01 起算」;對應 TDD 小節斷言兩份不同分析頁各自的「雜湊組法收單一入口」下游工作包不互相搶鎖,最小實作是把鎖鍵改成「`{分析頁雜湊}#WP-NN`」複合鍵。
|
||||
|
||||
**例子**:分析頁 A 與分析頁 B 各有自己的第二個工作包。鎖鍵分別是 `{分析頁A雜湊}#WP-02` 與 `{分析頁B雜湊}#WP-02`,領取其中一個不影響另一個,兩邊各自從 1 起算。
|
||||
|
||||
## N-07:`PLAN_CONTENTS` 存取庫欄格式
|
||||
|
||||
**裁決**:`PLAN_CONTENTS` 目錄頁的存取庫欄改成清單,同一行、多個值用頓號分隔,不拆成多行子條列。
|
||||
|
||||
**出處**:「工作分解結構(WBS)」層2 技能行為表格,工作包名稱「`PLAN_CONTENTS` 存取庫欄改清單,同行頓號分隔」;對應 TDD 小節斷言那一行 upsert 後讀得回多個值,最小實作是改範本並在寫入時以頓號串接。
|
||||
|
||||
**例子**:
|
||||
```
|
||||
- 存取庫:plugins/sdlc、plugins/log
|
||||
```
|
||||
|
||||
## L-03:年月週次進雜湊輸入
|
||||
|
||||
**裁決**:工作日誌頁名的雜湊輸入改吃「年-月-週次」字串(例如 `2026-09-W1`),取代原本的 `{owner}/{repo}`。週次字串進的是雜湊輸入本身,不是先照舊算出雜湊再在頁名後面加後綴。
|
||||
|
||||
**出處**:測試計畫「一週一頁工作日誌」小節第一個 TDD 循環,斷言三個不同存取庫、同一週的三筆日誌落在同一頁,且雜湊輸入不含 `{owner}/{repo}`,最小實作是「頁名改吃週次字串」。
|
||||
|
||||
**例子**:`plugins/sdlc`、`plugins/log`、`plugins/meta` 三個存取庫在同一週(週五落在 2026-09-04)各寫一筆日誌。三筆都算出同一個雜湊、落在同一頁 `LOG_{hash(2026-09-W1)}`,各自在頁面內容裡帶自己的存取庫欄位。
|
||||
|
||||
可直接貼進測試檔的指令:
|
||||
```
|
||||
worklog-target.sh week 2026-09-04
|
||||
# 輸出:2026-09-W1
|
||||
```
|
||||
|
||||
邊界情況(反例,跨月份):`2026-08-28` 是 8 月最後一個週五,算出 `2026-08-W4`;隔一週的 `2026-09-04` 只差 7 天,卻因為跨了月份算出 `2026-09-W1`。兩者雜湊不同、落在不同頁,不能因為「只差一週」就假設落在同一頁。
|
||||
```
|
||||
worklog-target.sh week 2026-08-28
|
||||
# 輸出:2026-08-W4
|
||||
```
|
||||
|
||||
## L-05:舊日誌拆頁
|
||||
|
||||
**裁決**:舊制一庫一頁的工作日誌,依每筆條目自己的日期拆進對應的週頁,不整頁原樣搬過去。拆頁動作可重跑不重複(用條目內容雜湊去重),拆不出日期的條目列進待處理清單,不猜日期也不丟棄。
|
||||
|
||||
**出處**:「工作分解結構(WBS)」層3 搬遷與清理表格,工作包名稱「舊一庫一頁日誌依條目日期拆進各週頁,可重跑」,標明「不可逆」;對應 TDD 小節斷言含日期的條目落到正確週頁、沒日期的條目列進待處理清單且不丟掉,同一份輸入跑兩次不產生重複條目。
|
||||
|
||||
**例子**:舊頁裡四筆條目:
|
||||
|
||||
| 條目 | 日期 | 落頁 |
|
||||
| --- | --- | --- |
|
||||
| 條目一 | 2026-08-14 | `LOG_{hash(2026-08-W2)}` |
|
||||
| 條目二 | 2026-08-28 | `LOG_{hash(2026-08-W4)}` |
|
||||
| 條目三 | 2026-09-04 | `LOG_{hash(2026-09-W1)}` |
|
||||
| 條目四 | 無日期欄位 | 列進待處理清單,不猜週次 |
|
||||
|
||||
三筆有日期的條目各自落進對應週頁;第四筆沒有日期,列進一份待處理清單交人工確認,不強行歸入任何一週。同一份舊頁重跑一次拆頁,用條目內容雜湊去重,不會讓已經拆過的四筆再多出一份——重跑後 `LOG_{hash(2026-08-W2)}` 頁裡條目一依然只有一份,不是兩份。
|
||||
|
||||
## O-09:六條輸出原則裡哪幾條進得了 lint
|
||||
|
||||
**裁決**:六條輸出原則裡,只有「避免書面語」與「問句要放句尾」這兩條寫成 `ste100-lint.sh` 裡的程式化判定;其餘四條要靠語意判斷,不硬塞進 lint。
|
||||
|
||||
**出處**:「工作分解結構(WBS)」層2 技能行為表格,工作包名稱「`ste100-lint.sh` 補書面語詞彙與問句位置,加名詞展開寫法檢查」,註記「O-09 定案」;對應 TDD 小節有兩個判定,一個餵「請您進行身分驗證確認之動作」斷言抓得到書面語並建議改寫,另一個餵「請告訴我目的地,以便為您查詢班機」斷言抓得到問句不在句尾。
|
||||
|
||||
**例子**:
|
||||
- 輸入「請您進行身分驗證確認之動作」→ 判定為書面語,建議改寫成「請幫我確認您的身分」
|
||||
- 輸入「請告訴我目的地,以便為您查詢班機」→ 判定為問句不在句尾,應改成先問句、後補充理由
|
||||
|
||||
## A-12:關鍵路徑圖涵蓋所有工作包
|
||||
|
||||
**裁決**:「涵蓋所有工作包」是指關鍵路徑圖上要畫出全部工作包,不是把 WBS 拆成每一包都串在同一條鏈上。圖裡只有真正的最長鏈標成關鍵路徑,其餘工作包照自己實際的相依邊掛上去,不為了「全部在一條鏈上」而編造假的先後順序。
|
||||
|
||||
**出處**:分析頁「關鍵路徑(CPM)」節開頭:「本圖收進全部 55 個工作包(2026-09-07 裁示:關鍵路徑圖必須涵蓋所有工作包)」,並註明「`crit` 只標最長那一條鏈,其餘照自己的相依邊掛,不串成假的先後順序」。
|
||||
|
||||
**例子**:55 個工作包全部畫進甘特圖;只有一條鏈(定案交付包 → 雜湊組法收單一入口 → 一週一頁工作日誌 → 舊日誌拆頁)標成關鍵路徑,其餘工作包各自照自己的相依關係接線,沒有相依的直接從錨點日期起排,不硬接到關鍵路徑上。
|
||||
|
||||
可直接比對的斷言:
|
||||
- 甘特圖節點總數:55(等於分析頁工作包總數,一個都不能少)
|
||||
- 標 `crit` 的節點數:4(就是上面那條鏈),其餘 51 個工作包不掛 `crit`
|
||||
- 反例:沒有相依的工作包(例如一個獨立的小型修正包)不會被接在關鍵路徑任何一個節點後面,而是直接從錨點日期起排;如果檢查發現它被接進了那條 4 節點的鏈,就是誤把「涵蓋」做成了「全部串成一條鏈」
|
||||
|
||||
## I-07:不監看時的相依判定
|
||||
|
||||
**裁決**:implement 階段選擇不監看 PR 時,判斷某個工作包是否「已完成」要同時滿足兩個條件:狀態欄本身寫著「已完成」,而且那個工作包對應的 commit 真的在目前分支的歷史裡(用 `git merge-base --is-ancestor` 判定,狀態欄要多存一個 commit 欄位)。兩個條件都成立才放行,只滿足其中一條不算。
|
||||
|
||||
這個判法跟「PR 已合併」不衝突:監看模式下 PR 合併之後,commit 自然會進到分支歷史裡,兩個條件同時成立;不監看模式下沒有實際等 PR 合併,改靠這兩個條件直接對真實的 git 歷史查驗,效果等同,但不必守著輪詢。
|
||||
|
||||
**出處**:測試計畫「implement PR 監看二選一」小節第二個 TDD 循環,斷言相依包狀態欄寫「已完成」但其 commit 不在目前分支歷史裡時不放行,兩條都成立才放行;使用者故事驗收計畫「PR 沒人審把階段掛住」失敗流程一列寫明「相依判定改吃『狀態欄加 git 祖先』」。
|
||||
|
||||
**例子**:某個工作包的狀態欄寫「已完成」、commit 欄記著一個 40 碼 SHA-1。查驗時執行 `git merge-base --is-ancestor {該commit} HEAD`;結束碼 0 才判定它真的完成,可以讓依賴它的下一包開工;結束碼非 0(commit 不在目前分支歷史)即使狀態欄寫完成也不放行。
|
||||
|
||||
反例(另一半條件不成立):狀態欄寫「進行中」,commit 欄記的 commit 其實已經是 HEAD 的祖先(`git merge-base --is-ancestor` 結束碼 0)。這種情況一樣不放行——兩個條件要同時成立,狀態欄沒寫「已完成」,光是 commit 在歷史裡也不夠。
|
||||
|
||||
## I-09:同一張 PR 疊多個工作包要不要收斂
|
||||
|
||||
**裁決**:不設上限,也不強制收斂。一張 PR 可以疊上任意數量的工作包;每次收尾時要印出目前這張 PR 疊了幾個工作包、累計改了幾行(用 `git diff --shortstat` 取得),讓疊加狀況看得見,但不會因為疊太多就被擋下。
|
||||
|
||||
**出處**:「定案規格交付包」工作包的測試計畫小節,列出十項定案的簡表,其中一項寫明「I-09 不設上限」;「implement PR 監看二選一」小節第四個 TDD 循環,斷言每次收尾都印出目前這張 PR 疊了幾包、累計幾行,最小實作是取 `git diff --shortstat` 與領取紀錄。
|
||||
|
||||
**例子**:同一張 PR 已經疊了 3 個工作包、累計改了 214 行。收尾時印出「本 PR 目前疊 3 包,累計 +180/-34 行」,然後照常繼續,不會因為已經疊了 3 包就強制先關閉這張 PR。
|
||||
|
||||
## 無繼承例子的工作包:`analyze-check.sh` 三合一靜態檢核
|
||||
|
||||
**說明**:這份文件收錄的十項技術定案加 F-01 決議,沒有一項對應到「三合一靜態檢核」這個工作包。逐一核對過 N-01、N-02、N-05、N-07、L-03、L-05、O-09、A-12、I-07、I-09、F-01,都不是這個工作包的裁決依據,硬套任何一項的例子都是誤導。
|
||||
|
||||
**如實記錄**:這個工作包沒有從十項技術定案加 F-01 決議裡繼承到的例子,動工時要自己另外準備測試資料——具體要涵蓋哪三種靜態檢核、各自的正常輸入與異常輸入長什麼樣子,留給工作包自己在分析頁或動工當下決定,不在這份文件裡代寫。
|
||||
|
||||
## F-01:五個未註冊存取庫的去向
|
||||
|
||||
盤點 jsc 技能組時,發現五個存取庫檔案完整、能動,但沒登錄進 `plugins/meta` marketplace 正本的 `.claude-plugin/marketplace.json`。這一節記下五個存取庫各自的決議,供 E 表重寫直接引用。
|
||||
|
||||
**裁決**:五個存取庫全部不納入正本,各自維持獨立系統。逐一列用途與決議:
|
||||
|
||||
| 存取庫 | 一句話用途 | 決議 |
|
||||
| --- | --- | --- |
|
||||
| `plugins/code`(jsc-code) | .NET/NuGet 升版、Gitea AI review findings 修復、存取庫批次同步、`TARGET.md` 每日待辦 | 不納入正本,維持獨立系統 |
|
||||
| `plugins/doc`(jsc-doc) | Gitea 通知分組處理、docker 註解整理、議題分析與同步、工時日誌 | 不納入正本,維持獨立系統 |
|
||||
| `plugins/persona`(jsc-persona) | AI 人格化記憶聊天,跟 SDLC 技能組完全不相干的獨立系統 | 不納入正本,維持獨立系統 |
|
||||
| `plugins/shared`(jsc-shared) | 三十多支跨助理共用規格類技能(`spec-*`) | 不納入正本,維持獨立系統 |
|
||||
| `plugins/code-review`(呼叫前綴 `jsc:`,不是 `jsc-code-review:`) | 以 GitHub Actions 為基礎的 RPG 攻防式 `git diff` review,跟正本裡互動式的 `jsc-review` 是兩套不同東西 | 不納入正本,維持獨立系統 |
|
||||
|
||||
**出處**:這一輪盤點(2026-09-07)裡使用者針對「五個未註冊存取庫逐一定去向」這一項待辦的明確答覆——五個全部不納入,不再逐一討論註冊、歸檔或刪除三選一。
|
||||
|
||||
**對 E 表的具體影響**:`meta/tools/delegate-spec.tsv` 本身已經是對的——現有 35 列,不含這五個存取庫的任何技能,不必再修。真正還記著這幾支技能、需要訂正的是 `/root/plugins/TODO.md` 第 652~655 行那份 E 表(設計討論用的表格,跟 `delegate-spec.tsv` 是兩份不同的東西)。決議之後,TODO.md 那份 E 表要照下面的方式修正,實際改檔案交給 WP-36(或 TODO.md 自己校正清單裡已經開著的 F-02 項):
|
||||
|
||||
- **E-13**(TODO.md 第 652 行,`jsc-doc:notifications`,定期讀 Gitea 通知分組提醒):整條移除。這支技能不會進正本,助理的技能清單裡永遠找不到它。
|
||||
- **E-14**(TODO.md 第 653 行,`jsc-code:review-resolve`,巡檢 findings 有沒有新的未處理項目):整條移除,理由同上。
|
||||
- **E-15**(TODO.md 第 654 行,原列 `jsc-pkg:pkg-update`、`jsc-code:nuget`):只留 `jsc-pkg:pkg-update` 那一半,`jsc-code:nuget` 那一半移除。
|
||||
- **E-16**(TODO.md 第 655 行,原列 `jsc-code:sync`、`jsc-gitea:repo-sync`):只留 `jsc-gitea:repo-sync` 那一半,`jsc-code:sync` 那一半移除。
|
||||
- **M-20**(TODO.md 第 934 行,`jsc-code:target` 跟助理待辦簿的關係要收攏成一套,還是只巡檢它的系統排程):這個問題本身不成立了。`jsc-code:target` 不在正本裡,助理的技能清單與委派判定清單都碰不到它,不會被觸發,也就沒有「兩份待辦互不知道」的風險。這一項直接關閉,不必再往下決議要收攏還是只巡檢。
|
||||
|
||||
`plugins/persona`、`plugins/shared` 沒有被 TODO.md 那份 E 表任何一列引用,純粹是盤點時發現的閒置存取庫,記下「維持獨立、不納入」即可,不需要再對 E 表或委派判定清單做任何修正。
|
||||
|
||||
**例子**:`meta/tools/delegate-spec.tsv` 現有 35 列,範圍剛好卡在 `ask` 到 `sdlc`,不含 `code`、`code-review`、`doc`、`persona`、`shared` 五個 domain 的任何一支技能——這份檔案本來就是決議之後該有的樣子,不必動它。要改的是 TODO.md 裡那份 E 表:核對 E-13 到 E-16、M-20 這五列,照上面的方式移除或裁半,不必再往回加東西,也不必幫已刪的那一半補回來。
|
||||
|
||||
**不是價值判斷**:五個存取庫都是完整、能動的系統,不納入正本不代表它們沒用或做得不好。`persona` 是另一條產品線,人格化聊天跟 SDLC 開發流程沒有交集;`shared` 是跨助理共用規格技能,服務對象是所有助理而不是單一 SDLC 流程;`code`、`doc`、`code-review` 三個雖然功能上跟 jsc 技能組相近(都碰 Gitea、都碰程式碼),但各自的呼叫方式、維運節奏、目標使用情境都不同,例如 `code-review` 連呼叫前綴都還是舊的 `jsc:`,跟正本裡 `jsc-review` 的互動式流程本來就是兩套設計。維持獨立系統,讓 jsc 技能組正本只收它管得到、巡檢得到的技能,才是對的做法。
|
||||
|
||||
## 跟 `wp01-todo-corrections.md` 的分工
|
||||
|
||||
這份文件收十項技術定案跟 F-01 決議,都是這一輪盤點裡定下來、可以直接引用的規格內容。
|
||||
|
||||
`TODO.md` 的狀態校正另外放在 [`wp01-todo-corrections.md`](wp01-todo-corrections.md),不併進這份文件;不能開 PR 的完整理由見該文件開頭。
|
||||
@@ -0,0 +1,43 @@
|
||||
# TODO.md 狀態校正清單
|
||||
|
||||
## 為什麼這份不走 PR
|
||||
|
||||
`/root/plugins/TODO.md` 不在任何 git 存取庫底下。`/root/plugins` 本身不是 git 存取庫,`.git` 底下只有空的 `info/`。沒有存取庫,就沒有地方可以開分支、送 commit、開 PR。
|
||||
|
||||
因此這份校正只能整理成清單,交給使用者參考。實際的檔案修改要靠使用者手動打開 `TODO.md`,對照下面的編號逐行更新。
|
||||
|
||||
這份清單分兩節:第一節是十五項狀態校正,第二節是五項數字更新。兩節的來源都是同一輪盤點(2026-09-07,分析頁「核對結果:TODO.md 有 15 項狀態過期」與後面那段五項數字敘述),11 個存取庫各自以 `origin/develop` 為準逐一核對得出。
|
||||
|
||||
## 第一節:十五項狀態校正
|
||||
|
||||
15 項待辦裡,TODO.md 記的狀態跟實際狀態對不上。其中六項(F-06、W-04、R-04、G-02、G-03、G-07)是「早就做完卻還記著未動工」——照舊表動工會做白工,這六項要優先改。其餘九項是「部分完成」,TODO.md 記著未動工,實際已經做了一部分,剩下的落差寫在證據欄裡。
|
||||
|
||||
| 編號 | TODO.md 原記 | 實際狀態 | 證據 |
|
||||
| --- | --- | --- | --- |
|
||||
| F-06 | `[ ]` 未動工 | 已完成 | `hooks/comment-scope.sh:91` 已含三種頁型 |
|
||||
| W-04 | `[ ]` 未動工 | 已完成 | `hooks/templates/error-contents.md:13` 起已是條列 |
|
||||
| R-04 | `[ ]` 未動工 | 已完成 | `wire-cli.sh:1394-2270`,十類 140 條自我斷言,五支 CLI 各有路徑 |
|
||||
| G-02 | `[ ]` 未動工 | 已完成 | `issue.sh:81-88` 只列既有標籤,`90-103` 對不到就回 4 |
|
||||
| G-03 | `[ ]` 未動工 | 已完成 | `issue.sh:202-204` 空集合就不寫進 payload |
|
||||
| G-07 | `[ ]` 未動工 | 已完成 | `wiki-to-issue/SKILL.md:25` 完成條件已要求回報實際標籤 |
|
||||
| W-02 | `[ ]` 未動工 | 部分完成 | `wiki-contents.sh:268-293` 的 `format` 子命令已是共用轉檔唯一實作 |
|
||||
| W-05 | `[ ]` 未動工 | 部分完成 | `wiki-contents.sh:168-174` 取不出鍵就中止(不猜已在),差頁型對照表 |
|
||||
| W-06 | `[ ]` 未動工 | 部分完成 | `check-contents-format.sh` 已在,但驗的是暫存檔,不是真實頁面 |
|
||||
| F-04 | `[ ]` 記六種缺庫 | 部分完成 | 站台已有 10 個 `knowledges/` 庫,只缺 LEARN、ERROR、REPORT、TOOLING、MAINTAIN 五種 |
|
||||
| F-05 | `[ ]` 未動工 | 部分完成 | `gitea.sh:70` 已指名要設哪個變數並回 3。新缺失:那句訊息是英文,還沒改成中文 |
|
||||
| N-08 | `[ ]` 未動工 | 部分完成 | `migrate-wiki.sh` 已在,且認兩代舊演算法,差第 150 行 `WANT` 沒有「計畫名稱」候選鍵 |
|
||||
| A-11 | `[ ]` 未動工 | 部分完成 | `analyze/SKILL.md:43` 內文已要求每則待辦寫出驗收依據,缺的只有程式化擋關 |
|
||||
| R-01 | `[ ]` 未動工 | 部分完成 | 三段抽出一段(`deploy-verify.md`),剩兩段仍逐字重複,其中一段 23 行四份相同(`skill-new/SKILL.md:68-90` 的「結束碼」路由表) |
|
||||
| F-03 | `[ ]` 記帶過期清單 | 部分完成 | `plugins/jsc` 兩份 marketplace 與正本 `diff` 為空,已於 2026-09-01 手動對齊。「過期」這個說法不成立,但去向仍未定 |
|
||||
|
||||
## 第二節:五項數字更新
|
||||
|
||||
以下五項是 TODO.md 裡記的數字跟現況對不上,不牽涉狀態欄,只是數字本身要改。
|
||||
|
||||
| 項目 | TODO.md 原記 | 實際數字 |
|
||||
| --- | --- | --- |
|
||||
| `wire-cli.sh` 總行數 | 2629 行 | 2860 行 |
|
||||
| `implement/SKILL.md` 總行數 | 113 行 | 162 行 |
|
||||
| `skill-check` 的 `description` 字元數 | 819 字元 | 1318 字元 |
|
||||
| `delegate-spec.tsv` 裡 `probe` 欄未接線(`pending`)支數 | 7 支 | 8 支 |
|
||||
| `jsc-assist` 的 `jsc.requires` 項數 | 4 項 | 5 項 |
|
||||
+20
-11
@@ -1,6 +1,6 @@
|
||||
---
|
||||
name: skill-check
|
||||
description: Routine compliance, script, hook, flow-efficiency, and cost-efficiency audit of the whole jsc skill set with no change request in hand. Sync every domain repo from the Gitea canonical marketplace, then run three parallel groups - lint-scripts.sh plus lint-frontmatter.sh plus check-behaviors.sh plus ste100-lint.sh plus check-link-format.sh plus check-wiki-rules.sh plus check-page-name.sh plus hook smoke, the guidelines.md checklist audit, and an optimization review that first reads each domain's SKILLSET_{HASH} so suggestions already applied or deferred are never re-scanned or re-asked, then covers parallelism, tool extraction, repeated interaction, redundant checks, misplaced gates, and avoidable token, sub-agent, API, scan, or interaction cost. Confirm compliance fixes and optimization suggestions before applying them, recording each decision with its date, re-check until accepted fixes pass, then open a PR per affected repo via jsc-git pr. Close by appending the round's result to every changed domain's SKILLSET_{HASH} and its SKILLSET_CONTENTS block, or to the plugins/meta page when no domain was changed. Use for periodic or on-demand skill-set checks; not for applying a change request (use skillset-update) or editing one skill (use skill-update).
|
||||
description: Routine compliance, script, hook, flow-efficiency, and cost-efficiency audit of the whole jsc skill set with no change request in hand. Sync every domain repo from the Gitea canonical marketplace, then run three parallel groups - lint-scripts.sh plus lint-frontmatter.sh plus check-behaviors.sh plus ste100-lint.sh plus check-link-format.sh plus check-wiki-rules.sh plus check-page-name.sh plus check-delegate.sh plus check-skill-paths.sh plus hook smoke, the guidelines.md checklist audit, and an optimization review that first reads each domain's SKILLSET_{HASH} so suggestions already applied or deferred are never re-scanned or re-asked, then covers parallelism, tool extraction, repeated interaction, redundant checks, misplaced gates, and avoidable token, sub-agent, API, scan, or interaction cost. Confirm compliance fixes and optimization suggestions before applying them, recording each decision with its date, re-check until accepted fixes pass, then open a PR per affected repo via jsc-git pr. Close by appending the round's result to every changed domain's SKILLSET_{HASH} and its SKILLSET_CONTENTS block, or to the plugins/meta page when no domain was changed. Use for periodic or on-demand skill-set checks; not for applying a change request (use skillset-update) or editing one skill (use skill-update).
|
||||
---
|
||||
|
||||
# skill-check — audit compliance, flow efficiency, and cost efficiency
|
||||
@@ -14,7 +14,7 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
||||
The three review groups of step 2 all read this synced tree, so the sync finishes first.
|
||||
2. Run the three review groups over the synced repos. They are independent — every one only reads, none writes a file — so **launch all three in parallel** and merge their results in step 3.
|
||||
|
||||
**Group 1 — validate scripts, frontmatter, behavior lists, language, wiki rules, page names, and hooks.**
|
||||
**Group 1 — validate scripts, frontmatter, behavior lists, language, wiki rules, page names, the delegation list, and hooks.**
|
||||
1. For every synced domain repo, run `tools/lint-scripts.sh {domain-path}`. One run per domain, and the runs go **in parallel** — no domain's verdict depends on another's. The tool covers three checks in one pass: `sh -n` syntax, executable bit, and an exit-code declaration in the file header. Route each exit code: 0 — the domain's scripts pass all three; 1 — the failing items are printed as `{file}:{check}:{detail}`, so report each one; 2 — usage error, the tool takes exactly one argument; 3 — nothing was scanned, because the path is missing or the domain has neither `tools/` nor `hooks/`. Record exit 3 as 「無腳本可掃」; a domain with no script directory is not a failure, but exit 3 is **never** a pass.
|
||||
2. For every synced domain repo, run `tools/lint-frontmatter.sh {domain-path}`. One run per domain, and the runs go **in parallel** alongside the `lint-scripts.sh` runs. It parses the frontmatter of every `skills/*/SKILL.md` without a YAML library — paired `---` delimiters, the required `name` and `description` keys, unquoted scalars carrying a colon-space or ending in a colon, unquoted scalars opening with `&`, `*`, `!`, `|`, `>`, `%`, `@` or a backtick, and quoted scalars that never close. Route each exit code: 0 — every SKILL.md in that domain parses; 1 — the failures are printed on stderr as `{檔案}:{鍵}:{說明}`, so report every one as a compliance failure with the file and key it belongs to; 2 — usage error, the tool takes exactly one argument; 3 — nothing was scanned, because the domain path or `skills/` is missing, or `skills/` holds no `SKILL.md`. Record exit 3 as 「無 frontmatter 可掃」with the cause from stderr and carry it into the step 3 merge; exit 3 is **never** a pass. This check exists because a broken frontmatter makes Antigravity drop the whole skill with **no error message at all** — 34 skills on disk loaded as 28, and only a file-by-file comparison found it.
|
||||
3. For every synced domain repo, run `tools/check-behaviors.sh {domain-path}`. One run per domain, and the runs go **in parallel** alongside the `lint-scripts.sh` runs — no domain's verdict depends on another's. It compares `references/behaviors.md` against `skills/`: section per skill, dictionary order, one table per section, five rows, no empty content cell. Route each exit code: 0 — that domain's behavior list matches; 1 — the mismatches are printed on stderr as `{檔案}:{技能名}:{說明}`, so report every one as a compliance failure with the skill it belongs to; 2 — usage error, the tool takes exactly one argument; 3 — nothing was checked, because `references/behaviors.md` is missing, `skills/` is missing, or no `SKILL.md` was found. Record exit 3 as 「無清單可查」with the cause from stderr and carry it into the step 3 merge; a domain with no behavior list is a compliance failure, and exit 3 is **never** a pass.
|
||||
@@ -23,9 +23,17 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
||||
6. Run the two wiki-rule checkers once each, not per domain — both judge shared rules, so a second run adds nothing:
|
||||
- `jsc-gitea/tools/check-wiki-rules.sh`, which verifies wiki repo resolution and the `hash-id` rule for every page type. It takes no argument. Route each exit code: 0 — printed `OK` on stdout, every item passed; 1 — the first mismatch is printed on stderr as `{項目}: want=… got=…` and the script stops there, so report that item and rerun after the fix, because the remaining items were never reached. Those are its only two codes. Until this audit, no flow in the whole repository ever called it.
|
||||
- `tools/check-page-name.sh {root}`, where `{root}` is the directory holding the domain repos — the parent directory of the paths `tools/sync-domains.sh` printed in step 1, so no extra derivation is needed. It compares the page-name pattern in its three copies: `jsc-gitea/tools/page-name.sh` (the canonical one), `jsc-hooks/hooks/comment-scope.sh` and `jsc-log/tools/worklog-pending.sh`. Route each exit code: 0 — the three agree; 1 — the mismatches are printed on stderr as `{檔案}:{說明}`, so report each one as a compliance failure, and a copy that could not be found is one of those lines; 2 — usage error, the tool takes exactly one argument; 3 — none of the three copies was found, so the root is wrong: fix it and rerun. Record exit 3 as 「什麼都沒查」; it is **never** a pass. The three copies stay separate on purpose — a hook must be self-contained and may not depend on another plugin's path at run time — so consistency is checked here instead of shared in a function.
|
||||
7. For every shell script directly named by a SKILL.md, confirm the skill routes every exit code the script's header declares. `lint-scripts.sh` proves the script exists and declares its codes; this check is the other half — that the caller branches on each of them. Report evidence as `skill file:line -> script path`.
|
||||
8. When the `jsc-hooks` domain is present, run `jsc-hooks/tools/wire-cli.sh smoke {cli}` for every CLI reported by `jsc-cli/tools/detect-clis.sh`; the per-CLI smokes run **in parallel**. When no CLI is detected, run `jsc-hooks/tools/wire-cli.sh smoke codex` as the minimum hook behavior check and label it 「預設 hook smoke」 in the report. Use `smoke`, not `purge` or rewiring actions, and set `JSC_READONLY=1` for the whole audit so a mistyped sub-command is refused in code (exit 6) instead of rewiring the machine; `status` and `smoke` are unaffected by that variable. Route each `smoke` exit code: 0 — the run passed its own assertions; 2 — usage error, so fix the CLI code and rerun; 4 — the smoke failed, which includes the script's own result-line count not matching what it expected. **Read the count from the script's `lines<TAB>{數量}` output line; never write the number into this skill.** The script counts its own result lines and asserts them, so a hardcoded number here goes stale the moment a hook or a decision path is added — an out-of-date count in a SKILL.md is exactly what misled the previous audit.
|
||||
9. When a hook or script smoke fails, route it as a compliance failure with script name, exit code, output summary, and proposed fix. Do not continue to report the affected hook as compliant.
|
||||
7. Run `tools/check-delegate.sh {root}` once for the whole round, with the same `{root}` item 6 passed to `check-page-name.sh`. It compares the delegation list `tools/delegate-spec.tsv` against the skills `tools/list-skills.sh` finds on this machine: one skill one row, twelve columns, every mandatory column filled, every `next` naming a skill that exists, and every `probe` either a runnable read-only command, a `pending:{reason}`, or a `-` on the rows that take one. It belongs in group 1 for the same reason `ste100-lint.sh` does — it is a deterministic script verdict, and it is judged **once for the whole round** rather than per domain, because the list is a single file covering every domain. Handing it to the group 2 sub agents would have ten agents run the same script over the same file and report ten copies of the same lines, with no single verdict anywhere; handing it to group 3 would turn a pass-or-fail check into a suggestion. Route each exit code:
|
||||
- 0 — the list and the machine's skills correspond one to one and every mandatory column is filled. **A run that printed lines on stdout and exited 0 passed.** Those lines are hints, not compliance failures, and they are printed on stdout precisely so they are told apart from the failures on stderr: `origin=seed` marks a row seeded from the earlier inventory that has not been through the decision tree yet, a version-behind line marks a row whose recorded `version` trails its domain's current one, a `probe=pending:` line marks a delegated slice whose read-only entry point is not wired yet, and a line saying a `probe` domain is not installed here marks a script this machine cannot check. The version number is per domain, so one skill's change marks every other skill of that domain — counting those as failures paints whole domains red on every release, and the hint stops being read at all. Report the hint count and the rows, and open no decision-tree item for them.
|
||||
- 1 — a missing row, a duplicate row, a row for a skill this machine does not have, an empty column, a column value outside its vocabulary, a `next` naming a skill that does not exist, or a `probe` in the wrong shape — a command on a row whose `way` holds `invoke`, a `-` on a row whose `way` holds only `patrol` or `remind`, a dollar sign or tilde, an unknown substitution point, or a script that does not exist. Every one is printed on stderr as `{清單路徑}:{domain}/{技能名}:{說明}`. Report each as a compliance failure, named by the skill it belongs to. A missing row means the assistant is blind to that skill; an extra row means it will trigger a skill that cannot be called, and a failing trigger retries instead of pausing. A wrong `probe` fails every unattended round in the same silent way, and the command-on-an-`invoke`-row case is worse than a failure: the assistant runs a bare script where the whole skill was supposed to run, and the round looks clean.
|
||||
- 2 — usage error: the script takes at most one argument. Fix the call and rerun; this is a defect in this skill, not a finding about the skill set.
|
||||
- 3 — nothing was checked, because `tools/delegate-spec.tsv` is missing, the root could not be derived, or `list-skills.sh` listed no skill. Record it as 「無委派清單可查」 with the cause from stderr and carry it into the step 3 merge; **exit 3 is never a pass**, because a check that read nothing reports neither a missing row nor an extra one.
|
||||
|
||||
This verdict is **not** one of the guidelines.md audit-checklist items, so it stays out of the nine that step 3 merges into every domain's checklist and is reported on its own line, one line for the round.
|
||||
8. For every synced domain repo, run `tools/check-skill-paths.sh {domain-path}`. One run per domain, and the runs go **in parallel** alongside the other group 1 per-domain runs. It reads every `skills/*/SKILL.md` and `references/*.md` and resolves each `tools/…` or `hooks/…` script path written in them. `lint-scripts.sh` proves a script exists inside its own repo; this one proves the path as written reaches it. Route each exit code: 0 — no path in that domain points at a file that is not there, and the hint lines it printed are counted separately from failures; 1 — the `missing` lines name paths that resolve to nothing, so report each as a compliance failure with its file and line; 2 — usage error, the tool takes exactly one argument; 3 — nothing was scanned, because the domain path is missing or it has neither `skills/*/SKILL.md` nor `references/*.md`. Record exit 3 as 「無文件可掃」; exit 3 is **never** a pass. Its `unrooted` and `unknown` lines are hints, never failures — `unrooted` marks a path with no plugin directory name, which resolves against whatever the current directory happens to be, and `unknown` marks a cross-domain path whose repo is not on this machine. Carry the two hint counts into the report without turning them into decision-tree items: the whole skill set carries hundreds of `unrooted` paths, and promoting them to failures would turn every domain red at once, which reads the same as no report at all. This check exists because item 9 below was already supposed to catch this and could not: a human reading item 9 checks that the named script exists in `tools/`, which it does, and never asks whether the path as written reaches it — so the same defect passed review every round until a path exited 127 in front of someone. This verdict is **not** one of the guidelines.md audit-checklist items either, so it stays out of the nine that step 3 merges into every domain's checklist and is reported on its own line, one line per domain.
|
||||
9. For every shell script directly named by a SKILL.md, confirm the skill routes every exit code the script's header declares. `lint-scripts.sh` proves the script exists and declares its codes; this check is the other half — that the caller branches on each of them. Report evidence as `skill file:line -> script path`.
|
||||
10. When the `jsc-hooks` domain is present, run `jsc-hooks/tools/wire-cli.sh smoke {cli}` for every CLI reported by `jsc-cli/tools/detect-clis.sh`; the per-CLI smokes run **in parallel**. When no CLI is detected, run `jsc-hooks/tools/wire-cli.sh smoke codex` as the minimum hook behavior check and label it 「預設 hook smoke」 in the report. Use `smoke`, not `purge` or rewiring actions, and set `JSC_READONLY=1` for the whole audit so a mistyped sub-command is refused in code (exit 6) instead of rewiring the machine; `status` and `smoke` are unaffected by that variable. Route each `smoke` exit code: 0 — the run passed its own assertions; 2 — usage error, so fix the CLI code and rerun; 4 — the smoke failed, which includes the script's own result-line count not matching what it expected. **Read the count from the script's `lines<TAB>{數量}` output line; never write the number into this skill.** The script counts its own result lines and asserts them, so a hardcoded number here goes stale the moment a hook or a decision path is added — an out-of-date count in a SKILL.md is exactly what misled the previous audit.
|
||||
11. When a hook or script smoke fails, route it as a compliance failure with script name, exit code, output summary, and proposed fix. Do not continue to report the affected hook as compliant.
|
||||
|
||||
**Group 2 — audit every skill of every domain against the guidelines.md audit checklist.** This group MUST run as a sub agent, one sub agent per domain repo, and those sub agents run **in parallel**. Each sub agent reports its findings: skill, failed checklist item, evidence (file:line), proposed fix. Cover the checklist's four flow checks by name, not only the naming and language items:
|
||||
- Every step number, file path and section title the skill references — inside itself and in other files — really exists (the pointer points at something).
|
||||
@@ -71,13 +79,14 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
||||
|
||||
Each optimization finding reports skill, aspect, evidence (file:line), current flow step count, proposed flow step count, what time or interaction it saves, what cost it saves, current cost driver, proposed cost driver, whether correctness decreases, which protection would be weakened if any, the **決議** (`套用`, `延後` or `自訂`) recorded in step 3, and the **決議日期** that decision was made. The last two fields start empty and are filled in by step 3; they are what step 8 writes to the wiki and what the next round reads back, so a finding that reaches step 8 with either field empty is unfinished, not optional. Cost savings may be token volume, sub-agent count, API calls, file scans, full-repo audits, or user prompts. Keep optimization findings separate from compliance failures.
|
||||
|
||||
Completion condition for all three groups: every domain has a `lint-scripts.sh` verdict, a `lint-frontmatter.sh` verdict, a `check-behaviors.sh` verdict, an `ste100-lint.sh` verdict and a `check-link-format.sh` verdict, `check-wiki-rules.sh` and `check-page-name.sh` each have one verdict for the whole run, every script named by a SKILL.md has an exit-code-routing verdict, and every smoked CLI has a `smoke` exit code plus the `lines` value the script printed for it; every domain has a group 2 audit result that names a verdict for all checklist items — the four flow checks included, and the nine group 1 items left blank for the step 3 merge rather than re-scanned; and every one of the six aspects has returned a verdict for every domain whose settled list was read, 「無發現」 where an aspect found nothing and every settled entry of that domain excluded rather than re-reported — a domain whose pre-read failed carries 「本輪未取得已決議清單,優化建議暫不提出」 instead, and that sentence is a complete group 3 result for it.
|
||||
Completion condition for all three groups: every domain has a `lint-scripts.sh` verdict, a `lint-frontmatter.sh` verdict, a `check-behaviors.sh` verdict, an `ste100-lint.sh` verdict, a `check-link-format.sh` verdict and a `check-skill-paths.sh` verdict — the last one carrying its `unrooted` and `unknown` hint counts separately from its failures — `check-wiki-rules.sh`, `check-page-name.sh` and `check-delegate.sh` each have one verdict for the whole run — `check-delegate.sh` carrying its hint lines separately from its failures, or 「無委派清單可查」 where it exited 3 — every script named by a SKILL.md has an exit-code-routing verdict, and every smoked CLI has a `smoke` exit code plus the `lines` value the script printed for it; every domain has a group 2 audit result that names a verdict for all checklist items — the four flow checks included, and the nine group 1 items left blank for the step 3 merge rather than re-scanned; and every one of the six aspects has returned a verdict for every domain whose settled list was read, 「無發現」 where an aspect found nothing and every settled entry of that domain excluded rather than re-reported — a domain whose pre-read failed carries 「本輪未取得已決議清單,優化建議暫不提出」 instead, and that sentence is a complete group 3 result for it.
|
||||
3. Merge the three groups, then present compliance failures and optimization findings separately via the `jsc-ask:ask` decision tree. Merging means one thing in code: fill the nine skipped checklist items of every group 2 sub agent report from the matching group 1 verdicts, so each domain ends with one complete checklist and no item counted twice. Seven of the nine are per-domain verdicts, one domain to one item. The other two — `check-page-name.sh` and `check-wiki-rules.sh` — are judged **once for the whole round**, and that one verdict goes into that same item of **every** domain's checklist; re-judging a whole-round item per domain is precisely the double counting this merge exists to stop. A domain that group 3 marked 「本輪未取得已決議清單,優化建議暫不提出」 still gets its full compliance checklist here; only its optimization findings are missing, and the merge report says so.
|
||||
- Compliance failure options: apply the proposed fix / skip / custom fix. Every option states its impact scope, for example skipping leaves the skill non-compliant until the next audit.
|
||||
- The `check-delegate.sh` failures join that same set, one decision-tree item per reported row, and they carry one extra note in their impact scope: fixing a missing row means running the delegation decision tree of [`../../references/delegate-criteria.md`](../../references/delegate-criteria.md) for that skill in step 4, which is more questions than most fixes. Its **hint** lines never become decision-tree items — a hint is a note about a row that is already there, and turning it into a question re-asks a settled judgement every round, which is the 「重複來回」 group 3 exists to catch.
|
||||
- Optimization options: apply / defer / custom. Record the chosen option in the finding's 決議 field as `套用`, `延後` or `自訂`, and today's date in 決議日期. Any suggestion that weakens a protection must name the protection it removes and must not be applied unless the user explicitly accepts that tradeoff. Cost optimization may move, merge, cache, or narrow checks; it must not delete a compliance check only because it is expensive.
|
||||
|
||||
Completion condition: every domain's checklist is complete after the merge, with the two whole-round verdicts carrying the same value in every domain, and every compliance failure and every optimization finding has a recorded decision — every optimization finding carrying both 決議 and 決議日期.
|
||||
4. Apply the confirmed fixes and accepted optimizations — the file-change part MUST run as a sub agent, one sub agent per affected domain repo, and those sub agents run **in parallel**: each repo's files are independent. A fix that changes a skill's behavior also updates that skill's `## {name}` section in the same repo's `references/behaviors.md`, in the same pass, so the fix and the behavior list land in one PR. Then run `tools/sync-skill-manifest.sh {domain-path}` directly (no sub agent needed) for each affected domain repo to refresh that domain README's 「Skills 目錄」 section and bump the version in all three manifests. Route each exit code: 0 — the README block and all three manifests are synced; 1 — the domain path, `skills/`, `README.md`, the `JSC-SKILLS` markers, a `SKILL.md`, a manifest, or a manifest `version` field is missing, so fix the named cause on stderr and rerun; 2 — usage error, the script takes exactly one argument; any other code — the script runs under `set -e`, so treat it as an environment fault and stop, never as a successful sync. Completion condition: every affected repo carries the changes, the matching `references/behaviors.md` update for every fix that changed a skill's behavior, and the manifest bump.
|
||||
4. Apply the confirmed fixes and accepted optimizations — the file-change part MUST run as a sub agent, one sub agent per affected domain repo, and those sub agents run **in parallel**: each repo's files are independent. A fix that changes a skill's behavior also updates that skill's `## {name}` section in the same repo's `references/behaviors.md`, in the same pass, so the fix and the behavior list land in one PR. A confirmed `check-delegate.sh` fix is written by the **main agent**, never by the per-repo sub agents: `tools/delegate-spec.tsv` is one file for the whole skill set, and parallel agents writing one file overwrite each other's rows. A missing row is filled by running the decision tree of [`../../references/delegate-criteria.md`](../../references/delegate-criteria.md) for that skill through `jsc-ask:ask` and writing the answer as a row with `origin` set to `judged`; an extra row is deleted; a dead `next` is repointed at a skill that exists; a wrong `probe` is rewritten per that same file — verified against the owning repo, not guessed — and set to `pending:{reason}` when the slice has no read-only entry point on this machine. A fix that changed a skill's behavior in this same round also re-judges that skill and moves its row's `version`. Then run `tools/sync-skill-manifest.sh {domain-path}` directly (no sub agent needed) for each affected domain repo to refresh that domain README's 「Skills 目錄」 section and bump the version in all three manifests. Route each exit code: 0 — the README block and all three manifests are synced; 1 — the domain path, `skills/`, `README.md`, the `JSC-SKILLS` markers, a `SKILL.md`, a manifest, or a manifest `version` field is missing, so fix the named cause on stderr and rerun; 2 — usage error, the script takes exactly one argument; any other code — the script runs under `set -e`, so treat it as an environment fault and stop, never as a successful sync. Completion condition: every affected repo carries the changes, the matching `references/behaviors.md` update for every fix that changed a skill's behavior, the `tools/delegate-spec.tsv` rows for every accepted delegation fix, and the manifest bump.
|
||||
5. Sync the canonical marketplace — a **required** step, never optional. The canonical pair lives in `plugins/meta` and every domain repo carries a byte-identical copy, so a fix that leaves the copies apart makes some repos register a stale plugin set. Run `tools/sync-marketplace.sh {domain} {repo-url} {description}` once with an existing entry's own current values (rewriting the same entry is idempotent); the script rewrites both canonical files and copies them into every domain repo. Route each exit code:
|
||||
- Exit 3 — written, but some domain repo is not present locally. Run `tools/sync-domains.sh`, then rerun this step.
|
||||
- Exit 2 — usage error: the script takes exactly three arguments. Fix them and rerun.
|
||||
@@ -85,7 +94,7 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
||||
- Exit 0 — every copy holds identical bytes; the script verifies that itself.
|
||||
|
||||
Completion condition: the script exits 0 and prints the touched paths.
|
||||
6. Re-run the group 1 script, frontmatter, behavior-list, language, link-format, wiki-rule, page-name and hook validation, re-check the guidelines.md audit checklist for every touched skill, then re-run the optimization aspect that produced each accepted optimization. These three re-runs are as independent as the first pass, so run them **in parallel** and merge them the same way step 3 did. On any compliance failure, **return to step 3**: confirm and fix again, until all accepted compliance fixes pass. On an accepted optimization that does not produce the promised step reduction or cost reduction, or still weakens correctness beyond the recorded decision, return to step 3 for a new decision. Completion condition: `tools/lint-scripts.sh` exits 0 or 3 for every domain, `tools/lint-frontmatter.sh` exits 0 for every domain — exit 3 is 「什麼都沒掃」 and never counts as a pass — `tools/check-behaviors.sh` exits 0 for every domain, `tools/ste100-lint.sh` exits 0 for every domain, `tools/check-link-format.sh` exits 0 for every domain — its exit 3 is 「什麼都沒掃」 and never counts as a pass — `jsc-gitea/tools/check-wiki-rules.sh` exits 0, `tools/check-page-name.sh` exits 0 — its exit 3 is 「什麼都沒查」 and never counts as a pass — every hook smoke exits 0 with the `lines` count the script itself asserted, every domain's checklist passes in full — the two whole-round verdicts filled into each domain from the one run that produced them — and every accepted optimization has a matching verification result.
|
||||
6. Re-run the group 1 script, frontmatter, behavior-list, language, link-format, script-path, wiki-rule, page-name, delegation-list and hook validation, re-check the guidelines.md audit checklist for every touched skill, then re-run the optimization aspect that produced each accepted optimization. These three re-runs are as independent as the first pass, so run them **in parallel** and merge them the same way step 3 did. On any compliance failure, **return to step 3**: confirm and fix again, until all accepted compliance fixes pass. On an accepted optimization that does not produce the promised step reduction or cost reduction, or still weakens correctness beyond the recorded decision, return to step 3 for a new decision. Completion condition: `tools/lint-scripts.sh` exits 0 or 3 for every domain, `tools/lint-frontmatter.sh` exits 0 for every domain — exit 3 is 「什麼都沒掃」 and never counts as a pass — `tools/check-behaviors.sh` exits 0 for every domain, `tools/ste100-lint.sh` exits 0 for every domain, `tools/check-link-format.sh` exits 0 for every domain — its exit 3 is 「什麼都沒掃」 and never counts as a pass — `tools/check-skill-paths.sh` exits 0 for every domain — its exit 3 is 「什麼都沒掃」 and never counts as a pass, and its `unrooted` and `unknown` lines stay hints rather than becoming failures — `jsc-gitea/tools/check-wiki-rules.sh` exits 0, `tools/check-page-name.sh` exits 0 — its exit 3 is 「什麼都沒查」 and never counts as a pass — `tools/check-delegate.sh` exits 0, its remaining stdout lines counted as hints rather than failures and its exit 3 read as 「無委派清單可查」 and never as a pass, every hook smoke exits 0 with the `lines` count the script itself asserted, every domain's checklist passes in full — the two whole-round verdicts filled into each domain from the one run that produced them — and every accepted optimization has a matching verification result.
|
||||
7. Call `jsc-git:pr` once per affected domain repo to open a Push Request. Completion condition: every affected repo has a PR URL, and all URLs are reported in one table with the format in [`../../references/pr-report.md`](../../references/pr-report.md).
|
||||
8. Write the round's result to the wiki. This step **MUST run as a sub agent**, one sub agent per affected domain repo, and those sub agents run **in parallel**: each domain writes its own page, and no page waits on another.
|
||||
|
||||
@@ -93,7 +102,7 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
||||
|
||||
- **Which page.** For every domain repo actually changed in this round, resolve `gitea.sh wiki-repo SKILLSET` and append one section to `SKILLSET_` plus `gitea.sh hash-id "{owner}/{repo}"` of that domain repo. Append; never overwrite — the page accumulates every change that domain has ever seen.
|
||||
- **When nothing changed.** No domain repo changed in this round means one page, hashed from `plugins/meta`, gets one section recording 「本輪無發現」 with the group verdicts that produced that conclusion. A round that found nothing still has to leave the evidence that it ran.
|
||||
- **What each section holds.** The layout is [`../../templates/skillset-page.md`](../../templates/skillset-page.md): date, change type `skill-check`, the change request in one sentence, the skills touched, the files changed, the PR URL from step 7, the deploy-route verdict and the verification result. The `skill-check` section additionally carries the 優化建議 table, every row filled including 決議 and 決議日期 — that table is exactly what the next round reads in step 2's group 3.
|
||||
- **What each section holds.** The layout is [`../../templates/skillset-page.md`](../../templates/skillset-page.md): date, change type `skill-check`, the change request in one sentence, the skills touched, the files changed, the PR URL from step 7, the deploy-route verdict and the verification result. A section for a round that wrote delegation rows also names the skills whose rows this round judged or repointed, so the row's own missing note column is covered here. The `skill-check` section additionally carries the 優化建議 table, every row filled including 決議 and 決議日期 — that table is exactly what the next round reads in step 2's group 3.
|
||||
- **Directory page.** Refresh that page's own block in `SKILLSET_CONTENTS` with `jsc-gitea/tools/wiki-contents.sh` — never by hand, and never through `jsc-gitea:wiki`. That page is a heading-plus-bullets list and holds no markdown table: one `## SKILLSET_{HASH}` block per domain repo, every field one `- {欄位名}:{值}` line under it. Build one file holding this domain's single block, following [`../../templates/skillset-contents.md`](../../templates/skillset-contents.md), then run:
|
||||
|
||||
`jsc-gitea/tools/wiki-contents.sh upsert SKILLSET 2 "SKILLSET_{HASH}" {entry file} templates/skillset-contents.md`
|
||||
@@ -140,10 +149,10 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
||||
|
||||
| status | Use it when |
|
||||
| --- | --- |
|
||||
| `ok` | every domain ended with a complete checklist, every accepted fix passed its re-check, every affected repo has a PR URL, and every wiki write exited 0 |
|
||||
| `ok` | every domain ended with a complete checklist, `check-delegate.sh` exited 0 for the round, every accepted fix passed its re-check, every affected repo has a PR URL, and every wiki write exited 0 |
|
||||
| `blocked` | a gate or a missing prerequisite stopped the round before anything was audited — `sync-domains.sh` never reached exit 0, or the call itself was refused |
|
||||
| `failed` | the round broke mid-way — a re-check in step 6 kept failing, or a wiki write failed again after its one retry |
|
||||
| `degraded` | the round finished with a part missing — a domain carries 「本輪未取得已決議清單,優化建議暫不提出」, or a content page was written while its `SKILLSET_CONTENTS` block was not |
|
||||
| `degraded` | the round finished with a part missing — a domain carries 「本輪未取得已決議清單,優化建議暫不提出」, the delegation check came back 「無委派清單可查」, or a content page was written while its `SKILLSET_CONTENTS` block was not |
|
||||
| `aborted` | the user stopped the round, or a prerequisite turned out not to hold and this skill stopped on its own |
|
||||
|
||||
`{exit code}` is this round's own result as a number: `0` for `ok`, non-zero otherwise. `detail` is optional, one line, at most 200 characters.
|
||||
|
||||
@@ -18,13 +18,25 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
||||
2. Ask for fix details via the `jsc-ask:ask` decision tree (call a replacement skill? move a deterministic input/output flow to `tools/`? run the detailed flow as a sub agent? drop the feature too?). If the fix touches wiki or Gitea access, confirm it reads inherited environment variables before asking the user. Every option states its impact scope. Completion condition: every question has a recorded answer.
|
||||
3. Apply the confirmed fix, then check the guidelines.md audit checklist for the file — the per-file fix work MUST run as a sub agent, one sub agent per affected domain repo, and those sub agents **run in parallel**: each repo's files are independent, so serialising them only adds waiting. Each sub agent reports one line per file: the path and either the applied fix or「無需修正」with the reason. On any checklist failure, return to step 5.2. Completion condition: the fix is in the file and every checklist item passes for it.
|
||||
|
||||
Completion condition: every file in the step 4 inventory is marked either fixed-with-a-clean-checklist or explicitly no-fix-needed with a reason — no file is left without a verdict.
|
||||
`jsc-meta/tools/delegate-spec.tsv` appears in that inventory as the row naming the skill. Mark it as handled in step 6 and edit it nowhere else: the row goes out there, together with the skill directory, and splitting the edit over two steps risks one of them removing a row the other still expects to be there.
|
||||
|
||||
Completion condition: every file in the step 4 inventory is marked either fixed-with-a-clean-checklist, explicitly no-fix-needed with a reason, or deferred to step 6 as the delegation list is — no file is left without a verdict.
|
||||
6. Delete the skill directory `skills/{name}/` and remove that skill's `## {name}` section from `references/behaviors.md` — the whole section, its table included, leaving every other section untouched. Both deletions ship in this same PR: a behavior list still carrying a deleted skill fails the domain's next audit, and the extra section is exactly what `check-behaviors.sh` reports. Then run `tools/sync-skill-manifest.sh {domain-path}` directly (no sub agent needed) to sync the domain README and bump the version in all three manifests. Route each exit code: 0 — the README block and all three manifests are synced; 1 — the domain path, `skills/`, `README.md`, the `JSC-SKILLS` markers, a remaining `SKILL.md`, a manifest, or a manifest `version` field is missing, so fix the named cause on stderr and rerun; 2 — usage error, the script takes exactly one argument; any other code — the script runs under `set -e`, so treat it as an environment fault and stop, never as a successful sync.
|
||||
|
||||
Delete that skill's row from `jsc-meta/tools/delegate-spec.tsv` in the same pass — that one row, every other row left byte for byte as it was. A list still carrying a deleted skill makes the background assistant trigger a skill that cannot be called, and a failing trigger does not pause itself: it retries every round, for good. Then repoint every remaining row whose `next` column named the deleted skill; those rows now name something that cannot be called either, and they are the second half of the same defect. In the same pass, check every remaining row's `probe` column against the files this deletion removed: a deletion that took a `tools/` script down with the skill leaves any row whose read-only command named that script pointing at nothing, and the assistant then fails that entry every round without ever pausing on it. Repoint such a row at a script that exists, or set it to `pending:{reason}` when this deletion left the slice with no read-only entry at all. The file lives in `plugins/meta` whichever domain lost the skill, so deleting a skill outside `meta` changes two repos and step 7 opens the second Push Request for this one.
|
||||
|
||||
**The task-book half is not wired yet.** [`../../references/delegate-criteria.md`](../../references/delegate-criteria.md) also asks this skill to drop the assistant task-book entries that name the deleted skill. That task book does not exist yet, so there is nothing to remove from and this skill does not go looking for it. When the task book ships, add that removal here as a step of its own. Until then, carry 「待辦簿引用尚未接線」 into the step 8.3 wiki section, so a later reader does not take this deletion as having cleaned a place it never touched.
|
||||
|
||||
Then run `tools/check-behaviors.sh {domain-path}` and route each exit code: 0 — the remaining sections match the remaining skills; 1 — every mismatch is printed on stderr as `{檔案}:{技能名}:{說明}`, so fix each one and rerun, the deleted skill's leftover section included; 2 — usage error, the tool takes exactly one argument; 3 — nothing was checked, because `references/behaviors.md` is missing, `skills/` is missing, or no `SKILL.md` was found, so fix the named cause and rerun. **Exit 3 is never a pass.**
|
||||
|
||||
Completion condition: the directory is gone, `references/behaviors.md` holds no `## {name}` section for the deleted skill, `tools/check-behaviors.sh {domain-path}` exits 0, the README's 「Skills 目錄」 no longer lists the skill, and all three manifests show the same new version.
|
||||
7. Call `jsc-git:pr` to open a Push Request. Completion condition: a PR URL comes back and is reported with the table format in [`../../references/pr-report.md`](../../references/pr-report.md).
|
||||
Then run `tools/check-delegate.sh`. It takes the plugins root, not a domain path, and the list is one file covering every domain, so it runs **once for the whole flow**. Route each exit code:
|
||||
- 0 — the list matches the skills on this machine and every mandatory column is filled; the deleted skill has no row left, and no surviving row points at it. **A run that printed lines on stdout and exited 0 still passed.** Those lines are hints, not defects: `origin=seed` marks a row seeded from the earlier inventory and awaiting review, and a version-behind line marks a row whose `version` trails its domain's current one, a `probe=pending:` line marks a delegated slice whose read-only entry point is not wired yet, and a line saying a `probe` domain is not installed here marks a script this machine cannot check, which every skill of the domain this deletion just bumped will now show. Report them as hints and fix nothing for them; a deletion held open over a version-behind line would never close.
|
||||
- 1 — a row remains for a skill this machine no longer has, a surviving row's `next` points at the deleted skill, or a surviving row's `probe` points at a script this deletion removed. All three are printed on stderr as `{清單路徑}:{domain}/{技能名}:{說明}` — the first is the row this step was supposed to remove, the second is a `next` this step was supposed to repoint, the third a `probe` this step was supposed to repoint or set to `pending:{reason}`. Fix each and rerun.
|
||||
- 2 — usage error: the script takes at most one argument. Fix the call and rerun.
|
||||
- 3 — nothing was checked, because `tools/delegate-spec.tsv` is missing, the root could not be derived, or `list-skills.sh` listed no skill. Read stderr and fix the named cause; set `JSC_PLUGINS_ROOT` to the directory holding the domain repos for the root case, as in step 1. **Exit 3 is never a pass** — a check that looked nowhere reports no leftover row either.
|
||||
|
||||
Completion condition: the directory is gone, `references/behaviors.md` holds no `## {name}` section for the deleted skill, `tools/delegate-spec.tsv` holds no row for it and no `next` naming it, `tools/check-behaviors.sh {domain-path}` and `tools/check-delegate.sh` both exit 0, the README's 「Skills 目錄」 no longer lists the skill, and all three manifests show the same new version.
|
||||
7. Call `jsc-git:pr` to open a Push Request. When the deleted skill lived in a domain other than `meta`, the `tools/delegate-spec.tsv` removal is a change to `plugins/meta` and needs its own Push Request against that repo — two repos changed, two PRs, neither waiting on the other. Completion condition: a PR URL comes back for every repo this run changed, `plugins/meta` included when the row was removed there, and each is reported with the table format in [`../../references/pr-report.md`](../../references/pr-report.md).
|
||||
8. Deploy the deletion, verify it took, then report:
|
||||
1. Follow [`../../references/deploy-verify.md`](../../references/deploy-verify.md) from section 1 to section 5: `tools/deploy-route.sh {domain-path}` picks the route, the deploy route or the worktree route runs, and the verification then runs in a **fresh CLI process**, never in the session that ran the deploy. That session raised the restart gate itself and still holds the old skill set, so verifying inside it either gets blocked or passes on stale behavior. On the worktree route, add that the skill stays installed and stays callable until the outstanding release PR merges. Completion condition: every completion condition in `deploy-verify.md` sections 1 to 5 holds for this domain repo.
|
||||
2. Verify the deletion concretely, on top of the `deploy-verify.md` items:
|
||||
@@ -35,7 +47,7 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
||||
|
||||
On any mismatch — the deleted skill still listed, a leftover from exit 1, a fixed caller that now fails, a prompt failure, or unexpected stderr — fix the cause and rerun this step from 8.1. Completion condition: the skill is absent from the list, the verification script exits 0 or its exit 3 is reported as「無處可查」and carried into step 8.3, every fixed caller ran, every checkable CLI completed the prompt with the expected result, and every untestable CLI has a stated reason.
|
||||
3. Write the change report to the wiki — this part MUST run as a sub agent. It is two pages in two repos, and they must not be mixed up.
|
||||
- **Content page `SKILLSET_{HASH}`.** Resolve its repo with `jsc-gitea/tools/gitea.sh wiki-repo SKILLSET`, which reads `JSC_WIKI_REPO_SKILLSET` first, then `JSC_WIKI_REPO`. `{HASH}` is `gitea.sh hash-id "{owner}/{repo}"` of the domain repo that lost the skill, used at the full 40 characters it prints. Write it through `jsc-gitea:wiki` following [`../../templates/skillset-page.md`](../../templates/skillset-page.md): **append** a section for this change — date, 「刪除」, skill name, changed files (the step 5 inventory verdicts included), PR URL, the step 8.1 route verdict and the step 8.2 verification result per item, the deep-delete verdict「無處可查」included when it applies — and keep every earlier section.
|
||||
- **Content page `SKILLSET_{HASH}`.** Resolve its repo with `jsc-gitea/tools/gitea.sh wiki-repo SKILLSET`, which reads `JSC_WIKI_REPO_SKILLSET` first, then `JSC_WIKI_REPO`. `{HASH}` is `gitea.sh hash-id "{owner}/{repo}"` of the domain repo that lost the skill, used at the full 40 characters it prints. Write it through `jsc-gitea:wiki` following [`../../templates/skillset-page.md`](../../templates/skillset-page.md): **append** a section for this change — date, 「刪除」, skill name, changed files (the step 5 inventory verdicts included), PR URL, the step 8.1 route verdict and the step 8.2 verification result per item, the deep-delete verdict「無處可查」included when it applies, and the step 6 note 「待辦簿引用尚未接線」 — and keep every earlier section.
|
||||
- **Directory page `SKILLSET_CONTENTS`.** It lives in the CONTENTS repo, never in the SKILLSET one. `wiki-contents.sh` resolves it itself with `gitea.sh wiki-repo CONTENTS`, whose chain is `JSC_WIKI_REPO_CONTENTS` then `JSC_WIKI_REPO` and never falls back to `JSC_WIKI_REPO_SKILLSET`. That page is a heading-plus-bullets list and holds no markdown table: one `## SKILLSET_{HASH}` block per domain repo, every field one `- {欄位名}:{值}` line under it. Build one file holding this domain's single block, following [`../../templates/skillset-contents.md`](../../templates/skillset-contents.md), with its 異動頁 bullet written as `[SKILLSET_{HASH}]({url})` from the **absolute** URL that `gitea.sh wiki-url {SKILLSET repo} SKILLSET_{HASH}` prints. The H2 heading itself carries no link, no URL, no affix and no date — only the content page name. Every link on both pages takes that `[{text}]({url})` form; the double-bracket wiki-link form resolves only inside one wiki, so it is never used. Then run:
|
||||
|
||||
`jsc-gitea/tools/wiki-contents.sh upsert SKILLSET 2 "SKILLSET_{HASH}" {entry file} templates/skillset-contents.md`
|
||||
@@ -79,10 +91,10 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
||||
|
||||
| status | Use it when |
|
||||
| --- | --- |
|
||||
| `ok` | the skill directory and its behavior-list section are gone, the PR is open, `deploy-verify.md` sections 1 to 5 hold, `verify-skill-removed.sh` exited 0, and both wiki writes exited 0 |
|
||||
| `ok` | the skill directory, its behavior-list section and its `delegate-spec.tsv` row are gone, every PR this run needed is open, `deploy-verify.md` sections 1 to 5 hold, `verify-skill-removed.sh` and `check-delegate.sh` both exited 0, and both wiki writes exited 0 |
|
||||
| `blocked` | a gate or a missing prerequisite stopped the run before any file changed — `sync-domains.sh` never reached exit 0, or no skill could be listed to pick from |
|
||||
| `failed` | the run broke mid-way — a leftover from `verify-skill-removed.sh` exit 1 could not be removed, or a wiki write failed again after its one retry |
|
||||
| `degraded` | the deletion landed with a part missing — the deep-delete check came back 「無處可查」, or the content page was written while its `SKILLSET_CONTENTS` block was not |
|
||||
| `degraded` | the deletion landed with a part missing — the deep-delete check came back 「無處可查」, the skill's PR is open while the `delegate-spec.tsv` PR is not, or the content page was written while its `SKILLSET_CONTENTS` block was not |
|
||||
| `aborted` | the user stopped the run, or a prerequisite turned out not to hold and this skill stopped on its own |
|
||||
|
||||
`{exit code}` is this run's own result as a number: `0` for `ok`, non-zero otherwise. `detail` is optional, one line, at most 200 characters.
|
||||
|
||||
@@ -20,8 +20,11 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
||||
- Trigger (when to use, when not to, trigger keywords)
|
||||
- Input and output (can a standard input/output flow move down to `tools/`; does it need Gitea operations — if so, make the skill use `jsc-gitea/tools/gitea.sh` + token)
|
||||
- Owning domain (offer the domain list from the step 1.1 `domain<TAB>path` rows — the domains registered in the canonical marketplace)
|
||||
- Delegation verdict — the five decision-tree questions of [`../../references/delegate-criteria.md`](../../references/delegate-criteria.md), in the order that file lists them, plus a sixth question for the `next` column: which skill should run after this one, and a seventh for the `probe` column: which read-only command the assistant actually runs for the delegated slice. Ask all seven through this same `jsc-ask:ask` tree; never answer them from the model's own reading of the draft flow. Every option states its impact scope: a `full` verdict lets the background assistant run the skill unattended, a `slice` or `cond` verdict leaves the other half in the user's hands, `none` keeps the whole skill there. The `next` question applies to all four verdicts, `none` included — `none` says the assistant does not run this skill for the user, which says nothing about what should follow it — so offer the step 1.1 skill rows as its options and the answer then names a skill that exists.
|
||||
|
||||
Completion condition: goal, trigger, input/output and owning domain each have a recorded answer.
|
||||
The `probe` question is asked only when the `way` answer holds no `invoke`; a `way` containing `invoke`, and a `none` verdict, both take `-` without asking, because the assistant's action there is the skill itself and a command in that column would silently downgrade the whole delegation to a bare script run. When it is asked, settle three things per that same reference file and never by copying another row: which script, whether it takes a read-only flag, and how a failure is reported. Verify the script, the sub-command and the flag name in the owning repo before writing them down — a description of a script is not evidence the script exists. The flag matters most: the patrol round is unattended, and a wrong flag turns a read-only stocktake into something that writes. An entry that needs the network gets `pending:{reason}` this round rather than a command, because an expired key then fails or silently reports nothing on every round while a local read fails on none.
|
||||
|
||||
Completion condition: goal, trigger, input/output, owning domain and the delegation verdict each have a recorded answer, and the verdict carries a value for every column `delegate-criteria.md` marks mandatory for that verdict, `-` where it marks the column unused.
|
||||
2. If the domain does not exist (`tools/sync-domains.sh` clones every domain **registered in the marketplace**, so a missing directory means the domain is unregistered — the repository itself may already exist on Gitea):
|
||||
1. Propose one short English word for the new domain (a single word preferred) and confirm it with the user. Completion condition: the user confirms the domain word.
|
||||
2. Check before creating: run `jsc-gitea/tools/gitea.sh clone-url plugins/{domain}`. A URL comes back when the repository already exists — clone it, skip creation, and go on to step 2.3 to fill in whatever content is missing. Only when no URL comes back create the repository through the tool, never by hand: `gitea.sh api POST /orgs/plugins/repos` when `plugins` is an organization, `POST /user/repos` when `plugins` is the token's own account (`tea repo create` does the same job). Only when the call is refused (403 — the token has write but not admin rights on the owner) ask the user to create `plugins/{domain}` by hand, then continue. Completion condition: `gitea.sh clone-url plugins/{domain}` prints a URL and cloning it succeeds.
|
||||
@@ -36,11 +39,20 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
||||
3. Generate the skill per guidelines.md — this step MUST run as a sub agent:
|
||||
- `skills/{name}/SKILL.md`: entirely in English (description within either cap — ≤ 5 sentences or ≤ 5 steps — and stating when to use and when not to; body in STE100-style English)
|
||||
- Rules enforceable by hooks go to `jsc-hooks` (never scattered in this domain); standard input/output flows go to `tools/`
|
||||
- `jsc-meta/tools/delegate-spec.tsv`: append this skill's row, built from the step 1.2 verdict — one skill one row, the twelve tab-separated columns in the order that file's header lists, `probe` last. A column the verdict does not use holds a single `-`; an empty cell and a cell holding a space both fail the checker. Write `probe` as the header describes: the script path starts at `{root}/jsc-{domain}/`, `{cli}` and `{repo}` are the only other substitution points, no dollar sign and no tilde, and any read-only flag goes in front of the command. `origin` is `judged`, because the verdict came from the decision tree in this same run, and `version` is the version the three manifests carry after the `sync-skill-manifest.sh` run below. **A skill with no row is not created.** The row is the only thing that tells the background assistant this skill exists, so without it every later round is blind to it, and no later step recreates it. The file lives in `plugins/meta` whichever domain gained the skill, so a skill added to another domain changes two repos and step 5 opens the second Push Request for this one.
|
||||
- `references/behaviors.md`: add one `## {name}` section for the new skill, placed in dictionary order among the existing sections, carrying the five rows the guidelines' 「技能行為清單」 section defines — 觸發時機、關鍵步驟、外部呼叫、完成條件、可驗證跡象. Write what the skill really does; do not copy the `description`. A read-only skill still fills 可驗證跡象 with 「無寫入跡象,只有回報內容」. The behavior list ships in this same PR — a skill added without its section leaves the domain's list out of sync the moment this PR merges. When the domain has no `references/behaviors.md` yet, create it with the header line `# jsc-{domain} 技能行為清單`.
|
||||
|
||||
Then run `tools/sync-skill-manifest.sh {domain-path}` directly (no sub agent needed) to sync the domain README's 「Skills 目錄」 section and bump the version in all three manifests. Route each exit code: 0 — the README block and all three manifests are synced; 1 — the domain path, `skills/`, `README.md`, the `JSC-SKILLS` markers, a `SKILL.md`, a manifest, or a manifest `version` field is missing, so fix the named cause on stderr and rerun; 2 — usage error, the script takes exactly one argument; any other code — the script runs under `set -e`, so treat it as an environment fault and stop, never as a successful sync. Completion condition: `skills/{name}/SKILL.md` exists, `references/behaviors.md` holds a `## {name}` section with all five rows filled, the README lists the skill, and all three manifests show the same new version.
|
||||
4. Self-check every item of the guidelines.md audit checklist; fix anything that fails. Run `tools/check-behaviors.sh {domain-path}` for the behavior-list item instead of comparing by eye, and route each exit code: 0 — the list matches `skills/` and all five rows are filled; 1 — every mismatch is printed on stderr as `{檔案}:{技能名}:{說明}`, so fix each one and rerun; 2 — usage error, the tool takes exactly one argument; 3 — nothing was checked, because `references/behaviors.md` is missing, `skills/` is missing, or no `SKILL.md` was found, so create the missing file and rerun. **Exit 3 is never a pass.** Completion condition: every checklist item passes and `tools/check-behaviors.sh {domain-path}` exits 0.
|
||||
5. Call `jsc-git:pr` to open a Push Request. Completion condition: a PR URL comes back and is reported with the table format in [`../../references/pr-report.md`](../../references/pr-report.md).
|
||||
Then run `tools/sync-skill-manifest.sh {domain-path}` directly (no sub agent needed) to sync the domain README's 「Skills 目錄」 section and bump the version in all three manifests. Route each exit code: 0 — the README block and all three manifests are synced; 1 — the domain path, `skills/`, `README.md`, the `JSC-SKILLS` markers, a `SKILL.md`, a manifest, or a manifest `version` field is missing, so fix the named cause on stderr and rerun; 2 — usage error, the script takes exactly one argument; any other code — the script runs under `set -e`, so treat it as an environment fault and stop, never as a successful sync. Completion condition: `skills/{name}/SKILL.md` exists, `references/behaviors.md` holds a `## {name}` section with all five rows filled, `tools/delegate-spec.tsv` holds this skill's row with every mandatory column filled, the README lists the skill, and all three manifests show the same new version.
|
||||
4. Self-check every item of the guidelines.md audit checklist; fix anything that fails. Run `tools/check-behaviors.sh {domain-path}` for the behavior-list item instead of comparing by eye, and route each exit code: 0 — the list matches `skills/` and all five rows are filled; 1 — every mismatch is printed on stderr as `{檔案}:{技能名}:{說明}`, so fix each one and rerun; 2 — usage error, the tool takes exactly one argument; 3 — nothing was checked, because `references/behaviors.md` is missing, `skills/` is missing, or no `SKILL.md` was found, so create the missing file and rerun. **Exit 3 is never a pass.**
|
||||
|
||||
Then run `tools/check-delegate.sh` for the delegation-list item. It takes the plugins root, not a domain path, and the list is one file covering every domain, so it runs **once for the whole flow** — a second run per domain checks the same file again and reports the same lines. Route each exit code:
|
||||
- 0 — the list matches the skills on this machine and every mandatory column is filled. **A run that printed lines on stdout and exited 0 still passed.** Those lines are hints, not defects: `origin=seed` marks a row seeded from the earlier inventory and awaiting review, and a version-behind line marks a row whose `version` trails its domain's current one, a `probe=pending:` line marks a delegated slice whose read-only entry point is not wired yet, and a line saying a `probe` domain is not installed here marks a script this machine cannot check. The version number is per domain, so bumping one skill's domain marks every other skill in it — reading those lines as failures paints the whole domain red on every release until nobody reads them at all. Report the hints, fix nothing for them, and treat this item as passed.
|
||||
- 1 — a missing row, a duplicate row, a row for a skill this machine does not have, an empty column, a column value outside its vocabulary, a `next` pointing at a skill that does not exist, or a `probe` in the wrong shape — a command on a row whose `way` holds `invoke`, a `-` on a row whose `way` holds only `patrol` or `remind`, a dollar sign or tilde, an unknown substitution point, or a script that does not exist. Every one is printed on stderr as `{清單路徑}:{domain}/{技能名}:{說明}`; fix each and rerun. The new skill's own missing row is the expected finding when step 3 skipped its write, and the fix is that write, not an edit here.
|
||||
- 2 — usage error: the script takes at most one argument. Fix the call and rerun.
|
||||
- 3 — nothing was checked, because `tools/delegate-spec.tsv` is missing, the root could not be derived, or `list-skills.sh` listed no skill. Read stderr and fix the named cause; set `JSC_PLUGINS_ROOT` to the directory holding the domain repos for the root case, as in step 1.1. **Exit 3 is never a pass** — it means the check looked nowhere, so a new skill with no row would sail through it.
|
||||
|
||||
Completion condition: every checklist item passes, `tools/check-behaviors.sh {domain-path}` exits 0, and `tools/check-delegate.sh` exits 0 with the new skill's row present, its hint lines reported as hints.
|
||||
5. Call `jsc-git:pr` to open a Push Request. When the new skill went into a domain other than `meta`, the `tools/delegate-spec.tsv` row is a change to `plugins/meta` and needs its own Push Request against that repo — two repos changed, two PRs, neither waiting on the other. Completion condition: a PR URL comes back for every repo this run changed, `plugins/meta` included when the row landed there, and each is reported with the table format in [`../../references/pr-report.md`](../../references/pr-report.md).
|
||||
6. Deploy the new skill, verify it runs, then report:
|
||||
1. Follow [`../../references/deploy-verify.md`](../../references/deploy-verify.md) from section 1 to section 5: `tools/deploy-route.sh {domain-path}` picks the route, the deploy route or the worktree route runs, and the verification then runs in a **fresh CLI process**, never in the session that ran the deploy. That session raised the restart gate itself and still holds the old skill body, so verifying inside it either gets blocked or passes on stale behavior. Verify the added skill's row in `tools/list-skills.sh`, every tool the skill added, and one minimal prompt per checkable CLI — the per-CLI prompts run in parallel. Completion condition: every completion condition in `deploy-verify.md` sections 1 to 5 holds for this domain repo.
|
||||
2. Write the change report to the wiki — this part MUST run as a sub agent. It is two pages in two repos, and they must not be mixed up.
|
||||
@@ -88,10 +100,10 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
||||
|
||||
| status | Use it when |
|
||||
| --- | --- |
|
||||
| `ok` | the new `SKILL.md` and its behavior-list section are in place, the checklist passes, the PR is open, `deploy-verify.md` sections 1 to 5 hold, and both wiki writes exited 0 |
|
||||
| `ok` | the new `SKILL.md`, its behavior-list section and its `delegate-spec.tsv` row are in place, the checklist passes, every PR this run needed is open, `deploy-verify.md` sections 1 to 5 hold, and both wiki writes exited 0 |
|
||||
| `blocked` | a gate or a missing prerequisite stopped the run before any file was created — `sync-domains.sh` never reached exit 0, or Gitea refused the repository creation and nobody created it by hand |
|
||||
| `failed` | the run broke mid-way — `sync-marketplace.sh` or `sync-skill-manifest.sh` kept failing, or a wiki write failed again after its one retry |
|
||||
| `degraded` | the skill landed with a part missing — the content page was written while its `SKILLSET_CONTENTS` block was not, or a CLI could not be verified and the reason was recorded |
|
||||
| `degraded` | the skill landed with a part missing — the content page was written while its `SKILLSET_CONTENTS` block was not, the skill's PR is open while the `delegate-spec.tsv` PR is not, or a CLI could not be verified and the reason was recorded |
|
||||
| `aborted` | the user stopped the run, or a prerequisite turned out not to hold and this skill stopped on its own |
|
||||
|
||||
`{exit code}` is this run's own result as a number: `0` for `ok`, non-zero otherwise. `detail` is optional, one line, at most 200 characters.
|
||||
|
||||
@@ -13,13 +13,23 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
||||
2. Run `tools/list-skills.sh` and present its `domain / name / description` rows to the user. The tool prints skills, not domains, so read the domain column to prove coverage. Exit 1 means the root could not be derived, the domain list was unreadable, or no skill was found — read stderr, fix the named cause (`JSC_PLUGINS_ROOT` for the root case, as in step 1) and rerun; never read it as an empty skill set. Completion condition: the script exits 0 and every domain printed by step 1 appears in at least one row; a domain with no row means its repo is missing or holds no skill — return to step 1 for that domain.
|
||||
3. Let the user pick the skill to update. Completion condition: one `{domain}/{name}` pair is confirmed.
|
||||
4. Ask for update details via the `jsc-ask:ask` decision tree (change the goal? the trigger? the flow? move rules down to a hook or a tool?). Every option states its impact scope (example: renaming breaks the existing invocation command). Completion condition: every question has a recorded answer.
|
||||
5. Update the skill — the modification part MUST run as a sub agent: modify SKILL.md and related files. In the same pass, update this skill's `## {name}` section in `references/behaviors.md` so its five rows — 觸發時機、關鍵步驟、外部呼叫、完成條件、可驗證跡象 — describe the new behavior. A renamed skill gets its section renamed and moved back into dictionary order. The behavior list ships in this same PR: a behavior change that lands without its section makes the domain's list wrong from the merge onward, and the next audit reports drift this step created. Then run `tools/sync-skill-manifest.sh {domain-path}` directly (no sub agent needed) to sync the domain README's 「Skills 目錄」 section and bump the version in all three manifests. Route each exit code: 0 — the README block and all three manifests are synced; 1 — the domain path, `skills/`, `README.md`, the `JSC-SKILLS` markers, a `SKILL.md`, a manifest, or a manifest `version` field is missing, so fix the named cause on stderr and rerun; 2 — usage error, the script takes exactly one argument; any other code — the script runs under `set -e`, so treat it as an environment fault and stop, never as a successful sync. Completion condition: the skill files carry the change, the skill's `references/behaviors.md` section states the new behavior with all five rows filled, and all three manifests show the same new version.
|
||||
6. Check every item of the guidelines.md audit checklist. Run `tools/check-behaviors.sh {domain-path}` for the behavior-list item instead of comparing by eye, and route each exit code: 0 — the list matches `skills/` and all five rows are filled; 1 — every mismatch is printed on stderr as `{檔案}:{技能名}:{說明}`, so fix each one and rerun; 2 — usage error, the tool takes exactly one argument; 3 — nothing was checked, because `references/behaviors.md` is missing, `skills/` is missing, or no `SKILL.md` was found, so create the missing file and rerun. **Exit 3 is never a pass.** On any failure, **return to step 4**: ask again and fix, until all items pass. Completion condition: every checklist item passes and `tools/check-behaviors.sh {domain-path}` exits 0.
|
||||
7. Call `jsc-git:pr` to open a Push Request. Completion condition: a PR URL comes back and is reported with the table format in [`../../references/pr-report.md`](../../references/pr-report.md).
|
||||
|
||||
Settle the delegation verdict in the same tree, before any file is touched. A change that touches the **flow** or the **`description`** re-runs the whole decision tree of [`../../references/delegate-criteria.md`](../../references/delegate-criteria.md) — all five questions, the `next` question and the `probe` question — and produces a fresh verdict. The `probe` question is re-asked even when the verdict itself comes back unchanged: a skill that switched which script it calls, or that gained a read-only flag it did not have, leaves that column naming something the assistant can no longer run, and the reference file's three points settle it — which script, whether it takes a read-only flag, how a failure is reported — each verified in the owning repo rather than copied from the old value. Skipping that leaves a skill that just turned from read-only into file-writing sitting on its old verdict, and the background assistant keeps triggering it on a description of behavior it no longer has. A change that only rewrites wording and touches no behavior may keep the recorded verdict; then step 5 moves the row's `version` alone and the reuse is stated in the report, never left silent. Every option states its impact scope, this one included: reusing a verdict wrongly is the one failure this flow cannot detect later, because the row still looks complete. Completion condition: the run holds either a fresh verdict with a value in every column `delegate-criteria.md` marks mandatory for it, or a recorded decision to reuse the existing verdict together with the reason it changed no behavior.
|
||||
5. Update the skill — the modification part MUST run as a sub agent: modify SKILL.md and related files. In the same pass, update this skill's `## {name}` section in `references/behaviors.md` so its five rows — 觸發時機、關鍵步驟、外部呼叫、完成條件、可驗證跡象 — describe the new behavior. A renamed skill gets its section renamed and moved back into dictionary order. In the same pass, update this skill's row in `jsc-meta/tools/delegate-spec.tsv` from the step 4 answer: a re-judged skill has every column rewritten from the fresh verdict with `origin` set to `judged`; a reused verdict keeps its columns and its `origin` untouched. Either way the `version` column moves to the version the manifests carry after the `sync-skill-manifest.sh` run below — a row left on the old version reads as never revisited, and the next audit reports it as pending re-judgement. The reuse itself is **not** recorded in the row: the twelve columns hold no note column and a thirteenth column fails the checker, so state it in the PR description and in the step 8.2 wiki section as 「沿用前一輪判定」 with the date that judgement was made. A reused verdict still gets its `probe` column re-checked against the files this run touched — a renamed or removed script leaves that column naming something the assistant cannot run, and the checker reports it as a missing script. A renamed skill also has its row's `name` column renamed, and every other row whose `next` named the old name is repointed in the same edit — those rows now name a skill that cannot be called, and the assistant retries such a name instead of pausing on it. The file lives in `plugins/meta` whichever domain owns the skill, so updating a skill outside `meta` changes two repos. The behavior list ships in this same PR: a behavior change that lands without its section makes the domain's list wrong from the merge onward, and the next audit reports drift this step created. Then run `tools/sync-skill-manifest.sh {domain-path}` directly (no sub agent needed) to sync the domain README's 「Skills 目錄」 section and bump the version in all three manifests. Route each exit code: 0 — the README block and all three manifests are synced; 1 — the domain path, `skills/`, `README.md`, the `JSC-SKILLS` markers, a `SKILL.md`, a manifest, or a manifest `version` field is missing, so fix the named cause on stderr and rerun; 2 — usage error, the script takes exactly one argument; any other code — the script runs under `set -e`, so treat it as an environment fault and stop, never as a successful sync. Completion condition: the skill files carry the change, the skill's `references/behaviors.md` section states the new behavior with all five rows filled, its `tools/delegate-spec.tsv` row carries the fresh verdict or the reused one with a moved `version`, and all three manifests show the same new version.
|
||||
6. Check every item of the guidelines.md audit checklist. Run `tools/check-behaviors.sh {domain-path}` for the behavior-list item instead of comparing by eye, and route each exit code: 0 — the list matches `skills/` and all five rows are filled; 1 — every mismatch is printed on stderr as `{檔案}:{技能名}:{說明}`, so fix each one and rerun; 2 — usage error, the tool takes exactly one argument; 3 — nothing was checked, because `references/behaviors.md` is missing, `skills/` is missing, or no `SKILL.md` was found, so create the missing file and rerun. **Exit 3 is never a pass.**
|
||||
|
||||
Then run `tools/check-delegate.sh` for the delegation-list item. It takes the plugins root, not a domain path, and the list is one file covering every domain, so it runs **once for the whole flow**. Route each exit code:
|
||||
- 0 — the list matches the skills on this machine and every mandatory column is filled. **A run that printed lines on stdout and exited 0 still passed.** Those lines are hints, not defects: `origin=seed` marks a row seeded from the earlier inventory and awaiting review, and a version-behind line marks a row whose `version` trails its domain's current one, a `probe=pending:` line marks a delegated slice whose read-only entry point is not wired yet, and a line saying a `probe` domain is not installed here marks a script this machine cannot check. The version number is per domain, so bumping one skill's domain marks every other skill in it — reading those lines as failures paints the whole domain red on every release until nobody reads them at all. Report the hints and treat this item as passed. The one hint worth acting on here is a version-behind line naming **the skill this run just changed**: that row's `version` was supposed to move in step 5, so go back and move it.
|
||||
- 1 — a missing row, a duplicate row, a row for a skill this machine does not have, an empty column, a column value outside its vocabulary, a `next` pointing at a skill that does not exist, or a `probe` in the wrong shape — a command on a row whose `way` holds `invoke`, a `-` on a row whose `way` holds only `patrol` or `remind`, a dollar sign or tilde, an unknown substitution point, or a script that does not exist. Every one is printed on stderr as `{清單路徑}:{domain}/{技能名}:{說明}`; fix each and rerun. A rename that left the old name behind lands here twice — once as a stale row, once as another row's dead `next`.
|
||||
- 2 — usage error: the script takes at most one argument. Fix the call and rerun.
|
||||
- 3 — nothing was checked, because `tools/delegate-spec.tsv` is missing, the root could not be derived, or `list-skills.sh` listed no skill. Read stderr and fix the named cause; set `JSC_PLUGINS_ROOT` to the directory holding the domain repos for the root case, as in step 1. **Exit 3 is never a pass.**
|
||||
|
||||
On any failure, **return to step 4**: ask again and fix, until all items pass. Completion condition: every checklist item passes, `tools/check-behaviors.sh {domain-path}` exits 0, and `tools/check-delegate.sh` exits 0 with its hint lines reported as hints.
|
||||
7. Call `jsc-git:pr` to open a Push Request. When the updated skill lives in a domain other than `meta`, the `tools/delegate-spec.tsv` row is a change to `plugins/meta` and needs its own Push Request against that repo — two repos changed, two PRs, neither waiting on the other. Completion condition: a PR URL comes back for every repo this run changed, `plugins/meta` included when the row landed there, and each is reported with the table format in [`../../references/pr-report.md`](../../references/pr-report.md).
|
||||
8. Deploy the update, verify it runs, then report:
|
||||
1. Follow [`../../references/deploy-verify.md`](../../references/deploy-verify.md) from section 1 to section 5: `tools/deploy-route.sh {domain-path}` picks the route, the deploy route or the worktree route runs, and the verification then runs in a **fresh CLI process**, never in the session that ran the deploy. That session raised the restart gate itself and still holds the old skill body, so verifying inside it either gets blocked or passes on stale behavior. Verify the updated `description` in the skill's `tools/list-skills.sh` row, every tool this change touched, and one minimal prompt per checkable CLI — the per-CLI prompts run in parallel. Completion condition: every completion condition in `deploy-verify.md` sections 1 to 5 holds for this domain repo.
|
||||
2. Write the change report to the wiki — this part MUST run as a sub agent. It is two pages in two repos, and they must not be mixed up.
|
||||
- **Content page `SKILLSET_{HASH}`.** Resolve its repo with `jsc-gitea/tools/gitea.sh wiki-repo SKILLSET`, which reads `JSC_WIKI_REPO_SKILLSET` first, then `JSC_WIKI_REPO`. `{HASH}` is `gitea.sh hash-id "{owner}/{repo}"` of the changed domain repo, used at the full 40 characters it prints. Write it through `jsc-gitea:wiki` following [`../../templates/skillset-page.md`](../../templates/skillset-page.md): **append** a section for this change — date, 「更新」, skill name, changed files, PR URL, the step 8.1 route verdict and verification result per item — and keep every earlier section.
|
||||
- **Content page `SKILLSET_{HASH}`.** Resolve its repo with `jsc-gitea/tools/gitea.sh wiki-repo SKILLSET`, which reads `JSC_WIKI_REPO_SKILLSET` first, then `JSC_WIKI_REPO`. `{HASH}` is `gitea.sh hash-id "{owner}/{repo}"` of the changed domain repo, used at the full 40 characters it prints. Write it through `jsc-gitea:wiki` following [`../../templates/skillset-page.md`](../../templates/skillset-page.md): **append** a section for this change — date, 「更新」, skill name, changed files, PR URL, the step 8.1 route verdict and verification result per item, and the delegation verdict this run recorded: the fresh verdict with its columns, or 「沿用前一輪判定」 with the date of the judgement being reused. The row itself has no room for that note, so this section is the only place it is kept — and keep every earlier section.
|
||||
- **Directory page `SKILLSET_CONTENTS`.** It lives in the CONTENTS repo, never in the SKILLSET one. `wiki-contents.sh` resolves it itself with `gitea.sh wiki-repo CONTENTS`, whose chain is `JSC_WIKI_REPO_CONTENTS` then `JSC_WIKI_REPO` and never falls back to `JSC_WIKI_REPO_SKILLSET`. That page is a heading-plus-bullets list and holds no markdown table: one `## SKILLSET_{HASH}` block per domain repo, every field one `- {欄位名}:{值}` line under it. Build one file holding this domain's single block, following [`../../templates/skillset-contents.md`](../../templates/skillset-contents.md), with its 異動頁 bullet written as `[SKILLSET_{HASH}]({url})` from the **absolute** URL that `gitea.sh wiki-url {SKILLSET repo} SKILLSET_{HASH}` prints. The H2 heading itself carries no link, no URL, no affix and no date — only the content page name. Every link on both pages takes that `[{text}]({url})` form; the double-bracket wiki-link form resolves only inside one wiki, so it is never used. Then run:
|
||||
|
||||
`jsc-gitea/tools/wiki-contents.sh upsert SKILLSET 2 "SKILLSET_{HASH}" {entry file} templates/skillset-contents.md`
|
||||
@@ -63,10 +73,10 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
||||
|
||||
| status | Use it when |
|
||||
| --- | --- |
|
||||
| `ok` | the skill files and the behavior-list section carry the change, the checklist passes, the PR is open, `deploy-verify.md` sections 1 to 5 hold, and both wiki writes exited 0 |
|
||||
| `ok` | the skill files, the behavior-list section and the `delegate-spec.tsv` row carry the change, the checklist passes, every PR this run needed is open, `deploy-verify.md` sections 1 to 5 hold, and both wiki writes exited 0 |
|
||||
| `blocked` | a gate or a missing prerequisite stopped the run before any file changed — `sync-domains.sh` never reached exit 0, or no skill could be listed to pick from |
|
||||
| `failed` | the run broke mid-way — the step 6 checklist loop kept failing, or a wiki write failed again after its one retry |
|
||||
| `degraded` | the update landed with a part missing — the content page was written while its `SKILLSET_CONTENTS` block was not, or a CLI could not be verified and the reason was recorded |
|
||||
| `degraded` | the update landed with a part missing — the content page was written while its `SKILLSET_CONTENTS` block was not, the skill's PR is open while the `delegate-spec.tsv` PR is not, or a CLI could not be verified and the reason was recorded |
|
||||
| `aborted` | the user stopped the run, or a prerequisite turned out not to hold and this skill stopped on its own |
|
||||
|
||||
`{exit code}` is this run's own result as a number: `0` for `ok`, non-zero otherwise. `detail` is optional, one line, at most 200 characters.
|
||||
|
||||
@@ -14,13 +14,25 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
||||
2. Ask for the change details via the `jsc-ask:ask` decision tree: what rule or behavior changes, which skills and which domains are affected. Include three required checks before the affected-skill list is final: whether any deterministic input/output flow must move to `tools/`, whether any detailed flow must run as a sub agent, and whether any wiki or Gitea flow must read inherited environment variables before asking the user. Every option states its impact scope (example: changing a shared flow step touches every skill that calls it). These three are a shaping guardrail asked before any file is touched; keep asking them even when a later step would catch the same problem.
|
||||
|
||||
Completion condition: the `domain<TAB>path` rows are in hand, and the affected-skill list plus the three checks are agreed with the user.
|
||||
2. Apply the change to every affected skill — the modification part MUST run as a sub agent, one sub agent per affected domain repo, and those sub agents **run in parallel**: each repo's files are independent. Every sub agent also updates its own repo's `references/behaviors.md` in the same pass: a changed behavior rewrites that skill's `## {name}` section, a new skill gets a section inserted in dictionary order, a removed skill loses its section. Keep all five rows filled — 觸發時機、關鍵步驟、外部呼叫、完成條件、可驗證跡象. Each repo's behavior list ships in that repo's own PR, so no cross-repo PR pair has to be merged in order. Then run `tools/sync-skill-manifest.sh {domain-path}` directly (no sub agent needed) for each affected domain repo to sync that domain README's 「Skills 目錄」 section and bump the version in all three manifests; these runs are independent per repo and may also go in parallel. Route each exit code: 0 — the README block and all three manifests are synced; 1 — the domain path, `skills/`, `README.md`, the `JSC-SKILLS` markers, a `SKILL.md`, a manifest, or a manifest `version` field is missing, so fix the named cause on stderr and rerun; 2 — usage error, the script takes exactly one argument; any other code — the script runs under `set -e`, so treat it as an environment fault and stop, never as a successful sync. Completion condition: every affected domain repo carries the change, its behavior-list update, the README sync, and the manifest bump.
|
||||
3. Check every item of the guidelines.md audit checklist for each touched skill — one sub agent per affected domain repo, run in parallel. Each sub agent runs `tools/check-behaviors.sh {domain-path}` for the behavior-list item of its own repo instead of comparing by eye, and routes each exit code: 0 — that repo's list matches its `skills/` and all five rows are filled; 1 — every mismatch is printed on stderr as `{檔案}:{技能名}:{說明}`, so fix each one and rerun; 2 — usage error, the tool takes exactly one argument; 3 — nothing was checked, because `references/behaviors.md` is missing, `skills/` is missing, or no `SKILL.md` was found, so create the missing file and rerun. **Exit 3 is never a pass.** On any failure, **return to step 1.2**: ask again and fix, until all items pass. Completion condition: every checklist item passes for every touched skill, and `tools/check-behaviors.sh` exits 0 for every affected domain repo.
|
||||
4. Call `jsc-git:pr` once per affected domain repo to open a Push Request. Completion condition: every affected repo has a PR URL, and all URLs are reported in one table with the format in [`../../references/pr-report.md`](../../references/pr-report.md).
|
||||
2. Apply the change to every affected skill — the modification part MUST run as a sub agent, one sub agent per affected domain repo, and those sub agents **run in parallel**: each repo's files are independent. Every sub agent also updates its own repo's `references/behaviors.md` in the same pass: a changed behavior rewrites that skill's `## {name}` section, a new skill gets a section inserted in dictionary order, a removed skill loses its section. Keep all five rows filled — 觸發時機、關鍵步驟、外部呼叫、完成條件、可驗證跡象. Each repo's behavior list ships in that repo's own PR, so no cross-repo PR pair has to be merged in order.
|
||||
|
||||
Every sub agent also re-runs the delegation decision tree of [`../../references/delegate-criteria.md`](../../references/delegate-criteria.md) for **every** skill its repo touched — all five questions, the `next` question and the `probe` question, one skill at a time, not one verdict for the repo, and **not one skipped**. A batch is exactly where skipping happens: the change that turned three skills from read-only into file-writing looks like one change, and re-judging only the obvious one leaves the other two being triggered on a verdict that no longer describes them. A skill whose text this batch rewrote without touching its flow or its `description` may keep its verdict, and then only its `version` moves; that reuse is stated in step 5.2's wiki section, exactly as a fresh verdict is.
|
||||
|
||||
The sub agents do **not** write those verdicts. `jsc-meta/tools/delegate-spec.tsv` is one file for the whole skill set, and parallel sub agents writing one file overwrite each other's rows. Each sub agent returns its verdicts as rows — twelve tab-separated columns each, `probe` last, `-` in every column its verdict leaves unused, `origin` set to `judged` for a fresh verdict and left as it was for a reused one — and the **main agent** merges them into the file in one edit after the sub agents finish. A batch is where the `probe` column goes stale fastest: a change that moves or renames a `tools/` script across several domains leaves every row naming it pointing at nothing, so each sub agent verifies that column against its own repo's files — which script, whether it takes a read-only flag, how a failure is reported — and returns `pending:{reason}` rather than a command for any slice that would need the network. When `meta` is one of the affected repos, that edit rides in its PR; when it is not, it is a change to `plugins/meta` and step 4 opens the extra Push Request for it. Then run `tools/sync-skill-manifest.sh {domain-path}` directly (no sub agent needed) for each affected domain repo to sync that domain README's 「Skills 目錄」 section and bump the version in all three manifests; these runs are independent per repo and may also go in parallel. Route each exit code: 0 — the README block and all three manifests are synced; 1 — the domain path, `skills/`, `README.md`, the `JSC-SKILLS` markers, a `SKILL.md`, a manifest, or a manifest `version` field is missing, so fix the named cause on stderr and rerun; 2 — usage error, the script takes exactly one argument; any other code — the script runs under `set -e`, so treat it as an environment fault and stop, never as a successful sync. Completion condition: every affected domain repo carries the change, its behavior-list update, the README sync, and the manifest bump; and every touched skill has a delegation verdict from this run — fresh, or recorded as reused with the reason — merged into `tools/delegate-spec.tsv` by the main agent, with no touched skill left without one.
|
||||
3. Check every item of the guidelines.md audit checklist for each touched skill — one sub agent per affected domain repo, run in parallel. Each sub agent runs `tools/check-behaviors.sh {domain-path}` for the behavior-list item of its own repo instead of comparing by eye, and routes each exit code: 0 — that repo's list matches its `skills/` and all five rows are filled; 1 — every mismatch is printed on stderr as `{檔案}:{技能名}:{說明}`, so fix each one and rerun; 2 — usage error, the tool takes exactly one argument; 3 — nothing was checked, because `references/behaviors.md` is missing, `skills/` is missing, or no `SKILL.md` was found, so create the missing file and rerun. **Exit 3 is never a pass.**
|
||||
|
||||
The **main agent** then runs `tools/check-delegate.sh` once for the whole batch, not inside the per-repo sub agents: the list is one file covering every domain, so a run per repo checks the same file over again and hands back the same lines from every agent, with nobody holding one verdict. Route each exit code:
|
||||
- 0 — the list matches the skills on this machine and every mandatory column is filled. **A run that printed lines on stdout and exited 0 still passed.** Those lines are hints, not defects: `origin=seed` marks a row seeded from the earlier inventory and awaiting review, and a version-behind line marks a row whose `version` trails its domain's current one, a `probe=pending:` line marks a delegated slice whose read-only entry point is not wired yet, and a line saying a `probe` domain is not installed here marks a script this machine cannot check. A batch bumps several domains at once, so it produces those lines by the dozen — reading them as failures would fail every batch this skill ever runs. Report them as hints. The ones worth acting on are the version-behind lines naming **skills this batch touched**: their `version` was supposed to move in step 2, so go back and move it.
|
||||
- 1 — a missing row, a duplicate row, a row for a skill this machine does not have, an empty column, a column value outside its vocabulary, a `next` pointing at a skill that does not exist, or a `probe` in the wrong shape — a command on a row whose `way` holds `invoke`, a `-` on a row whose `way` holds only `patrol` or `remind`, a dollar sign or tilde, an unknown substitution point, or a script that does not exist. Every one is printed on stderr as `{清單路徑}:{domain}/{技能名}:{說明}`; fix each and rerun. A merge that lost one sub agent's rows shows up here as those skills missing, so read this code as a merge check too.
|
||||
- 2 — usage error: the script takes at most one argument. Fix the call and rerun.
|
||||
- 3 — nothing was checked, because `tools/delegate-spec.tsv` is missing, the root could not be derived, or `list-skills.sh` listed no skill. Read stderr and fix the named cause; set `JSC_PLUGINS_ROOT` to the directory holding the domain repos for the root case, as in step 1.1. **Exit 3 is never a pass.**
|
||||
|
||||
On any failure, **return to step 1.2**: ask again and fix, until all items pass. Completion condition: every checklist item passes for every touched skill, `tools/check-behaviors.sh` exits 0 for every affected domain repo, and `tools/check-delegate.sh` exits 0 once for the batch with its hint lines reported as hints.
|
||||
4. Call `jsc-git:pr` once per affected domain repo to open a Push Request, plus one against `plugins/meta` when the `tools/delegate-spec.tsv` merge landed there and `meta` is not itself an affected repo. Completion condition: every affected repo has a PR URL, `plugins/meta` included when the list changed there, and all URLs are reported in one table with the format in [`../../references/pr-report.md`](../../references/pr-report.md).
|
||||
5. Deploy the batch change, verify it runs, then report:
|
||||
1. Follow [`../../references/deploy-verify.md`](../../references/deploy-verify.md) from section 1 to section 5, once per affected domain repo — the route judgements run in parallel. The batch takes the deploy route only when **every** affected repo's `tools/deploy-route.sh` exits 0; a single exit 3 puts the whole batch on the worktree route, because the change reaches the CLIs only when the last repo merges, so name every outstanding release PR. The verification then runs in a **fresh CLI process**, never in the session that ran the deploy: that session raised the restart gate itself and still holds the old skill bodies. Verify every touched skill's row in `tools/list-skills.sh`, every tool this change touched, and one minimal prompt per affected domain per checkable CLI — the per-CLI and per-domain prompts run in parallel. Completion condition: every completion condition in `deploy-verify.md` sections 1 to 5 holds for every affected domain repo.
|
||||
2. Write the change report to the wiki — this part MUST run as a sub agent, one sub agent per affected domain repo, run in parallel. Each sub agent writes two pages in two repos, and they must not be mixed up.
|
||||
- **Content page `SKILLSET_{HASH}`.** Resolve its repo with `jsc-gitea/tools/gitea.sh wiki-repo SKILLSET`, which reads `JSC_WIKI_REPO_SKILLSET` first, then `JSC_WIKI_REPO`. `{HASH}` is `gitea.sh hash-id "{owner}/{repo}"` of that repo, used at the full 40 characters it prints. Write it through `jsc-gitea:wiki` following [`../../templates/skillset-page.md`](../../templates/skillset-page.md): **append** a section for this change — date, 「批次更新」, the change request in one line, touched skills, changed files, PR URL, the step 5.1 route verdict and verification result per item — and keep every earlier section.
|
||||
- **Content page `SKILLSET_{HASH}`.** Resolve its repo with `jsc-gitea/tools/gitea.sh wiki-repo SKILLSET`, which reads `JSC_WIKI_REPO_SKILLSET` first, then `JSC_WIKI_REPO`. `{HASH}` is `gitea.sh hash-id "{owner}/{repo}"` of that repo, used at the full 40 characters it prints. Write it through `jsc-gitea:wiki` following [`../../templates/skillset-page.md`](../../templates/skillset-page.md): **append** a section for this change — date, 「批次更新」, the change request in one line, touched skills, changed files, PR URL, the step 5.1 route verdict and verification result per item, and this repo's skills' delegation verdicts from step 2: each fresh verdict with its columns, each reused one as 「沿用前一輪判定」 with the date of the judgement being reused. The row itself has no note column, so this section is the only place that distinction is kept — and keep every earlier section.
|
||||
- **Directory page `SKILLSET_CONTENTS`.** One shared page holds every domain's block, so each sub agent writes only its own. It lives in the CONTENTS repo, never in the SKILLSET one: `wiki-contents.sh` resolves it itself with `gitea.sh wiki-repo CONTENTS`, whose chain is `JSC_WIKI_REPO_CONTENTS` then `JSC_WIKI_REPO` and never falls back to `JSC_WIKI_REPO_SKILLSET`. That page is a heading-plus-bullets list and holds no markdown table: one `## SKILLSET_{HASH}` block per domain repo, every field one `- {欄位名}:{值}` line under it. Build one file holding this domain's single block, following [`../../templates/skillset-contents.md`](../../templates/skillset-contents.md), with its 異動頁 bullet written as `[SKILLSET_{HASH}]({url})` from the **absolute** URL that `gitea.sh wiki-url {SKILLSET repo} SKILLSET_{HASH}` prints. The H2 heading itself carries no link, no URL, no affix and no date — only the content page name. Every link on both pages takes that `[{text}]({url})` form; the double-bracket wiki-link form resolves only inside one wiki, so it is never used. Then run:
|
||||
|
||||
`jsc-gitea/tools/wiki-contents.sh upsert SKILLSET 2 "SKILLSET_{HASH}" {entry file} templates/skillset-contents.md`
|
||||
@@ -64,10 +76,10 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
||||
|
||||
| status | Use it when |
|
||||
| --- | --- |
|
||||
| `ok` | every affected repo carries the change and its behavior-list update, every checklist passes, every repo has a PR URL, `deploy-verify.md` sections 1 to 5 hold for all of them, and every wiki write exited 0 |
|
||||
| `ok` | every affected repo carries the change and its behavior-list update, every touched skill has this run's delegation verdict in `delegate-spec.tsv`, every checklist passes, every repo has a PR URL, `deploy-verify.md` sections 1 to 5 hold for all of them, and every wiki write exited 0 |
|
||||
| `blocked` | a gate or a missing prerequisite stopped the run before any file changed — `sync-domains.sh` never reached exit 0, or the affected-skill list was never agreed |
|
||||
| `failed` | the run broke mid-way — the step 3 checklist loop kept failing for some repo, or a wiki write failed again after its one retry |
|
||||
| `degraded` | part of the batch landed and part did not — some repos got their PR and others did not, or a content page was written while its `SKILLSET_CONTENTS` block was not. Name the repos in `detail` |
|
||||
| `degraded` | part of the batch landed and part did not — some repos got their PR and others did not, the domain PRs are open while the `delegate-spec.tsv` PR is not, or a content page was written while its `SKILLSET_CONTENTS` block was not. Name the repos in `detail` |
|
||||
| `aborted` | the user stopped the run, or a prerequisite turned out not to hold and this skill stopped on its own |
|
||||
|
||||
`{exit code}` is this run's own result as a number: `0` for `ok`, non-zero otherwise. `detail` is optional, one line, at most 200 characters.
|
||||
|
||||
Executable
+292
@@ -0,0 +1,292 @@
|
||||
#!/usr/bin/env sh
|
||||
# check-delegate.sh — 檢查委派判定清單 tools/delegate-spec.tsv 有沒有跟本機實際技能對齊。
|
||||
#
|
||||
# 用法: check-delegate.sh [<plugins-root>]
|
||||
# 不給參數就交給 tools/plugins-root.sh 推導根目錄,判準與 list-skills.sh 完全相同。
|
||||
#
|
||||
# 檢查五項:
|
||||
# 1. 一一對應 — 清單一支技能一列,跟 list-skills.sh 的實際技能不多不少,也不重複。
|
||||
# 2. 欄位齊全 — 12 欄,每一欄非空;四種結論各自的必填欄位都填了,不該填的填 -。
|
||||
# 3. 欄位可填值 — verdict、way、trigger、recur、origin 只認固定詞彙;next 要指到
|
||||
# 一支真的存在的技能。指到不存在的技能,助理會一路重試一支叫不出來的東西。
|
||||
# 4. 唯讀指令 — probe 的填法與那一支腳本在不在,判準見下。
|
||||
# 5. 版本號與來源 — 只印提示,不影響結束碼,理由見下。
|
||||
#
|
||||
# 為什麼要這支: 技能組每天在動,手工盤點只會過期。清單缺一列,助理就永遠不知道那支技能
|
||||
# 存在;清單多一列,助理會去觸發一支不存在的技能,而且失敗不會自動暫停。這兩件事靠眼睛
|
||||
# 比對每輪都會漏,交給程式判定才穩。
|
||||
#
|
||||
# 為什麼版本號落後只算提示: 版本號是 domain 層級的,同一個 domain 改一支技能,其餘技能的
|
||||
# 版本號也會一起落後、也會被標成要複判。當成稽核缺失的話,每次發版整個 domain 都亮紅,
|
||||
# 提示很快就會被當成雜訊忽略,真正要複判的那一支反而看不見。
|
||||
#
|
||||
# 為什麼 origin=seed 只算提示: 種入的那一批是依既有盤點填的,還沒正式走過決策樹,本來就
|
||||
# 知道它待複核。它是「已經有結論、但要再確認一次」,不是「漏填」。列成缺失會讓清單從
|
||||
# 第一天就是紅的,紅到全部複核完為止,這段期間所有真的缺失都會被蓋掉。
|
||||
#
|
||||
# probe 什麼算缺失、什麼只算提示: 缺失的判準只有一條——這一列照著跑,無人值守那一輪會出事。
|
||||
# 四種算缺失:
|
||||
# 一、way 含 invoke 或這一列不交,probe 卻填了指令。種入那一支會改拿指令當待辦簿的動作,
|
||||
# 整支交出於是變成只跑一支腳本,那支技能該寫的頁一頁都不會寫,而且看起來完全正常。
|
||||
# 二、way 只有 patrol 或 remind,probe 卻是減號。那幾列的動作原本一律退回只提醒,
|
||||
# 等於判過要交、實際什麼都沒交出去。接不上就寫 pending 並講明理由,別留減號。
|
||||
# 三、指令裡有金錢符號或波浪號,或用了 root、cli、repo 以外的代入點。前者在無人值守
|
||||
# 那一輪解不出來也進不了允許清單,後者代不進去會原樣送進指令,兩種都是靜靜失敗。
|
||||
# 四、指令指到的腳本在本機不存在。助理每一輪都會叫不到它,而失敗不會自動暫停。
|
||||
# 兩種只算提示:
|
||||
# 一、pending:{理由}。入口還沒接上是判過的結論,跟 origin=seed 同一類,不是漏填。
|
||||
# 二、指令指到的 domain 本機沒有裝。那是這台機器少裝一個 domain,不是清單填錯——
|
||||
# 算成缺失的話,只裝半套的機器每一輪都亮紅,真的填錯反而看不見。
|
||||
#
|
||||
# 輸出: 缺失一行一個,格式 {清單路徑}:{domain}/{name}:{說明}(stderr);
|
||||
# 提示同格式(stdout),讓呼叫端分得開缺失與提示;統計摘要走 stderr。
|
||||
# 結束碼: 0=清單與實際技能一一對應、必填欄位齊全(可能帶提示,提示不影響這一碼)
|
||||
# 1=缺列、多列、重複列、欄位空著、欄位值不合法、next 指到不存在的技能,
|
||||
# 或 probe 填錯欄位、指到不存在的腳本、用了認不得的代入點,清單在 stderr
|
||||
# 2=用法錯誤(本腳本最多吃一個參數)
|
||||
# 3=找不到 tools/delegate-spec.tsv、推導不出根目錄,或列不出任何技能——
|
||||
# **什麼都沒查**,不等於通過
|
||||
set -u
|
||||
|
||||
usage() {
|
||||
echo 'usage: check-delegate.sh [<plugins-root>]' >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
[ "$#" -le 1 ] || usage
|
||||
if [ "$#" -eq 1 ]; then
|
||||
[ -n "$1" ] || usage
|
||||
JSC_PLUGINS_ROOT=${1%/}
|
||||
export JSC_PLUGINS_ROOT
|
||||
fi
|
||||
|
||||
HERE=$(CDPATH= cd -- "$(dirname -- "$0")" && pwd)
|
||||
SPEC="$HERE/delegate-spec.tsv"
|
||||
[ -f "$SPEC" ] || { echo "找不到委派判定清單:$SPEC" >&2; exit 3; }
|
||||
|
||||
. "$HERE/plugins-root.sh"
|
||||
ROOT=$(jsc_plugins_root) || { echo "推導不出技能組工作目錄根位置" >&2; exit 3; }
|
||||
|
||||
TMPD=$(mktemp -d) || { echo "無法建立暫存目錄" >&2; exit 3; }
|
||||
trap 'rm -rf "$TMPD"' EXIT
|
||||
TAB=$(printf '\t')
|
||||
|
||||
# 實際技能清單。真實來源只有 list-skills.sh 一處,本腳本不自己掃 SKILL.md:
|
||||
# 兩套掃法會各自漂移,屆時分不出是清單錯還是掃法錯。
|
||||
"$HERE/list-skills.sh" > "$TMPD/raw.txt" 2>/dev/null \
|
||||
|| { echo "list-skills.sh 列不出技能,先跑 sync-domains.sh:$ROOT" >&2; exit 3; }
|
||||
cut -f1,2 "$TMPD/raw.txt" | LC_ALL=C sort > "$TMPD/skills.txt"
|
||||
[ -s "$TMPD/skills.txt" ] || { echo "掃不到任何技能:$ROOT" >&2; exit 3; }
|
||||
|
||||
# 各 domain 的現行版本號與本機目錄。domain 名以 plugin.json 的 name 為準,checkout 目錄名
|
||||
# 只是退路:目錄名是誰 clone 誰決定的,換一台機器就可能叫別的名字。第三欄記那個目錄,
|
||||
# probe 要拿它把 {root}/jsc-{domain} 換成本機的實際位置,才驗得到腳本在不在。
|
||||
: > "$TMPD/versions.txt"
|
||||
for p in "$ROOT"/*/plugin.json; do
|
||||
[ -f "$p" ] || continue
|
||||
n=$(sed -n 's/.*"name"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$p" | head -n1)
|
||||
v=$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' "$p" | head -n1)
|
||||
case $n in
|
||||
jsc-?*) ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
[ -n "$v" ] || continue
|
||||
printf '%s\t%s\t%s\n' "${n#jsc-}" "$v" "${p%/plugin.json}" >> "$TMPD/versions.txt"
|
||||
done
|
||||
|
||||
# 清單資料列:# 開頭的註解與空行都不算。
|
||||
grep -v '^[[:space:]]*#' "$SPEC" | grep -v '^[[:space:]]*$' > "$TMPD/rows.txt" || true
|
||||
[ -s "$TMPD/rows.txt" ] || { echo "清單裡一列資料都沒有:$SPEC" >&2; exit 3; }
|
||||
|
||||
: > "$TMPD/fail-set.txt"
|
||||
: > "$TMPD/fail-row.txt"
|
||||
: > "$TMPD/hint.txt"
|
||||
|
||||
report() { # $1=domain/name 或 -,$2=說明
|
||||
printf '%s:%s:%s\n' "$SPEC" "$1" "$2" >> "$TMPD/fail-set.txt"
|
||||
}
|
||||
|
||||
# --- 1. 一一對應 ---
|
||||
cut -f1,2 "$TMPD/rows.txt" | LC_ALL=C sort > "$TMPD/keys.txt"
|
||||
LC_ALL=C uniq -d "$TMPD/keys.txt" > "$TMPD/dup.txt"
|
||||
LC_ALL=C uniq "$TMPD/keys.txt" > "$TMPD/keys-uniq.txt"
|
||||
LC_ALL=C comm -23 "$TMPD/skills.txt" "$TMPD/keys-uniq.txt" > "$TMPD/missing.txt"
|
||||
LC_ALL=C comm -13 "$TMPD/skills.txt" "$TMPD/keys-uniq.txt" > "$TMPD/extra.txt"
|
||||
|
||||
while IFS="$TAB" read -r d n; do
|
||||
[ -n "${d:-}" ] || continue
|
||||
report "$d/$n" '清單有兩列以上寫同一支技能,只留一列'
|
||||
done < "$TMPD/dup.txt"
|
||||
|
||||
while IFS="$TAB" read -r d n; do
|
||||
[ -n "${d:-}" ] || continue
|
||||
report "$d/$n" '這支技能存在,清單缺這一列。沒有判定結果,助理永遠不知道它存在'
|
||||
done < "$TMPD/missing.txt"
|
||||
|
||||
while IFS="$TAB" read -r d n; do
|
||||
[ -n "${d:-}" ] || continue
|
||||
report "$d/$n" '清單多這一列,本機沒有這支技能。請刪掉,否則助理會去觸發叫不出來的技能'
|
||||
done < "$TMPD/extra.txt"
|
||||
|
||||
# --- 2~5. 逐列查欄位。多出來的列上面已經報過,這裡跳過,同一個缺陷不印兩遍。 ---
|
||||
awk -F"$TAB" \
|
||||
-v SPEC="$SPEC" -v SKILLS="$TMPD/skills.txt" -v VERS="$TMPD/versions.txt" \
|
||||
-v FAILS="$TMPD/fail-row.txt" -v HINTS="$TMPD/hint.txt" '
|
||||
function bad(k, m) { printf "%s:%s:%s\n", SPEC, k, m > FAILS }
|
||||
function hint(k, m) { printf "%s:%s:%s\n", SPEC, k, m > HINTS }
|
||||
function vlt(a, b, x, y, na, nb, n, i, ai, bi) {
|
||||
na = split(a, x, "."); nb = split(b, y, ".")
|
||||
n = (na > nb) ? na : nb
|
||||
for (i = 1; i <= n; i++) {
|
||||
ai = (i <= na) ? x[i] + 0 : 0
|
||||
bi = (i <= nb) ? y[i] + 0 : 0
|
||||
if (ai < bi) return 1
|
||||
if (ai > bi) return 0
|
||||
}
|
||||
return 0
|
||||
}
|
||||
function way_ok(w, t, m, i) {
|
||||
m = split(w, t, ",")
|
||||
for (i = 1; i <= m; i++) if (!(t[i] in WAY)) return 0
|
||||
return (m > 0)
|
||||
}
|
||||
function trig_ok(t, e) {
|
||||
if (t ~ /^at:..*$/) return 1
|
||||
if (t ~ /^after:..*$/) { e = substr(t, 7); sub(/:.*$/, "", e); return (e in EV) }
|
||||
return 0
|
||||
}
|
||||
# probe 裡認不得的代入點,回傳第一個;全部認得回傳空字串。認不得的代入點代不進去,
|
||||
# 會原樣送進指令,於是那一輪安安靜靜跑錯東西。
|
||||
function ph_bad(s, t, p) {
|
||||
t = s
|
||||
while (match(t, /\{[^}]*\}/)) {
|
||||
p = substr(t, RSTART + 1, RLENGTH - 2)
|
||||
if (!(p in PH)) return p
|
||||
t = substr(t, RSTART + RLENGTH)
|
||||
}
|
||||
return ""
|
||||
}
|
||||
# probe 的第一個非環境變數指派詞,也就是腳本路徑本身。
|
||||
function script_of(s, n, a, i) {
|
||||
n = split(s, a, " ")
|
||||
for (i = 1; i <= n; i++) {
|
||||
if (a[i] ~ /^[A-Za-z_][A-Za-z0-9_]*=/) continue
|
||||
return a[i]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
BEGIN {
|
||||
split("full slice cond none", a, " "); for (i in a) VERDICT[a[i]] = 1
|
||||
split("invoke patrol remind", b, " "); for (i in b) WAY[b[i]] = 1
|
||||
split("seed judged", c, " "); for (i in c) ORIGIN[c[i]] = 1
|
||||
split("worklog-written wp-merged stage-entered analyze-completed hook-error session-start session-end", \
|
||||
d, " "); for (i in d) EV[d[i]] = 1
|
||||
split("root cli repo", e, " "); for (i in e) PH[e[i]] = 1
|
||||
}
|
||||
FILENAME == SKILLS { sk[$1 "\t" $2] = 1; next }
|
||||
FILENAME == VERS { cur[$1] = $2; ddir[$1] = $3; next }
|
||||
{
|
||||
key = $1 "/" $2
|
||||
if (NF != 12) { bad(key, "這一列有 " NF " 欄,合約規定 12 欄"); next }
|
||||
if (!(($1 "\t" $2) in sk)) next
|
||||
verdict = $3; way = $4; slice = $5; human = $6
|
||||
trig = $7; rec = $8; nxt = $9; ver = $10; org = $11; probe = $12
|
||||
|
||||
for (i = 1; i <= 12; i++)
|
||||
if ($i == "") bad(key, "第 " i " 欄是空的。TSV 沒有空格這種值,不填就寫一個減號")
|
||||
|
||||
if (!(verdict in VERDICT)) {
|
||||
bad(key, "verdict 只認 full、slice、cond、none,實際是「" verdict "」")
|
||||
next
|
||||
}
|
||||
|
||||
# 不交的那一列只留理由:交出方式、切片、時間點、週期全部要空成減號。
|
||||
# 留著值等於清單自己在說「不交但這樣交」,下一輪讀的人不知道該信哪一邊。
|
||||
if (verdict == "none") {
|
||||
if (way != "-") bad(key, "不交的列,way 要寫 -,實際是「" way "」")
|
||||
if (slice != "-") bad(key, "不交的列,slice 要寫 -,實際是「" slice "」")
|
||||
if (trig != "-") bad(key, "不交的列,trigger 要寫 -,實際是「" trig "」")
|
||||
if (rec != "-") bad(key, "不交的列,recur 要寫 -,實際是「" rec "」")
|
||||
if (human == "-") bad(key, "不交的列要寫不交的理由,否則下次分不出「判過決定不交」與「還沒判」")
|
||||
} else {
|
||||
if (way == "-") bad(key, "交出去的列一定要有交出方式,way 不可以是 -")
|
||||
else if (!way_ok(way)) bad(key, "way 只認 invoke、patrol、remind,多個用半形逗號隔開,實際是「" way "」")
|
||||
if (!trig_ok(trig)) bad(key, "trigger 要寫 at:{時間} 或 after:{固定事件名},實際是「" trig "」")
|
||||
if (rec != "once" && rec !~ /^every:..*$/ && rec !~ /^cron:..*$/)
|
||||
bad(key, "recur 只認 once、every:{間隔}、cron:{式子},實際是「" rec "」")
|
||||
}
|
||||
|
||||
if (verdict == "full") {
|
||||
if (slice != "-") bad(key, "全交是整支都交,slice 要寫 -,實際是「" slice "」")
|
||||
if (human != "-") bad(key, "全交沒有留在人手上的那一半,human 要寫 -,實際是「" human "」")
|
||||
}
|
||||
# 切片交與條件式交少了「留在人手上的那一半」,助理下一輪會把整支技能當成可交的一路跑完。
|
||||
if (verdict == "slice" || verdict == "cond") {
|
||||
if (slice == "-") bad(key, "交出的那一段沒寫,slice 不可以是 -")
|
||||
if (human == "-") bad(key, "留在人手上的那一半沒寫,助理下一輪會把整支技能當成可交的一路跑完")
|
||||
}
|
||||
|
||||
if (nxt !~ /^jsc-[a-z0-9-]+:[a-z0-9-]+$/)
|
||||
bad(key, "next 要寫成 jsc-{domain}:{name},實際是「" nxt "」")
|
||||
else {
|
||||
n2 = substr(nxt, 5); sub(/:/, "\t", n2)
|
||||
if (!(n2 in sk)) bad(key, "next 指到不存在的技能「" nxt "」,助理會一路重試叫不出來的東西")
|
||||
}
|
||||
|
||||
if (!(org in ORIGIN)) bad(key, "origin 只認 seed 與 judged,實際是「" org "」")
|
||||
else if (org == "seed") hint(key, "origin=seed:依既有盤點種入,還沒走過決策樹,待複核")
|
||||
|
||||
if (ver !~ /^[0-9]+(\.[0-9]+)*$/) bad(key, "version 要是 plugin 版本號,實際是「" ver "」")
|
||||
else if (($1 in cur) && vlt(ver, cur[$1]))
|
||||
hint(key, "判定時記的版本號 " ver " 落後 jsc-" $1 " 現行的 " cur[$1] ",要複判")
|
||||
|
||||
# --- probe:那一段唯讀盤點實際要跑的指令。判準見檔頭「什麼算缺失、什麼只算提示」。 ---
|
||||
if (verdict == "none" || way ~ /(^|,)invoke(,|$)/) {
|
||||
if (probe != "-")
|
||||
bad(key, "way 含 invoke 或這一列不交,probe 要寫 -,實際是「" probe "」。填了指令,種入那一支會改拿指令當動作,整支交出就變成只跑一支腳本")
|
||||
} else if (probe == "-") {
|
||||
bad(key, "way 只有 patrol 或 remind,probe 不可以是 -:沒有指令的那幾筆一律退回只提醒,等於判過要交卻什麼都沒交出去。接不上就寫 pending:{理由}")
|
||||
}
|
||||
|
||||
if (probe ~ /^pending:/) {
|
||||
if (probe == "pending:") bad(key, "pending 後面要寫不接的理由,留白的話下一輪分不出是刻意還是漏填")
|
||||
else hint(key, "probe=" probe ":唯讀盤點的入口還沒接上,待接線")
|
||||
} else if (probe != "-") {
|
||||
if (probe ~ /[$~]/)
|
||||
bad(key, "probe 裡有金錢符號或波浪號,實際是「" probe "」。那兩種寫法在無人值守那一輪解不出來,也進不了允許清單,會被靜靜擋掉")
|
||||
p2 = ph_bad(probe)
|
||||
if (p2 != "")
|
||||
bad(key, "probe 用了認不得的代入點「{" p2 "}」,只認 {root}、{cli}、{repo}。代不進去的字面值會原樣送進指令")
|
||||
sp = script_of(probe)
|
||||
if (sp !~ /^\{root\}\/jsc-[a-z0-9-]+\/..*$/)
|
||||
bad(key, "probe 的腳本路徑要寫成 {root}/jsc-{domain}/… ,實際是「" sp "」")
|
||||
else {
|
||||
pd = sp; sub(/^\{root\}\/jsc-/, "", pd); sub(/\/.*$/, "", pd)
|
||||
rest = sp; sub(/^\{root\}\/jsc-[a-z0-9-]+\//, "", rest)
|
||||
if (!(pd in ddir))
|
||||
hint(key, "probe 指到的 jsc-" pd " 本機沒有裝,這一列的腳本這一次驗不到")
|
||||
else if (system("test -f '\''" ddir[pd] "/" rest "'\''") != 0)
|
||||
bad(key, "probe 指到的腳本不存在:" ddir[pd] "/" rest "。助理每一輪都會叫不到它,而失敗不會自動暫停")
|
||||
}
|
||||
}
|
||||
}
|
||||
' "$TMPD/skills.txt" "$TMPD/versions.txt" "$TMPD/rows.txt"
|
||||
|
||||
cat "$TMPD/fail-set.txt" "$TMPD/fail-row.txt" > "$TMPD/fails.txt"
|
||||
|
||||
if [ -s "$TMPD/hint.txt" ]; then
|
||||
LC_ALL=C sort "$TMPD/hint.txt"
|
||||
fi
|
||||
|
||||
rows=$(wc -l < "$TMPD/rows.txt" | tr -d ' ')
|
||||
skills=$(wc -l < "$TMPD/skills.txt" | tr -d ' ')
|
||||
hints=$(wc -l < "$TMPD/hint.txt" | tr -d ' ')
|
||||
|
||||
if [ -s "$TMPD/fails.txt" ]; then
|
||||
LC_ALL=C sort "$TMPD/fails.txt" >&2
|
||||
echo "委派判定清單不符:$SPEC 有 $rows 列,本機有 $skills 支技能,逐項見上方(另有 $hints 則提示,見 stdout)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "委派判定清單檢查通過:$SPEC 的 $rows 列對上 $skills 支技能,必填欄位齊全(另有 $hints 則提示,見 stdout)" >&2
|
||||
exit 0
|
||||
Executable
+141
@@ -0,0 +1,141 @@
|
||||
#!/usr/bin/env sh
|
||||
# check-skill-paths.sh — 檢查一個 domain 存取庫的文件裡,寫出來的腳本路徑解不解得出來。
|
||||
#
|
||||
# 用法: check-skill-paths.sh <domain-path>
|
||||
#
|
||||
# 檢查兩項(掃 {domain-path} 底下的 skills/*/SKILL.md 與 references/*.md):
|
||||
# 一、帶 domain 名的路徑(jsc-{domain}/tools/x.sh、{domain}/hooks/x.sh)——那個檔案要
|
||||
# 真的在對應的存取庫底下。指到不存在的檔案算缺失。
|
||||
# 二、不帶 domain 名的路徑(tools/x.sh、hooks/x.sh)——檔案在這個存取庫底下就只算提示,
|
||||
# 不算缺失,理由見下面「為什麼不帶前綴只算提示」。檔案根本不在,才算缺失。
|
||||
#
|
||||
# 為什麼要有這支: lint-scripts.sh 掃的是 tools/ 與 hooks/ 目錄裡的檔案,它證明得了
|
||||
# 「這個存取庫裡有這支腳本、語法沒問題」,卻證明不了「文件裡寫的那條路徑解得出那支腳本」。
|
||||
# 兩件事差很遠。2026-09-04 實際踩到: 一份技能本文把自家腳本寫成不帶前綴的 tools/x.sh,
|
||||
# 而那支技能的基底目錄是 skills/{名稱}/,照字面解出來是 skills/{名稱}/tools/x.sh,
|
||||
# 結束碼 127。人工覆核那一輪看的是「tools/ 底下有沒有 x.sh」,有,於是就過了——
|
||||
# 覆核的問題問錯了,所以每一輪都會再過一次。
|
||||
#
|
||||
# 為什麼不帶前綴只算提示,不算缺失:
|
||||
# 不帶前綴的相對路徑會相對於**當下的工作目錄**解。在自己那個存取庫裡跑,剛好解得對;
|
||||
# 換一個工作目錄就解到別人的 tools/ 底下,或者解不出來。兩種都不會有明確的錯誤訊息,
|
||||
# 前者更糟——它會跑起來,跑的是另一支腳本。無人值守那一輪還多一層: 相對路徑進不了
|
||||
# 權限允許清單(那邊比對的是完整字面絕對路徑),會被靜靜擋掉。
|
||||
# 話說回來,這是整個技能組共通的寫法,一次上百處。把它判成缺失會讓每一個存取庫都紅,
|
||||
# 而一份全紅的報告跟沒有報告一樣。所以先量出來、指得出是哪幾行,改不改由人決定。
|
||||
#
|
||||
# 判定範圍與其極限: 只認 tools/ 與 hooks/ 兩個目錄底下的 *.sh。templates/ 與 references/
|
||||
# 底下的檔案不在這一支的範圍內——那些是資料不是入口,指錯了不會變成一支跑起來的別的程式。
|
||||
# 跨 domain 的路徑要那個 domain 的存取庫也在這台機器上才驗得到;不在就印成提示,
|
||||
# 不當缺失。這台機器沒裝,跟路徑寫錯,是兩件事。
|
||||
#
|
||||
# 輸出: 一行一項,格式 {檔案}:{行號}:{類別}:{路徑}(stdout);統計摘要走 stderr。
|
||||
# 類別 missing=指到不存在的檔案,unrooted=不帶前綴、相對於工作目錄解,
|
||||
# unknown=跨 domain 但那個存取庫不在這台機器上。
|
||||
# 結束碼: 0=掃到文件且沒有缺失(提示不算缺失)
|
||||
# 1=有缺失(missing 那幾行)
|
||||
# 2=用法錯誤(本腳本只吃一個參數)
|
||||
# 3=domain 路徑不存在,或底下一份可掃的文件都沒有——**什麼都沒掃**,不等於通過
|
||||
set -u
|
||||
|
||||
usage() {
|
||||
echo 'usage: check-skill-paths.sh <domain-path>' >&2
|
||||
exit 2
|
||||
}
|
||||
|
||||
[ "$#" -eq 1 ] || usage
|
||||
DOMAIN=${1%/}
|
||||
[ -n "$DOMAIN" ] || usage
|
||||
[ -d "$DOMAIN" ] || { echo "找不到 domain 路徑:$DOMAIN" >&2; exit 3; }
|
||||
|
||||
HERE=$(CDPATH= cd -P -- "$(dirname -- "$0")" && pwd -P)
|
||||
# 根目錄推導與別的檢核腳本共用同一套規則。跨 domain 的路徑要靠它才找得到別的存取庫;
|
||||
# 推不出來不是致命的,那幾筆改印成 unknown 提示。
|
||||
ROOT=''
|
||||
if [ -f "$HERE/plugins-root.sh" ]; then
|
||||
# shellcheck source=/dev/null
|
||||
. "$HERE/plugins-root.sh"
|
||||
ROOT=$(jsc_plugins_root 2>/dev/null) || ROOT=''
|
||||
fi
|
||||
|
||||
TMP=$(mktemp) || { echo "無法建立暫存檔" >&2; exit 3; }
|
||||
HITS=$(mktemp) || { rm -f "$TMP"; echo "無法建立暫存檔" >&2; exit 3; }
|
||||
trap 'rm -f "$TMP" "$HITS"' EXIT
|
||||
|
||||
# skills/*/SKILL.md 與 references/*.md 兩處。README 不掃: 那裡的路徑是給人看的目錄,
|
||||
# 不是叫誰去跑的入口。
|
||||
find "$DOMAIN/skills" -type f -name 'SKILL.md' -print 2>/dev/null > "$TMP"
|
||||
find "$DOMAIN/references" -type f -name '*.md' -print 2>/dev/null >> "$TMP"
|
||||
sort -o "$TMP" "$TMP"
|
||||
[ -s "$TMP" ] || { echo "底下沒有 skills/*/SKILL.md 也沒有 references/*.md,無文件可掃:$DOMAIN" >&2; exit 3; }
|
||||
|
||||
TOTAL=$(wc -l < "$TMP" | tr -d ' ')
|
||||
|
||||
# 這個存取庫自己的 domain 名。目錄名可能帶 jsc- 前綴(安裝後)或不帶(工作目錄版面),
|
||||
# 兩種都要認得,否則自家的路徑會被當成跨 domain 而驗不到。
|
||||
SELF=$(basename -- "$DOMAIN")
|
||||
SELF=${SELF#jsc-}
|
||||
|
||||
# 找某個 domain 的存取庫目錄。工作目錄版面不帶前綴、安裝後帶前綴,兩種都試。
|
||||
domain_dir() { # $1=domain 名
|
||||
[ -n "$ROOT" ] || return 1
|
||||
if [ -d "$ROOT/jsc-$1" ]; then printf '%s' "$ROOT/jsc-$1"; return 0; fi
|
||||
if [ -d "$ROOT/$1" ]; then printf '%s' "$ROOT/$1"; return 0; fi
|
||||
return 1
|
||||
}
|
||||
|
||||
while IFS= read -r f; do
|
||||
[ -n "$f" ] || continue
|
||||
|
||||
# 第一趟:帶 domain 名的路徑。前面可能還接著根目錄代入點(例如 {CURRENT}/),
|
||||
# 那不影響判定——要驗的是 {domain}/{tools|hooks}/{檔名} 這一段。
|
||||
grep -noE '(jsc-)?[a-z][a-z0-9-]*/(tools|hooks)/[a-z0-9-]+\.sh' "$f" 2>/dev/null |
|
||||
while IFS=: read -r ln path; do
|
||||
dom=${path%%/*}
|
||||
dom=${dom#jsc-}
|
||||
rest=${path#*/}
|
||||
if [ "$dom" = "$SELF" ]; then
|
||||
[ -f "$DOMAIN/$rest" ] || printf '%s:%s:missing:%s\n' "$f" "$ln" "$path"
|
||||
continue
|
||||
fi
|
||||
if dir=$(domain_dir "$dom"); then
|
||||
[ -f "$dir/$rest" ] || printf '%s:%s:missing:%s\n' "$f" "$ln" "$path"
|
||||
else
|
||||
printf '%s:%s:unknown:%s\n' "$f" "$ln" "$path"
|
||||
fi
|
||||
done
|
||||
|
||||
# 第二趟:不帶 domain 名的路徑。字元集把斜線排掉,第一趟已經算過的那幾筆才不會再算一次。
|
||||
grep -noE '(^|[^-a-zA-Z0-9/_.{])(tools|hooks)/[a-z0-9-]+\.sh' "$f" 2>/dev/null |
|
||||
while IFS=: read -r ln raw; do
|
||||
path=$(printf '%s' "$raw" | sed 's|^[^t h]*||; s|^\(tools\|hooks\)|\1|')
|
||||
case "$path" in
|
||||
tools/*|hooks/*) ;;
|
||||
*) path=${raw#?} ;;
|
||||
esac
|
||||
case "$path" in
|
||||
tools/*|hooks/*) ;;
|
||||
*) continue ;;
|
||||
esac
|
||||
if [ -f "$DOMAIN/$path" ]; then
|
||||
printf '%s:%s:unrooted:%s\n' "$f" "$ln" "$path"
|
||||
else
|
||||
printf '%s:%s:missing:%s\n' "$f" "$ln" "$path"
|
||||
fi
|
||||
done
|
||||
done < "$TMP" | sort -u > "$HITS"
|
||||
|
||||
N_MISS=$(grep -c ':missing:' "$HITS" 2>/dev/null || true)
|
||||
N_UNROOT=$(grep -c ':unrooted:' "$HITS" 2>/dev/null || true)
|
||||
N_UNKNOWN=$(grep -c ':unknown:' "$HITS" 2>/dev/null || true)
|
||||
: "${N_MISS:=0}" "${N_UNROOT:=0}" "${N_UNKNOWN:=0}"
|
||||
|
||||
[ -s "$HITS" ] && cat "$HITS"
|
||||
|
||||
if [ "$N_MISS" -gt 0 ]; then
|
||||
echo "腳本路徑檢查有缺失:共掃 $TOTAL 份文件,$N_MISS 條指到不存在的檔案,另有 $N_UNROOT 條不帶 domain 名、$N_UNKNOWN 條跨 domain 但存取庫不在這台機器上" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "腳本路徑檢查通過:共掃 $TOTAL 份文件,沒有指到不存在的檔案;另有 $N_UNROOT 條不帶 domain 名、$N_UNKNOWN 條跨 domain 但存取庫不在這台機器上,兩種都只是提示" >&2
|
||||
exit 0
|
||||
@@ -0,0 +1,108 @@
|
||||
# delegate-spec.tsv — jsc 技能組的委派判定清單。一支技能一列,記「這一支能不能交給背景助理」。
|
||||
#
|
||||
# 判準本身寫在 references/delegate-criteria.md,四支技能異動技能(skill-new、skill-update、
|
||||
# skill-delete、skillset-update)共用那一份。這張表只放判定結果,不放判準。
|
||||
#
|
||||
# 判定結果只放這裡,不寫進 SKILL.md 的 frontmatter:name 與 description 之外的自訂欄位,
|
||||
# 有被各 CLI 的技能驗證擋掉的風險。新增或刪除技能時同時補上或刪掉這一列,
|
||||
# tools/check-delegate.sh 才對得起來;缺列的技能,助理永遠不知道它存在。
|
||||
#
|
||||
# 欄位:domain<TAB>name<TAB>verdict<TAB>way<TAB>slice<TAB>human<TAB>trigger<TAB>recur<TAB>next<TAB>version<TAB>origin<TAB>probe
|
||||
# domain 技能所屬 domain,去掉開頭的 jsc-。形狀比照 list-skills.sh 第一欄
|
||||
# name 技能名。形狀比照 list-skills.sh 第二欄,兩欄合起來就是一支技能的身分
|
||||
# verdict full=全交 slice=切片交 cond=條件式交 none=不交
|
||||
# way 交出方式,多個用半形逗號隔開:invoke=觸發 patrol=巡檢 remind=提醒;不交寫 -
|
||||
# slice 交出的那一段。全交寫 -,整支都交;條件式交要把條件與條件不成立時的行為
|
||||
# 一起寫進來;不交寫 -
|
||||
# human 留在人手上的那一半。切片交與條件式交必填——少了它,助理下一輪會把整支技能
|
||||
# 當成可交的一路跑完。不交填不交的理由,否則下次分不出「判過決定不交」與
|
||||
# 「還沒判」。全交寫 -
|
||||
# trigger 第一次什麼時候到期:at:{ISO 時間},立刻要做寫 at:now;或 after:{事件名}。
|
||||
# 事件名只認固定詞彙,其中三個一定要帶參數,少了參數會被擋下:
|
||||
# 不帶參數:worklog-written、hook-error、session-start、session-end
|
||||
# 要帶參數:wp-merged:{工作包代號}、stage-entered:{階段}、
|
||||
# analyze-completed:{HASH}
|
||||
# 為什麼要寫明參數形狀:那三個事件是「哪一個工作包合併了」而不是「有工作包
|
||||
# 合併了」,少了參數就指不到特定的一件事。寫成不帶參數的形狀,登錄那一步會
|
||||
# 回欄位不合法,那支技能於是靜靜沒有內建項——少了什麼要看種入回報的 bad=
|
||||
# 那幾行才發現。不交寫 -
|
||||
# recur 做完之後還要不要再排:once、every:{間隔}、cron:{式子}。事件型 trigger 配
|
||||
# every:{間隔} 時,間隔讀作重新武裝的最短間隔。不交寫 -
|
||||
# next 跑完之後建議接哪一支,寫成 jsc-{domain}:{name}。每一列都要填,不交的也要填
|
||||
# ——不交講的是助理不代跑,跟「跑完之後該接什麼」無關
|
||||
# version 判定當下該 domain 的 plugin 版本號。落後現行版本代表要複判,那只是提示,
|
||||
# 不算稽核缺失:版本號是 domain 層級,同 domain 改一支技能其餘技能也會被標到,
|
||||
# 當成缺失的話每次發版整個 domain 都亮紅,提示很快就被當雜訊忽略
|
||||
# origin seed=依既有盤點種入、待複核 judged=正式走過決策樹判定。
|
||||
# seed 只印成待複核提示,不算缺失;技能有異動時就地走一次決策樹,轉成 judged
|
||||
# probe 那一段唯讀盤點實際要跑的指令。只認三種寫法:
|
||||
# 一、一行指令。腳本路徑一律寫成 {root}/jsc-{domain}/… 開頭。{root} 是種入那一支
|
||||
# 拿到的字面絕對根目錄,由它自己代入;那一層的目錄名以 jsc-{domain} 為準,
|
||||
# 找不到就退回不帶前綴的 {domain},比照它找這一份清單本身的作法。
|
||||
# 指令裡不可以出現金錢符號或波浪號:那兩種寫法在無人值守那一輪解不出來,
|
||||
# 也進不了允許清單,會被靜靜擋掉。要帶環境變數就寫在指令最前面,
|
||||
# 例如 JSC_READONLY=1。另外兩個代入點,一個目標跑一次:{cli} 是助理偵測到的
|
||||
# CLI 代號,{repo} 是助理掃到的存取庫工作目錄。這三個以外的大括號一律算填錯——
|
||||
# 代不進去的字面值會原樣送進指令。
|
||||
# 結束碼只准表示過與不過,不准用來編碼狀態。這一條是後來補的,因為漏了它
|
||||
# 就踩過一次:填進來的那一支用結束碼帶三種狀態(接好、接好但這支 CLI 做不到、
|
||||
# 有東西沒接),而讀的那一邊照非零判失敗,於是有先天限制的那一支 CLI 每輪
|
||||
# 讓那一筆失敗一次、一天 96 次,而沒有人修得動。失敗次數存在的理由是指出
|
||||
# 「有一筆壞掉的項目每輪重試而沒人知道」,被修不動的數字填滿就等於用假的
|
||||
# 壞掉把真的壞掉蓋掉。要填的那一支如果用結束碼帶狀態,先去那一邊加一個
|
||||
# 只回過與不過的模式,不要在這一欄將就。
|
||||
# 填之前一定要真的跑一次那一行,不能照技能文件的措辭抄。實際踩過兩次:
|
||||
# 一次抄來的子命令那支腳本根本沒有,跑起來是用法錯誤;一次抄來的子命令會
|
||||
# 在標準輸入沒人關閉時無限等待,換成同一支的另一個子命令才回得來。兩種都
|
||||
# 不會在種入那一刻報錯,要等無人值守那一輪才發作,而那一輪沒有人在看。
|
||||
# 二、pending:{理由}。這一段切得出唯讀盤點,入口還沒接上;冒號後面寫不接的理由,
|
||||
# 留白的話下一輪分不出是刻意還是漏填。
|
||||
# 三、-。這一列沒有唯讀盤點入口。
|
||||
# 哪一種列填哪一種:way 含 invoke 的列與不交的列一律填 -。觸發的意思是呼叫整支
|
||||
# 技能,這一欄填了指令會讓種入那一支改拿指令當待辦簿的動作,於是整支交出變成
|
||||
# 只跑一支腳本,那支技能該寫的頁一頁都不會寫,而且看起來完全正常。way 只有
|
||||
# patrol 或 remind 的列一定要有值:那幾列的動作原本一律退回只提醒,有值才有
|
||||
# 事情做。
|
||||
# 為什麼要連網的先不填:連網要金鑰,金鑰一過期就讓那一項每輪失敗,或每輪靜靜
|
||||
# 回報沒事——後者更難查。純本機讀取本來一輪都不會失敗。先填會連網的那一種,等於
|
||||
# 用一批每輪報錯的項目把真的發現蓋掉。所以要連網的先寫 pending,理由寫清楚,
|
||||
# 等入口與金鑰都有著落再換成指令。
|
||||
# 檢核怎麼看:pending 只印成待接線提示,不算缺失,同 origin=seed 那一條——它是
|
||||
# 「判過、知道還沒接」,不是漏填。填錯欄位、指到不存在的腳本、用了認不得的
|
||||
# 代入點,都算缺失。
|
||||
#
|
||||
ask ask slice patrol 唯讀查 QUESTION_CONTENTS,確認要交辦的事是不是早就有答案 問答本身。助理在背景問不到人,沒有人在場就收不到答案 at:now every:1d jsc-gitea:wiki 0.1.3 seed pending:要連 wiki 讀 QUESTION 目錄頁,得帶金鑰
|
||||
assist assistant none - - 助理本身。讓它自我發動,一輪巡檢會在背景又叫起另一輪,誰都停不下來 - - jsc-log:stats 0.1.6 seed -
|
||||
cli delegate cond invoke 條件是這一項任務唯讀:唯讀巡檢可以委派給別支 CLI,省當前 CLI 的額度。條件不成立,也就是會改檔案的任務,一律不委派;委派失敗就退回自己跑 判斷哪一項算唯讀、額度要不要省,還有委派給哪一支 CLI at:now every:1d jsc-log:stats 0.3.4 seed -
|
||||
cli deploy slice remind 遠端有新版就提醒 安裝、更新、卸除、要求重啟 at:now every:1d jsc-hooks:hooks-install 0.3.4 seed pending:查遠端發佈版本要連 Gitea 並帶金鑰
|
||||
cli doctor cond invoke 條件式:只有在 doctor 呼叫自家 tools/ 與 templates/ 的路徑不再帶版本號之後才可以交。交出的那一段是定期整輪健檢、寫 CHECK_{HASH}。條件不成立時的行為:一律不交,維持人在現場叫用 修——那是 jsc-cli:setup,逐項確認。另外,條件沒滿足之前整支都留在人手上:doctor 自家腳本走的是 CLI 載入技能時給的外掛基底目錄,那條路徑帶版本號、進不了允許清單,無人值守的每一輪都會無聲卡在第一支腳本 at:now every:7d jsc-cli:setup 0.3.4 seed -
|
||||
cli models slice invoke 定期跑 model-tags.sh sync 重建能力標籤表,並盤點各 CLI 可用模型 換模型、改設定 at:now every:7d jsc-cli:doctor 0.3.4 seed -
|
||||
cli setup none - - 改設定與接線,要逐項確認 - - jsc-cli:doctor 0.3.4 seed -
|
||||
git commit none - - 對外不可逆 - - jsc-git:pr 0.1.5 seed -
|
||||
git pr none - - 對外不可逆 - - jsc-log:worklog 0.1.5 seed -
|
||||
gitea html-export none - - 要人指定是哪一頁或哪一個議題。助理在背景猜不到,猜錯就匯出別人的頁 - - jsc-gitea:html-style 0.2.5 seed -
|
||||
gitea html-style none - - 版型與樣式是使用者的偏好,要逐項確認才寫得下去 - - jsc-gitea:html-export 0.2.5 seed -
|
||||
gitea repo-sync slice patrol 盤點哪些存取庫落後遠端、哪些還沒同步下來 clone 與 update——會動工作目錄 at:now every:1d jsc-git:pr 0.2.5 seed pending:repo-sync.sh 會 clone 與 pull,沒有唯讀子命令;盤點落後也要連遠端
|
||||
gitea wiki none - - 助理的手腳,不獨立排程。助理所有 wiki 讀寫都經過它,一律附加 - - jsc-gitea:html-export 0.2.5 seed -
|
||||
gitea wiki-to-issue none - - 對外不可逆 - - jsc-sdlc:analyze 0.2.5 seed -
|
||||
hooks hooks-install slice patrol wire-cli.sh status --verdict 唯讀盤點接線,先天限制不算失敗 重新接線 at:now every:1d jsc-hooks:repair 0.4.5 seed JSC_READONLY=1 {root}/jsc-hooks/tools/wire-cli.sh status {cli} --verdict
|
||||
hooks repair slice invoke 巡檢抓到 hook 錯誤就發動修復 診斷、改哪一支、開 PR,全照 repair 自己的流程 after:hook-error every:1h jsc-git:pr 0.4.4 seed -
|
||||
log learn slice patrol 發動技能前先查過去教訓,也就是 consult 那一段 記錄教訓的判斷。哪一次值得留下來要人說 at:now every:1d jsc-log:worklog 0.1.9 seed pending:要連 wiki 讀 LEARN 目錄頁,得帶金鑰
|
||||
log report slice invoke 週期到了就產週報、月報、年報 報告要不要改寫、要不要送人看 at:now every:7d jsc-log:learn 0.1.9 seed -
|
||||
log stats full invoke - - at:now every:7d jsc-log:report 0.1.9 seed -
|
||||
log worklog slice patrol,remind 任務結束時收口計時與 token,補進 worklog-pending;該寫沒寫就催 寫日誌本體——狀態、細節、難處要人給 after:session-end every:1h jsc-log:learn 0.1.9 seed pending:worklog-pending.sh 七個子命令全部要先給工作階段雜湊,沒有不帶參數的盤點入口,掃不出「該寫沒寫」的那幾筆
|
||||
meta skill-check cond invoke 條件是只交機械檢核那一段:腳本語法、manifest 版本一致、README 技能清單與實際技能對得上。條件不成立的那一段,也就是語意審查與流程效率判斷,一律不交,那要讀完整份 SKILL.md 語意審查、流程與成本效率判斷,還有要不要套用建議 at:now every:7d jsc-meta:skill-update 0.3.1 seed -
|
||||
meta skill-delete none - - 改技能組本身,等於助理改自己 - - jsc-meta:skill-check 0.3.1 seed -
|
||||
meta skill-new none - - 改技能組本身,等於助理改自己 - - jsc-meta:skill-check 0.3.1 seed -
|
||||
meta skill-update none - - 改技能組本身,等於助理改自己 - - jsc-meta:skill-check 0.3.1 seed -
|
||||
meta skillset-update none - - 改技能組本身,等於助理改自己 - - jsc-meta:skill-check 0.3.1 seed -
|
||||
meta ste100-sync slice patrol,remind 定期比對上游版本,落後就提醒 套用上游變更 at:now every:7d jsc-meta:skill-check 0.3.1 seed pending:比對上游版本要連上游站台
|
||||
meta tooling-guide full invoke - - at:now every:7d jsc-meta:skill-check 0.3.1 seed -
|
||||
pkg pkg-update slice patrol 用 list-packages.sh、latest-version.sh 唯讀盤點落後最新穩定版的套件 升版、跑建置與測試 at:now every:7d jsc-review:code-review 0.1.0 seed {root}/jsc-pkg/tools/list-packages.sh {repo}
|
||||
review api-doc none - - 審查要判斷,判準要讀完整份文件與程式碼;助理在背景判不出來 - - jsc-git:pr 0.1.3 seed -
|
||||
review code-review none - - 審查要判斷,而且要不要照著改由呼叫端決定 - - jsc-review:api-doc 0.1.3 seed -
|
||||
review comment-cleanup none - - 會改專案檔案 - - jsc-git:commit 0.1.3 seed -
|
||||
sdlc analyze slice patrol,remind 盤點 ANALYZE_CONTENTS 未完成的分析並先把選項清單備好;另巡檢分析頁勾選與工作包議題狀態對不對得上 分析本體全部要決策。勾選與議題對不上時要對齊哪一邊,是真實來源衝突,也要人判 at:now every:1d jsc-sdlc:implement 0.3.2 seed pending:要連 wiki 讀 ANALYZE 目錄頁,得帶金鑰
|
||||
sdlc implement slice patrol,remind wp-gate.sh check-deps 盤點哪些工作包可以開始;階段鎖殘留就提醒 挑工作包、寫程式碼、開 PR。鎖檔不自己刪 at:now every:1d jsc-log:worklog 0.3.2 seed {root}/jsc-hooks/hooks/sdlc-gate.sh wp-report
|
||||
sdlc maintain none - - 核心是決策與寫程式碼 - - jsc-log:worklog 0.3.2 seed -
|
||||
sdlc plan slice patrol,remind 盤點 PLAN_CONTENTS 還沒分析的計畫,先把選項清單備好 規劃本體全部要決策 at:now every:1d jsc-sdlc:analyze 0.3.2 seed pending:要連 wiki 讀 PLAN 目錄頁,得帶金鑰
|
||||
|
Reference in New Issue
Block a user