feat(執行): 拿排程條目記下的 CLI 清單比對,少跑一支就點名

偵測 CLI 那一支純看 PATH,分不出「裝了但執行檔不在 PATH 上」。而條目帶的
PATH 是安裝當下拍的,其中某些 CLI 裝在會過期的目錄底下——這台機器實測就有
一支裝在帶行程編號的多殼層目錄,重開機之後那條路徑就不在了。

少了基準的後果不是報錯,是安靜地少做一支。那一輪照樣把偵測到的每一支都跑
過、照樣全部成功、照樣回報「都跑過了」,因為它不知道該有幾支。實測那一輪報
「對 4 支 CLI 都跑過,全部成功」,而機器上裝了 5 支——報告讀起來完全正常。

所以條目多記一個變數,記下安裝當下偵測到哪幾支,作為往後每一輪的參照基準。
判法照組 PATH 那一套逐支 command -v,不另叫外部腳本:install 那一刻本來就用
同一套判過一次,再叫一支等於同一件事兩套實作,而那一支拿得到的資訊跟這裡
一樣多,多繞一層沒有換到任何東西。

讀的那一邊比對之後印 cli_missing= 並點名少了哪一支,同時明說「全部成功不代表
全部跑過」。只報不修:那條路徑本質上是暫時的,真正的解法是那支 CLI 該裝在
穩定位置,或者重跑一次排程安裝重新拍快照——兩件都不是這一支該替人決定的。

舊條目沒有那個變數時安靜通過,不誤報:那一種情況分不出「沒少」與「沒基準」,
而拿「沒基準」當缺失會讓每一台還沒重裝的機器每輪亮一次紅。

實測三種情況:基準與實際一致時不出聲;基準多一支不存在的會點名那一支;完全
沒設基準時印減號、不警告。另外拿條目實際帶的那條 PATH 在清空環境裡重現真機
情境,確實抓到少了那一支。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-09-07 09:40:00 +08:00
co-authored by Claude Opus 5
parent 0df1605a20
commit 6cb071a3e7
2 changed files with 45 additions and 4 deletions
+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*)