@double-codeing/flow2spec 3.0.19 → 3.1.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.
Files changed (52) hide show
  1. package/README.en.md +15 -6
  2. package/README.md +5 -5
  3. package/cli.js +122 -11
  4. package/docs/.mermaid-cache.json +1 -1
  5. package/docs/en/architecture.md +5 -5
  6. package/docs/en/commands-reference.md +29 -48
  7. package/docs/en/design-principles.md +12 -9
  8. package/docs/en/directory-conventions.md +26 -3
  9. package/docs/en/usage-guide.md +16 -10
  10. package/docs/en/usage-scenarios.md +3 -3
  11. package/docs//344/275/223/347/263/273/344/270/216/345/216/237/347/220/206.md +4 -4
  12. package/docs//344/275/277/347/224/250/346/241/210/344/276/213-/346/250/241/346/213/237/345/257/271/350/257/235.md +2 -2
  13. package/docs//344/275/277/347/224/250/350/257/264/346/230/216.md +15 -10
  14. package/docs//345/221/275/344/273/244/350/257/264/346/230/216.md +28 -51
  15. package/docs//347/233/256/345/275/225/344/270/216/350/267/257/345/276/204/347/272/246/345/256/232.md +26 -3
  16. package/docs//350/256/276/350/256/241/350/257/264/346/230/216.md +88 -57
  17. package/lib/claudeSettingsAdapter.js +99 -30
  18. package/lib/flow2specConfig.js +32 -6
  19. package/lib/init.js +264 -4
  20. package/package.json +2 -2
  21. package/templates/AGENTS.codex-stub.md +2 -0
  22. package/templates/AGENTS.md +18 -5
  23. package/templates/flow2spec.config.json +5 -2
  24. package/templates/hooks/f2s-config-inject.js +9 -147
  25. package/templates/hooks/f2s-config-session.js +95 -0
  26. package/templates/hooks/f2s-update-check.js +141 -0
  27. package/templates/knowledge/index.md +4 -4
  28. package/templates/knowledge/manifest-routing.json +34 -5
  29. package/templates/knowledge/template//347/273/210/347/250/277/346/250/241/347/211/210.md +2 -2
  30. package/templates/knowledge/topics/f2s-config-precheck.md +2 -2
  31. package/templates/knowledge/topics/f2s-fallback-triage.md +2 -2
  32. package/templates/knowledge/topics/f2s-stock-docs-vs-req-docs.md +3 -3
  33. package/templates/rules/f2s-config-check.mdc +3 -1
  34. package/templates/rules/f2s-flow2spec-unified-entry.mdc +21 -3
  35. package/templates/rules/f2s-implement-tech-design.mdc +1 -1
  36. package/templates/rules/f2s-karpathy-guidelines.mdc +1 -1
  37. package/templates/rules/f2s-stock-docs-vs-req-docs.mdc +3 -3
  38. package/templates/rules/f2s-topic-authoring.mdc +124 -0
  39. package/templates/skills/f2s-doc-arch/SKILL.md +37 -9
  40. package/templates/skills/f2s-doc-final/SKILL.md +5 -5
  41. package/templates/skills/f2s-git-commit/SKILL.md +21 -5
  42. package/templates/skills/{f2s-doc-add → f2s-kb-add}/SKILL.md +12 -7
  43. package/templates/skills/f2s-kb-addRules/SKILL.md +165 -0
  44. package/templates/skills/{f2s-ctx-build → f2s-kb-build}/SKILL.md +14 -9
  45. package/templates/skills/f2s-kb-feat/SKILL.md +8 -6
  46. package/templates/skills/f2s-kb-fix/SKILL.md +8 -6
  47. package/templates/skills/f2s-kb-migrate/SKILL.md +12 -10
  48. package/templates/skills/{f2s-ctx-rm → f2s-kb-rm}/SKILL.md +7 -5
  49. package/templates/skills/f2s-kb-sync/SKILL.md +13 -5
  50. package/templates/skills/f2s-kb-upgrade/SKILL.md +27 -11
  51. package/templates/skills/f2s-karpathy-guidelines/SKILL.md +0 -20
  52. package/templates/skills/stock-docs-vs-req-docs/SKILL.md +0 -35
@@ -27,12 +27,12 @@
27
27
 
28
28
  仓内 **四环**(规则环与技能环分列,勿合并为「规则+技能」):
29
29
 
30
- | 环 | 落点 | 职责 |
31
- | --- | --- | --- |
32
- | 知识环 | `.Knowledge/` | 路由 + 主题 + 存量/需求文档 |
33
- | 任务环 | `.task/` | 跨会话续作、用户代办 |
30
+ | 环 | 落点 | 职责 |
31
+ | ------ | ---------------------------- | ------------------------------------ |
32
+ | 知识环 | `.Knowledge/` | 路由 + 主题 + 存量/需求文档 |
33
+ | 任务环 | `.task/` | 跨会话续作、用户代办 |
34
34
  | 规则环 | 各工具 `rules` / `AGENTS.md` | 怎么读、怎么做(缺口闸门、路由顺序) |
35
- | 技能环 | `f2s-*` / `skills/` | 维护知识、触发 feat/fix/sync 等 |
35
+ | 技能环 | `f2s-*` / `skills/` | 维护知识、触发 feat/fix/sync 等 |
36
36
 
37
37
  ```mermaid
38
38
  graph TB
@@ -72,13 +72,13 @@ graph TB
72
72
  L2 --- V
73
73
  ```
74
74
 
75
- | 层级 | 路径 | 作用 |
76
- | --- | --- | --- |
77
- | L0 | `manifest-routing.json` | 机读路由、依赖声明 |
78
- | L1 | `matchers/*.json` | 关键词命中,**match** 只读一片 |
79
- | L2 | `topics/*.md` | 硬约束摘要;**expand** 拉依赖 |
80
- | L3 | `stock-docs/`、`req-docs/` | 长文档,按需下钻 |
81
- | 纵链 | `topicDependencies` | 主题级前置,所有任务共享 |
75
+ | 层级 | 路径 | 作用 |
76
+ | ---- | -------------------------- | ------------------------------ |
77
+ | L0 | `manifest-routing.json` | 机读路由、依赖声明 |
78
+ | L1 | `matchers/*.json` | 关键词命中,**match** 只读一片 |
79
+ | L2 | `topics/*.md` | 硬约束摘要;**expand** 拉依赖 |
80
+ | L3 | `stock-docs/`、`req-docs/` | 长文档,按需下钻 |
81
+ | 纵链 | `topicDependencies` | 主题级前置,所有任务共享 |
82
82
 
83
83
  读取流水线:`match → expand → verify → act`(详见 [体系与原理 §4](./体系与原理.md))。
84
84
 
@@ -105,8 +105,6 @@ graph LR
105
105
  note2["规则随工具升级"] -.-> R
106
106
  ```
107
107
 
108
-
109
-
110
108
  ### 2. 渐进式路由
111
109
 
112
110
  ```mermaid
@@ -120,8 +118,6 @@ graph LR
120
118
  M -->|未命中| FB[fallback-triage\n结构化分诊]
121
119
  ```
122
120
 
123
-
124
-
125
121
  ### 3. 技能维护闭环
126
122
 
127
123
  <p><img src="./images/flow-1.png" alt="技能维护闭环" style="max-width:100%;" /></p>
@@ -142,9 +138,9 @@ graph LR
142
138
 
143
139
  D1["架构文档"] -->|f2s-doc-arch| FIN["f2s-doc-final"]
144
140
  D2["PDF/初稿"] -->|f2s-doc-final| FIN
145
- FIN --> CTX["f2s-ctx-build"] --> K
141
+ FIN --> CTX["f2s-kb-build"] --> K
146
142
 
147
- OLD["存量代码/文档"] -->|f2s-doc-add| K
143
+ OLD["存量代码/文档"] -->|f2s-kb-add| K
148
144
 
149
145
  NR["新需求"] --> CL["f2s-req-clarify"] --> BE["f2s-req-backend"]
150
146
  BE --> IMPL["实现xxx技术方案"] -->|自动触发implement-tech-design规则| K
@@ -154,9 +150,7 @@ graph LR
154
150
 
155
151
  </details>
156
152
 
157
- 七条入口 · `f2s-git-commit` 是提交时的知识纪律收口 · `.Knowledge/` 是唯一汇聚点 · 知识驱动 AI,AI 驱动下轮开发
158
-
159
-
153
+ 七条入口 · `f2s-git-commit` 是提交时的知识纪律收口 · `.Knowledge/` 是唯一汇聚点 · 知识驱动 AI,AI 驱动下轮开发
160
154
 
161
155
  ### 4. 任务清单与跨会话续作
162
156
 
@@ -170,10 +164,51 @@ graph LR
170
164
  LD --> RS[按原技能约束继续]
171
165
  ```
172
166
 
173
- 任务不因会话结束丢失 · 关键词自动续作,无需重新说明上下文 · 技能约束完整恢复
167
+ 任务不因会话结束丢失 · 关键词自动续作,无需重新说明上下文 · 技能约束完整恢复
174
168
 
175
169
  ---
176
170
 
171
+ ### 5.知识库更新检测
172
+
173
+ ```mermaid
174
+ flowchart LR
175
+ A[用户执行 flow2spec init codex] --> B[写入 .codex/hooks/f2s-update-check.js]
176
+ A --> C[写入 .codex/hooks.json]
177
+
178
+ C --> D[注册 Codex SessionStart hook]
179
+ D --> E[matcher: startup|resume]
180
+ E --> F[command: node .codex/hooks/f2s-update-check.js]
181
+
182
+ G[Codex 新 session 启动或恢复] --> H{项目 hook 已信任?}
183
+ H -- 否 --> H1[Codex 提示通过 /hooks 审核并信任]
184
+ H1 --> H2[本次 hook 不自动执行]
185
+ H -- 是 --> F
186
+
187
+ F --> I{CI 环境?}
188
+ I -- 是 --> Z[静默跳过]
189
+ I -- 否 --> J{updateCheck.enabled=false?}
190
+
191
+ J -- 是 --> Z
192
+ J -- 否 --> K{.Knowledge/update-check.json 今天已检查?}
193
+
194
+ K -- 是 --> Z
195
+ K -- 否 --> L[读取 .Knowledge/manifest-routing.json version]
196
+
197
+ L --> M{有 manifest version?}
198
+ M -- 否 --> Z
199
+ M -- 是 --> N[npm view 当前包名 version]
200
+
201
+ N --> O[写入 .Knowledge/update-check.json 缓存]
202
+ O --> P{manifest version < npm latest?}
203
+
204
+ P -- 否 --> Z
205
+ P -- 是 --> Q[stdout 输出 JSON]
206
+
207
+ Q --> R[hookSpecificOutput.additionalContext]
208
+ R --> S[Codex 把提示注入会话上下文]
209
+ S --> T[提示用户执行 f2s-kb-upgrade]
210
+ ```
211
+
177
212
  ## 设计亮点
178
213
 
179
214
  ### 一、路由与上下文加载
@@ -220,7 +255,7 @@ taskC → [main] ← 漏写了
220
255
  └──────────────────────────────────────────┘
221
256
  ```
222
257
 
223
- 路由层保持轻量 · 执行细节按需加载 · 两者独立更新
258
+ 路由层保持轻量 · 执行细节按需加载 · 两者独立更新
224
259
 
225
260
  #### 4. 禁止全量扫描是硬约束
226
261
 
@@ -251,7 +286,7 @@ description: >
251
286
  用户输入 → Agent 扫 description 做语义匹配 → 触发对应技能
252
287
  ```
253
288
 
254
- 触发词在 description 里 · 不在正文里 · 命中率更高 · 双语覆盖减少漏触发
289
+ 触发词在 description 里 · 不在正文里 · 命中率更高 · 双语覆盖减少漏触发
255
290
 
256
291
  ---
257
292
 
@@ -294,13 +329,13 @@ git log .Knowledge/
294
329
 
295
330
  a3f1c2 f2s-kb-feat: 新增退款状态机路由
296
331
  b7e9d1 f2s-kb-fix: 修正 RestTemplate 注入约定
297
- c2a8f0 f2s-ctx-build: 订单服务架构说明入库
332
+ c2a8f0 f2s-kb-build: 订单服务架构说明入库
298
333
  d5b3e9 f2s-kb-sync: 沉淀支付重试队列设计
299
334
 
300
335
  代码变更 + 知识变更 → 同一 commit 或相邻 commit
301
336
  ```
302
337
 
303
- 知识有版本 · 可 review · 可回溯 · 可 blame
338
+ 知识有版本 · 可 review · 可回溯 · 可 blame
304
339
 
305
340
  #### 4. 禁止历史否定堆砌
306
341
 
@@ -313,7 +348,7 @@ git log .Knowledge/
313
348
  → 原写法已废弃,现改为 Bean 注入
314
349
  ```
315
350
 
316
- 每次修复原位改写 · 不叠加历史 · 知识库永远只描述现在
351
+ 每次修复原位改写 · 不叠加历史 · 知识库永远只描述现在
317
352
 
318
353
  ---
319
354
 
@@ -337,7 +372,7 @@ implement-tech-design 执行流
337
372
  输出待完成清单与提醒 ← 不可跳过
338
373
  ```
339
374
 
340
- 建议 → 可以被跳过 · 约束 → 必须明确处理才能继续
375
+ 建议 → 可以被跳过 · 约束 → 必须明确处理才能继续
341
376
 
342
377
  #### 2. fallback 本身是有程序的 topic
343
378
 
@@ -351,9 +386,7 @@ graph TD
351
386
  Q -->|不确定| STOP[停止执行\n等待明确指令]
352
387
  ```
353
388
 
354
-
355
-
356
- 未命中 ≠ 静默失败 · 降级本身有明确程序
389
+ 未命中 ≠ 静默失败 · 降级本身有明确程序
357
390
 
358
391
  #### 3. manifest / index 写权硬约束
359
392
 
@@ -380,7 +413,7 @@ matchers/*.json(diff 模式)
380
413
  ❌ 整文件重写严格禁止
381
414
  ```
382
415
 
383
- 原因:文档需要保证「现行真值覆盖 / 文风一致 / 禁历史否定堆砌」 · 要求写的人看到全文上下文
416
+ 原因:文档需要保证「现行真值覆盖 / 文风一致 / 禁历史否定堆砌」 · 要求写的人看到全文上下文
384
417
 
385
418
  #### 5. 任务清单与跨会话续作
386
419
 
@@ -413,7 +446,7 @@ todo.json 写权约束
413
446
  原因:多子 agent 并行落盘时,并发写会导致条目互相覆盖
414
447
  ```
415
448
 
416
- 生命周期由技能驱动 · 关键词路由实现跨会话自动续作 · linkedSkill 保证技能约束完整恢复
449
+ 生命周期由技能驱动 · 关键词路由实现跨会话自动续作 · linkedSkill 保证技能约束完整恢复
417
450
 
418
451
  ---
419
452
 
@@ -435,7 +468,7 @@ todo.json 写权约束
435
468
  └────────────┴─────────────────┘
436
469
  ```
437
470
 
438
- 两个维度正交 · 独立配置 · 默认左下角
471
+ 两个维度正交 · 独立配置 · 默认左下角
439
472
 
440
473
  #### 2. 确认权不可下放子 agent
441
474
 
@@ -450,9 +483,7 @@ graph LR
450
483
  S3[步骤3: 落盘] -->|subAgent=true 可并行| SUB2[子 agent]
451
484
  ```
452
485
 
453
-
454
-
455
- 用户对话只经过主 agent · 确认决策不可绕过用户 · 子 agent 只做执行不做决策
486
+ 用户对话只经过主 agent · 确认决策不可绕过用户 · 子 agent 只做执行不做决策
456
487
 
457
488
  #### 3. 技能可覆盖全局 subAgent 配置
458
489
 
@@ -466,7 +497,7 @@ subAgent: true 本技能默认不拆子:
466
497
  拆子会断上下文,导致澄清质量下降
467
498
  ```
468
499
 
469
- 全局配置是允许拆的上限 · 技能自己判断是否适合拆 · 配置 true 不等于一定拆
500
+ 全局配置是允许拆的上限 · 技能自己判断是否适合拆 · 配置 true 不等于一定拆
470
501
 
471
502
  #### 4. f2s-kb-sync 先出大纲,确认后再写
472
503
 
@@ -479,9 +510,7 @@ graph LR
479
510
  U -->|取消| STOP[不写入]
480
511
  ```
481
512
 
482
-
483
-
484
- 写入是破坏性操作 · 大纲是用户唯一的纠错机会 · 确认前不落盘
513
+ 写入是破坏性操作 · 大纲是用户唯一的纠错机会 · 确认前不落盘
485
514
 
486
515
  #### 5. 零输入推断
487
516
 
@@ -496,18 +525,20 @@ f2s-kb-sync 三种输入方式
496
525
  本次实现了什么、有什么值得沉淀
497
526
  ```
498
527
 
499
- 会话上下文本身就是信息源 · 不需要用户整理再输入
528
+ 会话上下文本身就是信息源 · 不需要用户整理再输入
500
529
 
501
530
  #### 5.1 执行开关如何进入 Agent(多端提示)
502
531
 
503
532
  `flow2spec.config.json` 决定 **`subAgent` / `switchAgentVerification` / `changeTracking`**,但各 AI 产品**不保证**会话启动即自动打开该文件。设计上用 **多条弱约束叠加** 降低「未读配置就开跑 `f2s-*`」的概率,同时避免在 `.Knowledge` 再维护一份与 `.codex/topics/f2s-config-check.md` 逐字重复的长文:
504
533
 
505
- | 机制 | 设计意图 |
506
- | --- | --- |
507
- | **Cursor `f2s-config-check.mdc`** | 规则层强制「技能正文前先 Read」。 |
508
- | **Claude `f2s-config-inject` PreToolUse** | 在调用 **`f2s-*` Skill** 时注入解析结果;**缺文件 / 坏 JSON / hook 异常**仍输出说明与默认语义,避免静默。 |
509
- | **Codex `AGENTS.md` + `renderProjectConfigBlock`** | 顶部 **Read** 硬约束 + **init 快照表**(与磁盘不一致时以 Read 为准)。 |
510
- | **知识库 `config-precheck` 主题** | 路由命中时只提供**摘要**与链向 Codex 长文,**不**替代 Read JSON。 |
534
+ | 机制 | 设计意图 |
535
+ | ----------------------------------------------------------- | --------------------------------------------------------------------------------- |
536
+ | **Cursor `f2s-config-check.mdc`** | 规则层强制「技能正文前先 Read」;Cursor hook 仅用于版本更新检测,不自动读取配置。 |
537
+ | **Claude `f2s-config-session` SessionStart** | 会话开始时注入一次配置摘要,降低遗忘概率。 |
538
+ | **Claude `f2s-config-inject` PreToolUse** | 仅在调用 **`f2s-*` Skill** 时做守门提示,提醒首步必须 Read;不反复注入完整配置。 |
539
+ | **Codex `AGENTS.md` / `.codex/topics/f2s-config-check.md`** | 文本层强制「技能正文前先 Read」;Codex hook 仅用于版本更新检测,不自动读取配置。 |
540
+ | **Codex `AGENTS.md` + `renderProjectConfigBlock`** | 顶部 **Read** 硬约束 + **init 快照表**(与磁盘不一致时以 Read 为准)。 |
541
+ | **知识库 `config-precheck` 主题** | 路由命中时只提供**摘要**与链向 Codex 长文,**不**替代 Read JSON。 |
511
542
 
512
543
  **权威仍为**项目根 JSON 的 **Read** 结果;各层为提示而非第二份真值源。操作侧完整表格与路径见 **[使用说明 § 一、`f2s-*` 与 `flow2spec.config.json`](./使用说明.md)**;口述节奏见 **[Flow2Spec-演讲稿 Slide 13b](./Flow2Spec-演讲稿.md)**。
513
544
 
@@ -540,14 +571,14 @@ flow2spec init cursor codex ← 跳过 Claude
540
571
  .Knowledge/ 始终不变,工具随时加减
541
572
  ```
542
573
 
543
- 同一份 `.Knowledge/` 驱动所有工具 · 加减工具不影响知识内容 · 新工具接入零重建
574
+ 同一份 `.Knowledge/` 驱动所有工具 · 加减工具不影响知识内容 · 新工具接入零重建
544
575
 
545
576
  #### 2. 知识主题可插拔:增删不连带
546
577
 
547
578
  ```
548
579
  添加主题 删除主题
549
580
  ───────────────────── ─────────────────────
550
- 1. 写 topics/xxx.md f2s-ctx-rm stock-docs/xxx.md
581
+ 1. 写 topics/xxx.md f2s-kb-rm stock-docs/xxx.md
551
582
  2. 写 matchers/m-xxx.json ↓
552
583
  3. 在 manifest-routing 注册 自动清除 topics/ + manifest
553
584
  + index 引用
@@ -555,7 +586,7 @@ flow2spec init cursor codex ← 跳过 Claude
555
586
  其他主题完全不受影响
556
587
  ```
557
588
 
558
- 新主题只需在 `topicDependencies` 里声明依赖 · 不声明则彼此独立 · 删除无副作用
589
+ 新主题只需在 `topicDependencies` 里声明依赖 · 不声明则彼此独立 · 删除无副作用
559
590
 
560
591
  #### 3. 技能可插拔:自包含单元,项目级可覆盖包级
561
592
 
@@ -569,13 +600,13 @@ f2s-doc-arch/SKILL.md my-review-skill/SKILL.md
569
600
  名字不冲突则共存 · 同名则项目级覆盖包级 · 互不感知
570
601
  ```
571
602
 
572
- 技能靠 `description` 字段自描述触发词 · 不需要注册表 · 不需要改全局配置 · 上线即生效
603
+ 技能靠 `description` 字段自描述触发词 · 不需要注册表 · 不需要改全局配置 · 上线即生效
573
604
 
574
605
  #### 4. 路由词表可插拔:分片隔离,局部更新
575
606
 
576
607
  词条变更只改对应 `matchers/m-xxx.json`,其他路由 diff 为零;结构见「[一、路由与上下文加载 → matchers 分片](#matchers-分片不嵌入-manifest)」。
577
608
 
578
- 词条变更局部化 · 合并冲突最小化 · 新增路由不影响存量
609
+ 词条变更局部化 · 合并冲突最小化 · 新增路由不影响存量
579
610
 
580
611
  #### 5. 执行模型可插拔:config 按项目切换
581
612
 
@@ -588,13 +619,14 @@ flow2spec.config.json
588
619
  switchAgentVerification: false → 落盘侧自验,日常使用
589
620
  switchAgentVerification: true → 交叉校验,高置信度关键场景
590
621
 
591
- changeTracking.feat/fix/implement: false 不创建任务清单
592
- changeTracking.feat/fix/implement: true 对应技能执行时自动创建任务清单,支持跨会话续作
622
+ changeTracking.feat: true f2s-kb-feat 默认创建任务清单
623
+ changeTracking.fix: false f2s-kb-fix 默认不创建任务清单
624
+ changeTracking.implement: true → implement-tech-design 默认创建任务清单
593
625
 
594
626
  三个维度正交 · 各技能可进一步细化覆盖全局配置
595
627
  ```
596
628
 
597
- 改一行配置切换执行策略 · 不修改任何技能文件 · 新项目开箱即用,老项目按需升级
629
+ 改一行配置切换执行策略 · 不修改任何技能文件 · 新项目开箱即用,老项目按需升级
598
630
 
599
631
  ---
600
632
 
@@ -641,4 +673,3 @@ flow2spec.config.json
641
673
  - [体系与原理](./体系与原理.md)
642
674
  - [使用案例-模拟对话](./使用案例-模拟对话.md)
643
675
  - [Flow2Spec-演讲稿](./Flow2Spec-演讲稿.md)
644
-
@@ -6,19 +6,19 @@
6
6
  const fs = require('fs');
7
7
  const path = require('path');
8
8
 
9
- const HOOK_COMMAND = 'node .claude/hooks/f2s-config-inject.js';
9
+ const HOOK_COMMAND_CONFIG_INJECT = 'node .claude/hooks/f2s-config-inject.js';
10
+ const HOOK_COMMAND_CONFIG_SESSION = 'node .claude/hooks/f2s-config-session.js';
11
+ const HOOK_COMMAND_UPDATE_CHECK = 'node .claude/hooks/f2s-update-check.js';
10
12
 
11
- /**
12
- * 判断 PreToolUse 数组里是否已存在 f2s-config-inject hook。
13
- * @param {Array} preToolUseArr
14
- * @returns {boolean}
15
- */
16
- function hasF2sHook(preToolUseArr) {
17
- if (!Array.isArray(preToolUseArr)) return false;
18
- for (const group of preToolUseArr) {
13
+ // 向下兼容
14
+ const HOOK_COMMAND = HOOK_COMMAND_CONFIG_INJECT;
15
+
16
+ function hasHookCommand(arr, fragment) {
17
+ if (!Array.isArray(arr)) return false;
18
+ for (const group of arr) {
19
19
  if (!group || !Array.isArray(group.hooks)) continue;
20
20
  for (const h of group.hooks) {
21
- if (h && h.type === 'command' && String(h.command || '').includes('f2s-config-inject')) {
21
+ if (h && h.type === 'command' && String(h.command || '').includes(fragment)) {
22
22
  return true;
23
23
  }
24
24
  }
@@ -26,8 +26,13 @@ function hasF2sHook(preToolUseArr) {
26
26
  return false;
27
27
  }
28
28
 
29
+ // 旧函数名保持兼容
30
+ function hasF2sHook(preToolUseArr) {
31
+ return hasHookCommand(preToolUseArr, 'f2s-config-inject');
32
+ }
33
+
29
34
  /**
30
- * 将 f2s PreToolUse hook 合并进现有 settings,返回新对象(不修改原对象)。
35
+ * 将 f2s PreToolUse 守门 hook 合并进现有 settings,返回新对象(不修改原对象)。
31
36
  * @param {object} existing 现有 settings(可为 {})
32
37
  * @returns {object}
33
38
  */
@@ -48,6 +53,48 @@ function mergeF2sHook(existing) {
48
53
  return { settings: next, changed: true };
49
54
  }
50
55
 
56
+ /**
57
+ * 将 f2s SessionStart 配置摘要 hook 合并进 settings。
58
+ * @param {object} existing
59
+ * @returns {{ settings, changed }}
60
+ */
61
+ function mergeConfigSessionHook(existing) {
62
+ const next = JSON.parse(JSON.stringify(existing || {}));
63
+ if (!next.hooks) next.hooks = {};
64
+ if (!next.hooks.SessionStart) next.hooks.SessionStart = [];
65
+
66
+ if (hasHookCommand(next.hooks.SessionStart, 'f2s-config-session')) {
67
+ return { settings: next, changed: false };
68
+ }
69
+
70
+ next.hooks.SessionStart.push({
71
+ hooks: [{ type: 'command', command: HOOK_COMMAND_CONFIG_SESSION }],
72
+ });
73
+
74
+ return { settings: next, changed: true };
75
+ }
76
+
77
+ /**
78
+ * 将 f2s SessionStart(版本检查)hook 合并进 settings。
79
+ * @param {object} existing
80
+ * @returns {{ settings, changed }}
81
+ */
82
+ function mergeUpdateCheckHook(existing) {
83
+ const next = JSON.parse(JSON.stringify(existing || {}));
84
+ if (!next.hooks) next.hooks = {};
85
+ if (!next.hooks.SessionStart) next.hooks.SessionStart = [];
86
+
87
+ if (hasHookCommand(next.hooks.SessionStart, 'f2s-update-check')) {
88
+ return { settings: next, changed: false };
89
+ }
90
+
91
+ next.hooks.SessionStart.push({
92
+ hooks: [{ type: 'command', command: HOOK_COMMAND_UPDATE_CHECK }],
93
+ });
94
+
95
+ return { settings: next, changed: true };
96
+ }
97
+
51
98
  /**
52
99
  * 读取 .claude/settings.json(不存在则返回 {})。
53
100
  * @param {string} claudeRoot .claude 目录绝对路径
@@ -74,41 +121,63 @@ function writeSettings(claudeRoot, settings) {
74
121
  }
75
122
 
76
123
  /**
77
- * templates/hooks/f2s-config-inject.js 复制到 .claude/hooks/。
78
- * @param {string} claudeRoot
79
- * @param {string} templatesDir
124
+ * 复制 hook 脚本到 .claude/hooks/。
80
125
  */
81
- function copyHookScript(claudeRoot, templatesDir) {
82
- const src = path.join(templatesDir, 'hooks', 'f2s-config-inject.js');
126
+ function copyHookScript(claudeRoot, templatesDir, scriptName) {
127
+ const src = path.join(templatesDir, 'hooks', scriptName);
83
128
  if (!fs.existsSync(src)) return { written: false, reason: 'missing-template' };
84
129
 
85
130
  const hooksDir = path.join(claudeRoot, 'hooks');
86
131
  if (!fs.existsSync(hooksDir)) fs.mkdirSync(hooksDir, { recursive: true });
87
132
 
88
- const dest = path.join(hooksDir, 'f2s-config-inject.js');
89
- fs.copyFileSync(src, dest);
133
+ let body = fs.readFileSync(src, 'utf8');
134
+ if (body.includes('__FLOW2SPEC_PACKAGE_NAME__')) {
135
+ let packageName = '@double-codeing/flow2spec';
136
+ try {
137
+ packageName = JSON.parse(
138
+ fs.readFileSync(path.join(templatesDir, '..', 'package.json'), 'utf8'),
139
+ ).name || packageName;
140
+ } catch (_) {}
141
+ body = body.replace(/__FLOW2SPEC_PACKAGE_NAME__/g, packageName);
142
+ }
143
+ fs.writeFileSync(path.join(hooksDir, scriptName), body, 'utf8');
90
144
  return { written: true };
91
145
  }
92
146
 
93
147
  /**
94
- * 主入口:为 claude agent 配置 f2s PreToolUse hook。
95
- * @param {string} cwd 项目根目录
96
- * @param {string} templatesDir flow2spec 包 templates 目录
97
- * @returns {{ hookScriptResult, settingsChanged }}
148
+ * 主入口:为 claude agent 配置 f2s hooks(SessionStart 配置摘要 + PreToolUse 守门 + SessionStart 更新检查)。
149
+ * @param {string} cwd
150
+ * @param {string} templatesDir
151
+ * @returns {{ hookScriptResult, updateCheckResult, settingsChanged }}
98
152
  */
99
153
  function writeClaudeAgentHooks(cwd, templatesDir) {
100
154
  const claudeRoot = path.join(cwd, '.claude');
101
155
  if (!fs.existsSync(claudeRoot)) fs.mkdirSync(claudeRoot, { recursive: true });
102
156
 
103
- const hookScriptResult = copyHookScript(claudeRoot, templatesDir);
157
+ const hookScriptResult = copyHookScript(claudeRoot, templatesDir, 'f2s-config-inject.js');
158
+ const configSessionResult = copyHookScript(claudeRoot, templatesDir, 'f2s-config-session.js');
159
+ const updateCheckResult = copyHookScript(claudeRoot, templatesDir, 'f2s-update-check.js');
104
160
 
105
- const existing = readSettings(claudeRoot);
106
- const { settings, changed } = mergeF2sHook(existing);
107
- if (changed) {
108
- writeSettings(claudeRoot, settings);
109
- }
161
+ let settings = readSettings(claudeRoot);
162
+ let changed = false;
163
+
164
+ const r1 = mergeF2sHook(settings);
165
+ if (r1.changed) { settings = r1.settings; changed = true; }
166
+
167
+ const r2 = mergeConfigSessionHook(settings);
168
+ if (r2.changed) { settings = r2.settings; changed = true; }
169
+
170
+ const r3 = mergeUpdateCheckHook(settings);
171
+ if (r3.changed) { settings = r3.settings; changed = true; }
172
+
173
+ if (changed) writeSettings(claudeRoot, settings);
110
174
 
111
- return { hookScriptResult, settingsChanged: changed };
175
+ return { hookScriptResult, configSessionResult, updateCheckResult, settingsChanged: changed };
112
176
  }
113
177
 
114
- module.exports = { writeClaudeAgentHooks, mergeF2sHook };
178
+ module.exports = {
179
+ writeClaudeAgentHooks,
180
+ mergeF2sHook,
181
+ mergeConfigSessionHook,
182
+ mergeUpdateCheckHook,
183
+ };
@@ -8,9 +8,12 @@ const DEFAULTS = {
8
8
  // switchAgentVerification:false=落盘侧同会话内验;true+技能绑定=交叉验(子落盘主验/主落盘子验)
9
9
  switchAgentVerification: false,
10
10
  changeTracking: {
11
- feat: false,
11
+ feat: true,
12
12
  fix: false,
13
- implement: false,
13
+ implement: true,
14
+ },
15
+ updateCheck: {
16
+ enabled: true,
14
17
  },
15
18
  };
16
19
 
@@ -35,7 +38,7 @@ const CONFIG_FIELDS = [
35
38
  {
36
39
  key: "changeTracking.feat",
37
40
  type: "boolean",
38
- default: false,
41
+ default: true,
39
42
  question: "启用变更追踪 - f2s-kb-feat(新增能力时创建可续作的任务清单)?",
40
43
  },
41
44
  {
@@ -47,9 +50,15 @@ const CONFIG_FIELDS = [
47
50
  {
48
51
  key: "changeTracking.implement",
49
52
  type: "boolean",
50
- default: false,
53
+ default: true,
51
54
  question: "启用变更追踪 - f2s-implement-tech-design(实现技术方案时创建可续作的任务清单)?",
52
55
  },
56
+ {
57
+ key: "updateCheck.enabled",
58
+ type: "boolean",
59
+ default: true,
60
+ question: "启用每日版本更新提示(每天第一次 Agent 对话时检查是否有新版 flow2spec)?",
61
+ },
53
62
  ];
54
63
 
55
64
  function normalizeBool(value, fallback) {
@@ -83,6 +92,7 @@ function loadFlow2specConfig(cwd) {
83
92
  const out = {
84
93
  ...DEFAULTS,
85
94
  changeTracking: { ...DEFAULTS.changeTracking },
95
+ updateCheck: { ...DEFAULTS.updateCheck },
86
96
  };
87
97
  if (!fs.existsSync(abs)) {
88
98
  return out;
@@ -126,6 +136,14 @@ function loadFlow2specConfig(cwd) {
126
136
  };
127
137
  }
128
138
  }
139
+ if (Object.prototype.hasOwnProperty.call(raw, "updateCheck")) {
140
+ const uc = raw.updateCheck;
141
+ if (uc && typeof uc === "object" && !Array.isArray(uc)) {
142
+ out.updateCheck = {
143
+ enabled: normalizeBool(uc.enabled, DEFAULTS.updateCheck.enabled),
144
+ };
145
+ }
146
+ }
129
147
  return out;
130
148
  }
131
149
 
@@ -209,10 +227,18 @@ function ensureFlow2specProjectConfig(cwd, templatesDir, options = {}) {
209
227
  try {
210
228
  base = JSON.parse(fs.readFileSync(src, "utf8"));
211
229
  } catch {
212
- base = { ...DEFAULTS, changeTracking: { ...DEFAULTS.changeTracking } };
230
+ base = {
231
+ ...DEFAULTS,
232
+ changeTracking: { ...DEFAULTS.changeTracking },
233
+ updateCheck: { ...DEFAULTS.updateCheck },
234
+ };
213
235
  }
214
236
  } else {
215
- base = { ...DEFAULTS, changeTracking: { ...DEFAULTS.changeTracking } };
237
+ base = {
238
+ ...DEFAULTS,
239
+ changeTracking: { ...DEFAULTS.changeTracking },
240
+ updateCheck: { ...DEFAULTS.updateCheck },
241
+ };
216
242
  }
217
243
  const merged = values && typeof values === "object" ? mergeValues(base, values) : base;
218
244
  fs.writeFileSync(dest, `${JSON.stringify(merged, null, 2)}\n`, "utf8");