cc-devflow 4.5.14 → 4.5.16
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 +5 -0
- package/.claude/skills/cc-act/SKILL.md +2 -2
- package/.claude/skills/cc-act/assets/PR_BRIEF_TEMPLATE.md +3 -0
- package/.claude/skills/cc-act/scripts/render-pr-brief.sh +113 -33
- package/.claude/skills/cc-check/SKILL.md +0 -1
- package/.claude/skills/cc-dev/CHANGELOG.md +5 -0
- package/.claude/skills/cc-dev/PLAYBOOK.md +6 -3
- package/.claude/skills/cc-dev/SKILL.md +11 -8
- package/.claude/skills/cc-dev/scripts/ensure-work-branch.sh +117 -0
- package/.claude/skills/cc-dev/scripts/prepare-change-worktree.sh +135 -0
- package/.claude/skills/cc-dev/scripts/resolve-cc-devflow.sh +8 -26
- package/.claude/skills/cc-do/SKILL.md +1 -2
- package/.claude/skills/cc-investigate/CHANGELOG.md +15 -0
- package/.claude/skills/cc-investigate/SKILL.md +86 -9
- package/.claude/skills/cc-investigate/assets/TASKS_TEMPLATE.md +57 -1
- package/.claude/skills/cc-investigate/references/investigation-contract.md +1 -0
- package/.claude/skills/cc-plan/CHANGELOG.md +23 -0
- package/.claude/skills/cc-plan/PLAYBOOK.md +8 -5
- package/.claude/skills/cc-plan/SKILL.md +91 -20
- package/.claude/skills/cc-plan/assets/TASKS_TEMPLATE.md +59 -8
- package/.claude/skills/cc-plan/references/planning-contract.md +15 -9
- package/.claude/skills/cc-pr-review/CHANGELOG.md +9 -0
- package/.claude/skills/cc-pr-review/PLAYBOOK.md +3 -0
- package/.claude/skills/cc-pr-review/SKILL.md +30 -1
- package/.claude/skills/cc-review/CHANGELOG.md +10 -0
- package/.claude/skills/cc-review/SKILL.md +53 -9
- package/.claude/skills/cc-review/references/implementation-review-branch.md +1 -0
- package/.claude/skills/cc-review/references/plan-review-branch.md +1 -0
- package/.claude/skills/cc-review/references/review-methods.md +30 -0
- package/.claude/skills/cc-roadmap/CHANGELOG.md +6 -0
- package/.claude/skills/cc-roadmap/SKILL.md +1 -1
- package/.claude/skills/cc-roadmap/scripts/lib/roadmap-tracking/markdown.js +274 -69
- package/.claude/skills/cc-roadmap/scripts/lib/roadmap-tracking/schema.js +69 -15
- package/CHANGELOG.md +18 -0
- package/README.md +3 -4
- package/README.zh-CN.md +3 -4
- package/bin/cc-devflow-cli.js +8 -94
- package/docs/examples/example-bindings.json +8 -8
- package/docs/examples/full-design-blocked/BACKLOG.md +12 -1
- package/docs/examples/full-design-blocked/README.md +1 -1
- package/docs/examples/full-design-blocked/ROADMAP.md +2 -2
- package/docs/examples/full-design-blocked/changes/REQ-002-bulk-invite-import/task.md +39 -5
- package/docs/examples/full-design-blocked/roadmap.json +7 -2
- package/docs/examples/local-handoff/BACKLOG.md +12 -1
- package/docs/examples/local-handoff/README.md +1 -1
- package/docs/examples/local-handoff/ROADMAP.md +2 -2
- package/docs/examples/local-handoff/changes/REQ-003-audit-log-export/task.md +39 -5
- package/docs/examples/local-handoff/roadmap.json +7 -2
- package/docs/examples/pdca-loop/BACKLOG.md +12 -1
- package/docs/examples/pdca-loop/README.md +1 -1
- package/docs/examples/pdca-loop/ROADMAP.md +2 -2
- package/docs/examples/pdca-loop/changes/REQ-001-copy-invite-link/task.md +39 -5
- package/docs/examples/pdca-loop/roadmap.json +7 -2
- package/lib/skill-runtime/CLAUDE.md +1 -1
- package/lib/skill-runtime/__tests__/cli-bootstrap.integration.test.js +2 -1
- package/lib/skill-runtime/__tests__/config.test.js +7 -2
- package/lib/skill-runtime/config.js +38 -6
- package/lib/skill-runtime/index.js +1 -9
- package/package.json +1 -1
- package/lib/skill-runtime/errors.js +0 -39
- package/lib/skill-runtime/query-registry.js +0 -101
- package/lib/skill-runtime/query.js +0 -126
- package/lib/skill-runtime/trace.js +0 -22
|
@@ -9,7 +9,6 @@ const {
|
|
|
9
9
|
ROADMAP_COLUMNS,
|
|
10
10
|
ROADMAP_HEADER_TO_KEY,
|
|
11
11
|
formatBacklogValue,
|
|
12
|
-
formatBoolean,
|
|
13
12
|
formatCell,
|
|
14
13
|
formatInlineCode,
|
|
15
14
|
formatList,
|
|
@@ -21,6 +20,169 @@ const {
|
|
|
21
20
|
parseList
|
|
22
21
|
} = require('./schema');
|
|
23
22
|
|
|
23
|
+
const DOCUMENT_LABELS = {
|
|
24
|
+
en: {
|
|
25
|
+
roadmapTitle: 'ROADMAP',
|
|
26
|
+
backlogTitle: 'BACKLOG',
|
|
27
|
+
implementationTracking: 'Implementation Tracking',
|
|
28
|
+
technicalArchitecture: 'Technical Architecture',
|
|
29
|
+
roadmapStateSource: 'Roadmap state source',
|
|
30
|
+
trackingSource: 'Tracking source',
|
|
31
|
+
outputLanguage: 'Output language',
|
|
32
|
+
deprecatedProjection: '> Deprecated projection. Edit `roadmap.json` instead.',
|
|
33
|
+
backlogMeta: 'Backlog Meta',
|
|
34
|
+
roadmapVersion: 'Roadmap version',
|
|
35
|
+
skillVersion: 'Skill version',
|
|
36
|
+
lastSynced: 'Last synced',
|
|
37
|
+
currentFocusStage: 'Current focus stage',
|
|
38
|
+
queue: 'Queue',
|
|
39
|
+
dependencyHandoff: 'Dependency Handoff',
|
|
40
|
+
serialSpine: 'Serial spine',
|
|
41
|
+
parallelReadyNextWave: 'Parallel-ready next wave',
|
|
42
|
+
notesOnBlockers: 'Notes on blockers',
|
|
43
|
+
projectDirectionHandoff: 'Project Direction Handoff',
|
|
44
|
+
projectDirectionMode: 'Project direction mode',
|
|
45
|
+
projectDirectionRationale: 'Direction mode rationale',
|
|
46
|
+
directionQuestionsSelected: 'Direction-specific questions selected',
|
|
47
|
+
directionQuestionsSkipped: 'Direction-specific questions skipped',
|
|
48
|
+
directionGuardrailsApplied: 'Direction guardrails applied',
|
|
49
|
+
planningPosture: 'Planning posture',
|
|
50
|
+
evidenceMaturity: 'Evidence maturity',
|
|
51
|
+
readyForReqPlan: 'Ready For Req-Plan',
|
|
52
|
+
parked: 'Parked',
|
|
53
|
+
yes: 'Yes',
|
|
54
|
+
no: 'No',
|
|
55
|
+
readyEmpty:
|
|
56
|
+
'- RM-001:\n - Primary Capability:\n - Secondary Capabilities:\n - Why now:\n - Success signal:\n - Entry constraints:\n - Capability gap:\n - Expected spec delta:\n - Open risks:\n - First planning question:\n - Required context to load:\n - Depends On:\n - Parallel With:\n - Why this is ready now:',
|
|
57
|
+
parkedEmpty: '- RM-XXX:\n - Reason parked:\n - Trigger to reopen:\n - Missing evidence:',
|
|
58
|
+
readyFields: {
|
|
59
|
+
primaryCapability: 'Primary Capability',
|
|
60
|
+
secondaryCapabilities: 'Secondary Capabilities',
|
|
61
|
+
whyNow: 'Why now',
|
|
62
|
+
successSignal: 'Success signal',
|
|
63
|
+
entryConstraints: 'Entry constraints',
|
|
64
|
+
capabilityGap: 'Capability gap',
|
|
65
|
+
expectedSpecDelta: 'Expected spec delta',
|
|
66
|
+
openRisks: 'Open risks',
|
|
67
|
+
firstPlanningQuestion: 'First planning question',
|
|
68
|
+
requiredContextToLoad: 'Required context to load',
|
|
69
|
+
dependsOn: 'Depends On',
|
|
70
|
+
parallelWith: 'Parallel With',
|
|
71
|
+
whyReadyNow: 'Why this is ready now'
|
|
72
|
+
},
|
|
73
|
+
parkedFields: {
|
|
74
|
+
parkedReason: 'Reason parked',
|
|
75
|
+
triggerToReopen: 'Trigger to reopen',
|
|
76
|
+
missingEvidence: 'Missing evidence'
|
|
77
|
+
},
|
|
78
|
+
roadmapColumns: ROADMAP_COLUMNS.map(([label, key]) => [label, key]),
|
|
79
|
+
backlogColumns: BACKLOG_QUEUE_COLUMNS.map(([label, key]) => [label, key])
|
|
80
|
+
},
|
|
81
|
+
'zh-CN': {
|
|
82
|
+
roadmapTitle: '路线图',
|
|
83
|
+
backlogTitle: '待办队列',
|
|
84
|
+
implementationTracking: '执行跟踪',
|
|
85
|
+
technicalArchitecture: '技术架构',
|
|
86
|
+
roadmapStateSource: '路线图状态源',
|
|
87
|
+
trackingSource: '跟踪源',
|
|
88
|
+
outputLanguage: 'Output language',
|
|
89
|
+
deprecatedProjection: '> 已废弃投影。请编辑 `roadmap.json`。',
|
|
90
|
+
backlogMeta: '待办元信息',
|
|
91
|
+
roadmapVersion: '路线图版本',
|
|
92
|
+
skillVersion: 'Skill 版本',
|
|
93
|
+
lastSynced: '最近同步',
|
|
94
|
+
currentFocusStage: '当前聚焦阶段',
|
|
95
|
+
queue: '队列',
|
|
96
|
+
dependencyHandoff: '依赖交接',
|
|
97
|
+
serialSpine: '串行主线',
|
|
98
|
+
parallelReadyNextWave: '下一波可并行事项',
|
|
99
|
+
notesOnBlockers: '阻塞说明',
|
|
100
|
+
projectDirectionHandoff: '项目方向交接',
|
|
101
|
+
projectDirectionMode: '项目方向模式',
|
|
102
|
+
projectDirectionRationale: '方向模式理由',
|
|
103
|
+
directionQuestionsSelected: '已选择的方向问题',
|
|
104
|
+
directionQuestionsSkipped: '已跳过的方向问题',
|
|
105
|
+
directionGuardrailsApplied: '已应用的方向护栏',
|
|
106
|
+
planningPosture: '规划姿态',
|
|
107
|
+
evidenceMaturity: '证据成熟度',
|
|
108
|
+
readyForReqPlan: '可进入 Req-Plan',
|
|
109
|
+
parked: '暂存',
|
|
110
|
+
yes: '是',
|
|
111
|
+
no: '否',
|
|
112
|
+
readyEmpty:
|
|
113
|
+
'- RM-001:\n - 主能力:\n - 次能力:\n - 为什么现在做:\n - 成功信号:\n - 进入约束:\n - 能力缺口:\n - 预期规格变化:\n - 未决风险:\n - 首个规划问题:\n - 必须加载的上下文:\n - 依赖:\n - 可并行:\n - 为什么现在已就绪:',
|
|
114
|
+
parkedEmpty: '- RM-XXX:\n - 暂存原因:\n - 重新打开触发条件:\n - 缺失证据:',
|
|
115
|
+
readyFields: {
|
|
116
|
+
primaryCapability: '主能力',
|
|
117
|
+
secondaryCapabilities: '次能力',
|
|
118
|
+
whyNow: '为什么现在做',
|
|
119
|
+
successSignal: '成功信号',
|
|
120
|
+
entryConstraints: '进入约束',
|
|
121
|
+
capabilityGap: '能力缺口',
|
|
122
|
+
expectedSpecDelta: '预期规格变化',
|
|
123
|
+
openRisks: '未决风险',
|
|
124
|
+
firstPlanningQuestion: '首个规划问题',
|
|
125
|
+
requiredContextToLoad: '必须加载的上下文',
|
|
126
|
+
dependsOn: '依赖',
|
|
127
|
+
parallelWith: '可并行',
|
|
128
|
+
whyReadyNow: '为什么现在已就绪'
|
|
129
|
+
},
|
|
130
|
+
parkedFields: {
|
|
131
|
+
parkedReason: '暂存原因',
|
|
132
|
+
triggerToReopen: '重新打开触发条件',
|
|
133
|
+
missingEvidence: '缺失证据'
|
|
134
|
+
},
|
|
135
|
+
roadmapColumns: [
|
|
136
|
+
['RM-ID', 'rmId'],
|
|
137
|
+
['事项', 'item'],
|
|
138
|
+
['阶段', 'stage'],
|
|
139
|
+
['优先级', 'priority'],
|
|
140
|
+
['主能力', 'primaryCapability'],
|
|
141
|
+
['次能力', 'secondaryCapabilities'],
|
|
142
|
+
['预期规格变化', 'expectedSpecDelta'],
|
|
143
|
+
['依赖', 'dependsOn'],
|
|
144
|
+
['状态', 'status'],
|
|
145
|
+
['REQ', 'req'],
|
|
146
|
+
['进度', 'progress']
|
|
147
|
+
],
|
|
148
|
+
backlogColumns: [
|
|
149
|
+
['RM-ID', 'rmId'],
|
|
150
|
+
['标题', 'item'],
|
|
151
|
+
['来源阶段', 'stage'],
|
|
152
|
+
['优先级', 'priority'],
|
|
153
|
+
['主能力', 'primaryCapability'],
|
|
154
|
+
['次能力', 'secondaryCapabilities'],
|
|
155
|
+
['能力缺口', 'capabilityGap'],
|
|
156
|
+
['预期规格变化', 'expectedSpecDelta'],
|
|
157
|
+
['证据', 'evidence'],
|
|
158
|
+
['依赖', 'dependsOn'],
|
|
159
|
+
['可并行', 'parallelWith'],
|
|
160
|
+
['未知项', 'unknowns'],
|
|
161
|
+
['下一决策', 'nextDecision'],
|
|
162
|
+
['就绪', 'ready']
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
function labelsFor(tracking) {
|
|
168
|
+
return DOCUMENT_LABELS[tracking?.outputPolicy?.documentLanguage] || DOCUMENT_LABELS.en;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
function outputLanguageFor(tracking) {
|
|
172
|
+
return tracking?.outputPolicy?.documentLanguage || DEFAULT_TRACKING.outputPolicy?.documentLanguage || 'en';
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
function extractAnySection(markdown, headings) {
|
|
176
|
+
for (const heading of headings) {
|
|
177
|
+
const section = extractSection(markdown, heading);
|
|
178
|
+
if (section) {
|
|
179
|
+
return section;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return null;
|
|
184
|
+
}
|
|
185
|
+
|
|
24
186
|
function splitRow(line) {
|
|
25
187
|
return line
|
|
26
188
|
.trim()
|
|
@@ -98,7 +260,10 @@ function parseTable(sectionBody, headerMap, buildRow) {
|
|
|
98
260
|
}
|
|
99
261
|
|
|
100
262
|
function trackingFromRoadmap(markdown) {
|
|
101
|
-
const section =
|
|
263
|
+
const section = extractAnySection(markdown, [
|
|
264
|
+
'Implementation Tracking',
|
|
265
|
+
DOCUMENT_LABELS['zh-CN'].implementationTracking
|
|
266
|
+
]);
|
|
102
267
|
if (!section) {
|
|
103
268
|
return [];
|
|
104
269
|
}
|
|
@@ -135,6 +300,7 @@ function parseBacklogMeta(sectionBody) {
|
|
|
135
300
|
currentFocusStage: ''
|
|
136
301
|
};
|
|
137
302
|
let lastSyncedAt = '';
|
|
303
|
+
let documentLanguage = '';
|
|
138
304
|
|
|
139
305
|
for (const line of lines) {
|
|
140
306
|
const match = /^-\s+([^:]+):\s*(.*)$/.exec(line);
|
|
@@ -145,18 +311,20 @@ function parseBacklogMeta(sectionBody) {
|
|
|
145
311
|
const label = normalizeHeader(match[1]);
|
|
146
312
|
const value = normalizeCell(match[2].replace(/`/g, ''));
|
|
147
313
|
|
|
148
|
-
if (label === 'roadmap version') {
|
|
314
|
+
if (label === 'roadmap version' || label === '路线图版本') {
|
|
149
315
|
meta.roadmapVersion = value;
|
|
150
|
-
} else if (label === 'skill version') {
|
|
316
|
+
} else if (label === 'skill version' || label === 'skill 版本') {
|
|
151
317
|
meta.skillVersion = value;
|
|
152
|
-
} else if (label === 'last synced') {
|
|
318
|
+
} else if (label === 'last synced' || label === '最近同步') {
|
|
153
319
|
lastSyncedAt = value;
|
|
154
|
-
} else if (label === 'current focus stage') {
|
|
320
|
+
} else if (label === 'current focus stage' || label === '当前聚焦阶段') {
|
|
155
321
|
meta.currentFocusStage = value;
|
|
322
|
+
} else if (label === 'output language') {
|
|
323
|
+
documentLanguage = value;
|
|
156
324
|
}
|
|
157
325
|
}
|
|
158
326
|
|
|
159
|
-
return { meta, lastSyncedAt };
|
|
327
|
+
return { meta, lastSyncedAt, documentLanguage };
|
|
160
328
|
}
|
|
161
329
|
|
|
162
330
|
function parseBacklogQueue(sectionBody) {
|
|
@@ -279,11 +447,11 @@ function parseDependencyHandoff(sectionBody) {
|
|
|
279
447
|
const label = normalizeHeader(match[1]);
|
|
280
448
|
const value = normalizeCell(match[2].replace(/`/g, ''));
|
|
281
449
|
|
|
282
|
-
if (label === 'serial spine') {
|
|
450
|
+
if (label === 'serial spine' || label === '串行主线') {
|
|
283
451
|
next.serialSpine = value;
|
|
284
|
-
} else if (label === 'parallel ready next wave') {
|
|
452
|
+
} else if (label === 'parallel ready next wave' || label === '下一波可并行事项') {
|
|
285
453
|
next.parallelReadyNextWave = value;
|
|
286
|
-
} else if (label === 'notes on blockers') {
|
|
454
|
+
} else if (label === 'notes on blockers' || label === '阻塞说明') {
|
|
287
455
|
next.notesOnBlockers = value;
|
|
288
456
|
}
|
|
289
457
|
}
|
|
@@ -327,26 +495,35 @@ function mergeItemMaps(baseItems, incomingItems) {
|
|
|
327
495
|
function trackingFromBacklog(markdown, baseTracking) {
|
|
328
496
|
const next = normalizeTracking(baseTracking);
|
|
329
497
|
|
|
330
|
-
const metaSection =
|
|
498
|
+
const metaSection = extractAnySection(markdown, ['Backlog Meta', DOCUMENT_LABELS['zh-CN'].backlogMeta]);
|
|
331
499
|
if (metaSection) {
|
|
332
500
|
const parsed = parseBacklogMeta(metaSection.body);
|
|
333
501
|
next.backlogMeta = parsed.meta;
|
|
334
502
|
if (parsed.lastSyncedAt) {
|
|
335
503
|
next.lastSyncedAt = parsed.lastSyncedAt;
|
|
336
504
|
}
|
|
505
|
+
if (parsed.documentLanguage) {
|
|
506
|
+
next.outputPolicy.documentLanguage = parsed.documentLanguage;
|
|
507
|
+
}
|
|
337
508
|
}
|
|
338
509
|
|
|
339
|
-
const queueSection =
|
|
510
|
+
const queueSection = extractAnySection(markdown, ['Queue', DOCUMENT_LABELS['zh-CN'].queue]);
|
|
340
511
|
if (queueSection) {
|
|
341
512
|
next.items = mergeItemMaps(next.items, parseBacklogQueue(queueSection.body));
|
|
342
513
|
}
|
|
343
514
|
|
|
344
|
-
const dependencySection =
|
|
515
|
+
const dependencySection = extractAnySection(markdown, [
|
|
516
|
+
'Dependency Handoff',
|
|
517
|
+
DOCUMENT_LABELS['zh-CN'].dependencyHandoff
|
|
518
|
+
]);
|
|
345
519
|
if (dependencySection) {
|
|
346
520
|
next.dependencyHandoff = parseDependencyHandoff(dependencySection.body);
|
|
347
521
|
}
|
|
348
522
|
|
|
349
|
-
const readySection =
|
|
523
|
+
const readySection = extractAnySection(markdown, [
|
|
524
|
+
'Ready For Req-Plan',
|
|
525
|
+
DOCUMENT_LABELS['zh-CN'].readyForReqPlan
|
|
526
|
+
]);
|
|
350
527
|
if (readySection) {
|
|
351
528
|
next.items = mergeItemMaps(
|
|
352
529
|
next.items,
|
|
@@ -373,7 +550,7 @@ function trackingFromBacklog(markdown, baseTracking) {
|
|
|
373
550
|
);
|
|
374
551
|
}
|
|
375
552
|
|
|
376
|
-
const parkedSection =
|
|
553
|
+
const parkedSection = extractAnySection(markdown, ['Parked', DOCUMENT_LABELS['zh-CN'].parked]);
|
|
377
554
|
if (parkedSection) {
|
|
378
555
|
next.items = mergeItemMaps(
|
|
379
556
|
next.items,
|
|
@@ -408,8 +585,10 @@ function trackingFromMarkdown(roadmapMarkdown = '', backlogMarkdown = '') {
|
|
|
408
585
|
}
|
|
409
586
|
|
|
410
587
|
function renderRoadmapTable(tracking) {
|
|
411
|
-
const
|
|
412
|
-
const
|
|
588
|
+
const labels = labelsFor(tracking);
|
|
589
|
+
const columns = labels.roadmapColumns;
|
|
590
|
+
const header = `| ${columns.map(([label]) => label).join(' | ')} |`;
|
|
591
|
+
const separator = `|${columns.map(() => '------').join('|')}|`;
|
|
413
592
|
const rows = tracking.items.length
|
|
414
593
|
? tracking.items.map((item) =>
|
|
415
594
|
[
|
|
@@ -450,13 +629,16 @@ function isRoadmapState(tracking) {
|
|
|
450
629
|
}
|
|
451
630
|
|
|
452
631
|
function buildTrackingBody(roadmapFile, trackingFile, tracking) {
|
|
632
|
+
const labels = labelsFor(tracking);
|
|
453
633
|
const relativePath = path.relative(path.dirname(roadmapFile), trackingFile).replace(/\\/g, '/');
|
|
454
634
|
const displayPath = relativePath || path.basename(trackingFile);
|
|
455
|
-
const sourceLabel = isRoadmapState(tracking) ?
|
|
635
|
+
const sourceLabel = isRoadmapState(tracking) ? labels.roadmapStateSource : labels.trackingSource;
|
|
636
|
+
const outputLanguage = outputLanguageFor(tracking);
|
|
456
637
|
|
|
457
638
|
return [
|
|
458
639
|
'',
|
|
459
640
|
`- ${sourceLabel}: \`${displayPath}\``,
|
|
641
|
+
`- ${labels.outputLanguage}: ${outputLanguage}`,
|
|
460
642
|
'',
|
|
461
643
|
'<!-- roadmap-tracking:start -->',
|
|
462
644
|
renderRoadmapTable(tracking),
|
|
@@ -476,6 +658,7 @@ function formatMermaidLabel(value) {
|
|
|
476
658
|
}
|
|
477
659
|
|
|
478
660
|
function renderArchitectureDiagram(tracking) {
|
|
661
|
+
const labels = labelsFor(tracking);
|
|
479
662
|
const architecture = tracking.architecture || {};
|
|
480
663
|
const nodes = Array.isArray(architecture.nodes) ? architecture.nodes : [];
|
|
481
664
|
const edges = Array.isArray(architecture.edges) ? architecture.edges : [];
|
|
@@ -484,7 +667,7 @@ function renderArchitectureDiagram(tracking) {
|
|
|
484
667
|
return '';
|
|
485
668
|
}
|
|
486
669
|
|
|
487
|
-
const lines = [
|
|
670
|
+
const lines = [`## ${labels.technicalArchitecture}`, '', '```mermaid', 'flowchart TD'];
|
|
488
671
|
|
|
489
672
|
nodes.forEach((node) => {
|
|
490
673
|
const id = formatMermaidId(node.id);
|
|
@@ -509,20 +692,28 @@ function renderArchitectureDiagram(tracking) {
|
|
|
509
692
|
}
|
|
510
693
|
|
|
511
694
|
function renderRoadmapDocument({ original = '# ROADMAP\n', roadmapFile, trackingFile, tracking }) {
|
|
512
|
-
const
|
|
695
|
+
const labels = labelsFor(tracking);
|
|
696
|
+
const baseOriginal = original.trim() === '# ROADMAP' ? `# ${labels.roadmapTitle}\n` : original;
|
|
697
|
+
const section = extractAnySection(baseOriginal, [
|
|
698
|
+
'Implementation Tracking',
|
|
699
|
+
labels.implementationTracking
|
|
700
|
+
]);
|
|
513
701
|
const body = buildTrackingBody(roadmapFile, trackingFile, tracking);
|
|
514
|
-
const nextSection = `##
|
|
702
|
+
const nextSection = `## ${labels.implementationTracking}${body}`;
|
|
515
703
|
const architectureSection = isRoadmapState(tracking) ? `\n${renderArchitectureDiagram(tracking)}` : '';
|
|
516
704
|
|
|
517
705
|
const rendered = section
|
|
518
|
-
? `${
|
|
519
|
-
: `${
|
|
706
|
+
? `${baseOriginal.slice(0, section.start)}${nextSection}${baseOriginal.slice(section.end)}`
|
|
707
|
+
: `${baseOriginal.replace(/\s*$/, '')}\n\n${nextSection}\n`;
|
|
520
708
|
|
|
521
709
|
if (!architectureSection.trim()) {
|
|
522
710
|
return rendered;
|
|
523
711
|
}
|
|
524
712
|
|
|
525
|
-
const existingArchitecture =
|
|
713
|
+
const existingArchitecture = extractAnySection(rendered, [
|
|
714
|
+
'Technical Architecture',
|
|
715
|
+
labels.technicalArchitecture
|
|
716
|
+
]);
|
|
526
717
|
if (existingArchitecture) {
|
|
527
718
|
return `${rendered.slice(0, existingArchitecture.start)}${architectureSection.trimEnd()}\n${rendered.slice(existingArchitecture.end)}`;
|
|
528
719
|
}
|
|
@@ -530,9 +721,15 @@ function renderRoadmapDocument({ original = '# ROADMAP\n', roadmapFile, tracking
|
|
|
530
721
|
return `${rendered.replace(/\s*$/, '')}\n\n${architectureSection}`;
|
|
531
722
|
}
|
|
532
723
|
|
|
724
|
+
function renderLocalizedBoolean(value, labels) {
|
|
725
|
+
return value ? labels.yes : labels.no;
|
|
726
|
+
}
|
|
727
|
+
|
|
533
728
|
function renderBacklogQueue(tracking) {
|
|
534
|
-
const
|
|
535
|
-
const
|
|
729
|
+
const labels = labelsFor(tracking);
|
|
730
|
+
const columns = labels.backlogColumns;
|
|
731
|
+
const header = `| ${columns.map(([label]) => label).join(' | ')} |`;
|
|
732
|
+
const separator = `|${columns.map(() => '------').join('|')}|`;
|
|
536
733
|
const queueItems = tracking.items.filter((item) => !item.backlog.parked);
|
|
537
734
|
const rows = queueItems.length
|
|
538
735
|
? queueItems.map((item) =>
|
|
@@ -550,7 +747,7 @@ function renderBacklogQueue(tracking) {
|
|
|
550
747
|
formatList(item.backlog.parallelWith),
|
|
551
748
|
formatBacklogValue(item.backlog.unknowns),
|
|
552
749
|
formatBacklogValue(item.backlog.nextDecision),
|
|
553
|
-
|
|
750
|
+
renderLocalizedBoolean(item.backlog.ready, labels)
|
|
554
751
|
].join(' | ')
|
|
555
752
|
)
|
|
556
753
|
: [
|
|
@@ -568,7 +765,7 @@ function renderBacklogQueue(tracking) {
|
|
|
568
765
|
'-',
|
|
569
766
|
'-',
|
|
570
767
|
'-',
|
|
571
|
-
|
|
768
|
+
labels.no
|
|
572
769
|
].join(' | ')
|
|
573
770
|
];
|
|
574
771
|
|
|
@@ -576,104 +773,112 @@ function renderBacklogQueue(tracking) {
|
|
|
576
773
|
}
|
|
577
774
|
|
|
578
775
|
function renderReadyForReqPlan(tracking) {
|
|
776
|
+
const labels = labelsFor(tracking);
|
|
777
|
+
const fields = labels.readyFields;
|
|
579
778
|
const readyItems = tracking.items.filter((item) => item.backlog.ready && !item.backlog.parked);
|
|
580
779
|
if (!readyItems.length) {
|
|
581
|
-
return
|
|
780
|
+
return labels.readyEmpty;
|
|
582
781
|
}
|
|
583
782
|
|
|
584
783
|
return readyItems
|
|
585
784
|
.map((item) =>
|
|
586
785
|
[
|
|
587
786
|
`- ${item.rmId}:`,
|
|
588
|
-
` -
|
|
589
|
-
` -
|
|
590
|
-
` -
|
|
591
|
-
` -
|
|
592
|
-
` -
|
|
593
|
-
` -
|
|
594
|
-
` -
|
|
595
|
-
` -
|
|
596
|
-
` -
|
|
597
|
-
` -
|
|
598
|
-
` -
|
|
599
|
-
` -
|
|
600
|
-
` -
|
|
787
|
+
` - ${fields.primaryCapability}: ${formatInlineCode(item.primaryCapability)}`,
|
|
788
|
+
` - ${fields.secondaryCapabilities}: ${item.secondaryCapabilities.length ? formatInlineCode(item.secondaryCapabilities.join(', ')) : '`-`'}`,
|
|
789
|
+
` - ${fields.whyNow}: ${formatBacklogValue(item.backlog.whyNow)}`,
|
|
790
|
+
` - ${fields.successSignal}: ${formatBacklogValue(item.backlog.successSignal)}`,
|
|
791
|
+
` - ${fields.entryConstraints}: ${formatBacklogValue(item.backlog.entryConstraints)}`,
|
|
792
|
+
` - ${fields.capabilityGap}: ${formatBacklogValue(item.backlog.capabilityGap)}`,
|
|
793
|
+
` - ${fields.expectedSpecDelta}: ${formatBacklogValue(item.expectedSpecDelta)}`,
|
|
794
|
+
` - ${fields.openRisks}: ${formatBacklogValue(item.backlog.openRisks)}`,
|
|
795
|
+
` - ${fields.firstPlanningQuestion}: ${formatBacklogValue(item.backlog.firstPlanningQuestion)}`,
|
|
796
|
+
` - ${fields.requiredContextToLoad}: ${formatBacklogValue(item.backlog.requiredContextToLoad)}`,
|
|
797
|
+
` - ${fields.dependsOn}: ${item.dependsOn.length ? formatInlineCode(item.dependsOn.join(', ')) : '`-`'}`,
|
|
798
|
+
` - ${fields.parallelWith}: ${item.backlog.parallelWith.length ? formatInlineCode(item.backlog.parallelWith.join(', ')) : '`-`'}`,
|
|
799
|
+
` - ${fields.whyReadyNow}: ${formatBacklogValue(item.backlog.whyReadyNow)}`
|
|
601
800
|
].join('\n')
|
|
602
801
|
)
|
|
603
802
|
.join('\n\n');
|
|
604
803
|
}
|
|
605
804
|
|
|
606
805
|
function renderParked(tracking) {
|
|
806
|
+
const labels = labelsFor(tracking);
|
|
807
|
+
const fields = labels.parkedFields;
|
|
607
808
|
const parkedItems = tracking.items.filter((item) => item.backlog.parked);
|
|
608
809
|
if (!parkedItems.length) {
|
|
609
|
-
return
|
|
810
|
+
return labels.parkedEmpty;
|
|
610
811
|
}
|
|
611
812
|
|
|
612
813
|
return parkedItems
|
|
613
814
|
.map((item) =>
|
|
614
815
|
[
|
|
615
816
|
`- ${item.rmId}:`,
|
|
616
|
-
` -
|
|
617
|
-
` -
|
|
618
|
-
` -
|
|
817
|
+
` - ${fields.parkedReason}: ${formatBacklogValue(item.backlog.parkedReason)}`,
|
|
818
|
+
` - ${fields.triggerToReopen}: ${formatBacklogValue(item.backlog.triggerToReopen)}`,
|
|
819
|
+
` - ${fields.missingEvidence}: ${formatBacklogValue(item.backlog.missingEvidence)}`
|
|
619
820
|
].join('\n')
|
|
620
821
|
)
|
|
621
822
|
.join('\n\n');
|
|
622
823
|
}
|
|
623
824
|
|
|
624
825
|
function renderProjectDirectionHandoff(tracking) {
|
|
826
|
+
const labels = labelsFor(tracking);
|
|
625
827
|
const context = tracking.context || {};
|
|
626
828
|
|
|
627
829
|
return [
|
|
628
|
-
`-
|
|
629
|
-
`-
|
|
630
|
-
`-
|
|
631
|
-
`-
|
|
632
|
-
`-
|
|
633
|
-
`-
|
|
634
|
-
`-
|
|
830
|
+
`- ${labels.projectDirectionMode}: ${formatBacklogValue(context.projectDirectionMode)}`,
|
|
831
|
+
`- ${labels.projectDirectionRationale}: ${formatBacklogValue(context.projectDirectionRationale)}`,
|
|
832
|
+
`- ${labels.directionQuestionsSelected}: ${formatList(context.directionQuestionsSelected || [])}`,
|
|
833
|
+
`- ${labels.directionQuestionsSkipped}: ${formatList(context.directionQuestionsSkipped || [])}`,
|
|
834
|
+
`- ${labels.directionGuardrailsApplied}: ${formatList(context.directionGuardrailsApplied || [])}`,
|
|
835
|
+
`- ${labels.planningPosture}: ${formatBacklogValue(context.planningPosture)}`,
|
|
836
|
+
`- ${labels.evidenceMaturity}: ${formatBacklogValue(context.evidenceMaturity)}`
|
|
635
837
|
].join('\n');
|
|
636
838
|
}
|
|
637
839
|
|
|
638
840
|
function renderBacklogDocument({ backlogFile, trackingFile, tracking }) {
|
|
841
|
+
const labels = labelsFor(tracking);
|
|
639
842
|
const relativePath = path.relative(path.dirname(backlogFile), trackingFile).replace(/\\/g, '/');
|
|
640
843
|
const displayPath = relativePath || path.basename(trackingFile);
|
|
641
|
-
const sourceLabel = isRoadmapState(tracking) ?
|
|
844
|
+
const sourceLabel = isRoadmapState(tracking) ? labels.roadmapStateSource : labels.trackingSource;
|
|
845
|
+
const outputLanguage = outputLanguageFor(tracking);
|
|
642
846
|
const deprecationNotice = isRoadmapState(tracking)
|
|
643
|
-
? [
|
|
847
|
+
? [labels.deprecatedProjection, '']
|
|
644
848
|
: [];
|
|
645
849
|
|
|
646
850
|
return [
|
|
647
|
-
|
|
851
|
+
`# ${labels.backlogTitle}`,
|
|
648
852
|
'',
|
|
649
853
|
...deprecationNotice,
|
|
650
|
-
|
|
854
|
+
`## ${labels.backlogMeta}`,
|
|
651
855
|
'',
|
|
652
|
-
`-
|
|
653
|
-
`-
|
|
654
|
-
`-
|
|
655
|
-
`-
|
|
856
|
+
`- ${labels.roadmapVersion}: ${formatInlineCode(tracking.backlogMeta.roadmapVersion)}`,
|
|
857
|
+
`- ${labels.skillVersion}: ${formatInlineCode(tracking.backlogMeta.skillVersion)}`,
|
|
858
|
+
`- ${labels.lastSynced}: ${formatInlineCode(tracking.lastSyncedAt)}`,
|
|
859
|
+
`- ${labels.currentFocusStage}: ${formatInlineCode(tracking.backlogMeta.currentFocusStage)}`,
|
|
656
860
|
`- ${sourceLabel}: \`${displayPath}\``,
|
|
861
|
+
`- ${labels.outputLanguage}: ${outputLanguage}`,
|
|
657
862
|
'',
|
|
658
|
-
|
|
863
|
+
`## ${labels.queue}`,
|
|
659
864
|
'',
|
|
660
865
|
renderBacklogQueue(tracking),
|
|
661
866
|
'',
|
|
662
|
-
|
|
867
|
+
`## ${labels.dependencyHandoff}`,
|
|
663
868
|
'',
|
|
664
|
-
`-
|
|
665
|
-
`-
|
|
666
|
-
`-
|
|
869
|
+
`- ${labels.serialSpine}: ${formatBacklogValue(tracking.dependencyHandoff.serialSpine)}`,
|
|
870
|
+
`- ${labels.parallelReadyNextWave}: ${formatBacklogValue(tracking.dependencyHandoff.parallelReadyNextWave)}`,
|
|
871
|
+
`- ${labels.notesOnBlockers}: ${formatBacklogValue(tracking.dependencyHandoff.notesOnBlockers)}`,
|
|
667
872
|
'',
|
|
668
|
-
|
|
873
|
+
`## ${labels.projectDirectionHandoff}`,
|
|
669
874
|
'',
|
|
670
875
|
renderProjectDirectionHandoff(tracking),
|
|
671
876
|
'',
|
|
672
|
-
|
|
877
|
+
`## ${labels.readyForReqPlan}`,
|
|
673
878
|
'',
|
|
674
879
|
renderReadyForReqPlan(tracking),
|
|
675
880
|
'',
|
|
676
|
-
|
|
881
|
+
`## ${labels.parked}`,
|
|
677
882
|
'',
|
|
678
883
|
renderParked(tracking),
|
|
679
884
|
''
|