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>
109 lines
5.2 KiB
Bash
Executable File
109 lines
5.2 KiB
Bash
Executable File
#!/bin/sh
|
||
# mistake-needs-ticket-guard.sh — PreToolUse(Write|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
|