diff --git a/.claude-plugin/plugin.json b/.claude-plugin/plugin.json index 73faddd..a23d9eb 100644 --- a/.claude-plugin/plugin.json +++ b/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "jsc-log", - "version": "0.0.8", + "version": "0.0.9", "description": "工作日誌(LOG_{HASH} wiki 頁)、技能使用統計與教訓紀錄(LEARN_{HASH} wiki 頁)", "skills": "./skills", "author": { diff --git a/.codex-plugin/plugin.json b/.codex-plugin/plugin.json index 09756e6..4e99326 100644 --- a/.codex-plugin/plugin.json +++ b/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "jsc-log", - "version": "0.0.8", + "version": "0.0.9", "description": "工作日誌(LOG_{HASH} wiki 頁)、技能使用統計與教訓紀錄(LEARN_{HASH} wiki 頁)", "skills": "./skills" } diff --git a/README.md b/README.md index 3335079..86439b0 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,7 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安 | --- | --- | | `tools/usage-stats.sh` | 聚合 `$JSC_HOME/usage/*.jsonl`:`skills` 列技能使用次數、`chains` 列呼叫鏈次數(皆降冪),`--cli ` 過濾 | | `tools/worklog-target.sh` | 接收已由 `jsc-gitea/tools/hash-id` 算好的 `HASH`,組出 `LOG_{HASH}`、`LOG_CONTENTS`(本身不再計算 SHA-1) | +| `tools/worklog-pending.sh` | 待寫入日誌的暫存區,存放於 `$JSC_HOME/worklog-pending/{HASH}/`。`add {HASH} {檔案}` 存一段內容(`jsc-sdlc` 的階段回報發現沒寫日誌時會呼叫),`cat {HASH}` 依時間印出全部、`list` 列路徑、`clear` 清除。結束碼 `3` 代表沒有暫存內容。**寫進 wiki 成功之後才 clear**,先清再寫會兩邊都沒有 | | `tools/token-usage.sh` | 讀單一 CLI 這次工作的 token 用量,印出「input(tab)output」;來源讀不到就印「N/A(tab)N/A」並正常結束。第二個參數傳 session id,就只讀該階段的 transcript,數字才會跟花費時間對得上。各 CLI 的取得方式寫在腳本開頭註解 | ## Skills 目錄 @@ -34,7 +35,7 @@ Marketplace 統一為 `jsc`(https://gitea.jsc.idv.tw/plugins/meta.git),安 ### `worklog` -工作完成後蒐集十項資訊(存取庫、分支、計畫連結、工作包連結、花費時間、token 用量、任務狀態、執行細節、困難與解決、PR 目標分支),用 `tools/worklog-target.sh` 產生目標頁,再套範本附加到 `LOG_{HASH}` 與 `LOG_CONTENTS`。 +工作完成後蒐集十項資訊(存取庫、分支、計畫連結、工作包連結、花費時間、token 用量、任務狀態、執行細節、困難與解決、PR 目標分支),用 `tools/worklog-target.sh` 產生目標頁,再套範本附加到 `LOG_{HASH}` 與 `LOG_CONTENTS`。寫入前先讀 `tools/worklog-pending.sh cat {HASH}`:之前有階段跑完沒寫日誌,內容會暫存在那裡,這次一併寫進去,**寫成功之後才清暫存**。 ### `stats` diff --git a/plugin.json b/plugin.json index bbed3be..1c557aa 100644 --- a/plugin.json +++ b/plugin.json @@ -1,6 +1,6 @@ { "name": "jsc-log", - "version": "0.0.8", + "version": "0.0.9", "description": "工作日誌(LOG_{HASH} wiki 頁)、技能使用統計與教訓紀錄(LEARN_{HASH} wiki 頁)", "skills": "./skills/" } diff --git a/skills/worklog/SKILL.md b/skills/worklog/SKILL.md index e7aa0e3..9c2b4fe 100644 --- a/skills/worklog/SKILL.md +++ b/skills/worklog/SKILL.md @@ -1,6 +1,6 @@ --- name: worklog -description: After finishing a work package, collect ten facts (repo, branch, plan link, work package link, elapsed time from session-timer, token usage per CLI, status, details, difficulties, PR target) and append a templated entry to wiki LOG_{HASH} plus LOG_CONTENTS. HASH follows the shared 8-char rule with the H-prefix fallback, and the work-week Friday still drives the page content. Trigger at the end of implement or maintain; not for planning notes. +description: After finishing a work package, collect ten facts (repo, branch, plan link, work package link, elapsed time from session-timer, token usage per CLI, status, details, difficulties, PR target) and append a templated entry to wiki LOG_{HASH} plus LOG_CONTENTS. HASH follows the shared 8-char rule with the H-prefix fallback, and the work-week Friday still drives the page content. Merge whatever tools/worklog-pending.sh holds for that HASH into the same write, then clear the pending area once the wiki write succeeded. Trigger at the end of implement or maintain; not for planning notes. --- # worklog — work log @@ -30,5 +30,7 @@ The `{HASH}` in every page name above is computed with `jsc-gitea/tools/hash-id` 2. Compute `{HASH}` from the code repo's `{owner}/{repo}` with `jsc-gitea/tools/hash-id`. Done when the 8-character `{HASH}` is known. 3. Run `tools/worklog-target.sh "{HASH}" all`. Use `PAGE` for `LOG_{HASH}` and `CONTENTS` for `LOG_CONTENTS`. Done when both page names are known. 4. Fix the work week: the Friday of the current work week drives the page content and the row dates. Done when that Friday is fixed as a `yyyy-MM-dd` date. -5. Read `PAGE` via `jsc-gitea:wiki`. If it does not exist, create it with the structure described in `templates/log-entry.md`; otherwise APPEND the new entry at the end and never overwrite existing entries. Done when the new entry exists on `PAGE`. -6. Update `CONTENTS` in the same pass (apply `templates/log-contents.md`; add the row if missing, otherwise refresh its 條目數 and 最後更新). Done when the row for `PAGE` carries this week's Friday date. +5. Collect what the pending area holds for this `{HASH}`: run `tools/worklog-pending.sh cat {HASH}`. Exit 3 means nothing is pending — carry on with this run's entry alone. Anything it prints was written by an earlier SDLC stage that ended without a work log, so it goes into **this** write, ahead of this run's own entry, in the order printed. Done when the pending content is either merged into the entries about to be written, or confirmed empty. +6. Read `PAGE` via `jsc-gitea:wiki`. If it does not exist, create it with the structure described in `templates/log-entry.md`; otherwise APPEND the new entries at the end and never overwrite existing entries. Done when every entry from step 5 plus this run's own entry exists on `PAGE`. +7. Update `CONTENTS` in the same pass (apply `templates/log-contents.md`; add the row if missing, otherwise refresh its 條目數 and 最後更新). Done when the row for `PAGE` carries this week's Friday date. +8. Clear the pending area: run `tools/worklog-pending.sh clear {HASH}` **only after the wiki write of step 6 succeeded**. Clearing first and failing the write loses the content on both sides. Skip this when step 5 found nothing. Done when the script reports the cleared path, or step 5 was empty. diff --git a/tools/worklog-pending.sh b/tools/worklog-pending.sh new file mode 100755 index 0000000..a530b72 --- /dev/null +++ b/tools/worklog-pending.sh @@ -0,0 +1,92 @@ +#!/usr/bin/env sh +# worklog-pending.sh — 待寫入工作日誌的暫存區(供 jsc-sdlc 階段回報與 jsc-log:worklog 使用)。 +# +# 為什麼要有這支腳本:SDLC 每個階段結束都要回報工作日誌連結。階段跑完卻沒寫日誌時, +# 內容如果只留在對話裡,換一個工作階段就消失了,下次寫日誌也補不回來。所以暫存搬到檔案層: +# 階段回報發現沒有日誌,就把該階段的內容存進本區並警告使用者;下次 jsc-log:worklog 寫入時 +# 先把本區的內容一併寫進去,寫完才清掉。 +# +# 用法: +# worklog-pending.sh add 把一段待寫入的日誌內容存起來,印出存放路徑 +# worklog-pending.sh list 列出該 hash 的暫存檔路徑(一行一個,依時間排序) +# worklog-pending.sh cat 依時間順序印出全部暫存內容 +# worklog-pending.sh clear 清掉該 hash 的暫存(寫入日誌成功後才做) +# +# 為 jsc-gitea/tools/hash-id 算出的 8 碼工作日誌 hash,也就是 LOG_{HASH} 的 HASH。 +# 存放位置: $JSC_HOME/worklog-pending/{hash}/{UTC 時間}-{pid}.md(JSC_HOME 預設 ~/.jsc) +# +# 結束碼: 0=成功 1=讀寫失敗 2=用法錯誤 3=該 hash 沒有暫存內容 +# +# 陷阱: +# - clear 只在日誌確實寫進 wiki 之後才呼叫。先清再寫,寫失敗就兩邊都沒有。 +# - 檔名帶 UTC 時間與 pid,同一秒內兩個工作階段各存各的,不會互相覆蓋。 +set -eu + +JSC_HOME="${JSC_HOME:-$HOME/.jsc}" +ROOT="$JSC_HOME/worklog-pending" + +usage() { + cat >&2 <<'EOF' +用法: + worklog-pending.sh add 存一段待寫入的日誌內容 + worklog-pending.sh list 列出暫存檔路徑 + worklog-pending.sh cat 印出全部暫存內容 + worklog-pending.sh clear 清掉暫存(寫入日誌成功後才做) +結束碼: 0=成功 1=讀寫失敗 2=用法錯誤 3=沒有暫存內容 +EOF + exit 2 +} + +valid_hash() { # 只收 8 碼大寫英數,擋掉路徑穿越 + case "$1" in + [0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z][0-9A-Z]) return 0 ;; + *) echo "[jsc][工作日誌暫存][ERR]:hash 須為 8 碼大寫英數,收到「${1:-空值}」。" >&2; exit 2 ;; + esac +} + +cmd="${1:-}"; [ -n "$cmd" ] || usage +shift || true +hash="${1:-}"; [ -n "$hash" ] || usage +valid_hash "$hash" +dir="$ROOT/$hash" + +case "$cmd" in + add) + src="${2:-}" + [ -n "$src" ] || usage + [ -f "$src" ] || { echo "[jsc][工作日誌暫存][ERR]:找不到內容檔「$src」。" >&2; exit 1; } + mkdir -p "$dir" || { echo "[jsc][工作日誌暫存][ERR]:建不出暫存目錄「$dir」。" >&2; exit 1; } + stamp=$(date -u +%Y%m%dT%H%M%SZ) + target="$dir/$stamp-$$.md" + cp "$src" "$target" || { echo "[jsc][工作日誌暫存][ERR]:寫不進「$target」。" >&2; exit 1; } + printf '%s\n' "$target" + ;; + list) + [ -d "$dir" ] || exit 3 + found=0 + for f in "$dir"/*.md; do + [ -f "$f" ] || continue + printf '%s\n' "$f" + found=1 + done + [ "$found" -eq 1 ] || exit 3 + ;; + cat) + [ -d "$dir" ] || exit 3 + found=0 + for f in "$dir"/*.md; do + [ -f "$f" ] || continue + cat "$f" + printf '\n' + found=1 + done + [ "$found" -eq 1 ] || exit 3 + ;; + clear) + [ -d "$dir" ] || exit 3 + rm -rf "$dir" || { echo "[jsc][工作日誌暫存][ERR]:清不掉「$dir」。" >&2; exit 1; } + printf '已清除暫存:%s\n' "$dir" + ;; + *) + usage ;; +esac