dowafu 0.1.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +58 -25
- package/README_zh-tw.md +197 -0
- package/dist/adapters/anthropic-messages.js +18 -11
- package/dist/adapters/gemini-native.js +19 -16
- package/dist/adapters/read-file-tool-description.js +5 -0
- package/dist/adapters/responses.js +26 -14
- package/dist/audit.js +17 -1
- package/dist/cli-args.js +103 -38
- package/dist/cli.js +78 -43
- package/dist/dispatch-home.js +24 -6
- package/dist/doctor.js +91 -0
- package/dist/error-classify.js +13 -4
- package/dist/gate.js +3 -2
- package/dist/mask.js +16 -3
- package/dist/messages.js +396 -0
- package/dist/output.js +60 -37
- package/dist/prompt.js +5 -3
- package/dist/providers.js +46 -34
- package/dist/raw-integrity.js +6 -5
- package/dist/report.js +76 -22
- package/dist/runner.js +21 -10
- package/dist/ticket.js +35 -25
- package/dist/validate.js +21 -20
- package/dist/whitelist.js +9 -1
- package/package.json +3 -2
- package/providers.json +8 -3
- package/publish/en/.agents/skills/find-holes-external/SKILL.md +450 -0
- package/publish/en/.agents/skills/preflight/SKILL.md +137 -0
- package/publish/en/.agents/skills/wrap/SKILL.md +64 -0
- package/publish/en/.claude/agents/explore-haiku.md +8 -0
- package/publish/en/.claude/agents/hole-finder-cost.md +15 -0
- package/publish/en/.claude/agents/hole-finder-feasibility.md +15 -0
- package/publish/en/.claude/agents/hole-finder-safety.md +15 -0
- package/publish/en/.claude/agents/hole-finder.md +14 -0
- package/publish/en/.claude/skills/find-holes/SKILL.md +114 -0
- package/publish/en/.claude/skills/find-holes-external/SKILL.md +463 -0
- package/publish/en/.claude/skills/preflight/SKILL.md +198 -0
- package/publish/en/.claude/skills/wrap/SKILL.md +61 -0
- package/publish/en/README.md +106 -0
- package/publish/en/workflow_spec.md +71 -0
- package/publish/{.agents → zh-tw/.agents}/skills/find-holes-external/SKILL.md +195 -20
- package/publish/{.agents → zh-tw/.agents}/skills/preflight/SKILL.md +49 -7
- package/publish/{.claude → zh-tw/.claude}/skills/find-holes/SKILL.md +32 -4
- package/publish/{.claude → zh-tw/.claude}/skills/find-holes-external/SKILL.md +194 -19
- package/publish/{.claude → zh-tw/.claude}/skills/preflight/SKILL.md +51 -6
- package/publish/{README.md → zh-tw/README.md} +16 -0
- /package/publish/{.agents → zh-tw/.agents}/skills/wrap/SKILL.md +0 -0
- /package/publish/{.claude → zh-tw/.claude}/agents/explore-haiku.md +0 -0
- /package/publish/{.claude → zh-tw/.claude}/agents/hole-finder-cost.md +0 -0
- /package/publish/{.claude → zh-tw/.claude}/agents/hole-finder-feasibility.md +0 -0
- /package/publish/{.claude → zh-tw/.claude}/agents/hole-finder-safety.md +0 -0
- /package/publish/{.claude → zh-tw/.claude}/agents/hole-finder.md +0 -0
- /package/publish/{.claude → zh-tw/.claude}/skills/wrap/SKILL.md +0 -0
- /package/publish/{workflow_spec.md → zh-tw/workflow_spec.md} +0 -0
|
@@ -60,6 +60,11 @@ system prompt 來源——角色、禁令、輸出格式、收尾句都在裡面
|
|
|
60
60
|
cd <repo 根的絕對路徑> && dowafu <工單目錄> --repo-root . --dry-run
|
|
61
61
|
```
|
|
62
62
|
|
|
63
|
+
**`--lang` 決定 CLI 輸出與 spoke prompt 的語言,預設是 `en`。** 你裝的是中文套件、lens 檔也是
|
|
64
|
+
中文的,所以**中文專案要帶 `--lang zh-tw`**——不帶的話 CLI 會用英文輸出,spoke 也會拿到英文
|
|
65
|
+
prompt,而**兩邊都不會報錯,只是安靜地混語**。不想每次打,可以設環境變數 `DISPATCH_LANG=zh-tw`;
|
|
66
|
+
優先序是 `--lang` > `DISPATCH_LANG` > 內建預設 `en`。
|
|
67
|
+
|
|
63
68
|
你的終端機不保證落在哪一個 workspace folder,而 `--repo-root` 預設取 cwd。cwd 錯了會
|
|
64
69
|
**安靜地錯**——工單照樣解析、spoke 照樣派出去,只是白名單邊界與 lens 定義都指到別處。
|
|
65
70
|
|
|
@@ -87,8 +92,8 @@ dowafu --version
|
|
|
87
92
|
**四、實跑用背景執行,進度靠檔案而不是終端機輸出。**
|
|
88
93
|
|
|
89
94
|
用檔案讀取工具輪詢 `tmp/spoke/<ticket-id>/run.jsonl`:CLI 逐事件寫入該檔,讀得出跑到
|
|
90
|
-
哪一輪、有沒有 `round_error
|
|
91
|
-
|
|
95
|
+
哪一輪、有沒有 `round_error`。**完成判定見 §5**——「兩個 `spoke_end`」只是其中一半。
|
|
96
|
+
背景終端機的輸出不保證拿得到,而單支 spoke 可能跑上好幾分鐘。
|
|
92
97
|
|
|
93
98
|
> **把終端機當啟動器,不要當資料通道。**
|
|
94
99
|
|
|
@@ -106,6 +111,7 @@ dowafu --version
|
|
|
106
111
|
| 每個 spoke 的 provider/model | 見下 |
|
|
107
112
|
| **每題的「問題 → 答案在哪個檔 → 在清單裡嗎」對照** | **必列,見下方格式** |
|
|
108
113
|
| 預估成本量級 | 參考值:三個 spoke、中等工單約 40k token |
|
|
114
|
+
| **每支 spoke 的產物落點** | **必列**,見下方〈幾支 spoke 就要幾個落點〉 |
|
|
109
115
|
|
|
110
116
|
### 具體問題與允許清單**必須逐題對照著列**
|
|
111
117
|
|
|
@@ -132,6 +138,50 @@ dowafu --version
|
|
|
132
138
|
換一批對準答案位置的檔案,同一個 lens 就抓得到。**這個自問是為了在派工前擋下落差,
|
|
133
139
|
不是派工後才發現。**
|
|
134
140
|
|
|
141
|
+
### 每支 spoke 各一張表——而且**那張表本身就是交件物,不是「我有做」的宣告**
|
|
142
|
+
|
|
143
|
+
**那張表每支 spoke 各填一張,而且兩張都要攤在使用者面前。** 說「清單都對過了」「該有的檔都在」
|
|
144
|
+
**不能取代把表給他看**——「允許清單已涵蓋所有問題」只是一句話,真假都一樣好寫。
|
|
145
|
+
|
|
146
|
+
每一列要寫**你實際預期答案所在的那個檔的路徑**——不是目錄、不是「tags 那幾支路由」、
|
|
147
|
+
不是 lens 的名字。寫成與允許清單同樣的形式,兩邊才對得起來:
|
|
148
|
+
|
|
149
|
+
| Q | 問題 | 答案在哪個檔 | 在清單裡嗎 |
|
|
150
|
+
| --- | --- | --- | --- |
|
|
151
|
+
| 1 | `requireAuth` 回傳的 userId 夠不夠做刪除自己的檢查 | `lib/auth-guard.ts` | ✅ |
|
|
152
|
+
| 2 | 最後一位管理員的防護是不是原子的 | `prisma/schema.prisma`(其餘看待審段落本身) | ✅ |
|
|
153
|
+
|
|
154
|
+
**把路徑寫進那一欄之前,先確認答案真的在那個檔裡**——grep 那個符號,或直接開檔。
|
|
155
|
+
這一欄是為了在派工前擋下漏檔;**憑印象填的話它什麼都擋不住**:一個看起來很合理的檔名,
|
|
156
|
+
與正確的那個一樣能通過格式檢查,而差額是 spoke 用錢付的。
|
|
157
|
+
|
|
158
|
+
**兩支最後拿到同一批檔也可以,但要說得出為什麼。** 清單相同是**可以解釋的結論**,不是起點;
|
|
159
|
+
而「裁到兩份不一樣為止」是同一個錯誤的反面。
|
|
160
|
+
|
|
161
|
+
**一份清單餵兩支 lens,會往交集收斂,而不是聯集。** 最先掉的是「只有其中一支需要」的檔,
|
|
162
|
+
而那正是那支 lens 被派去看的東西;spoke 這時只能把缺口寫進「無法驗證」欄,而用這種方式
|
|
163
|
+
發現要付一整輪派工的錢。為省錢裁清單是合理的——但要**各自對著自己的問題裁,不是對著另一支裁**。
|
|
164
|
+
|
|
165
|
+
### 幾支 spoke 就要幾個落點——先挖好坑再派
|
|
166
|
+
|
|
167
|
+
一支 spoke 的產物落在 `tmp/spoke/<ticket-id>/` 底下**以它的 agent 為名的那一組檔**:
|
|
168
|
+
`<agent>.md`,以及 `raw/<agent>.request.json`/`.response.json`/`.errors.json`。
|
|
169
|
+
那一組同進同出,所以**落點就是 `<ticket-id>` + `<agent>` 這個組合**。
|
|
170
|
+
|
|
171
|
+
**派工計畫要逐支列出落點路徑,判準只有一句:落點數要等於 spoke 數,而且兩兩不同。**
|
|
172
|
+
|
|
173
|
+
| spoke | lens | provider/model | 產物落點 |
|
|
174
|
+
| --- | --- | --- | --- |
|
|
175
|
+
| 1 | safety | openai/gpt-5.6-luna | `tmp/spoke/auth-review-luna/hole-finder-safety.md` |
|
|
176
|
+
| 2 | safety | deepseek/deepseek-v4-flash | `tmp/spoke/auth-review-ds/hole-finder-safety.md` |
|
|
177
|
+
| 3 | feasibility | gemini/gemini-3.6-flash | `tmp/spoke/auth-review-luna/hole-finder-feasibility.md` |
|
|
178
|
+
|
|
179
|
+
**兩支算出同一個路徑,就是坑不夠**——而且解法不是改個檔名,是**拆工單目錄**:同一個 lens 要跑
|
|
180
|
+
多個型號時,一個型號一個目錄(ticket-id 加後綴),各派一次。
|
|
181
|
+
不同 lens 共用一個目錄沒有問題,它們的 agent 名本來就不同。
|
|
182
|
+
|
|
183
|
+
這一欄要用數的,不要用看的。**你不需要知道撞名會發生什麼**——數不對就先停下來拆目錄。
|
|
184
|
+
|
|
135
185
|
### lens
|
|
136
186
|
|
|
137
187
|
| agent | 視角 |
|
|
@@ -148,7 +198,7 @@ dowafu --version
|
|
|
148
198
|
| provider | model |
|
|
149
199
|
| --- | --- |
|
|
150
200
|
| `openai` | `gpt-5.6-luna`/`gpt-5.6-terra`/`gpt-5.6-sol` |
|
|
151
|
-
| `deepseek` | `deepseek-v4-flash` |
|
|
201
|
+
| `deepseek` | `deepseek-v4-flash`/`deepseek-v4-pro` |
|
|
152
202
|
| `gemini` | `gemini-3.1-flash-lite`/`gemini-3.5-flash-lite`/`gemini-3.6-flash` |
|
|
153
203
|
| `anthropic` | `claude-opus-5`/`claude-sonnet-5` |
|
|
154
204
|
|
|
@@ -178,8 +228,14 @@ dowafu --version
|
|
|
178
228
|
| hole-finder-feasibility | gemini | gemini-3.1-flash-lite | |
|
|
179
229
|
```
|
|
180
230
|
|
|
181
|
-
首行 `<!-- format: v1 -->` **必須有**;`model`
|
|
182
|
-
|
|
231
|
+
首行 `<!-- format: v1 -->` **必須有**;`model` 必填;只列你要派的那幾個。`effort` 留白
|
|
232
|
+
即為 **`high`**——四家的 `reasoning.default` 目前都是 `high`。要調就查
|
|
233
|
+
`providers.json` 的 `reasoning.allowed`,**各家值域不同**(例如 `deepseek` 沒有
|
|
234
|
+
`medium`);填了不在值域內的值會被擋下並列出允許值,不會靜默降級。
|
|
235
|
+
|
|
236
|
+
**agent 欄在同一份 `_dispatch.md` 裡不得重複。** 一個 agent 一列;要用同一個 lens 跑多個型號,
|
|
237
|
+
拆成多個工單目錄(見 §2〈幾支 spoke 就要幾個落點〉)。**CLI 在解析期就會擋下重複的 agent,
|
|
238
|
+
乾跑一樣會被擋**——但那是最後一道防線,不是可以省掉數落點那一步的理由。
|
|
183
239
|
|
|
184
240
|
### `_shared.md`(所有 spoke 共用)
|
|
185
241
|
|
|
@@ -218,7 +274,10 @@ dowafu --version
|
|
|
218
274
|
3. **允許清單要涵蓋「回答這些問題實際需要的檔案」。** 逐題自問:要回答這題得讀哪些檔?
|
|
219
275
|
漏了的話 spoke 只能在「無法驗證」欄記下缺什麼——**那是派工端的失誤,不是它的問題**。
|
|
220
276
|
路徑**相對 repo 根目錄**。留空也合法(純文字審查),但那樣就讀不到程式碼,會少掉
|
|
221
|
-
「文件說 X、`src/foo.ts:42` 其實是 Y
|
|
277
|
+
「文件說 X、`src/foo.ts:42` 其實是 Y」這類最有價值的發現。**清單屬於這一份
|
|
278
|
+
`<agent>.md`,不屬於整批派工**——不要把另一支的清單整份複製過來:對它有用、對這一支
|
|
279
|
+
沒用的檔,在讀取順序裡是純負擔;反過來就是漏洞。**沒開過的檔不能拿來證明「答案不在
|
|
280
|
+
那裡」**——如果你指不出某一題的答案在哪個檔,那一題現在就是沒有檔可依,不管表上填了什麼。
|
|
222
281
|
|
|
223
282
|
4. **大的檔案排在清單最後——這能省掉一半成本。** spoke **嚴格照清單順序**讀檔,而多數
|
|
224
283
|
模型**一輪只叫一個檔**,每一輪又會把先前讀過的全部內容重送一次。所以一個檔被重複
|
|
@@ -261,6 +320,10 @@ dowafu --version
|
|
|
261
320
|
dowafu tmp/dispatch/<ticket-id> --repo-root . --dry-run
|
|
262
321
|
```
|
|
263
322
|
|
|
323
|
+
**一次乾跑只驗一個工單目錄。** 這一批如果拆成了多個目錄(同一個 lens 跑多個型號時就會),
|
|
324
|
+
**每一個都要各乾跑一次**,並把各次的估算**加總**之後再把數字呈給使用者。
|
|
325
|
+
只乾跑第一個就去實跑,等於其餘目錄完全沒經過這道檢查。
|
|
326
|
+
|
|
264
327
|
**跑之前先跟使用者說明這一步在幹嘛。** 他多半沒用過這個工具,看你在下指令會以為已經
|
|
265
328
|
開始派工、開始計費了:
|
|
266
329
|
|
|
@@ -277,10 +340,44 @@ dowafu tmp/dispatch/<ticket-id> --repo-root . --dry-run
|
|
|
277
340
|
| 允許清單估算 + 檔數 | spoke 讀得到哪些東西、多大 |
|
|
278
341
|
| 最壞總消耗 | **這是上限不是預期值**(各 spoke 的 cap 加總),實際通常遠低於此 |
|
|
279
342
|
|
|
280
|
-
|
|
343
|
+
**用自己的話、用表格轉述——除非你是逐位元組貼上原輸出,否則不要放進 code fence。**
|
|
344
|
+
code fence 的語意就是「這是工具印出來的」,把改寫過的內容裝進去,等於宣稱一個你其實
|
|
345
|
+
沒做到的準確度。改寫沒有問題,而且常常比原輸出好讀;把改寫冒充成原輸出才有問題。
|
|
346
|
+
|
|
347
|
+
**要轉述就連限定語一起轉。** 報表裡那些限定語,正是讓數字不會被誤讀的部分——總量是上限
|
|
348
|
+
而非預期值、價目取自哪一天、估算建立在什麼假設上、每支 lens 收尾句的確認行。它們看起來
|
|
349
|
+
最像可以省的,卻正是讓這些數字能拿來做決定的東西。**限定語一刪,你交給使用者的數字就
|
|
350
|
+
比工具給你的更硬。**
|
|
351
|
+
|
|
352
|
+
**工具標了 `⚠` 或 `ℹ` 的那幾行一律逐字轉述,不得改寫。** `⚠` 是工具在說「現在有事」——
|
|
353
|
+
輸出目錄已經有產物、清單順序正在多花錢、某支 spoke 什麼都沒讀。把它改寫成一句比較平順的話,
|
|
354
|
+
是你能對這份報表做的最貴的一件事,因為讀者會失去唯一那個「需要你做決定」的訊號。
|
|
355
|
+
特別是:`⚠ 大檔排清單最後可降至 N(本項省 N%)` 的意思是**你現在沒有排好**,
|
|
356
|
+
不是「已經排好了、重排只能再省一點」。
|
|
281
357
|
|
|
282
|
-
|
|
283
|
-
|
|
358
|
+
必須跟著數字一起活下來的限定語,逐項點名:
|
|
359
|
+
|
|
360
|
+
| 出現在哪 | 什麼一定要跟著轉 |
|
|
361
|
+
| --- | --- |
|
|
362
|
+
| 每支 spoke 那一行 | `effort=`、`lang=`、`store=`,以及它的 `cap` |
|
|
363
|
+
| 單價子行 | 每 M token 的數字**與**`價目查證日 <日期>` |
|
|
364
|
+
| `ℹ` 收尾句檢查 | 每支一行,照印的轉 |
|
|
365
|
+
| 初始 prompt 估算 | 它**不含工單與允許清單**,以及閘門上限 |
|
|
366
|
+
| 允許清單估算 | 它是上限、**不去重**,以及字元/token 的換算基礎 |
|
|
367
|
+
| 逐個讀順序放大量 | 它是「逐個讀假設下的上限、批次讀的廠牌不適用」、排序的判定,以及**本項不含初始 prompt 與工單** |
|
|
368
|
+
| 最壞總消耗 | 它是**上限不是預期值**,且是各 spoke cap 的加總 |
|
|
369
|
+
|
|
370
|
+
少了這些,數字讀起來會比工具的原意更硬。**自己把 token 換算成錢時,要講明那是你算的、依據哪一行單價。**
|
|
371
|
+
|
|
372
|
+
報表只給 token,不給金額,且**只在乾跑階段成立**。要換算成錢,**價目來源是
|
|
373
|
+
`providers.json` 的 `pricing`(`inputPerM`/`cachedInputPerM`/`outputPerM`),不要查
|
|
374
|
+
官網**——那份數字就是 CLI 計費用的,查官網會讓「你報的錢」與「CLI 算的錢」對不上。
|
|
375
|
+
`pricingSource.asOf` 看起來過舊就回報使用者,不要自行改數字(要改是改
|
|
376
|
+
`providers.json`)。**實跑**的 `summary.md` 有「估算成本」欄,每支 spoke 結束也會印
|
|
377
|
+
一行 `cost=`,那是 CLI 自己算好的金額,**直接轉述即可,不必自己算**。
|
|
378
|
+
|
|
379
|
+
然後逐項核對:`repoRoot` 是這個專案、`model` 跟你寫的一致、**報表印出的 `effort` 是
|
|
380
|
+
你預期的那一級**、估算 token 量級合理、**沒有 `⚠ 輸出目錄…未被…忽略` 的警告**。
|
|
284
381
|
|
|
285
382
|
任何一項不對就修工單重跑,**不要往下走**。
|
|
286
383
|
|
|
@@ -288,6 +385,21 @@ token 量級合理、**沒有 `⚠ 輸出目錄…未被…忽略` 的警告**
|
|
|
288
385
|
|
|
289
386
|
## 5. 實跑
|
|
290
387
|
|
|
388
|
+
**輸出目錄必須是一個還不存在的目錄。** 先看 `tmp/spoke/<ticket-id>/`:已經有東西了就
|
|
389
|
+
**換一個新的 ticket-id 派出去**——換 id 不花錢,碰撞這件事就不存在了。
|
|
390
|
+
|
|
391
|
+
**刪產物是使用者的決定,永遠不是你的。** 派工前不行、順手整理不行、「它擋路」也不行。
|
|
392
|
+
你可以問要不要清掉,但不可以自己清,也不可以直接跑上去。那底下的東西是花錢買來的,
|
|
393
|
+
而目錄本身不會告訴你使用者還要不要它。(第 7 節的清理是另一回事:那是**裁決之後**、
|
|
394
|
+
他說了才做的。)
|
|
395
|
+
|
|
396
|
+
**這條有 CLI 撐著。** 目錄非空時它會在派工前中止——沒呼叫任何 API、沒花任何錢——
|
|
397
|
+
並要你換一個 ticket-id。**沒有可以蓋過它的旗標**:清目錄是使用者的動作,
|
|
398
|
+
不是你能帶的參數。
|
|
399
|
+
|
|
400
|
+
CLI 開跑時會清空 `run.jsonl`(舊事件會讓你數錯),**但那一步只在它真的跑起來時才執行**。
|
|
401
|
+
啟動失敗的話,上一次的產物原封不動留著——而**檔案不會告訴你它是不是這一次的**。
|
|
402
|
+
|
|
291
403
|
```bash
|
|
292
404
|
dowafu tmp/dispatch/<ticket-id> --repo-root . --yes
|
|
293
405
|
```
|
|
@@ -306,9 +418,37 @@ dowafu tmp/dispatch/<ticket-id> --repo-root . --yes
|
|
|
306
418
|
> **前景執行本身另有外部工具的逾時上限**(十分鐘量級),與 `--timeout` 無關、擋不住。
|
|
307
419
|
> **預估這次會跑久(清單大、問題多、選了較慢的型號)就改背景執行**,不要在前景硬等。
|
|
308
420
|
|
|
421
|
+
### 啟動確認:先確認它真的跑起來了,再開始等
|
|
422
|
+
|
|
423
|
+
**下指令之前先記下當下時間**(`date -u +%Y-%m-%dT%H:%M:%SZ`),下完隔十幾秒讀一次
|
|
424
|
+
`tmp/spoke/<ticket-id>/run.jsonl`:
|
|
425
|
+
|
|
426
|
+
| 讀到 | 判定 |
|
|
427
|
+
| --- | --- |
|
|
428
|
+
| 檔案不存在 | **沒跑起來**——CLI 一開跑就會建它,這不是「還在等 API」 |
|
|
429
|
+
| 有 `spoke_start`,`ts` 晚於你下指令的時刻 | 起來了,開始輪詢 |
|
|
430
|
+
| 有內容,但 `ts` 早於你下指令的時刻 | **沒跑起來,你讀到的是上一次的產物** |
|
|
431
|
+
|
|
432
|
+
`ts` 是每一行都有的 ISO 8601 時間戳,**這是判斷「這一份是不是這一次」的唯一機械依據**。
|
|
433
|
+
|
|
434
|
+
**沒跑起來就不要繼續等。** 這個失敗形態自己看不出來:舊產物的兩個 `spoke_end` 都是
|
|
435
|
+
`succeeded`,格式、稽核欄、成本全部正常,唯一的破綻是時間戳。
|
|
436
|
+
|
|
437
|
+
### 等多久算不正常
|
|
438
|
+
|
|
439
|
+
**看的不是總耗時,是 `run.jsonl` 有沒有在長。** 單支 spoke 跑上十分鐘是正常的,但
|
|
440
|
+
**十分鐘之內一定會有新事件寫進來**——單次 API 呼叫的逾時預設就是十分鐘,而逾時與重試
|
|
441
|
+
各自都會寫一行 `round_error`。
|
|
442
|
+
|
|
443
|
+
> **超過十分鐘沒有任何新事件,就停下來告訴使用者**,不要繼續等、也不要自行重跑。
|
|
444
|
+
> 把最後一個事件與它的 `ts` 一起報給他,讓他判斷。
|
|
445
|
+
|
|
309
446
|
**進度一律以 `run.jsonl` 為準**——CLI 逐事件寫入該檔,中途 Ctrl-C 也讀得出跑到哪。
|
|
310
447
|
終端機那條通道可不可靠依 host 而定(見 §1.5),`run.jsonl` 不受影響。
|
|
311
448
|
|
|
449
|
+
**跑完的判定是兩件事同時成立**:兩個 `spoke_end`,**而且**這份 `run.jsonl` 通過了上面的
|
|
450
|
+
啟動確認。只看 `spoke_end` 會把上一次的產物當成這一次的結果。
|
|
451
|
+
|
|
312
452
|
**真的撞到失敗或逾時:要不要重跑由使用者決定,不要自行重跑。** 重跑是重新付費,中斷前已
|
|
313
453
|
花的錢救不回來(沒有 resume 機制)。把中斷時的狀態(`run.jsonl` 讀到哪、失敗訊息)告訴
|
|
314
454
|
使用者,讓他判斷要不要重來——這與「零讀取就整份重跑」不衝突:那條是「判定沒跑」,這裡是
|
|
@@ -316,28 +456,53 @@ dowafu tmp/dispatch/<ticket-id> --repo-root . --yes
|
|
|
316
456
|
|
|
317
457
|
---
|
|
318
458
|
|
|
319
|
-
## 6.
|
|
459
|
+
## 6. 回收——摘要優先,原文為例外
|
|
320
460
|
|
|
321
461
|
產物在 `tmp/spoke/<ticket-id>/`:`<agent>.md`(原文)、`summary.md`(稽核表)、
|
|
322
462
|
`run.jsonl`(執行記錄)、`raw/`(完整請求與回應)。
|
|
323
463
|
|
|
464
|
+
**`run.jsonl` 是逐事件附加寫入的,不會被覆蓋。** 產物與 `raw/` 若被蓋掉——重跑,或另一支
|
|
465
|
+
寫到同一個名字——那個檔裡仍然留著每一支的 `spoke_start`(provider 與型號)、逐輪 usage、
|
|
466
|
+
每一次讀檔(含被拒的)、錯誤,以及 `spoke_end` 的 token 與成本。
|
|
467
|
+
**報告文字救不回來,但花了多少錢、讀了哪些檔,可以還原。**
|
|
468
|
+
|
|
469
|
+
> **回收之前先確認 §5 的啟動確認過了。** 這個目錄底下的任何檔案,都不會告訴你它是不是
|
|
470
|
+
> 這一次的產物。
|
|
471
|
+
|
|
324
472
|
**呈現順序不得更動**:
|
|
325
473
|
|
|
326
|
-
1. **逐個 spoke 的內容都要讓使用者看到**,標明 lens
|
|
327
|
-
|
|
474
|
+
1. **逐個 spoke 的內容都要讓使用者看到**,標明 lens 與模型。**摘要是預設**,滿足以下
|
|
475
|
+
四個必要條件:
|
|
328
476
|
1. **明確宣告取捨**——在摘要開頭寫明「本節為摘要,非逐字照登」,不安靜地摘掉
|
|
329
477
|
2. **判讀涵蓋每一條,無一略過**——每個 spoke 的每一條觀察都要在後面的「hub 判讀」出現,
|
|
330
478
|
這是取代「原文照登」的可稽核性來源:原文不在你眼前列出,不代表它沒被看過
|
|
331
479
|
3. **指出原文路徑**(`tmp/spoke/<ticket-id>/<agent>.md`),使用者隨時可自行比對
|
|
332
|
-
4. **只在產物尚未清理時才成立**——第 7
|
|
333
|
-
仍是唯一選擇,不能摘要
|
|
480
|
+
4. **只在產物尚未清理時才成立**——第 7 節清掉之後就沒有底本可查
|
|
334
481
|
> 這條規則要防的不是「沒有原文」,是**防止 hub 只挑對自己有利的講**。滿足以上四件事,
|
|
335
482
|
> 手段換成摘要也一樣防得住;換句話說,要守住的是目的,不是「原文」這個手段本身。
|
|
336
483
|
|
|
337
|
-
|
|
338
|
-
|
|
484
|
+
**原文照登用於兩種情形**:產物已被第 7 節清掉(沒有底本可查,摘要不成立),或單份
|
|
485
|
+
規模小到摘要反而多此一舉。除此之外都走摘要。
|
|
486
|
+
|
|
487
|
+
**做不到第 2 條就不要派這麼多 spoke**——問題出在派工規模,不在呈現方式;不要拿
|
|
488
|
+
「沒把握」當理由退回整份照登。
|
|
489
|
+
2. **`summary.md` 的稽核欄轉述進上面那一節——它印出來的每一段都要點名。** 每支 spoke
|
|
490
|
+
一段一行,**順序照 `summary.md` 印的**:`工具呼叫` 在最前面,排在 `收尾句` 之前。
|
|
491
|
+
某一段是空的時候,CLI 會自己印它的空值字(中文那套印 `無`),**照它印的抄,
|
|
492
|
+
而且一段都不准漏掉**。全部寫出來不比只寫大部分貴,而少一個段名使用者看得出來,
|
|
493
|
+
少一列他看不出來。
|
|
494
|
+
|
|
495
|
+
**`⚠` 開頭的那幾段不准省,`(無法稽核)` 也不准省。** 它們不是那幾個欄位以外的裝飾,
|
|
496
|
+
是稽核在告訴你出事了;省掉它們,使用者手上就只剩下說「沒事」的那幾段。
|
|
497
|
+
|
|
498
|
+
**有內容的段落一律逐字照抄。** 只有 `pass` 與 CLI 自己的空值字可以壓縮。說「沒事」的
|
|
499
|
+
段落留著最省事,說「有事」的那段才是會被刪掉的——所以這條規則是刻意不對稱的:
|
|
500
|
+
**一段講的東西越多,你對它的處置自由越少。**
|
|
339
501
|
3. **之後另立「hub 判讀」一節**——去重,逐條標註你的初步判讀(成立/不成立+為什麼/
|
|
340
|
-
|
|
502
|
+
需使用者裁決)。**每一項都要標明它來自哪幾條觀察**,寫成 spoke + 條號
|
|
503
|
+
(`safety 2、3;feasibility 9`),而且**每一條觀察都要出現在至少一項裡**。
|
|
504
|
+
兩支 spoke 的編號觀察,要嘛全部出現在那一欄,要嘛沒出現的一眼就看得出來——**這正是重點**:
|
|
505
|
+
沒有編號的話,「安靜地沒被列進來」與「你判讀過但認為不成立」長得一模一樣。
|
|
341
506
|
|
|
342
507
|
### 跑了多次時怎麼合併
|
|
343
508
|
|
|
@@ -358,17 +523,24 @@ dowafu tmp/dispatch/<ticket-id> --repo-root . --yes
|
|
|
358
523
|
不同:幻覺要重跑或換模型,位置錯只需自己重新定位。**把位置錯判成幻覺,會丟掉整份能用的
|
|
359
524
|
產出。**
|
|
360
525
|
|
|
526
|
+
**這條對你自己寫的行號同樣成立。** 驗完 spoke 的引用、隔幾段自己憑印象寫一次行號,
|
|
527
|
+
等於把漂移換上你的名字放回去——**而你的份量更重**,因為你說了你開過檔。
|
|
528
|
+
|
|
361
529
|
**三、驗 spoke 引用時,註解不算證據。** 「spoke 說某段有註解背書某個結論」不夠,還要驗
|
|
362
530
|
**註解說的還成不成立**——註解會與程式碼漂移,而漂移的註解讀起來跟正確的一模一樣,
|
|
363
531
|
只驗「註解存在且內容吻合」會把錯的判成對的。AGENTS.md 必答檢查第 1 條「不能只憑檔名、
|
|
364
532
|
註解或行號」原本管的是寫規劃書時,這裡把它擴到驗收 spoke 引用時。
|
|
365
533
|
|
|
534
|
+
**spoke 說「我讀不到 X 所以無法確認」是正確回報,不是假警報。** 它指出的是**你沒放進清單**的檔,
|
|
535
|
+
那是你的缺口、不是它的錯——把它歸到「假警報」,或自己默默查掉就往下走,
|
|
536
|
+
會把「清單裁錯了」這個唯一的訊號蓋掉。**你可以自己補查,但仍要明說清單當時是短的。**
|
|
537
|
+
|
|
366
538
|
### 稽核表怎麼看
|
|
367
539
|
|
|
368
540
|
| 欄位 | 意思 |
|
|
369
541
|
| --- | --- |
|
|
542
|
+
| `工具呼叫:N(允許 N/拒絕 N)` | 讀了幾次、幾次被拒——`run.jsonl` `toolCalls[]` 的統計。**印在最前面**,排在收尾句之前 |
|
|
370
543
|
| `收尾句` | pass/fail |
|
|
371
|
-
| `工具呼叫:N(允許 N/拒絕 N)` | 讀了幾次、幾次被拒——`run.jsonl` `toolCalls[]` 的統計 |
|
|
372
544
|
| `觀察:N` | 條數;`無法計數` 表示格式無法辨識,翻原文確認 |
|
|
373
545
|
| `清單外引用` | 引用了允許清單外的路徑,**可能是臆測**——對照 `toolCalls[]` 判斷。**此欄至今沒抓到過真正的幻覺**:抓到的多半是 spoke 照抄素材的縮寫路徑、轉述素材裡提過但自己標明讀不到的路徑,或絕對/相對路徑混用。先查該路徑是不是出現在你自己的 `_shared.md` 裡,或只是寫法不同,不要預設是編的 |
|
|
374
546
|
| `無法驗證欄` | 有沒有照模板寫這一節。**判讀產出品質時看這欄有多具體**(例如逐項標明哪個結論依賴哪個不可讀的檔案),不要看觀察條數——條數不可靠,重疊、灌水都會推高條數但不代表品質 |
|
|
@@ -414,6 +586,9 @@ dowafu tmp/dispatch/<ticket-id> --repo-root . --yes
|
|
|
414
586
|
rm -rf tmp/spoke/<ticket-id> tmp/dispatch/<ticket-id>
|
|
415
587
|
```
|
|
416
588
|
|
|
589
|
+
**這是整套流程裡唯一會刪東西的地方,而且要等使用者裁決完、他說了才刪。** 其他任何時候
|
|
590
|
+
——包括派工前那個擋路的目錄——一律照第 5 節:可以問,不可以自己刪。
|
|
591
|
+
|
|
417
592
|
lens 定義留著,下次還會用。
|
|
418
593
|
|
|
419
594
|
---
|
|
@@ -427,7 +602,7 @@ lens 定義留著,下次還會用。
|
|
|
427
602
|
| 真失敗或逾時 | **要不要重跑問使用者,不要自行重跑**——重跑是重新付費,中斷前的花費救不回來 |
|
|
428
603
|
| 撞 429 | 加 `--concurrency 1` 重跑 |
|
|
429
604
|
| 報告品質差 | 換一個型號重跑,或同一組設定再跑一次取聯集(見第 3 節「跑 2–3 次怎麼做」) |
|
|
430
|
-
| 缺 API key | 使用者要在 `~/.config/
|
|
605
|
+
| 缺 API key | 使用者要在 `~/.config/dowafu/.env` 設定,**你不要去碰那個檔** |
|
|
431
606
|
| 找不到 `dowafu` | **查不到不代表沒安裝**——見 §1.5,多半是沙箱不讀家目錄 |
|
|
432
607
|
| `Operation not permitted` | host 的沙箱擋的,**不是工單或指令的問題**。照提示放行再跑一次 |
|
|
433
608
|
|
|
@@ -41,11 +41,12 @@ cd <repo 根的絕對路徑>
|
|
|
41
41
|
echo "=== 流程規範 ==="
|
|
42
42
|
ls CLAUDE.md AGENTS.md workflow_spec.md 2>&1
|
|
43
43
|
# 這條只幫你定位「內容寫在哪個檔」。它有命中 ≠ 你讀得到——判準見下。
|
|
44
|
-
|
|
44
|
+
# 兩種寫法都要找:專案本來那一章的語言,未必和你裝的語言套件相同。
|
|
45
|
+
grep -nE "規劃→實作→驗收|Plan → Implement → Accept" CLAUDE.md AGENTS.md workflow_spec.md 2>/dev/null
|
|
45
46
|
|
|
46
47
|
echo "=== skill 與 lens ==="
|
|
47
48
|
ls .claude/skills/ 2>/dev/null
|
|
48
|
-
ls .claude/agents/hole-finder
|
|
49
|
+
ls .claude/agents/hole-finder*.md 2>/dev/null
|
|
49
50
|
|
|
50
51
|
echo "=== tmp/ ==="
|
|
51
52
|
git check-ignore -q tmp && echo "已忽略" || echo "未忽略"
|
|
@@ -55,6 +56,10 @@ git check-ignore -q tmp && echo "已忽略" || echo "未忽略"
|
|
|
55
56
|
|
|
56
57
|
**判準只有一條:「規劃→實作→驗收流程規範(主從形態)」這一章的內容,你現在讀得到嗎?**
|
|
57
58
|
|
|
59
|
+
**那一章可能是以另一種語言的標題存在的。** 語言套件各帶各的副本,所以本來就有這一章的專案
|
|
60
|
+
最後會變成兩份——兩種語言,而只有一份會自動載入。上面那道 grep 兩種寫法都找就是為了這個;
|
|
61
|
+
**命中超過一個檔時,先讀下一段再下判斷。**
|
|
62
|
+
|
|
58
63
|
讀得到就算通過。內容是直接貼在入口檔裡、還是用 `@` 之類的方式引入的,**那是使用者的
|
|
59
64
|
選擇,不在檢查範圍內**。
|
|
60
65
|
|
|
@@ -62,6 +67,11 @@ git check-ignore -q tmp && echo "已忽略" || echo "未忽略"
|
|
|
62
67
|
讀完在回報裡註明「規範不在自動載入範圍內,本次是手動讀取的」——讓使用者知道換個
|
|
63
68
|
session 又會漏掉。
|
|
64
69
|
|
|
70
|
+
**找到不只一份,就要講明哪一份會被自動載入。** 專案可能本來就把這一章內嵌在入口檔裡,
|
|
71
|
+
而根目錄又多一份 `workflow_spec.md`——兩份的語言還可能不同(語言套件各裝各的)。
|
|
72
|
+
這時只回報「內容讀得到」不夠:要指出**你 context 裡的是哪一份**,以及兩份之間沒有任何
|
|
73
|
+
同步機制。自動載入的那一份,才是之後每個 session 真正生效的那一份。
|
|
74
|
+
|
|
65
75
|
> **為什麼會讀不到?** 入口檔因 host 而異:Claude Code 讀 `CLAUDE.md`(**不讀
|
|
66
76
|
> `AGENTS.md`**),其他 host 多半讀 repo 根的 `AGENTS.md`。而 `@xxx.md` 是 Claude Code
|
|
67
77
|
> 的 import 語法,**別的 host 不會展開它**——那時你看到的只是一行字,規範內容從來沒進
|
|
@@ -69,8 +79,20 @@ session 又會漏掉。
|
|
|
69
79
|
|
|
70
80
|
### skill 與 lens
|
|
71
81
|
|
|
72
|
-
`.claude/skills/find-holes-external/` 與
|
|
73
|
-
|
|
82
|
+
`.claude/skills/find-holes-external/` 與 lens 定義在不在。**回報你實際看到的檔名,
|
|
83
|
+
缺哪個就點名**——「看到三個」不算檢查,是哪三個才算。
|
|
84
|
+
|
|
85
|
+
應該有四個,四個都算正常:
|
|
86
|
+
|
|
87
|
+
| 檔 | 是什麼 |
|
|
88
|
+
| --- | --- |
|
|
89
|
+
| `hole-finder.md` | 通用 lens |
|
|
90
|
+
| `hole-finder-cost.md` | 成本 |
|
|
91
|
+
| `hole-finder-feasibility.md` | 可行性 |
|
|
92
|
+
| `hole-finder-safety.md` | 安全、併發、失敗態 |
|
|
93
|
+
|
|
94
|
+
> 上面那道 glob 的 `*` 前面沒有連字號是刻意的:`hole-finder-*.md` 配不到
|
|
95
|
+
> `hole-finder.md`,拿它去數卻期待四個,怎麼數都對不起來。
|
|
74
96
|
|
|
75
97
|
**lens 缺了不要自己補寫**——它是 spoke 的 system prompt 來源,自己寫的版本會讓產出跟
|
|
76
98
|
稽核判準對不上。
|
|
@@ -84,6 +106,9 @@ session 又會漏掉。
|
|
|
84
106
|
|
|
85
107
|
## 2. 如果你是 Claude Code 的 agent
|
|
86
108
|
|
|
109
|
+
**你如果要用外派(`/find-holes-external`),第 3 節的第一項與第四項你也要查**——
|
|
110
|
+
不管是哪個 host 在驅動,CLI 都得跑得起來、設定都得到位。第 3 節其餘部分才是其他 host 專屬的。
|
|
111
|
+
|
|
87
112
|
下面兩項只影響 **Claude Code 自己的內派 sub-agent**。外派(`find-holes-external` 走
|
|
88
113
|
`dowafu`)的 spoke 模型由工單的 `_dispatch.md` 決定,**不受這兩項影響**——
|
|
89
114
|
這個專案只跑外派的話,這一節查了也不會改變什麼。
|
|
@@ -142,7 +167,7 @@ grep -h "\"model\"\|\"effortLevel\"" ~/.claude/settings.json .claude/settings.js
|
|
|
142
167
|
|
|
143
168
|
## 3. 如果你不是 Claude Code 的 agent
|
|
144
169
|
|
|
145
|
-
第 2
|
|
170
|
+
第 2 節那兩項對你不存在,跳過。你要確認的是下面四件事,**按這個順序**——前一項不成立,
|
|
146
171
|
後面查了也沒有意義。
|
|
147
172
|
|
|
148
173
|
### 一、`dowafu` 在哪、跑不跑得起來
|
|
@@ -158,11 +183,15 @@ dowafu --version
|
|
|
158
183
|
|
|
159
184
|
| 症狀 | 意思 | 怎麼回報 |
|
|
160
185
|
| --- | --- | --- |
|
|
161
|
-
| `Operation not permitted` | **沙箱擋的**,不是沒安裝。CLI 多半裝在家目錄底下,而沙箱預設不讀家目錄 | 照 host 的提示放行後重試。順帶告訴使用者:API key(`~/.config/
|
|
186
|
+
| `Operation not permitted` | **沙箱擋的**,不是沒安裝。CLI 多半裝在家目錄底下,而沙箱預設不讀家目錄 | 照 host 的提示放行後重試。順帶告訴使用者:API key(`~/.config/dowafu/.env`)與對外網路同樣被擋,派工時一併要放行 |
|
|
162
187
|
| `command not found` | 可能沒裝,也可能裝在 PATH 之外 | 問使用者 CLI 裝在哪(請他跑 `which dowafu`),**不要自己搜檔案系統** |
|
|
163
188
|
|
|
164
189
|
**`command -v dowafu` 查不到不代表沒安裝**,別拿那個當判準。
|
|
165
190
|
|
|
191
|
+
**既沒回來也沒報錯,是第三種情況:它在等。** 不帶 `--yes` 時 CLI 會印出確認提示並卡在
|
|
192
|
+
stdin 上,而這在不同 host 會表現成逾時、表現成沒有輸出、或表現成「要不要幫你送出輸入」。
|
|
193
|
+
**記下你的環境是哪一種**——派工當下會再遇到一次,而那個時機點知道就晚了。
|
|
194
|
+
|
|
166
195
|
### 二、lens 定義與 skill 在不在
|
|
167
196
|
|
|
168
197
|
見第 1 節的「skill 與 lens」。有一點對你特別重要:
|
|
@@ -178,6 +207,22 @@ dowafu --version
|
|
|
178
207
|
語法,你不會展開它——入口檔裡若只有那一行,你看到的就是一行字,而**你很可能以為自己
|
|
179
208
|
已經讀過規範了**。實際檢查你的 context 裡有沒有那章的內容,別憑印象。
|
|
180
209
|
|
|
210
|
+
### 四、CLI 的設定到位了嗎——`dowafu --doctor`
|
|
211
|
+
|
|
212
|
+
```bash
|
|
213
|
+
dowafu --doctor
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
它會印出設定目錄解析到哪、`.env` 在不在、**哪幾家有 key**(只看有沒有,不印值)、
|
|
217
|
+
內建的型號白名單、以及找到哪幾支 lens 定義。不呼叫 API、不花錢,**而且不需要工單**——
|
|
218
|
+
這正是它在「什麼都還沒有」的時候能用的原因。
|
|
219
|
+
|
|
220
|
+
缺的項目照它印的回報。**不要主動幫使用者寫 key,也不要請他把 key 貼進這段對話**——
|
|
221
|
+
貼進來的東西會留在這段對話的歷史裡。幫他建目錄、放一份空範本可以,值要由他自己填進檔案。
|
|
222
|
+
|
|
223
|
+
`dowafu --doctor` 只印得出錯誤時,那與第一項是同一個發現:CLI 從這裡跑不起來,
|
|
224
|
+
下面幾項都還輪不到。
|
|
225
|
+
|
|
181
226
|
---
|
|
182
227
|
|
|
183
228
|
## 4. 輸出
|
|
@@ -65,6 +65,22 @@ import 機制**。兩種讀者得分別交代,否則其中一邊會靜默漏
|
|
|
65
65
|
|
|
66
66
|
目標專案若沒有 `CLAUDE.md`,另建一個、內容一行 `@AGENTS.md` 即可(官方建議做法)。
|
|
67
67
|
|
|
68
|
+
### 專案本來就有一章流程規範時
|
|
69
|
+
|
|
70
|
+
很多專案本來就有一份,直接貼在入口檔裡——而且語言可能跟你剛裝的這套不同,因為每個語言
|
|
71
|
+
套件各帶各的 `workflow_spec.md`。就這樣把檔案複製進去,專案裡會變成**兩份、而且沒有任何
|
|
72
|
+
機制保證同步**;真正管到每個 session 的是入口檔會自動載入的那一份——**是本來就在的那章,
|
|
73
|
+
不是你剛裝的那個檔**。
|
|
74
|
+
|
|
75
|
+
二選一,另一份要拿掉:
|
|
76
|
+
|
|
77
|
+
- **留 `workflow_spec.md`**(建議):把入口檔裡舊的那一章刪掉,換成上面那段 import
|
|
78
|
+
- **留內嵌的那一章**:把它的內容換成你要統一的語言那份 `workflow_spec.md` 的內容,
|
|
79
|
+
並且**不要**把 `workflow_spec.md` 複製進專案
|
|
80
|
+
|
|
81
|
+
不論走哪一條,專案裡最後**只留一份**。裝完跑一次 `preflight`——它會回報實際在 context
|
|
82
|
+
裡的是哪一份,所以這個決定就算漏掉了,還有一道會抓到。
|
|
83
|
+
|
|
68
84
|
## 這裡不准出現的東西
|
|
69
85
|
|
|
70
86
|
`publish/` 的內容會在一個不知道來源專案存在的地方執行,所以不得出現絕對路徑、來源專案的
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|