@seanyao/roll 4.630.2 → 4.702.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.
Files changed (108) hide show
  1. package/CHANGELOG.md +64 -0
  2. package/README.md +65 -56
  3. package/conventions/global/AGENTS.md +8 -7
  4. package/dist/roll.mjs +12909 -8532
  5. package/docs/INDEX.md +32 -0
  6. package/docs/architecture.md +444 -0
  7. package/docs/difftest-freeze-paradigm.md +113 -0
  8. package/docs/live-console.md +203 -0
  9. package/docs/manifesto.md +65 -0
  10. package/docs/migration/role-taxonomy-v4.md +60 -0
  11. package/docs/verification.md +83 -0
  12. package/guide/INDEX.md +86 -0
  13. package/guide/assets/layouts/cards-2.png +0 -0
  14. package/guide/assets/layouts/cards-3.png +0 -0
  15. package/guide/assets/layouts/cards-4.png +0 -0
  16. package/guide/assets/layouts/compare.png +0 -0
  17. package/guide/assets/layouts/highlight.png +0 -0
  18. package/guide/assets/layouts/pipeline.png +0 -0
  19. package/guide/assets/layouts/plain.png +0 -0
  20. package/guide/assets/layouts/quote.png +0 -0
  21. package/guide/assets/layouts/timeline.png +0 -0
  22. package/guide/en/acceptance-evidence.md +231 -0
  23. package/guide/en/ai-agents.md +185 -0
  24. package/guide/en/backlog-github-sync.md +108 -0
  25. package/guide/en/changelog.md +66 -0
  26. package/guide/en/configuration.md +112 -0
  27. package/guide/en/consistency.md +58 -0
  28. package/guide/en/conventions.md +113 -0
  29. package/guide/en/dream.md +121 -0
  30. package/guide/en/faq.md +855 -0
  31. package/guide/en/feedback.md +31 -0
  32. package/guide/en/getting-started.md +103 -0
  33. package/guide/en/installation.md +86 -0
  34. package/guide/en/legacy-onboarding.md +195 -0
  35. package/guide/en/loop-data-layout.md +256 -0
  36. package/guide/en/loop-driven-architecture.md +186 -0
  37. package/guide/en/loop.md +1324 -0
  38. package/guide/en/methodology.md +715 -0
  39. package/guide/en/migration-2.0.md +154 -0
  40. package/guide/en/overview.md +190 -0
  41. package/guide/en/pairing.md +151 -0
  42. package/guide/en/patterns/README.md +76 -0
  43. package/guide/en/patterns/graft-pattern.md +110 -0
  44. package/guide/en/patterns/replant-pattern.md +114 -0
  45. package/guide/en/patterns/seed-pattern.md +132 -0
  46. package/guide/en/peer.md +71 -0
  47. package/guide/en/pr-review.md +62 -0
  48. package/guide/en/practices/engineering-common-sense.md +395 -0
  49. package/guide/en/pricing.md +116 -0
  50. package/guide/en/project-setup.md +126 -0
  51. package/guide/en/roll-doc-audit.md +98 -0
  52. package/guide/en/skills.md +206 -0
  53. package/guide/en/test-isolation.md +51 -0
  54. package/guide/en/testing/quality-rubric.md +340 -0
  55. package/guide/en/testing.md +123 -0
  56. package/guide/en/tools.md +173 -0
  57. package/guide/skills.md +30 -0
  58. package/guide/zh/acceptance-evidence.md +194 -0
  59. package/guide/zh/ai-agents.md +170 -0
  60. package/guide/zh/backlog-github-sync.md +105 -0
  61. package/guide/zh/changelog.md +57 -0
  62. package/guide/zh/configuration.md +99 -0
  63. package/guide/zh/consistency.md +48 -0
  64. package/guide/zh/conventions.md +96 -0
  65. package/guide/zh/dream.md +97 -0
  66. package/guide/zh/faq.md +773 -0
  67. package/guide/zh/feedback.md +30 -0
  68. package/guide/zh/getting-started.md +96 -0
  69. package/guide/zh/installation.md +83 -0
  70. package/guide/zh/legacy-onboarding.md +192 -0
  71. package/guide/zh/loop-data-layout.md +236 -0
  72. package/guide/zh/loop-driven-architecture.md +186 -0
  73. package/guide/zh/loop.md +1124 -0
  74. package/guide/zh/methodology.md +702 -0
  75. package/guide/zh/migration-2.0.md +154 -0
  76. package/guide/zh/overview.md +186 -0
  77. package/guide/zh/pairing.md +117 -0
  78. package/guide/zh/patterns/README.md +74 -0
  79. package/guide/zh/patterns/graft-pattern.md +108 -0
  80. package/guide/zh/patterns/replant-pattern.md +112 -0
  81. package/guide/zh/patterns/seed-pattern.md +130 -0
  82. package/guide/zh/peer.md +63 -0
  83. package/guide/zh/pr-review.md +54 -0
  84. package/guide/zh/practices/engineering-common-sense.md +393 -0
  85. package/guide/zh/pricing.md +97 -0
  86. package/guide/zh/project-setup.md +114 -0
  87. package/guide/zh/roll-doc-audit.md +90 -0
  88. package/guide/zh/skills.md +191 -0
  89. package/guide/zh/test-isolation.md +46 -0
  90. package/guide/zh/testing/quality-rubric.md +284 -0
  91. package/guide/zh/testing.md +116 -0
  92. package/guide/zh/tools.md +173 -0
  93. package/package.json +4 -1
  94. package/skills/README.md +1 -0
  95. package/skills/roll-.qa/SKILL.md +1 -1
  96. package/skills/roll-.review/SKILL.md +1 -1
  97. package/skills/roll-build/SKILL.md +1 -1
  98. package/skills/roll-build/references/full-contract.md +16 -13
  99. package/skills/roll-design/SKILL.md +3 -3
  100. package/skills/roll-design/references/full-contract.md +17 -13
  101. package/skills/roll-fix/SKILL.md +1 -1
  102. package/skills/roll-fix/references/full-contract.md +13 -10
  103. package/skills/roll-peer/SKILL.md +1 -1
  104. package/skills/roll-prime/SKILL.md +77 -0
  105. package/skills/roll-prime/references/explorer-annex.md +39 -0
  106. package/skills/roll-prime/references/supervisor-prompt.md +165 -0
  107. package/skills/route-cases/skills.json +10 -0
  108. package/template/AGENTS.md +3 -1
@@ -0,0 +1,393 @@
1
+ # Roll 工程常识清单
2
+
3
+ > **这些不是"最佳实践"——它们是基线要求。** 违反即为 Bug。
4
+
5
+ ## 1. 幂等性 🔁
6
+
7
+ **定义:** 同一操作执行 N 次,结果与执行一次相同。
8
+
9
+ **必须测试:**
10
+ ```typescript
11
+ it('should be idempotent', async () => {
12
+ await operation(data) // 第 1 次
13
+ const result1 = await getState()
14
+
15
+ await operation(data) // 第 2 次
16
+ const result2 = await getState()
17
+
18
+ await operation(data) // 第 3 次
19
+ const result3 = await getState()
20
+
21
+ expect(result1).toEqual(result2)
22
+ expect(result2).toEqual(result3)
23
+ })
24
+ ```
25
+
26
+ **常见场景:**
27
+ - [ ] 导入 / 摄取操作
28
+ - [ ] 配置更新
29
+ - [ ] 状态变更
30
+ - [ ] API 调用
31
+ - [ ] 文件写入
32
+
33
+ **本次反面案例:** 重复运行 ingest -> 文件被复制了 7 次
34
+
35
+ ---
36
+
37
+ ## 2. 跨模块契约一致性 🔗
38
+
39
+ **定义:** 在多个模块间共享的数据 / ID / 格式必须完全一致。
40
+
41
+ **必须检查:**
42
+ ```typescript
43
+ // 检查清单
44
+ - [ ] ID 生成算法是否一致?
45
+ - [ ] 数据序列化格式是否一致?
46
+ - [ ] 路径处理是否一致?(例如 / vs -)
47
+ - [ ] 是否已抽取为共享函数 / 常量?
48
+ ```
49
+
50
+ **测试模板:**
51
+ ```typescript
52
+ it('should generate same ID across modules', () => {
53
+ const scannerId = generateScannerId('articles/test.md')
54
+ const inboxId = generateInboxId('articles/test.md')
55
+ expect(scannerId).toEqual(inboxId)
56
+ })
57
+ ```
58
+
59
+ **本次反面案例:** Scanner 用 `-` 替换 `/`,inbox 用原始路径 -> 去重失败
60
+
61
+ ---
62
+
63
+ ## 3. 数据流完整性 🌊
64
+
65
+ **定义:** 从生产者到消费者的完整管道必须端到端贯通。
66
+
67
+ **必须验证:**
68
+ ```typescript
69
+ // 集成测试 —— 必须存在
70
+ describe('Data Flow: Producer -> Consumer', () => {
71
+ it('should write data that consumer can read', async () => {
72
+ await producer.write(testData)
73
+ const result = await consumer.read()
74
+ expect(result).toEqual(testData)
75
+ })
76
+ })
77
+ ```
78
+
79
+ **检查清单:**
80
+ - [ ] 谁写入数据?(生产者)
81
+ - [ ] 谁读取数据?(消费者)
82
+ - [ ] 中间存储是什么?(state / 文件 / 缓存)
83
+ - [ ] 是否有集成测试来验证?
84
+
85
+ **本次反面案例:** Ingest 没有写 state,status 读不到 -> 显示为 0
86
+
87
+ ---
88
+
89
+ ## 4. 原子性 ⚛️
90
+
91
+ **定义:** 一个操作要么完全成功,要么完全不执行(没有中间状态)。
92
+
93
+ **必须考虑:**
94
+ - [ ] 部分失败时如何回滚?
95
+ - [ ] 是否有事务机制?
96
+ - [ ] 崩溃后如何保证数据一致性?
97
+
98
+ **测试模板:**
99
+ ```typescript
100
+ it('should be atomic', async () => {
101
+ try {
102
+ await operation([item1, item2, INVALID_ITEM, item4])
103
+ } catch (e) {
104
+ // 失败后,已处理的项应被回滚
105
+ const state = await getState()
106
+ expect(state).toEqual(initialState)
107
+ }
108
+ })
109
+ ```
110
+
111
+ ---
112
+
113
+ ## 5. 输入校验 🛡️
114
+
115
+ **定义:** 永远不要信任任何外部输入 —— 必须校验。
116
+
117
+ **必须检查:**
118
+ - [ ] Null / undefined 处理
119
+ - [ ] 类型检查
120
+ - [ ] 范围检查(数组长度、数值范围)
121
+ - [ ] 特殊字符 / 注入攻击防护
122
+ - [ ] 文件路径穿越防护
123
+
124
+ **测试模板:**
125
+ ```typescript
126
+ it('should handle invalid inputs gracefully', async () => {
127
+ await expect(operation(null)).rejects.toThrow()
128
+ await expect(operation('')).rejects.toThrow()
129
+ await expect(operation({})).rejects.toThrow()
130
+ })
131
+ ```
132
+
133
+ ---
134
+
135
+ ## 6. 优雅降级 🪂
136
+
137
+ **定义:** 当依赖失败时,系统仍应提供有限的功能。
138
+
139
+ **必须考虑:**
140
+ - [ ] 外部 API 失败怎么办?
141
+ - [ ] 数据库连接断开怎么办?
142
+ - [ ] 是否有兜底机制?
143
+ - [ ] 用户能得到什么反馈?
144
+
145
+ **测试模板:**
146
+ ```typescript
147
+ it('should degrade gracefully when dependency fails', async () => {
148
+ mockDependency.toThrow('Network error')
149
+
150
+ // 不应崩溃
151
+ const result = await operation()
152
+
153
+ // 应返回兜底值或部分结果
154
+ expect(result).toEqual(fallbackValue)
155
+ })
156
+ ```
157
+
158
+ ---
159
+
160
+ ## 7. 可观测性 👁️
161
+
162
+ **定义:** 系统状态必须可见、可追踪。
163
+
164
+ **必须提供:**
165
+ - [ ] 进度反馈(针对长时间运行的操作)
166
+ - [ ] 状态查询接口(例如 status 命令)
167
+ - [ ] 错误日志(失败原因)
168
+ - [ ] 关键指标(计数、耗时)
169
+
170
+ **本次改进:**
171
+ - 新增 `kkb status` 展示原始文件统计 ✅
172
+ - 新增 `kkb compile` 进度反馈 ✅
173
+
174
+ ---
175
+
176
+ ## 8. 并发安全 🧵
177
+
178
+ **定义:** 多线程 / 多进程对共享资源的访问必须安全。
179
+
180
+ **必须考虑:**
181
+ - [ ] 文件读写冲突
182
+ - [ ] 数据库事务隔离级别
183
+ - [ ] 内存中共享状态的加锁
184
+ - [ ] 竞态条件
185
+
186
+ **测试模板:**
187
+ ```typescript
188
+ it('should handle concurrent writes', async () => {
189
+ await Promise.all([
190
+ operation(data1),
191
+ operation(data2),
192
+ operation(data3)
193
+ ])
194
+
195
+ // 验证最终状态一致性
196
+ const state = await getState()
197
+ expect(state).toBeValid()
198
+ })
199
+ ```
200
+
201
+ ---
202
+
203
+ ## 强制检查流程
204
+
205
+ 在每个 Story 的 **测试设计评审(Test Design Review)** 阶段,必须回答以下问题:
206
+
207
+ ```markdown
208
+ ### 工程常识检查清单
209
+ - [ ] **幂等性**:能否重复运行?是否有测试?
210
+ - [ ] **跨模块契约**:ID / 格式 / 算法是否一致?
211
+ - [ ] **数据流**:生产者 -> 消费者管道是否完整?
212
+ - [ ] **原子性**:部分失败时是否回滚?
213
+ - [ ] **输入校验**:所有输入是否都已校验?
214
+ - [ ] **优雅降级**:依赖失败时会发生什么?
215
+ - [ ] **可观测性**:用户能否看到进度 / 状态?
216
+ - [ ] **并发安全**:多线程访问是否安全?
217
+
218
+ **任何一项不满足,都必须在编写实现代码之前补齐测试 / 设计。**
219
+ ```
220
+
221
+ ---
222
+
223
+ ## 9. Shell 脚本性能 🐚
224
+
225
+ **定义:** `$()` 命令替换会 fork 一个子 shell。在热路径(每个测试、每条目录项、每次消息查找都调用的函数)中,这是主要开销来源。
226
+
227
+ **经验法则:**
228
+ - 1 次子 shell fork ≈ Linux 上 2–3 ms
229
+ - 测试套件 setup 中 fork 1000 次 = 每次运行 +2–3 秒
230
+ - 1739 个测试 × 2.3 秒 = **约 67 分钟被浪费的 CI 时间**(本仓库实测)
231
+
232
+ **热路径中必须避免:**
233
+ ```bash
234
+ # ❌ 子 shell fork —— 被调用上千次时很慢
235
+ upper="$(echo "$lang" | tr '[:lower:]' '[:upper:]')"
236
+ upper="$(_some_helper_function "$lang")"
237
+ safe="$(_sanitize_key "$key")"
238
+
239
+ # ✅ 内联等价写法 —— 零 fork
240
+ case "$lang" in
241
+ en|EN) upper=EN ;;
242
+ zh|ZH) upper=ZH ;;
243
+ *) upper="$(printf '%s' "$lang" | tr '[:lower:]' '[:upper:]')" ;; # 罕见路径可接受
244
+ esac
245
+ safe="${key//[^A-Za-z0-9_]/_}" # 参数扩展,无 fork
246
+ printf -v "$varname" '%s' "$val" # 用 printf -v 代替子 shell 赋值
247
+ ```
248
+
249
+ **兼容性陷阱 —— "修了两次"反模式:**
250
+ ```
251
+ PR #211: 修 $(echo | tr) → ${lang^^} ✅ 快,但仅限 bash 4+
252
+ PR #213: 修 bash 3.2 兼容 → $(_helper) ❌ 重新引入了子 shell
253
+ PR #218: 两者都修 → 内联 case ✅ 快且 bash 3.2 安全
254
+ ```
255
+ 为兼容性修复时,要验证修复没有重新引入原来的问题。
256
+ 加一个时延断言或基准测试来守护回归。
257
+
258
+ **内联后的死代码:**
259
+ 内联一个 helper 函数的逻辑时,删掉原函数并 grep 所有调用方。
260
+ 留下一个零调用方的函数会误导后续贡献者通过 `$()` 调用它,从而重新引入 fork。
261
+
262
+ **必须检查:**
263
+ - [ ] 这个函数是否在循环、setup() 或逐条目录加载中被调用?
264
+ - [ ] 它是否在任何地方用了 `$()`?能否用 `case`、`${var//...}` 或 `printf -v` 替换?
265
+ - [ ] 内联之后,原 helper 是否已成为死代码?删掉它。
266
+ - [ ] 是否有时延测试或 CI 上限来捕获回归?(见 `ROLL_TEST_TIME_CAP`)
267
+
268
+ ---
269
+
270
+ ## 10. Shell 资源清理 🧹
271
+
272
+ **定义:** 每个设置的 `trap` 都必须显式重置。临时文件和锁文件绝不能比拥有它的进程存活更久。
273
+
274
+ **trap - EXIT 模式:**
275
+ ```bash
276
+ # ❌ 悬挂的 trap —— 函数返回后 EXIT handler 仍留在调用方 shell 中
277
+ local tmp; tmp=$(mktemp)
278
+ trap "rm -f '$tmp'" EXIT
279
+ # ... 干活 ...
280
+ mv "$tmp" "$dst"
281
+ return 0 # EXIT trap 仍然 armed —— 之后任何 exit 都会对陈旧路径触发 rm
282
+
283
+ # ✅ 用完后总是重置
284
+ local tmp; tmp=$(mktemp)
285
+ trap "rm -f '$tmp'" EXIT
286
+ # ... 干活 ...
287
+ mv "$tmp" "$dst" 2>/dev/null || rm -f "$tmp"
288
+ trap - EXIT # 返回前解除
289
+ return 0
290
+ ```
291
+
292
+ **清理 helper 中的目录作用域:**
293
+ ```bash
294
+ # ❌ 错误 —— 扫描的是环境变量默认值,而不是实际使用的路径
295
+ _cleanup_tmp() {
296
+ local dir; dir=$(dirname "${MY_PATH:-$HOME/.default/path}")
297
+ ...
298
+ }
299
+ _do_work() {
300
+ local custom_path="$1" # 可能与 MY_PATH 不同
301
+ _cleanup_tmp # 扫描了错误的目录!
302
+ }
303
+
304
+ # ✅ 显式传入实际目录
305
+ _cleanup_tmp() {
306
+ local dir="${1:-$(dirname "${MY_PATH:-$HOME/.default/path}")}"
307
+ ...
308
+ }
309
+ _do_work() {
310
+ local custom_path="$1"
311
+ _cleanup_tmp "$(dirname "$custom_path")"
312
+ }
313
+ ```
314
+
315
+ **必须检查:**
316
+ - [ ] 每个 `trap "…" EXIT` 在函数返回前都有匹配的 `trap - EXIT`。
317
+ - [ ] 清理 helper 接受目标目录作为参数 —— 不依赖隐式的环境变量路径。
318
+ - [ ] trap 字符串中临时文件名被引号包住:`"rm -f '$tmp'"` 而不是 `"rm -f $tmp"`。
319
+
320
+ ---
321
+
322
+ ## 11. 测试可靠性 🧪
323
+
324
+ **定义:** 测试不得依赖在不同主机上可能静默失败的环境假设。
325
+
326
+ **PID 假设:**
327
+ ```bash
328
+ # ❌ 假设 pid_max ≤ 99999 —— 在 pid_max 较大的容器中会静默失败
329
+ local stale_tmp="runs.jsonl.tmp.99999"
330
+
331
+ # ✅ 使用一个确定已死的进程
332
+ bash -c 'exit 0' &
333
+ local dead_pid=$!
334
+ wait "$dead_pid" 2>/dev/null || true
335
+ local stale_tmp="runs.jsonl.tmp.${dead_pid}"
336
+ ```
337
+
338
+ **Heredoc 作用域:**
339
+ 在 heredoc 之外定义的函数,在生成的脚本执行时无法在其内部使用。
340
+ 调用它们会静默 no-op(若用 `|| true` 守护)或直接崩溃。
341
+ ```bash
342
+ # ❌ _some_helper 在生成脚本的作用域中未定义
343
+ cat > script.sh <<'EOF'
344
+ _some_helper 2>/dev/null || true # 静默 no-op —— 永远"成功"
345
+ EOF
346
+
347
+ # ✅ 要么内联逻辑,要么在 heredoc 内部定义该函数
348
+ ```
349
+
350
+ **必须检查:**
351
+ - [ ] 测试是否使用了可能在主机上冲突的硬编码 PID、端口或路径?
352
+ - [ ] 测试是否调用了只在外层 shell 定义、而非 heredoc 内部定义的函数?
353
+ - [ ] "死进程"检查是否使用了真正已退出的进程,而不是猜测的 PID?
354
+
355
+ ---
356
+
357
+ ## 自动化防护
358
+
359
+ ### CI 闸门规则
360
+ ```yaml
361
+ # .github/roll-checks.yml —— 作为 CI 闸门在每个 PR 上强制执行
362
+ checks:
363
+ idempotency:
364
+ - pattern: "ingest|import|sync"
365
+ require_test: "idempotency"
366
+
367
+ cross_module_contract:
368
+ - files: ["src/*/index.ts"]
369
+ check: "shared_id_generation"
370
+
371
+ data_flow:
372
+ - require_integration_test: true
373
+ ```
374
+
375
+ 这些作为 CI 闸门在每个 PR 上运行。慢性问题 —— 死代码、文档过期、结构漂移 ——
376
+ 由 `roll-.dream`(每晚代码健康扫描)捕获,并把 `REFACTOR-XXX` 条目写回 backlog。
377
+
378
+ ### Pre-Commit 钩子
379
+ ```bash
380
+ #!/bin/bash
381
+ # .git/hooks/pre-commit
382
+ echo "🔍 Checking engineering common sense..."
383
+
384
+ # 检查幂等性测试
385
+ if git diff --cached --name-only | grep -q "ingest\|import\|sync"; then
386
+ if ! grep -r "idempotency\|repeated run\|multiple times" tests/ 2>/dev/null; then
387
+ echo "❌ Missing idempotency tests!"
388
+ exit 1
389
+ fi
390
+ fi
391
+
392
+ echo "✅ Basic checks passed"
393
+ ```
@@ -0,0 +1,97 @@
1
+ # Pricing — 成本可见性与价格快照
2
+
3
+ Roll 按**模型公开单价**(而非你的订阅价格)计算每轮 cycle 的成本 — 它是一个可跨项目、跨 agent 对比的基准数字。本文档介绍 `roll config prices` 命令、价格快照机制、以及历史成本如何不受调价影响。
4
+
5
+ ## 成本显示在哪里
6
+
7
+ dashboard(`roll loop status`)在每轮 cycle 显示两列成本相关数据:
8
+
9
+ | 列 | 含义 |
10
+ |----|------|
11
+ | **model** | 使用的 agent + 版本(如 `deepseek-v4-pro`、`claude-sonnet-4-6`),决定了哪套价格生效 |
12
+ | **cost** | 按公开单价 × 该轮实际 token 用量计算。币种跟随厂商:Anthropic 显示 `$`(USD),DeepSeek / Kimi 显示 `¥`(CNY) |
13
+
14
+ Roll 通过**价格快照文件**(而非硬编码常量)查询单价。快照存放在 Roll 安装目录下的 `lib/prices/` 中。
15
+
16
+ ## 支持的厂商
17
+
18
+ | 厂商 | 币种 | 数据来源 |
19
+ |------|------|----------|
20
+ | Anthropic (Claude) | USD | `platform.claude.com/docs/en/about-claude/pricing` |
21
+ | DeepSeek | CNY | `api-docs.deepseek.com/zh-cn/quick_start/pricing/` |
22
+ | Kimi (Moonshot) | CNY | `platform.kimi.com/docs/pricing/chat` |
23
+
24
+ ## `roll config prices` 命令
25
+
26
+ ```bash
27
+ roll config prices show # 打印当前所有厂商的价格快照表
28
+ roll config prices refresh # 拉取所有厂商官方定价文档、对比、有变化才落新快照
29
+ ```
30
+
31
+ ### `roll config prices show`
32
+
33
+ 打印当前生效快照的元数据和所有已知模型的每百万 token 单价表:
34
+
35
+ ```
36
+ in 基础输入 token
37
+ out 输出 token
38
+ cw 缓存写入 token(单价比输入略高)
39
+ cr 缓存读取 token(单价极低)
40
+ ```
41
+
42
+ 费率单位:**每百万 token,厂商本地币种**。
43
+
44
+ ### `roll config prices refresh`
45
+
46
+ 从各厂商拉取官方定价页面,解析价格表,与本地最新快照对比。支持按厂商刷新:
47
+ `roll config prices refresh anthropic|deepseek|kimi`。
48
+
49
+ - **价格有变** → 写入新快照文件(`snapshot-YYYY-MM-DD.json`),终端打印 diff(红色减、绿色加),dashboard 下次渲染时自动使用新价格。
50
+ - **无变化** → 打印 `up to date` 后退出。
51
+
52
+ 网络故障或页面解析失败时,命令会报错退出 — **已有的快照不会被失败的拉取覆盖**。
53
+
54
+ ## 价格快照
55
+
56
+ 每个快照是一个 JSON 文件,按日期命名,存放在 `lib/prices/` 下:
57
+
58
+ ```
59
+ lib/prices/
60
+ snapshot-2026-05-22.json
61
+ snapshot-2026-06-01.json ← refresh 检测到价格变化后写入
62
+ ```
63
+
64
+ 快照内容:
65
+
66
+ | 字段 | 说明 |
67
+ |------|------|
68
+ | `version` | 快照创建时的 ISO 8601 时间戳 |
69
+ | `effective_at` | 厂商开始执行此价格的日期 |
70
+ | `source_url` | 使用的官方定价页面 URL |
71
+ | `prices` | 字典:`模型名 → {in, out, cache_create, cache_read}` 每百万 token 单价 |
72
+
73
+ 快照**永不删除** — 每个版本都保留,方便回溯任意时间点生效的费率表。
74
+
75
+ ## 历史成本固化
76
+
77
+ loop cycle 结束时,Roll 会在 usage 事件中额外写入两个字段:
78
+
79
+ | 字段 | 用途 |
80
+ |------|------|
81
+ | `cost_list_usd` | 按当时快照计算出的成本 — 永久固定 |
82
+ | `prices_version` | 计算时使用的快照版本号 |
83
+
84
+ dashboard 渲染历史 cycle 时优先读取 `cost_list_usd`。如果该字段缺失(此功能上线之前的旧 cycle),则回退到用*当前*快照现算,并在行末追加浅灰色 `[legacy]` 标记。
85
+
86
+ **核心效果:** 厂商调价、`roll config prices refresh`、Roll 版本升级都不会回头改写历史 cycle 的成本数字。"当时实际花了多少"是事实,不动。
87
+
88
+ ## 常见问题
89
+
90
+ **Q: cost 列反映的是我的实际账单吗?**
91
+ 不是。它使用的是公开单价。如果你是订阅用户(Claude Pro、Team 等),实际成本会更低。把它当成一个可横向对比的基准数字。
92
+
93
+ **Q: 价格变动后怎么办?**
94
+ 运行 `roll config prices refresh`。如果有变化会自动写新快照,后续 cycle 使用新价格。旧 cycle 的历史成本保持不变。
95
+
96
+ **Q: 能加其他厂商的价格吗?**
97
+ 可以 — `roll config prices refresh --vendor deepseek`(或 `kimi`)。`--vendor` 参数告诉抓取器去爬哪个厂商的定价页面。
@@ -0,0 +1,114 @@
1
+ # Roll — 项目初始化
2
+
3
+ ## 初始化项目
4
+
5
+ 在项目根目录执行:
6
+
7
+ ```bash
8
+ roll init
9
+ ```
10
+
11
+ `roll init` 会先诊断当前目录状态,再决定是否改动文件:
12
+
13
+ 1. **空目录** —— 全新起点。Roll 直接写入 `AGENTS.md`、空的 `.roll/`
14
+ 骨架(`backlog.md`、`features/`、`domain/`),可继续在 `.roll/agents.yaml`
15
+ 声明 scoped agent binding。不问问题。这是
16
+ **seed(播种)** 接入模式 —— 见 [patterns/seed-pattern.md](patterns/seed-pattern.md)。
17
+ 2. **PRD/文档-only** —— Roll 发现需求或产品文档,但没有源码和 manifest。
18
+ 这是新项目路径,会指向设计;不会进入已有代码库接入。
19
+ 3. **已有代码库但未接入 Roll** —— Roll 检测到源码但没有 `.roll/`。它**不会**默默
20
+ 生成骨架,而是引导你用 `$roll-onboard`:扫描代码、问一组认知 / 范围 /
21
+ 隐私问题、产出 `.roll/init-diagnosis.yaml` 和 `.roll/onboard-plan.yaml`
22
+ 供审阅。审阅成对产物后执行
23
+ `roll init --apply`:它会打印审阅检查点,列出每个计划文件操作的动作、目标路径、
24
+ 合并/创建模式和用户内容处理方式,并在交互终端等待确认。非交互自动化里,审阅后必须显式执行
25
+ `roll init --apply --auto`。这是 **graft(嫁接)** 模式 —— 见
26
+ [legacy-onboarding.md](legacy-onboarding.md) 与
27
+ [patterns/graft-pattern.md](patterns/graft-pattern.md)。
28
+ 4. **已初始化** —— `.roll/`、`AGENTS.md`、backlog、features 都存在。Roll
29
+ 打印 `Already initialized` 和 `Next: roll status`。
30
+ 5. **部分接入 Roll** —— 有一部分 Roll 标记但不完整。Roll 打印
31
+ 缺失项和仍存在的 pre-v2 旧标记。`roll init --repair` 会先预览修复计划,
32
+ 在交互终端等待确认;非交互自动化必须显式执行 `roll init --repair --auto`。
33
+ 修复只创建缺失的 Roll-owned 文件或合并 Roll-owned 区块,并写入
34
+ `.roll/onboard-changeset.yaml`,之后 `roll setup offboard` 可以反向移除这些改动。
35
+
36
+ 任一路径之后,都可以用 `roll next` 接着走。它读取相同的 Roll 标记,以及
37
+ `.roll/brief.md`、`.roll/onboard-plan.yaml`、`.roll/backlog.md`,只输出一个下一步:
38
+ 从 brief 进入设计、审阅并 apply onboard plan、修复 partial 标记、执行旧布局迁移、
39
+ 对下一张 Todo 开 loop,或在没有可执行项时查看 status。
40
+
41
+ 正在从 2.0 之前的布局升级(`BACKLOG.md` 在根目录或 `docs/features/`)?
42
+ 先跑 `npx @seanyao/roll@2 migrate` —— 见
43
+ [migration-2.0.md](migration-2.0.md)。`roll init` 会拒绝在迁移到一半的
44
+ 项目上叠加骨架。
45
+
46
+ ## 更新约定和技能
47
+
48
+ roll 发布新版本后,将新约定同步到项目:
49
+
50
+ ```bash
51
+ roll sync
52
+ ```
53
+
54
+ `sync` 只覆盖 roll 管理的文件(技能和全局约定),不会动你的 `.roll/backlog.md`、项目源码等文件。
55
+
56
+ ## 典型首次使用流程
57
+
58
+ ```bash
59
+ curl -fsSL https://seanyao.github.io/roll/install | bash # 安装 roll
60
+ roll setup # 全机器配置 AI 工具(仅需一次)
61
+ cd my-project
62
+ roll init # 诊断并路由该项目
63
+ roll next # 接续 design/apply/repair/migrate/loop/status
64
+ roll loop on # 开启自主执行
65
+ ```
66
+
67
+ `roll setup` 会为本机已安装的 AI 工具同步约定。Agent 语义写在
68
+ `~/.roll/agents.yaml`(Machine Scope)和 `.roll/agents.yaml`(Project Scope)。
69
+ 旧的 `primary_agent`、local agent、pairing 或 v3 route-slot 数据可以通过
70
+ `roll agent migrate --dry-run` 预览迁移到 scoped 模型。
71
+
72
+ ## 创建的文件
73
+
74
+ | 文件 | 用途 |
75
+ |------|------|
76
+ | `AGENTS.md` | Agent 约定:领域模型、作用域、编码规范(根目录 — 所有 AI 客户端的入口) |
77
+ | `.roll/backlog.md` | 故事跟踪(Epic / Feature / Story / Fix / Refactor) |
78
+ | `.roll/features/` | 每个 Feature 的深度文档 |
79
+ | `.roll/domain/` | DDD 模型、context map、架构记录 |
80
+
81
+ ## 幂等性
82
+
83
+ `roll init` 可安全重复执行:完整项目会提示 `roll status`,部分项目会提示
84
+ `roll init --repair`,不会再次强行跑脚手架。
85
+
86
+ ## 另见
87
+
88
+ - [installation.md](installation.md) — 安装和更新 roll
89
+ - [conventions.md](conventions.md) — AGENTS.md 结构和约定
90
+ - [patterns/](patterns/README.md) — 三种接入模式(seed / graft / replant)
91
+ - [legacy-onboarding.md](legacy-onboarding.md) — 将 Roll 嫁接到已有代码库
92
+ - [migration-2.0.md](migration-2.0.md) — 从 2.0 之前的布局升级到 `.roll/`
93
+ - [loop.md](loop.md) — 开启自主执行
94
+
95
+ ## Git Hooks 自动配置(US-INFRA-008/009)
96
+
97
+ Roll 的 TCR 提交前检查在 `hooks/pre-commit` 里。
98
+ Git 默认忽略这个目录——需要把 `core.hooksPath` 指向它才能生效。
99
+ Roll 在三个地方自动完成配置,不会出现"检查门被绕过"的时间窗口:
100
+
101
+ 1. **`roll setup`** — 在当前仓库设置 `core.hooksPath=hooks`。
102
+ 2. **自主 loop 每轮 cycle preflight** — 每轮启动时确保 worktree 的 hooks 路径正确。
103
+ 3. **Claude Code SessionStart hook**(`.claude/settings.json`)— 每次新开 Claude Code 会话时自动执行 `git config core.hooksPath hooks`。
104
+
105
+ **手动覆盖:** 如果你已经把 `core.hooksPath` 设成了别的值,Roll 不会覆盖它。
106
+ 自动配置只在该值未设或等于 git 默认值 `.git/hooks` 时才触发。
107
+
108
+ **排查:** 提交时没有运行测试:
109
+
110
+ ```bash
111
+ git config core.hooksPath # 应该显示: hooks
112
+ ls hooks/pre-commit # 应该存在且可执行
113
+ roll setup # 重新执行配置步骤
114
+ ```
@@ -0,0 +1,90 @@
1
+ # roll-doc-audit —— 文档/产品一致性审计
2
+
3
+ `roll-doc-audit` 核对用户可见文档表面与真实实现: README、指南、网站页面、CLI help、
4
+ 测试和源码。需要文档盘点时,它也会产出草稿文档:文档索引、为缺文档目录补的模块
5
+ README,以及 Phase 3b 阶段的跨目录主题文档(数据流、状态机、外部集成等)。它不会
6
+ 在没有源码证据时编造行为。
7
+
8
+ ```
9
+ $roll-doc-audit # 完整运行(全部 phase)
10
+ $roll-doc-audit --dry-run # 仅 Phase 1–2;打印 Phase 3 / 3b 计划,不写任何文件
11
+ $roll-doc-audit --force # 即便目标文件已存在也重新生成草稿
12
+ ```
13
+
14
+ ## 四 Phase 全流程
15
+
16
+ roll-doc-audit 依序运行四个 phase,外加深度读取的 Phase 3b——当项目存在值得记录的
17
+ 跨目录结构时触发。
18
+
19
+ | Phase | 名称 | 做什么 |
20
+ |-------|------|--------|
21
+ | 1 | Scan & Index | 遍历目录树,分类每个 `*.md` 与约定文件,(覆盖)写出 `docs/INDEX.md`,含覆盖率摘要与缺口报告。 |
22
+ | 2 | Gap Analysis | 找出有 ≥ 3 个源文件(或被 ≥ 5 个文件引用)却无 `README.md` 的模块目录,以及特殊缺口(领域模型图、约定文档)。 |
23
+ | 3 | Fill | 对每个目录级缺口,读取至多 20 个源文件并生成草稿 `README.md` / 上下文图 / 约定文档。已存在的文件除非 `--force` 否则跳过。 |
24
+ | 3b | Deep Read | 构建完整项目符号表(全量读取,不截断),侦测 Phase 3 单独无法发现的六类跨目录主题。 |
25
+ | 4 | Report | 打印各 phase 摘要:索引文档数、缺口数、生成草稿数、Phase 3b 符号表计数与主题文档。 |
26
+
27
+ Phase 3b 是"逐目录"文档与"贯穿整个代码库逻辑"文档之间的分水岭。Phase 3 孤立地
28
+ 读取每个缺口目录(且每个目录至多 20 个文件);Phase 3b 全量读取每个源文件并跨文件
29
+ 推理。
30
+
31
+ ## Phase 3b —— 六类主题
32
+
33
+ Phase 3b 在**满足任一条件**时运行:Phase 2 发现了缺口,**或**项目展现出 Phase 3
34
+ 无法捕捉的代码特征(跨 ≥ 3 个目录的 import 链、被共享的状态枚举、外部端点调用,
35
+ 或 CI 配置)。纯文档项目若无源码缺口则完全跳过 Phase 3b。
36
+
37
+ 构建符号表(`exports`、`imports`、`enums`、`external_urls`、`configs`)后,
38
+ Phase 3b 侦测六类主题。每类在其侦测规则无命中时跳过,目标文件已存在时也跳过
39
+ (除非 `--force`)。
40
+
41
+ | # | 主题 | 触发条件 | 输出 |
42
+ |---|------|----------|------|
43
+ | 1 | 数据流 / 调用链 | 从入口文件(`bin/`、`main.*`、`index.*`)出发的 import 链跨越 ≥ 3 个不同源目录 | `docs/data-flows.md` |
44
+ | 2 | 状态机 | 名为 `*State` / `*Status` 的枚举被 ≥ 2 个源文件引用 | `docs/state-machines.md` |
45
+ | 3 | 外部集成 | `fetch` / `axios` / `http.*` 调用或 `*_URL` / `*_HOST` 常量(排除注释与测试夹具) | `docs/integrations.md` |
46
+ | 4 | 部署管线 | 存在 CI 配置文件(`.github/workflows/*.yml`、`.gitlab-ci.yml`、`circle.yml`、`Jenkinsfile`)加部署 URL 模式 | `docs/deployment.md` |
47
+ | 5 | Agent 入口 | 根目录无 `AGENTS.md` 且源码根有 ≥ 3 个子目录 | `AGENTS.md` |
48
+ | 6 | 高引用目录 | 某目录被 ≥ 5 个其他源文件引用,即使自身 < 3 个源文件 | `<dir>/README.md` |
49
+
50
+ 每篇主题文档都为每条论断标注 `file:line`,均来自真实符号表记录——roll-doc-audit 绝不
51
+ 伪造行号。
52
+
53
+ ## dry-run / force 行为
54
+
55
+ **`--dry-run`** 运行 Phase 1–2,随后打印 Phase 3 填充计划与 Phase 3b 计划
56
+ (符号表摘要计数,加上*将要*生成的主题文档,每条标 `(plan)`)。不写任何磁盘文件。
57
+ 用它在完整运行前先预览。
58
+
59
+ **`--force`** 即便目标文件已存在也重新生成草稿。它只影响草稿生成(Phase 3 与
60
+ Phase 3b 的输出文件);无论带不带 flag,符号表每次运行都从头重建。`--force` 不改变
61
+ `docs/INDEX.md` 的行为(始终重建),也绝不覆盖草稿目标之外的人工内容。
62
+
63
+ **默认(无 flag)** 是幂等的:无新缺口时重新运行是 no-op——不写文件,不改已有
64
+ 草稿。
65
+
66
+ ## 典型输出文件清单
67
+
68
+ 对一个含代码的项目完整运行,可能产出:
69
+
70
+ ```
71
+ docs/INDEX.md # Phase 1 —— 始终(覆盖)写出
72
+ src/<module>/README.md # Phase 3 —— 每个模块缺口一个
73
+ docs/CONVENTIONS.md # Phase 3 —— 当无约定文档时
74
+ .roll/domain/context-map.md # Phase 3 —— 当无领域条目时
75
+ docs/data-flows.md # Phase 3b —— 跨目录调用链
76
+ docs/state-machines.md # Phase 3b —— 共享状态枚举
77
+ docs/integrations.md # Phase 3b —— 外部端点
78
+ docs/deployment.md # Phase 3b —— CI 管线
79
+ AGENTS.md # Phase 3b —— 仅当不存在时
80
+ <dir>/README.md # Phase 3b —— 高引用目录
81
+ ```
82
+
83
+ 只有 `docs/INDEX.md` 会被覆盖——它是派生产物。其余每个文件都是草稿,以下面这行
84
+ 开头:
85
+
86
+ ```
87
+ > **Draft** —— auto-generated by roll-doc-audit on YYYY-MM-DD. Review before treating as authoritative.
88
+ ```
89
+
90
+ 审阅每篇草稿,按需修改,提交你想保留的那些。