Files
ISEP/scripts/test-isep-doctor.sh
T
Leo fbc56b9e59 isep-doctor 判準改成「每一個 Claude Code 自己回報有沒有載入」,不再看設定長相(inkstone/ISEP#150 → c6995)
同一台 Mac 有 CLI 與 Desktop 內建兩個 Claude Code,讀同一份 ~/.claude 卻不一定同結論:
settings 多了 path 時 Desktop 2.1.266 忽略 inkstone marketplace、CLI 2.1.220 照常載入(c6991)。
第一版看到 path 就對整台判 ,在 CLI 上是假陽性。

- 逐一找 CLI(PATH)與 Desktop(最新版本,數字排序),各跑 plugin list --json,依 errors 各判各的
- 設定比對只在某一個真的報錯時當解釋+修法,永遠不單獨判 
- 查不了 ⇒ ◐、離開碼 2,不講成 
- test-isep-doctor.sh 離線 11 條(假 claude 可執行檔);舊版跑這份 pass=1 fail=10
- test-isep-doctor-live.sh 實機 3 條:真的 CLI 2.1.220/Desktop 2.1.266,隔離 HOME 重現有/無 path,不動 ~/.claude
- 盤點表與 plugin.json 描述的腳本數 62→65(這棵樹上實數)

版本號待總管定。

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-09-13 16:23:40 +08:00

96 lines
5.6 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 bash
# 迴歸測試:scripts/isep-doctorinkstone/ISEP#150)——全離線
# 用假的 claude 可執行檔(shell 腳本)代替真的 CLIDesktop,走的是 doctor 真正的 subprocess 那條路。
# 真的 Claude Code 版本的實測在 scripts/test-isep-doctor-live.sh。
set -u
HERE="$(cd "$(dirname "$0")" && pwd)"
T=$(mktemp -d); trap 'rm -rf "$T"' EXIT
pass=0; fail=0
URL=https://git.uncle6.me/inkstone/ISEP.git
mkfake() { # 路徑 版本 plugin-list 輸出(原樣印出)
mkdir -p "$(dirname "$1")"
printf '%s' "$3" > "$1.out"
cat > "$1" <<EOF
#!/bin/sh
if [ "\$1" = "--version" ]; then echo "$2 (Claude Code)"; exit 0; fi
cat "$1.out"
EOF
chmod +x "$1"
}
run() { OUT=$(ISEP_DOCTOR_CLAUDE_HOME="$T/home" python3 "$HERE/isep-doctor" 2>&1); CODE=$?; }
ok() { pass=$((pass+1)); echo "ok $1"; }
bad() { fail=$((fail+1)); echo "FAIL $1 (exit=$CODE)"; printf '%s\n' "$OUT" | sed 's/^/ /'; }
expect() { # 名稱 離開碼 要有的樣式(| 分隔,可空) 不准有的樣式(可空)
local p miss=""
[ "$CODE" = "$2" ] || miss="exit"
local IFS='|'
for p in $3; do printf '%s' "$OUT" | grep -q -- "$p" || miss="$miss 缺[$p]"; done
if [ -n "${4:-}" ] && printf '%s' "$OUT" | grep -q -- "$4"; then miss="$miss 多了[$4]"; fi
[ -z "$miss" ] && ok "$1" || { bad "$1$miss"; }
}
mkdir -p "$T/home/plugins"
echo "{\"inkstone\":{\"source\":{\"source\":\"git\",\"url\":\"$URL\"}}}" > "$T/home/plugins/known_marketplaces.json"
SET_PATH="{\"extraKnownMarketplaces\":{\"inkstone\":{\"source\":{\"source\":\"git\",\"url\":\"$URL\",\"path\":\"/Users/x/ISEP\"}}},\"model\":\"keep\"}"
SET_CLEAN="{\"extraKnownMarketplaces\":{\"inkstone\":{\"source\":{\"source\":\"git\",\"url\":\"$URL\"}}}}"
LOADED='[{"id":"isep@inkstone","version":"0.30.1","enabled":true}]'
NOTFOUND='[{"id":"isep@inkstone","version":"0.30.1","enabled":true,"errors":["Marketplace inkstone not found"]}]'
# ① 假陽性(c6991):設定有 path,但這個 Claude Code 自己回報載入正常 → ✅、不准點名 path
echo "$SET_PATH" > "$T/home/settings.json"
mkfake "$T/b/cli" 2.1.220 "$LOADED"
export ISEP_DOCTOR_CLAUDE_BINS="CLI=$T/b/cli"; run
expect "① 有 path 但實際載入(2.1.220 形狀)→ ✅ 不點名 path" 0 "✅ CLI 2.1.220" "path"
# ② 真陽性(c6990):同一份設定,CLI 載得進、Desktop 載不進 → 1;兩邊各講各的;點名 path;給修法
mkfake "$T/b/desk" 2.1.266 "$NOTFOUND"
export ISEP_DOCTOR_CLAUDE_BINS="CLI=$T/b/cli:Desktop=$T/b/desk"; run
expect "② CLI 載得進、Desktop 載不進 → 1,逐一講、點名 path" 1 "✅ CLI 2.1.220|❌ Desktop 2.1.266|Marketplace inkstone not found|多了 path|^ python3 "
printf '%s' "$OUT" | grep -q "CLI 與 Desktop 都一樣" && bad "② 不准再說 CLI 與 Desktop 都一樣" || ok "② 沒有把整台機器講成同一個結論"
# ③ 真陰性:拿掉 path,兩邊都載入 → 0
echo "$SET_CLEAN" > "$T/home/settings.json"
mkfake "$T/b/desk" 2.1.266 "$LOADED"; run
expect "③ 沒有 path、兩邊都載入 → 0" 0 "✅ CLI 2.1.220|✅ Desktop 2.1.266" "❌"
# ④ 別的原因失敗(設定沒有多餘欄位)→ 1,照實轉述,不編原因、不給 path 修法
mkfake "$T/b/desk" 2.1.266 '[{"id":"isep@inkstone","version":"0.30.1","enabled":true,"errors":["Plugin directory missing"]}]'; run
expect "④ 其他錯誤照實轉述、不編原因" 1 "❌ Desktop|Plugin directory missing" "修法(一行"
# ⑤ 沒安裝 → 1
mkfake "$T/b/desk" 2.1.266 '[]'; run
expect "⑤ 沒安裝 → 1" 1 "❌ Desktop 2.1.266isep@inkstone 沒有安裝"
# ⑥ 查不了(輸出不是 JSON)+另一個正常 → 2,◐,不准講成 ❌ 或 ✅
mkfake "$T/b/desk" 2.1.266 'Error: something broke'; run
expect "⑥ 一個查不了、一個正常 → 2" 2 "◐ Desktop|讀不到不等於沒載入|✅ CLI" "❌"
# ⑦ 一個 Claude Code 都找不到 → 2
export ISEP_DOCTOR_CLAUDE_BINS=""; run
expect "⑦ 找不到任何 Claude Code → 2" 2 "◐ 查不了"
# ⑧ 修法那一行真的修得好(在假 HOME 上原封不動執行印給 leo 的那一行)
echo "$SET_PATH" > "$T/home/settings.json"
mkfake "$T/b/desk" 2.1.266 "$NOTFOUND"
export ISEP_DOCTOR_CLAUDE_BINS="Desktop=$T/b/desk"; run
fixline=$(printf '%s\n' "$OUT" | grep '^ python3 ' | sed 's/^ //')
mkdir -p "$T/fake/.claude" && cp "$T/home/settings.json" "$T/fake/.claude/settings.json"
HOME="$T/fake" bash -c "$fixline"
if [ -n "$fixline" ] && python3 -c "import json,sys;d=json.load(open('$T/fake/.claude/settings.json'));s=d['extraKnownMarketplaces']['inkstone']['source'];sys.exit(0 if 'path' not in s and d['model']=='keep' and s['url'].endswith('ISEP.git') else 1)"; then
ok "⑧ 修法一行拿掉 path、其他設定不動"
else fail=$((fail+1)); echo "FAIL ⑧ 修法一行"; cat "$T/fake/.claude/settings.json"; fi
# ⑧b 修完再問一次(Desktop 改回報正常)→ 0:出路走得通
cp "$T/fake/.claude/settings.json" "$T/home/settings.json"; mkfake "$T/b/desk" 2.1.266 "$LOADED"; run
expect "⑧b 照修法修完再跑 → ✅" 0 "✅ Desktop" "多了 path"
# ⑨ 自動尋找:Desktop 取數字上最新的那一份(2.1.99 < 2.1.266,字串排序會選錯)
unset ISEP_DOCTOR_CLAUDE_BINS
D="$T/h9/Library/Application Support/Claude/claude-code"
mkfake "$D/2.1.99/claude.app/Contents/MacOS/claude" 2.1.99 "$NOTFOUND"
mkfake "$D/2.1.266/claude.app/Contents/MacOS/claude" 2.1.266 "$LOADED"
OUT=$(HOME="$T/h9" PATH="/usr/bin:/bin" ISEP_DOCTOR_CLAUDE_HOME="$T/home" /usr/bin/env python3 "$HERE/isep-doctor" 2>&1); CODE=$?
expect "⑨ Desktop 取最新版本(數字排序)" 0 "✅ Desktop 2.1.266" "2.1.99"
echo "pass=$pass fail=$fail"; [ "$fail" = 0 ]