c2638668e3
leo 2026-08-20:「同一個 plugin 你用,薄殼也用,保證兩邊同步」
「我要你幫雲端做薄殼,永遠都有問題,你要做的就是這組設定
你自己可以 dogfooding」
搬進來:41 支 hook(51 條註冊)/7 支 command/2 支 skill/23 支腳本。
不搬 .env、wiki、docs——那些是知識不是環境。
51 條 hook 路徑全部從 $CLAUDE_PROJECT_DIR/.claude/hooks/ 改成 ${CLAUDE_PLUGIN_ROOT}/hooks/,
零漏網。那正是薄殼一直壞掉的根:雲端 cwd 不是真身,寫死路徑就斷。
尚未驗證:Claude Code 能不能從私有 Gitea repo 裝 marketplace(要憑證)。
下一步就是在本機實際裝一次,通了才動雲端 bootstrap.sh。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
71 lines
3.8 KiB
Bash
Executable File
71 lines
3.8 KiB
Bash
Executable File
#!/bin/bash
|
||
# check-bundle-drift.sh — 驗「Arcrun 原始碼 vs bundles 鏡像」有沒有漂移(2026-07-28 立)
|
||
#
|
||
# 解的病(install-flow-map.md §3.8 的誠實缺口):Arcrun main 改了 cypher/portal
|
||
# 但忘記重打包 bundle → 新裝用戶拿到舊引擎(07-27 同事 demo 前夕連線全斷的根因)。
|
||
# 之前只靠流程紀律,本腳本把它變機械可查。
|
||
#
|
||
# 用法:scripts/check-bundle-drift.sh <Arcrun repo 路徑> <bundles clone 路徑>
|
||
# 例: scripts/check-bundle-drift.sh /private/tmp/wt-arcrun <scratchpad>/bundles-push2
|
||
# 出口碼:0=無漂移;1=有漂移(列出哪個件);2=用法/環境錯
|
||
set -euo pipefail
|
||
cd "$(dirname "$0")/.."
|
||
ARCRUN="${1:?用法:$0 <Arcrun路徑> <bundles clone路徑>}"
|
||
BUNDLES="${2:?缺 bundles clone 路徑}"
|
||
[ -d "$ARCRUN/console-ui" ] || { echo "❌ $ARCRUN 不像 Arcrun repo"; exit 2; }
|
||
[ -f "$BUNDLES/manifest.json" ] || { echo "❌ $BUNDLES 沒有 manifest.json"; exit 2; }
|
||
DRIFT=0
|
||
|
||
echo "① UI(console-ui/public → tier2/ui)"
|
||
node products/arcrun-rag/installer/scripts/build-ui-bundle.mjs \
|
||
--arcrun "$ARCRUN" --out /tmp/drift-ui.js >/dev/null
|
||
A=$(shasum -a 256 /tmp/drift-ui.js | cut -d' ' -f1)
|
||
B=$(shasum -a 256 "$BUNDLES/tier2/ui/index.js" | cut -d' ' -f1)
|
||
if [ "$A" = "$B" ]; then echo " ✅ 一致($(echo $A | cut -c1-12))"
|
||
else echo " 🔴 漂移:原始碼 $(echo $A | cut -c1-12) ≠ 鏡像 $(echo $B | cut -c1-12) → 重跑 build-ui-bundle.mjs 推鏡像"; DRIFT=1; fi
|
||
|
||
echo "② cypher(cypher-executor → tier2/cypher)"
|
||
( cd "$ARCRUN/cypher-executor" && npx wrangler deploy --dry-run --outdir /tmp/drift-cypher >/dev/null 2>&1 ) \
|
||
|| { echo " ⚠️ cypher dry-run 失敗(依賴沒裝?)"; DRIFT=1; }
|
||
if [ -f /tmp/drift-cypher/index.js ]; then
|
||
A=$(shasum -a 256 /tmp/drift-cypher/index.js | cut -d' ' -f1)
|
||
B=$(shasum -a 256 "$BUNDLES/tier2/cypher/index.js" | cut -d' ' -f1)
|
||
if [ "$A" = "$B" ]; then echo " ✅ 一致($(echo $A | cut -c1-12))"
|
||
else echo " 🔴 漂移:原始碼 $(echo $A | cut -c1-12) ≠ 鏡像 $(echo $B | cut -c1-12) → 重建 cypher 推鏡像"; DRIFT=1; fi
|
||
fi
|
||
|
||
echo "②b 其餘 tier2(kbdb/registry/mcp——07-28 真實案例:kbdb bundle 缺 /entries/libraries=庫目錄靜默失效)"
|
||
for t2 in kbdb registry mcp; do
|
||
( cd "$ARCRUN/$t2" && npx wrangler deploy --dry-run --outdir /tmp/drift-$t2 >/dev/null 2>&1 ) || { echo " ⚠️ $t2 dry-run 失敗"; DRIFT=1; continue; }
|
||
A=$(shasum -a 256 /tmp/drift-$t2/index.js | cut -d' ' -f1)
|
||
B=$(shasum -a 256 "$BUNDLES/tier2/$t2/index.js" | cut -d' ' -f1)
|
||
if [ "$A" = "$B" ]; then echo " ✅ $t2 一致($(echo $A | cut -c1-12))"
|
||
else echo " 🔴 $t2 漂移:原始碼 $(echo $A | cut -c1-12) ≠ 鏡像 $(echo $B | cut -c1-12)"; DRIFT=1; fi
|
||
done
|
||
|
||
echo "③ daemon(collector 產物 vs 鏡像 zip)"
|
||
for z in ArcrunRAG-mac-unsigned.zip; do
|
||
L="products/arcrun-rag/collector/cmd/arcrun-tray/$z"
|
||
[ -f "$L" ] && [ -f "$BUNDLES/daemon/$z" ] || continue
|
||
A=$(shasum -a 256 "$L" | cut -d' ' -f1); B=$(shasum -a 256 "$BUNDLES/daemon/$z" | cut -d' ' -f1)
|
||
if [ "$A" = "$B" ]; then echo " ✅ $z 一致"
|
||
else echo " 🔴 $z 漂移(本地重建過沒推?)"; DRIFT=1; fi
|
||
done
|
||
|
||
echo "④ manifest 內 sha vs 檔案實體"
|
||
python3 - "$BUNDLES" <<'PY'
|
||
import json,sys,hashlib,os
|
||
b=sys.argv[1]; m=json.load(open(os.path.join(b,'manifest.json'))); bad=0
|
||
for c in m['core']:
|
||
p=os.path.join(b,c['main_file'])
|
||
real=hashlib.sha256(open(p,'rb').read()).hexdigest()
|
||
if real!=c['sha256']:
|
||
print(f" 🔴 {c['name']}: manifest sha ≠ 檔案實體"); bad=1
|
||
print(" ✅ 27 件 manifest sha 全對" if not bad else "", end="\n" if not bad else "")
|
||
sys.exit(bad)
|
||
PY
|
||
[ $? -ne 0 ] && DRIFT=1
|
||
|
||
[ $DRIFT -eq 0 ] && echo "✅ 無漂移" || echo "🔴 有漂移——照上面指示重建後推鏡像(arm)+釘 commit+部署安裝器"
|
||
exit $DRIFT
|