- What:README 的工具表補進彙總腳本,並改寫 worklog 與 report 兩節; tools/token-usage.sh 的檔頭改寫成完整的結束碼宣告。 - Why:README 還停在舊流程,讀的人會以為報表數字仍由技能自己數,也不知道週五已經有腳本可用。 token-usage.sh 原本只寫「護欄回傳 2」,沒說來源讀不到時印 N/A 也算成功, 接手的人容易把那個情況當成故障,白追一輪。 - How:工具表加一列,寫出彙總腳本的輸出欄位與「無資料不估算」; worklog 一節寫出四項來源併行取得、週五由腳本算; report 一節寫出三線併行、彙總改走腳本,以及教訓頁另解自己的 wiki 存取庫。 相依清單補上 jsc-ask 一列,說明它負責問期間與任務狀態。 - Who:整個 log 技能組的說明文件。
80 lines
3.5 KiB
Bash
Executable File
80 lines
3.5 KiB
Bash
Executable File
#!/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。
|
||
#
|
||
# 結束碼: 0=成功(含來源讀不到而印 N/A 的情況,那是「這個 CLI 沒有可讀數字」,不是故障)
|
||
# 2=用法錯誤(沒給 cli,或 cli 名稱不在 claude|codex|copilot|antigravity|kiro 之內)
|
||
#
|
||
# 各 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"
|