助理算得出哪幾筆到期、哪幾筆逾期,但那些結果只寫在監控頁上——人要自己
去翻,或自己跑一次狀態查詢。這一支把它帶到前景。
session-reminder.sh 只讀助理那一輪寫好的提醒佇列,一個判定都不做。
自己拿 due 欄與 next_run 去跟現在比就是第二套到期判定,跟助理那一套遲早
對不上,而對不上的那一天兩邊都說自己是對的。它也要快:這一支跑在每一個
工作階段的開頭。
只印佇列換來一個新的失效模式,正面處理:助理停了,佇列就不再更新,而一份
舊佇列讀起來跟新的一模一樣。所以佇列檔頭帶那一輪的時間戳與 epoch,這裡
算出它多舊;超過心跳門檻或心跳不新鮮,就明說這批提醒是多久以前算的、
助理現在的心跳是什麼狀態。門檻與狀態都取 heartbeat.sh 印的那一行。
佇列空又過期的那一種分兩路:待辦簿有東西才說話,零筆就安靜——人自己按停
也算零筆那一種,對著一個刻意的決定每個工作階段催一次是噪音不是提醒。
助理狀態目錄根本不存在時整支安靜退出,那台機器從沒啟動過助理。
一個工作階段只提一次,記號是 sessions/{代號}.reminded。接不到 session id
的 CLI 全部共用 default,所以 session-timer.sh 的 restart 分支順手清掉那個
記號——不清的話那支 CLI 從第二個工作階段起再也收不到提醒。清除掛在那裡
不掛在這裡:「這是不是新的工作階段」的判準只有那一支知道。
接線與檢核一起改,不留一支沒人驗的 hook:hooks.json 與推導出來的
codex-hooks.json 各加一條、kiro 的 agentSpawn 加一條、claude 的 status
逐支列舉加一項、冒煙測試加一條並把預期條數從 17 改成 18、執行期錯誤掃描
的 jsc 判定加一支腳本名,還有散在文件與回報字串裡的「九支 hook」十處
全部改成十支。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
67 lines
4.1 KiB
Bash
Executable File
67 lines
4.1 KiB
Bash
Executable File
#!/usr/bin/env sh
|
||
# session-timer.sh — 記錄工作階段花費時間(供 jsc-log:worklog 取用)。
|
||
# 用法:
|
||
# session-timer.sh start # SessionStart:記錄起始時間(已有紀錄就不動)
|
||
# session-timer.sh restart # SessionStart:一律覆寫起始時間
|
||
# session-timer.sh mark # Stop/SessionEnd:更新最後活動時間
|
||
# session-timer.sh report [sid] # 印出 {sid} {seconds};無紀錄印 0
|
||
#
|
||
# 結束碼:0=一律成功,四個子命令都走到最後那一行 exit 0,不認得的子命令也一樣(case 沒有
|
||
# 相符分支就直接落到那一行)。這支接在 SessionStart 與 Stop/SessionEnd 上,本來就不擋人:
|
||
# 狀態檔寫不進去只是少一筆計時,report 讀不到起始時間就印 0,都照樣 exit 0。
|
||
# 唯一的非零來源是 lib.sh 載入失敗:本檔以 `. "$HERE/lib.sh"` 載入,沒有接 `|| true`,
|
||
# 檔案不在時 sh 會就地結束並回 2。這兩個事件不擋工具呼叫,回 2 只會在宿主留下一筆 hook 錯誤。
|
||
#
|
||
# start 與 restart 的差別在「同一個 session id 會不會重複開始」:
|
||
# start 給 Claude 這種每個工作階段都有自己 session id 的 CLI。續接同一階段時
|
||
# SessionStart 會再觸發一次,覆寫起始時間會讓花費時間歸零。
|
||
# restart 給接不到 session id 的 CLI(kiro)。那些 CLI 的紀錄共用 default,
|
||
# 不覆寫就會把上一個工作階段的起始時間算進來,花費時間虛胖。
|
||
#
|
||
# restart 另外清掉提醒記號($JSC_HOME/sessions/{代號}.reminded):那個記號讓提醒一個工作
|
||
# 階段只提一次,而共用 default 代號的 CLI 不清就等於只提第一次、往後永遠不提。
|
||
#
|
||
# 這兩個子命令另外兼一件事:判定為「新的工作階段」時清除部署後的重啟閘門
|
||
# (restart-gate.sh clear)。新工作階段代表 CLI 行程是新起的,新版技能組一定已經載入。
|
||
# 判準只有這裡知道——start 分支的「起始檔不存在」就是這個 session id 第一次開始,
|
||
# 所以清除掛在這裡,不在 restart-gate.sh 裡自己再判一次。
|
||
# 清除的範圍是「跑到這一支腳本的那個 CLI 自己那一份狀態檔」,由 restart-gate.sh clear 認定,
|
||
# 這裡不必也不能過問:這個工作階段開始的只有一支 CLI,別支沒重啟,閘門要留著。
|
||
HERE=$(dirname "$0"); . "$HERE/lib.sh"
|
||
hook_trace "session-timer ${1:-}"
|
||
read_stdin
|
||
sid=$(session_id)
|
||
|
||
# 放下這一支 CLI 的部署後重啟閘門。狀態檔的路徑、範圍與格式只留在 restart-gate.sh,
|
||
# 這裡不碰檔案,所以改成一支 CLI 一份狀態檔之後這裡不用跟著改。
|
||
# 一律 </dev/null:clear 不讀標準輸入,但這裡的標準輸入是宿主餵進來的管線,不關掉會卡住。
|
||
clear_restart_gate() {
|
||
sh "$HERE/restart-gate.sh" clear </dev/null 2>/dev/null || true
|
||
}
|
||
|
||
case "${1:-mark}" in
|
||
start)
|
||
f="$JSC_HOME/sessions/$sid.start"
|
||
if [ ! -f "$f" ]; then
|
||
now_epoch > "$f"
|
||
clear_restart_gate # 起始檔不存在=這個工作階段第一次開始,也就是行程新起的那一次
|
||
fi ;;
|
||
restart)
|
||
now_epoch > "$JSC_HOME/sessions/$sid.start"
|
||
rm -f "$JSC_HOME/sessions/$sid.end"
|
||
# 提醒記號一起清。那個記號讓提醒一個工作階段只提一次,而接不到 session id 的 CLI
|
||
# 全部共用 default 這一個代號——不清的話第一個工作階段提過之後,往後每一個工作階段
|
||
# 都會被當成「已經提過」,那支 CLI 從此再也收不到任何提醒。
|
||
# 清除掛在這裡不掛在提醒那一支:「這是不是新的工作階段」的判準只有這一支知道。
|
||
rm -f "$JSC_HOME/sessions/$sid.reminded"
|
||
clear_restart_gate ;; # 接不到 session id 的 CLI 每次工作階段開始都算新的,一律清
|
||
mark)
|
||
now_epoch > "$JSC_HOME/sessions/$sid.end" ;;
|
||
report)
|
||
rsid="${2:-$sid}"
|
||
s=$(cat "$JSC_HOME/sessions/$rsid.start" 2>/dev/null || echo "")
|
||
e=$(cat "$JSC_HOME/sessions/$rsid.end" 2>/dev/null || now_epoch)
|
||
if [ -n "$s" ]; then echo "$rsid $((e - s))"; else echo "$rsid 0"; fi ;;
|
||
esac
|
||
exit 0
|