#!/bin/bash # SessionStart hook — 開 session 就把「全局」推到眼前(InkStoneCo#17 / D69 / D70 / D71) # # 掛在 settings.json 的 SessionStart(matcher: startup|resume|clear)。stdout 會被當成 context 注入。 # # ── 這支在整個機制裡的位置(leo 2026-08-11 拍板)───────────────────────────── # 算 = 雲端的 Arcrun 工作流 `global_index`(讀 Gitea 五個 repo 的票 + 讀 KBDB 藏書地圖) # 存 = 雲端(總圖住雲端,不推回地端;沒有東西需要同步,所以沒有漂移源) # 拿 = 本檔。**由機制保證取一次**,不靠 AI 記得去打 MCP # (openhuman SuperContext 的教訓:靠模型自己選擇要不要查,就是會漏) # # ⚠️ 例外=下面 push 2/5 的「各 repo wiki 全景」:那段**算在地端**。 # 不是不想放雲端,是雲端拿不到 repo 樹(只有 API 列檔一條路,撞 principles 紅線)。 # # ── 為什麼不再 cat status.md ──────────────────────────────────────────────── # 2026-08-11 實測:舊版這支吐 235,880 bytes(因為它 cat 整份 216 KB 的落帳流水), # 真正進到 context 的只有 2 KB 預覽 + 一個要自己去 Read 的檔名。 # ⇒ 「開場就知道」等於沒發生。**注入通道的預算是有限的,落帳流水不該佔著它。** # 進度/狀態一律去 Gitea(D52 + D72),不在地端養第二份會漂的快照。 # # 順序=重要性:全局總圖最前面(它最可能被截斷保護到),其次原則,最後踩坑標題。 set -euo pipefail GLOBAL_INDEX_URL="https://arcrun-cypher-executor.leo21c.workers.dev/webhooks/named/leo/global_index/query" PANORAMA_FILE="system-dev/wiki/PANORAMA.md" PRINCIPLES_FILE="system-dev/wiki/principles.md" MISTAKES_FILE="system-dev/wiki/mistakes.md" MISTAKES_TAIL=20 # 只推最近 N 條標題(全份 96 條/11 KB 會吃掉總圖的預算) # ── push 1/5:全局總圖(雲端現算)──────────────────────────────────────────── # 降級規格(D71,票與知識不對稱): # 算得出來 → 注入 # 算不出來/破損/空 → **完全不注入內容**,只誠實說一句「這次沒有」 # (寧可冷啟動,不要注入垃圾;票尤其不能給一份看起來像現況的舊東西) GLOBAL_MD="" GLOBAL_ERR="" if RESP=$(curl -sS -m 45 -X POST "$GLOBAL_INDEX_URL" \ -H 'Content-Type: application/json' -d '{}' 2>/dev/null); then GLOBAL_MD=$(printf '%s' "$RESP" | python3 -c ' import sys, json try: d = json.load(sys.stdin) except Exception: sys.exit(0) def find_md(x, depth=0): # 工作流的最終輸出可能被包一層 data(code 零件的回應信封),兩種形狀都收 if depth > 3 or not isinstance(x, dict): return None if x.get("success") is True and isinstance(x.get("md"), str) and x["md"].strip(): return x["md"] return find_md(x.get("data"), depth + 1) md = find_md(d) if md: sys.stdout.write(md) ' 2>/dev/null || true) if [ -z "$GLOBAL_MD" ]; then GLOBAL_ERR=$(printf '%s' "$RESP" | python3 -c ' import sys, json try: d = json.load(sys.stdin) except Exception: sys.stdout.write("回應不是 JSON"); sys.exit(0) sys.stdout.write(str((d or {}).get("error") or "工作流沒有交出 md")[:200]) ' 2>/dev/null || echo "回應解析失敗") fi else GLOBAL_ERR="連不上雲端(curl 失敗或逾時 45 秒)" fi echo "════════════════════════════════════════════════" if [ -n "$GLOBAL_MD" ]; then printf '%s\n' "$GLOBAL_MD" else echo "⚠️ 這次拿不到全局總圖:${GLOBAL_ERR}" echo " 刻意不給你一份舊的——票的狀態放舊的比沒有更危險(會去重做已經做完的事)。" echo " ⇒ 你現在**不知道有哪些票、庫裡有哪些知識**。動手前先自己撈:" echo " Gitea:GET https://git.uncle6.me/api/v1/repos/Leo//issues?state=open" echo " (五個 repo:InkStoneCo / Arcrun / arcrun-rag / mira / system-dev-template)" echo " 知識:kbdb_get_map()" echo " 修這條管路:工作流 leo:wf:global_index(雲端),本 hook 只負責取來印。" fi echo "════════════════════════════════════════════════" echo "" # ── push 2/5:各 repo 的 wiki 全景(leo 2026-08-12「一次看到全景」的另一半)── # 上面那段是**票**(雲端現算)+ KBDB 藏書地圖;這段是**各 repo 真正的 wiki**。 # 為什麼不塞進雲端那支工作流:工作流跑在 Cloudflare 上,要拿 repo 樹只有 # 「Gitea contents API 列檔」一條路,而 principles 紅線寫死 # 「讀 repo 走 git clone/fetch,不走 API 列檔」。 # ⇒ 在有 git 的地方算好(`scripts/wiki-panorama.sh`,人發起、不輪詢), # 存成 repo 裡的一份 md,本檔只負責印。 # 只印到 `panorama:inject-end` 為止——標記以下是給 grep 的完整卡片清單, # 全倒進來會撐爆 context(全檔 ~28 KB,注入段 ~6 KB)。 if [ -f "$PANORAMA_FILE" ]; then echo "════════════════════════════════════════════════" awk '/panorama:inject-end/{exit} {print}' "$PANORAMA_FILE" # 過期就講出來(不自動重算:重算要連網 clone 十幾個 repo,不該卡在開場) P_GEN=$(grep -m1 -oE '[0-9]{4}-[0-9]{2}-[0-9]{2} 產生' "$PANORAMA_FILE" | cut -d' ' -f1 || true) W_LAST=$(git log -1 --format=%ad --date=short -- system-dev/wiki 2>/dev/null || true) if [ -n "$P_GEN" ] && [ -n "$W_LAST" ] && [ "$W_LAST" \> "$P_GEN" ]; then echo "" echo "⚠️ 這張全景圖是 ${P_GEN} 算的,但 wiki 在 ${W_LAST} 又被改過 ⇒ 它已經不準了。" echo " 重算:bash scripts/wiki-panorama.sh --write" fi echo "════════════════════════════════════════════════" echo "" else echo "────────────────────────────────────────────────" echo "⚠️ 沒有各 repo 的 wiki 全景圖($PANORAMA_FILE)⇒ 你**不知道哪些知識記在哪個 repo**。" echo " 產生(約一分鐘,git clone 各 repo 的 wiki 目錄,不走 API):" echo " bash scripts/wiki-panorama.sh --write" echo "" fi # ── push 3/5:進度不在地端(D72)──────────────────────────────────────────── echo "────────────────────────────────────────────────" echo "📍 進度/狀態一律去 Gitea 撈,不要在任何檔案裡找(D52 + D72)" echo " 等 leo = labels=s/stage | 可開工 = s/todo | 進行中 = s/doing" echo " 知識庫(system-dev/wiki/)只放**事實**:踩過的坑、決策、憑證在哪。**不放進度**。" echo " 🔴 不要在對話或任何檔案裡另養一份「等 leo 的清單」——它一定會漂。" echo "" # ── push 4/5:principles(全文,行動前必服從)──────────────────────────────── if [ -f "$PRINCIPLES_FILE" ] && grep -q '^- ' "$PRINCIPLES_FILE" 2>/dev/null; then echo "════════════════════════════════════════════════" echo "📐 設計原則(行動前必服從,來自 principles.md)" echo "════════════════════════════════════════════════" grep '^- ' "$PRINCIPLES_FILE" P_COUNT=$(grep -c '^- ' "$PRINCIPLES_FILE") if [ "$P_COUNT" -gt 15 ]; then echo "" echo "(⚠️ principles 已 ${P_COUNT} 條 > 15:請考慮合併相近原則、或把較細的下放成 card)" fi echo "" fi # ── push 5/5:mistakes(只推最近 N 條標題)────────────────────────────────── if [ -f "$MISTAKES_FILE" ] && grep -q 'MISTAKE' "$MISTAKES_FILE" 2>/dev/null; then M_TOTAL=$(grep -cE 'MISTAKE' "$MISTAKES_FILE") echo "────────────────────────────────────────────────" echo "⚠️ 已知踩坑:最近 ${MISTAKES_TAIL} 條(全部 ${M_TOTAL} 條在 $MISTAKES_FILE,撞到就 grep 全文)" grep -E 'MISTAKE' "$MISTAKES_FILE" | tail -n "$MISTAKES_TAIL" | sed 's/^/ /' echo "" fi echo "────────────────────────────────────────────────" echo "以上是 index,不是內容——它只讓你知道「有這件事、去哪裡找」。" echo "要完整脈絡(decisions / mistakes / SDD)→ 執行 /wiki-recall" echo "════════════════════════════════════════════════" exit 0