dowafu 0.3.0 → 0.3.2
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 +14 -0
- package/dist/adapters/responses.js +5 -1
- package/dist/audit.js +33 -64
- package/dist/cli-args.js +15 -0
- package/dist/cli.js +26 -5
- package/dist/doctor.js +114 -0
- package/dist/error-classify.js +13 -4
- package/dist/json-output.js +2 -4
- package/dist/messages.js +70 -14
- package/dist/output.js +6 -22
- package/dist/prompt.js +15 -0
- package/dist/report.js +8 -1
- package/dist/ticket.js +46 -2
- package/package.json +1 -1
- package/providers.json +8 -3
- package/publish/en/.agents/skills/find-holes-external/SKILL.md +63 -7
- package/publish/en/.agents/skills/preflight/SKILL.md +20 -3
- package/publish/en/.claude/skills/find-holes/SKILL.md +5 -0
- package/publish/en/.claude/skills/find-holes-external/SKILL.md +62 -6
- package/publish/en/.claude/skills/preflight/SKILL.md +21 -2
- package/publish/zh-tw/.agents/skills/find-holes-external/SKILL.md +93 -9
- package/publish/zh-tw/.agents/skills/preflight/SKILL.md +28 -3
- package/publish/zh-tw/.claude/skills/find-holes/SKILL.md +11 -0
- package/publish/zh-tw/.claude/skills/find-holes-external/SKILL.md +92 -8
- package/publish/zh-tw/.claude/skills/preflight/SKILL.md +30 -2
|
@@ -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
|
|
|
@@ -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,15 +138,49 @@ dowafu --version
|
|
|
132
138
|
換一批對準答案位置的檔案,同一個 lens 就抓得到。**這個自問是為了在派工前擋下落差,
|
|
133
139
|
不是派工後才發現。**
|
|
134
140
|
|
|
135
|
-
### 每支 spoke
|
|
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 用錢付的。
|
|
136
157
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
可以,但要說得出為什麼——**清單相同是結論,不是起點**。
|
|
158
|
+
**兩支最後拿到同一批檔也可以,但要說得出為什麼。** 清單相同是**可以解釋的結論**,不是起點;
|
|
159
|
+
而「裁到兩份不一樣為止」是同一個錯誤的反面。
|
|
140
160
|
|
|
141
161
|
**一份清單餵兩支 lens,會往交集收斂,而不是聯集。** 最先掉的是「只有其中一支需要」的檔,
|
|
142
162
|
而那正是那支 lens 被派去看的東西;spoke 這時只能把缺口寫進「無法驗證」欄,而用這種方式
|
|
143
|
-
|
|
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
|
+
這一欄要用數的,不要用看的。**你不需要知道撞名會發生什麼**——數不對就先停下來拆目錄。
|
|
144
184
|
|
|
145
185
|
### lens
|
|
146
186
|
|
|
@@ -158,7 +198,7 @@ dowafu --version
|
|
|
158
198
|
| provider | model |
|
|
159
199
|
| --- | --- |
|
|
160
200
|
| `openai` | `gpt-5.6-luna`/`gpt-5.6-terra`/`gpt-5.6-sol` |
|
|
161
|
-
| `deepseek` | `deepseek-v4-flash` |
|
|
201
|
+
| `deepseek` | `deepseek-v4-flash`/`deepseek-v4-pro` |
|
|
162
202
|
| `gemini` | `gemini-3.1-flash-lite`/`gemini-3.5-flash-lite`/`gemini-3.6-flash` |
|
|
163
203
|
| `anthropic` | `claude-opus-5`/`claude-sonnet-5` |
|
|
164
204
|
|
|
@@ -193,6 +233,10 @@ dowafu --version
|
|
|
193
233
|
`providers.json` 的 `reasoning.allowed`,**各家值域不同**(例如 `deepseek` 沒有
|
|
194
234
|
`medium`);填了不在值域內的值會被擋下並列出允許值,不會靜默降級。
|
|
195
235
|
|
|
236
|
+
**agent 欄在同一份 `_dispatch.md` 裡不得重複。** 一個 agent 一列;要用同一個 lens 跑多個型號,
|
|
237
|
+
拆成多個工單目錄(見 §2〈幾支 spoke 就要幾個落點〉)。**CLI 在解析期就會擋下重複的 agent,
|
|
238
|
+
乾跑一樣會被擋**——但那是最後一道防線,不是可以省掉數落點那一步的理由。
|
|
239
|
+
|
|
196
240
|
### `_shared.md`(所有 spoke 共用)
|
|
197
241
|
|
|
198
242
|
```markdown
|
|
@@ -232,7 +276,8 @@ dowafu --version
|
|
|
232
276
|
路徑**相對 repo 根目錄**。留空也合法(純文字審查),但那樣就讀不到程式碼,會少掉
|
|
233
277
|
「文件說 X、`src/foo.ts:42` 其實是 Y」這類最有價值的發現。**清單屬於這一份
|
|
234
278
|
`<agent>.md`,不屬於整批派工**——不要把另一支的清單整份複製過來:對它有用、對這一支
|
|
235
|
-
|
|
279
|
+
沒用的檔,在讀取順序裡是純負擔;反過來就是漏洞。**沒開過的檔不能拿來證明「答案不在
|
|
280
|
+
那裡」**——如果你指不出某一題的答案在哪個檔,那一題現在就是沒有檔可依,不管表上填了什麼。
|
|
236
281
|
|
|
237
282
|
4. **大的檔案排在清單最後——這能省掉一半成本。** spoke **嚴格照清單順序**讀檔,而多數
|
|
238
283
|
模型**一輪只叫一個檔**,每一輪又會把先前讀過的全部內容重送一次。所以一個檔被重複
|
|
@@ -275,6 +320,10 @@ dowafu --version
|
|
|
275
320
|
dowafu tmp/dispatch/<ticket-id> --repo-root . --dry-run
|
|
276
321
|
```
|
|
277
322
|
|
|
323
|
+
**一次乾跑只驗一個工單目錄。** 這一批如果拆成了多個目錄(同一個 lens 跑多個型號時就會),
|
|
324
|
+
**每一個都要各乾跑一次**,並把各次的估算**加總**之後再把數字呈給使用者。
|
|
325
|
+
只乾跑第一個就去實跑,等於其餘目錄完全沒經過這道檢查。
|
|
326
|
+
|
|
278
327
|
**跑之前先跟使用者說明這一步在幹嘛。** 他多半沒用過這個工具,看你在下指令會以為已經
|
|
279
328
|
開始派工、開始計費了:
|
|
280
329
|
|
|
@@ -300,6 +349,26 @@ code fence 的語意就是「這是工具印出來的」,把改寫過的內容
|
|
|
300
349
|
最像可以省的,卻正是讓這些數字能拿來做決定的東西。**限定語一刪,你交給使用者的數字就
|
|
301
350
|
比工具給你的更硬。**
|
|
302
351
|
|
|
352
|
+
**工具標了 `⚠` 或 `ℹ` 的那幾行一律逐字轉述,不得改寫。** `⚠` 是工具在說「現在有事」——
|
|
353
|
+
輸出目錄已經有產物、清單順序正在多花錢、某支 spoke 什麼都沒讀。把它改寫成一句比較平順的話,
|
|
354
|
+
是你能對這份報表做的最貴的一件事,因為讀者會失去唯一那個「需要你做決定」的訊號。
|
|
355
|
+
特別是:`⚠ 大檔排清單最後可降至 N(本項省 N%)` 的意思是**你現在沒有排好**,
|
|
356
|
+
不是「已經排好了、重排只能再省一點」。
|
|
357
|
+
|
|
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
|
+
|
|
303
372
|
報表只給 token,不給金額,且**只在乾跑階段成立**。要換算成錢,**價目來源是
|
|
304
373
|
`providers.json` 的 `pricing`(`inputPerM`/`cachedInputPerM`/`outputPerM`),不要查
|
|
305
374
|
官網**——那份數字就是 CLI 計費用的,查官網會讓「你報的錢」與「CLI 算的錢」對不上。
|
|
@@ -392,6 +461,11 @@ dowafu tmp/dispatch/<ticket-id> --repo-root . --yes
|
|
|
392
461
|
產物在 `tmp/spoke/<ticket-id>/`:`<agent>.md`(原文)、`summary.md`(稽核表)、
|
|
393
462
|
`run.jsonl`(執行記錄)、`raw/`(完整請求與回應)。
|
|
394
463
|
|
|
464
|
+
**`run.jsonl` 是逐事件附加寫入的,不會被覆蓋。** 產物與 `raw/` 若被蓋掉——重跑,或另一支
|
|
465
|
+
寫到同一個名字——那個檔裡仍然留著每一支的 `spoke_start`(provider 與型號)、逐輪 usage、
|
|
466
|
+
每一次讀檔(含被拒的)、錯誤,以及 `spoke_end` 的 token 與成本。
|
|
467
|
+
**報告文字救不回來,但花了多少錢、讀了哪些檔,可以還原。**
|
|
468
|
+
|
|
395
469
|
> **回收之前先確認 §5 的啟動確認過了。** 這個目錄底下的任何檔案,都不會告訴你它是不是
|
|
396
470
|
> 這一次的產物。
|
|
397
471
|
|
|
@@ -425,7 +499,10 @@ dowafu tmp/dispatch/<ticket-id> --repo-root . --yes
|
|
|
425
499
|
段落留著最省事,說「有事」的那段才是會被刪掉的——所以這條規則是刻意不對稱的:
|
|
426
500
|
**一段講的東西越多,你對它的處置自由越少。**
|
|
427
501
|
3. **之後另立「hub 判讀」一節**——去重,逐條標註你的初步判讀(成立/不成立+為什麼/
|
|
428
|
-
|
|
502
|
+
需使用者裁決)。**每一項都要標明它來自哪幾條觀察**,寫成 spoke + 條號
|
|
503
|
+
(`safety 2、3;feasibility 9`),而且**每一條觀察都要出現在至少一項裡**。
|
|
504
|
+
兩支 spoke 的編號觀察,要嘛全部出現在那一欄,要嘛沒出現的一眼就看得出來——**這正是重點**:
|
|
505
|
+
沒有編號的話,「安靜地沒被列進來」與「你判讀過但認為不成立」長得一模一樣。
|
|
429
506
|
|
|
430
507
|
### 跑了多次時怎麼合併
|
|
431
508
|
|
|
@@ -446,11 +523,18 @@ dowafu tmp/dispatch/<ticket-id> --repo-root . --yes
|
|
|
446
523
|
不同:幻覺要重跑或換模型,位置錯只需自己重新定位。**把位置錯判成幻覺,會丟掉整份能用的
|
|
447
524
|
產出。**
|
|
448
525
|
|
|
526
|
+
**這條對你自己寫的行號同樣成立。** 驗完 spoke 的引用、隔幾段自己憑印象寫一次行號,
|
|
527
|
+
等於把漂移換上你的名字放回去——**而你的份量更重**,因為你說了你開過檔。
|
|
528
|
+
|
|
449
529
|
**三、驗 spoke 引用時,註解不算證據。** 「spoke 說某段有註解背書某個結論」不夠,還要驗
|
|
450
530
|
**註解說的還成不成立**——註解會與程式碼漂移,而漂移的註解讀起來跟正確的一模一樣,
|
|
451
531
|
只驗「註解存在且內容吻合」會把錯的判成對的。AGENTS.md 必答檢查第 1 條「不能只憑檔名、
|
|
452
532
|
註解或行號」原本管的是寫規劃書時,這裡把它擴到驗收 spoke 引用時。
|
|
453
533
|
|
|
534
|
+
**spoke 說「我讀不到 X 所以無法確認」是正確回報,不是假警報。** 它指出的是**你沒放進清單**的檔,
|
|
535
|
+
那是你的缺口、不是它的錯——把它歸到「假警報」,或自己默默查掉就往下走,
|
|
536
|
+
會把「清單裁錯了」這個唯一的訊號蓋掉。**你可以自己補查,但仍要明說清單當時是短的。**
|
|
537
|
+
|
|
454
538
|
### 稽核表怎麼看
|
|
455
539
|
|
|
456
540
|
| 欄位 | 意思 |
|
|
@@ -41,7 +41,8 @@ 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
|
|
@@ -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
|
|
|
@@ -101,6 +106,9 @@ session 又會漏掉。
|
|
|
101
106
|
|
|
102
107
|
## 2. 如果你是 Claude Code 的 agent
|
|
103
108
|
|
|
109
|
+
**你如果要用外派(`/find-holes-external`),第 3 節的第一項與第四項你也要查**——
|
|
110
|
+
不管是哪個 host 在驅動,CLI 都得跑得起來、設定都得到位。第 3 節其餘部分才是其他 host 專屬的。
|
|
111
|
+
|
|
104
112
|
下面兩項只影響 **Claude Code 自己的內派 sub-agent**。外派(`find-holes-external` 走
|
|
105
113
|
`dowafu`)的 spoke 模型由工單的 `_dispatch.md` 決定,**不受這兩項影響**——
|
|
106
114
|
這個專案只跑外派的話,這一節查了也不會改變什麼。
|
|
@@ -159,7 +167,7 @@ grep -h "\"model\"\|\"effortLevel\"" ~/.claude/settings.json .claude/settings.js
|
|
|
159
167
|
|
|
160
168
|
## 3. 如果你不是 Claude Code 的 agent
|
|
161
169
|
|
|
162
|
-
第 2
|
|
170
|
+
第 2 節那兩項對你不存在,跳過。你要確認的是下面四件事,**按這個順序**——前一項不成立,
|
|
163
171
|
後面查了也沒有意義。
|
|
164
172
|
|
|
165
173
|
### 一、`dowafu` 在哪、跑不跑得起來
|
|
@@ -180,6 +188,10 @@ dowafu --version
|
|
|
180
188
|
|
|
181
189
|
**`command -v dowafu` 查不到不代表沒安裝**,別拿那個當判準。
|
|
182
190
|
|
|
191
|
+
**既沒回來也沒報錯,是第三種情況:它在等。** 不帶 `--yes` 時 CLI 會印出確認提示並卡在
|
|
192
|
+
stdin 上,而這在不同 host 會表現成逾時、表現成沒有輸出、或表現成「要不要幫你送出輸入」。
|
|
193
|
+
**記下你的環境是哪一種**——派工當下會再遇到一次,而那個時機點知道就晚了。
|
|
194
|
+
|
|
183
195
|
### 二、lens 定義與 skill 在不在
|
|
184
196
|
|
|
185
197
|
見第 1 節的「skill 與 lens」。有一點對你特別重要:
|
|
@@ -195,6 +207,22 @@ dowafu --version
|
|
|
195
207
|
語法,你不會展開它——入口檔裡若只有那一行,你看到的就是一行字,而**你很可能以為自己
|
|
196
208
|
已經讀過規範了**。實際檢查你的 context 裡有沒有那章的內容,別憑印象。
|
|
197
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
|
+
|
|
198
226
|
---
|
|
199
227
|
|
|
200
228
|
## 4. 輸出
|