ISEP 0.1.0:環境設定收成一個 plugin,本機與雲端共用一份
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>
This commit is contained in:
Executable
+96
@@ -0,0 +1,96 @@
|
||||
#!/bin/bash
|
||||
# github-arm.sh — 解除 GitHub 接觸保險(D20 發射鈕,leo 親手跑,AI 不得代跑)
|
||||
# 用法:scripts/github-arm.sh "任務描述" [有效分鐘,預設30,上限60]
|
||||
set -euo pipefail
|
||||
|
||||
if [ ! -t 0 ]; then
|
||||
echo "❌ 本腳本必須由人類在終端機互動執行(防 AI 代按發射鈕)。" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
MISSION="${1:-}"
|
||||
MINUTES="${2:-30}"
|
||||
if [ -z "$MISSION" ]; then
|
||||
echo "用法:scripts/github-arm.sh \"任務描述\" [分鐘]" >&2
|
||||
exit 1
|
||||
fi
|
||||
# 第二參數必須是純數字分鐘。2026-08-01 leo 實撞:AI 給的指令把中文註解寫在同一行,
|
||||
# 被當成分鐘數 → 下方 $(( )) 算術炸掉 → EXPIRY unbound、保險沒解成卻看似執行過。
|
||||
case "$MINUTES" in
|
||||
''|*[!0-9]*)
|
||||
echo "❌ 第二個參數要純數字分鐘(收到:$MINUTES)" >&2
|
||||
echo " 正確:scripts/github-arm.sh \"任務描述\" 30" >&2
|
||||
exit 1;;
|
||||
esac
|
||||
if [ "$MINUTES" -gt 60 ]; then MINUTES=60; fi
|
||||
if [ "$MINUTES" -lt 1 ]; then MINUTES=1; fi
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
# ── 搬遷預覽(arcrun-rag#27,leo:「解保險前要看得到這次會搬什麼」)──────────
|
||||
# 純讀本機已存在的檔案(ship.targets.json + stage/prod 兩份 manifest.json),
|
||||
# 完全不碰網路——此刻保險還沒解,不能在這裡先觸網。
|
||||
# 找不到這些檔就安靜略過(本腳本不是只給出貨用,其他 GitHub 任務沒有這些檔是正常的)。
|
||||
ARCRUN_RAG_TARGETS="products/arcrun-rag/installer/ship.targets.json"
|
||||
STAGE_BUNDLE_DIR="/private/tmp/arcrun-rag-bundles-staging"
|
||||
PROD_BUNDLE_DIR="/private/tmp/arcrun-rag-bundles"
|
||||
if [ -f "$ARCRUN_RAG_TARGETS" ] && [ -f "$STAGE_BUNDLE_DIR/manifest.json" ] && [ -f "$PROD_BUNDLE_DIR/manifest.json" ]; then
|
||||
echo "═══════════════════════════════════════════"
|
||||
echo "📦 搬遷預覽(只讀本機檔案,尚未碰網路)"
|
||||
echo "═══════════════════════════════════════════"
|
||||
python3 - "$ARCRUN_RAG_TARGETS" "$STAGE_BUNDLE_DIR" "$PROD_BUNDLE_DIR" <<'PYEOF' || echo "(搬遷預覽讀檔失敗,略過——不影響下面的保險流程)"
|
||||
import json, os, sys
|
||||
targets_json, stage_dir, prod_dir = sys.argv[1], sys.argv[2], sys.argv[3]
|
||||
cfg = json.load(open(targets_json))
|
||||
prod = cfg.get("targets", {}).get("prod", {})
|
||||
remote = prod.get("bundles", {}).get("remote", "(未知)")
|
||||
branch = prod.get("bundles", {}).get("branch", "main")
|
||||
stage = json.load(open(os.path.join(stage_dir, "manifest.json")))
|
||||
prodm = json.load(open(os.path.join(prod_dir, "manifest.json")))
|
||||
print(f"搬到哪:{remote}(branch {branch})")
|
||||
print(f"版本:prod 目前 {prodm.get('release')} → stage 現在是 {stage.get('release')}")
|
||||
stage_core = {c.get("name"): c.get("sha256", "") for c in stage.get("core", [])}
|
||||
prod_core = {c.get("name"): c.get("sha256", "") for c in prodm.get("core", [])}
|
||||
changed = [n for n in prod_core if stage_core.get(n) != prod_core.get(n)]
|
||||
same = [n for n in prod_core if n in stage_core and stage_core.get(n) == prod_core.get(n)]
|
||||
print(f"prod 管的 {len(prod_core)} 顆裡,內容會變的:{len(changed)} 顆")
|
||||
for n in changed:
|
||||
print(f" - {n}")
|
||||
if same:
|
||||
print(f"內容沒變(sha 相同):{len(same)} 顆 — {', '.join(same)}")
|
||||
has_local_clone = os.path.isdir(os.path.join(prod_dir, ".git"))
|
||||
est = "1 次(push;沿用已存在的本地 clone,不需再 clone)" if has_local_clone \
|
||||
else "2 次(clone 1 + push 1;本地還沒有這個 clone)"
|
||||
print(f"預估碰 GitHub 幾次:{est}")
|
||||
print("(不含 jsDelivr purge——那是 CDN 快取清除,不算 GitHub 接觸,ROE 不計)")
|
||||
PYEOF
|
||||
echo ""
|
||||
else
|
||||
echo "(找不到本地 stage/prod bundle 的 manifest.json,略過搬遷預覽——非出貨類任務屬正常)"
|
||||
echo ""
|
||||
fi
|
||||
|
||||
echo "═══════════════════════════════════════════"
|
||||
echo "🚀 GitHub 接觸儀式 — 發射前檢查(ROE)"
|
||||
echo "═══════════════════════════════════════════"
|
||||
echo "任務:$MISSION"
|
||||
echo "時效:$MINUTES 分鐘(到期自動回保險)"
|
||||
echo ""
|
||||
echo "交戰規則(每條都要守):"
|
||||
echo " □ 單一 repo,不跨 repo fan-out"
|
||||
echo " □ 網路請求 ≤5 次(clone/push/PR 各算一次)"
|
||||
echo " □ 禁批量操作、禁迴圈打 API、禁開/改 Actions"
|
||||
echo " □ 動作間隔像人手(秒級間隔,不連發)"
|
||||
echo " □ 一收到 403/429/驗證挑戰 → 立即全停回報"
|
||||
echo ""
|
||||
read -r -p "以上確認,解除保險?(yes/N) " CONFIRM
|
||||
if [ "$CONFIRM" != "yes" ]; then
|
||||
echo "已取消,保險維持。"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
EXPIRY=$(( $(date +%s) + MINUTES * 60 ))
|
||||
printf '%s\n%s\n%s\n' "$EXPIRY" "$MISSION" "armed_at=$(date '+%Y-%m-%d %H:%M:%S')" > .github-armed
|
||||
echo ""
|
||||
echo "✅ 保險已解除至 $(date -r "$EXPIRY" '+%H:%M:%S')。期間每次 GitHub 接觸自動記入 github-contact-log.md。"
|
||||
echo " 提前上保險:rm .github-armed"
|
||||
Reference in New Issue
Block a user