feat(wiki): 目錄頁專用存取庫入準則,skill-check 加入優化建議流程
What:準則的環境變數表與命名總表加入 JSC_WIKI_REPO_CONTENTS 與目錄頁專用存取庫 一節,HASH 規則改為完整 40 碼。skill-check 的 Group 3 先讀上一輪決議,建議表加上 決議與決議日期兩欄,新增步驟 8 把稽核結果寫進 SKILLSET 頁。新增 check-page-name.sh 與兩份 SKILLSET 範本。 Why:優化建議原本每輪產出後就散掉,決議為延後的項目下一輪會重新掃、重新問一次, 正是 skill-check 自己第三個面向點名的毛病。SKILLSET_CONTENTS 是 14 個目錄頁裡 唯一沒有範本的,四支技能都被要求寫它,卻沒有欄位定義可套。 How:Group 1 補進三支現成但沒人呼叫的檢查腳本——ste100-lint.sh、check-wiki-rules.sh 與新增的 check-page-name.sh。讀不到上一輪決議時只停掉 Group 3,不再中止整輪:那兩組 完全不碰 wiki,金鑰失效就會鎖死整組技能唯一的稽核路徑。另外四支 meta 技能原本把目錄頁 寫進 SKILLSET 存取庫,一併改走 CONTENTS。
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jsc-meta",
|
"name": "jsc-meta",
|
||||||
"version": "0.2.7",
|
"version": "0.2.8",
|
||||||
"description": "技能組自我管理:新建、更新、刪除技能與技能準則",
|
"description": "技能組自我管理:新建、更新、刪除技能與技能準則",
|
||||||
"skills": "./skills",
|
"skills": "./skills",
|
||||||
"author": {
|
"author": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jsc-meta",
|
"name": "jsc-meta",
|
||||||
"version": "0.2.7",
|
"version": "0.2.8",
|
||||||
"description": "技能組自我管理:新建、更新、刪除技能與技能準則",
|
"description": "技能組自我管理:新建、更新、刪除技能與技能準則",
|
||||||
"skills": "./skills",
|
"skills": "./skills",
|
||||||
"jsc": {
|
"jsc": {
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安
|
|||||||
|
|
||||||
### `skill-check`
|
### `skill-check`
|
||||||
|
|
||||||
例行稽核——沒有變更需求時,同步存取庫之後併行跑三組:`lint-scripts.sh` 加 `lint-frontmatter.sh` 加 `check-behaviors.sh` 加 hook smoke、準則審核檢查清單、流程與成本優化審查。優化面向包含可平行化、可下放工具、重複來回、冗餘步驟、過早或過晚的閘門與可省的成本;不符項目與優化建議分開回報,逐項決策樹確認後才套用,最後逐 repo 開 PR。有變更需求改用 skillset-update。
|
例行稽核——沒有變更需求時,同步存取庫之後併行跑三組:`lint-scripts.sh` 加 `lint-frontmatter.sh` 加 `check-behaviors.sh` 加 `ste100-lint.sh` 加 `check-wiki-rules.sh` 加 `check-page-name.sh` 加 hook smoke、準則審核檢查清單、流程與成本優化審查。優化審查先讀回各 domain `SKILLSET_{HASH}` 上已決議的建議,決議欄寫著「套用」或「延後」的不重複掃、不重複問;面向包含可平行化、可下放工具、重複來回、冗餘步驟、過早或過晚的閘門與可省的成本。不符項目與優化建議分開回報,逐項決策樹確認並記下決議與決議日期後才套用,逐 repo 開 PR,最後把本輪結果附加到每個受影響 domain 的 `SKILLSET_{HASH}` 並登記在 `SKILLSET_CONTENTS`。有變更需求改用 skillset-update。
|
||||||
|
|
||||||
### `ste100-sync`
|
### `ste100-sync`
|
||||||
|
|
||||||
@@ -63,6 +63,8 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安
|
|||||||
| `references/pr-report.md` | PR 收尾回報格式唯一來源,所有會開 PR 的技能都指向這裡 |
|
| `references/pr-report.md` | PR 收尾回報格式唯一來源,所有會開 PR 的技能都指向這裡 |
|
||||||
| `references/deploy-verify.md` | 四支異動技能共用的部署與驗證流程:判路線、部署或工作樹、**在新的 CLI 行程裡驗證**、失敗分流 |
|
| `references/deploy-verify.md` | 四支異動技能共用的部署與驗證流程:判路線、部署或工作樹、**在新的 CLI 行程裡驗證**、失敗分流 |
|
||||||
| `references/behaviors.md` | 本 domain 的技能行為清單:一支技能一節,五列記下觸發時機、關鍵步驟、外部呼叫、完成條件、可驗證跡象,供稽核與驗證比對。格式合約見 `references/guidelines.md` 的「技能行為清單」 |
|
| `references/behaviors.md` | 本 domain 的技能行為清單:一支技能一節,五列記下觸發時機、關鍵步驟、外部呼叫、完成條件、可驗證跡象,供稽核與驗證比對。格式合約見 `references/guidelines.md` 的「技能行為清單」 |
|
||||||
|
| `templates/skillset-contents.md` | `SKILLSET_CONTENTS` 目錄頁樣板。一列代表一個 domain 存取庫;本頁落在 `JSC_WIKI_REPO_CONTENTS`,指向內容頁的連結用絕對網址,一律用 `jsc-gitea/tools/wiki-contents.sh upsert SKILLSET 2 "{owner}/{repo}"` 只寫自己那一列 |
|
||||||
|
| `templates/skillset-page.md` | `SKILLSET_{HASH}` 內容頁樣板。歷次異動**累積**分節,每節記日期、異動類型、異動需求、動到的技能、改動檔案、PR 網址、部署路線判定與驗證結果;`skill-check` 那一節另含優化建議表,決議與決議日期兩欄供下一輪讀回 |
|
||||||
| `templates/tooling-contents.md` | `TOOLING_CONTENTS` 目錄頁樣板。一列代表一組「機器、CLI、帳號」;只更新自己那一列,別人的列原樣保留,**禁止整頁覆蓋** |
|
| `templates/tooling-contents.md` | `TOOLING_CONTENTS` 目錄頁樣板。一列代表一組「機器、CLI、帳號」;只更新自己那一列,別人的列原樣保留,**禁止整頁覆蓋** |
|
||||||
| `templates/tooling-page.md` | `TOOLING_{HASH}` 內容頁樣板。分節對應 `inventory-tooling.sh` 的輸出;**每次盤點覆寫整頁**,只留現況,不留歷史 |
|
| `templates/tooling-page.md` | `TOOLING_{HASH}` 內容頁樣板。分節對應 `inventory-tooling.sh` 的輸出;**每次盤點覆寫整頁**,只留現況,不留歷史 |
|
||||||
| `tools/plugins-root.sh` | 推導技能組工作目錄的根,六支腳本共用。以 plugin 形式安裝時「腳本上兩層」會落在快取目錄,所以推導規則抽出來;推不出來 exit 1 並指名要設 `JSC_PLUGINS_ROOT` |
|
| `tools/plugins-root.sh` | 推導技能組工作目錄的根,六支腳本共用。以 plugin 形式安裝時「腳本上兩層」會落在快取目錄,所以推導規則抽出來;推不出來 exit 1 並指名要設 `JSC_PLUGINS_ROOT` |
|
||||||
@@ -70,6 +72,7 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安
|
|||||||
| `tools/lint-scripts.sh` | 一個 domain 的腳本檢查三合一:`sh -n` 語法、執行權限、檔頭結束碼宣告;有不合格 exit 1,沒有腳本可掃 exit 3(**不等於通過**) |
|
| `tools/lint-scripts.sh` | 一個 domain 的腳本檢查三合一:`sh -n` 語法、執行權限、檔頭結束碼宣告;有不合格 exit 1,沒有腳本可掃 exit 3(**不等於通過**) |
|
||||||
| `tools/lint-frontmatter.sh` | 一個 domain 每支 `skills/*/SKILL.md` 的 frontmatter 解析檢查:分隔線成對、必要鍵齊全、未加引號的純量不含「冒號加空白」也不以 YAML 特殊字元起頭、引號收得起來。不相依任何 YAML 套件。不合格 exit 1(清單在 stderr),用法錯誤 exit 2,沒有 SKILL.md 可掃 exit 3(**不等於通過**)。frontmatter 壞掉時 Antigravity 會**靜默丟棄整支技能**,沒有任何錯誤訊息 |
|
| `tools/lint-frontmatter.sh` | 一個 domain 每支 `skills/*/SKILL.md` 的 frontmatter 解析檢查:分隔線成對、必要鍵齊全、未加引號的純量不含「冒號加空白」也不以 YAML 特殊字元起頭、引號收得起來。不相依任何 YAML 套件。不合格 exit 1(清單在 stderr),用法錯誤 exit 2,沒有 SKILL.md 可掃 exit 3(**不等於通過**)。frontmatter 壞掉時 Antigravity 會**靜默丟棄整支技能**,沒有任何錯誤訊息 |
|
||||||
| `tools/check-behaviors.sh` | 比對一個 domain 的 `references/behaviors.md` 與 `skills/`:節對技能、字典序、每節一張表、五個欄位齊全且內容欄非空;不符 exit 1,用法錯誤 exit 2,找不到清單或找不到技能 exit 3(**不等於通過**) |
|
| `tools/check-behaviors.sh` | 比對一個 domain 的 `references/behaviors.md` 與 `skills/`:節對技能、字典序、每節一張表、五個欄位齊全且內容欄非空;不符 exit 1,用法錯誤 exit 2,找不到清單或找不到技能 exit 3(**不等於通過**) |
|
||||||
|
| `tools/check-page-name.sh` | 比對 wiki 頁名樣式三處是否一致:`jsc-gitea/tools/page-name.sh`(正本)、`jsc-hooks/hooks/comment-scope.sh`、`jsc-log/tools/worklog-pending.sh`。三處刻意不共用函式,因為 hook 必須自足;斷言十五種型別、40 碼與 8 碼兩種長度。不一致 exit 1,用法錯誤 exit 2,三處一支都找不到 exit 3(**不等於通過**) |
|
||||||
| `tools/deploy-route.sh` | 判定改動有沒有進存取庫的預設分支,決定走部署路線(exit 0)或工作樹路線(exit 3);判不出來 exit 1,**不等於工作樹路線** |
|
| `tools/deploy-route.sh` | 判定改動有沒有進存取庫的預設分支,決定走部署路線(exit 0)或工作樹路線(exit 3);判不出來 exit 1,**不等於工作樹路線** |
|
||||||
| `tools/sync-domains.sh` | 依 Gitea 正本 marketplace 把所有 domain 存取庫 clone 或 pull 到本機,印出 `domain<TAB>path`;**只有 exit 0 代表全部到位且最新**,exit 3 代表有存取庫跳過或 pull 失敗(stderr 列路徑),exit 2 代表有 domain clone 失敗 |
|
| `tools/sync-domains.sh` | 依 Gitea 正本 marketplace 把所有 domain 存取庫 clone 或 pull 到本機,印出 `domain<TAB>path`;**只有 exit 0 代表全部到位且最新**,exit 3 代表有存取庫跳過或 pull 失敗(stderr 列路徑),exit 2 代表有 domain clone 失敗 |
|
||||||
| `tools/list-skills.sh` | 列出正本 marketplace 上各 domain 存取庫的技能,印出 `domain<TAB>name<TAB>description`;不在正本清單上的存取庫不列 |
|
| `tools/list-skills.sh` | 列出正本 marketplace 上各 domain 存取庫的技能,印出 `domain<TAB>name<TAB>description`;不在正本清單上的存取庫不列 |
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "jsc-meta",
|
"name": "jsc-meta",
|
||||||
"version": "0.2.7",
|
"version": "0.2.8",
|
||||||
"description": "技能組自我管理:新建、更新、刪除技能與技能準則",
|
"description": "技能組自我管理:新建、更新、刪除技能與技能準則",
|
||||||
"skills": "./skills/",
|
"skills": "./skills/",
|
||||||
"jsc": {
|
"jsc": {
|
||||||
|
|||||||
+20
-20
@@ -7,50 +7,50 @@
|
|||||||
| 項目 | 內容 |
|
| 項目 | 內容 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| 觸發時機 | 手上沒有異動需求,要對整組技能做例行或臨時稽核時用。帶著異動需求要改多支技能走 skillset-update、只改一支走 skill-update |
|
| 觸發時機 | 手上沒有異動需求,要對整組技能做例行或臨時稽核時用。帶著異動需求要改多支技能走 skillset-update、只改一支走 skill-update |
|
||||||
| 關鍵步驟 | 先跑 sync-domains.sh 同步全部 domain 存取庫、再平行跑三組審查(第一組平行跑腳本檢查、frontmatter 檢查、行為清單檢查與 hook smoke,第二組以 sub agent 逐 domain 對 guidelines 檢查清單稽核,第三組以 sub agent 分六個面向審查流程與成本)、合併三組結果並用決策樹逐項確認(第二組留白的五項由第一組的結論補上)、以平行 sub agent 套用確認過的修正並跑 sync-skill-manifest.sh、跑 sync-marketplace.sh 同步兩份正本 marketplace、重跑三組驗證直到接受的修正全通過、每個受影響存取庫各開一條 PR |
|
| 關鍵步驟 | 先跑 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 的絕對網址、用 wiki-contents.sh upsert SKILLSET 2 把自己那一列寫進 CONTENTS 存取庫的 SKILLSET_CONTENTS |
|
||||||
| 外部呼叫 | tools/sync-domains.sh、tools/lint-scripts.sh、tools/lint-frontmatter.sh、tools/check-behaviors.sh、tools/sync-skill-manifest.sh、tools/sync-marketplace.sh、jsc-cli/tools/detect-clis.sh、jsc-hooks/tools/wire-cli.sh smoke、jsc-ask:ask、jsc-git:pr |
|
| 外部呼叫 | tools/sync-domains.sh、tools/lint-scripts.sh、tools/lint-frontmatter.sh、tools/check-behaviors.sh、tools/ste100-lint.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/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 檢查與行為清單檢查的結論(frontmatter 檢查退出 3 是「什麼都沒掃」,不算通過)、每個 domain 的檢查清單在合併後補齊、每項不合規與每項優化建議都有決策紀錄、接受的修正重驗通過、每個受影響存取庫都拿到 PR 網址 |
|
| 完成條件 | 每個 domain 都有腳本檢查、frontmatter 檢查、行為清單檢查與語言檢查的結論,wiki 規則檢查與頁名樣式檢查各有一次結論(frontmatter 檢查退出 3 是「什麼都沒掃」、頁名樣式檢查退出 3 是「什麼都沒查」,都不算通過)、每個 domain 的檢查清單在合併後補齊且那兩項整輪一份的結論在每個 domain 都填上同一個值、讀不到已決議清單的 domain 記成「本輪未取得已決議清單,優化建議暫不提出」、每項不合規與每項優化建議都有決策紀錄且優化建議帶決議日期、接受的修正重驗通過、每個受影響存取庫都拿到 PR 網址、每個受影響 domain 的 wiki 頁都寫成功,或列為未寫入並附完整內容 |
|
||||||
| 可驗證跡象 | 受影響存取庫留下檔案改動、改到行為的技能連帶改寫該存取庫的 references/behaviors.md、每個 domain 的 lint-frontmatter.sh 退出 0、README 的「Skills 目錄」重寫、三份 manifest 版本號提升、兩份 marketplace 檔逐位元一致、每個受影響存取庫一條 PR |
|
| 可驗證跡象 | 受影響存取庫留下檔案改動、改到行為的技能連帶改寫該存取庫的 references/behaviors.md、每個 domain 的 lint-frontmatter.sh 與 ste100-lint.sh 退出 0、check-page-name.sh 退出 0、README 的「Skills 目錄」重寫、三份 manifest 版本號提升、兩份 marketplace 檔逐位元一致、每個受影響存取庫一條 PR、每個受影響 domain 的 SKILLSET_{HASH} 各附加一節,並由 wiki-contents.sh upsert 退出 0 在 SKILLSET_CONTENTS 留下自己那一列、列裡以絕對網址指向該內容頁;本輪無 domain 被改動時,改成 plugins/meta 那一頁記「本輪無發現」 |
|
||||||
|
|
||||||
## skill-delete
|
## skill-delete
|
||||||
|
|
||||||
| 項目 | 內容 |
|
| 項目 | 內容 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| 觸發時機 | 要把一支技能從技能組移除時用。改名不走這支,走 skill-update |
|
| 觸發時機 | 要把一支技能從技能組移除時用。改名不走這支,走 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 |
|
| 關鍵步驟 | 跑 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 的絕對網址、用 wiki-contents.sh upsert SKILLSET 2 把自己那一列寫進 CONTENTS 存取庫的 SKILLSET_CONTENTS 並依 0、1、2、3、4、7、8 各自分流 |
|
||||||
| 外部呼叫 | tools/sync-domains.sh、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-ask:ask、jsc-git:pr、jsc-gitea:wiki |
|
| 外部呼叫 | tools/sync-domains.sh、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/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 網址與 wiki 頁都到手 |
|
| 完成條件 | 盤點清單每一檔都有「已修正」或「無需修正」的結論、技能目錄與行為清單那一節都不存在、list-skills.sh 查不到那一列、殘留檢查退出 0 或據實記成「無處可查」並帶進報告、PR 網址到手、SKILLSET_{HASH} 附加一節且舊節原樣留著、wiki-contents.sh upsert 退出 0 |
|
||||||
| 可驗證跡象 | skills/{name}/ 目錄消失、references/behaviors.md 少一節、README 與三份 manifest 更新、一條 PR、wiki SKILLSET_{HASH} 附加一節並登記在 SKILLSET_CONTENTS |
|
| 可驗證跡象 | skills/{name}/ 目錄消失、references/behaviors.md 少一節、README 與三份 manifest 更新、一條 PR、wiki SKILLSET_{HASH} 附加一節,並在 CONTENTS 存取庫的 SKILLSET_CONTENTS 留下自己那一列、列裡以絕對網址指向該內容頁 |
|
||||||
|
|
||||||
## skill-new
|
## skill-new
|
||||||
|
|
||||||
| 項目 | 內容 |
|
| 項目 | 內容 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| 觸發時機 | 要在技能組新增一支技能時用。改既有技能走 skill-update |
|
| 觸發時機 | 要在技能組新增一支技能時用。改既有技能走 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 |
|
| 關鍵步驟 | 平行跑 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 的絕對網址、用 wiki-contents.sh upsert SKILLSET 2 把自己那一列寫進 CONTENTS 存取庫的 SKILLSET_CONTENTS 並依 0、1、2、3、4、7、8 各自分流 |
|
||||||
| 外部呼叫 | tools/list-skills.sh、tools/sync-domains.sh、tools/sync-marketplace.sh、tools/check-behaviors.sh、tools/sync-skill-manifest.sh、tools/deploy-route.sh、jsc-gitea/tools/gitea.sh、jsc-ask:ask、jsc-git:pr、jsc-gitea:wiki |
|
| 外部呼叫 | tools/list-skills.sh、tools/sync-domains.sh、tools/sync-marketplace.sh、tools/check-behaviors.sh、tools/sync-skill-manifest.sh、tools/deploy-route.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 節的完成條件全數成立、wiki 頁寫成功 |
|
| 完成條件 | 四項提問都有紀錄、SKILL.md 與行為清單那一節都在、README 與三份 manifest 同步、檢查清單全過且 check-behaviors.sh 退出 0、PR 網址到手、deploy-verify.md 第 1 到第 5 節的完成條件全數成立、SKILLSET_{HASH} 附加一節且舊節原樣留著、wiki-contents.sh upsert 退出 0 |
|
||||||
| 可驗證跡象 | 新增 skills/{name}/SKILL.md、references/behaviors.md 多一節、README 與三份 manifest 更新、新 domain 時兩份 marketplace 檔多一筆 plugin 條目並同步到每個 domain 存取庫、一條 PR、wiki SKILLSET_{HASH} 附加一節 |
|
| 可驗證跡象 | 新增 skills/{name}/SKILL.md、references/behaviors.md 多一節、README 與三份 manifest 更新、新 domain 時兩份 marketplace 檔多一筆 plugin 條目並同步到每個 domain 存取庫、一條 PR、wiki SKILLSET_{HASH} 附加一節,並在 CONTENTS 存取庫的 SKILLSET_CONTENTS 留下自己那一列、列裡以絕對網址指向該內容頁 |
|
||||||
|
|
||||||
## skill-update
|
## skill-update
|
||||||
|
|
||||||
| 項目 | 內容 |
|
| 項目 | 內容 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| 觸發時機 | 要改一支既有技能時用。新增走 skill-new、刪除走 skill-delete、一次改多支或跨 domain 走 skillset-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 |
|
| 關鍵步驟 | 跑 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 的絕對網址、用 wiki-contents.sh upsert SKILLSET 2 把自己那一列寫進 CONTENTS 存取庫的 SKILLSET_CONTENTS 並依 0、1、2、3、4、7、8 各自分流 |
|
||||||
| 外部呼叫 | tools/sync-domains.sh、tools/list-skills.sh、tools/check-behaviors.sh、tools/sync-skill-manifest.sh、tools/deploy-route.sh、jsc-ask:ask、jsc-git:pr、jsc-gitea:wiki |
|
| 外部呼叫 | tools/sync-domains.sh、tools/list-skills.sh、tools/check-behaviors.sh、tools/sync-skill-manifest.sh、tools/deploy-route.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 節的完成條件全數成立、wiki 頁寫成功 |
|
| 完成條件 | 每個提問都有紀錄、技能檔案帶著改動、行為清單那一節與新行為一致且 check-behaviors.sh 退出 0、三份 manifest 同版、檢查清單全過、PR 網址到手、deploy-verify.md 第 1 到第 5 節的完成條件全數成立、SKILLSET_{HASH} 附加一節且舊節原樣留著、wiki-contents.sh upsert 退出 0 |
|
||||||
| 可驗證跡象 | 該技能的 SKILL.md 與相關檔案改動、references/behaviors.md 對應節改寫、README 與三份 manifest 更新、一條 PR、wiki SKILLSET_{HASH} 附加一節 |
|
| 可驗證跡象 | 該技能的 SKILL.md 與相關檔案改動、references/behaviors.md 對應節改寫、README 與三份 manifest 更新、一條 PR、wiki SKILLSET_{HASH} 附加一節,並在 CONTENTS 存取庫的 SKILLSET_CONTENTS 留下自己那一列、列裡以絕對網址指向該內容頁 |
|
||||||
|
|
||||||
## skillset-update
|
## skillset-update
|
||||||
|
|
||||||
| 項目 | 內容 |
|
| 項目 | 內容 |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| 觸發時機 | 一個異動需求橫跨多支技能或多個 domain,要一次做完時用。只改一支走 skill-update、手上沒有異動需求的例行稽核走 skill-check |
|
| 觸發時機 | 一個異動需求橫跨多支技能或多個 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 行程驗證、逐存取庫把異動報告附加到 wiki |
|
| 關鍵步驟 | 平行啟動 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 的絕對網址、用 wiki-contents.sh upsert SKILLSET 2 把自己那一列寫進 CONTENTS 存取庫的 SKILLSET_CONTENTS 並依 0、1、2、3、4、7、8 各自分流 |
|
||||||
| 外部呼叫 | tools/sync-domains.sh、tools/check-behaviors.sh、tools/sync-skill-manifest.sh、tools/deploy-route.sh、tools/list-skills.sh、jsc-ask:ask、jsc-git:pr、jsc-gitea:wiki |
|
| 外部呼叫 | tools/sync-domains.sh、tools/check-behaviors.sh、tools/sync-skill-manifest.sh、tools/deploy-route.sh、tools/list-skills.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 節對每個存取庫都成立、每個存取庫的 wiki 頁都寫成功 |
|
| 完成條件 | 受影響技能清單與三項塑形檢查都跟使用者談定、每個受影響存取庫都帶著改動、README 同步與 manifest 提升、每支動過的技能檢查清單全過且該 domain 的 check-behaviors.sh 退出 0、每個受影響存取庫都有 PR 網址、deploy-verify.md 第 1 到第 5 節對每個存取庫都成立、每個存取庫的 SKILLSET_{HASH} 都附加一節且舊節原樣留著、每個存取庫的 wiki-contents.sh upsert 都退出 0 |
|
||||||
| 可驗證跡象 | 每個受影響存取庫的技能檔案改動、各自的 references/behaviors.md 更新、README 與三份 manifest 更新、每個存取庫一條 PR、每個存取庫的 wiki SKILLSET_{HASH} 各附加一節並登記在 SKILLSET_CONTENTS |
|
| 可驗證跡象 | 每個受影響存取庫的技能檔案改動、各自的 references/behaviors.md 更新、README 與三份 manifest 更新、每個存取庫一條 PR、每個存取庫的 wiki SKILLSET_{HASH} 各附加一節,並在 CONTENTS 存取庫的 SKILLSET_CONTENTS 各留下自己那一列、列裡以絕對網址指向該內容頁 |
|
||||||
|
|
||||||
## ste100-sync
|
## ste100-sync
|
||||||
|
|
||||||
|
|||||||
+62
-19
@@ -135,19 +135,21 @@ PR 開立、更新、留言修正的收尾回報格式只看 [`references/pr-rep
|
|||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| `GITEA_HOST` | Gitea 站台(例:`https://gitea.jsc.idv.tw`) | 詢問使用者 |
|
| `GITEA_HOST` | Gitea 站台(例:`https://gitea.jsc.idv.tw`) | 詢問使用者 |
|
||||||
| `GITEA_TOKEN` | Gitea API token | 改用 tea 登入金鑰(`tea login list`);tea 也沒有才詢問使用者 |
|
| `GITEA_TOKEN` | Gitea API token | 改用 tea 登入金鑰(`tea login list`);tea 也沒有才詢問使用者 |
|
||||||
| `JSC_WIKI_REPO_QUESTION` | `QUESTION_CONTENTS`、`QUESTION_{HASH}` 所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
| `JSC_WIKI_REPO_CONTENTS` | **全部** `*_CONTENTS` 目錄頁所在的 `{owner}/{repo}`,十四種型別的目錄頁共用這一組 | 退回 `JSC_WIKI_REPO`;再沒有就 exit 3。**刻意不退回型別變數** |
|
||||||
| `JSC_WIKI_REPO_PLAN` | `PLAN_CONTENTS`、`PLAN_{HASH}` 所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
| `JSC_WIKI_REPO_QUESTION` | `QUESTION_{HASH}` 內容頁所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
||||||
| `JSC_WIKI_REPO_ANALYZE` | `ANALYZE_CONTENTS`、`ANALYZE_{HASH}` 所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
| `JSC_WIKI_REPO_PLAN` | `PLAN_{HASH}` 內容頁所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
||||||
| `JSC_WIKI_REPO_DELIVER` | `DELIVER_CONTENTS`、`DELIVER_{HASH}` 所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
| `JSC_WIKI_REPO_ANALYZE` | `ANALYZE_{HASH}` 內容頁所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
||||||
| `JSC_WIKI_REPO_MAINTAIN` | `MAINTAIN_CONTENTS` 所在的 `{owner}/{repo}`(本類型只有目錄頁) | 退回 `JSC_WIKI_REPO` |
|
| `JSC_WIKI_REPO_DELIVER` | `DELIVER_{HASH}` 內容頁所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
||||||
| `JSC_WIKI_REPO_REPO` | `REPO_CONTENTS`、`REPO_{HASH}` 所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
| `JSC_WIKI_REPO_MAINTAIN` | 保留給 `MAINTAIN` 的內容頁。本類型目前只有目錄頁,目錄頁走 `CONTENTS`,所以這個變數現在解不到任何一頁 | 退回 `JSC_WIKI_REPO` |
|
||||||
| `JSC_WIKI_REPO_LOG` | `LOG_CONTENTS`、`LOG_{HASH}` 所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
| `JSC_WIKI_REPO_REPO` | `REPO_{HASH}` 內容頁所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
||||||
| `JSC_WIKI_REPO_LEARN` | `LEARN_CONTENTS`、`LEARN_{HASH}` 所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
| `JSC_WIKI_REPO_LOG` | `LOG_{HASH}` 內容頁所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
||||||
| `JSC_WIKI_REPO_ERROR` | `ERROR_CONTENTS`、`ERROR_{HASH}` 所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
| `JSC_WIKI_REPO_LEARN` | `LEARN_{HASH}` 內容頁所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
||||||
| `JSC_WIKI_REPO_CHECK` | `CHECK_CONTENTS`、`CHECK_{HASH}` 所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
| `JSC_WIKI_REPO_ERROR` | `ERROR_{HASH}` 內容頁所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
||||||
| `JSC_WIKI_REPO_REPORT` | `REPORT_CONTENTS`、`REPORT_{HASH}` 所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
| `JSC_WIKI_REPO_CHECK` | `CHECK_{HASH}` 內容頁所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
||||||
| `JSC_WIKI_REPO_SKILLSET` | `SKILLSET_CONTENTS`、`SKILLSET_{HASH}` 所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
| `JSC_WIKI_REPO_REPORT` | `REPORT_{HASH}` 內容頁所在的 `{owner}/{repo}`,也是 `REPORT` 雜湊來源的取值處 | 退回 `JSC_WIKI_REPO` |
|
||||||
| `JSC_WIKI_REPO_TOOLING` | `TOOLING_CONTENTS`、`TOOLING_{HASH}` 所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
| `JSC_WIKI_REPO_SKILLSET` | `SKILLSET_{HASH}` 內容頁所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
||||||
|
| `JSC_WIKI_REPO_TOOLING` | `TOOLING_{HASH}` 內容頁所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
||||||
|
| `JSC_WIKI_REPO_MONITOR` | `MONITOR_{HASH}` 內容頁所在的 `{owner}/{repo}` | 退回 `JSC_WIKI_REPO` |
|
||||||
| `JSC_WIKI_REPO` | 未逐類設定時的共用 wiki `{owner}/{repo}` | 詢問使用者 |
|
| `JSC_WIKI_REPO` | 未逐類設定時的共用 wiki `{owner}/{repo}` | 詢問使用者 |
|
||||||
| `JSC_HOME` | Hook 資料目錄 | 預設 `~/.jsc` |
|
| `JSC_HOME` | Hook 資料目錄 | 預設 `~/.jsc` |
|
||||||
| `JSC_PR_WATCH_INTERVAL` | `jsc-gitea/tools/pr-watch.sh` 輪詢 PR 狀態的間隔秒數 | 預設 60 |
|
| `JSC_PR_WATCH_INTERVAL` | `jsc-gitea/tools/pr-watch.sh` 輪詢 PR 狀態的間隔秒數 | 預設 60 |
|
||||||
@@ -155,7 +157,12 @@ PR 開立、更新、留言修正的收尾回報格式只看 [`references/pr-rep
|
|||||||
| `JSC_ASSISTANT_GATE` | 助理運行閘門的開關,`off` 關閉整道閘門 | 閘門開啟 |
|
| `JSC_ASSISTANT_GATE` | 助理運行閘門的開關,`off` 關閉整道閘門 | 閘門開啟 |
|
||||||
| `JSC_ASSISTANT_HEARTBEAT_TTL` | 助理心跳的過期門檻秒數。排程週期由這個值推導 | 預設 300;壞值退回預設 |
|
| `JSC_ASSISTANT_HEARTBEAT_TTL` | 助理心跳的過期門檻秒數。排程週期由這個值推導 | 預設 300;壞值退回預設 |
|
||||||
|
|
||||||
頁面類型只讀自己的 `JSC_WIKI_REPO_{TYPE}`。只有該變數未設定時,才退回 `JSC_WIKI_REPO`。不得跨類型代用。
|
解析規則分兩條,都由 `jsc-gitea/tools/gitea.sh wiki-repo {TYPE}` 執行:
|
||||||
|
|
||||||
|
1. **內容頁**只讀自己的 `JSC_WIKI_REPO_{TYPE}`,只有該變數未設定時才退回 `JSC_WIKI_REPO`,再沒有就 exit 3。
|
||||||
|
2. **目錄頁**一律解 `CONTENTS`,鏈是 `JSC_WIKI_REPO_CONTENTS` → `JSC_WIKI_REPO` → exit 3。中間刻意不插型別變數:目錄頁全部落在同一個存取庫才找得齊,插了型別變數就等於十四個目錄頁散在十四處。
|
||||||
|
|
||||||
|
型別共十五種:十四種內容型別加上 `CONTENTS`。**十五種都不得跨類型代用**——拿 `JSC_WIKI_REPO_PLAN` 去寫 `ANALYZE_{HASH}` 不行,拿 `JSC_WIKI_REPO_LOG` 去寫 `LOG_CONTENTS` 也不行,後者要走 `JSC_WIKI_REPO_CONTENTS`。
|
||||||
|
|
||||||
## 版本前置檢查
|
## 版本前置檢查
|
||||||
|
|
||||||
@@ -356,21 +363,54 @@ kiro 是唯一真的擋不了的,verdict 據實寫 `degraded`,不寫 `wired`
|
|||||||
|
|
||||||
`MAINTAIN` 沒有內容頁。維護登記全部寫在 `MAINTAIN_CONTENTS` 的表格裡:`jsc-sdlc:implement` 只往那一頁附加登記,`jsc-sdlc:maintain` 只讀那一頁再回寫「前次維護時間」,兩支都沒有產生 `MAINTAIN_{HASH}` 的步驟,`jsc-sdlc/templates/` 也沒有對應範本。總表以前列著這個內容頁,照著找只會找到一個不存在的頁。要補內容頁就先補技能步驟與範本,不能只在總表上寫著。
|
`MAINTAIN` 沒有內容頁。維護登記全部寫在 `MAINTAIN_CONTENTS` 的表格裡:`jsc-sdlc:implement` 只往那一頁附加登記,`jsc-sdlc:maintain` 只讀那一頁再回寫「前次維護時間」,兩支都沒有產生 `MAINTAIN_{HASH}` 的步驟,`jsc-sdlc/templates/` 也沒有對應範本。總表以前列著這個內容頁,照著找只會找到一個不存在的頁。要補內容頁就先補技能步驟與範本,不能只在總表上寫著。
|
||||||
|
|
||||||
`{HASH}` 一律為 `{owner}/{repo}`(必要時加上主題字串)的 SHA-1 前 8 碼,大寫。
|
### 目錄頁專用存取庫
|
||||||
若第一碼是 `0-9`、`A`、`B`、`C`,就改成 `H` 加上原 SHA-1 前 7 碼,總長仍維持 8 碼。
|
|
||||||
同一規則套用到所有目錄頁與內容頁。
|
目錄頁與內容頁分屬不同存取庫,這是刻意的。
|
||||||
|
|
||||||
|
| 項目 | 目錄頁 | 內容頁 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 頁名 | `{TYPE}_CONTENTS` | `{TYPE}_{HASH}` |
|
||||||
|
| 存取庫解析 | 一律解 `CONTENTS`:`JSC_WIKI_REPO_CONTENTS` → `JSC_WIKI_REPO` → exit 3 | 解自己的型別:`JSC_WIKI_REPO_{TYPE}` → `JSC_WIKI_REPO` → exit 3 |
|
||||||
|
| 帶雜湊 | 否 | 是 |
|
||||||
|
|
||||||
|
`CONTENTS` 因此是第十五種頁面類型,而且是唯一一種自己沒有頁的:沒有 `CONTENTS_CONTENTS`,也沒有 `CONTENTS_{HASH}`。
|
||||||
|
它只用來解存取庫,`gitea.sh wiki-repo CONTENTS` 是全部目錄頁的解析入口。
|
||||||
|
總表列的十四種是頁的分類,`CONTENTS` 是存取庫的分類,兩張清單長度不同是正常的。
|
||||||
|
|
||||||
|
三條規則,寫入前逐條核對:
|
||||||
|
|
||||||
|
1. 任何 `*_CONTENTS` 頁都走 `gitea.sh wiki-repo CONTENTS`,十四種型別的目錄頁全部落在同一個存取庫。
|
||||||
|
2. 目錄頁的解析鏈**不退回型別變數**。設了 `JSC_WIKI_REPO_LOG` 不會讓 `LOG_CONTENTS` 跟著搬過去。
|
||||||
|
3. 目錄頁指向內容頁的連結**一律用絕對網址**(`{GITEA_HOST}/{owner}/{repo}/wiki/{頁名}`),不用 `[[頁名]]` 這種同 wiki 連結。兩頁跨存取庫,同 wiki 連結會指到目錄頁自己那個存取庫裡不存在的頁,點下去是 404,而且看起來像頁沒寫成功。
|
||||||
|
|
||||||
|
**為什麼要分開。** 目錄頁是全部使用者共用的索引,內容頁按專案或機器分散在各自的存取庫。混在一起的話,換一個專案就換一份索引,「這台機器有哪些頁」永遠問不到完整答案。索引集中一處、內容各自落地,才查得到全貌。
|
||||||
|
|
||||||
|
代價寫明:跨存取庫沒有原子性。內容頁寫成功、目錄頁寫失敗時,據實回報未寫入的目錄列與完整內容,不得反過來先寫目錄頁。
|
||||||
|
|
||||||
|
`{HASH}` 一律為 `{owner}/{repo}`(必要時加上主題字串)的**完整 SHA-1**,40 碼十六進位,`a-f` 一律轉大寫。
|
||||||
|
不截短、不加前綴:截短過的舊頁名以 `jsc-gitea/tools/migrate-wiki.sh` 遷移。
|
||||||
|
由 `jsc-gitea/tools/hash-id` 產生,空輸入 exit 2。
|
||||||
|
同一規則套用到所有內容頁;目錄頁不帶雜湊。
|
||||||
|
|
||||||
`REPORT` 用得到那個主題字串:雜湊來源為 `{owner}/{repo}/{期間}`,期間是 `daily`、`weekly`、`monthly`、`yearly` 其中之一。
|
`REPORT` 用得到那個主題字串:雜湊來源為 `{owner}/{repo}/{期間}`,期間是 `daily`、`weekly`、`monthly`、`yearly` 其中之一。
|
||||||
|
這裡的 `{owner}/{repo}` 是 **`REPORT` wiki 存取庫**,也就是 `gitea.sh wiki-repo REPORT` 解出來的那一組值,**不是**被統計的那個程式碼存取庫。
|
||||||
|
兩者取錯會算出不同雜湊,同一份報表就散成兩頁,而且兩頁都寫得成功、都看不出錯。
|
||||||
年、月、週、日各自一頁,每頁內依期間累積分節。
|
年、月、週、日各自一頁,每頁內依期間累積分節。
|
||||||
|
|
||||||
`SKILLSET` 的雜湊來源就是被改動的 domain 存取庫 `{owner}/{repo}`,算法同上,由同一支 `jsc-gitea/tools/hash-id` 產生。
|
`SKILLSET` 的雜湊來源就是被改動的 domain 存取庫 `{owner}/{repo}`,算法同上,由同一支 `jsc-gitea/tools/hash-id` 產生。
|
||||||
頁內**累積**歷次異動:每次異動附加一節,不覆蓋舊紀錄。要看一支技能改過幾次,就在同一頁上翻。
|
頁內**累積**歷次異動:每次異動附加一節,不覆蓋舊紀錄。要看一支技能改過幾次,就在同一頁上翻。
|
||||||
|
|
||||||
`CHECK` 記的是一台執行環境,不是一個存取庫,所以雜湊來源為 `{主機名}/{登入帳號}`。
|
`CHECK` 記的是一台執行環境,不是一個存取庫,所以雜湊來源為 `{主機名}/{登入帳號}`。
|
||||||
8 碼與 `H` 前綴的算法完全相同,由同一支 `jsc-gitea/tools/hash-id` 產生。
|
算法同上,由同一支 `jsc-gitea/tools/hash-id` 產生。
|
||||||
在沒有存取庫的目錄也跑得出體檢,是這個例外存在的原因。
|
在沒有存取庫的目錄也跑得出體檢,是這個例外存在的原因。
|
||||||
機器層的雜湊來源不只這一個,`MONITOR` 也照同一組取值,規則見下。
|
機器層的雜湊來源不只這一個,`MONITOR` 也照同一組取值,規則見下。
|
||||||
|
|
||||||
|
**`{主機名}` 一律取短主機名,不含網域。** `CHECK`、`TOOLING`、`MONITOR` 三種機器層頁面共用這一條。
|
||||||
|
取值方式固定為:`hostname` 的輸出取第一個點以前的那一段,全部轉小寫;取不到就退回 `uname -n` 再做同樣的截取。
|
||||||
|
理由是**同一台機器只能算出同一個雜湊**。這幾張頁的來源不只一處:`CHECK` 由模型自己填,`MONITOR` 由 `jsc-assist/tools/patrol.sh` 用程式算。
|
||||||
|
同一台機器上,程式拿到 FQDN(`web01.jsc.idv.tw`)、模型填短主機名(`web01`),兩邊就各開一張頁,各寫各的,兩張都寫得成功,也都看不出被分裂。
|
||||||
|
截到第一個點以前,兩條路徑才收斂到同一個值。
|
||||||
|
|
||||||
`TOOLING` 記的也是機器層事實,雜湊來源再多一段:`{主機名}/{工具名稱}/{登入帳號}`。
|
`TOOLING` 記的也是機器層事實,雜湊來源再多一段:`{主機名}/{工具名稱}/{登入帳號}`。
|
||||||
`{工具名稱}` 是 CLI 代號,取自 `jsc-cli/tools/detect-clis.sh` 輸出的第一欄,值為 `claude`、`codex`、`copilot`、`antigravity`、`kiro` 其中之一。
|
`{工具名稱}` 是 CLI 代號,取自 `jsc-cli/tools/detect-clis.sh` 輸出的第一欄,值為 `claude`、`codex`、`copilot`、`antigravity`、`kiro` 其中之一。
|
||||||
一台機器、一支 CLI、一個帳號各一頁;算法同上,由同一支 `jsc-gitea/tools/hash-id` 產生。
|
一台機器、一支 CLI、一個帳號各一頁;算法同上,由同一支 `jsc-gitea/tools/hash-id` 產生。
|
||||||
@@ -379,10 +419,11 @@ kiro 是唯一真的擋不了的,verdict 據實寫 `degraded`,不寫 `wired`
|
|||||||
少了中間那一段,同一台機器上五支 CLI 會算出同一個雜湊,五份盤點互相覆蓋,最後只剩最後寫入的那一支,讀的人卻看不出被蓋掉。
|
少了中間那一段,同一台機器上五支 CLI 會算出同一個雜湊,五份盤點互相覆蓋,最後只剩最後寫入的那一支,讀的人卻看不出被蓋掉。
|
||||||
帶上工具名稱,一支 CLI 就有一頁,換一支 CLI 重跑也不會動到別支的頁。
|
帶上工具名稱,一支 CLI 就有一頁,換一支 CLI 重跑也不會動到別支的頁。
|
||||||
|
|
||||||
`MONITOR` 的雜湊來源比照 `CHECK`,取 `{主機名}/{登入帳號}`。
|
`MONITOR` 的雜湊來源比照 `CHECK`,取 `{主機名}/{登入帳號}`,`{主機名}` 照上面那條取短主機名。
|
||||||
助理巡檢的是一台機器,不是一個存取庫。
|
助理巡檢的是一台機器,不是一個存取庫。
|
||||||
一台機器一頁,換一支 CLI 不另開頁。
|
一台機器一頁,換一支 CLI 不另開頁。
|
||||||
算法同上,由同一支 `jsc-gitea/tools/hash-id` 產生。
|
算法同上,由同一支 `jsc-gitea/tools/hash-id` 產生。
|
||||||
|
`patrol.sh` 與模型填值兩條路徑都要照這一條截取,改動任一邊就回頭核對另一邊。
|
||||||
|
|
||||||
**為什麼不帶工具名稱。** 這一點與 `TOOLING` 相反。
|
**為什麼不帶工具名稱。** 這一點與 `TOOLING` 相反。
|
||||||
`TOOLING` 一支 CLI 一頁,因為每支 CLI 各有自己的已安裝 plugin 與 hook 接線。
|
`TOOLING` 一支 CLI 一頁,因為每支 CLI 各有自己的已安裝 plugin 與 hook 接線。
|
||||||
@@ -401,6 +442,8 @@ kiro 是唯一真的擋不了的,verdict 據實寫 `degraded`,不寫 `wired`
|
|||||||
- [ ] 細節流程已標示 MUST run as a sub agent
|
- [ ] 細節流程已標示 MUST run as a sub agent
|
||||||
- [ ] gitea 操作透過 gitea.sh 或 tea
|
- [ ] gitea 操作透過 gitea.sh 或 tea
|
||||||
- [ ] wiki repo 與 Gitea 認證先讀目前 shell 繼承的環境變數;只有缺值或無法解析時才詢問;頁面類型不得跨用其他 `JSC_WIKI_REPO_{TYPE}`
|
- [ ] wiki repo 與 Gitea 認證先讀目前 shell 繼承的環境變數;只有缺值或無法解析時才詢問;頁面類型不得跨用其他 `JSC_WIKI_REPO_{TYPE}`
|
||||||
|
- [ ] 目錄頁一律解 `CONTENTS` 存取庫(`gitea.sh wiki-repo CONTENTS`),內容頁解自己的型別;目錄頁指向內容頁的連結用絕對網址
|
||||||
|
- [ ] 頁名樣式三處一致:`jsc-gitea/tools/page-name.sh`(正本)、`jsc-hooks/hooks/comment-scope.sh`、`jsc-log/tools/worklog-pending.sh`,`tools/check-page-name.sh {root}` 退出 0;退出 3 是「什麼都沒查」,不算通過。三處刻意不共用函式,因為 hook 必須自足,不得在執行期相依別的 plugin 路徑
|
||||||
- [ ] 問詢透過 jsc-ask 決策樹規則
|
- [ ] 問詢透過 jsc-ask 決策樹規則
|
||||||
- [ ] `tools/` 與 `hooks/` 內的 shell 腳本都通過 `sh -n`;技能直接呼叫的腳本都存在、可執行,且退出碼有分流
|
- [ ] `tools/` 與 `hooks/` 內的 shell 腳本都通過 `sh -n`;技能直接呼叫的腳本都存在、可執行,且退出碼有分流
|
||||||
- [ ] hook 相關變更已用 `jsc-hooks/tools/wire-cli.sh smoke {cli}` 實測;沒有偵測到 CLI 時,至少跑 `smoke codex` 並標明是預設 hook smoke。行數讀腳本自己印的 `lines` 那一行,**技能與 README 都不得寫死數字**——腳本會自我斷言,抄一份數字進文件,加減判定路徑時就漂移,稽核反而被舊數字誤導
|
- [ ] hook 相關變更已用 `jsc-hooks/tools/wire-cli.sh smoke {cli}` 實測;沒有偵測到 CLI 時,至少跑 `smoke codex` 並標明是預設 hook smoke。行數讀腳本自己印的 `lines` 那一行,**技能與 README 都不得寫死數字**——腳本會自我斷言,抄一份數字進文件,加減判定路徑時就漂移,稽核反而被舊數字誤導
|
||||||
|
|||||||
+77
-13
@@ -1,6 +1,6 @@
|
|||||||
---
|
---
|
||||||
name: skill-check
|
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 hook smoke, the guidelines.md checklist audit, and a review of 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, re-check until accepted fixes pass, then open a PR per affected repo via jsc-git pr. 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-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 row, 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
|
# skill-check — audit compliance, flow efficiency, and cost efficiency
|
||||||
@@ -14,13 +14,17 @@ 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.
|
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.
|
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, and hooks.**
|
**Group 1 — validate scripts, frontmatter, behavior lists, language, wiki rules, page names, 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.
|
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.
|
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.
|
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.
|
||||||
4. 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`.
|
4. For every synced domain repo, run `tools/ste100-lint.sh {domain-path}`. One run per domain, and the runs go **in parallel** alongside the other group 1 runs. Route each exit code: 0 — every scanned file in that domain passes; 1 — the hits are printed on stdout as `{檔案}:{行號}:{類別}:{命中內容}`, so report every one as a compliance failure with the category it belongs to, after checking the two documented false-positive classes (a path or branch name holding a slash between Chinese characters, and English items listed with a slash); 2 — no scan target was given, which is a caller defect here, so fix the argument and rerun. The tool has no exit 3: an empty run returns 2 rather than a silent pass. This check lives in group 1 because the audit checklist demands 「`tools/ste100-lint.sh` 對該 domain 全綠」 for every domain — leaving it to the group 2 sub agents meant ten agents each ran it their own way, and the main agent never held one comparable verdict per domain.
|
||||||
5. 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.
|
5. Run the two wiki-rule checkers once each, not per domain — both judge shared rules, so a second run adds nothing:
|
||||||
6. 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.
|
- `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.
|
||||||
|
6. 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`.
|
||||||
|
7. 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.
|
||||||
|
8. 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:
|
**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).
|
- Every step number, file path and section title the skill references — inside itself and in other files — really exists (the pointer points at something).
|
||||||
@@ -28,9 +32,32 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
|||||||
- Every external call (script, API, other skill) states what to do on failure and routes every exit code.
|
- Every external call (script, API, other skill) states what to do on failure and routes every exit code.
|
||||||
- No gate the skill installs blocks the only path that lifts that gate.
|
- No gate the skill installs blocks the only path that lifts that gate.
|
||||||
|
|
||||||
Five checklist items are **already decided by group 1** and must not be re-run here: `sh -n` on every `tools/` and `hooks/` script, script existence with the executable bit, the hook smoke, the `references/behaviors.md` match, and the `lint-frontmatter.sh` verdict. Tell each sub agent to skip those five and leave them blank; the main agent fills them in from the group 1 verdicts when merging in step 3. Re-scanning the same files in every domain sub agent buys nothing — group 1 already scanned them all, with the same tools, on the same synced tree.
|
Eight checklist items are **already decided by group 1** and must not be re-run here: `sh -n` on every `tools/` and `hooks/` script, script existence with the executable bit, the hook smoke, the `references/behaviors.md` match, the `lint-frontmatter.sh` verdict, the `ste100-lint.sh` verdict, the page-name-pattern verdict from `tools/check-page-name.sh`, and the wiki repo resolution plus `hash-id` verdict from `jsc-gitea/tools/check-wiki-rules.sh`. Tell each sub agent to skip those eight and leave them blank; the main agent fills them in from the group 1 verdicts when merging in step 3. The last two are **one verdict for the whole round**, not one per domain — group 1 runs each of those two checkers once, because both judge rules the domains share — so the merge writes that single verdict into every domain's checklist. Re-scanning the same files in every domain sub agent buys nothing — group 1 already scanned them all, with the same tools, on the same synced tree.
|
||||||
|
|
||||||
**Group 3 — a flow and cost optimization review**, kept separate from the compliance audit. Each aspect **MUST run as a sub agent**, and the six aspects run in parallel with each other and with groups 1 and 2:
|
**Group 3 — a flow and cost optimization review**, kept separate from the compliance audit.
|
||||||
|
|
||||||
|
**Read the previous round's decisions before scanning anything.** For every synced domain, resolve `jsc-gitea/tools/gitea.sh wiki-repo SKILLSET`, compute the page name as `SKILLSET_` plus `gitea.sh hash-id "{owner}/{repo}"` of that domain repo, and read it through `jsc-gitea:wiki`. Take the 優化建議 table of every `skill-check` section on that page: an entry whose 決議 column reads `套用` or `延後` is **settled** — do not scan for it again, and do not put it back into the step 3 decision tree. Only a genuinely new finding, or an entry whose recorded 決議 is `自訂` with the custom fix not yet in place, reaches step 3.
|
||||||
|
|
||||||
|
Route every exit code of all three calls, not the read alone:
|
||||||
|
|
||||||
|
| Call | Exit | Do |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `gitea.sh wiki-repo SKILLSET` | 0 | The repo is in hand; go on to `hash-id` |
|
||||||
|
| | 2 | The page type was misspelled here, which is a defect in this skill and not a user setting. Fix the argument and rerun |
|
||||||
|
| | 3 | Neither `JSC_WIKI_REPO_SKILLSET` nor `JSC_WIKI_REPO` is set. Name both variables, ask per the `jsc-ask:ask` rules, then rerun. No answer means no settled list for that domain, per the rule below |
|
||||||
|
| `gitea.sh hash-id "{owner}/{repo}"` | 0 | Use the 40 characters it printed as the page-name suffix, unshortened |
|
||||||
|
| | 1 | No SHA-1 helper on this machine. Report that `sha1sum` or `shasum` has to be installed, and never hand-compute the hash |
|
||||||
|
| | 2 | Empty input, so the `{owner}/{repo}` was never resolved. Resolve it and rerun |
|
||||||
|
| `jsc-gitea:wiki` read | 0 | The settled list is in hand |
|
||||||
|
| | 4 | The page does not exist yet, so there is no previous round. Carry on with an empty settled list — the normal state for a domain audited the first time |
|
||||||
|
| | 7 | The token is invalid or lacks permission |
|
||||||
|
| | 8 | Some other API failure |
|
||||||
|
|
||||||
|
**A 7, an 8, an unanswered 3, or a stopped 1 or 2 ends group 3 for that domain, and nothing else.** An unread page cannot be told apart from an empty one, and treating it as empty re-asks every question the user already answered. So mark that domain 「本輪未取得已決議清單,優化建議暫不提出」, report the exit code that caused it, and run the rest of the round unchanged: group 1 and group 2 read no wiki at all, and steps 3 to 8 still apply and record every compliance fix. Stopping the whole round on a wiki failure would switch off the one routine compliance audit this skill set has — including the audit that finds a broken wiki setting.
|
||||||
|
|
||||||
|
This read exists because the audit was re-scanning and re-asking every accepted or deferred suggestion on every run — exactly the 「重複來回」 that aspect 3 below is supposed to catch, committed by the skill that defines it.
|
||||||
|
|
||||||
|
Each aspect **MUST run as a sub agent**, and the six aspects run in parallel with each other and with groups 1 and 2. Every sub agent gets that domain's settled list up front:
|
||||||
|
|
||||||
| Aspect | Scope |
|
| Aspect | Scope |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
@@ -41,14 +68,14 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
|||||||
| 5 Gate timing | Gates that run too early or too late, causing wasted work before a block or blocking the only path that clears the gate |
|
| 5 Gate timing | Gates that run too early or too late, causing wasted work before a block or blocking the only path that clears the gate |
|
||||||
| 6 Cost efficiency | Avoidable token, sub-agent, API, file-scan, full-repo audit, or user-interaction cost that can be reduced without weakening correctness |
|
| 6 Cost efficiency | Avoidable token, sub-agent, API, file-scan, full-repo audit, or user-interaction cost that can be reduced without weakening correctness |
|
||||||
|
|
||||||
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, and which protection would be weakened if any. 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.
|
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 and a `check-behaviors.sh` verdict, 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 five 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, 「無發現」 where an aspect found nothing.
|
Completion condition for all three groups: every domain has a `lint-scripts.sh` verdict, a `lint-frontmatter.sh` verdict, a `check-behaviors.sh` verdict and an `ste100-lint.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 eight 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 five 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.
|
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 eight 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. Six of the eight 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.
|
- 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.
|
||||||
- Optimization options: apply / defer / custom. 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.
|
- 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, and every compliance failure and every optimization finding has a recorded decision.
|
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. 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.
|
||||||
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:
|
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 3 — written, but some domain repo is not present locally. Run `tools/sync-domains.sh`, then rerun this step.
|
||||||
@@ -57,5 +84,42 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
|||||||
- Exit 0 — every copy holds identical bytes; the script verifies that itself.
|
- Exit 0 — every copy holds identical bytes; the script verifies that itself.
|
||||||
|
|
||||||
Completion condition: the script exits 0 and prints the touched paths.
|
Completion condition: the script exits 0 and prints the touched paths.
|
||||||
6. Re-run the group 1 script, frontmatter, behavior-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, every hook smoke exits 0 with the `lines` count the script itself asserted, all checklist items pass, and every accepted optimization has a matching verification result.
|
6. Re-run the group 1 script, frontmatter, behavior-list, language, 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, `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.
|
||||||
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).
|
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.
|
||||||
|
|
||||||
|
Without this step the whole audit stops at the PR and scatters. The other four `jsc-meta` change skills all append to `SKILLSET_{HASH}`; `skill-check` was the only one that did not, so the audit that produced the deferrals had nowhere to record them and step 2's group 3 had nothing to read back.
|
||||||
|
|
||||||
|
- **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.
|
||||||
|
- **Directory page.** Refresh that page's row in `SKILLSET_CONTENTS` with `jsc-gitea/tools/wiki-contents.sh` — never by hand, and never through `jsc-gitea:wiki`. Build one file holding the single row from [`../../templates/skillset-contents.md`](../../templates/skillset-contents.md), then run:
|
||||||
|
|
||||||
|
`jsc-gitea/tools/wiki-contents.sh upsert SKILLSET 2 "{owner}/{repo}" {row file} templates/skillset-contents.md`
|
||||||
|
|
||||||
|
The key column is `2`, the 存取庫 column, and the key is that domain repo's `{owner}/{repo}` written exactly as the row file writes it; the string is the same every round, so one domain keeps exactly one row. The script resolves the CONTENTS repo itself — the directory page lives there, never in the SKILLSET repo — reads the whole page, replaces the row whose key column matches, appends when none matches, and writes the page back, so every row owned by another domain stays as it was.
|
||||||
|
|
||||||
|
The 異動頁 cell holds an **absolute** URL from `gitea.sh wiki-url {SKILLSET repo} SKILLSET_{HASH}`, because the two pages sit in different wikis and `[[SKILLSET_{HASH}]]` would resolve inside the directory page's own repo. Fetch that URL only after the content page is written: **write the content page first** — a directory row naming a page whose write failed is worse than a missing row.
|
||||||
|
- **Exit codes.** Route every one of them. None of these calls may be read as success by default.
|
||||||
|
|
||||||
|
| Call | Exit | Do |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `gitea.sh wiki-repo` | 2 | The page type was misspelled. Fix the argument and rerun |
|
||||||
|
| | 3 | No wiki repo is configured for that type. Name the variable (`JSC_WIKI_REPO_SKILLSET` or `JSC_WIKI_REPO_CONTENTS`) and `JSC_WIKI_REPO`, ask per the `jsc-ask:ask` rules, then rerun |
|
||||||
|
| `gitea.sh hash-id` | 1 | No SHA-1 helper on this machine. Stop and report that `sha1sum` or `shasum` has to be installed, and never hand-compute the hash |
|
||||||
|
| | 2 | Empty input, which means the `{owner}/{repo}` was never resolved. Fix that first |
|
||||||
|
| Content page read | 0 | Append into the sections already there |
|
||||||
|
| | 4 | The page does not exist yet, so build it from the template |
|
||||||
|
| | 7 or 8 | Stop and write nothing, because a page rebuilt on top of an unread read loses every section already on it |
|
||||||
|
| `gitea.sh wiki-url` | 4 | The content page is not there, so the write above did **not** succeed. Go back and write it; put no directory row in until the page exists, because a row may not name a page that failed |
|
||||||
|
| | 5 | The API answered with no `html_url`. Stop and report it; never assemble the URL by hand from the host and the page name |
|
||||||
|
| `wiki-contents.sh upsert` | 0 | The row is in place. Report the `updated` or `added` it printed, with the page it named |
|
||||||
|
| | 1 | The write failed, or the directory page holds no markdown table. Report `SKILLSET_CONTENTS` as not written, together with the row content |
|
||||||
|
| | 2 | An argument was rejected. Fix it and rerun; nothing was written |
|
||||||
|
| | 3 | No CONTENTS wiki repo is configured. Report `JSC_WIKI_REPO_CONTENTS` and `JSC_WIKI_REPO` as the two variables to set. The round's section is on `SKILLSET_{HASH}` and stays there |
|
||||||
|
| | 4 | The directory page is absent and no template was passed. Rerun with `templates/skillset-contents.md` as the fifth argument |
|
||||||
|
| | 7 | The token is invalid or lacks permission, so the other domains' rows are unknown. Stop, report the token problem, and create no page — writing nothing is what keeps those rows alive |
|
||||||
|
| | 8 | Some other API failure. Stop, report that status, and create no page |
|
||||||
|
- **On a failed write.** Retry once. Still failing, hand the user the page name and the full section that was not written, so the round's result is not lost. **Never close the run reporting a page as written when it was not**, and never close it silently with the content only in the transcript.
|
||||||
|
|
||||||
|
Completion condition: every changed domain repo has one new section on its `SKILLSET_{HASH}` and one row in `SKILLSET_CONTENTS` written by a `wiki-contents.sh upsert` that exited 0, or — where nothing changed — the `plugins/meta` page carries the 「本輪無發現」 section and its row on the same terms; every content-page write is confirmed by a successful read-back or reported as not written with its full content handed back.
|
||||||
|
|||||||
@@ -34,4 +34,32 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
|||||||
- One minimal prompt per checkable CLI, each in its own fresh process and all in parallel, confirming `/jsc-{domain}:{name}` is gone or that the replacement path still works.
|
- One minimal prompt per checkable CLI, each in its own fresh process and all in parallel, confirming `/jsc-{domain}:{name}` is gone or that the replacement path still works.
|
||||||
|
|
||||||
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.
|
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 wiki page `SKILLSET_{HASH}` — this part MUST run as a sub agent. Call `jsc-gitea:wiki`; `{HASH}` comes from the `{owner}/{repo}` of the domain repo that lost the skill, and the wiki repo resolves through `JSC_WIKI_REPO_SKILLSET` first, then `JSC_WIKI_REPO`. **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. Add the page to `SKILLSET_CONTENTS` when it is new. When the write fails — no `{owner}/{repo}` resolves, or `jsc-gitea:wiki` reports an API error — hand the page name and the unwritten entry back to the user and leave this step open; never close the flow on an unwritten report. Completion condition: the page holds the new section plus all earlier sections, and `SKILLSET_CONTENTS` links it.
|
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.
|
||||||
|
- **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`. Build one file holding the single row from [`../../templates/skillset-contents.md`](../../templates/skillset-contents.md), its 異動頁 cell carrying the **absolute** URL from `gitea.sh wiki-url {SKILLSET repo} SKILLSET_{HASH}` — `[[SKILLSET_{HASH}]]` resolves only inside the directory page's own wiki, so it would be a dead link. Then run:
|
||||||
|
|
||||||
|
`jsc-gitea/tools/wiki-contents.sh upsert SKILLSET 2 "{owner}/{repo}" {row file} templates/skillset-contents.md`
|
||||||
|
|
||||||
|
The key column is `2`, the 存取庫 column, holding that repo's `{owner}/{repo}` exactly as the row file writes it, so one domain keeps exactly one row and no other domain's row moves. Never hand-edit the directory page. Write the content page first and fetch the URL only after it exists.
|
||||||
|
- **Exit codes.** Route every one of them:
|
||||||
|
|
||||||
|
| Call | Exit | Do |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `gitea.sh wiki-repo` | 2 | The page type was misspelled. Fix the argument and rerun |
|
||||||
|
| | 3 | No wiki repo is configured for that type. Name the variable (`JSC_WIKI_REPO_SKILLSET` for the content page, `JSC_WIKI_REPO_CONTENTS` for the directory page) and `JSC_WIKI_REPO`, ask per the `jsc-ask:ask` rules, then rerun |
|
||||||
|
| `gitea.sh hash-id` | 1 | No SHA-1 helper on this machine. Stop and report that `sha1sum` or `shasum` has to be installed, and never hand-compute the hash |
|
||||||
|
| | 2 | Empty input, so the `{owner}/{repo}` was never resolved. Fix that first |
|
||||||
|
| Content page read | 0 | Append into the sections already there |
|
||||||
|
| | 4 | The page does not exist yet, so build it from `templates/skillset-page.md` |
|
||||||
|
| | 7 or 8 | Stop and write nothing: a page rebuilt on top of an unread read loses every section already on it |
|
||||||
|
| `gitea.sh wiki-url` | 4 | The content page is not there, so the write above did **not** succeed. Go back and write it, and add no directory row until the page exists |
|
||||||
|
| | 5 | The API answered with no `html_url`. Stop and report it; never assemble the URL by hand from the host and the page name |
|
||||||
|
| `wiki-contents.sh upsert` | 0 | The row is in place. Report the `updated` or `added` it printed |
|
||||||
|
| | 1 | The write failed. Report `SKILLSET_CONTENTS` as not written, together with the row content |
|
||||||
|
| | 2 | An argument was rejected. Fix it and rerun; nothing was written |
|
||||||
|
| | 3 | No CONTENTS wiki repo is configured. Report `JSC_WIKI_REPO_CONTENTS` and `JSC_WIKI_REPO` as the two variables to set; the new section is on `SKILLSET_{HASH}` and stays there |
|
||||||
|
| | 4 | The directory page is absent and no template was passed. Rerun with `templates/skillset-contents.md` as the fifth argument |
|
||||||
|
| | 7 | The token is invalid or lacks permission, so the other domains' rows are unknown. Stop, report the token problem, and create no page |
|
||||||
|
| | 8 | Some other API failure. Stop, report that status, and create no page |
|
||||||
|
|
||||||
|
On any failure, hand the page name and the unwritten entry back to the user and leave this step open; never close the flow on an unwritten report. Completion condition: `SKILLSET_{HASH}` holds the new section plus all earlier sections, and `wiki-contents.sh upsert` exited 0 with this domain's row on `SKILLSET_CONTENTS` linking that page by absolute URL.
|
||||||
|
|||||||
@@ -43,4 +43,32 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
|||||||
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).
|
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).
|
||||||
6. Deploy the new skill, verify it runs, then report:
|
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.
|
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 wiki page `SKILLSET_{HASH}` — this part MUST run as a sub agent. Call `jsc-gitea:wiki`; `{HASH}` comes from the `{owner}/{repo}` of the domain repo that gained the skill, and the wiki repo resolves through `JSC_WIKI_REPO_SKILLSET` first, then `JSC_WIKI_REPO`. **Append** a section for this change — date, 「新增」, skill name, changed files, PR URL, the step 6.1 route verdict and verification result per item — and keep every earlier section. Add the page to `SKILLSET_CONTENTS` when it is new. When the write fails — no `{owner}/{repo}` resolves, or `jsc-gitea:wiki` reports an API error — hand the page name and the unwritten entry back to the user and leave this step open; never close the flow on an unwritten report. Completion condition: the page holds the new section plus all earlier sections, and `SKILLSET_CONTENTS` links it.
|
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 domain repo that gained 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, PR URL, the step 6.1 route verdict and verification result per item — 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`. Build one file holding the single row from [`../../templates/skillset-contents.md`](../../templates/skillset-contents.md), its 異動頁 cell carrying the **absolute** URL from `gitea.sh wiki-url {SKILLSET repo} SKILLSET_{HASH}` — `[[SKILLSET_{HASH}]]` resolves only inside the directory page's own wiki, so it would be a dead link. Then run:
|
||||||
|
|
||||||
|
`jsc-gitea/tools/wiki-contents.sh upsert SKILLSET 2 "{owner}/{repo}" {row file} templates/skillset-contents.md`
|
||||||
|
|
||||||
|
The key column is `2`, the 存取庫 column, holding that repo's `{owner}/{repo}` exactly as the row file writes it, so one domain keeps exactly one row and no other domain's row moves. Never hand-edit the directory page. Write the content page first and fetch the URL only after it exists.
|
||||||
|
- **Exit codes.** Route every one of them:
|
||||||
|
|
||||||
|
| Call | Exit | Do |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `gitea.sh wiki-repo` | 2 | The page type was misspelled. Fix the argument and rerun |
|
||||||
|
| | 3 | No wiki repo is configured for that type. Name the variable (`JSC_WIKI_REPO_SKILLSET` for the content page, `JSC_WIKI_REPO_CONTENTS` for the directory page) and `JSC_WIKI_REPO`, ask per the `jsc-ask:ask` rules, then rerun |
|
||||||
|
| `gitea.sh hash-id` | 1 | No SHA-1 helper on this machine. Stop and report that `sha1sum` or `shasum` has to be installed, and never hand-compute the hash |
|
||||||
|
| | 2 | Empty input, so the `{owner}/{repo}` was never resolved. Fix that first |
|
||||||
|
| Content page read | 0 | Append into the sections already there |
|
||||||
|
| | 4 | The page does not exist yet, so build it from `templates/skillset-page.md` |
|
||||||
|
| | 7 or 8 | Stop and write nothing: a page rebuilt on top of an unread read loses every section already on it |
|
||||||
|
| `gitea.sh wiki-url` | 4 | The content page is not there, so the write above did **not** succeed. Go back and write it, and add no directory row until the page exists |
|
||||||
|
| | 5 | The API answered with no `html_url`. Stop and report it; never assemble the URL by hand from the host and the page name |
|
||||||
|
| `wiki-contents.sh upsert` | 0 | The row is in place. Report the `updated` or `added` it printed |
|
||||||
|
| | 1 | The write failed. Report `SKILLSET_CONTENTS` as not written, together with the row content |
|
||||||
|
| | 2 | An argument was rejected. Fix it and rerun; nothing was written |
|
||||||
|
| | 3 | No CONTENTS wiki repo is configured. Report `JSC_WIKI_REPO_CONTENTS` and `JSC_WIKI_REPO` as the two variables to set; the new section is on `SKILLSET_{HASH}` and stays there |
|
||||||
|
| | 4 | The directory page is absent and no template was passed. Rerun with `templates/skillset-contents.md` as the fifth argument |
|
||||||
|
| | 7 | The token is invalid or lacks permission, so the other domains' rows are unknown. Stop, report the token problem, and create no page |
|
||||||
|
| | 8 | Some other API failure. Stop, report that status, and create no page |
|
||||||
|
|
||||||
|
On any failure, hand the page name and the unwritten entry back to the user and leave this step open; never close the flow on an unwritten report. Completion condition: `SKILLSET_{HASH}` holds the new section plus all earlier sections, and `wiki-contents.sh upsert` exited 0 with this domain's row on `SKILLSET_CONTENTS` linking that page by absolute URL.
|
||||||
|
|||||||
@@ -18,4 +18,32 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
|||||||
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).
|
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).
|
||||||
8. Deploy the update, verify it runs, then report:
|
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.
|
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 wiki page `SKILLSET_{HASH}` — this part MUST run as a sub agent. Call `jsc-gitea:wiki`; `{HASH}` comes from the `{owner}/{repo}` of the changed domain repo, and the wiki repo resolves through `JSC_WIKI_REPO_SKILLSET` first, then `JSC_WIKI_REPO`. **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. Add the page to `SKILLSET_CONTENTS` when it is new. When the write fails — no `{owner}/{repo}` resolves, or `jsc-gitea:wiki` reports an API error — hand the page name and the unwritten entry back to the user and leave this step open; never close the flow on an unwritten report. Completion condition: the page holds the new section plus all earlier sections, and `SKILLSET_CONTENTS` links it.
|
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.
|
||||||
|
- **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`. Build one file holding the single row from [`../../templates/skillset-contents.md`](../../templates/skillset-contents.md), its 異動頁 cell carrying the **absolute** URL from `gitea.sh wiki-url {SKILLSET repo} SKILLSET_{HASH}` — `[[SKILLSET_{HASH}]]` resolves only inside the directory page's own wiki, so it would be a dead link. Then run:
|
||||||
|
|
||||||
|
`jsc-gitea/tools/wiki-contents.sh upsert SKILLSET 2 "{owner}/{repo}" {row file} templates/skillset-contents.md`
|
||||||
|
|
||||||
|
The key column is `2`, the 存取庫 column, holding that repo's `{owner}/{repo}` exactly as the row file writes it, so one domain keeps exactly one row and no other domain's row moves. Never hand-edit the directory page. Write the content page first and fetch the URL only after it exists.
|
||||||
|
- **Exit codes.** Route every one of them:
|
||||||
|
|
||||||
|
| Call | Exit | Do |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `gitea.sh wiki-repo` | 2 | The page type was misspelled. Fix the argument and rerun |
|
||||||
|
| | 3 | No wiki repo is configured for that type. Name the variable (`JSC_WIKI_REPO_SKILLSET` for the content page, `JSC_WIKI_REPO_CONTENTS` for the directory page) and `JSC_WIKI_REPO`, ask per the `jsc-ask:ask` rules, then rerun |
|
||||||
|
| `gitea.sh hash-id` | 1 | No SHA-1 helper on this machine. Stop and report that `sha1sum` or `shasum` has to be installed, and never hand-compute the hash |
|
||||||
|
| | 2 | Empty input, so the `{owner}/{repo}` was never resolved. Fix that first |
|
||||||
|
| Content page read | 0 | Append into the sections already there |
|
||||||
|
| | 4 | The page does not exist yet, so build it from `templates/skillset-page.md` |
|
||||||
|
| | 7 or 8 | Stop and write nothing: a page rebuilt on top of an unread read loses every section already on it |
|
||||||
|
| `gitea.sh wiki-url` | 4 | The content page is not there, so the write above did **not** succeed. Go back and write it, and add no directory row until the page exists |
|
||||||
|
| | 5 | The API answered with no `html_url`. Stop and report it; never assemble the URL by hand from the host and the page name |
|
||||||
|
| `wiki-contents.sh upsert` | 0 | The row is in place. Report the `updated` or `added` it printed |
|
||||||
|
| | 1 | The write failed. Report `SKILLSET_CONTENTS` as not written, together with the row content |
|
||||||
|
| | 2 | An argument was rejected. Fix it and rerun; nothing was written |
|
||||||
|
| | 3 | No CONTENTS wiki repo is configured. Report `JSC_WIKI_REPO_CONTENTS` and `JSC_WIKI_REPO` as the two variables to set; the new section is on `SKILLSET_{HASH}` and stays there |
|
||||||
|
| | 4 | The directory page is absent and no template was passed. Rerun with `templates/skillset-contents.md` as the fifth argument |
|
||||||
|
| | 7 | The token is invalid or lacks permission, so the other domains' rows are unknown. Stop, report the token problem, and create no page |
|
||||||
|
| | 8 | Some other API failure. Stop, report that status, and create no page |
|
||||||
|
|
||||||
|
On any failure, hand the page name and the unwritten entry back to the user and leave this step open; never close the flow on an unwritten report. Completion condition: `SKILLSET_{HASH}` holds the new section plus all earlier sections, and `wiki-contents.sh upsert` exited 0 with this domain's row on `SKILLSET_CONTENTS` linking that page by absolute URL.
|
||||||
|
|||||||
@@ -19,4 +19,32 @@ Single source of guidelines: [`../../references/guidelines.md`](../../references
|
|||||||
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).
|
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).
|
||||||
5. Deploy the batch change, verify it runs, then report:
|
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.
|
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 wiki page `SKILLSET_{HASH}` — this part MUST run as a sub agent, one sub agent per affected domain repo, run in parallel. Call `jsc-gitea:wiki`; `{HASH}` comes from that repo's `{owner}/{repo}`, and the wiki repo resolves through `JSC_WIKI_REPO_SKILLSET` first, then `JSC_WIKI_REPO`. **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. Add each page to `SKILLSET_CONTENTS` when it is new. When a write fails — no `{owner}/{repo}` resolves, or `jsc-gitea:wiki` reports an API error — hand the page name and the unwritten entry back to the user and leave this step open; never close the flow on an unwritten report. Completion condition: every affected repo's page holds the new section plus all earlier sections, and `SKILLSET_CONTENTS` links them all.
|
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.
|
||||||
|
- **Directory page `SKILLSET_CONTENTS`.** One shared page holds every domain's row, 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`. Build one file holding the single row from [`../../templates/skillset-contents.md`](../../templates/skillset-contents.md), its 異動頁 cell carrying the **absolute** URL from `gitea.sh wiki-url {SKILLSET repo} SKILLSET_{HASH}` — `[[SKILLSET_{HASH}]]` resolves only inside the directory page's own wiki, so it would be a dead link. Then run:
|
||||||
|
|
||||||
|
`jsc-gitea/tools/wiki-contents.sh upsert SKILLSET 2 "{owner}/{repo}" {row file} templates/skillset-contents.md`
|
||||||
|
|
||||||
|
The key column is `2`, the 存取庫 column, holding that repo's `{owner}/{repo}` exactly as the row file writes it, so one domain keeps exactly one row and no sibling sub agent's row moves. Never hand-edit the directory page, and never overwrite it as a whole. Write the content page first and fetch the URL only after it exists.
|
||||||
|
- **Exit codes.** Route every one of them:
|
||||||
|
|
||||||
|
| Call | Exit | Do |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| `gitea.sh wiki-repo` | 2 | The page type was misspelled. Fix the argument and rerun |
|
||||||
|
| | 3 | No wiki repo is configured for that type. Name the variable (`JSC_WIKI_REPO_SKILLSET` for the content page, `JSC_WIKI_REPO_CONTENTS` for the directory page) and `JSC_WIKI_REPO`, ask per the `jsc-ask:ask` rules, then rerun |
|
||||||
|
| `gitea.sh hash-id` | 1 | No SHA-1 helper on this machine. Stop and report that `sha1sum` or `shasum` has to be installed, and never hand-compute the hash |
|
||||||
|
| | 2 | Empty input, so the `{owner}/{repo}` was never resolved. Fix that first |
|
||||||
|
| Content page read | 0 | Append into the sections already there |
|
||||||
|
| | 4 | The page does not exist yet, so build it from `templates/skillset-page.md` |
|
||||||
|
| | 7 or 8 | Stop and write nothing: a page rebuilt on top of an unread read loses every section already on it |
|
||||||
|
| `gitea.sh wiki-url` | 4 | The content page is not there, so the write above did **not** succeed. Go back and write it, and add no directory row until the page exists |
|
||||||
|
| | 5 | The API answered with no `html_url`. Stop and report it; never assemble the URL by hand from the host and the page name |
|
||||||
|
| `wiki-contents.sh upsert` | 0 | The row is in place. Report the `updated` or `added` it printed |
|
||||||
|
| | 1 | The write failed. Report `SKILLSET_CONTENTS` as not written, together with the row content |
|
||||||
|
| | 2 | An argument was rejected. Fix it and rerun; nothing was written |
|
||||||
|
| | 3 | No CONTENTS wiki repo is configured. Report `JSC_WIKI_REPO_CONTENTS` and `JSC_WIKI_REPO` as the two variables to set; the new section is on `SKILLSET_{HASH}` and stays there |
|
||||||
|
| | 4 | The directory page is absent and no template was passed. Rerun with `templates/skillset-contents.md` as the fifth argument |
|
||||||
|
| | 7 | The token is invalid or lacks permission, so the other domains' rows are unknown. Stop, report the token problem, and create no page |
|
||||||
|
| | 8 | Some other API failure. Stop, report that status, and create no page |
|
||||||
|
|
||||||
|
On any failure, hand the page name and the unwritten entry back to the user and leave this step open; never close the flow on an unwritten report. Completion condition: every affected repo's `SKILLSET_{HASH}` holds the new section plus all earlier sections, and every one of those repos has a row on `SKILLSET_CONTENTS` written by a `wiki-contents.sh upsert` that exited 0, linking its page by absolute URL.
|
||||||
|
|||||||
@@ -0,0 +1,38 @@
|
|||||||
|
# 技能組異動目錄
|
||||||
|
|
||||||
|
> 由 `jsc-meta` 的 `skill-new`、`skill-update`、`skill-delete`、`skillset-update`、`skill-check` 共同維護。這是目錄頁 `SKILLSET_CONTENTS`。
|
||||||
|
> 一列代表一個 domain 存取庫。技能組有幾個 domain 被改過,就有幾列。
|
||||||
|
> 本頁落在 `JSC_WIKI_REPO_CONTENTS` 解出來的存取庫,不是內容頁那一個。解析鏈是 `JSC_WIKI_REPO_CONTENTS` → `JSC_WIKI_REPO` → exit 3,中間不退回 `JSC_WIKI_REPO_SKILLSET`。
|
||||||
|
> 寫入一律用 `jsc-gitea/tools/wiki-contents.sh upsert SKILLSET 2 "{owner}/{repo}" {列檔} templates/skillset-contents.md`:`<TYPE>` 填 `SKILLSET`,鍵欄填數字 `2`,也就是「存取庫」那一欄。
|
||||||
|
> 它讀回整頁、換掉鍵欄相符的那一列、找不到才附加,最後整頁寫回。不得手工改目錄頁。
|
||||||
|
> `SKILLSET_{HASH}` 的 `{HASH}` 交給 `jsc-gitea/tools/hash-id` 產生,雜湊來源見 `jsc-meta/references/guidelines.md` 的「Wiki 頁命名總表」。
|
||||||
|
|
||||||
|
| 異動頁 | 存取庫 | 最近異動 | 異動次數 | 最後更新 |
|
||||||
|
| --- | --- | --- | ---: | --- |
|
||||||
|
| [SKILLSET_{HASH}]({GITEA_HOST}/{owner}/{repo}/wiki/SKILLSET_{HASH}) | {owner}/{repo} | {一句話寫這一次改了什麼} | {n} | {yyyy-MM-dd HH:mm} |
|
||||||
|
|
||||||
|
## 欄位說明
|
||||||
|
|
||||||
|
| 欄位 | 內容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 異動頁 | 指向 `SKILLSET_{HASH}` 的**絕對網址**,格式 `{GITEA_HOST}/{owner}/{repo}/wiki/SKILLSET_{HASH}`。`{owner}/{repo}` 是內容頁那一個存取庫 |
|
||||||
|
| 存取庫 | 被改動的 domain 存取庫 `{owner}/{repo}`,也就是這一頁的雜湊來源 |
|
||||||
|
| 最近異動 | 最後一次異動的一句話摘要,與內容頁最新一節的「異動需求」同一句 |
|
||||||
|
| 異動次數 | 該內容頁累積的節數。內容頁只附加不覆蓋,所以這個數字只會往上加 |
|
||||||
|
| 最後更新 | 最後一次寫入內容頁的時間,與那一節的日期一致 |
|
||||||
|
|
||||||
|
## 為什麼連結要用絕對網址
|
||||||
|
|
||||||
|
目錄頁與內容頁分屬不同存取庫。`[[SKILLSET_{HASH}]]` 這種同 wiki 連結解到的是目錄頁自己那個存取庫,那裡沒有這一頁,點下去是 404。
|
||||||
|
更麻煩的是它看起來像「頁沒寫成功」,實際上頁好好的,只是連結指錯地方,查的人會回去重寫一次已經寫好的頁。
|
||||||
|
|
||||||
|
## 寫入規則
|
||||||
|
|
||||||
|
- 一律走 `jsc-gitea/tools/wiki-contents.sh upsert`,鍵欄是第 2 欄「存取庫」,鍵值是 `{owner}/{repo}`。
|
||||||
|
- 那支腳本先整頁讀回來,再比對「存取庫」欄。
|
||||||
|
- 該欄相同就更新那一列,其餘欄位覆寫成本次結果。
|
||||||
|
- 找不到相同的一列,才新增一列。
|
||||||
|
- 只動自己那一列,別人的列原樣保留。
|
||||||
|
- 禁止整頁覆蓋。這一頁是全部 domain 共用的索引,覆蓋等於刪掉別的 domain 的紀錄。
|
||||||
|
- 讀不到舊內容就中止,不新增列,也不寫入。
|
||||||
|
- 先寫內容頁,成功了才回來更新這一列。目錄列指向一個寫失敗的頁,比缺一列更難查。
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
# 技能組異動 — {owner}/{repo}
|
||||||
|
|
||||||
|
> 由 `jsc-meta` 的 `skill-new`、`skill-update`、`skill-delete`、`skillset-update`、`skill-check` 共同維護。這是內容頁 `SKILLSET_{HASH}`。
|
||||||
|
> 一個 domain 存取庫一頁。雜湊來源是這個存取庫的 `{owner}/{repo}`。
|
||||||
|
> 本頁落在 `JSC_WIKI_REPO_SKILLSET` 解出來的存取庫;目錄頁 `SKILLSET_CONTENTS` 在別的存取庫,兩者不要混。
|
||||||
|
> **每次異動附加一節,不覆蓋舊紀錄。** 要看一支技能改過幾次,就在這一頁上翻。
|
||||||
|
> 節的排列由新到舊,最新那一次放最上面。
|
||||||
|
|
||||||
|
## {yyyy-MM-dd HH:mm} — {一句話寫這一次改了什麼}
|
||||||
|
|
||||||
|
| 項目 | 內容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 日期 | {yyyy-MM-dd HH:mm} |
|
||||||
|
| 異動類型 | {skill-new、skill-update、skill-delete、skillset-update、skill-check 五選一} |
|
||||||
|
| 異動需求 | {一句話。與目錄頁「最近異動」欄同一句} |
|
||||||
|
| 動到的技能 | {技能名,多支用頓號隔開;一支都沒動就寫「無」} |
|
||||||
|
| 改動檔案 | {存取庫內相對路徑,一行一個;一個檔都沒動就寫「無」} |
|
||||||
|
| PR 網址 | {絕對網址;沒開 PR 就寫「無」並說明原因} |
|
||||||
|
| 部署路線判定 | {部署路線、工作樹路線二選一,附 `tools/deploy-route.sh` 的結束碼} |
|
||||||
|
| 驗證結果 | {在新的 CLI 行程裡驗證的結果,寫實際看到的行為,不寫「已驗證」三個字了事} |
|
||||||
|
|
||||||
|
### 優化建議
|
||||||
|
|
||||||
|
> 只有 `skill-check` 那一節要附這張表,其餘四支不附。
|
||||||
|
> 下一輪 `skill-check` 會先讀回這張表:「決議」欄寫著 `套用` 或 `延後` 的項目不重複掃、不重複問。
|
||||||
|
> 所以「決議」與「決議日期」兩欄不得留空,留空等於下一輪讀不懂,只好重問一次。
|
||||||
|
|
||||||
|
| 面向 | 技能 | 證據 | 建議 | 決議 | 決議日期 |
|
||||||
|
| --- | --- | --- | --- | --- | --- |
|
||||||
|
| {1 可平行化、2 可下放工具、3 重複來回、4 冗餘檢查、5 閘門時機、6 成本效率 六選一} | {技能名} | {file:line} | {一句話寫怎麼改} | {套用、延後、自訂 三選一} | {yyyy-MM-dd} |
|
||||||
|
|
||||||
|
| 欄位 | 內容 |
|
||||||
|
| --- | --- |
|
||||||
|
| 面向 | 六個優化面向之一,名稱與 `skill-check` 的面向表逐字相同 |
|
||||||
|
| 技能 | 被建議的技能,跨技能的建議一列一支 |
|
||||||
|
| 證據 | `file:line`,指得到才寫得進來 |
|
||||||
|
| 建議 | 一句話寫怎麼改。會削弱防護的建議要在這裡點名被削弱的是哪一道 |
|
||||||
|
| 決議 | 使用者當輪的決定:`套用`、`延後`、`自訂`。`自訂` 要在同一列的建議欄補上實際採用的做法 |
|
||||||
|
| 決議日期 | 做出決定那一天。決議欄寫 `延後` 的項目,下一輪照這個日期認定為已決議,照樣不重問 |
|
||||||
|
|
||||||
|
## {yyyy-MM-dd HH:mm} — {上一次異動的一句話}
|
||||||
|
|
||||||
|
(上一次的內容原樣留著,不改、不刪。)
|
||||||
Executable
+142
@@ -0,0 +1,142 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# check-page-name.sh — 比對 wiki 頁名樣式三處是否一致。
|
||||||
|
#
|
||||||
|
# 用法: check-page-name.sh <root>
|
||||||
|
# <root> 是放 domain 存取庫的目錄,例如 /root/plugins。
|
||||||
|
# 目錄名同時吃 {domain} 與 jsc-{domain} 兩種寫法,也吃已安裝版面的版本目錄。
|
||||||
|
#
|
||||||
|
# 查哪三處:
|
||||||
|
# 1. {gitea}/tools/page-name.sh — 頁名樣式正本
|
||||||
|
# 2. {hooks}/hooks/comment-scope.sh — hook 內建的一份
|
||||||
|
# 3. {log}/tools/worklog-pending.sh — 工作日誌暫存內建的一份
|
||||||
|
#
|
||||||
|
# 為什麼三處各留一份,不共用函式: hook 必須自足。hook 在執行期去載別的 plugin 路徑,
|
||||||
|
# 那個 plugin 沒裝、版本不同、或路徑換了,hook 就當場失效,而且失效是安靜的。
|
||||||
|
# 共用函式換來的一致,付出的是 hook 的可用性。所以改成三處各自實作,一致性由稽核時比對。
|
||||||
|
#
|
||||||
|
# 每處斷言四項(判準見 jsc-meta references/guidelines.md 的「Wiki 頁命名總表」):
|
||||||
|
# 前兩處比對整個頁名,四項全查;第三處只驗純雜湊,沒有型別前綴,只查後兩項長度。
|
||||||
|
# 1. 型別清單 — 十五種型別逐一出現(只查比對整個頁名的那兩處): QUESTION、PLAN、ANALYZE、DELIVER、MAINTAIN、REPO、
|
||||||
|
# LOG、LEARN、ERROR、CHECK、REPORT、SKILLSET、TOOLING、MONITOR、CONTENTS。
|
||||||
|
# CONTENTS 是第十五種型別,「接受 CONTENTS」由這一項涵蓋。
|
||||||
|
# 2. 未知型別 — 出現 {某型別}_CONTENTS 或 {某型別}_{HASH} 的字樣,那個型別要在十五種之內。
|
||||||
|
# 3. 40 碼 — 接受完整 SHA-1 的 40 碼長度。
|
||||||
|
# 4. 8 碼 — 仍接受舊的 8 碼長度,遷移期間的舊頁名才讀得到。
|
||||||
|
# 5. H 開頭 — 仍接受 H 加 7 碼的舊頁名。這一項單獨列,因為三處很容易「一致地只收
|
||||||
|
# 純十六進位」——一致但都是錯的,前四項照樣全過。
|
||||||
|
#
|
||||||
|
# 判定方式與其極限: 本腳本做的是**文字層**比對,不執行那三支腳本。
|
||||||
|
# 三支的寫法各不相同(正規表示式、case 樣式、長度比較),沒有共同的可執行介面可以問,
|
||||||
|
# 要問就得各寫一套呼叫方式,那等於把三處的差異又抄第四份。
|
||||||
|
# 所以長度證據同時收樣式量詞({40}、{8,40})與檔頭文字(「40 碼」),兩者都算數。
|
||||||
|
# 代價講白: 這支抓得到「某一處漏了一種型別或一種長度」,抓不到「樣式寫法本身有錯」。
|
||||||
|
# 後者仍要人看,或由那三支自己的測試涵蓋。
|
||||||
|
#
|
||||||
|
# 輸出: 一行一個不合格項目,格式 {檔案}:{說明}(stderr);每處的判定摘要走 stdout。
|
||||||
|
# 結束碼: 0=三處一致,五項斷言全過
|
||||||
|
# 1=有不一致或有缺項,清單在 stderr(找不到其中一處或兩處也算這一碼)
|
||||||
|
# 2=用法錯誤(本腳本只吃一個參數)
|
||||||
|
# 3=三處一支都找不到——**什麼都沒查**,不等於通過。先確認 <root> 指對地方再重跑
|
||||||
|
set -u
|
||||||
|
|
||||||
|
usage() {
|
||||||
|
echo 'usage: check-page-name.sh <root>' >&2
|
||||||
|
exit 2
|
||||||
|
}
|
||||||
|
|
||||||
|
[ "$#" -eq 1 ] || usage
|
||||||
|
ROOT=${1%/}
|
||||||
|
[ -n "$ROOT" ] || usage
|
||||||
|
[ -d "$ROOT" ] || { echo "找不到根目錄:$ROOT" >&2; exit 3; }
|
||||||
|
|
||||||
|
# 十五種型別。這一行是本腳本的唯一真實來源,改動時同步 guidelines.md 的「Wiki 頁命名總表」。
|
||||||
|
TYPES='QUESTION PLAN ANALYZE DELIVER MAINTAIN REPO LOG LEARN ERROR CHECK REPORT SKILLSET TOOLING MONITOR CONTENTS'
|
||||||
|
|
||||||
|
# 長度證據的樣式。同時收樣式量詞與檔頭文字,理由見檔頭「判定方式與其極限」。
|
||||||
|
LEN40='\{40\}|\{8,40\}|\{40,40\}|40 碼|(-eq|=|\||\()[[:space:]]*40([^0-9]|$)'
|
||||||
|
LEN8='\{8\}|\{8,40\}|\{8,8\}|8 碼|(-eq|=|\||\()[[:space:]]*8([^0-9]|$)'
|
||||||
|
# H 開頭的舊頁名。舊演算法把首碼落在 0-9ABC 的改寫成 H 加原前 7 碼,十六個首碼有十三個
|
||||||
|
# 會命中,所以既有頁名多半長這樣。少了這一項,三處可以「都只收純十六進位」而一致地錯。
|
||||||
|
LENH='H\[0-9A-F\]\{7\}|H\[0-9A-Fa-f\]\{7\}|H 加(上)?(原)?前 7 碼|H\*'
|
||||||
|
|
||||||
|
hit=0
|
||||||
|
found=0
|
||||||
|
|
||||||
|
note() { # $1=檔案 $2=說明
|
||||||
|
printf '%s:%s\n' "$1" "$2" >&2
|
||||||
|
hit=1
|
||||||
|
}
|
||||||
|
|
||||||
|
find_file() { # $1=domain 目錄名(不含 jsc- 前綴) $2=存取庫內相對路徑
|
||||||
|
for _d in "$ROOT/$1" "$ROOT/jsc-$1"; do
|
||||||
|
[ -f "$_d/$2" ] && { printf '%s\n' "$_d/$2"; return 0; }
|
||||||
|
done
|
||||||
|
# 已安裝版面:一個 plugin 一個版本目錄,取排序最後的一份(通常即最新版)
|
||||||
|
_c=$(ls "$ROOT/jsc-$1"/*/"$2" "$ROOT/$1"/*/"$2" 2>/dev/null | sort | tail -n1)
|
||||||
|
[ -n "$_c" ] && [ -f "$_c" ] && { printf '%s\n' "$_c"; return 0; }
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
check_one() { # $1=檔案 $2=這一處的稱呼 $3=比對範圍:page=整個頁名 hash=只有雜湊
|
||||||
|
file=$1
|
||||||
|
label=$2
|
||||||
|
scope=$3
|
||||||
|
# 只有比對整個頁名的地方才該列型別。驗純雜湊的地方沒有型別前綴可比,
|
||||||
|
# 硬要它列十五種型別,等於逼它抄一份自己用不到的清單,下次改型別就多一處會漏。
|
||||||
|
[ "$scope" = 'page' ] || { check_len "$file"; printf '%s\t%s\n' "$label" "$file"; return 0; }
|
||||||
|
miss=''
|
||||||
|
for t in $TYPES; do
|
||||||
|
if ! grep -qE "(^|[^A-Za-z0-9_])$t([^A-Za-z0-9_]|\$)" "$file" 2>/dev/null; then
|
||||||
|
if [ -z "$miss" ]; then miss=$t; else miss="$miss、$t"; fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
[ -z "$miss" ] || note "$file" "型別清單缺 $miss"
|
||||||
|
|
||||||
|
# 反向查:出現了十五種以外的型別,代表某一處還留著已經改名或已經刪掉的型別。
|
||||||
|
unknown=''
|
||||||
|
for u in $(grep -oE '(^|[^A-Za-z0-9_])[A-Z][A-Z0-9]{2,}_(CONTENTS|\{HASH\})' "$file" 2>/dev/null \
|
||||||
|
| sed -e 's/^[^A-Z]*//' -e 's/_.*$//' | sort -u); do
|
||||||
|
case " $TYPES " in
|
||||||
|
*" $u "*) ;;
|
||||||
|
*) if [ -z "$unknown" ]; then unknown=$u; else unknown="$unknown、$u"; fi ;;
|
||||||
|
esac
|
||||||
|
done
|
||||||
|
[ -z "$unknown" ] || note "$file" "出現十五種以外的型別 $unknown"
|
||||||
|
|
||||||
|
check_len "$file"
|
||||||
|
|
||||||
|
printf '%s\t%s\n' "$label" "$file"
|
||||||
|
}
|
||||||
|
|
||||||
|
check_len() { # $1=檔案。長度斷言三處都要過,驗純雜湊的那一處也不例外。
|
||||||
|
grep -qE "$LEN40" "$1" 2>/dev/null || note "$1" '沒有接受 40 碼長度的跡象,完整 SHA-1 的頁名會被判為不合法'
|
||||||
|
grep -qE "$LEN8" "$1" 2>/dev/null || note "$1" '沒有接受 8 碼長度的跡象,遷移期間的舊頁名會讀不到'
|
||||||
|
grep -qE "$LENH" "$1" 2>/dev/null || note "$1" '沒有接受 H 開頭舊頁名的跡象,八成的既有頁名會讀不到'
|
||||||
|
}
|
||||||
|
|
||||||
|
# 三處逐一查。找不到就記一行,不中止:一次把三處的狀況都報回去,比修一處重跑一次快。
|
||||||
|
scan() { # $1=domain 目錄名 $2=相對路徑 $3=稱呼 $4=比對範圍 page|hash
|
||||||
|
if f=$(find_file "$1" "$2"); then
|
||||||
|
found=$((found + 1))
|
||||||
|
check_one "$f" "$3" "$4"
|
||||||
|
else
|
||||||
|
printf '%s/%s:%s\n' "$1" "$2" "在 $ROOT 底下找不到這一處(也試過 jsc-$1 與版本目錄)" >&2
|
||||||
|
hit=1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
scan gitea tools/page-name.sh '正本' page
|
||||||
|
scan hooks hooks/comment-scope.sh 'hook' page
|
||||||
|
scan log tools/worklog-pending.sh '工作日誌暫存' hash
|
||||||
|
|
||||||
|
if [ "$found" -eq 0 ]; then
|
||||||
|
echo "三處一支都找不到,什麼都沒查:$ROOT" >&2
|
||||||
|
exit 3
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$hit" -eq 0 ]; then
|
||||||
|
echo "頁名樣式檢查通過:三處一致(型別十五種、40 碼、8 碼、H 加 7 碼)" >&2
|
||||||
|
else
|
||||||
|
echo "頁名樣式檢查有不一致:已查 $found 處,清單見 stderr" >&2
|
||||||
|
fi
|
||||||
|
exit $hit
|
||||||
Reference in New Issue
Block a user