log 0.0.9 發佈:工作日誌待寫入暫存 #13
@@ -10,7 +10,7 @@ Close the loop on skill runs: record what a run taught you, consult it before th
|
|||||||
## Target pages
|
## Target pages
|
||||||
|
|
||||||
- Directory page: `LEARN_CONTENTS`. Content page: `LEARN_{HASH}`, one page per repository.
|
- Directory page: `LEARN_CONTENTS`. Content page: `LEARN_{HASH}`, one page per repository.
|
||||||
- Compute `{HASH}` from `{owner}/{repo}` with `jsc-gitea/tools/hash-id` (shared wiki hash rule: first 8 uppercase SHA-1 hex chars; `H` plus the first 7 chars when the raw hash starts with `0-9`, `A`, `B`, or `C`).
|
- Compute `{HASH}` from `{owner}/{repo}` with `jsc-gitea/tools/hash-id`.
|
||||||
- Wiki repo resolution: `JSC_WIKI_REPO_LEARN` first, then `JSC_WIKI_REPO`. Inspect the inherited shell environment variables first; ask the user per the `jsc-ask:ask` rules only when neither resolves. Never borrow another type's `JSC_WIKI_REPO_{TYPE}`.
|
- Wiki repo resolution: `JSC_WIKI_REPO_LEARN` first, then `JSC_WIKI_REPO`. Inspect the inherited shell environment variables first; ask the user per the `jsc-ask:ask` rules only when neither resolves. Never borrow another type's `JSC_WIKI_REPO_{TYPE}`.
|
||||||
- All wiki reads and writes go through `jsc-gitea:wiki`.
|
- All wiki reads and writes go through `jsc-gitea:wiki`.
|
||||||
|
|
||||||
|
|||||||
@@ -17,5 +17,5 @@ Data is recorded continuously by `jsc-hooks/hooks/skill-usage.sh` under `$JSC_HO
|
|||||||
|
|
||||||
## Reporting
|
## Reporting
|
||||||
|
|
||||||
1. Run the tool directly and present the output as a table.
|
1. Run the tool directly and present the output as a table. Done when every line the tool printed appears as one table row.
|
||||||
2. When there is no data, explain that `jsc-hooks` must be installed and wired first via `jsc-hooks:hooks-install`.
|
2. When the tool prints no rows, explain that `jsc-hooks` must be installed and wired first via `jsc-hooks:hooks-install`. Done when that instruction is reported and no table is shown.
|
||||||
|
|||||||
+14
-22
@@ -11,32 +11,24 @@ After work completes, collect the ten items below and append a `templates/log-en
|
|||||||
|
|
||||||
| # | Item | Source |
|
| # | Item | Source |
|
||||||
| --- | --- | --- |
|
| --- | --- | --- |
|
||||||
| 1 | Repository name | Parse `{owner}/{repo}` from `git remote get-url origin` |
|
| 1 | Repository name | Parse `{owner}/{repo}` from `git remote get-url origin`. This is the code repo — never pass it to `wiki-url`, which takes the wiki-hosting repo |
|
||||||
| 2 | Branch name | `git branch --show-current` |
|
| 2 | Branch name | `git branch --show-current` |
|
||||||
| 3 | Plan name | Absolute link to the plan page: `[PLAN_{HASH}](<url>)`, where `<url>` comes from `jsc-gitea/tools/gitea.sh wiki-url {owner}/{repo} PLAN_{HASH}` — PLAN and LOG may live in different wiki repos, and `[[...]]` only resolves inside one wiki |
|
| 3 | Plan name | Absolute link to the plan page: `[PLAN_{HASH}](<url>)`. Resolve the hosting repo with `jsc-gitea/tools/gitea.sh wiki-repo PLAN`, then take `<url>` from `gitea.sh wiki-url <that repo> PLAN_{HASH}` — PLAN and LOG may live in different wiki repos, and `[[...]]` only resolves inside one wiki. `wiki-repo` exit 3 (no wiki repo configured for that type) or `wiki-url` exit 4 (page not found) → fill the literal 「無」 for this row and carry on; a `worklog` run triggered from `maintain` normally has no plan page |
|
||||||
| 4 | Work package id | Absolute link to the work package heading: `[WP-xx](<url>#wp-xx)`, `<url>` from `gitea.sh wiki-url {owner}/{repo} ANALYZE_{HASH}` |
|
| 4 | Work package id | Absolute link to the work package heading: `[WP-xx](<url>#wp-xx)`. Resolve the hosting repo with `gitea.sh wiki-repo ANALYZE`, then take `<url>` from `gitea.sh wiki-url <that repo> ANALYZE_{HASH}`. Same fallback as row 3: `wiki-repo` exit 3 or `wiki-url` exit 4 → fill 「無」 and carry on |
|
||||||
| 5 | Elapsed time | `jsc-hooks/hooks/session-timer.sh report {session_id}` (seconds; convert to h/m) |
|
| 5 | Elapsed time | `jsc-hooks/hooks/session-timer.sh report {session_id}` (seconds; convert to h/m) |
|
||||||
| 6 | Token usage | See the table below; per-CLI methods differ. Fill `N/A` when unavailable |
|
| 6 | Token usage | `tools/token-usage.sh <cli> {session_id}` per CLI that ran; it prints `input<TAB>output`. Pass the same `{session_id}` as row 5 so the elapsed time and the token count describe one session. Fill `N/A` in both columns when it prints `N/A`; exit 2 means the CLI name is not one of claude / codex / copilot / antigravity / kiro, so fix the name and rerun |
|
||||||
| 7 | Task status | One of the literal values 「完成」、「部分完成」、「阻塞」 (with reason when blocked) |
|
| 7 | Task status | One of the literal values 「完成」, 「部分完成」, 「阻塞」 (with reason when blocked). Derive it from the session when the session shows it; otherwise ask via `jsc-ask:ask`, offering those three literals as the options and stating each option's impact scope (「完成」 closes the work package, 「部分完成」 leaves the remainder open for the next run, 「阻塞」 records the blocker and hands it back to the operator) |
|
||||||
| 8 | Details and outputs | Summarize what changed and which files or pages were produced |
|
| 8 | Details and outputs | One line per changed file or produced page: what changed there and why |
|
||||||
| 9 | Difficulties and resolutions | One pair per line |
|
| 9 | Difficulties and resolutions | One pair per line. Ask via `jsc-ask:ask` when the session does not show them |
|
||||||
| 10 | PR target branch | Link to the PR page |
|
| 10 | PR target branch | Link to the PR page |
|
||||||
|
|
||||||
### How to get token usage
|
The `{HASH}` in every page name above is computed with `jsc-gitea/tools/hash-id`.
|
||||||
|
|
||||||
| CLI | Method |
|
|
||||||
| --- | --- |
|
|
||||||
| claude | Sum the `usage` fields in transcript JSONL (`~/.claude/projects/**/*.jsonl`), or read `usage` from `claude -p --output-format json` |
|
|
||||||
| codex | Token counters under `~/.codex/sessions/**`, or `/status` inside the session |
|
|
||||||
| copilot | `/usage` inside the session |
|
|
||||||
| antigravity | Value shown in the UI; `N/A` when unreadable |
|
|
||||||
| kiro | No public source; fill `N/A` |
|
|
||||||
|
|
||||||
## Target page and work week
|
## Target page and work week
|
||||||
|
|
||||||
- Page name: `LOG_{HASH}`.
|
1. Resolve the wiki repo hosting LOG pages: `JSC_WIKI_REPO_LOG` first, then `JSC_WIKI_REPO`, via `gitea.sh wiki-repo LOG`. Inspect the inherited shell environment variables first; ask the user per the `jsc-ask:ask` rules only when neither resolves. Never borrow another type's `JSC_WIKI_REPO_{TYPE}`. Done when the hosting `{owner}/{repo}` is known.
|
||||||
- Compute `{HASH}` from `{owner}/{repo}` with `jsc-gitea/tools/hash-id` (shared wiki hash rule: first 8 uppercase SHA-1 hex chars; `H` plus the first 7 chars when the raw hash starts with `0-9`, `A`, `B`, or `C`).
|
2. Compute `{HASH}` from the code repo's `{owner}/{repo}` with `jsc-gitea/tools/hash-id`. Done when the 8-character `{HASH}` is known.
|
||||||
- Compute the target page by running `tools/worklog-target.sh "{HASH}" all`. Use `PAGE` for `LOG_{HASH}` and `CONTENTS` for `LOG_CONTENTS`.
|
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.
|
||||||
- The work-week Friday still drives the page content and the row dates.
|
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.
|
||||||
- Read the page via `jsc-gitea:wiki`. If it does not exist, create it with the structure described in `templates/log-contents.md`; otherwise APPEND the new entry at the end.
|
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`.
|
||||||
- Update `LOG_CONTENTS` in the same pass (apply `templates/log-contents.md`; add the row if missing).
|
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.
|
||||||
|
|||||||
Executable
+77
@@ -0,0 +1,77 @@
|
|||||||
|
#!/usr/bin/env sh
|
||||||
|
# token-usage.sh — 讀出單一 CLI 這次工作的 token 用量。
|
||||||
|
# 用法:
|
||||||
|
# token-usage.sh <cli> [session-id] # cli = claude|codex|copilot|antigravity|kiro
|
||||||
|
# 輸出: 一行「<input>(tab)<output>」。任何來源讀不到就印「N/A(tab)N/A」並 exit 0。
|
||||||
|
# 護欄: 沒給 cli 或 cli 名稱不認得,回傳 2。
|
||||||
|
#
|
||||||
|
# 各 CLI 的取得方式(原本寫在 worklog 的 SKILL.md,現在收在這裡):
|
||||||
|
# claude 加總 transcript JSONL(`$CLAUDE_CONFIG_DIR` 或 `~/.claude` 底下的
|
||||||
|
# `projects/**/*.jsonl`)每筆訊息的 `usage.input_tokens` 與
|
||||||
|
# `usage.output_tokens`。也可以改讀 `claude -p --output-format json`
|
||||||
|
# 回應裡的 `usage` 欄位。
|
||||||
|
# codex 讀 `~/.codex/sessions/**` 的 token 計數欄位;session 內打 `/status`
|
||||||
|
# 也看得到同一組數字。
|
||||||
|
# copilot 只有 session 內的 `/usage` 看得到,沒有可讀檔案 → N/A。
|
||||||
|
# antigravity 只顯示在 UI,沒有可讀檔案 → N/A。
|
||||||
|
# kiro 沒有公開來源 → N/A。
|
||||||
|
#
|
||||||
|
# 有給 session id 就優先取檔名含該 id 的 session 檔,因為日誌的花費時間也是按同一個
|
||||||
|
# session id 取的(session-timer.sh report {sid}),兩個數字必須描述同一個工作階段。
|
||||||
|
# 沒給 session id 才退回「最後修改的那一份」——那份可能是別的工作階段,或同一階段的
|
||||||
|
# sub agent 紀錄,數字只能當粗估。
|
||||||
|
set -u
|
||||||
|
|
||||||
|
na() { printf 'N/A\tN/A\n'; exit 0; }
|
||||||
|
|
||||||
|
cli="${1:-}"
|
||||||
|
sid="${2:-}"
|
||||||
|
if [ -z "$cli" ]; then
|
||||||
|
echo 'usage: token-usage.sh <cli> [session-id]' >&2
|
||||||
|
exit 2
|
||||||
|
fi
|
||||||
|
|
||||||
|
newest() { # <dir> <name-pattern> -> 最後修改的檔案路徑;找不到回非零
|
||||||
|
[ -d "$1" ] || return 1
|
||||||
|
f=$(find "$1" -type f -name "$2" -exec ls -t {} + 2>/dev/null | head -1)
|
||||||
|
[ -n "$f" ] || return 1
|
||||||
|
printf '%s\n' "$f"
|
||||||
|
}
|
||||||
|
|
||||||
|
pick() { # <dir> -> 先找 session id 相符的檔案,找不到才退回最後修改的
|
||||||
|
if [ -n "$sid" ]; then
|
||||||
|
if f=$(newest "$1" "*$sid*.jsonl"); then printf '%s\n' "$f"; return 0; fi
|
||||||
|
echo "warn: 找不到 session $sid 的 transcript,改用最後修改的那一份,數字可能不是本階段的。" >&2
|
||||||
|
fi
|
||||||
|
newest "$1" '*.jsonl'
|
||||||
|
}
|
||||||
|
|
||||||
|
sum_field() { # <file> <欄位名> -> 該欄位所有出現值的總和;沒有值就印空字串
|
||||||
|
grep -o "\"$2\"[[:space:]]*:[[:space:]]*[0-9][0-9]*" "$1" 2>/dev/null \
|
||||||
|
| grep -o '[0-9][0-9]*$' \
|
||||||
|
| awk '{ s += $1 } END { if (NR > 0) print s }'
|
||||||
|
}
|
||||||
|
|
||||||
|
case "$cli" in
|
||||||
|
claude)
|
||||||
|
src=$(pick "${CLAUDE_CONFIG_DIR:-$HOME/.claude}/projects") || na ;;
|
||||||
|
codex)
|
||||||
|
src=$(pick "$HOME/.codex/sessions") || na ;;
|
||||||
|
copilot|antigravity|kiro)
|
||||||
|
na ;;
|
||||||
|
*)
|
||||||
|
echo "unknown cli: $cli" >&2
|
||||||
|
exit 2 ;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
[ -r "$src" ] || na
|
||||||
|
# input 要把快取的部分加回來:Claude 的 usage 只在 input_tokens 記未快取的那幾個 token,
|
||||||
|
# 真正的輸入量落在 cache_creation_input_tokens 與 cache_read_input_tokens。只加第一欄,
|
||||||
|
# 報表會出現輸入幾百、輸出幾十萬的假數字。
|
||||||
|
input=$(sum_field "$src" input_tokens)
|
||||||
|
cache_new=$(sum_field "$src" cache_creation_input_tokens)
|
||||||
|
cache_hit=$(sum_field "$src" cache_read_input_tokens)
|
||||||
|
output=$(sum_field "$src" output_tokens)
|
||||||
|
[ -n "$input" ] && [ -n "$output" ] || na
|
||||||
|
input=$((input + ${cache_new:-0} + ${cache_hit:-0}))
|
||||||
|
printf '%s\t%s\n' "$input" "$output"
|
||||||
Reference in New Issue
Block a user