拿排程條目記下的 CLI 清單比對,少跑一支就點名 #38

Merged
admin merged 2 commits from feat/report-cli-gap-against-entry-snapshot into develop 2026-09-07 01:46:32 +00:00
2 changed files with 45 additions and 4 deletions
Showing only changes of commit 6cb071a3e7 - Show all commits
+20 -2
View File
@@ -169,6 +169,23 @@ if _det=$(find_tool cli tools/detect-clis.sh); then
fi
N_CLI=$(awk 'END{print NR+0}' "$CLIS")
# 跟排程條目安裝當下記下的那一份比對。少了哪一支要點名,不是只印個數字。
#
# 為什麼要比:偵測那一支純看 PATH,分不出「裝了但執行檔不在 PATH 上」。而條目帶的 PATH 是
# 安裝當下拍的,其中某些 CLI 裝在會過期的目錄底下——實測有一支裝在帶行程編號的多殼層目錄,
# 重開機之後那條路徑就不在了。
# 沒有基準的後果不是報錯,是安靜地少做一支:這一輪照樣把偵測到的每一支都跑過、照樣全部
# 成功、照樣回報「都跑過了」。實測那一輪報「對 4 支 CLI 都跑過,全部成功」,而機器上裝了
# 5 支——報告讀起來完全正常。
# 只報不修:那條路徑本質上是暫時的,真正的解法是那支 CLI 該裝在穩定位置,或者重跑一次
# 排程安裝重新拍一份快照。兩件都不是這一支該替人決定的。
CLI_MISSING=''
if [ -n "${JSC_ASSIST_CLIS:-}" ]; then
for _want in $JSC_ASSIST_CLIS; do
grep -qxF "$_want" "$CLIS" 2>/dev/null || CLI_MISSING="${CLI_MISSING:+$CLI_MISSING、}$_want"
done
fi
# {repo} 的代入來源還沒做出來。這裡不猜一個掃描規則頂替:猜錯就是在整台機器上跑指令,
# 而那一輪沒有人看得到它跑到哪裡去了。
REPO_READY=0
@@ -345,10 +362,11 @@ while IFS="$TAB" read -r c_id c_verdict c_state c_kind c_action c_trigger c_recu
fi
done <"$ROWS"
printf 'mode=%s rows=%s root=%s due=%s ran=%s ok=%s failed=%s held=%s skipped=%s write_failed=%s clis=%s\n' \
printf 'mode=%s rows=%s root=%s due=%s ran=%s ok=%s failed=%s held=%s skipped=%s write_failed=%s clis=%s cli_missing=%s\n' \
"$([ "$DRYRUN" -eq 1 ] && echo plan || echo run)" "$ROWS" "${ROOT:--}" \
"$N_DUE" "$N_RUN" "$N_OK" "$N_FAIL" "$N_HELD" "$N_SKIP" "$N_WRITE_BAD" "$N_CLI"
"$N_DUE" "$N_RUN" "$N_OK" "$N_FAIL" "$N_HELD" "$N_SKIP" "$N_WRITE_BAD" "$N_CLI" "${CLI_MISSING:--}"
[ -n "$CLI_MISSING" ] && warn "排程條目記著這台機器有 $JSC_ASSIST_CLIS,但這一輪只偵測到 $N_CLI 支,少了:$CLI_MISSING。帶 {cli} 代入點的那幾筆這一輪少跑了那幾支,而且**全部成功也不代表全部跑過**。成因通常是那支 CLI 裝在會過期的目錄底下(例如帶行程編號的多殼層目錄),條目帶的 PATH 是安裝當下拍的,那條路徑現在不在了。重跑一次 schedule.sh install patrol 會重新拍一份快照;那支 CLI 反覆消失就要考慮把它裝到穩定位置。"
[ "$N_HELD" -gt 0 ] && note "有 $N_HELD 筆代不出目標或指令形狀不對,這一輪跳過,逐筆印在上面的 held= 那幾行。**那幾筆的執行紀錄與失敗次數一個字都沒動**——代不出目標不是那一筆做錯了什麼,記成失敗會讓一個沒有人修得動的計數一路往上爬。"
[ "$N_SKIP" -gt 0 ] && note "有 $N_SKIP 筆這一批不跑:動作是只提醒的、動作是技能名的、還有不是內建項的,逐筆印在上面的 skip= 那幾行。"
[ "$RC_WRITE" -ne 0 ] && warn "有 $N_WRITE_BAD 筆的回寫失敗。指令跑過了,但待辦簿沒記到,下一輪會再跑一次同一筆,逐筆印在上面的 write_failed= 那幾行,各自帶了 tasks.sh 的結束碼。"
+25 -2
View File
@@ -381,6 +381,29 @@ cli_path() {
printf '%s' "${_dirs:+$_dirs:}/usr/bin:/bin"
}
# 條目要記下安裝當下偵測到哪幾支 CLI,作為往後每一輪的參照基準。
#
# 為什麼需要這個基準:偵測那一支純看 PATH,分不出「裝了但執行檔不在 PATH 上」。而條目帶的
# PATH 是安裝當下拍的,其中某些 CLI 裝在會過期的目錄底下——這台機器實測就有一支裝在帶行程
# 編號的多殼層目錄,重開機之後那條路徑就不在了。
# 少了基準的後果不是報錯,是安靜地少做一支:那一輪照樣把偵測到的每一支都跑過、照樣全部
# 成功、照樣回報「都跑過了」,因為它不知道該有幾支。實測那一輪報「對 4 支 CLI 都跑過,
# 全部成功」,而機器上裝了 5 支。
# 記下來之後,讀的那一邊才有東西可比,也才答得出「該不該重跑一次 install」。
# 判法照 cli_path() 那一套:逐支用 command -v 試,不叫外部腳本。兩個理由——這一支在 install
# 那一刻本來就已經用同一套判過一次(為了組 PATH),再叫一支等於同一件事兩套實作;而且那一支
# 只看 PATH,跟這裡拿得到的資訊一樣多,多繞一層沒有換到任何東西。
cli_codes() {
_codes=''
for _pair in claude:claude codex:codex copilot:copilot antigravity:agy kiro:kiro-cli; do
_code=${_pair%%:*}; _bin=${_pair#*:}
_abs=$(command -v "$_bin" 2>/dev/null) || continue
case "$_abs" in /*) ;; *) continue ;; esac
_codes="${_codes:+$_codes }$_code"
done
printf '%s' "$_codes"
}
# 條目的指令前綴:固定三個旗標,加上這一刻的環境快照。沒設定的變數直接跳過,不寫空值——
# 寫 NAME='' 進去,讀的人分不出是「刻意設成空」還是「安裝時忘了設」。
# JSC_GITEA_CONFIRM=yes 是必要的:寫入確認只認 tty,排程那一輪沒有 tty,不帶這個旗標監控頁
@@ -392,7 +415,7 @@ cli_path() {
# 中止的唯一證據」。不設這個變數,兩半就都落在 CLI 自己給的代號上。
# 2026-09-04 實測:一台機器累積了 91 筆假中止,其中 90 筆是同一支被每輪叫用的技能。
env_prefix() { # 順便把快照到的變數名稱寫進 $1,供輸出列出名稱(只有名稱,不含值)
_p="PATH=$(shq "$(cli_path)") JSC_CLI=cron JSC_GITEA_CONFIRM=yes"
_p="PATH=$(shq "$(cli_path)") JSC_ASSIST_CLIS=$(shq "$(cli_codes)") JSC_CLI=cron JSC_GITEA_CONFIRM=yes"
_names=''
for _n in $(snapshot_names); do
eval "_v=\${$_n:-}"
@@ -494,7 +517,7 @@ trap 'rm -rf "$TMPD"' EXIT
# 巡檢指令與環境快照在這裡就解出來。放進 cron_entry 再解的話,那支是在命令替換的子行程裡
# 跑,判不出 CLI 時 die 只結束子行程,主流程會帶著空指令繼續往下裝。
PATROL_RESOLVED=''
ENV_PREFIX="PATH=$(shq "$(cli_path)") JSC_CLI=cron JSC_GITEA_CONFIRM=yes"
ENV_PREFIX="PATH=$(shq "$(cli_path)") JSC_ASSIST_CLIS=$(shq "$(cli_codes)") JSC_CLI=cron JSC_GITEA_CONFIRM=yes"
SNAPSHOT_NAMES=''
case "$CMD:$JOBS" in
install:*patrol*)