Merge pull request '收尾寫一筆 skill-end 事件,執行狀態才回報得到助理' (#35) from feat/status-report into develop

Reviewed-on: #35
This commit was merged in pull request #35.
This commit is contained in:
2026-09-02 08:04:30 +00:00
8 changed files with 87 additions and 15 deletions
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "jsc-log", "name": "jsc-log",
"version": "0.1.7", "version": "0.1.8",
"description": "工作日誌(LOG_{HASH} wiki 頁)、技能使用統計與教訓紀錄(LEARN_{HASH} wiki 頁)", "description": "工作日誌(LOG_{HASH} wiki 頁)、技能使用統計與教訓紀錄(LEARN_{HASH} wiki 頁)",
"skills": "./skills", "skills": "./skills",
"author": { "author": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "jsc-log", "name": "jsc-log",
"version": "0.1.7", "version": "0.1.8",
"description": "工作日誌(LOG_{HASH} wiki 頁)、技能使用統計與教訓紀錄(LEARN_{HASH} wiki 頁)", "description": "工作日誌(LOG_{HASH} wiki 頁)、技能使用統計與教訓紀錄(LEARN_{HASH} wiki 頁)",
"skills": "./skills", "skills": "./skills",
"jsc": { "jsc": {
+1 -1
View File
@@ -1,6 +1,6 @@
{ {
"name": "jsc-log", "name": "jsc-log",
"version": "0.1.7", "version": "0.1.8",
"description": "工作日誌(LOG_{HASH} wiki 頁)、技能使用統計與教訓紀錄(LEARN_{HASH} wiki 頁)", "description": "工作日誌(LOG_{HASH} wiki 頁)、技能使用統計與教訓紀錄(LEARN_{HASH} wiki 頁)",
"skills": "./skills/", "skills": "./skills/",
"jsc": { "jsc": {
+12 -12
View File
@@ -7,37 +7,37 @@
| 項目 | 內容 | | 項目 | 內容 |
| --- | --- | | --- | --- |
| 觸發時機 | 一次技能執行留下可重用的教訓時,用 record 模式記錄。要跑某支技能之前,用 consult 模式查過去的教訓。工時與 Token 紀錄不走這支,走 worklog | | 觸發時機 | 一次技能執行留下可重用的教訓時,用 record 模式記錄。要跑某支技能之前,用 consult 模式查過去的教訓。工時與 Token 紀錄不走這支,走 worklog |
| 關鍵步驟 | record 模式收齊日期、技能、CLI、情境、教訓、下次做法這六欄、從 `git remote get-url origin` 解出 `{owner}/{repo}`、用 `hash-id` 算出完整 40 碼大寫的 `{HASH}`、用 `wiki-repo LEARN` 解出教訓頁存取庫、開 sub agent 讀 `LEARN_{HASH}`、依 `wiki-get` 的退出碼分支(0 在表尾追加一列、4 才用 `templates/learn-page.md` 建頁、7 與 8 停止並回報)、取 `wiki-url` 的絕對網址並寫成 `[{頁名}]({絕對網址})`、把該網址交給 `link-check.sh` 驗證(0 才寫入、1 有 DEAD 就不寫並回報那幾筆、2 沒給網址、3 未設 `GITEA_HOST`、7 金鑰被拒就停下)、同一輪跑 `wiki-contents.sh upsert LEARN 1 {owner}/{repo}` 更新落在 CONTENTS 存取庫的 `LEARN_CONTENTS`、依它的退出碼分流(0 已寫、1 寫入失敗、2 參數錯、3 未設 `JSC_WIKI_REPO_CONTENTS`、4 缺範本、7 金鑰失效、8 其他 API 失敗)、寫入失敗重試一次;consult 模式算出 `{HASH}`、從 CONTENTS 存取庫讀 `LEARN_CONTENTS`、從 LEARN 存取庫讀 `LEARN_{HASH}`、依列上的絕對網址讀頁、挑出「技能」欄相符的列、整理每一列的「下次做法」交給呼叫端 | | 關鍵步驟 | record 模式收齊日期、技能、CLI、情境、教訓、下次做法這六欄、從 `git remote get-url origin` 解出 `{owner}/{repo}`、用 `hash-id` 算出完整 40 碼大寫的 `{HASH}`、用 `wiki-repo LEARN` 解出教訓頁存取庫、開 sub agent 讀 `LEARN_{HASH}`、依 `wiki-get` 的退出碼分支(0 在表尾追加一列、4 才用 `templates/learn-page.md` 建頁、7 與 8 停止並回報)、取 `wiki-url` 的絕對網址並寫成 `[{頁名}]({絕對網址})`、把該網址交給 `link-check.sh` 驗證(0 才寫入、1 有 DEAD 就不寫並回報那幾筆、2 沒給網址、3 未設 `GITEA_HOST`、7 金鑰被拒就停下)、同一輪跑 `wiki-contents.sh upsert LEARN 1 {owner}/{repo}` 更新落在 CONTENTS 存取庫的 `LEARN_CONTENTS`、依它的退出碼分流(0 已寫、1 寫入失敗、2 參數錯、3 未設 `JSC_WIKI_REPO_CONTENTS`、4 缺範本、7 金鑰失效、8 其他 API 失敗)、寫入失敗重試一次;consult 模式算出 `{HASH}`、從 CONTENTS 存取庫讀 `LEARN_CONTENTS`、從 LEARN 存取庫讀 `LEARN_{HASH}`、依列上的絕對網址讀頁、挑出「技能」欄相符的列、整理每一列的「下次做法」交給呼叫端;兩種模式都以 `jsc-hooks/tools/report-status.sh skill-end jsc-log:learn {status} {結束碼} {detail}` 收尾,腳本不在這台機器上就安靜跳過 |
| 外部呼叫 | `jsc-gitea/tools/hash-id`、`jsc-gitea/tools/gitea.sh wiki-repo LEARN` 與 `wiki-repo CONTENTS` 與 `wiki-url`、`jsc-gitea/tools/link-check.sh`(寫入前驗證連結)、`jsc-gitea/tools/wiki-contents.sh upsert`(目錄頁那一列)、`jsc-gitea:wiki`(其餘 wiki 讀寫)、`git remote get-url origin`、`templates/learn-page.md`、`templates/learn-contents.md` | | 外部呼叫 | `jsc-gitea/tools/hash-id`、`jsc-gitea/tools/gitea.sh wiki-repo LEARN` 與 `wiki-repo CONTENTS` 與 `wiki-url`、`jsc-gitea/tools/link-check.sh`(寫入前驗證連結)、`jsc-gitea/tools/wiki-contents.sh upsert`(目錄頁那一列)、`jsc-gitea:wiki`(其餘 wiki 讀寫)、`git remote get-url origin`、`templates/learn-page.md`、`templates/learn-contents.md` |
| 完成條件 | record 模式要 sub agent 回報兩頁都寫入成功,主代理確認新列在 `LEARN_{HASH}` 上,原有的列一列不少,寫入前 `link-check.sh` 回 0,`wiki-contents.sh` 回 0 並印出 `updated` 或 `added`。`link-check.sh` 回 1 就不寫目錄頁,改回報 DEAD 清單。consult 模式要兩頁都讀到,或以退出碼 4 回報頁面不存在,或在 5、7、8 停止並回報狀態 | | 完成條件 | record 模式要 sub agent 回報兩頁都寫入成功,主代理確認新列在 `LEARN_{HASH}` 上,原有的列一列不少,寫入前 `link-check.sh` 回 0,`wiki-contents.sh` 回 0 並印出 `updated` 或 `added`。`link-check.sh` 回 1 就不寫目錄頁,改回報 DEAD 清單。consult 模式要兩頁都讀到,或以退出碼 4 回報頁面不存在,或在 5、7、8 停止並回報狀態。收尾一定要寫一筆 `skill-end` 狀態事件:兩頁都成功是 `ok`,內容頁寫成功但目錄頁沒更新是 `degraded`,連結驗證回 1 或讀寫回 7、8 是 `failed`,雜湊工具缺席或 wiki 存取庫沒設定是 `blocked`,使用者中止或根本沒有可記的教訓是 `aborted` |
| 可驗證跡象 | LEARN 存取庫的 `LEARN_{HASH}` 表尾多一列教訓;CONTENTS 存取庫的 `LEARN_CONTENTS` 上該 repo 那一列的「最後更新時間」換新,且「教訓紀錄」欄是 `[{頁名}]({絕對網址})`,頁面上沒有 `[[...]]` 這種同 wiki 寫法。頁面原本不存在時,會新建 `LEARN_{HASH}` 或 `LEARN_CONTENTS`。連結驗證不過就兩頁都沒有新內容,只有 DEAD 清單的回報。consult 模式無寫入跡象,只有回報內容 | | 可驗證跡象 | LEARN 存取庫的 `LEARN_{HASH}` 表尾多一列教訓;CONTENTS 存取庫的 `LEARN_CONTENTS` 上該 repo 那一列的「最後更新時間」換新,且「教訓紀錄」欄是 `[{頁名}]({絕對網址})`,頁面上沒有 `[[...]]` 這種同 wiki 寫法。頁面原本不存在時,會新建 `LEARN_{HASH}` 或 `LEARN_CONTENTS`。連結驗證不過就兩頁都沒有新內容,只有 DEAD 清單的回報。consult 模式在 wiki 上無寫入跡象,只有回報內容。兩種模式跑完,`$JSC_HOME/usage/events.jsonl` 都會多一筆 `{kind:skill,phase:end}` 事件,`name` 欄是 `jsc-log:learn`,`status` 欄是那五個值之一;`jsc-hooks` 不在這台機器上時沒有這一筆,技能本身照樣跑完 |
## report ## report
| 項目 | 內容 | | 項目 | 內容 |
| --- | --- | | --- | --- |
| 觸發時機 | 有人要一段期間的工作總結時用,期間分年、月、週、日四種。單一工作包的紀錄不走這支,走 worklog | | 觸發時機 | 有人要一段期間的工作總結時用,期間分年、月、週、日四種。單一工作包的紀錄不走這支,走 worklog |
| 關鍵步驟 | 呼叫端沒指定期間就依 `jsc-ask:ask` 問、跑 `tools/report-range.sh` 取得起訖日與標籤、平行做四件事(`tools/report-template.sh resolve` 解出範本、從 CONTENTS 存取庫讀 `LOG_CONTENTS` 並照列上的絕對網址逐頁讀回工作日誌、年報另外讀 `LEARN_CONTENTS` 並用 `wiki-repo LEARN` 解出教訓內容頁的存取庫、解出 REPORT 的 wiki repo)、把頁面內容存成檔案後跑 `tools/log-aggregate.sh` 算出條目數、涵蓋 repo、花費時間、Token 用量、任務狀態、從存活條目挑出阻塞與未完成工作包、照範本的標題與表格填出報告、用 `hash-id "{REPORT wiki 存取庫}/{period}"` 算出完整 40 碼頁名、讀 `REPORT_{HASH}` 後把本期當成新章節追加在最前、取 `wiki-url` 的絕對網址並依它的退出碼分流(4 是頁還沒寫、5 是頁上沒有 `html_url`、7 與 8 一律停下並回報金鑰或 API 狀態,不得當成 4)、章節內與目錄列的連結一律寫成 `[{文字}]({絕對網址})` 並在寫入前全數交給 `link-check.sh` 驗證(0 才寫入、1 有 DEAD 就不寫並回報那幾筆、2 沒給網址、3 未設 `GITEA_HOST`、7 金鑰被拒就停下)、最後跑 `wiki-contents.sh upsert REPORT 2 {HASH}` 更新落在 CONTENTS 存取庫的 `REPORT_CONTENTS`(鍵取第 2 欄的裸 HASH,不取第 1 欄那個帶主機名的連結) | | 關鍵步驟 | 呼叫端沒指定期間就依 `jsc-ask:ask` 問、跑 `tools/report-range.sh` 取得起訖日與標籤、平行做四件事(`tools/report-template.sh resolve` 解出範本、從 CONTENTS 存取庫讀 `LOG_CONTENTS` 並照列上的絕對網址逐頁讀回工作日誌、年報另外讀 `LEARN_CONTENTS` 並用 `wiki-repo LEARN` 解出教訓內容頁的存取庫、解出 REPORT 的 wiki repo)、把頁面內容存成檔案後跑 `tools/log-aggregate.sh` 算出條目數、涵蓋 repo、花費時間、Token 用量、任務狀態、從存活條目挑出阻塞與未完成工作包、照範本的標題與表格填出報告、用 `hash-id "{REPORT wiki 存取庫}/{period}"` 算出完整 40 碼頁名、讀 `REPORT_{HASH}` 後把本期當成新章節追加在最前、取 `wiki-url` 的絕對網址並依它的退出碼分流(4 是頁還沒寫、5 是頁上沒有 `html_url`、7 與 8 一律停下並回報金鑰或 API 狀態,不得當成 4)、章節內與目錄列的連結一律寫成 `[{文字}]({絕對網址})` 並在寫入前全數交給 `link-check.sh` 驗證(0 才寫入、1 有 DEAD 就不寫並回報那幾筆、2 沒給網址、3 未設 `GITEA_HOST`、7 金鑰被拒就停下)、最後跑 `wiki-contents.sh upsert REPORT 2 {HASH}` 更新落在 CONTENTS 存取庫的 `REPORT_CONTENTS`(鍵取第 2 欄的裸 HASH,不取第 1 欄那個帶主機名的連結)、最後跑 `jsc-hooks/tools/report-status.sh skill-end jsc-log:report {status} {結束碼} {detail}` 記下本輪結果,腳本不在這台機器上就安靜跳過 |
| 外部呼叫 | `tools/report-range.sh`、`tools/report-template.sh`、`tools/log-aggregate.sh`、`jsc-gitea/tools/gitea.sh wiki-repo`(CONTENTS、LOG、LEARN、REPORT)與 `hash-id` 與 `wiki-url`、`jsc-gitea/tools/link-check.sh`(寫入前驗證連結)、`jsc-gitea/tools/wiki-contents.sh upsert`(目錄頁那一列)、`jsc-gitea:wiki`、`jsc-ask:ask`、`templates/report-{period}.md`、`templates/report-contents.md` | | 外部呼叫 | `tools/report-range.sh`、`tools/report-template.sh`、`tools/log-aggregate.sh`、`jsc-gitea/tools/gitea.sh wiki-repo`(CONTENTS、LOG、LEARN、REPORT)與 `hash-id` 與 `wiki-url`、`jsc-gitea/tools/link-check.sh`(寫入前驗證連結)、`jsc-gitea/tools/wiki-contents.sh upsert`(目錄頁那一列)、`jsc-gitea:wiki`、`jsc-ask:ask`、`templates/report-{period}.md`、`templates/report-contents.md` |
| 完成條件 | 回報頁面 URL,或回報跳過寫入與它的原因,或在讀取回 7、8 時停下並回報狀態。每次寫入前 `link-check.sh` 要回 0,回 1 就不寫該頁並回報 DEAD 清單。`wiki-contents.sh upsert` 要回 0,回 1、2、3、4、7、8 就照該碼回報且不得謊報已寫入。收尾要講出期間標籤、條目數、涵蓋的 repo、範本來源、頁面 URL、帶到下一期的未完成工作包清單,以及 `ELAPSED_MISSING` 與 `TOKEN_MISSING` | | 完成條件 | 回報頁面 URL,或回報跳過寫入與它的原因,或在讀取回 7、8 時停下並回報狀態。每次寫入前 `link-check.sh` 要回 0,回 1 就不寫該頁並回報 DEAD 清單。`wiki-contents.sh upsert` 要回 0,回 1、2、3、4、7、8 就照該碼回報且不得謊報已寫入。收尾要講出期間標籤、條目數、涵蓋的 repo、範本來源、頁面 URL、帶到下一期的未完成工作包清單,以及 `ELAPSED_MISSING` 與 `TOKEN_MISSING`。收尾一定要寫一筆 `skill-end` 狀態事件:章節與目錄列都到位是 `ok`(範圍內沒有條目、`log-aggregate.sh` 回 3 也算 `ok`,`detail` 帶 `ENTRIES=0`),報告本文交出去但 wiki 沒寫全是 `degraded`,連結驗證回 1 或讀寫回 7、8 是 `failed`,期間算不出來或範本與存取庫沒設定是 `blocked`,使用者中止是 `aborted` |
| 可驗證跡象 | REPORT 存取庫的 `REPORT_{HASH}`(雜湊取自 REPORT wiki 存取庫的 `{owner}/{repo}` 加期間,不是程式碼存取庫)多一個本期章節;CONTENTS 存取庫的 `REPORT_CONTENTS` 該列的「最新一期」、「期數」、「最後更新」換新,且「報表頁」欄是 `[{頁名}]({絕對網址})`、「HASH」欄是不帶連結的裸 HASH,兩頁都找不到 `[[...]]` 這種同 wiki 寫法。連結驗證不過就沒有新章節,也沒有新的目錄列,只有 DEAD 清單的回報。重跑同一期間只換掉那一列,不會多出第二列。本機留下工作日誌頁面內容的暫存檔,供 `log-aggregate.sh` 讀取。沒設定 REPORT wiki repo 時不寫 wiki,只印出報告本文;沒設定 `JSC_WIKI_REPO_CONTENTS` 時內容頁照寫,只有目錄頁那一列沒動 | | 可驗證跡象 | REPORT 存取庫的 `REPORT_{HASH}`(雜湊取自 REPORT wiki 存取庫的 `{owner}/{repo}` 加期間,不是程式碼存取庫)多一個本期章節;CONTENTS 存取庫的 `REPORT_CONTENTS` 該列的「最新一期」、「期數」、「最後更新」換新,且「報表頁」欄是 `[{頁名}]({絕對網址})`、「HASH」欄是不帶連結的裸 HASH,兩頁都找不到 `[[...]]` 這種同 wiki 寫法。連結驗證不過就沒有新章節,也沒有新的目錄列,只有 DEAD 清單的回報。重跑同一期間只換掉那一列,不會多出第二列。本機留下工作日誌頁面內容的暫存檔,供 `log-aggregate.sh` 讀取。沒設定 REPORT wiki repo 時不寫 wiki,只印出報告本文;沒設定 `JSC_WIKI_REPO_CONTENTS` 時內容頁照寫,只有目錄頁那一列沒動。跑完 `$JSC_HOME/usage/events.jsonl` 會多一筆 `{kind:skill,phase:end}` 事件,`name` 欄是 `jsc-log:report`,`status` 與 `exit` 兩欄對得上上一列講的判準;`jsc-hooks` 不在這台機器上時沒有這一筆,技能本身照樣跑完 |
## stats ## stats
| 項目 | 內容 | | 項目 | 內容 |
| --- | --- | | --- | --- |
| 觸發時機 | 使用者問某支技能用了幾次,或問技能之間的呼叫鏈用了幾次。Token 與工時統計不走這支,走 worklog | | 觸發時機 | 使用者問某支技能用了幾次,或問技能之間的呼叫鏈用了幾次。Token 與工時統計不走這支,走 worklog |
| 關鍵步驟 | 直接跑 `tools/usage-stats.sh skills` 或 `tools/usage-stats.sh chains`、需要時加 `--cli` 篩選單一 CLI、先讀退出碼再看輸出、退出碼 0 就把每一行印成表格一列、一行都沒印也是退出碼 0,代表次數為零,要說明 `jsc-hooks` 還沒經 `jsc-hooks:hooks-install` 安裝接線且不出表、退出碼 2 代表子指令或 `--cli` 參數被拒,改正參數後重跑 | | 關鍵步驟 | 直接跑 `tools/usage-stats.sh skills` 或 `tools/usage-stats.sh chains`、需要時加 `--cli` 篩選單一 CLI、先讀退出碼再看輸出、退出碼 0 就把每一行印成表格一列、一行都沒印也是退出碼 0,代表次數為零,要說明 `jsc-hooks` 還沒經 `jsc-hooks:hooks-install` 安裝接線且不出表、退出碼 2 代表子指令或 `--cli` 參數被拒,改正參數後重跑、最後跑 `jsc-hooks/tools/report-status.sh skill-end jsc-log:stats {status} {結束碼} {detail}` 記下本輪結果,腳本不在這台機器上就安靜跳過 |
| 外部呼叫 | `tools/usage-stats.sh`;資料由 `jsc-hooks/hooks/skill-usage.sh` 持續寫進 `$JSC_HOME/usage/*.jsonl`,這支技能只讀不寫 | | 外部呼叫 | `tools/usage-stats.sh`;資料由 `jsc-hooks/hooks/skill-usage.sh` 持續寫進 `$JSC_HOME/usage/*.jsonl`,這支技能只讀不寫 |
| 完成條件 | 讀到退出碼,並走完該退出碼指定的分支 | | 完成條件 | 讀到退出碼,並走完該退出碼指定的分支。收尾一定要寫一筆 `skill-end` 狀態事件:退出碼 0 是 `ok`(一行都沒印也是 `ok`,`detail` 帶 `count=0`),只答出一半的統計是 `degraded`,退出碼 2 是 `failed`(那一輪什麼都沒讀到,不得當成次數為零),統計腳本不在這台機器上是 `blocked`,使用者中止或問的其實是工時與 Token 是 `aborted` |
| 可驗證跡象 | 無寫入跡象,只有回報內容 | | 可驗證跡象 | 統計本身無寫入跡象,只有回報內容。跑完 `$JSC_HOME/usage/events.jsonl` 會多一筆 `{kind:skill,phase:end}` 事件,`name` 欄是 `jsc-log:stats`;`jsc-hooks` 不在這台機器上時沒有這一筆,技能本身照樣跑完 |
## worklog ## worklog
| 項目 | 內容 | | 項目 | 內容 |
| --- | --- | | --- | --- |
| 觸發時機 | implement 或 maintain 階段每結束一項任務就寫一筆。一項任務是一個工作包、一輪 PR 意見修正,或一次獨立的修正提交。下一項任務開始前就要寫完。規劃階段的筆記不走這支 | | 觸發時機 | implement 或 maintain 階段每結束一項任務就寫一筆。一項任務是一個工作包、一輪 PR 意見修正,或一次獨立的修正提交。下一項任務開始前就要寫完。規劃階段的筆記不走這支 |
| 關鍵步驟 | 全程由 sub agent 收集與寫入、平行取得十項事實(`git remote get-url origin` 的 repo、`git branch --show-current` 的分支、PLAN 頁絕對連結、ANALYZE 頁工作包絕對連結、`session-timer.sh report` 的花費時間、`token-usage.sh` 的各 CLI Token、任務狀態、細節與產出、困難與解法、PR 目標分支)、平行解出 LOG wiki repo(只供內容頁)與完整 40 碼大寫的 `{HASH}`、跑 `tools/worklog-target.sh` 取得頁名與本週五日期、用 `templates/log-entry.md` 填出單筆條目檔、跑 `tools/worklog-pending.sh merge` 併入待寫內容(同時收編同一個 `{HASH}` 的「`H` 加前 7 碼」舊目錄)、跑 `tools/worklog-pending.sh orphans` 掃出現行規則定址不到的暫存目錄(0 就安靜帶過,4 就把每一列回報給使用者並繼續本輪)、讀 `PAGE` 後依退出碼分支(0 追加在頁尾、4 才建頁、7 與 8 停止且不建頁)、寫入前把 `MERGED` 裡的每個連結交給 `link-check.sh` 驗證(0 才寫入、1 有 DEAD 就不寫並回報那幾筆、2 沒給網址、3 未設 `GITEA_HOST`、7 金鑰被拒就停下)、同一輪用 `wiki-repo CONTENTS` 解出目錄頁存取庫、取 `wiki-url` 的絕對網址並寫成 `[{頁名}]({絕對網址})`、同樣先過 `link-check.sh` 才跑 `wiki-contents.sh upsert LOG 2 {HASH}` 更新 `LOG_CONTENTS`(鍵取第 2 欄的裸 HASH,不取第 1 欄那個帶主機名的連結)並依 0、1、2、3、4、7、8 各自分流、最後依成敗跑 `worklog-pending.sh commit` 或 `abort` | | 關鍵步驟 | 全程由 sub agent 收集與寫入、平行取得十項事實(`git remote get-url origin` 的 repo、`git branch --show-current` 的分支、PLAN 頁絕對連結、ANALYZE 頁工作包絕對連結、`session-timer.sh report` 的花費時間、`token-usage.sh` 的各 CLI Token、任務狀態、細節與產出、困難與解法、PR 目標分支)、平行解出 LOG wiki repo(只供內容頁)與完整 40 碼大寫的 `{HASH}`、跑 `tools/worklog-target.sh` 取得頁名與本週五日期、用 `templates/log-entry.md` 填出單筆條目檔、跑 `tools/worklog-pending.sh merge` 併入待寫內容(同時收編同一個 `{HASH}` 的「`H` 加前 7 碼」舊目錄)、跑 `tools/worklog-pending.sh orphans` 掃出現行規則定址不到的暫存目錄(0 就安靜帶過,4 就把每一列回報給使用者並繼續本輪)、讀 `PAGE` 後依退出碼分支(0 追加在頁尾、4 才建頁、7 與 8 停止且不建頁)、寫入前把 `MERGED` 裡的每個連結交給 `link-check.sh` 驗證(0 才寫入、1 有 DEAD 就不寫並回報那幾筆、2 沒給網址、3 未設 `GITEA_HOST`、7 金鑰被拒就停下)、同一輪用 `wiki-repo CONTENTS` 解出目錄頁存取庫、取 `wiki-url` 的絕對網址並寫成 `[{頁名}]({絕對網址})`、同樣先過 `link-check.sh` 才跑 `wiki-contents.sh upsert LOG 2 {HASH}` 更新 `LOG_CONTENTS`(鍵取第 2 欄的裸 HASH,不取第 1 欄那個帶主機名的連結)並依 0、1、2、3、4、7、8 各自分流、最後依成敗跑 `worklog-pending.sh commit` 或 `abort`、再跑 `jsc-hooks/tools/report-status.sh skill-end jsc-log:worklog {status} {結束碼} {detail}` 記下本輪結果,腳本不在這台機器上就安靜跳過 |
| 外部呼叫 | `jsc-hooks/hooks/session-timer.sh report`、`tools/token-usage.sh`、`tools/worklog-target.sh`、`tools/worklog-pending.sh`、`jsc-gitea/tools/gitea.sh wiki-repo`(LOG 與 CONTENTS)與 `wiki-url`、`jsc-gitea/tools/link-check.sh`(寫入前驗證連結)、`jsc-gitea/tools/wiki-contents.sh upsert`(目錄頁那一列)、`jsc-gitea/tools/hash-id`、`jsc-gitea:wiki`、`jsc-ask:ask`、`git remote get-url origin`、`git branch --show-current`、`templates/log-entry.md`、`templates/log-contents.md` | | 外部呼叫 | `jsc-hooks/hooks/session-timer.sh report`、`tools/token-usage.sh`、`tools/worklog-target.sh`、`tools/worklog-pending.sh`、`jsc-gitea/tools/gitea.sh wiki-repo`(LOG 與 CONTENTS)與 `wiki-url`、`jsc-gitea/tools/link-check.sh`(寫入前驗證連結)、`jsc-gitea/tools/wiki-contents.sh upsert`(目錄頁那一列)、`jsc-gitea/tools/hash-id`、`jsc-gitea:wiki`、`jsc-ask:ask`、`git remote get-url origin`、`git branch --show-current`、`templates/log-entry.md`、`templates/log-contents.md` |
| 完成條件 | 兩次寫入前 `link-check.sh` 都回 0,`MERGED` 的每一筆條目都在 `PAGE` 上,原有條目逐字不動,`wiki-contents.sh upsert` 回 0 且 `CONTENTS` 該列帶著本週五日期、其他列不動,`worklog-pending.sh` 的 `commit` 或 `abort` 其中一個跑過並回報退出碼,`orphans` 也跑過且回 0 或已把孤兒清單回報出去。`link-check.sh` 回 1 或 `upsert` 回非 0 就照該碼回報,並把步驟七當成失敗處理,讓待寫內容留著 | | 完成條件 | 兩次寫入前 `link-check.sh` 都回 0,`MERGED` 的每一筆條目都在 `PAGE` 上,原有條目逐字不動,`wiki-contents.sh upsert` 回 0 且 `CONTENTS` 該列帶著本週五日期、其他列不動,`worklog-pending.sh` 的 `commit` 或 `abort` 其中一個跑過並回報退出碼,`orphans` 也跑過且回 0 或已把孤兒清單回報出去。`link-check.sh` 回 1 或 `upsert` 回非 0 就照該碼回報,並把步驟七當成失敗處理,讓待寫內容留著。收尾一定要寫一筆 `skill-end` 狀態事件:兩頁都到位是 `ok`(`orphans` 掃到孤兒仍算 `ok`,但 `detail` 要帶筆數,因為孤兒屬於別的存取庫,不影響本輪結論),內容頁寫成功而 `LOG_CONTENTS` 沒更新是 `degraded`,連結驗證回 1 不寫是 `failed`,雜湊工具或日期運算缺席、wiki 存取庫沒設定是 `blocked`,使用者中止或這一輪根本沒有任務結束是 `aborted` |
| 可驗證跡象 | LOG 存取庫的 `LOG_{HASH}` 頁尾多一筆條目,條目裡的計畫名稱、工作包編號、PR 目標分支三欄都是 `[{文字}]({絕對網址})`;CONTENTS 存取庫的 `LOG_CONTENTS` 該列的「條目數」與「最後更新」換新,且「日誌頁」欄是 `[{頁名}]({絕對網址})`,頁面上沒有 `[[...]]` 這種同 wiki 寫法,「HASH」欄是不帶連結的裸 HASH。連結驗證不過就兩頁都沒有新內容,待寫檔原樣保留。重跑同一頁只換掉那一列,不會多出第二列。`$JSC_HOME/worklog-pending/{HASH}` 底下的待寫檔在 `commit` 後清空,`abort` 後原樣保留;該目錄名是 40 碼大寫十六進位,或尚未遷移的舊暫存那種 8 碼大寫十六進位、`H` 加 7 碼大寫十六進位;推得出對映的舊目錄會連同新目錄一起被清掉。暫存區留下非 40 碼的目錄時,該輪的回報上看得到 `orphans` 印出的那幾列。本機留下填好的條目檔 | | 可驗證跡象 | LOG 存取庫的 `LOG_{HASH}` 頁尾多一筆條目,條目裡的計畫名稱、工作包編號、PR 目標分支三欄都是 `[{文字}]({絕對網址})`;CONTENTS 存取庫的 `LOG_CONTENTS` 該列的「條目數」與「最後更新」換新,且「日誌頁」欄是 `[{頁名}]({絕對網址})`,頁面上沒有 `[[...]]` 這種同 wiki 寫法,「HASH」欄是不帶連結的裸 HASH。連結驗證不過就兩頁都沒有新內容,待寫檔原樣保留。重跑同一頁只換掉那一列,不會多出第二列。`$JSC_HOME/worklog-pending/{HASH}` 底下的待寫檔在 `commit` 後清空,`abort` 後原樣保留;該目錄名是 40 碼大寫十六進位,或尚未遷移的舊暫存那種 8 碼大寫十六進位、`H` 加 7 碼大寫十六進位;推得出對映的舊目錄會連同新目錄一起被清掉。暫存區留下非 40 碼的目錄時,該輪的回報上看得到 `orphans` 印出的那幾列。本機留下填好的條目檔。跑完 `$JSC_HOME/usage/events.jsonl` 會多一筆 `{kind:skill,phase:end}` 事件,`name` 欄是 `jsc-log:worklog`,`status` 與 `exit` 兩欄對得上上一列講的判準,孤兒筆數落在 `detail` 欄;`jsc-hooks` 不在這台機器上時沒有這一筆,技能本身照樣跑完 |
+20
View File
@@ -87,3 +87,23 @@ Run before a skill run, to apply past lessons.
Done when both pages are read, or reported missing under exit 4, or the run stopped on 5, 7 or 8. Done when both pages are read, or reported missing under exit 4, or the run stopped on 5, 7 or 8.
3. Surface every row whose 技能 matches the skill about to run, and summarize each matched 下次做法 for the caller to apply. Done when the matched rows (or 「無相符教訓」) are reported. 3. Surface every row whose 技能 matches the skill about to run, and summarize each matched 下次做法 for the caller to apply. Done when the matched rows (or 「無相符教訓」) are reported.
## Close: record how the run ended
Both modes end here, as the very last thing this skill does:
`jsc-hooks/tools/report-status.sh skill-end jsc-log:learn {status} {exit} "{detail}"`
Resolve that path the way this file already resolves `jsc-gitea/tools/hash-id` and the other sibling plugin scripts — the sibling plugin directory, no separate lookup rule for this one call. **A missing script is not a failure here: skip this step in silence and let the run end as it stands.** The script swallows its own write errors and exits 0 even then, so nothing branches on its code either. A lesson that was recorded stays recorded whether or not the recorder of recorders was installed.
| status | This skill's case |
| --- | --- |
| `ok` | record — both pages carry the new row and every row that was there before is still there. consult — both pages were read, or a page was reported absent under exit 4, and the matched 下次做法 lines reached the caller |
| `blocked` | The run never reached a page: `hash-id` exit 1 (no SHA-1 helper), `wiki-repo LEARN` or `wiki-repo CONTENTS` exit 3 (no wiki repo configured for that page type), or `link-check.sh` exit 3 (`GITEA_HOST` unset) |
| `degraded` | record — the lesson row is on `LEARN_{HASH}` but `wiki-contents.sh upsert` did not land the directory row (exit 1, 3, 7 or 8), so the lesson is on the wiki and nothing points at it. consult — one of the two pages was read and the other stopped the run, so the caller got part of the lesson set and knows it |
| `failed` | An API call answered with something unexpected after the work started: `link-check.sh` exit 1 on a DEAD link, a `wiki-get` that came back 7 or 8, or a page write that failed its retry as well. Nothing reached `LEARN_{HASH}` |
| `aborted` | The user stopped the run, or record mode was called with nothing reusable to record, so the six facts never formed an entry and no write was attempted |
`{exit}` is the exit code of whatever decided the status, `0` for `ok`. `{detail}` is one short line well under 200 characters: the mode plus counts and exit codes, never the lesson text, page names, branch names, or personal data.
Done when the command has run, or the script was absent and this step was skipped.
+18
View File
@@ -116,3 +116,21 @@ Done when the page URL is reported, or the skipped write is reported with its re
State the period label, entry count, repositories covered, template source, and the page URL. Name every unfinished work package that carried over — that list is what the next period starts from. State `ELAPSED_MISSING` and `TOKEN_MISSING` whenever either is above 0, so a small total is read as missing data rather than a light week. State the period label, entry count, repositories covered, template source, and the page URL. Name every unfinished work package that carried over — that list is what the next period starts from. State `ELAPSED_MISSING` and `TOKEN_MISSING` whenever either is above 0, so a small total is read as missing data rather than a light week.
Done when those five facts, the carry-over list and the two missing-data counts are stated. Done when those five facts, the carry-over list and the two missing-data counts are stated.
Then record how the run ended, as the very last thing this skill does:
`jsc-hooks/tools/report-status.sh skill-end jsc-log:report {status} {exit} "{detail}"`
Resolve that path the way this file already resolves `jsc-gitea/tools/link-check.sh` and the other sibling plugin scripts — the sibling plugin directory, no separate lookup rule for this one call. **A missing script is not a failure here: skip this step in silence and let the run end as it stands.** The script swallows its own write errors and exits 0 even then, so nothing branches on its code either. A report that was produced stays produced whether or not the recorder was installed.
| status | This skill's case |
| --- | --- |
| `ok` | The period's section is on `REPORT_{HASH}` and the `REPORT_CONTENTS` row carries this period. `log-aggregate.sh` exit 3 stays `ok`: an empty range is an answer, and section 2 requires the report to be produced anyway — put `ENTRIES=0` in `{detail}` so the zero is read as a counted zero, not a run that quit |
| `blocked` | Nothing could be summarised and nothing was: `report-range.sh` exit 4 (this machine's `date` does no date arithmetic), `report-template.sh resolve` exit 3 (neither template exists), `wiki-repo CONTENTS` or `wiki-repo LOG` exit 3 (no directory or log pages to read), `hash-id` exit 1, or `link-check.sh` exit 3 or 7 |
| `degraded` | The report body is finished and handed to the caller but did not fully land: `wiki-repo REPORT` exit 3 skipped the wiki write entirely, or the section landed and `wiki-contents.sh upsert` did not, or `wiki-repo LEARN` exit 3 left the yearly 全年教訓 section filled with 無. Say which part is missing in `{detail}` |
| `failed` | The collection or the write broke part-way: `link-check.sh` exit 1 on a DEAD link, a `jsc-gitea:wiki` read or a `wiki-url` call that came back 7 or 8, `log-aggregate.sh` exit 4 on an unreadable page file, or a write that failed its retry as well |
| `aborted` | The user stopped the run, most often at the period question in section 1, so no range was ever fixed and no page was read |
`{exit}` is the exit code of whatever decided the status, `0` for `ok`. `{detail}` is one short line well under 200 characters: the period plus counts and exit codes, never report text, page names, branch names, or personal data.
Done when the command has run, or the script was absent and this step was skipped.
+17
View File
@@ -25,3 +25,20 @@ Data is recorded continuously by `jsc-hooks/hooks/skill-usage.sh` under `$JSC_HO
| 2 | The subcommand or the `--cli` argument was rejected — the subcommand is neither `skills` nor `chains`, or `--cli` came with no value. Fix the argument and rerun. Never rerun the same command unchanged, and never report the counts as zero: nothing was read | | 2 | The subcommand or the `--cli` argument was rejected — the subcommand is neither `skills` nor `chains`, or `--cli` came with no value. Fix the argument and rerun. Never rerun the same command unchanged, and never report the counts as zero: nothing was read |
Done when the exit code was read and the branch it names was taken. Done when the exit code was read and the branch it names was taken.
2. Record how the run ended, as the very last thing this skill does:
`jsc-hooks/tools/report-status.sh skill-end jsc-log:stats {status} {exit} "{detail}"`
Resolve that path the way this file already names `jsc-hooks/hooks/skill-usage.sh` — the sibling plugin directory, no separate lookup rule for this one call. **A missing script is not a failure here: skip this step in silence and let the run end as it stands.** The script swallows its own write errors and exits 0 even then, so nothing branches on its code either. This skill only reads counts; it must never fail because a count of its own could not be written.
| status | This skill's case |
| --- | --- |
| `ok` | The tool exited 0 and every printed line reached the report. A run that printed no line is `ok` as well — the count really is zero, so say `count=0` in `{detail}` rather than dressing an empty data file up as a problem |
| `blocked` | `tools/usage-stats.sh` is not on this machine, which is a partial plugin install rather than a zero count. No number was ever read, so none is reported |
| `degraded` | The caller asked for both counts and only one sub-command answered, so the report covers half of what was asked. Name the half that is missing in `{detail}` |
| `failed` | Exit 2 — the sub-command or the `--cli` value was rejected, so nothing was read. This is the one case that must never be reported as a count of zero, and recording it as `failed` is what keeps the two apart in the event stream too |
| `aborted` | The user stopped the run, or the request turned out to be about elapsed time or token usage, which belong to `jsc-log:worklog`; this skill then stops before it counts anything |
`{exit}` is the exit code of whatever decided the status, `0` for `ok`. `{detail}` is one short line well under 200 characters: the sub-command plus counts and exit codes, never branch names or personal data.
Done when the command has run, or the script was absent and this step was skipped.
+17
View File
@@ -115,3 +115,20 @@ The `{HASH}` in every page name above is computed with `jsc-gitea/tools/hash-id`
| 2 | The claim path is not the one `merge` produced, or it points outside this `{HASH}`'s pending directory. Rerun from step 4 with the `CLAIM` value that `merge` printed; never pass a hand-written path | | 2 | The claim path is not the one `merge` produced, or it points outside this `{HASH}`'s pending directory. Rerun from step 4 with the `CLAIM` value that `merge` printed; never pass a hand-written path |
Done when one of the two ran and its exit code was reported. Done when one of the two ran and its exit code was reported.
8. Record how this run ended, as the very last thing this skill does:
`jsc-hooks/tools/report-status.sh skill-end jsc-log:worklog {status} {exit} "{detail}"`
Resolve that path the way row 5 already resolves `jsc-hooks/hooks/session-timer.sh` — the sibling plugin directory, no separate lookup rule for this one call. **A missing script is not a failure here: skip this step in silence and let the run end as it stands.** The script swallows its own write errors and exits 0 even then, so nothing branches on its code either. A run whose result could not be recorded still had that result, and a work log that fails because the recorder is absent is worse than no recording.
| status | This skill's case |
| --- | --- |
| `ok` | Steps 5 and 6 both wrote and step 7 cleared the pending area. `orphans` exit 4 stays `ok`: an orphan directory belongs to some other repository and changes nothing about this entry — carry its line count in `{detail}` so the count is on record even though the run passed |
| `blocked` | Nothing could be written and nothing was: `hash-id` exit 1 (no SHA-1 helper on this machine), `worklog-target.sh friday` exit 4 (no date arithmetic), `wiki-repo LOG` exit 3 (no LOG wiki repo configured), or `link-check.sh` exit 3 (`GITEA_HOST` unset) or exit 7 (token rejected). The gate stopped the run before a page was touched |
| `degraded` | The entry is on `LOG_{HASH}` but the close-out is short: `wiki-contents.sh upsert` returned non-zero so `LOG_CONTENTS` still carries the old row, or `worklog-pending.sh commit` exited 1 so the pending files survive a successful write and the next run merges them again |
| `failed` | Nothing reached the wiki after the run started working: `link-check.sh` exit 1 stopped the write on a DEAD link, the `PAGE` read came back 7 or 8, or `worklog-pending.sh merge` exited 1 |
| `aborted` | The user stopped the run, or the trigger turned out not to hold — no task ended here, so there is no entry to write and none was attempted |
`{exit}` is the exit code of whatever decided the status, `0` for `ok`. `{detail}` is one short line well under 200 characters: counts and exit codes only, never entry text, page names, branch names, or personal data.
Done when the command has run, or the script was absent and this step was skipped.