cc-devflow 4.5.3 → 4.5.5
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/.claude/skills/cc-act/CHANGELOG.md +12 -0
- package/.claude/skills/cc-act/PLAYBOOK.md +28 -5
- package/.claude/skills/cc-act/SKILL.md +45 -12
- package/.claude/skills/cc-act/assets/PR_BRIEF_TEMPLATE.md +39 -0
- package/.claude/skills/cc-act/assets/RELEASE_NOTE_TEMPLATE.md +16 -0
- package/.claude/skills/cc-act/references/closure-contract.md +3 -0
- package/.claude/skills/cc-act/scripts/cc-act-common.sh +48 -0
- package/.claude/skills/cc-act/scripts/generate-status-report.sh +3 -0
- package/.claude/skills/cc-act/scripts/render-pr-brief.sh +6 -0
- package/.claude/skills/cc-act/scripts/sync-act-docs.sh +13 -0
- package/.claude/skills/cc-check/CHANGELOG.md +6 -0
- package/.claude/skills/cc-check/PLAYBOOK.md +4 -0
- package/.claude/skills/cc-check/SKILL.md +15 -2
- package/.claude/skills/cc-check/assets/REPORT_CARD_TEMPLATE.json +18 -0
- package/.claude/skills/cc-do/CHANGELOG.md +12 -0
- package/.claude/skills/cc-do/PLAYBOOK.md +13 -10
- package/.claude/skills/cc-do/SKILL.md +40 -16
- package/.claude/skills/cc-do/references/execution-recovery.md +12 -0
- package/.claude/skills/cc-do/references/parallel-dispatch.md +6 -4
- package/.claude/skills/cc-do/scripts/detect-file-conflicts.sh +49 -3
- package/.claude/skills/cc-investigate/CHANGELOG.md +12 -0
- package/.claude/skills/cc-investigate/PLAYBOOK.md +12 -1
- package/.claude/skills/cc-investigate/SKILL.md +31 -5
- package/.claude/skills/cc-investigate/assets/ANALYSIS_TEMPLATE.md +44 -0
- package/.claude/skills/cc-investigate/assets/TASKS_TEMPLATE.md +1 -0
- package/.claude/skills/cc-investigate/assets/TASK_MANIFEST_TEMPLATE.json +9 -1
- package/.claude/skills/cc-investigate/references/investigation-contract.md +2 -0
- package/.claude/skills/cc-plan/CHANGELOG.md +29 -0
- package/.claude/skills/cc-plan/PLAYBOOK.md +43 -17
- package/.claude/skills/cc-plan/SKILL.md +85 -44
- package/.claude/skills/cc-plan/assets/DESIGN_TEMPLATE.md +109 -3
- package/.claude/skills/cc-plan/assets/TASKS_TEMPLATE.md +32 -5
- package/.claude/skills/cc-plan/assets/TASK_MANIFEST_TEMPLATE.json +85 -4
- package/.claude/skills/cc-plan/assets/TINY_DESIGN_TEMPLATE.md +78 -0
- package/.claude/skills/cc-plan/references/planning-contract.md +29 -7
- package/.claude/skills/cc-roadmap/CHANGELOG.md +12 -0
- package/.claude/skills/cc-roadmap/PLAYBOOK.md +15 -9
- package/.claude/skills/cc-roadmap/SKILL.md +22 -16
- package/.claude/skills/cc-roadmap/assets/BACKLOG_TEMPLATE.md +3 -1
- package/.claude/skills/cc-roadmap/assets/ROADMAP_TEMPLATE.md +11 -1
- package/.claude/skills/cc-roadmap/assets/TRACKING_TEMPLATE.json +57 -10
- package/.claude/skills/cc-roadmap/scripts/lib/roadmap-tracking/markdown.js +68 -3
- package/.claude/skills/cc-roadmap/scripts/lib/roadmap-tracking/schema.js +120 -0
- package/.claude/skills/cc-roadmap/scripts/lib/roadmap-tracking/store.js +25 -1
- package/.claude/skills/cc-roadmap/scripts/locate-roadmap-item.sh +13 -5
- package/.claude/skills/cc-roadmap/scripts/roadmap-tracking.js +3 -3
- package/.claude/skills/cc-roadmap/scripts/sync-roadmap-progress.sh +3 -3
- package/CHANGELOG.md +15 -0
- package/README.md +5 -5
- package/README.zh-CN.md +5 -5
- package/bin/cc-devflow-cli.js +93 -2
- package/docs/CLAUDE.md +1 -1
- package/docs/examples/START-HERE.md +3 -3
- package/docs/examples/example-bindings.json +27 -10
- package/docs/examples/full-design-blocked/BACKLOG.md +4 -2
- package/docs/examples/full-design-blocked/README.md +4 -4
- package/docs/examples/full-design-blocked/ROADMAP.md +16 -2
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/design.md +39 -1
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/task-manifest.json +41 -0
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/planning/tasks.md +8 -1
- package/docs/examples/full-design-blocked/roadmap.json +123 -0
- package/docs/examples/local-handoff/BACKLOG.md +4 -2
- package/docs/examples/local-handoff/README.md +4 -4
- package/docs/examples/local-handoff/ROADMAP.md +16 -2
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/design.md +19 -1
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/task-manifest.json +26 -0
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/planning/tasks.md +8 -1
- package/docs/examples/local-handoff/roadmap.json +121 -0
- package/docs/examples/pdca-loop/BACKLOG.md +4 -2
- package/docs/examples/pdca-loop/README.md +4 -4
- package/docs/examples/pdca-loop/ROADMAP.md +16 -2
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/design.md +19 -1
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/task-manifest.json +22 -3
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/planning/tasks.md +8 -1
- package/docs/examples/pdca-loop/roadmap.json +191 -0
- package/docs/examples/scripts/check-example-bindings.sh +7 -4
- package/docs/get-shit-done-strategy-audit.md +518 -0
- package/docs/guides/getting-started.md +2 -2
- package/docs/guides/getting-started.zh-CN.md +2 -2
- package/lib/compiler/__tests__/inventory.test.js +51 -0
- package/lib/compiler/__tests__/skills-registry.test.js +17 -3
- package/lib/compiler/inventory.js +78 -0
- package/lib/skill-runtime/__tests__/approve.test.js +92 -0
- package/lib/skill-runtime/__tests__/autopilot.test.js +4 -0
- package/lib/skill-runtime/__tests__/cli-bootstrap.integration.test.js +9 -1
- package/lib/skill-runtime/__tests__/planner.tdd.test.js +20 -0
- package/lib/skill-runtime/__tests__/query.test.js +147 -1
- package/lib/skill-runtime/__tests__/readiness.test.js +53 -0
- package/lib/skill-runtime/__tests__/release.test.js +85 -0
- package/lib/skill-runtime/__tests__/runtime.integration.test.js +11 -0
- package/lib/skill-runtime/__tests__/schemas.test.js +56 -0
- package/lib/skill-runtime/__tests__/worker-run.test.js +29 -0
- package/lib/skill-runtime/errors.js +39 -0
- package/lib/skill-runtime/index.js +8 -0
- package/lib/skill-runtime/operations/approve.js +17 -2
- package/lib/skill-runtime/operations/release.js +6 -3
- package/lib/skill-runtime/operations/worker-run.js +30 -0
- package/lib/skill-runtime/planner.js +10 -2
- package/lib/skill-runtime/query-registry.js +101 -0
- package/lib/skill-runtime/query.js +159 -91
- package/lib/skill-runtime/readiness.js +84 -0
- package/lib/skill-runtime/schemas.js +28 -3
- package/lib/skill-runtime/trace.js +22 -0
- package/package.json +1 -1
|
@@ -23,20 +23,20 @@
|
|
|
23
23
|
|
|
24
24
|
## Local Kit
|
|
25
25
|
|
|
26
|
-
-
|
|
27
|
-
- 需要结构化
|
|
26
|
+
- 生成骨架时先用 `assets/TRACKING_TEMPLATE.json` 写 `devflow/roadmap.json`,再渲染 `assets/ROADMAP_TEMPLATE.md` / `assets/BACKLOG_TEMPLATE.md` 形状
|
|
27
|
+
- 需要结构化 roadmap state 时用 `assets/TRACKING_TEMPLATE.json`
|
|
28
28
|
- 需要追问脚本时看 `references/roadmap-dialogue.md`
|
|
29
29
|
- 需要定位 / 回写条目时用 `scripts/locate-roadmap-item.sh` 和 `scripts/sync-roadmap-progress.sh`
|
|
30
|
-
- `scripts/locate-roadmap-item.sh` 先读 `roadmap
|
|
31
|
-
- 只想把
|
|
32
|
-
- `scripts/sync-roadmap-progress.sh` 会把 `roadmap
|
|
30
|
+
- `scripts/locate-roadmap-item.sh` 先读 `roadmap.json`,再回落到旧 `roadmap-tracking.json` 和 Markdown,避免定位依赖 markdown 列位或文案漂移
|
|
31
|
+
- 只想把 state 重渲染回 `ROADMAP.md` / `BACKLOG.md` 时,直接调用 `scripts/roadmap-tracking.js render`
|
|
32
|
+
- `scripts/sync-roadmap-progress.sh` 会把 `roadmap.json` 当真相源,再回渲染 `ROADMAP.md` 和 deprecated `BACKLOG.md`
|
|
33
33
|
- 变更版本时同步 `CHANGELOG.md`,必要时用 `scripts/bump-skill-version.sh`
|
|
34
34
|
|
|
35
35
|
## Context Sweep
|
|
36
36
|
|
|
37
37
|
进入 roadmap 对话前,至少摸清:
|
|
38
38
|
|
|
39
|
-
1. 现有 `devflow/ROADMAP.md` / `devflow/BACKLOG.md`
|
|
39
|
+
1. 现有 `devflow/roadmap.json` / `devflow/ROADMAP.md` / `devflow/BACKLOG.md`
|
|
40
40
|
2. `CLAUDE.md`、`README*`、`TODOS.md`
|
|
41
41
|
3. 项目语言和持久决策:`devflow/specs/INDEX.md`、相关 capability specs、当前 roadmap/backlog、历史 `planning/design.md` / `planning/analysis.md`、`change-meta.json`、长期 design decision
|
|
42
42
|
4. 最近相关 docs / specs / plans
|
|
@@ -116,6 +116,11 @@
|
|
|
116
116
|
|
|
117
117
|
## Output Contract
|
|
118
118
|
|
|
119
|
+
`devflow/roadmap.json`
|
|
120
|
+
- single editable roadmap state
|
|
121
|
+
- output policy, meta, context, evidence, route, stages, items, handoff, and architecture
|
|
122
|
+
- flat `architecture.nodes` / `architecture.edges` used to generate Mermaid
|
|
123
|
+
|
|
119
124
|
`devflow/ROADMAP.md`
|
|
120
125
|
- version / skill version / context snapshot / evidence ledger
|
|
121
126
|
- 1-3 个阶段
|
|
@@ -128,13 +133,14 @@
|
|
|
128
133
|
- 非目标
|
|
129
134
|
- `RM Dependency Graph`
|
|
130
135
|
- `Parallel waves`
|
|
131
|
-
- `Implementation Tracking` 由 `devflow/roadmap
|
|
136
|
+
- `Implementation Tracking` 和 `Technical Architecture` 由 `devflow/roadmap.json` 渲染,避免手改 markdown 表格或 Mermaid
|
|
132
137
|
|
|
133
138
|
`devflow/BACKLOG.md`
|
|
139
|
+
- deprecated compatibility projection; edit `devflow/roadmap.json` instead
|
|
134
140
|
- 只保留会真的进入下一轮 `cc-plan` 的事项
|
|
135
141
|
- 每项注明来源阶段、优先级、证据、`Depends On`、`Parallel With`、当前未知点、下一决策、是否 ready
|
|
136
142
|
- developer-facing / operator-facing 条目要带 target user、time to first value、magic moment 和 adoption bottleneck,方便 `cc-plan` 继续做 DX 设计
|
|
137
|
-
- `Backlog Meta`、`Queue`、`Dependency Handoff`、`Ready For Req-Plan`、`Parked`
|
|
143
|
+
- `Backlog Meta`、`Queue`、`Dependency Handoff`、`Ready For Req-Plan`、`Parked` 由 `devflow/roadmap.json` 回渲染,避免 roadmap truth 和 backlog handoff 分叉
|
|
138
144
|
|
|
139
145
|
## Review Loop
|
|
140
146
|
|
|
@@ -153,7 +159,7 @@
|
|
|
153
159
|
## Versioning
|
|
154
160
|
|
|
155
161
|
- `patch`: 文案澄清、模板说明、小修补
|
|
156
|
-
- `minor`: 上下文收集、评审、字段增强,且不破坏既有
|
|
162
|
+
- `minor`: 上下文收集、评审、字段增强,且不破坏既有 roadmap state 习惯
|
|
157
163
|
- `major`: 核心输出契约变化,需要 migration note
|
|
158
164
|
|
|
159
165
|
## Exit Rule
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cc-roadmap
|
|
3
|
-
version:
|
|
3
|
+
version: 5.0.0
|
|
4
4
|
description: "Use when defining, resetting, or narrowing project direction, stage order, or backlog priority before a concrete requirement enters the PDCA loop."
|
|
5
5
|
triggers:
|
|
6
6
|
- "帮我定路线图"
|
|
@@ -19,16 +19,20 @@ reads:
|
|
|
19
19
|
- "assets/TRACKING_TEMPLATE.json"
|
|
20
20
|
- "references/roadmap-dialogue.md"
|
|
21
21
|
writes:
|
|
22
|
+
- path: "devflow/roadmap.json"
|
|
23
|
+
durability: "durable"
|
|
24
|
+
required: true
|
|
22
25
|
- path: "devflow/ROADMAP.md"
|
|
23
26
|
durability: "durable"
|
|
24
27
|
required: true
|
|
25
28
|
- path: "devflow/BACKLOG.md"
|
|
26
29
|
durability: "durable"
|
|
27
|
-
required:
|
|
30
|
+
required: false
|
|
31
|
+
when: "deprecated compatibility projection is generated for downstream readers"
|
|
28
32
|
- path: "devflow/roadmap-tracking.json"
|
|
29
33
|
durability: "durable"
|
|
30
34
|
required: false
|
|
31
|
-
when: "
|
|
35
|
+
when: "legacy projects are being migrated into devflow/roadmap.json"
|
|
32
36
|
entry_gate:
|
|
33
37
|
- "Read current roadmap, backlog, related capability specs, and surrounding repo context before proposing direction."
|
|
34
38
|
- "Load cc-devflow native language and durable-decision sources (`devflow/specs/`, current roadmap/backlog, prior `planning/design.md` or `planning/analysis.md`, and `change-meta.json`) before naming stages, capabilities, users, or backlog items."
|
|
@@ -68,7 +72,7 @@ tool_budget:
|
|
|
68
72
|
|
|
69
73
|
写入任何 durable Markdown 或 JSON metadata 前,先运行 `cc-devflow config resolve --format policy`。
|
|
70
74
|
|
|
71
|
-
- `Output language` 是机器约束,`devflow/
|
|
75
|
+
- `Output language` 是机器约束,`devflow/roadmap.json`、`devflow/ROADMAP.md` 和兼容投影必须记录并遵守它。
|
|
72
76
|
- `agent_preferences` 是用户偏好建议,只影响表达方式和结构选择,不覆盖本 Skill 的工作流边界。
|
|
73
77
|
- 如果配置解析失败,先修配置或向用户说明阻塞,不要用默认语言继续生成正式文档。
|
|
74
78
|
|
|
@@ -76,9 +80,10 @@ tool_budget:
|
|
|
76
80
|
|
|
77
81
|
1. `PLAYBOOK.md`
|
|
78
82
|
2. `CHANGELOG.md`
|
|
79
|
-
3. `assets/
|
|
80
|
-
4. `assets/
|
|
81
|
-
5. `
|
|
83
|
+
3. `assets/TRACKING_TEMPLATE.json`
|
|
84
|
+
4. `assets/ROADMAP_TEMPLATE.md`
|
|
85
|
+
5. `assets/BACKLOG_TEMPLATE.md`
|
|
86
|
+
6. `references/roadmap-dialogue.md`
|
|
82
87
|
|
|
83
88
|
## Use This Skill When
|
|
84
89
|
|
|
@@ -104,14 +109,14 @@ tool_budget:
|
|
|
104
109
|
|
|
105
110
|
## Harness Contract
|
|
106
111
|
|
|
107
|
-
- Allowed actions: read current strategy files, repo context, and recent reality; compare route shapes; decompose independent subsystems into stages and RM candidates; write `devflow/
|
|
112
|
+
- Allowed actions: read current strategy files, repo context, and recent reality; compare route shapes; decompose independent subsystems into stages and RM candidates; write `devflow/roadmap.json` as the editable roadmap state, then generate `devflow/ROADMAP.md` and the deprecated `devflow/BACKLOG.md` compatibility projection from that state.
|
|
108
113
|
- Forbidden actions: decompose implementation tasks, invent hidden context, or jump into `cc-plan` before the roadmap is approved.
|
|
109
114
|
- Required evidence: every stage and backlog item must point back to explicit repo facts, user constraints, or observed market signals.
|
|
110
115
|
- Reroute rule: once the conversation collapses to one concrete requirement, stop strategic expansion and hand off to `cc-plan`.
|
|
111
116
|
|
|
112
117
|
## Entry Gate
|
|
113
118
|
|
|
114
|
-
1. 如果 `devflow/ROADMAP.md`
|
|
119
|
+
1. 如果 `devflow/roadmap.json`、`devflow/ROADMAP.md`、`devflow/BACKLOG.md` 或旧 `devflow/roadmap-tracking.json` 已存在,先读现状再重写。
|
|
115
120
|
2. 先判断这是“项目方向问题”还是“单 requirement 执行问题”。
|
|
116
121
|
3. 如果输入是多个独立子系统的混合目标,先拆成阶段和 `RM` 候选;不要继续追问某个子系统的实现细节。
|
|
117
122
|
4. 先做一次上下文扫描,不能跳过现有事实直接写愿景。
|
|
@@ -232,7 +237,7 @@ tool_budget:
|
|
|
232
237
|
|
|
233
238
|
## Review Loop
|
|
234
239
|
|
|
235
|
-
写完 `devflow/ROADMAP.md` / `devflow/BACKLOG.md`
|
|
240
|
+
写完 `devflow/roadmap.json` 并生成 `devflow/ROADMAP.md` / `devflow/BACKLOG.md` 后,至少完成这些检查:
|
|
236
241
|
|
|
237
242
|
1. Placeholder scan:不能有 TBD、TODO、`[NEEDS CONTEXT]` 之类的逃避词。
|
|
238
243
|
2. Evidence scan:每个阶段是否都能指回某个现实证据,而不是空洞愿景。
|
|
@@ -250,8 +255,9 @@ tool_budget:
|
|
|
250
255
|
## Output
|
|
251
256
|
|
|
252
257
|
- `devflow/ROADMAP.md`
|
|
253
|
-
- `devflow/
|
|
254
|
-
- `devflow/
|
|
258
|
+
- `devflow/roadmap.json`
|
|
259
|
+
- `devflow/BACKLOG.md` as a deprecated compatibility projection
|
|
260
|
+
- `devflow/roadmap-tracking.json` only when migrating legacy projects
|
|
255
261
|
|
|
256
262
|
## Good Output
|
|
257
263
|
|
|
@@ -270,13 +276,13 @@ tool_budget:
|
|
|
270
276
|
|
|
271
277
|
- `patch`:措辞、模板字段说明、非契约性澄清
|
|
272
278
|
- `minor`:新增兼容字段、上下文收集规则、评审规则、输出结构增强
|
|
273
|
-
- `major`:改变 `devflow/
|
|
279
|
+
- `major`:改变 `devflow/roadmap.json`、生成投影、阶段模型或 handoff 预期
|
|
274
280
|
|
|
275
281
|
每次修改都必须:
|
|
276
282
|
|
|
277
283
|
1. 更新本文件 frontmatter 的 `version`
|
|
278
284
|
2. 更新 `CHANGELOG.md`
|
|
279
|
-
3. 如果会影响已有 `devflow/ROADMAP.md` / `devflow/BACKLOG.md` 使用方式,在 `CHANGELOG.md` 写清 migration note
|
|
285
|
+
3. 如果会影响已有 `devflow/ROADMAP.md` / `devflow/BACKLOG.md` / `devflow/roadmap-tracking.json` 使用方式,在 `CHANGELOG.md` 写清 migration note
|
|
280
286
|
|
|
281
287
|
## Bundled Resources
|
|
282
288
|
|
|
@@ -286,7 +292,7 @@ tool_budget:
|
|
|
286
292
|
- 结构化 tracking 模板:`assets/TRACKING_TEMPLATE.json`
|
|
287
293
|
- 对话骨架:`references/roadmap-dialogue.md`
|
|
288
294
|
- 条目定位:`scripts/locate-roadmap-item.sh`
|
|
289
|
-
-
|
|
295
|
+
- roadmap state 渲染器:`scripts/roadmap-tracking.js`
|
|
290
296
|
- 进度回写:`scripts/sync-roadmap-progress.sh`
|
|
291
297
|
- 版本递增:`scripts/bump-skill-version.sh`
|
|
292
298
|
|
|
@@ -302,7 +308,7 @@ tool_budget:
|
|
|
302
308
|
|
|
303
309
|
1. 先收上下文,再收意见。
|
|
304
310
|
2. 没有现实证据时必须明确写成 assumption,而不是偷偷当事实。
|
|
305
|
-
3. `devflow/ROADMAP.md`
|
|
311
|
+
3. `devflow/roadmap.json` 是唯一可编辑方向真相源,`devflow/ROADMAP.md` 和 `devflow/BACKLOG.md` 是生成投影。
|
|
306
312
|
4. 决策理由必须保留下来,方便以后重跑时比较版本差异。
|
|
307
313
|
5. 路线图里的术语必须沿用项目语言;没有 canonical term 时写 assumption,不要创造第二套概念系统。
|
|
308
314
|
6. 不要为了显得完整而写 6 个阶段,能打赢下一仗比画完整战争图更重要。
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# BACKLOG
|
|
2
2
|
|
|
3
|
+
> Deprecated projection. Edit `roadmap.json` instead.
|
|
4
|
+
|
|
3
5
|
## Backlog Meta
|
|
4
6
|
|
|
5
7
|
- Roadmap version:
|
|
@@ -7,7 +9,7 @@
|
|
|
7
9
|
- Output language:
|
|
8
10
|
- Last synced:
|
|
9
11
|
- Current focus stage:
|
|
10
|
-
-
|
|
12
|
+
- Roadmap state source: `devflow/roadmap.json`
|
|
11
13
|
|
|
12
14
|
## Queue
|
|
13
15
|
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
## Roadmap Meta
|
|
4
4
|
|
|
5
|
+
- Roadmap state source: `devflow/roadmap.json`
|
|
5
6
|
- Roadmap version:
|
|
6
7
|
- Skill version:
|
|
7
8
|
- Output language:
|
|
@@ -178,6 +179,15 @@ flowchart LR
|
|
|
178
179
|
- Serial spine:
|
|
179
180
|
- Parallel-ready branches:
|
|
180
181
|
|
|
182
|
+
## Technical Architecture
|
|
183
|
+
|
|
184
|
+
```mermaid
|
|
185
|
+
flowchart TD
|
|
186
|
+
roadmap_json["roadmap.json"] --> roadmap_md["ROADMAP.md"]
|
|
187
|
+
roadmap_json --> backlog_md["BACKLOG.md (deprecated)"]
|
|
188
|
+
roadmap_md --> cc_plan["cc-plan"]
|
|
189
|
+
```
|
|
190
|
+
|
|
181
191
|
## Parallel Waves
|
|
182
192
|
|
|
183
193
|
| Wave | Ready when | Items | Why parallel |
|
|
@@ -197,7 +207,7 @@ flowchart LR
|
|
|
197
207
|
|
|
198
208
|
## Implementation Tracking
|
|
199
209
|
|
|
200
|
-
-
|
|
210
|
+
- Roadmap state source: `devflow/roadmap.json`
|
|
201
211
|
|
|
202
212
|
<!-- roadmap-tracking:start -->
|
|
203
213
|
| RM-ID | Item | Stage | Priority | Primary Capability | Secondary Capabilities | Expected Spec Delta | Depends On | Status | REQ | Progress |
|
|
@@ -1,20 +1,30 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version":
|
|
2
|
+
"version": 3,
|
|
3
3
|
"outputPolicy": {
|
|
4
4
|
"documentLanguage": ""
|
|
5
5
|
},
|
|
6
|
-
"
|
|
7
|
-
"backlogMeta": {
|
|
6
|
+
"meta": {
|
|
8
7
|
"roadmapVersion": "roadmap.v1",
|
|
9
|
-
"skillVersion": "
|
|
8
|
+
"skillVersion": "5.0.0",
|
|
9
|
+
"status": "active",
|
|
10
|
+
"lastUpdated": "2026-05-01",
|
|
10
11
|
"currentFocusStage": "Stage 1"
|
|
11
12
|
},
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
"
|
|
13
|
+
"context": {
|
|
14
|
+
"planningPosture": "",
|
|
15
|
+
"evidenceMaturity": "",
|
|
16
|
+
"canonicalTerms": [],
|
|
17
|
+
"durableDecisionSources": []
|
|
17
18
|
},
|
|
19
|
+
"evidence": [],
|
|
20
|
+
"route": {
|
|
21
|
+
"recommended": "",
|
|
22
|
+
"whyThisWinsNow": "",
|
|
23
|
+
"rejectedRoutes": [],
|
|
24
|
+
"firstSignal": "",
|
|
25
|
+
"killSignal": ""
|
|
26
|
+
},
|
|
27
|
+
"stages": [],
|
|
18
28
|
"items": [
|
|
19
29
|
{
|
|
20
30
|
"rmId": "RM-001",
|
|
@@ -48,5 +58,42 @@
|
|
|
48
58
|
"missingEvidence": ""
|
|
49
59
|
}
|
|
50
60
|
}
|
|
51
|
-
]
|
|
61
|
+
],
|
|
62
|
+
"handoff": {
|
|
63
|
+
"readyForCcPlan": [],
|
|
64
|
+
"parked": [],
|
|
65
|
+
"serialSpine": [
|
|
66
|
+
"RM-001"
|
|
67
|
+
],
|
|
68
|
+
"parallelWaves": []
|
|
69
|
+
},
|
|
70
|
+
"architecture": {
|
|
71
|
+
"diagramType": "flowchart",
|
|
72
|
+
"nodes": [
|
|
73
|
+
{
|
|
74
|
+
"id": "roadmap_json",
|
|
75
|
+
"label": "roadmap.json"
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
"id": "roadmap_md",
|
|
79
|
+
"label": "ROADMAP.md"
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"id": "cc_plan",
|
|
83
|
+
"label": "cc-plan"
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
"edges": [
|
|
87
|
+
{
|
|
88
|
+
"from": "roadmap_json",
|
|
89
|
+
"to": "roadmap_md",
|
|
90
|
+
"label": "renders"
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
"from": "roadmap_md",
|
|
94
|
+
"to": "cc_plan",
|
|
95
|
+
"label": "hands off"
|
|
96
|
+
}
|
|
97
|
+
]
|
|
98
|
+
}
|
|
52
99
|
}
|
|
@@ -445,13 +445,18 @@ function renderRoadmapTable(tracking) {
|
|
|
445
445
|
return [header, separator, ...rows.map((row) => `| ${row} |`)].join('\n');
|
|
446
446
|
}
|
|
447
447
|
|
|
448
|
+
function isRoadmapState(tracking) {
|
|
449
|
+
return Number(tracking.version) === 3;
|
|
450
|
+
}
|
|
451
|
+
|
|
448
452
|
function buildTrackingBody(roadmapFile, trackingFile, tracking) {
|
|
449
453
|
const relativePath = path.relative(path.dirname(roadmapFile), trackingFile).replace(/\\/g, '/');
|
|
450
454
|
const displayPath = relativePath || path.basename(trackingFile);
|
|
455
|
+
const sourceLabel = isRoadmapState(tracking) ? 'Roadmap state source' : 'Tracking source';
|
|
451
456
|
|
|
452
457
|
return [
|
|
453
458
|
'',
|
|
454
|
-
`-
|
|
459
|
+
`- ${sourceLabel}: \`${displayPath}\``,
|
|
455
460
|
'',
|
|
456
461
|
'<!-- roadmap-tracking:start -->',
|
|
457
462
|
renderRoadmapTable(tracking),
|
|
@@ -460,14 +465,69 @@ function buildTrackingBody(roadmapFile, trackingFile, tracking) {
|
|
|
460
465
|
].join('\n');
|
|
461
466
|
}
|
|
462
467
|
|
|
468
|
+
function formatMermaidId(value) {
|
|
469
|
+
return String(value || '')
|
|
470
|
+
.trim()
|
|
471
|
+
.replace(/[^A-Za-z0-9_]/g, '_');
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
function formatMermaidLabel(value) {
|
|
475
|
+
return String(value || '').replace(/"/g, '\\"');
|
|
476
|
+
}
|
|
477
|
+
|
|
478
|
+
function renderArchitectureDiagram(tracking) {
|
|
479
|
+
const architecture = tracking.architecture || {};
|
|
480
|
+
const nodes = Array.isArray(architecture.nodes) ? architecture.nodes : [];
|
|
481
|
+
const edges = Array.isArray(architecture.edges) ? architecture.edges : [];
|
|
482
|
+
|
|
483
|
+
if (!nodes.length && !edges.length) {
|
|
484
|
+
return '';
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const lines = ['## Technical Architecture', '', '```mermaid', 'flowchart TD'];
|
|
488
|
+
|
|
489
|
+
nodes.forEach((node) => {
|
|
490
|
+
const id = formatMermaidId(node.id);
|
|
491
|
+
if (id) {
|
|
492
|
+
lines.push(` ${id}["${formatMermaidLabel(node.label || node.id)}"]`);
|
|
493
|
+
}
|
|
494
|
+
});
|
|
495
|
+
|
|
496
|
+
edges.forEach((edge) => {
|
|
497
|
+
const from = formatMermaidId(edge.from);
|
|
498
|
+
const to = formatMermaidId(edge.to);
|
|
499
|
+
if (!from || !to) {
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
const label = String(edge.label || '').trim();
|
|
504
|
+
lines.push(label ? ` ${from} -->|${formatMermaidLabel(label)}| ${to}` : ` ${from} --> ${to}`);
|
|
505
|
+
});
|
|
506
|
+
|
|
507
|
+
lines.push('```', '');
|
|
508
|
+
return lines.join('\n');
|
|
509
|
+
}
|
|
510
|
+
|
|
463
511
|
function renderRoadmapDocument({ original = '# ROADMAP\n', roadmapFile, trackingFile, tracking }) {
|
|
464
512
|
const section = extractSection(original, 'Implementation Tracking');
|
|
465
513
|
const body = buildTrackingBody(roadmapFile, trackingFile, tracking);
|
|
466
514
|
const nextSection = `## Implementation Tracking${body}`;
|
|
515
|
+
const architectureSection = isRoadmapState(tracking) ? `\n${renderArchitectureDiagram(tracking)}` : '';
|
|
467
516
|
|
|
468
|
-
|
|
517
|
+
const rendered = section
|
|
469
518
|
? `${original.slice(0, section.start)}${nextSection}${original.slice(section.end)}`
|
|
470
519
|
: `${original.replace(/\s*$/, '')}\n\n${nextSection}\n`;
|
|
520
|
+
|
|
521
|
+
if (!architectureSection.trim()) {
|
|
522
|
+
return rendered;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const existingArchitecture = extractSection(rendered, 'Technical Architecture');
|
|
526
|
+
if (existingArchitecture) {
|
|
527
|
+
return `${rendered.slice(0, existingArchitecture.start)}${architectureSection.trimEnd()}\n${rendered.slice(existingArchitecture.end)}`;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
return `${rendered.replace(/\s*$/, '')}\n\n${architectureSection}`;
|
|
471
531
|
}
|
|
472
532
|
|
|
473
533
|
function renderBacklogQueue(tracking) {
|
|
@@ -564,17 +624,22 @@ function renderParked(tracking) {
|
|
|
564
624
|
function renderBacklogDocument({ backlogFile, trackingFile, tracking }) {
|
|
565
625
|
const relativePath = path.relative(path.dirname(backlogFile), trackingFile).replace(/\\/g, '/');
|
|
566
626
|
const displayPath = relativePath || path.basename(trackingFile);
|
|
627
|
+
const sourceLabel = isRoadmapState(tracking) ? 'Roadmap state source' : 'Tracking source';
|
|
628
|
+
const deprecationNotice = isRoadmapState(tracking)
|
|
629
|
+
? ['> Deprecated projection. Edit `roadmap.json` instead.', '']
|
|
630
|
+
: [];
|
|
567
631
|
|
|
568
632
|
return [
|
|
569
633
|
'# BACKLOG',
|
|
570
634
|
'',
|
|
635
|
+
...deprecationNotice,
|
|
571
636
|
'## Backlog Meta',
|
|
572
637
|
'',
|
|
573
638
|
`- Roadmap version: ${formatInlineCode(tracking.backlogMeta.roadmapVersion)}`,
|
|
574
639
|
`- Skill version: ${formatInlineCode(tracking.backlogMeta.skillVersion)}`,
|
|
575
640
|
`- Last synced: ${formatInlineCode(tracking.lastSyncedAt)}`,
|
|
576
641
|
`- Current focus stage: ${formatInlineCode(tracking.backlogMeta.currentFocusStage)}`,
|
|
577
|
-
`-
|
|
642
|
+
`- ${sourceLabel}: \`${displayPath}\``,
|
|
578
643
|
'',
|
|
579
644
|
'## Queue',
|
|
580
645
|
'',
|
|
@@ -65,6 +65,47 @@ const DEFAULT_TRACKING = {
|
|
|
65
65
|
items: []
|
|
66
66
|
};
|
|
67
67
|
|
|
68
|
+
const DEFAULT_ROADMAP_STATE = {
|
|
69
|
+
version: 3,
|
|
70
|
+
outputPolicy: {
|
|
71
|
+
documentLanguage: 'en'
|
|
72
|
+
},
|
|
73
|
+
meta: {
|
|
74
|
+
roadmapVersion: '',
|
|
75
|
+
skillVersion: '',
|
|
76
|
+
status: 'active',
|
|
77
|
+
lastUpdated: '',
|
|
78
|
+
currentFocusStage: ''
|
|
79
|
+
},
|
|
80
|
+
context: {
|
|
81
|
+
planningPosture: '',
|
|
82
|
+
evidenceMaturity: '',
|
|
83
|
+
canonicalTerms: [],
|
|
84
|
+
durableDecisionSources: []
|
|
85
|
+
},
|
|
86
|
+
evidence: [],
|
|
87
|
+
route: {
|
|
88
|
+
recommended: '',
|
|
89
|
+
whyThisWinsNow: '',
|
|
90
|
+
rejectedRoutes: [],
|
|
91
|
+
firstSignal: '',
|
|
92
|
+
killSignal: ''
|
|
93
|
+
},
|
|
94
|
+
stages: [],
|
|
95
|
+
items: [],
|
|
96
|
+
handoff: {
|
|
97
|
+
readyForCcPlan: [],
|
|
98
|
+
parked: [],
|
|
99
|
+
serialSpine: [],
|
|
100
|
+
parallelWaves: []
|
|
101
|
+
},
|
|
102
|
+
architecture: {
|
|
103
|
+
diagramType: 'flowchart',
|
|
104
|
+
nodes: [],
|
|
105
|
+
edges: []
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
|
|
68
109
|
function normalizeHeader(value) {
|
|
69
110
|
return String(value || '')
|
|
70
111
|
.trim()
|
|
@@ -188,6 +229,83 @@ function normalizeTracking(raw) {
|
|
|
188
229
|
};
|
|
189
230
|
}
|
|
190
231
|
|
|
232
|
+
function normalizeStringList(value) {
|
|
233
|
+
if (Array.isArray(value)) {
|
|
234
|
+
return value.map((entry) => String(entry).trim()).filter(Boolean);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
return parseList(value);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function buildRoadmapHandoff(tracking, handoff = {}) {
|
|
241
|
+
const items = Array.isArray(tracking.items) ? tracking.items : [];
|
|
242
|
+
const dependencyHandoff = tracking.dependencyHandoff || {};
|
|
243
|
+
const readyForCcPlan = normalizeStringList(handoff.readyForCcPlan);
|
|
244
|
+
const parked = normalizeStringList(handoff.parked);
|
|
245
|
+
|
|
246
|
+
return {
|
|
247
|
+
readyForCcPlan: readyForCcPlan.length
|
|
248
|
+
? readyForCcPlan
|
|
249
|
+
: items.filter((item) => item.backlog.ready && !item.backlog.parked).map((item) => item.rmId),
|
|
250
|
+
parked: parked.length
|
|
251
|
+
? parked
|
|
252
|
+
: items.filter((item) => item.backlog.parked).map((item) => item.rmId),
|
|
253
|
+
serialSpine: normalizeStringList(handoff.serialSpine || dependencyHandoff.serialSpine),
|
|
254
|
+
parallelWaves: normalizeStringList(
|
|
255
|
+
handoff.parallelWaves || dependencyHandoff.parallelReadyNextWave
|
|
256
|
+
)
|
|
257
|
+
};
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
function normalizeRoadmapState(raw = {}) {
|
|
261
|
+
const tracking = normalizeTracking(raw);
|
|
262
|
+
const meta = raw.meta || {};
|
|
263
|
+
const context = raw.context || {};
|
|
264
|
+
const route = raw.route || {};
|
|
265
|
+
const architecture = raw.architecture || {};
|
|
266
|
+
|
|
267
|
+
return {
|
|
268
|
+
...DEFAULT_ROADMAP_STATE,
|
|
269
|
+
version: 3,
|
|
270
|
+
outputPolicy: {
|
|
271
|
+
...DEFAULT_ROADMAP_STATE.outputPolicy,
|
|
272
|
+
...(raw.outputPolicy || {})
|
|
273
|
+
},
|
|
274
|
+
meta: {
|
|
275
|
+
...DEFAULT_ROADMAP_STATE.meta,
|
|
276
|
+
roadmapVersion: String(meta.roadmapVersion || tracking.backlogMeta.roadmapVersion).trim(),
|
|
277
|
+
skillVersion: String(meta.skillVersion || tracking.backlogMeta.skillVersion).trim(),
|
|
278
|
+
status: String(meta.status || DEFAULT_ROADMAP_STATE.meta.status).trim(),
|
|
279
|
+
lastUpdated: String(meta.lastUpdated || tracking.lastSyncedAt).trim(),
|
|
280
|
+
currentFocusStage: String(meta.currentFocusStage || tracking.backlogMeta.currentFocusStage).trim()
|
|
281
|
+
},
|
|
282
|
+
context: {
|
|
283
|
+
...DEFAULT_ROADMAP_STATE.context,
|
|
284
|
+
...context,
|
|
285
|
+
canonicalTerms: normalizeStringList(context.canonicalTerms),
|
|
286
|
+
durableDecisionSources: normalizeStringList(context.durableDecisionSources)
|
|
287
|
+
},
|
|
288
|
+
evidence: Array.isArray(raw.evidence) ? raw.evidence : [],
|
|
289
|
+
route: {
|
|
290
|
+
...DEFAULT_ROADMAP_STATE.route,
|
|
291
|
+
...route,
|
|
292
|
+
rejectedRoutes: Array.isArray(route.rejectedRoutes) ? route.rejectedRoutes : []
|
|
293
|
+
},
|
|
294
|
+
stages: Array.isArray(raw.stages) ? raw.stages : [],
|
|
295
|
+
items: tracking.items,
|
|
296
|
+
backlogMeta: tracking.backlogMeta,
|
|
297
|
+
dependencyHandoff: tracking.dependencyHandoff,
|
|
298
|
+
lastSyncedAt: tracking.lastSyncedAt,
|
|
299
|
+
handoff: buildRoadmapHandoff(tracking, raw.handoff || {}),
|
|
300
|
+
architecture: {
|
|
301
|
+
...DEFAULT_ROADMAP_STATE.architecture,
|
|
302
|
+
...architecture,
|
|
303
|
+
nodes: Array.isArray(architecture.nodes) ? architecture.nodes : [],
|
|
304
|
+
edges: Array.isArray(architecture.edges) ? architecture.edges : []
|
|
305
|
+
}
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
|
|
191
309
|
const ROADMAP_HEADER_TO_KEY = new Map(
|
|
192
310
|
ROADMAP_COLUMNS.map(([header, key]) => [normalizeHeader(header), key])
|
|
193
311
|
);
|
|
@@ -225,6 +343,7 @@ const PARKED_FIELD_MAP = new Map(
|
|
|
225
343
|
module.exports = {
|
|
226
344
|
BACKLOG_QUEUE_COLUMNS,
|
|
227
345
|
BACKLOG_QUEUE_HEADER_TO_KEY,
|
|
346
|
+
DEFAULT_ROADMAP_STATE,
|
|
228
347
|
DEFAULT_TRACKING,
|
|
229
348
|
PARKED_FIELD_MAP,
|
|
230
349
|
READY_FIELD_MAP,
|
|
@@ -240,6 +359,7 @@ module.exports = {
|
|
|
240
359
|
normalizeCell,
|
|
241
360
|
normalizeHeader,
|
|
242
361
|
normalizeItem,
|
|
362
|
+
normalizeRoadmapState,
|
|
243
363
|
normalizeTracking,
|
|
244
364
|
parseList
|
|
245
365
|
};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
const fs = require('fs');
|
|
2
|
+
const path = require('path');
|
|
2
3
|
|
|
3
4
|
const {
|
|
4
5
|
emptyBacklog,
|
|
5
6
|
normalizeItem,
|
|
7
|
+
normalizeRoadmapState,
|
|
6
8
|
normalizeTracking,
|
|
7
9
|
parseList
|
|
8
10
|
} = require('./schema');
|
|
@@ -63,7 +65,26 @@ function upgradeLegacyTracking(parsed) {
|
|
|
63
65
|
});
|
|
64
66
|
}
|
|
65
67
|
|
|
68
|
+
function isRoadmapStateFile(filePath) {
|
|
69
|
+
return path.basename(filePath || '') === 'roadmap.json';
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function legacyTrackingFileFor(filePath) {
|
|
73
|
+
return path.join(path.dirname(filePath), 'roadmap-tracking.json');
|
|
74
|
+
}
|
|
75
|
+
|
|
66
76
|
function loadTracking({ trackingFile, roadmapFile = '', backlogFile = '' }) {
|
|
77
|
+
if (isRoadmapStateFile(trackingFile)) {
|
|
78
|
+
if (fs.existsSync(trackingFile)) {
|
|
79
|
+
return normalizeRoadmapState(readJson(trackingFile));
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const legacyTrackingFile = legacyTrackingFileFor(trackingFile);
|
|
83
|
+
if (fs.existsSync(legacyTrackingFile)) {
|
|
84
|
+
return normalizeRoadmapState(readJson(legacyTrackingFile));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
67
88
|
if (trackingFile && fs.existsSync(trackingFile)) {
|
|
68
89
|
return upgradeLegacyTracking(readJson(trackingFile));
|
|
69
90
|
}
|
|
@@ -112,7 +133,10 @@ function applySyncArgs(tracking, args) {
|
|
|
112
133
|
}
|
|
113
134
|
|
|
114
135
|
function persistTrackingFiles({ trackingFile, roadmapFile, backlogFile, tracking }) {
|
|
115
|
-
writeJson(
|
|
136
|
+
writeJson(
|
|
137
|
+
trackingFile,
|
|
138
|
+
isRoadmapStateFile(trackingFile) ? normalizeRoadmapState(tracking) : tracking
|
|
139
|
+
);
|
|
116
140
|
|
|
117
141
|
const roadmapOutput = renderRoadmapDocument({
|
|
118
142
|
original: readFileIfExists(roadmapFile) || '# ROADMAP\n',
|