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