@slope-dev/slope 1.60.0 → 1.61.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -0
- package/dist/cli/commands/agent.js +2 -2
- package/dist/cli/commands/agent.js.map +1 -1
- package/dist/cli/commands/commit-ready.js +1 -1
- package/dist/cli/commands/commit-ready.js.map +1 -1
- package/dist/cli/commands/next.d.ts +1 -1
- package/dist/cli/commands/next.d.ts.map +1 -1
- package/dist/cli/commands/next.js +31 -2
- package/dist/cli/commands/next.js.map +1 -1
- package/dist/cli/commands/now.d.ts +3 -0
- package/dist/cli/commands/now.d.ts.map +1 -1
- package/dist/cli/commands/now.js +14 -2
- package/dist/cli/commands/now.js.map +1 -1
- package/dist/cli/commands/review-state.d.ts.map +1 -1
- package/dist/cli/commands/review-state.js +45 -4
- package/dist/cli/commands/review-state.js.map +1 -1
- package/dist/cli/commands/review.d.ts +9 -1
- package/dist/cli/commands/review.d.ts.map +1 -1
- package/dist/cli/commands/review.js +67 -39
- package/dist/cli/commands/review.js.map +1 -1
- package/dist/cli/commands/roadmap.d.ts.map +1 -1
- package/dist/cli/commands/roadmap.js +274 -5
- package/dist/cli/commands/roadmap.js.map +1 -1
- package/dist/cli/commands/sprint.d.ts.map +1 -1
- package/dist/cli/commands/sprint.js +353 -54
- package/dist/cli/commands/sprint.js.map +1 -1
- package/dist/cli/guards/claim-required.d.ts.map +1 -1
- package/dist/cli/guards/claim-required.js +19 -4
- package/dist/cli/guards/claim-required.js.map +1 -1
- package/dist/cli/guards/next-action.js +1 -1
- package/dist/cli/guards/next-action.js.map +1 -1
- package/dist/cli/guards/phase-boundary.d.ts.map +1 -1
- package/dist/cli/guards/phase-boundary.js +8 -2
- package/dist/cli/guards/phase-boundary.js.map +1 -1
- package/dist/cli/guards/post-push.js +2 -2
- package/dist/cli/guards/post-push.js.map +1 -1
- package/dist/cli/guards/review-tier.d.ts.map +1 -1
- package/dist/cli/guards/review-tier.js +2 -3
- package/dist/cli/guards/review-tier.js.map +1 -1
- package/dist/cli/guards/roadmap-edit-shipped.d.ts.map +1 -1
- package/dist/cli/guards/roadmap-edit-shipped.js +143 -7
- package/dist/cli/guards/roadmap-edit-shipped.js.map +1 -1
- package/dist/cli/guards/scope-drift.d.ts.map +1 -1
- package/dist/cli/guards/scope-drift.js +8 -2
- package/dist/cli/guards/scope-drift.js.map +1 -1
- package/dist/cli/guards/session-briefing.js +6 -2
- package/dist/cli/guards/session-briefing.js.map +1 -1
- package/dist/cli/guards/sprint-completion.d.ts.map +1 -1
- package/dist/cli/guards/sprint-completion.js +94 -18
- package/dist/cli/guards/sprint-completion.js.map +1 -1
- package/dist/cli/index.js +4 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/cli/registry.js +25 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli/roadmap-source-store.d.ts +37 -0
- package/dist/cli/roadmap-source-store.d.ts.map +1 -0
- package/dist/cli/roadmap-source-store.js +298 -0
- package/dist/cli/roadmap-source-store.js.map +1 -0
- package/dist/cli/sprint-inference.js +1 -1
- package/dist/cli/sprint-inference.js.map +1 -1
- package/dist/cli/sprint-rollover.d.ts +102 -0
- package/dist/cli/sprint-rollover.d.ts.map +1 -0
- package/dist/cli/sprint-rollover.js +558 -0
- package/dist/cli/sprint-rollover.js.map +1 -0
- package/dist/cli/sprint-state.d.ts +72 -1
- package/dist/cli/sprint-state.d.ts.map +1 -1
- package/dist/cli/sprint-state.js +203 -5
- package/dist/cli/sprint-state.js.map +1 -1
- package/dist/cli/template-generator.d.ts.map +1 -1
- package/dist/cli/template-generator.js +45 -32
- package/dist/cli/template-generator.js.map +1 -1
- package/dist/cli/workflow-resync.d.ts.map +1 -1
- package/dist/cli/workflow-resync.js +9 -8
- package/dist/cli/workflow-resync.js.map +1 -1
- package/dist/core/briefing.d.ts.map +1 -1
- package/dist/core/briefing.js +254 -14
- package/dist/core/briefing.js.map +1 -1
- package/dist/core/builder.d.ts +16 -2
- package/dist/core/builder.d.ts.map +1 -1
- package/dist/core/builder.js +82 -5
- package/dist/core/builder.js.map +1 -1
- package/dist/core/index.d.ts +7 -3
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +3 -1
- package/dist/core/index.js.map +1 -1
- package/dist/core/roadmap-focus.d.ts +101 -0
- package/dist/core/roadmap-focus.d.ts.map +1 -0
- package/dist/core/roadmap-focus.js +293 -0
- package/dist/core/roadmap-focus.js.map +1 -0
- package/dist/core/roadmap-sources.d.ts +52 -0
- package/dist/core/roadmap-sources.d.ts.map +1 -0
- package/dist/core/roadmap-sources.js +483 -0
- package/dist/core/roadmap-sources.js.map +1 -0
- package/dist/core/roadmap.d.ts +25 -1
- package/dist/core/roadmap.d.ts.map +1 -1
- package/dist/core/roadmap.js +62 -45
- package/dist/core/roadmap.js.map +1 -1
- package/dist/core/workflow-engine.d.ts.map +1 -1
- package/dist/core/workflow-engine.js +17 -2
- package/dist/core/workflow-engine.js.map +1 -1
- package/dist/mcp/registry.d.ts +1 -1
- package/dist/mcp/registry.d.ts.map +1 -1
- package/dist/mcp/registry.js +5 -4
- package/dist/mcp/registry.js.map +1 -1
- package/package.json +1 -1
- package/src/core/workflows/sprint-standard.yaml +1 -1
- package/templates/claude-code/CLAUDE.md +3 -1
- package/templates/claude-code/commands/start-sprint.md +9 -5
- package/templates/claude-code/rules/sprint-checklist.md +13 -10
- package/templates/codex/plugins/slope/.codex-plugin/plugin.json +1 -1
- package/templates/codex/plugins/slope/skills/slope-sprint/SKILL.md +5 -4
- package/templates/cursor/rules/slope-sprint-checklist.mdc +11 -8
- package/templates/generic/SLOPE-CHECKLIST.md +10 -7
- package/templates/pi/skills/start-sprint.md +9 -5
|
@@ -1,49 +1,69 @@
|
|
|
1
|
-
import { mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
|
|
2
|
-
import { dirname, isAbsolute, join } from 'node:path';
|
|
1
|
+
import { existsSync, mkdirSync, readFileSync, readdirSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { dirname, isAbsolute, join, relative, resolve } from 'node:path';
|
|
3
3
|
import { formatSprintReview, compareSprintIds, normalizeScorecard, parseSprintNumber } from '../../core/index.js';
|
|
4
4
|
import { loadConfig } from '../config.js';
|
|
5
5
|
import { resolveMetaphor } from '../metaphor.js';
|
|
6
|
-
import { updateGate } from '../sprint-state.js';
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
path = join(dir, files[files.length - 1]);
|
|
6
|
+
import { loadSprintState, updateGate } from '../sprint-state.js';
|
|
7
|
+
function discoverScorecardPaths(cwd, config) {
|
|
8
|
+
const dir = join(cwd, config.scorecardDir);
|
|
9
|
+
if (!existsSync(dir))
|
|
10
|
+
return [];
|
|
11
|
+
const patternParts = config.scorecardPattern.split('*');
|
|
12
|
+
const prefix = patternParts[0] ?? '';
|
|
13
|
+
const suffix = patternParts[1] ?? '';
|
|
14
|
+
const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
15
|
+
const regex = new RegExp(`^${escapeRegex(prefix)}(\\d+(?:\\.\\d+)?)${escapeRegex(suffix)}$`);
|
|
16
|
+
return readdirSync(dir)
|
|
17
|
+
.map(file => ({ file, sprint: parseSprintNumber(file.match(regex)?.[1] ?? '') }))
|
|
18
|
+
.filter((entry) => entry.sprint != null && entry.sprint >= config.minSprint)
|
|
19
|
+
.sort((a, b) => compareSprintIds(a.sprint, b.sprint))
|
|
20
|
+
.map(entry => join(dir, entry.file));
|
|
21
|
+
}
|
|
22
|
+
function resolveScorecardPath(path, sprintSelector, cwd, config) {
|
|
23
|
+
if (path && sprintSelector) {
|
|
24
|
+
console.error('\nUse either an explicit scorecard path or --sprint, not both.\n');
|
|
25
|
+
process.exit(1);
|
|
26
|
+
}
|
|
27
|
+
if (path)
|
|
28
|
+
return isAbsolute(path) ? path : resolve(cwd, path);
|
|
29
|
+
if (sprintSelector) {
|
|
30
|
+
const sprint = parseSprintNumber(sprintSelector);
|
|
31
|
+
if (sprint == null) {
|
|
32
|
+
console.error(`\nInvalid sprint selector: ${sprintSelector}\n`);
|
|
33
|
+
process.exit(1);
|
|
35
34
|
}
|
|
36
|
-
|
|
37
|
-
|
|
35
|
+
const selected = join(cwd, config.scorecardDir, config.scorecardPattern.replace('*', String(sprint)));
|
|
36
|
+
if (!existsSync(selected)) {
|
|
37
|
+
console.error(`\nScorecard not found for Sprint ${sprint}: ${relative(cwd, selected)}\n`);
|
|
38
38
|
process.exit(1);
|
|
39
39
|
}
|
|
40
|
+
return selected;
|
|
41
|
+
}
|
|
42
|
+
const scorecards = discoverScorecardPaths(cwd, config);
|
|
43
|
+
if (scorecards.length === 0) {
|
|
44
|
+
console.error('\nNo scorecards found. Pass an explicit scorecard path.\n');
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
if (scorecards.length > 1) {
|
|
48
|
+
console.error('\nMultiple scorecards found; refusing to guess which sprint to review.');
|
|
49
|
+
console.error('Pass an explicit path, for example:');
|
|
50
|
+
console.error(` slope review ${relative(cwd, scorecards[scorecards.length - 1])}`);
|
|
51
|
+
console.error('');
|
|
52
|
+
process.exit(1);
|
|
40
53
|
}
|
|
54
|
+
return scorecards[0];
|
|
55
|
+
}
|
|
56
|
+
export function reviewCommand(path, mode, metaphorFlag, outputPath, sprintSelector) {
|
|
57
|
+
const config = loadConfig();
|
|
58
|
+
const cwd = process.cwd();
|
|
59
|
+
const metaphor = resolveMetaphor(metaphorFlag ? [`--metaphor=${metaphorFlag}`] : [], config.metaphor);
|
|
60
|
+
const scorecardPath = resolveScorecardPath(path, sprintSelector, cwd, config);
|
|
41
61
|
let raw;
|
|
42
62
|
try {
|
|
43
|
-
raw = JSON.parse(readFileSync(
|
|
63
|
+
raw = JSON.parse(readFileSync(scorecardPath, 'utf8'));
|
|
44
64
|
}
|
|
45
65
|
catch {
|
|
46
|
-
console.error(`\nFailed to parse ${
|
|
66
|
+
console.error(`\nFailed to parse ${scorecardPath}\n`);
|
|
47
67
|
process.exit(1);
|
|
48
68
|
}
|
|
49
69
|
const card = normalizeScorecard(raw);
|
|
@@ -54,12 +74,20 @@ export function reviewCommand(path, mode, metaphorFlag, outputPath) {
|
|
|
54
74
|
if (outputPath !== null) {
|
|
55
75
|
const reviewPath = outputPath
|
|
56
76
|
? isAbsolute(outputPath) ? outputPath : join(cwd, outputPath)
|
|
57
|
-
: join(
|
|
77
|
+
: join(dirname(scorecardPath), `sprint-${card.sprint_number}-review.md`);
|
|
58
78
|
mkdirSync(dirname(reviewPath), { recursive: true });
|
|
59
79
|
writeFileSync(reviewPath, review + '\n');
|
|
60
|
-
console.
|
|
80
|
+
console.error(`\nReview written: ${relative(cwd, reviewPath)}`);
|
|
81
|
+
}
|
|
82
|
+
// Generating a historical sprint's review must not complete a different
|
|
83
|
+
// active sprint's gate.
|
|
84
|
+
const sprintState = loadSprintState(cwd);
|
|
85
|
+
if (sprintState?.sprint === card.sprint_number) {
|
|
86
|
+
updateGate(cwd, 'review_md', true);
|
|
61
87
|
}
|
|
62
|
-
// Mark review_md gate complete
|
|
63
|
-
updateGate(cwd, 'review_md', true);
|
|
64
88
|
}
|
|
89
|
+
export const reviewCommandInternals = {
|
|
90
|
+
discoverScorecardPaths,
|
|
91
|
+
resolveScorecardPath,
|
|
92
|
+
};
|
|
65
93
|
//# sourceMappingURL=review.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review.js","sourceRoot":"","sources":["../../../src/cli/commands/review.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"review.js","sourceRoot":"","sources":["../../../src/cli/commands/review.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"roadmap.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/roadmap.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"roadmap.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/roadmap.ts"],"names":[],"mappings":"AA8+BA,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA6ElE"}
|
|
@@ -1,14 +1,15 @@
|
|
|
1
1
|
import { readFileSync, writeFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
2
|
-
import { join } from 'node:path';
|
|
3
|
-
import { parseRoadmap, validateRoadmap, castRoadmapStructure, findShippedSprintsOnMain, compareSprintIds, computeCriticalPath, findParallelOpportunities, formatSprintLabel, formatRoadmapSummary, formatStrategicContext, isRoadmapSprintPending, loadScorecards, loadVision, parseSprintNumber, analyzeBacklog, mergeBacklogs, runAnalyzers, estimateComplexity, generateRoadmapFromVision, RoadmapGenerationError, } from '../../core/index.js';
|
|
2
|
+
import { dirname, join, relative, resolve } from 'node:path';
|
|
3
|
+
import { parseRoadmap, validateRoadmap, castRoadmapStructure, findShippedSprintsOnMain, compareSprintIds, computeCriticalPath, findParallelOpportunities, formatSprintLabel, formatRoadmapSummary, formatStrategicContext, buildRoadmapFocus, formatRoadmapFocus, formatRoadmapSprintLabel, roadmapSprintOrderValue, isRoadmapSprintPending, loadScorecards, discoverScorecardFiles, sprintNumberFromScorecardFile, loadVision, parseSprintNumber, analyzeBacklog, mergeBacklogs, runAnalyzers, estimateComplexity, generateRoadmapFromVision, RoadmapGenerationError, } from '../../core/index.js';
|
|
4
4
|
import { loadConfig } from '../config.js';
|
|
5
|
-
import { buildRoadmapReality, formatRoadmapRealitySection } from '../pre-sprint-reality.js';
|
|
5
|
+
import { buildRoadmapReality, formatRoadmapRealitySection, roadmapRealityIssues } from '../pre-sprint-reality.js';
|
|
6
6
|
import { interviewCommand } from './interview.js';
|
|
7
|
+
import { loadRoadmapSourceStore, hasModularRoadmapSources, planRoadmapSourceArchive, applyRoadmapSourceArchive, validateRoadmapSourceStore, writeRoadmapSourceProjection, } from '../roadmap-source-store.js';
|
|
7
8
|
// --- Helpers ---
|
|
8
9
|
function parseArgs(args) {
|
|
9
10
|
const result = {};
|
|
10
11
|
for (const arg of args) {
|
|
11
|
-
const match = arg.match(/^--(\w[\w-]*)(?:=(
|
|
12
|
+
const match = arg.match(/^--(\w[\w-]*)(?:=(.*))?$/);
|
|
12
13
|
if (match)
|
|
13
14
|
result[match[1]] = match[2] ?? 'true';
|
|
14
15
|
}
|
|
@@ -301,6 +302,225 @@ function statusSubcommand(flags, cwd) {
|
|
|
301
302
|
printCompactRoadmapStatus(roadmap, currentSprint, completedSprints, cwd);
|
|
302
303
|
}
|
|
303
304
|
}
|
|
305
|
+
function displayPath(cwd, path) {
|
|
306
|
+
return relative(cwd, resolve(cwd, path)).replace(/\\/g, '/');
|
|
307
|
+
}
|
|
308
|
+
function focusEvidence(roadmap, sprintId, flags, cwd) {
|
|
309
|
+
const config = loadConfig(cwd);
|
|
310
|
+
const evidence = [{
|
|
311
|
+
kind: 'roadmap',
|
|
312
|
+
label: 'Roadmap source',
|
|
313
|
+
ref: displayPath(cwd, resolveRoadmapPath(flags, cwd)),
|
|
314
|
+
sprint: sprintId,
|
|
315
|
+
}];
|
|
316
|
+
const selected = roadmap.sprints.find(sprint => sprint.id === sprintId);
|
|
317
|
+
const phase = roadmap.phases.find(candidate => candidate.sprints.includes(sprintId));
|
|
318
|
+
const phaseIndex = phase?.sprints.indexOf(sprintId) ?? -1;
|
|
319
|
+
const contextIds = new Set([
|
|
320
|
+
sprintId,
|
|
321
|
+
...(selected?.depends_on ?? []),
|
|
322
|
+
...(phaseIndex < 0 ? [] : phase.sprints.slice(Math.max(0, phaseIndex - 2), phaseIndex)),
|
|
323
|
+
]);
|
|
324
|
+
const contextByValue = new Map([...contextIds].map(id => [roadmapSprintOrderValue(roadmap, id), id]));
|
|
325
|
+
for (const path of discoverScorecardFiles(config, cwd)) {
|
|
326
|
+
const scorecardSprint = sprintNumberFromScorecardFile(path, config);
|
|
327
|
+
if (scorecardSprint == null)
|
|
328
|
+
continue;
|
|
329
|
+
const roadmapSprintId = contextByValue.get(roadmapSprintOrderValue(roadmap, scorecardSprint));
|
|
330
|
+
if (roadmapSprintId == null)
|
|
331
|
+
continue;
|
|
332
|
+
evidence.push({
|
|
333
|
+
kind: 'scorecard',
|
|
334
|
+
label: `${formatRoadmapSprintLabel(roadmap, roadmapSprintId)} scorecard`,
|
|
335
|
+
ref: displayPath(cwd, path),
|
|
336
|
+
sprint: roadmapSprintId,
|
|
337
|
+
});
|
|
338
|
+
const reviewPath = [scorecardSprint, roadmapSprintId]
|
|
339
|
+
.map(id => join(dirname(path), `sprint-${id}-review.md`))
|
|
340
|
+
.find(candidate => existsSync(candidate));
|
|
341
|
+
if (reviewPath) {
|
|
342
|
+
evidence.push({
|
|
343
|
+
kind: 'review',
|
|
344
|
+
label: `${formatRoadmapSprintLabel(roadmap, roadmapSprintId)} review`,
|
|
345
|
+
ref: displayPath(cwd, reviewPath),
|
|
346
|
+
sprint: roadmapSprintId,
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return evidence;
|
|
351
|
+
}
|
|
352
|
+
function focusSubcommand(flags, cwd) {
|
|
353
|
+
if (!Object.prototype.hasOwnProperty.call(flags, 'sprint') || flags.sprint === 'true') {
|
|
354
|
+
console.error('\nMissing required --sprint=N for roadmap focus.');
|
|
355
|
+
console.error('Usage: slope roadmap focus --sprint=N [--path=<file>] [--json]\n');
|
|
356
|
+
process.exit(1);
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
const sprintId = parseSprintNumber(flags.sprint);
|
|
360
|
+
if (sprintId == null) {
|
|
361
|
+
console.error(`\nInvalid sprint number: ${flags.sprint || '(empty)'}`);
|
|
362
|
+
console.error('Usage: slope roadmap focus --sprint=N [--path=<file>] [--json]\n');
|
|
363
|
+
process.exit(1);
|
|
364
|
+
return;
|
|
365
|
+
}
|
|
366
|
+
const roadmap = loadRoadmapFile(flags, cwd);
|
|
367
|
+
if (!roadmap) {
|
|
368
|
+
process.exit(1);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
const config = loadConfig(cwd);
|
|
372
|
+
const scorecards = loadScorecards(config, cwd);
|
|
373
|
+
const completedSprintIds = scorecards.map(card => card.sprint_number);
|
|
374
|
+
const hazards = roadmapRealityIssues(buildRoadmapReality(cwd, roadmap), sprintId)
|
|
375
|
+
.map(issue => ({
|
|
376
|
+
sprint: sprintId,
|
|
377
|
+
sprint_label: formatRoadmapSprintLabel(roadmap, sprintId),
|
|
378
|
+
type: 'roadmap_reality',
|
|
379
|
+
severity: issue.type === 'error' ? 'major' : 'minor',
|
|
380
|
+
description: issue.message,
|
|
381
|
+
}));
|
|
382
|
+
const focus = buildRoadmapFocus(roadmap, sprintId, {
|
|
383
|
+
completedSprintIds,
|
|
384
|
+
hazards,
|
|
385
|
+
scorecards,
|
|
386
|
+
evidence: focusEvidence(roadmap, sprintId, flags, cwd),
|
|
387
|
+
});
|
|
388
|
+
if (!focus) {
|
|
389
|
+
console.error(`\nSprint ${formatRoadmapSprintLabel(roadmap, sprintId)} was not found in the roadmap.\n`);
|
|
390
|
+
process.exit(1);
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
393
|
+
if (flags.json === 'true') {
|
|
394
|
+
console.log(JSON.stringify(focus, null, 2));
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
console.log(formatRoadmapFocus(focus).trimEnd());
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
function compileSourcesSubcommand(flags, cwd) {
|
|
401
|
+
try {
|
|
402
|
+
const store = loadRoadmapSourceStore(cwd, flags.source);
|
|
403
|
+
const validation = validateRoadmapSourceStore(store, { checkProjection: false });
|
|
404
|
+
if (!validation.valid) {
|
|
405
|
+
throw new Error([
|
|
406
|
+
'Modular roadmap sources are invalid:',
|
|
407
|
+
...validation.errors.map(issue => ` - ${issue.source ? `${issue.source}: ` : ''}${issue.message}`),
|
|
408
|
+
'Run `slope roadmap validate-sources` for the full report.',
|
|
409
|
+
].join('\n'));
|
|
410
|
+
}
|
|
411
|
+
const existing = existsSync(store.outputPath) ? readFileSync(store.outputPath, 'utf8') : null;
|
|
412
|
+
const changed = existing !== store.projection;
|
|
413
|
+
const output = displayPath(cwd, store.outputPath);
|
|
414
|
+
if (flags.check === 'true') {
|
|
415
|
+
if (changed) {
|
|
416
|
+
throw new Error(`Roadmap projection drift: ${output}. Run \`slope roadmap compile\` to regenerate it from modular sources.`);
|
|
417
|
+
}
|
|
418
|
+
console.log(`\nRoadmap projection is current: ${output}\n`);
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
if (flags['dry-run'] === 'true') {
|
|
422
|
+
console.log(`\nRoadmap compile dry run: ${changed ? 'would write' : 'already current'} ${output}`);
|
|
423
|
+
console.log(` Sources: ${store.sources.length}; phases: ${store.roadmap.phases.length}; sprints: ${store.roadmap.sprints.length}\n`);
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
const result = writeRoadmapSourceProjection(store);
|
|
427
|
+
console.log(`\nRoadmap projection ${result}: ${output}`);
|
|
428
|
+
console.log(` Sources: ${store.sources.length}; phases: ${store.roadmap.phases.length}; sprints: ${store.roadmap.sprints.length}\n`);
|
|
429
|
+
}
|
|
430
|
+
catch (error) {
|
|
431
|
+
console.error(`\n${error.message}\n`);
|
|
432
|
+
process.exit(1);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
function validateSourcesSubcommand(flags, cwd) {
|
|
436
|
+
const explicitSource = Object.prototype.hasOwnProperty.call(flags, 'source');
|
|
437
|
+
let sourceExists;
|
|
438
|
+
try {
|
|
439
|
+
sourceExists = hasModularRoadmapSources(cwd, flags.source);
|
|
440
|
+
}
|
|
441
|
+
catch (error) {
|
|
442
|
+
console.error(`\n${error.message}\n`);
|
|
443
|
+
process.exit(1);
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
if (!sourceExists) {
|
|
447
|
+
if (explicitSource) {
|
|
448
|
+
console.error(`\nModular roadmap manifest not found: ${flags.source || '(empty)'}\n`);
|
|
449
|
+
process.exit(1);
|
|
450
|
+
return;
|
|
451
|
+
}
|
|
452
|
+
console.log('\nSingle-file roadmap mode; run `slope roadmap validate` for docs/backlog/roadmap.json.\n');
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
let store;
|
|
456
|
+
try {
|
|
457
|
+
store = loadRoadmapSourceStore(cwd, flags.source);
|
|
458
|
+
}
|
|
459
|
+
catch (error) {
|
|
460
|
+
console.error(`\n${error.message}\n`);
|
|
461
|
+
process.exit(1);
|
|
462
|
+
return;
|
|
463
|
+
}
|
|
464
|
+
const validation = validateRoadmapSourceStore(store);
|
|
465
|
+
console.log(`\nModular roadmap sources: ${displayPath(cwd, store.manifestPath)}`);
|
|
466
|
+
console.log('═'.repeat(40));
|
|
467
|
+
if (validation.valid) {
|
|
468
|
+
console.log('\n✓ Modular sources and compiled projection are valid');
|
|
469
|
+
}
|
|
470
|
+
else {
|
|
471
|
+
console.log(`\n✗ ${validation.errors.length} source error${validation.errors.length === 1 ? '' : 's'} found`);
|
|
472
|
+
}
|
|
473
|
+
for (const issue of validation.errors) {
|
|
474
|
+
console.log(` ✗ ${issue.source ? `[${issue.source}] ` : ''}${issue.message}`);
|
|
475
|
+
}
|
|
476
|
+
for (const issue of validation.warnings) {
|
|
477
|
+
console.log(` ⚠ ${issue.source ? `[${issue.source}] ` : ''}${issue.message}`);
|
|
478
|
+
}
|
|
479
|
+
console.log(`\n Sources: ${store.sources.length}; phases: ${store.roadmap.phases.length}; sprints: ${store.roadmap.sprints.length}\n`);
|
|
480
|
+
if (!validation.valid)
|
|
481
|
+
process.exit(1);
|
|
482
|
+
}
|
|
483
|
+
function archiveSourcesSubcommand(flags, cwd) {
|
|
484
|
+
if (!Object.prototype.hasOwnProperty.call(flags, 'through') || flags.through === 'true') {
|
|
485
|
+
console.error('\nMissing required --through=N for roadmap archive.');
|
|
486
|
+
console.error('Usage: slope roadmap archive --through=N [--source=<file>] [--dry-run]\n');
|
|
487
|
+
process.exit(1);
|
|
488
|
+
return;
|
|
489
|
+
}
|
|
490
|
+
const through = parseSprintNumber(flags.through);
|
|
491
|
+
if (through == null) {
|
|
492
|
+
console.error(`\nInvalid archive boundary: ${flags.through || '(empty)'}\n`);
|
|
493
|
+
process.exit(1);
|
|
494
|
+
return;
|
|
495
|
+
}
|
|
496
|
+
try {
|
|
497
|
+
const store = loadRoadmapSourceStore(cwd, flags.source);
|
|
498
|
+
const projectionBefore = existsSync(store.outputPath) ? readFileSync(store.outputPath, 'utf8') : null;
|
|
499
|
+
const plan = planRoadmapSourceArchive(store, through);
|
|
500
|
+
console.log(`\nRoadmap archive through Sprint ${through}:`);
|
|
501
|
+
if (plan.moves.length === 0) {
|
|
502
|
+
console.log(' No complete live phases are eligible.\n');
|
|
503
|
+
return;
|
|
504
|
+
}
|
|
505
|
+
for (const move of plan.moves)
|
|
506
|
+
console.log(` ${move.from} -> ${move.to}`);
|
|
507
|
+
if (flags['dry-run'] === 'true') {
|
|
508
|
+
console.log('\n --dry-run: source files, manifest, and projection are unchanged.\n');
|
|
509
|
+
return;
|
|
510
|
+
}
|
|
511
|
+
applyRoadmapSourceArchive(store, plan);
|
|
512
|
+
const reloaded = loadRoadmapSourceStore(cwd, flags.source);
|
|
513
|
+
const validation = validateRoadmapSourceStore(reloaded);
|
|
514
|
+
if (!validation.valid || readFileSync(reloaded.outputPath, 'utf8') !== projectionBefore) {
|
|
515
|
+
throw new Error('Archive verification failed: compiled projection changed or archived evidence is invalid.');
|
|
516
|
+
}
|
|
517
|
+
console.log(`\n Archived ${plan.moves.length} phase source${plan.moves.length === 1 ? '' : 's'}; compatibility projection unchanged.\n`);
|
|
518
|
+
}
|
|
519
|
+
catch (error) {
|
|
520
|
+
console.error(`\n${error.message}\n`);
|
|
521
|
+
process.exit(1);
|
|
522
|
+
}
|
|
523
|
+
}
|
|
304
524
|
function printFullRoadmapStatus(roadmap, currentSprint, completedSprints) {
|
|
305
525
|
console.log(`\n# Roadmap Status — ${roadmap.name}`);
|
|
306
526
|
console.log('\u2550'.repeat(40));
|
|
@@ -479,7 +699,35 @@ function mergeScorecardTickets(existingTickets, scorecardTickets) {
|
|
|
479
699
|
return existing ? { ...existing, ...ticket } : ticket;
|
|
480
700
|
});
|
|
481
701
|
}
|
|
702
|
+
function modularAuthorityBlocksProjectionMutation(flags, cwd, action) {
|
|
703
|
+
let defaultExists = false;
|
|
704
|
+
let explicitExists = false;
|
|
705
|
+
try {
|
|
706
|
+
defaultExists = hasModularRoadmapSources(cwd);
|
|
707
|
+
if (!defaultExists && Object.prototype.hasOwnProperty.call(flags, 'source')) {
|
|
708
|
+
explicitExists = hasModularRoadmapSources(cwd, flags.source);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
catch (error) {
|
|
712
|
+
console.error(`\n${error.message}\n`);
|
|
713
|
+
process.exit(1);
|
|
714
|
+
return true;
|
|
715
|
+
}
|
|
716
|
+
if (!defaultExists && Object.prototype.hasOwnProperty.call(flags, 'source') && !explicitExists) {
|
|
717
|
+
console.error(`\nModular roadmap manifest not found: ${flags.source || '(empty)'}\n`);
|
|
718
|
+
process.exit(1);
|
|
719
|
+
return true;
|
|
720
|
+
}
|
|
721
|
+
if (!defaultExists && !explicitExists)
|
|
722
|
+
return false;
|
|
723
|
+
console.error(`\nModular roadmap sources are authoritative; \`roadmap ${action}\` cannot edit the generated projection.`);
|
|
724
|
+
console.error('Update the source YAML and run `slope roadmap compile`.\n');
|
|
725
|
+
process.exit(1);
|
|
726
|
+
return true;
|
|
727
|
+
}
|
|
482
728
|
function syncSubcommand(flags, cwd) {
|
|
729
|
+
if (modularAuthorityBlocksProjectionMutation(flags, cwd, 'sync'))
|
|
730
|
+
return;
|
|
483
731
|
const dryRun = flags['dry-run'] === 'true';
|
|
484
732
|
const path = resolveRoadmapPath(flags, cwd);
|
|
485
733
|
const config = loadConfig(cwd);
|
|
@@ -546,6 +794,8 @@ function syncSubcommand(flags, cwd) {
|
|
|
546
794
|
console.log(`\n Written to ${path}\n`);
|
|
547
795
|
}
|
|
548
796
|
async function generateSubcommand(flags, cwd) {
|
|
797
|
+
if (modularAuthorityBlocksProjectionMutation(flags, cwd, 'generate'))
|
|
798
|
+
return;
|
|
549
799
|
const vision = loadVision(cwd);
|
|
550
800
|
if (!vision) {
|
|
551
801
|
console.error('\nNo vision found. Create one first:');
|
|
@@ -635,6 +885,18 @@ export async function roadmapCommand(args) {
|
|
|
635
885
|
case 'status':
|
|
636
886
|
statusSubcommand(flags, cwd);
|
|
637
887
|
break;
|
|
888
|
+
case 'focus':
|
|
889
|
+
focusSubcommand(flags, cwd);
|
|
890
|
+
break;
|
|
891
|
+
case 'compile':
|
|
892
|
+
compileSourcesSubcommand(flags, cwd);
|
|
893
|
+
break;
|
|
894
|
+
case 'validate-sources':
|
|
895
|
+
validateSourcesSubcommand(flags, cwd);
|
|
896
|
+
break;
|
|
897
|
+
case 'archive':
|
|
898
|
+
archiveSourcesSubcommand(flags, cwd);
|
|
899
|
+
break;
|
|
638
900
|
case 'show':
|
|
639
901
|
showSubcommand(flags, cwd);
|
|
640
902
|
break;
|
|
@@ -656,13 +918,20 @@ Usage:
|
|
|
656
918
|
slope roadmap validate [--path=<file>] Schema + dependency graph checks
|
|
657
919
|
slope roadmap review [--path=<file>] Automated architect review
|
|
658
920
|
slope roadmap status [--path=<file>] [--sprint=N] [--full] Compact current progress
|
|
921
|
+
slope roadmap focus --sprint=N [--path=<file>] [--json] Bounded sprint context
|
|
922
|
+
slope roadmap compile [--source=<file>] [--dry-run|--check] Compile modular YAML sources
|
|
923
|
+
slope roadmap validate-sources [--source=<file>] Validate sources and projection drift
|
|
924
|
+
slope roadmap archive --through=N [--source=<file>] [--dry-run] Archive whole terminal phases
|
|
659
925
|
slope roadmap show [--path=<file>] Render summary (critical path, parallel tracks)
|
|
660
926
|
slope roadmap sync [--path=<file>] [--dry-run] Sync scorecards into roadmap
|
|
661
927
|
slope roadmap generate [--path=<file>] [--dry-run] Generate from vision + concrete backlog signals
|
|
662
928
|
|
|
663
929
|
Options:
|
|
664
930
|
--path=<file> Path to roadmap JSON (default: docs/backlog/roadmap.json)
|
|
665
|
-
--sprint=N
|
|
931
|
+
--sprint=N Select a sprint (required for focus; override for status)
|
|
932
|
+
--json Emit machine-readable focus JSON
|
|
933
|
+
--source=<file> Modular roadmap manifest (default: docs/roadmap/project.yaml)
|
|
934
|
+
--check Fail when the compiled roadmap projection has drifted
|
|
666
935
|
--full Show full roadmap history for status
|
|
667
936
|
--dry-run Show what would change without writing (for sync and generate)
|
|
668
937
|
|