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
+110
View File
@@ -0,0 +1,110 @@
#!/bin/bash
# PreToolUse hook — 影子表警察:抓 D91 的指紋(宣告 schema 在一邊,資料倒進 JSON 團在另一邊)
#
# 🚫 **本檔目前是死的:沒有註冊進 .claude/settings.json,不會被執行。**
# leo 2026-08-15:「**我是要你提案封鎖方式,不是要你就去做,急着做造成太多疊牀架屋了。**」
# ⇒ 總管在討論「疊牀架屋是病」的同時去疊了這一層。已測過(該擋兩條擋、六條不該擋全放),
# 但**要不要掛由 leo 裁**——它只在「過渡期止血」這一個用途上值得存在。
# ⇒ 真正的封鎖方式是**刪掉 metadata_json 與 entry_type 兩個欄位**(減,不是加),
# 提案見 matrix/arcrun 的 pending-changes.md。
#
# ⚠️ 這支是**過渡期的止血帶,不是答案**(leo 2026-08-15 定調)。
# 真正的解是「**刪掉那兩個欄位,讓儲存層沒有位置放壞東西**」——提案在 matrix/arcrun 的 pending-changes.md。
# 偵測永遠落後一步:D91 就是從「多開一張表」變異成「JSON 團」的。
# 在收窄的 API 出來之前,這支至少擋得住已知的那個形狀。**別因為有閘就以為安全。**
#
# 【為什麼 kbdb-api-wall-guard 抓不到】
# 那支守著 D38「三張表打天下,永不加表」,而 D91 **完全沒有違反它**——一張表都沒加。
# 它做的是:seed 一張宣告 6 個欄位的 template,然後把資料倒進 metadata_json。
# ⇒ **一張沒人管得到的影子表,而表數是三。現有的閘數表,而病不在表數上。**
#
# 【病徵】kbdb/migrations/0004_execution_log_template.sql 自己的註解就寫著
# 「template 這裡只負責 schema 文件化⋯⋯結構化欄位打包進 metadata_json」
# ⇒ 那張宣告了 6 個欄位的 template,沒有任何東西讀它。
# 【擴散】同註解:「recipe_stat 早已示範這個模式合法」
# ⇒ 活著的 7 種 entry_type 裡有 6 種是這形狀——不是角落,是多數。
#
# 攔的是**形狀不是關鍵字**:型別標籤與 JSON 團打包必須**同時**出現才命中
# (今天已有四次閘因為比對指令形狀而誤攔,不再犯)。註解、測試、文件一律放行。
# 豁免:該行尾加 `shadow-table-ok`(留痕,commit 說明理由)。
#
# 全文:頂層 system-dev/wiki/decisions-summary.md D91、D92。
exec python3 -c '
import json, re, sys
try:
d = json.load(sys.stdin)
except Exception:
sys.exit(0)
if d.get("tool_name") not in ("Write", "Edit", "MultiEdit"):
sys.exit(0)
i = d.get("tool_input") or {}
path = i.get("file_path") or ""
if not path:
sys.exit(0)
parts = [i.get("content") or "", i.get("new_string") or ""]
for e in (i.get("edits") or []):
parts.append(e.get("new_string") or "")
body = "\n".join(p for p in parts if p)
if not body:
sys.exit(0)
low = path.lower()
if re.search(r"\.(md|txt|json|yaml|yml)$", low): sys.exit(0)
if re.search(r"(^|/)(wiki|docs|tests?)/", low): sys.exit(0)
if re.search(r"(test|spec)\.[a-z]+$|_test\.go$", low): sys.exit(0)
if not re.search(r"\.(ts|js|mjs|sql|go)$", low): sys.exit(0)
live = []
for line in body.splitlines():
if "shadow-table-ok" in line:
continue
s = re.sub(r"--.*$", "", line)
s = re.sub(r"//.*$", "", s)
if re.match(r"\s*[*#]", s):
continue
live.append(s)
live = "\n".join(live)
# A:把型別標籤釘在 entries 上
a = len(re.findall(r"""entry_type\s*[:=]\s*[\x27"][a-z_]+[\x27"]""", live))
# B:結構化欄位被打包進 JSON 團
b = len(re.findall(r"""metadata_json[^\n]{0,80}(JSON\.stringify|json_object|\{)|(JSON\.stringify|json_object)\([^\n]{0,80}metadata_json""", live))
# Cseed 一張宣告了欄位的 template
c = len(re.findall(r"""INSERT\s+(OR\s+IGNORE\s+)?INTO\s+templates\b[^;]{0,200}slots_json|slots_json\s*[:=]""", live, re.I | re.S))
if not ((a and b) or (c and b)):
sys.exit(0)
sys.stderr.write(f"""❌ BLOCKED — 影子表警察(D91 的指紋)
檔案:{path}
命中:型別標籤 {a} 處/JSON 團打包 {b} 處/template 宣告 {c} 處
你正在寫的形狀是:**宣告一個 schema,然後把資料倒進 metadata_json**。
那會做出一張**沒人管得到的影子表**——表數還是三,但欄位從此改不動:
要加一欄,得同時改「一個沒人讀的宣告」和「一段打包程式」,
而**沒有任何機制會告訴你它們已經對不上了**。
leo 2026-08-15:「這每個都是一個 template⋯⋯**以後你不能修改 fields,因為表禁止動**,
如果要多一欄,要不就是說要改表,**要不就是全塞在能塞的格子裡**。」
先回答這三題,答不出來就不是這樣寫:
① 這些被打包的欄位,**誰會讀 schema 宣告**?沒有人讀 ⇒ 那個宣告是裝飾品
② 要加第八個欄位時,**有什麼東西會擋住「只改了一半」**?
③ 這批資料的形狀是**我們決定**的,還是**使用者的想法**決定的?
使用者決定 ⇒ 不准有 schema,走 v-table
Arcrun#133 的判準:這張表要改的時候,誰付 migration 的代價?)
真的有理由這樣寫(例:那條路徑的寫入放大有實測數字,且已在票上記錄)
⇒ 該行尾加 `shadow-table-ok`,並在 commit 說明理由。
⚠️ 本閘是過渡期止血帶。真正的解是刪掉 metadata_json 與 entry_type(減,不是加)。
參考:system-dev/wiki/decisions-summary.md **D91**(病徵與擴散)、**D92**(同族形狀)
""")
sys.exit(2)
'