From bb91cc2832c96956251a1a8294d6fc4487de9383 Mon Sep 17 00:00:00 2001 From: Jeffery Date: Mon, 24 Aug 2026 11:36:24 +0800 Subject: [PATCH] =?UTF-8?q?feat(wrapper):=20=E6=96=B0=E5=A2=9E=E7=84=A1=20?= =?UTF-8?q?Hook=20CLI=20=E7=9A=84=E5=8C=85=E8=A3=9D=E5=95=9F=E5=8B=95?= =?UTF-8?q?=E5=99=A8=E8=88=87=E6=97=A5=E8=AA=8C=E5=9B=9E=E5=A1=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit What:新增 tools/jsc-wrap.sh 包裝啟動器與 tools/scan-logs.sh 離線日誌回填腳本。 Why:copilot、antigravity 沒有 hook 系統,計時與技能用量原本完全缺漏,需要 hook 之外的落地方案。 How:jsc-wrap.sh 匯出 JSC_CLI 與 JSC_SESSION_ID,啟動前後各呼叫一次 session-timer.sh,結束時自動執行 scan-logs.sh 並原樣傳遞子行程退出碼;scan-logs.sh 解析 copilot、antigravity、codex 的原生日誌,把技能用量與階段界線補進 $JSC_HOME,重掃不產生重複記錄。 Who:無 hook 系統的 CLI(copilot、antigravity)與僅有 notify 的 codex,資料供 jsc-log:worklog 與 jsc-log:stats 使用。 Co-Authored-By: Claude Fable 5 --- tools/jsc-wrap.sh | 24 ++++++++++++ tools/scan-logs.sh | 91 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 115 insertions(+) create mode 100755 tools/jsc-wrap.sh create mode 100755 tools/scan-logs.sh diff --git a/tools/jsc-wrap.sh b/tools/jsc-wrap.sh new file mode 100755 index 0000000..88bcf6b --- /dev/null +++ b/tools/jsc-wrap.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env sh +# jsc-wrap.sh — 無 hook 系統 CLI 的包裝啟動器(例:copilot、antigravity)。 +# 用法: jsc-wrap.sh {cli} [args...] +# 行為: 匯出 JSC_CLI 與 JSC_SESSION_ID → session-timer start → 執行 CLI → +# 結束後 session-timer mark 並以 scan-logs.sh 回填用量,最後回傳 CLI 的結束碼。 +HERE=$(cd "$(dirname "$0")" && pwd) +HOOKS="$HERE/../hooks" +cli="${1:-}" +if [ -z "$cli" ]; then + echo "用法:jsc-wrap.sh {cli} [args...]" >&2 + exit 2 +fi +shift +JSC_CLI="$cli" +# 未提供 session id 就自動產生({cli}-時間戳-PID),讓計時與用量共用同一個 session +[ -n "${JSC_SESSION_ID:-}" ] || JSC_SESSION_ID="$cli-$(date +%Y%m%d%H%M%S)-$$" +export JSC_CLI JSC_SESSION_ID +sh "$HOOKS/session-timer.sh" start &2 + exit 2 +fi + +STATE="$JSC_HOME/usage/scan-state" +mkdir -p "$STATE" 2>/dev/null || true + +# 檔案修改時間(epoch),取不到就用現在 +mtime_epoch() { + stat -c %Y "$1" 2>/dev/null || date -r "$1" +%s 2>/dev/null || now_epoch +} + +# 回填工作階段界線:start 只補缺,end 取較新值(不覆蓋較新的即時紀錄) +record_session() { # $1=sid $2=epoch + [ -f "$JSC_HOME/sessions/$1.start" ] || echo "$2" > "$JSC_HOME/sessions/$1.start" + old=$(cat "$JSC_HOME/sessions/$1.end" 2>/dev/null || echo 0) + if [ "$2" -gt "$old" ] 2>/dev/null; then echo "$2" > "$JSC_HOME/sessions/$1.end"; fi +} + +# 印出日誌檔自上次掃描後的新增內容,並更新位移(位移即去重機制) +new_content() { # $1=file + key=$(printf '%s' "$1" | cksum | tr ' \t' '--') + off_f="$STATE/$cli-$key.offset" + off=$(cat "$off_f" 2>/dev/null || echo 0) + size=$(wc -c < "$1" 2>/dev/null || echo 0) + [ "$size" -gt "$off" ] 2>/dev/null || return 0 + tail -c +"$((off + 1))" "$1" 2>/dev/null + echo "$size" > "$off_f" +} + +# 從新增內容萃取 jsc 技能代號,逐筆追加(同一批先去重;格式與 skill-usage.sh 完全相同) +append_skills() { # stdin=內容 $1=sid + grep -oE 'jsc-[a-z]+:[a-z0-9][a-z0-9-]*' 2>/dev/null | sort -u | while IFS= read -r sk; do + printf '{"ts":"%s","cli":"%s","session":"%s","skill":"%s"}\n' \ + "$(now_iso)" "$cli" "$1" "$sk" >> "$JSC_HOME/usage/skills.jsonl" + done +} + +# 掃描一個日誌目錄;$2=預設 sid(空字串時用檔名當 sid);$3=sessions 時回填階段界線 +scan_dir() { + find "$1" -maxdepth 3 -type f \( -name '*.json' -o -name '*.jsonl' -o -name '*.log' \) 2>/dev/null \ + | while IFS= read -r f; do + s="$2" + [ -n "$s" ] || s="$cli-$(basename "$f" | sed 's/\.[^.]*$//')" + [ "${3:-}" = "sessions" ] && record_session "$s" "$(mtime_epoch "$f")" + new_content "$f" | append_skills "$s" + done + return 0 +} + +case "$cli" in + copilot) + d="$HOME/.config/copilot" + if [ ! -d "$d" ]; then echo "[jsc] 找不到 copilot 日誌目錄($d),略過回填。"; exit 0; fi + [ -d "$d/history-session-state" ] && scan_dir "$d/history-session-state" "$sid" sessions + [ -d "$d/history" ] && scan_dir "$d/history" "$sid" sessions + [ -d "$d/logs" ] && scan_dir "$d/logs" "$sid" logs ;; + antigravity) + found="" + for d in "$HOME/.antigravity/logs" "$HOME/.config/antigravity/logs" "$HOME/.antigravity"; do + if [ -d "$d" ]; then found=1; scan_dir "$d" "$sid" sessions; break; fi + done + if [ -z "$found" ]; then echo "[jsc] 找不到 antigravity 日誌目錄,略過回填。"; exit 0; fi ;; + codex) + d1="$HOME/.codex/sessions"; d2="$HOME/.codex/log" + if [ ! -d "$d1" ] && [ ! -d "$d2" ]; then + echo "[jsc] 找不到 codex 日誌目錄($d1、$d2),略過回填。"; exit 0 + fi + [ -d "$d1" ] && scan_dir "$d1" "$sid" sessions + [ -d "$d2" ] && scan_dir "$d2" "$sid" logs ;; + *) + echo "[jsc] 尚未支援 $cli 的日誌回填,略過。" ;; +esac +exit 0