Files
hooks/tools/scan-logs.sh
T
jiantw83 04225a7a2d docs(hooks): 每支腳本檔頭補上結束碼宣告,文件對齊九支 hook 的現況
共用函式庫與各支腳本的檔頭各補一段結束碼宣告,逐個子命令寫明哪些情況放行、
哪些情況擋下。說明文件改寫成九支 hook 的現況,補上寫入與提交閘門、唯讀模式、
建議子命令與新的環境變數。異常目錄範本補上「一律附加、不整頁覆蓋」的寫入語意。

呼叫端要靠結束碼決定下一步,但多數腳本只寫用法、沒寫結束碼,
讀的人得自己翻程式碼推,推錯就把安靜降級當成失敗處理。
共用函式庫載不到時,殼層會就地結束並回非零,接在工具呼叫前的閘門遇到這一下
等於無聲擋人,腳本自己的放行路徑一條都跑不到,這件事非寫進每一支檔頭不可。
文件停在八支 hook 的舊敘述,看的人會誤判覆蓋範圍,以為每支 CLI 都擋得住。
目錄頁的寫入語意只寫在腳本裡,換一支工具來寫就會整頁覆蓋。

一支腳本一段檔頭,逐子命令列出結束碼,並各自註明共用函式庫載入失敗會回哪一個碼。
文件的行數一律引用腳本自己印出來的那一行,不另抄一份數字,
判定路徑增減時就不會漂移。覆蓋範圍逐支 CLI 分開寫,接不上的就寫接不上。
2026-08-31 11:17:28 +08:00

97 lines
4.2 KiB
Bash
Executable File
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#!/usr/bin/env sh
# scan-logs.sh — 離線回填:解析各 CLI 的原生日誌,把可辨識的技能使用與工作階段界線
# 補進 $JSC_HOME/usage/skills.jsonl(與 skill-usage.sh 同一種紀錄格式)與 $JSC_HOME/sessions/。
# 用法: scan-logs.sh --cli {name} [--session {sid}]
# 支援: copilot(~/.config/copilot/)、antigravity(全域日誌目錄)、codex(~/.codex/sessions/、~/.codex/log/)。
# 去重: 以 $JSC_HOME/usage/scan-state/ 記住每個日誌檔已掃描的位元組數,重掃只讀新增段落。
# 結束碼: 0=回填完成,或找不到該 CLI 的日誌目錄、尚未支援該 CLI(兩種都只印一行說明就結束,
# 回填不到資料不算失敗)
# 2=用法錯誤(沒給 --cli)
# 註: 本檔以 `. "$HERE/../hooks/lib.sh"` 載入共用函式,沒有接 `|| true`。lib.sh 讀不到時
# sh 會就地結束並回 2,跟用法錯誤同碼;分不出是哪一種時,先確認 hooks/lib.sh 在不在。
HERE=$(cd "$(dirname "$0")" && pwd); . "$HERE/../hooks/lib.sh"
cli=""; sid=""
while [ $# -gt 0 ]; do
case "$1" in
--cli) cli="${2:-}"; shift; shift ;;
--session) sid="${2:-}"; shift; shift ;;
*) shift ;;
esac
done
if [ -z "$cli" ]; then
echo "用法:scan-logs.sh --cli {name} [--session {sid}]" >&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