chore: template 1.16.0——wiki 讀取兩支 hook(查詢即搜尋 wiki+subagent 自動注入)
leo 2026-07-20:「花很多力氣去產生 wiki,最重要的就是要可以查詢, 結果要查的時候就跳過,那就白寫了」 - wiki-first-search.sh(Grep|Glob|Read):查 code 的當下用同組關鍵字 grep wiki,只推命中行 - subagent-wiki-guard.sh(Task):查證類任務自動注入「先查 wiki」給 subagent - update.sh/install.sh 來源改指 Gitea(原指 GitHub uncle6me-web 已 suspend=自動更新早就死了) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+1
-1
@@ -1 +1 @@
|
||||
1.10.0
|
||||
1.16.0
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
---
|
||||
status: draft # active | draft | paused | closed(生命週期鐵律見 ../SDD-LIFECYCLE.md)
|
||||
superseded_by: "" # closed 且被取代時填接替的 SDD 資料夾名
|
||||
---
|
||||
|
||||
# [子系統名稱] — Design
|
||||
|
||||
> 狀態:[草稿 / 審核中 / 已採納 / 已廢棄]
|
||||
> 建立:[YYYY-MM-DD] | 最後更新:[YYYY-MM-DD]
|
||||
> 負責人:[名稱]
|
||||
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
# Logseq 任務 marker 解析(單一真相源)
|
||||
|
||||
> **這是「Logseq 原生任務語法」解析的唯一權威規格。** 任何要從 Logseq graph
|
||||
> 抓任務狀態的功能,一律 import 這份、不得各寫一份自己的 mapping。
|
||||
>
|
||||
> **已知兩個消費者**(共用同一套解析,見各自 issue):
|
||||
> 1. **vault 萃取**(`/wiki-extract`,template#5):marker → 卡片 frontmatter `task_status`。
|
||||
> 2. **tasks→Project 投影**(`system-dev/workflows/tasks-project-sync.*`,template#4):
|
||||
> 當投影來源是 Logseq graph(notes/kb)時,用這份判斷任務與狀態。
|
||||
>
|
||||
> 兩者**只共用「怎麼 parse」**(哪幾行是任務、marker 是什麼、正規狀態是什麼、跳過什麼);
|
||||
> parse 完各自要「拿狀態做什麼」(寫卡 vs 投影 issue)不同,那部分各管各的。
|
||||
|
||||
---
|
||||
|
||||
## 為什麼不是 GFM checkbox(規格更正,leo 2026-07-04 發現)
|
||||
|
||||
Logseq 的原生任務**不是** GFM 的 `- [ ]` / `- [x]`,而是**大寫 marker 開頭的 block**:
|
||||
|
||||
```
|
||||
- TODO AI 查看 leo21c 內所有 Repo,找到本地 Repo 搬到 Gitea
|
||||
- DOING 建立知識總庫,可查所有子庫
|
||||
- DONE 手機和電腦 Logseq 可以被放進知識總庫
|
||||
```
|
||||
|
||||
若照舊規格只抓 `- [ ]` checkbox,**notes / kb 兩個 Logseq graph 的任務會全數漏抓**。
|
||||
|
||||
> 兩種源、兩套語法、同一條下游管線:
|
||||
> - **SDD `tasks.md`**(各 repo `system-dev/docs/3-specs/**`)→ GFM checkbox(現行不變)。
|
||||
> - **Logseq graph(notes / kb)** → 本檔的大寫 marker。
|
||||
|
||||
---
|
||||
|
||||
## 解析規格
|
||||
|
||||
### 1. 任務行辨識(regex)
|
||||
|
||||
```
|
||||
^\s*- (TODO|DOING|NOW|LATER|WAITING|DONE|CANCELED|CANCELLED)\s+
|
||||
```
|
||||
|
||||
- marker 必須是 block(`-` bullet)的**開頭第一個 token**、全大寫、後接空白。
|
||||
- `CANCELED` 與英式 `CANCELLED` 皆收(Logseq 兩種都產)。
|
||||
- marker 後面到行尾(或到子 bullet 之前)是**任務內文**。
|
||||
|
||||
### 2. marker → 正規狀態(task_status)
|
||||
|
||||
| Logseq marker | 正規 task_status |
|
||||
|---------------|------------------|
|
||||
| `TODO`、`LATER` | `todo` |
|
||||
| `DOING`、`NOW` | `in-progress` |
|
||||
| `WAITING` | `blocked` |
|
||||
| `DONE` | `done` |
|
||||
| `CANCELED`、`CANCELLED` | `closed` |
|
||||
|
||||
> `LATER`/`NOW` 是 Logseq「排程視圖」用的同義 marker(LATER≈TODO、NOW≈DOING),
|
||||
> 正規化後與 TODO/DOING 併軌,下游不必區分。
|
||||
|
||||
### 3. 必須跳過的東西(別當任務內文)
|
||||
|
||||
Logseq 的任務 block 底下常掛時間戳與屬性行,這些**不是內文**,解析時整段略過:
|
||||
|
||||
- **`:LOGBOOK:` … `:END:` 區塊**:marker 被點擊計時產生的時間戳紀錄。
|
||||
遇到 `:LOGBOOK:` 那行起、到 `:END:` 那行止(含兩端),整塊丟掉。
|
||||
- **屬性行 `key:: value`**:如 `collapsed:: true`、`id:: 65a...`、`SCHEDULED:: <...>`、
|
||||
`DEADLINE:: <...>`。凡符合 `^\s*[\w-]+:: ` 的行都是屬性,不是內文。
|
||||
(`SCHEDULED`/`DEADLINE` 的日期若下游要用可另抓,但**不得當任務描述文字**。)
|
||||
|
||||
### 4. 巢狀子 bullet
|
||||
|
||||
任務 block 底下縮排的子 bullet 是該任務的補充說明(非獨立任務,除非子 bullet 自己也帶 marker)。
|
||||
萃取時可併入該任務的描述脈絡;投影時只取母 block 那行當任務標題。
|
||||
|
||||
---
|
||||
|
||||
## 自檢(實作或 LLM 執行前跑一遍)
|
||||
|
||||
- [ ] 用的是大寫 marker regex,**不是** `- [ ]` checkbox。
|
||||
- [ ] 八個 marker 全部覆蓋(含 `LATER`/`NOW`/`CANCELLED` 別漏)。
|
||||
- [ ] `:LOGBOOK:...:END:` 與 `key:: value` 屬性行有跳過,沒混進任務文字。
|
||||
- [ ] 狀態用上表**正規名**(`todo`/`in-progress`/`blocked`/`done`/`closed`),不是原始 marker 字面。
|
||||
@@ -0,0 +1,57 @@
|
||||
# FEATURE REQUEST: KBDB 應提供 upsert block endpoint(目前只能 client 端拼 GET+PATCH/POST)
|
||||
|
||||
> 日期:2026-05-29
|
||||
> 來源:arcrun Phase 2(降級假零件成 recipe)
|
||||
> 類型:API 缺口 —— upsert 語義目前不存在於 KBDB,被迫由 client 端拼湊
|
||||
> 關聯:[BUG-2026-05-29-patch-blocks-403-different-org.md](./BUG-2026-05-29-patch-blocks-403-different-org.md)(拼湊路徑的 PATCH 那段還壞著)
|
||||
|
||||
---
|
||||
|
||||
## 問題
|
||||
|
||||
arcrun 原本有一個 `kbdb_upsert_block` 零件,行為是「依 page_name + user_id 查找,有就更新、沒有就新建」。但它**完全是 client 端拼湊**:
|
||||
|
||||
```
|
||||
GET /blocks?page_name=X&limit=10 # 查找
|
||||
→ client 端 filter user_id 找第一筆
|
||||
→ 找到:PATCH /blocks/:id # 更新
|
||||
→ 沒找到:POST /blocks # 新建
|
||||
```
|
||||
|
||||
KBDB **沒有** upsert 語義的 endpoint。實測(同一把 key):
|
||||
|
||||
| 探測 | HTTP |
|
||||
|---|---|
|
||||
| `PUT /blocks` | 404 |
|
||||
| `POST /blocks/upsert` | 404 |
|
||||
| `PUT /blocks/upsert` | 404 |
|
||||
|
||||
## 為什麼這是 KBDB 該補的、不是 arcrun 該拼的
|
||||
|
||||
arcrun 的設計原則是**薄殼 / 薄 API**:arcrun 只幫既有 API 套一層 recipe(endpoint + auth),**不無中生有功能**。
|
||||
|
||||
「先查再分支寫」這套 upsert 邏輯,是在 client 端**變出 KBDB 沒有的功能**。這有幾個壞處:
|
||||
|
||||
1. **競態(race condition)**:GET 和後續 PATCH/POST 之間,別人可能插入同 page_name 的 block,造成重複或覆寫。只有 KBDB server 端用單一交易(upsert / `ON CONFLICT`)才能正確。
|
||||
2. **語義碎裂**:每個 client(arcrun / 其他 SDK)各自拼一套 upsert,filter 規則(怎麼算「同一筆」)可能不一致。
|
||||
3. **拼湊路徑現在還壞著**:它依賴 PATCH /blocks/:id,而那個 endpoint 目前回 403(見關聯 bug)。
|
||||
|
||||
## 建議
|
||||
|
||||
KBDB 提供一個原生 upsert endpoint,例如:
|
||||
|
||||
```
|
||||
POST /blocks/upsert
|
||||
Body: { page_name, user_id, content, type, source, tags, ... }
|
||||
語義:依 (page_name, user_id) 找唯一 block —— 存在則更新、不存在則建立(單一交易,server 端 ON CONFLICT)
|
||||
回應:{ id, action: "created" | "updated" }
|
||||
```
|
||||
|
||||
有了它之後:
|
||||
- arcrun 端只要建一個 `recipe:kbdb_upsert` 指向 `POST /blocks/upsert`,套殼即可,跟其他 5 個 KBDB recipe 一致。
|
||||
- 競態由 KBDB server 端交易保證,client 不再拼湊。
|
||||
|
||||
## arcrun 端現狀(等 KBDB)
|
||||
|
||||
- 其餘 5 個 KBDB 操作已降級成 recipe 並驗收:`kbdb_get`(200) / `kbdb_create_block`(201) / `kbdb_ingest`(201) / `kbdb_delete`(200) 綠;`kbdb_patch_block` 因上述 403 bug 待驗。
|
||||
- `kbdb_upsert_block` **暫不降級、源碼暫留**,等 KBDB 出 `POST /blocks/upsert` 後改建 `recipe:kbdb_upsert` 套殼。
|
||||
@@ -0,0 +1,68 @@
|
||||
# BUG: PATCH /blocks/:id 回 403 "block belongs to different org"(同一把 key 能 create/get/delete 卻不能 patch)
|
||||
|
||||
> 回報日期:2026-05-29
|
||||
> 回報來源:arcrun Phase 2(把 kbdb_* 零件降級成 recipe,逐個驗收時發現)
|
||||
> 嚴重度:中高 —— PATCH endpoint 對「自己剛建、且能刪的 block」拒絕更新,等於 update 能力全壞
|
||||
> 影響:任何「查→改」或 upsert 流程(先 GET 找到 block,再 PATCH 更新)都無法完成
|
||||
|
||||
---
|
||||
|
||||
## 症狀
|
||||
|
||||
用**同一把 API key**、對**同一個 block**,四個操作的結果不一致:
|
||||
|
||||
| 操作 | endpoint | HTTP | 結果 |
|
||||
|---|---|---|---|
|
||||
| 建立 | `POST /blocks` | **201** | ✅ 建出 block,回 id |
|
||||
| 讀取 | `GET /blocks/:id` | **200** | ✅ 讀得到 |
|
||||
| **更新** | **`PATCH /blocks/:id`** | **403** | ❌ `{"error":"block belongs to different org"}` |
|
||||
| 刪除 | `DELETE /blocks/:id` | **200** | ✅ `{"deleted":true}` |
|
||||
|
||||
**矛盾點**:同一把 key 能 create / get / delete 這個 block —— 代表 KBDB 認定我擁有它(org 一致)。但 PATCH 卻說「belongs to different org」。**create 寫進去的 org 判定,和 patch 讀出來比對的 org 判定不一致**,這是 KBDB 內部 org 歸屬邏輯的 bug。
|
||||
|
||||
## 重現(裸 curl,不經 arcrun)
|
||||
|
||||
為排除是 arcrun 注入問題,直接用裸 curl + Bearer token 打 `https://kbdb.finally.click`:
|
||||
|
||||
```bash
|
||||
TOKEN="Bearer ak_402d…" # 同一把 key,全程不變
|
||||
BASE=https://kbdb.finally.click
|
||||
|
||||
# 1. 建立 → 201
|
||||
curl -X POST $BASE/blocks -H "Authorization: $TOKEN" -H 'Content-Type: application/json' \
|
||||
-d '{"content":"...","type":"note","page_name":"kbdb_bug_repro","source":"...","user_id":"arcrun_phase2"}'
|
||||
# → {"id":"f39ea877-...","action":"created"} HTTP 201
|
||||
|
||||
# 2. 讀取 → 200
|
||||
curl $BASE/blocks/f39ea877-... -H "Authorization: $TOKEN"
|
||||
# → HTTP 200
|
||||
|
||||
# 3. 更新 → 403 ★ BUG
|
||||
curl -X PATCH $BASE/blocks/f39ea877-... -H "Authorization: $TOKEN" -H 'Content-Type: application/json' \
|
||||
-d '{"content":"patched"}'
|
||||
# → {"error":"block belongs to different org"} HTTP 403
|
||||
|
||||
# 4. 刪除 → 200(證明我擁有此 block)
|
||||
curl -X DELETE $BASE/blocks/f39ea877-... -H "Authorization: $TOKEN"
|
||||
# → {"deleted":true} HTTP 200
|
||||
```
|
||||
|
||||
經 arcrun(cypher-executor → auth_static_key 注入同一把 token → recipe 轉發)也是完全相同結果,所以**確定是 KBDB server 端 PATCH 路徑的問題,不是 client / arcrun 的問題**。
|
||||
|
||||
## 推測方向(給 KBDB 排查)
|
||||
|
||||
create / get / delete 的 org 判定路徑,和 PATCH 的 org 判定路徑不一致。可能:
|
||||
|
||||
1. **PATCH 用了不同的 org 解析來源**:例如 create 用 token → org_id 的某種映射寫入 block,但 PATCH 的 org-check 從另一個欄位 / 另一張表讀,兩邊算出的 org 不同。
|
||||
2. **block 落地時的 org_id 與 token 的 org_id 不一致**:create 時可能用了 default org 或 null org 寫入,PATCH 的 ownership 檢查卻嚴格比對 token org,導致「自己建的卻不是自己 org」。
|
||||
3. **org-check 是 PATCH 獨有、其他三個 verb 沒做**:所以只有 PATCH 露出這個不一致。
|
||||
|
||||
建議從「create 時 block 實際寫入的 org_id」對比「PATCH org-check 讀的 org_id」兩個值下手,它們應該相等卻不等。
|
||||
|
||||
## 對 arcrun 的影響(已隔離,不阻擋 arcrun Phase 2)
|
||||
|
||||
- arcrun 已把 `kbdb_patch_block` 降級成 recipe,recipe 的轉發 + auth 注入經驗證**正確無誤**(請求成功打到 KBDB 的 PATCH handler,非 401)。
|
||||
- 403 屬 KBDB 端行為,依 arcrun 原則「能不能打通由發 key 的服務裁決」,這不是 recipe 的 bug。
|
||||
- 但 arcrun 的 `kbdb_upsert_block`(GET 查找 → 分支 PATCH/POST)會用到 PATCH,**此 bug 未解前,upsert 的 PATCH 分支無法驗收 2xx**。arcrun 端會把該分支標「未驗收:阻擋於 KBDB PATCH 403」。
|
||||
|
||||
KBDB 修好後請通知 arcrun,重跑 `kbdb_patch_block` recipe 驗收即可。
|
||||
@@ -126,10 +126,23 @@ gloss: 一句話定義這個概念是什麼(給下游語義 normalize 用,
|
||||
|
||||
- [自包含改寫的要點,不寫「詳見原文」]
|
||||
|
||||
## 實體
|
||||
|
||||
> 本卡內文的關鍵實體(也是 graph node)。名+描述一起供下游 embedding normalize。
|
||||
> AI 生產、人不必讀;集中放、一實體一行、不縮排、不重複。
|
||||
- **原子筆記**(atomic note/卡片原子化)— 每張卡只承載一個不可再分論點的知識記錄單元。
|
||||
- **傳統筆記**(大鍋炒筆記)— 把多主題混雜在同一篇、難精確引用的記錄方式。
|
||||
|
||||
## 關聯
|
||||
|
||||
### 內文知識關係(內文實體間;端點=上方 `## 實體` 的正規名,一字不差)
|
||||
|
||||
- 原子筆記 >> 對立於 >> 傳統筆記
|
||||
- 傳統筆記 >> 犧牲 >> 精確引用
|
||||
|
||||
### 卡片關係(卡對卡)
|
||||
|
||||
- [[本卡]] >> 謂詞(動詞短語) >> [[他卡]]
|
||||
- [[原子筆記]] >> 是其最小單元 >> [[卡片盒筆記法]]
|
||||
```
|
||||
|
||||
### 架構:三層 + 標籤橫切(183 卡實證)
|
||||
@@ -147,15 +160,22 @@ cards/<bucket>/
|
||||
- **frontmatter `tags:` 而非行內 `#tag`**:內文常用 `#`(如 `#猜想`),行內標籤會讓 ingest 分不清「分類」與「內文範例」污染 graph;frontmatter 零歧義。標籤只能用 `TAXONOMY.md` 列出的;**禁止繞過字典在卡片直接冒新標籤**,但字典可受控擴充(遇新軸先查重、確認非同義詞,再登記進本 repo 的 TAXONOMY.md)。
|
||||
- **麵包屑帶路徑**:H1 次行 `← [[<bucket>/00-INDEX]]`。指 `00-INDEX` 因固定名跨桶撞名,**一律帶路徑**;卡片間連結用裸 `[[卡名]]`。
|
||||
|
||||
### 使用 typed-edge 三元組(不只裸 `[[wikilink]]`)
|
||||
### 使用 typed-edge 三元組(抓內文實體關係,不只卡對卡)
|
||||
|
||||
整理時,發現內容與其他頁面有關聯,用**帶語義的三元組**寫進 `## 關聯`,而非只列裸 `[[頁面]]`。裸 `[[A]]` 只說「有關」、沒說關係,下游要建 knowledge graph 還得回讀兩張卡;三元組把關係也預編譯,ingest 直接 parse 出帶類型的有向邊。
|
||||
用**帶語義的三元組** `A >> 謂詞 >> B` 寫進 `## 關聯`。**重點是抓內文裡的實體關係**——卡對卡(`[[卡A]] >> 謂詞 >> [[卡B]]`)只是把既有雙鏈加個動詞、資訊量幾乎沒增加;知識圖譜的價值在內文概念間的關係(`原子筆記 >> 對立於 >> 傳統筆記`,這些 A/B 是內文概念、不是卡標題)。
|
||||
|
||||
格式 `A >> 謂詞 >> B`,規則:
|
||||
1. **方向性**:必須讀成「A(謂詞)B」一句通順的話;A、B 順序=主→賓真實方向。
|
||||
2. **謂詞用動詞 / 動詞短語**(反駁、奠基於、是…的實作),天然帶方向。
|
||||
3. **謂詞自由書寫**,不受控詞彙;下游對謂詞 embedding 時同義謂詞會自動聚類,但方向仍靠書寫順序保證。
|
||||
4. **向後相容**:純 `[[A]]` 仍合法(無類型邊),盡量補謂詞。
|
||||
2. **謂詞用動詞 / 動詞短語**(反駁、奠基於、犧牲),天然帶方向。**禁名詞當謂詞**——`>> 存儲格式 >>`、`>> 操作體驗 >>` 讀不通,是錯的。
|
||||
3. **謂詞自由書寫但別太天馬行空**:寫「參考/參照」皆可(下游 embed 自動聚類同義謂詞),別寫「瞄了一眼」這種抓不到同義的。
|
||||
4. **內文三元組端點用裸文字**(非 `[[wikilink]]`),避免在 Logseq 產生大量紅色斷鏈;卡對卡那層才用 `[[]]`。
|
||||
5. **向後相容**:純 `[[A]]` 仍合法(無類型邊),盡量補謂詞。
|
||||
|
||||
> **★ 硬自檢(Haiku 量產必備護欄)★** —— 內文三元組的「端點 = `## 實體` 詞條」
|
||||
> `A >> 謂詞 >> B` 的 A、B 必須與 `## 實體` 某個粗體正規名【一字不差】。**寫完後逐條自檢**:把 A、B 拿去 `## 實體` 找有沒有完全相同的正規名,沒有 → 這條錯了。
|
||||
> 修法擇一:(a) 改用實體表已有的詞;(b) 端點確是重要實體 → 補進 `## 實體` 再指它。
|
||||
> 禁止:端點帶括號註解、端點是整句補語、端點是形容詞短語。
|
||||
> (實證:光寫規則 Haiku 會略過,端點對不齊 14 條;寫成自檢動作後 14→0。跑 1-2 張看不出,跑 12 張才暴露。)
|
||||
|
||||
`>>` 為分隔語法,全程一致即可。這是 Karpathy LLM Wiki「知識互連」的強化版——連結不只存在,還帶類型與方向。
|
||||
|
||||
@@ -166,7 +186,9 @@ cards/<bucket>/
|
||||
- **在知識生產的當下、由整理者(CC / Cowork)建**:gloss 跟三元組同階段萃,**不留給下游 ingest 臨時補**——下游只有單檔/跨庫視角,編不出貼合的 gloss。
|
||||
- **選填、deep tier 才產**:淺萃不浪費。
|
||||
- **gloss ≠ 摘要**:`gloss` 是 frontmatter 給機器 normalize 的定義句(「X 是…」);`## 摘要` 是給人讀的核心句。
|
||||
- **對齊下游 envelope**:frontmatter `gloss:` 對應 ingest envelope 的 `nodes[].gloss`。
|
||||
- **兩層 gloss**:① frontmatter `gloss:` 描述「卡標題」這個 node;② `## 實體` 區塊的每行描述句,描述「內文實體」這些 node。**內文實體也是 graph node、也需描述句**才能被下游 embedding normalize(`黃仁勳` vs `Jensen Huang` 靠描述拉近向量)。
|
||||
- **實體要描述、謂詞不用**:實體同義詞字面差遠需描述拉近;謂詞同義詞字面本就近,裸詞 embed 自動聚類。
|
||||
- **對齊下游 envelope**:frontmatter `gloss:` 與 `## 實體` 詞條對應 ingest envelope 的 `nodes[].gloss`。
|
||||
|
||||
> **改寫時必守**:① 絕不寫入 raw source(只往 `cards/<bucket>/` 寫,事後驗 raw source 0 異動);② 檔名=卡片全名,冒號用全形「:」、斜線用全形「/」,全程一種字元避免斷鏈。
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@ t() { if [ "$IS_ZH" = "yes" ]; then printf '%s\n' "$1"; else printf '%s\n' "$2";
|
||||
# tn = 不換行版(給 prompt 用)
|
||||
tn() { if [ "$IS_ZH" = "yes" ]; then printf '%s' "$1"; else printf '%s' "$2"; fi; }
|
||||
|
||||
REPO_URL="https://raw.githubusercontent.com/uncle6me-web/system-dev-template/main/template"
|
||||
REPO_URL="https://git.uncle6.me/Leo/system-dev-template/raw/branch/main/template"
|
||||
# install.sh / update.sh 住在 main/scripts/(不在 template/)。
|
||||
SCRIPTS_URL="https://raw.githubusercontent.com/uncle6me-web/system-dev-template/main/scripts"
|
||||
SCRIPTS_URL="https://git.uncle6.me/Leo/system-dev-template/raw/branch/main/scripts"
|
||||
CREATED=()
|
||||
SKIPPED=()
|
||||
|
||||
@@ -103,6 +103,25 @@ echo ""
|
||||
t "📦 安裝模組:$MODULE" "📦 Module: $MODULE"
|
||||
echo ""
|
||||
|
||||
# ── 重複安裝防呆(1.10.1):install 只管「全新安裝」,一切後續歸 update ──
|
||||
# 判準是「裝過沒」,不分新版舊版:
|
||||
# - 新結構 system-dev/ 已存在,或
|
||||
# - 舊結構 .claude/wiki/ 或 .claude/VERSION 存在(裝過舊版、待遷移)
|
||||
# 裝過了還跑 install → 會重複建範本、甚至跟真資料並存(先 install 建空殼,遷移就被擋)。
|
||||
# 正解:偵測到裝過 → 不動任何東西,導去 update(更新/遷移/補新檔都由它處理)。
|
||||
if [ -d "system-dev" ] || [ -d ".claude/wiki" ] || [ -f ".claude/VERSION" ]; then
|
||||
t "🛑 偵測到這個專案已經安裝過 system-dev-template。" \
|
||||
"🛑 system-dev-template is already installed in this project."
|
||||
t " 後續的更新、遷移、補新檔,一律由「更新腳本」處理(不要重跑 install):" \
|
||||
" All updates, migrations, and new-file additions are handled by the UPDATER (don't re-run install):"
|
||||
echo ""
|
||||
echo " curl -sSL https://git.uncle6.me/Leo/system-dev-template/raw/branch/main/scripts/update.sh | bash"
|
||||
echo ""
|
||||
t " (重跑 install 可能建出空白範本、跟你的真資料並存,故在此停止。)" \
|
||||
" (Re-running install could create empty templates alongside your real data, so it stops here.)"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# ── 偵測 vault 類型 → 決定 raw source(原始文件)路徑 ──────────
|
||||
# 為什麼:這個模板原本假設「原始文件在 docs/」,但 Logseq / Obsidian
|
||||
# 這種 PKM vault 有自己的目錄慣例,整理時不能照 docs/ 那套搬動,
|
||||
@@ -235,6 +254,10 @@ create_dir ".claude/commands"
|
||||
create_dir ".claude/hooks"
|
||||
download_if_missing "system-dev/docs/README.md" "$REPO_URL/system-dev/docs/README.md"
|
||||
|
||||
# Logseq 任務 marker 解析(單一真相源):vault 萃取(/wiki-extract)與 tasks→Project
|
||||
# 投影(tasks-project-sync)共用同一套解析,別各寫一份。放共用區,兩模組都拿得到。
|
||||
download_if_missing "system-dev/docs/4-guides/logseq-markers.md" "$REPO_URL/system-dev/docs/4-guides/logseq-markers.md"
|
||||
|
||||
# 工具版號:放 system-dev/,不寄生 .claude/。
|
||||
download_if_missing "system-dev/VERSION" "$REPO_URL/system-dev/VERSION"
|
||||
|
||||
@@ -258,6 +281,8 @@ if $WANT_WIKI; then
|
||||
download_if_missing ".claude/commands/wiki-capture.md" "$REPO_URL/.claude/commands/wiki-capture.md"
|
||||
download_if_missing ".claude/commands/wiki-update.md" "$REPO_URL/.claude/commands/wiki-update.md"
|
||||
download_if_missing ".claude/commands/wiki-recall.md" "$REPO_URL/.claude/commands/wiki-recall.md"
|
||||
# vault 增量萃取(Logseq/Obsidian → system-dev/wiki,冪等):給 Routine 反覆跑。
|
||||
download_if_missing ".claude/commands/wiki-extract.md" "$REPO_URL/.claude/commands/wiki-extract.md"
|
||||
|
||||
# wiki 相關 hooks:接關 + 機敏掃描
|
||||
download_if_missing ".claude/hooks/session-start-recall.sh" "$REPO_URL/.claude/hooks/session-start-recall.sh"
|
||||
@@ -277,6 +302,18 @@ if $WANT_SDD; then
|
||||
|
||||
download_if_missing ".claude/commands/sdd-check.md" "$REPO_URL/.claude/commands/sdd-check.md"
|
||||
download_if_missing ".claude/hooks/sdd-guard.sh" "$REPO_URL/.claude/hooks/sdd-guard.sh"
|
||||
|
||||
# SDD 生命週期鐵律(1.14,issue #6):規則真相源 + 規格變更緩衝區 + 獨立單一活性檢查
|
||||
download_if_missing "system-dev/docs/3-specs/SDD-LIFECYCLE.md" "$REPO_URL/system-dev/docs/3-specs/SDD-LIFECYCLE.md"
|
||||
download_if_missing "system-dev/docs/3-specs/pending-changes.md" "$REPO_URL/system-dev/docs/3-specs/pending-changes.md"
|
||||
download_if_missing "system-dev/scripts/sdd-active-check.sh" "$REPO_URL/scripts/sdd-active-check.sh"
|
||||
|
||||
# ── tasks⇄Project 投影(optional,issue #16)──────────────────
|
||||
# 帶檔 ≠ 啟用:workflow yaml 只是「留記錄+手動啟用素材」,啟用=對話答好且 acr push。
|
||||
# 投影邏輯依附 tasks.md(住 3-specs),故隨 SDD 模組帶下來;裝了不代表開。
|
||||
create_dir "system-dev/workflows"
|
||||
download_if_missing "system-dev/workflows/tasks-project-sync.yaml" "$REPO_URL/system-dev/workflows/tasks-project-sync.yaml"
|
||||
download_if_missing "system-dev/workflows/tasks-project-sync.local.sh" "$REPO_URL/system-dev/workflows/tasks-project-sync.local.sh"
|
||||
fi
|
||||
|
||||
# ── 安裝/更新腳本:一開始就放進 system-dev/scripts/ ──
|
||||
@@ -293,6 +330,8 @@ download_if_missing ".claude/hooks/pre-write-guard.sh" "$REPO_URL/.claude/hooks/
|
||||
download_if_missing ".claude/commands/issue-handle.md" "$REPO_URL/.claude/commands/issue-handle.md"
|
||||
|
||||
chmod +x .claude/hooks/*.sh 2>/dev/null || true
|
||||
chmod +x system-dev/workflows/*.sh 2>/dev/null || true
|
||||
chmod +x system-dev/scripts/*.sh 2>/dev/null || true
|
||||
|
||||
# ── 依模組產生 settings.json 的 hooks 區塊 ────────
|
||||
# settings.json 因模組而異,不能直接下載單一靜態檔,改條件組裝。
|
||||
@@ -447,6 +486,19 @@ fi
|
||||
if $WANT_SDD; then
|
||||
t " 動 code 前先在 system-dev/docs/3-specs/[子系統]/ 建 design.md(可用 /sdd-check 協助)" \
|
||||
" Before touching code, create design.md under system-dev/docs/3-specs/[subsystem]/ (use /sdd-check to help)"
|
||||
# ── tasks⇄Project 投影:裝/init 對話 + 一次性廣告(issue #16)──
|
||||
# 判準=能力(arcrun 裝了沒)+意願,不掃檔。落地成「CC 問一句」,install 只是交代 CC 去問。
|
||||
echo ""
|
||||
t " ❓ 待辦同步(optional,需 Arcrun):請你的 CC 問你一句——" \
|
||||
" ❓ Task sync (optional, needs Arcrun): have your CC ask you once —"
|
||||
t " 「您需要把本專案的待辦事項(tasks.md)同步到 GitHub 嗎?」" \
|
||||
" \"Do you want this project's tasks (tasks.md) mirrored to GitHub?\""
|
||||
t " 答「好」→ CC 查環境有沒有 Arcrun(mcp / acr 在 PATH):有就設定同步、沒有就一次性告知" \
|
||||
" Yes → CC checks for Arcrun (mcp / acr in PATH): set it up if present, otherwise inform you once"
|
||||
t " 「Arcrun 是免費的 AI-friendly 工作流套件,想裝跟 Claude 說就行;之後也可手動啟用」。" \
|
||||
" \"Arcrun is a free AI-friendly workflow toolkit — ask Claude to install it; you can also enable sync later.\""
|
||||
t " 答「不好」→ 不做、不再追問。投影 workflow 在 system-dev/workflows/(帶檔≠啟用)。" \
|
||||
" No → nothing happens, no nagging. The projection workflow sits in system-dev/workflows/ (shipped ≠ enabled)."
|
||||
fi
|
||||
t " GitHub issue:CC 可直接 /issue-handle 讀回自己 repo 的 issue(禁自動輪詢)" \
|
||||
" GitHub issues: CC can use /issue-handle to read issues from its own repo (no auto-polling)"
|
||||
|
||||
@@ -23,7 +23,7 @@ esac
|
||||
t() { if [ "$IS_ZH" = "yes" ]; then printf '%s\n' "$1"; else printf '%s\n' "$2"; fi; }
|
||||
tn() { if [ "$IS_ZH" = "yes" ]; then printf '%s' "$1"; else printf '%s' "$2"; fi; }
|
||||
|
||||
REPO_RAW="https://raw.githubusercontent.com/uncle6me-web/system-dev-template/main"
|
||||
REPO_RAW="https://git.uncle6.me/Leo/system-dev-template/raw/branch/main"
|
||||
TEMPLATE_URL="$REPO_RAW/template"
|
||||
|
||||
UPDATED=()
|
||||
@@ -31,6 +31,7 @@ KEPT=()
|
||||
NEW=()
|
||||
TEMPLATED=()
|
||||
MIGRATED=()
|
||||
COEXIST=()
|
||||
|
||||
# ── 版本比對:先看本機 vs 遠端,給使用者「值不值得更新」的判斷 ──
|
||||
# VERSION 新位置在 system-dev/,舊位置在 .claude/(1.8.x 以前)。優先讀新、回退舊。
|
||||
@@ -82,7 +83,12 @@ migrate_dir() { # $1=舊路徑 $2=新路徑
|
||||
local from="$1" to="$2"
|
||||
[ -e "$from" ] || return 0 # 舊的不存在 → 無需遷移
|
||||
if [ -e "$to" ]; then
|
||||
return 0 # 新的已存在 → 冪等略過,不覆蓋
|
||||
# 目的地已存在。兩種可能:
|
||||
# (a) 已遷移過 → 舊位置不該還在;冪等略過即可。
|
||||
# (b) 用戶先 install 建了空殼 → 舊位置仍有真資料,現在「並存」。
|
||||
# 不能靜默跳過 (b),也絕不自動合併(覆蓋風險)。→ 記為「並存待合併」,警告。
|
||||
COEXIST+=("$from ↔ $to")
|
||||
return 0
|
||||
fi
|
||||
mkdir -p "$(dirname "$to")"
|
||||
if mv "$from" "$to" 2>/dev/null; then
|
||||
@@ -211,15 +217,26 @@ keep_with_template ".claude/hooks/pre-write-guard.sh" "$TEMPLATE_URL/.claude/hoo
|
||||
update_file ".claude/commands/issue-handle.md" "$TEMPLATE_URL/.claude/commands/issue-handle.md"
|
||||
update_file "system-dev/VERSION" "$TEMPLATE_URL/system-dev/VERSION"
|
||||
|
||||
# Logseq 任務 marker 解析(單一真相源):vault 萃取(/wiki-extract)與 tasks→Project
|
||||
# 投影共用同一套;任一模組在用就補/更新(邏輯檔,可覆蓋)。
|
||||
if $HAS_WIKI || $HAS_SDD; then
|
||||
update_file "system-dev/docs/4-guides/logseq-markers.md" "$TEMPLATE_URL/system-dev/docs/4-guides/logseq-markers.md"
|
||||
fi
|
||||
|
||||
if $HAS_WIKI; then
|
||||
# wiki 的「邏輯檔」:導航與 hooks,可覆蓋。wiki 資料在 system-dev/,hooks/commands 留 .claude/。
|
||||
update_file "system-dev/wiki/INDEX.md" "$TEMPLATE_URL/system-dev/wiki/INDEX.md"
|
||||
update_file ".claude/hooks/session-start-recall.sh" "$TEMPLATE_URL/.claude/hooks/session-start-recall.sh"
|
||||
update_file ".claude/hooks/wiki-secret-scan.sh" "$TEMPLATE_URL/.claude/hooks/wiki-secret-scan.sh"
|
||||
# 1.16.0:讓 wiki 真的被讀到的兩支(開場 push 全文解決不了「只讀開頭」,見 CHANGELOG)
|
||||
update_file ".claude/hooks/wiki-first-search.sh" "$TEMPLATE_URL/.claude/hooks/wiki-first-search.sh"
|
||||
update_file ".claude/hooks/subagent-wiki-guard.sh" "$TEMPLATE_URL/.claude/hooks/subagent-wiki-guard.sh"
|
||||
update_file ".claude/commands/wiki-init.md" "$TEMPLATE_URL/.claude/commands/wiki-init.md"
|
||||
update_file ".claude/commands/wiki-capture.md" "$TEMPLATE_URL/.claude/commands/wiki-capture.md"
|
||||
update_file ".claude/commands/wiki-update.md" "$TEMPLATE_URL/.claude/commands/wiki-update.md"
|
||||
update_file ".claude/commands/wiki-recall.md" "$TEMPLATE_URL/.claude/commands/wiki-recall.md"
|
||||
# vault 增量萃取(Logseq/Obsidian → system-dev/wiki,冪等):邏輯檔,可覆蓋。舊版沒有 → 當新檔補。
|
||||
update_file ".claude/commands/wiki-extract.md" "$TEMPLATE_URL/.claude/commands/wiki-extract.md"
|
||||
# Cowork(claude.ai)的 wiki 整理 skill:規則檔,可覆蓋
|
||||
update_file "system-dev/docs/SKILL.md" "$TEMPLATE_URL/system-dev/docs/SKILL.md"
|
||||
|
||||
@@ -240,6 +257,18 @@ if $HAS_SDD; then
|
||||
update_file "system-dev/docs/2-architecture/decisions/TEMPLATE-adr.md" "$TEMPLATE_URL/system-dev/docs/2-architecture/decisions/TEMPLATE-adr.md"
|
||||
update_file ".claude/commands/sdd-check.md" "$TEMPLATE_URL/.claude/commands/sdd-check.md"
|
||||
update_file ".claude/hooks/sdd-guard.sh" "$TEMPLATE_URL/.claude/hooks/sdd-guard.sh"
|
||||
|
||||
# SDD 生命週期鐵律(1.14,issue #6):規則檔+獨立檢查腳本=邏輯檔可覆蓋;
|
||||
# pending-changes.md 裝著用戶的 proposal=用戶資料,只補不覆蓋。
|
||||
# (issue #13 教訓:update 不補新檔會造成結構斷層,新檔必須在這裡鋪。)
|
||||
update_file "system-dev/docs/3-specs/SDD-LIFECYCLE.md" "$TEMPLATE_URL/system-dev/docs/3-specs/SDD-LIFECYCLE.md"
|
||||
add_if_missing "system-dev/docs/3-specs/pending-changes.md" "$TEMPLATE_URL/system-dev/docs/3-specs/pending-changes.md"
|
||||
update_file "system-dev/scripts/sdd-active-check.sh" "$TEMPLATE_URL/scripts/sdd-active-check.sh"
|
||||
|
||||
# tasks⇄Project 投影(issue #16):邏輯檔,可覆蓋。舊版沒有 → add_if_missing 補。
|
||||
# 啟用狀態存遠端(acr push),不在這些檔裡,覆蓋不會關掉誰的同步。
|
||||
add_if_missing "system-dev/workflows/tasks-project-sync.yaml" "$TEMPLATE_URL/system-dev/workflows/tasks-project-sync.yaml"
|
||||
add_if_missing "system-dev/workflows/tasks-project-sync.local.sh" "$TEMPLATE_URL/system-dev/workflows/tasks-project-sync.local.sh"
|
||||
fi
|
||||
|
||||
# ── 自我更新:把最新的 update.sh / install.sh 抓到 system-dev/scripts/ ──
|
||||
@@ -247,7 +276,7 @@ fi
|
||||
update_file "system-dev/scripts/update.sh" "$REPO_RAW/scripts/update.sh"
|
||||
update_file "system-dev/scripts/install.sh" "$REPO_RAW/scripts/install.sh"
|
||||
|
||||
chmod +x .claude/hooks/*.sh system-dev/scripts/*.sh 2>/dev/null || true
|
||||
chmod +x .claude/hooks/*.sh system-dev/scripts/*.sh system-dev/workflows/*.sh 2>/dev/null || true
|
||||
|
||||
# ── 使用者資料檔:絕不碰,但提醒「設定可能有新欄位要手動補」──
|
||||
keep_file ".claude/settings.json"
|
||||
@@ -261,6 +290,18 @@ if [ ${#MIGRATED[@]} -gt 0 ]; then
|
||||
t "📦 結構遷移(已收進 system-dev/):" "📦 Layout migrated (moved into system-dev/):"
|
||||
for f in "${MIGRATED[@]}"; do echo " ⇒ $f"; done
|
||||
fi
|
||||
if [ ${#COEXIST[@]} -gt 0 ]; then
|
||||
echo ""
|
||||
t "🛑 偵測到 wiki 並存(新舊位置都有資料,需要合併):" \
|
||||
"🛑 Coexisting wiki detected (both old and new locations have data — needs merging):"
|
||||
for f in "${COEXIST[@]}"; do echo " ↔ $f"; done
|
||||
t " 成因:先跑過 install(建了空殼)才遷移,舊位置真資料沒被搬。" \
|
||||
" Cause: install ran first (created an empty shell), so migration skipped your real data in the old location."
|
||||
t " 不自動合併(避免覆蓋你的資料)。請叫你的 CC:" \
|
||||
" Not auto-merged (to avoid overwriting your data). Ask your CC:"
|
||||
t " 「.claude/wiki/ 和 system-dev/wiki/ 並存,請逐檔比對、把真資料合進 system-dev/,再刪舊的」" \
|
||||
" \"There are two wikis (.claude/wiki/ and system-dev/wiki/) — diff each file, merge the real data into system-dev/, then delete the old one.\""
|
||||
fi
|
||||
if [ ${#NEW[@]} -gt 0 ]; then
|
||||
echo ""
|
||||
t "🆕 新功能(舊版沒有,已加入):" "🆕 New features (absent in the old version, now added):"
|
||||
@@ -299,6 +340,34 @@ if [ -f ".claude/settings.json" ]; then
|
||||
$HAS_WIKI && ! grep -q "session-start-recall.sh" .claude/settings.json && MISSING+=("SessionStart: session-start-recall.sh")
|
||||
$HAS_WIKI && ! grep -q "wiki-secret-scan.sh" .claude/settings.json && MISSING+=("PreToolUse(Write|Edit): wiki-secret-scan.sh")
|
||||
$HAS_SDD && ! grep -q "sdd-guard.sh" .claude/settings.json && MISSING+=("PreToolUse(Write|Edit): sdd-guard.sh")
|
||||
|
||||
# ── 1.16.0:兩支 wiki 讀取 hook 自動註冊(不只提醒)──
|
||||
# 理由:這兩支的整個存在意義就是「不依賴任何人記得」。
|
||||
# 若靠人看提醒去手動補 settings.json,等於把同一個病搬到安裝環節。
|
||||
if $HAS_WIKI && command -v python3 >/dev/null 2>&1; then
|
||||
python3 - <<'PYEOF' 2>/dev/null || true
|
||||
import json, os
|
||||
p = ".claude/settings.json"
|
||||
try:
|
||||
with open(p) as f: d = json.load(f)
|
||||
except Exception:
|
||||
raise SystemExit(0) # 壞掉的 settings 不碰,交給下方提醒
|
||||
pre = d.setdefault("hooks", {}).setdefault("PreToolUse", [])
|
||||
blob = json.dumps(pre)
|
||||
added = []
|
||||
if "wiki-first-search" not in blob:
|
||||
pre.append({"matcher": "Grep|Glob|Read", "hooks": [
|
||||
{"type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/wiki-first-search.sh"}]})
|
||||
added.append("wiki-first-search")
|
||||
if "subagent-wiki-guard" not in blob:
|
||||
pre.append({"matcher": "Task", "hooks": [
|
||||
{"type": "command", "command": "$CLAUDE_PROJECT_DIR/.claude/hooks/subagent-wiki-guard.sh"}]})
|
||||
added.append("subagent-wiki-guard")
|
||||
if added:
|
||||
with open(p, "w") as f: json.dump(d, f, ensure_ascii=False, indent=2)
|
||||
print(" ✅ 已自動註冊 wiki 讀取 hook:" + "、".join(added))
|
||||
PYEOF
|
||||
fi
|
||||
if [ ${#MISSING[@]} -gt 0 ]; then
|
||||
echo ""
|
||||
t "📌 settings.json 是你的設定(沒動),但偵測到缺以下 hook,請手動補上:" \
|
||||
|
||||
@@ -39,21 +39,6 @@
|
||||
INDEX 是**所有檢索角度的入口**,不只標籤。原文是唯讀 SSoT,wiki 是改寫過的記憶。
|
||||
新增角度只要在這裡加一節(如「決策角度」「原則角度」),指向對應 cards 或 push 檔——**不必新增實體特殊檔**。
|
||||
|
||||
### 快速導航(本專案速覽)
|
||||
|
||||
**這個專案是什麼**:KBDB-graph —— KBDB 的 graph 插件(triplet 採集 + graph 查詢),類比 Apache AGE 之於 Postgres。已抽成獨立 public repo `uncle6me-web/kbdb-graph-plugin`(leo 產權)。基本盤(block CRUD,D1 三表)在 `arcrun/kbdb`,不在這。
|
||||
|
||||
**動工前必讀**:
|
||||
- `docs/HANDOFF-kbdb-plugin.md` —— 本目錄專屬交棒。
|
||||
- 上游約束見 `CLAUDE.md` 最頂 + `github.com/uncle6me-web/InkStoneCo`。
|
||||
|
||||
**文件去哪找**:
|
||||
- SDD(design+tasks)→ `docs/3-specs/`(現有:kbdb-graph-extraction、blocks-edit-api、plugin-install、arcrun-key-auth)
|
||||
- 歷史記錄 / bug 復盤 → `docs/5-records/`(PATCH 403 bug、upsert feature request)
|
||||
- 分類規則全表 → `docs/README.md`
|
||||
|
||||
**絕對限制**:本目錄只做 graph 插件 / **API-as-Wall(插件絕不碰表、零 SQL、零 migration、零建表)** / 部署繞開 GitHub、禁跨 repo Actions / 樂高法(actions < 100 行)。
|
||||
|
||||
### 標籤角度(按 `TAXONOMY.md` 的軸聚類,指向桶子索引)
|
||||
|
||||
```markdown
|
||||
@@ -64,17 +49,11 @@ INDEX 是**所有檢索角度的入口**,不只標籤。原文是唯讀 SSoT
|
||||
- [[ai/00-INDEX]] — AI 協作(M 卡)
|
||||
```
|
||||
|
||||
(尚未建 cards,現有決策見下「決策角度」。)
|
||||
### 決策角度(取代舊 decisions-summary.md 的視圖)
|
||||
|
||||
### 決策角度(取代舊 decisions-summary.md 的視圖;完整脈絡見 `decisions-summary.md` + `docs/2-architecture/decisions/`)
|
||||
|
||||
- **KBDB-graph 定位**(2026-06-13)— 本 repo = KBDB 的 graph 插件,獨立成 repo,類比 AGE 之於 Postgres。
|
||||
- **🔒 KBDB 鐵律 + API-as-Wall**(2026-06-14,最高原則)— 插件絕不碰表、零 SQL、零 migration,讀寫全走基本盤 HTTP API;新類型=建 template+填 slot,永不建表。
|
||||
- **獨立 repo 名**(2026-06-14)— public `uncle6me-web/kbdb-graph-plugin`,無 Actions。
|
||||
- **掛載介面 = 基本盤 API(非共用 D1)**(2026-06-14,推翻原判斷)— 圖在插件層記憶體從 records 組裝,不直接 SQL、不建 VIEW。
|
||||
- **安裝契約:KBDB_BASE_URL 安裝時 AI 填**(2026-06-14)— AI 查 CF subdomain 拼 URL → `wrangler secret put` + `deploy`;本地測試用 `.dev.vars`。
|
||||
- **~~萬物皆 Block(v3)~~**(2026-02-28 提出,2026-06-14 淘汰)— 帶獨立 blocks 表的「v3」是違規殘留已刪;基本盤真身 = arcrun/kbdb 3 表。
|
||||
- **避免再被 GitHub flag**(上游鐵律)— 禁跨 repo 自動同步 Actions;部署繞開 GitHub。
|
||||
```markdown
|
||||
- [[某決策卡]] — 一句話結論(YYYY-MM-DD)
|
||||
```
|
||||
|
||||
> 結構:INDEX(多角度入口)→ `cards/<bucket>/00-INDEX.md`(桶子索引,固定名)→ 概念原子卡。
|
||||
> 指 `00-INDEX` **一律帶路徑** `[[bucket/00-INDEX]]`(固定名跨桶撞名);卡片間用裸 `[[卡名]]`。
|
||||
|
||||
Reference in New Issue
Block a user