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:
2026-08-20 11:41:46 +08:00
commit c2638668e3
85 changed files with 11879 additions and 0 deletions
+108
View File
@@ -0,0 +1,108 @@
#!/bin/sh
# mistake-needs-ticket-guard.sh — PreToolUseWrite|Edit|MultiEdit):
# **往 mistakes.md 寫一條新教訓,如果機制擋得住,就必須附票號。**
#
# 🔴 立這條的原話(leo 2026-08-16,一口氣講了三次,因為前兩次我又拿去寫成文件):
# 「以後你自己寫入 mistake 的東西,**如果是機制可以防止的都要貼上票號**。」
# 「要不然你的 mistake 根本**不會協助你迭代**。」
# 「**沒迭代寫個 mistake 做什麼?下一次又犯同樣錯誤,你就說上次寫過。**」
#
# 【當天的活教材,就是這條規則本身要治的病】
# `mistakes.md:220` 那條(08-14)結尾自己寫著:
# 「📌 **待修**:`check` 應該要有唯讀模式,否則這個坑對每一個第一次用它的人都會再發生一次。」
# 它**沒有票號** ⇒ 沒有任何人/任何看板會撈到它 ⇒ 躺了兩天 ⇒
# 08-16 總管**原封不動照撞一次**,還在回覆裡說「這個我兩天前寫過」。
# ⇒ 那句「我寫過」正是 leo 預言的那句話。**寫下來不是迭代,開票才是。**
#
# 【判準:什麼叫「機制可以防止」】
# 不是所有教訓都要票。要票的是**下一次可以被機器擋下來**的那種:
# · 用錯工具/用錯順序/漏做一步 → 可以做成 hook 或 preflight
# · 兩份真相漂移/欄位漏填 → 可以做成不變式
# · 「我以為 X 其實 Y」的事實誤解 → 通常**不需要**票(那是知識,不是閘)
# 本閘不猜,用一個便宜的近似:**新增的段落裡出現「待修/應該要/下次要/
# 要改成/可以做成」這類「有人得動手」的字樣,就要求同段落有票號。**
#
# 【放行的寫法】同一段裡出現任一種票號定址即可:
# inkstone/arcrun-rag#88 Leo/Arcrun#136 本 repo 的 #142
# 真的不需要票(純知識型教訓):該段加 `no-ticket-needed` 一詞(留痕,說明理由)。
set -eu
PAYLOAD=$(cat 2>/dev/null || echo '{}')
RESULT=$(printf '%s' "$PAYLOAD" | python3 -c '
import sys, json, re
try:
d = json.load(sys.stdin)
except Exception:
sys.exit(0)
ti = d.get("tool_input") or {}
path = ti.get("file_path") or ""
if not path.endswith("mistakes.md"):
sys.exit(0)
# 收集這次「新寫進去」的文字(Write 全文;Edit 只看 new_string
chunks = []
if "content" in ti:
chunks.append(ti["content"])
if "new_string" in ti:
chunks.append(ti["new_string"])
for e in (ti.get("edits") or []):
if isinstance(e, dict) and "new_string" in e:
chunks.append(e["new_string"])
text = "\n".join(c for c in chunks if isinstance(c, str))
if not text.strip():
sys.exit(0)
# 「有人得動手」的訊號——出現這些就代表它是可被機制防止的
ACTION = re.compile(r"待修|應該要|下次要|要改成|可以做成|該做成|還沒做|尚未修|TODO|待辦")
# 票號定址:owner/repo#N 或裸 #N
TICKET = re.compile(r"(?:[A-Za-z0-9._-]+/[A-Za-z0-9._-]+)?#\d+")
# 逐「段」判斷(空行分段),只報第一個有問題的段落
for para in re.split(r"\n\s*\n", text):
if not ACTION.search(para):
continue
if "no-ticket-needed" in para:
continue
if TICKET.search(para):
continue
hit = ACTION.search(para).group(0)
snippet = " ".join(para.split())[:120]
print(json.dumps({"hit": hit, "snippet": snippet}, ensure_ascii=False))
break
' 2>/dev/null || true)
[ -n "$RESULT" ] || exit 0
HIT=$(printf '%s' "$RESULT" | python3 -c 'import sys,json;print(json.load(sys.stdin)["hit"])' 2>/dev/null || echo "待修")
SNIP=$(printf '%s' "$RESULT" | python3 -c 'import sys,json;print(json.load(sys.stdin)["snippet"])' 2>/dev/null || echo "")
cat >&2 <<EOF
🎫 這條教訓是「機制擋得住」的,但沒有票號——**沒有票,它不會被迭代**
觸發字樣:「$HIT」
那一段: $SNIP
【leo 2026-08-16,一口氣講了三次】
「以後你自己寫入 mistake 的東西,**如果是機制可以防止的都要貼上票號**。」
「要不然你的 mistake 根本**不會協助你迭代**。」
「**沒迭代寫個 mistake 做什麼?下一次又犯同樣錯誤,你就說上次寫過。**」
【當天的活教材(就是這條規則的來由)】
\`mistakes.md\` 那條 08-14 的結尾自己寫著「📌 待修:check 應該要有唯讀模式」,
**沒有票號** ⇒ 沒有看板撈得到 ⇒ 躺了兩天 ⇒ 08-16 總管原封不動照撞一次,
然後在回覆裡說「這個我兩天前寫過」。**那句話正是 leo 預言的那一句。**
【現在怎麼做(擇一)】
① **先開票,再寫教訓**(正解,順序不能反):
scripts/ticket where <關鍵字> # 先查這件事該掛哪張既有票
scripts/ticket say <owner/repo#N> -F <檔> # 有既有票就貼進去
scripts/ticket new <repo> -F <檔> # 真的沒有才開新票
然後把票號寫進這一段:\`inkstone/arcrun-rag#88\`
② **這條純粹是知識型教訓、沒有東西要動手**(例如「我以為 X 其實 Y」):
該段加一詞 \`no-ticket-needed\`,並在旁邊寫一句為什麼不需要閘
EOF
exit 2