@slope-dev/slope 1.58.5 → 1.59.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 +18 -0
- package/dist/cli/commands/help.d.ts +3 -1
- package/dist/cli/commands/help.d.ts.map +1 -1
- package/dist/cli/commands/help.js +60 -12
- package/dist/cli/commands/help.js.map +1 -1
- package/dist/cli/commands/now.d.ts +30 -0
- package/dist/cli/commands/now.d.ts.map +1 -0
- package/dist/cli/commands/now.js +155 -0
- package/dist/cli/commands/now.js.map +1 -0
- package/dist/cli/commands/roadmap.d.ts.map +1 -1
- package/dist/cli/commands/roadmap.js +120 -1
- package/dist/cli/commands/roadmap.js.map +1 -1
- package/dist/cli/commands/start.d.ts +2 -0
- package/dist/cli/commands/start.d.ts.map +1 -0
- package/dist/cli/commands/start.js +57 -0
- package/dist/cli/commands/start.js.map +1 -0
- package/dist/cli/commands/status.d.ts +5 -0
- package/dist/cli/commands/status.d.ts.map +1 -1
- package/dist/cli/commands/status.js +21 -3
- package/dist/cli/commands/status.js.map +1 -1
- package/dist/cli/index.js +17 -126
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/registry.d.ts +3 -0
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/cli/registry.js +77 -59
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli/template-generator.d.ts.map +1 -1
- package/dist/cli/template-generator.js +36 -11
- package/dist/cli/template-generator.js.map +1 -1
- package/dist/core/analyzers/git.d.ts.map +1 -1
- package/dist/core/analyzers/git.js +10 -1
- package/dist/core/analyzers/git.js.map +1 -1
- package/package.json +1 -1
- package/templates/codex/plugins/slope/.codex-plugin/plugin.json +1 -1
package/README.md
CHANGED
|
@@ -261,6 +261,20 @@ execute({ code: 'return computeHandicapCard(loadScorecards())' })
|
|
|
261
261
|
|
|
262
262
|
All commands use `npx slope` when installed locally.
|
|
263
263
|
|
|
264
|
+
Default help is intentionally small:
|
|
265
|
+
|
|
266
|
+
| Command | Description |
|
|
267
|
+
|---------|-------------|
|
|
268
|
+
| `npx slope now` | Compact current-state cockpit: current sprint, state, claims, next action |
|
|
269
|
+
| `npx slope start [--ticket=KEY]` | Start or begin work without exposing sprint/claim plumbing |
|
|
270
|
+
| `npx slope help` | Human command surface for daily work, setup, and direction |
|
|
271
|
+
| `npx slope help <command>` | Detailed usage for one command |
|
|
272
|
+
| `npx slope help --all` | Full command registry with audience labels |
|
|
273
|
+
|
|
274
|
+
Commands are classified as `human`, `agent`, `advanced`, or `internal`.
|
|
275
|
+
Humans should usually start with the default help surface; skills and agents
|
|
276
|
+
orchestrate the rest of the CLI as execution primitives.
|
|
277
|
+
|
|
264
278
|
### Setup
|
|
265
279
|
|
|
266
280
|
| Command | Description |
|
|
@@ -285,9 +299,13 @@ All commands use `npx slope` when installed locally.
|
|
|
285
299
|
|
|
286
300
|
| Command | Description |
|
|
287
301
|
|---------|-------------|
|
|
302
|
+
| `npx slope now` | Compact current-state cockpit |
|
|
303
|
+
| `npx slope start [--ticket=KEY]` | Start sprint state or begin a ticket with briefing, claim, prep, and next gates |
|
|
288
304
|
| `npx slope briefing` | Pre-sprint hazard index, nutrition alerts, filtered gotchas |
|
|
289
305
|
| `npx slope plan --complexity=<level>` | Club recommendation + training plan |
|
|
290
306
|
| `npx slope next` | Show next sprint number |
|
|
307
|
+
| `npx slope roadmap status [--sprint=N]` | Compact current roadmap state: active work, blockers, next ready, upcoming |
|
|
308
|
+
| `npx slope roadmap status --full` | Full historical roadmap status |
|
|
291
309
|
| `npx slope roadmap validate` | Validate roadmap dependencies and sprint status |
|
|
292
310
|
|
|
293
311
|
### Review & Findings
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* slope help [command]
|
|
2
|
+
* slope help [command] - Show human help, full registry, or command details.
|
|
3
3
|
*/
|
|
4
4
|
export declare function helpCommand(args: string[]): Promise<void>;
|
|
5
|
+
export declare function printDefaultHelp(): void;
|
|
6
|
+
export declare function printAllCommandHelp(): void;
|
|
5
7
|
//# sourceMappingURL=help.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/help.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"help.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/help.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgC/D;AAuBD,wBAAgB,gBAAgB,IAAI,IAAI,CAiBvC;AAED,wBAAgB,mBAAmB,IAAI,IAAI,CAgC1C"}
|
|
@@ -1,21 +1,26 @@
|
|
|
1
1
|
import { CLI_COMMAND_REGISTRY, CLI_INTERNAL_MODULES } from '../registry.js';
|
|
2
2
|
/**
|
|
3
|
-
* slope help [command]
|
|
3
|
+
* slope help [command] - Show human help, full registry, or command details.
|
|
4
4
|
*/
|
|
5
5
|
export async function helpCommand(args) {
|
|
6
6
|
if (args.includes('--help') || args.includes('-h')) {
|
|
7
7
|
console.log(`
|
|
8
|
-
slope help
|
|
8
|
+
slope help - Command reference
|
|
9
9
|
|
|
10
10
|
Usage:
|
|
11
|
-
slope help Show
|
|
11
|
+
slope help Show the bounded human command surface
|
|
12
12
|
slope help <command> Show detailed usage for a command
|
|
13
|
+
slope help --all Show all commands grouped by category
|
|
13
14
|
`);
|
|
14
15
|
return;
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
+
if (args.includes('--all')) {
|
|
18
|
+
printAllCommandHelp();
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const commandName = args.find(arg => !arg.startsWith('-'));
|
|
17
22
|
if (!commandName) {
|
|
18
|
-
|
|
23
|
+
printDefaultHelp();
|
|
19
24
|
return;
|
|
20
25
|
}
|
|
21
26
|
const meta = CLI_COMMAND_REGISTRY.find(c => c.cmd === commandName);
|
|
@@ -25,7 +30,44 @@ Usage:
|
|
|
25
30
|
}
|
|
26
31
|
printCommandDetail(meta);
|
|
27
32
|
}
|
|
28
|
-
|
|
33
|
+
const HUMAN_HELP_ORDER = [
|
|
34
|
+
'now',
|
|
35
|
+
'start',
|
|
36
|
+
'briefing',
|
|
37
|
+
'review',
|
|
38
|
+
'doctor',
|
|
39
|
+
'card',
|
|
40
|
+
'status',
|
|
41
|
+
'roadmap',
|
|
42
|
+
'vision',
|
|
43
|
+
'quickstart',
|
|
44
|
+
'init',
|
|
45
|
+
];
|
|
46
|
+
const AUDIENCE_LABELS = {
|
|
47
|
+
human: 'human',
|
|
48
|
+
agent: 'agent',
|
|
49
|
+
advanced: 'advanced',
|
|
50
|
+
internal: 'internal',
|
|
51
|
+
};
|
|
52
|
+
export function printDefaultHelp() {
|
|
53
|
+
const byName = new Map(CLI_COMMAND_REGISTRY.map(cmd => [cmd.cmd, cmd]));
|
|
54
|
+
console.log('\nSLOPE - Human Command Surface\n');
|
|
55
|
+
console.log('Daily work:');
|
|
56
|
+
for (const name of HUMAN_HELP_ORDER.slice(0, 8)) {
|
|
57
|
+
const cmd = byName.get(name);
|
|
58
|
+
if (cmd)
|
|
59
|
+
printCommandRow(cmd, 4);
|
|
60
|
+
}
|
|
61
|
+
console.log('\nSetup and direction:');
|
|
62
|
+
for (const name of HUMAN_HELP_ORDER.slice(8)) {
|
|
63
|
+
const cmd = byName.get(name);
|
|
64
|
+
if (cmd)
|
|
65
|
+
printCommandRow(cmd, 4);
|
|
66
|
+
}
|
|
67
|
+
console.log('\nAgents and skills use the rest of the CLI as execution primitives.');
|
|
68
|
+
console.log('Run `slope help <command>` for details, or `slope help --all` for the full registry.\n');
|
|
69
|
+
}
|
|
70
|
+
export function printAllCommandHelp() {
|
|
29
71
|
const categories = {};
|
|
30
72
|
for (const cmd of CLI_COMMAND_REGISTRY) {
|
|
31
73
|
if (CLI_INTERNAL_MODULES.includes(cmd.cmd))
|
|
@@ -35,7 +77,7 @@ function printCategoryList() {
|
|
|
35
77
|
categories[cat] = [];
|
|
36
78
|
categories[cat].push(cmd);
|
|
37
79
|
}
|
|
38
|
-
console.log('\nSLOPE CLI
|
|
80
|
+
console.log('\nSLOPE CLI - Full Command Reference\n');
|
|
39
81
|
const categoryOrder = ['lifecycle', 'scoring', 'analysis', 'planning', 'tooling'];
|
|
40
82
|
const categoryLabels = {
|
|
41
83
|
lifecycle: 'Lifecycle',
|
|
@@ -50,17 +92,17 @@ function printCategoryList() {
|
|
|
50
92
|
continue;
|
|
51
93
|
console.log(` ${categoryLabels[cat]}:`);
|
|
52
94
|
for (const cmd of cmds) {
|
|
53
|
-
|
|
54
|
-
console.log(` ${name.padEnd(18)} ${cmd.desc}`);
|
|
95
|
+
printCommandRow(cmd, 4, true);
|
|
55
96
|
}
|
|
56
97
|
console.log('');
|
|
57
98
|
}
|
|
58
|
-
console.log('Run `slope help <command>` for detailed usage.\n');
|
|
99
|
+
console.log('Run `slope help` for the bounded human surface, or `slope help <command>` for detailed usage.\n');
|
|
59
100
|
}
|
|
60
101
|
function printCommandDetail(meta) {
|
|
61
102
|
const displayName = meta.cmd === 'index-cmd' ? 'index' : meta.cmd;
|
|
62
|
-
console.log(`\nslope ${displayName}
|
|
103
|
+
console.log(`\nslope ${displayName} - ${meta.desc}\n`);
|
|
63
104
|
console.log(` Category: ${meta.category}\n`);
|
|
105
|
+
console.log(` Audience: ${AUDIENCE_LABELS[meta.audience]}\n`);
|
|
64
106
|
if (meta.subcommands && meta.subcommands.length > 0) {
|
|
65
107
|
console.log(' Subcommands:\n');
|
|
66
108
|
for (const sub of meta.subcommands) {
|
|
@@ -82,6 +124,12 @@ function printCommandDetail(meta) {
|
|
|
82
124
|
console.log('');
|
|
83
125
|
}
|
|
84
126
|
}
|
|
127
|
+
function printCommandRow(cmd, indent, includeAudience = false) {
|
|
128
|
+
const name = cmd.cmd === 'index-cmd' ? 'index' : cmd.cmd;
|
|
129
|
+
const prefix = ' '.repeat(indent);
|
|
130
|
+
const audience = includeAudience ? ` [${AUDIENCE_LABELS[cmd.audience]}]` : '';
|
|
131
|
+
console.log(`${prefix}${name.padEnd(14)} ${cmd.desc}${audience}`);
|
|
132
|
+
}
|
|
85
133
|
function suggestClosest(input) {
|
|
86
134
|
const names = CLI_COMMAND_REGISTRY
|
|
87
135
|
.filter(c => !CLI_INTERNAL_MODULES.includes(c.cmd))
|
|
@@ -92,7 +140,7 @@ function suggestClosest(input) {
|
|
|
92
140
|
if (matches.length > 0) {
|
|
93
141
|
console.error(`Did you mean: ${matches.join(', ')}?`);
|
|
94
142
|
}
|
|
95
|
-
console.error(`\nRun \`slope help\`
|
|
143
|
+
console.error(`\nRun \`slope help\` for the human surface or \`slope help --all\` for all commands.`);
|
|
96
144
|
process.exit(1);
|
|
97
145
|
}
|
|
98
146
|
//# sourceMappingURL=help.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../../src/cli/commands/help.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,oBAAoB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAG5E;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAc;IAC9C,IAAI,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACnD,OAAO,CAAC,GAAG,CAAC
|
|
1
|
+
{"version":3,"file":"help.js","sourceRoot":"","sources":["../../../src/cli/commands/help.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import type { RoadmapTicket } from '../../core/index.js';
|
|
2
|
+
interface NowSnapshot {
|
|
3
|
+
sprint: number;
|
|
4
|
+
sprintLabel: string;
|
|
5
|
+
source: string;
|
|
6
|
+
roadmap?: {
|
|
7
|
+
name: string;
|
|
8
|
+
theme?: string;
|
|
9
|
+
phase?: string;
|
|
10
|
+
phaseProgress?: string;
|
|
11
|
+
status: string;
|
|
12
|
+
};
|
|
13
|
+
sprintState?: {
|
|
14
|
+
phase: string;
|
|
15
|
+
pendingGates: string[];
|
|
16
|
+
};
|
|
17
|
+
claims: {
|
|
18
|
+
total: number;
|
|
19
|
+
ticketClaims: number;
|
|
20
|
+
};
|
|
21
|
+
nextAction: string;
|
|
22
|
+
nextTicket?: RoadmapTicket;
|
|
23
|
+
}
|
|
24
|
+
declare function buildNowSnapshot(cwd: string, flags: Record<string, string>): Promise<NowSnapshot>;
|
|
25
|
+
export declare function nowCommand(args: string[]): Promise<void>;
|
|
26
|
+
export declare const testInternals: {
|
|
27
|
+
buildNowSnapshot: typeof buildNowSnapshot;
|
|
28
|
+
};
|
|
29
|
+
export {};
|
|
30
|
+
//# sourceMappingURL=now.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"now.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/now.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAoC,aAAa,EAAe,MAAM,qBAAqB,CAAC;AAMxG,UAAU,WAAW;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,WAAW,CAAC,EAAE;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,EAAE,CAAC;KACxB,CAAC;IACF,MAAM,EAAE;QACN,KAAK,EAAE,MAAM,CAAC;QACd,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;IACF,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,aAAa,CAAC;CAC5B;AAwDD,iBAAe,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,WAAW,CAAC,CAkDhG;AAgCD,wBAAsB,UAAU,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAa9D;AAED,eAAO,MAAM,aAAa;;CAEzB,CAAC"}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
import { formatSprintLabel, formatSprintNumber, isRoadmapSprintPending, loadScorecards, parseSprintNumber } from '../../core/index.js';
|
|
2
|
+
import { loadConfig } from '../config.js';
|
|
3
|
+
import { inferSprintContext, loadRoadmapForInference } from '../sprint-inference.js';
|
|
4
|
+
import { loadSprintState, pendingGates } from '../sprint-state.js';
|
|
5
|
+
import { resolveStore } from '../store.js';
|
|
6
|
+
function parseArgs(args) {
|
|
7
|
+
const result = {};
|
|
8
|
+
for (const arg of args) {
|
|
9
|
+
const match = arg.match(/^--(\w[\w-]*)(?:=(.+))?$/);
|
|
10
|
+
if (match)
|
|
11
|
+
result[match[1]] = match[2] ?? 'true';
|
|
12
|
+
}
|
|
13
|
+
return result;
|
|
14
|
+
}
|
|
15
|
+
function sprintStatus(sprint, completed, currentSprint) {
|
|
16
|
+
if (!sprint)
|
|
17
|
+
return 'not in roadmap';
|
|
18
|
+
const explicit = sprint.status;
|
|
19
|
+
if (explicit === 'superseded')
|
|
20
|
+
return 'superseded';
|
|
21
|
+
if (explicit === 'complete' || completed.has(sprint.id))
|
|
22
|
+
return 'complete';
|
|
23
|
+
if (sprint.id === currentSprint)
|
|
24
|
+
return 'active';
|
|
25
|
+
if (isRoadmapSprintPending(sprint))
|
|
26
|
+
return 'pending';
|
|
27
|
+
return explicit ?? 'unknown';
|
|
28
|
+
}
|
|
29
|
+
function isTerminal(sprint, completed) {
|
|
30
|
+
const explicit = sprint.status;
|
|
31
|
+
return explicit === 'complete' || explicit === 'superseded' || completed.has(sprint.id);
|
|
32
|
+
}
|
|
33
|
+
function formatPhaseProgress(roadmap, sprint, completed) {
|
|
34
|
+
const phase = roadmap.phases.find(p => p.sprints.includes(sprint));
|
|
35
|
+
if (!phase)
|
|
36
|
+
return undefined;
|
|
37
|
+
const phaseSprints = roadmap.sprints.filter(s => phase.sprints.includes(s.id));
|
|
38
|
+
const completedCount = phaseSprints.filter(s => isTerminal(s, completed)).length;
|
|
39
|
+
return {
|
|
40
|
+
name: phase.name,
|
|
41
|
+
progress: `${completedCount}/${phaseSprints.length}`,
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
function findNextTicket(sprint, claims) {
|
|
45
|
+
if (!sprint)
|
|
46
|
+
return undefined;
|
|
47
|
+
const claimedTargets = new Set(claims.map(c => c.target));
|
|
48
|
+
return sprint.tickets.find(ticket => !claimedTargets.has(ticket.key)) ?? sprint.tickets[0];
|
|
49
|
+
}
|
|
50
|
+
function buildNextAction(snapshot) {
|
|
51
|
+
if (!snapshot.roadmap) {
|
|
52
|
+
return 'Run slope init or slope roadmap status to establish project direction.';
|
|
53
|
+
}
|
|
54
|
+
if (snapshot.nextTicket) {
|
|
55
|
+
return `Start ${snapshot.nextTicket.key}: ${snapshot.nextTicket.title}`;
|
|
56
|
+
}
|
|
57
|
+
if (snapshot.sprintState && snapshot.sprintState.pendingGates.length > 0) {
|
|
58
|
+
return `Clear pending gates: ${snapshot.sprintState.pendingGates.join(', ')}`;
|
|
59
|
+
}
|
|
60
|
+
return `Review ${snapshot.sprintLabel} and prepare closeout.`;
|
|
61
|
+
}
|
|
62
|
+
async function buildNowSnapshot(cwd, flags) {
|
|
63
|
+
const config = loadConfig(cwd);
|
|
64
|
+
const inferred = inferSprintContext(cwd, config);
|
|
65
|
+
const parsedSprint = flags.sprint ? parseSprintNumber(flags.sprint) : inferred.sprint;
|
|
66
|
+
if (parsedSprint == null) {
|
|
67
|
+
throw new Error(`Invalid sprint number: ${flags.sprint}`);
|
|
68
|
+
}
|
|
69
|
+
const sprint = parsedSprint;
|
|
70
|
+
const sprintLabel = formatSprintLabel(sprint);
|
|
71
|
+
const roadmap = loadRoadmapForInference(cwd, config) ?? undefined;
|
|
72
|
+
const scorecards = loadScorecards(config, cwd);
|
|
73
|
+
const completed = new Set(scorecards.map(card => card.sprint_number));
|
|
74
|
+
const current = roadmap?.sprints.find(s => s.id === sprint);
|
|
75
|
+
const phase = roadmap ? formatPhaseProgress(roadmap, sprint, completed) : undefined;
|
|
76
|
+
const state = loadSprintState(cwd);
|
|
77
|
+
const store = await resolveStore(cwd);
|
|
78
|
+
let claims;
|
|
79
|
+
try {
|
|
80
|
+
claims = await store.list(sprint);
|
|
81
|
+
}
|
|
82
|
+
finally {
|
|
83
|
+
store.close();
|
|
84
|
+
}
|
|
85
|
+
const partial = {
|
|
86
|
+
sprint,
|
|
87
|
+
sprintLabel,
|
|
88
|
+
source: flags.sprint ? 'flag' : inferred.source,
|
|
89
|
+
roadmap: roadmap ? {
|
|
90
|
+
name: roadmap.name,
|
|
91
|
+
theme: current?.theme,
|
|
92
|
+
phase: phase?.name,
|
|
93
|
+
phaseProgress: phase?.progress,
|
|
94
|
+
status: sprintStatus(current, completed, sprint),
|
|
95
|
+
} : undefined,
|
|
96
|
+
sprintState: state?.sprint === sprint ? {
|
|
97
|
+
phase: state.phase,
|
|
98
|
+
pendingGates: pendingGates(state),
|
|
99
|
+
} : undefined,
|
|
100
|
+
claims: {
|
|
101
|
+
total: claims.length,
|
|
102
|
+
ticketClaims: claims.filter(c => c.scope === 'ticket').length,
|
|
103
|
+
},
|
|
104
|
+
nextTicket: findNextTicket(current, claims),
|
|
105
|
+
};
|
|
106
|
+
return {
|
|
107
|
+
...partial,
|
|
108
|
+
nextAction: buildNextAction(partial),
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
function printNowSnapshot(snapshot) {
|
|
112
|
+
console.log('\nSLOPE Now');
|
|
113
|
+
console.log('='.repeat(32));
|
|
114
|
+
const theme = snapshot.roadmap?.theme ? ` - ${snapshot.roadmap.theme}` : '';
|
|
115
|
+
console.log(`Current: ${snapshot.sprintLabel}${theme}`);
|
|
116
|
+
if (snapshot.roadmap?.phase) {
|
|
117
|
+
const progress = snapshot.roadmap.phaseProgress ? ` (${snapshot.roadmap.phaseProgress})` : '';
|
|
118
|
+
console.log(`Phase: ${snapshot.roadmap.phase}${progress}`);
|
|
119
|
+
}
|
|
120
|
+
console.log(`Roadmap: ${snapshot.roadmap?.status ?? 'not found'} (${snapshot.source})`);
|
|
121
|
+
console.log(`Sprint state: ${snapshot.sprintState?.phase ?? 'not started'}`);
|
|
122
|
+
console.log(`Claims: ${snapshot.claims.total} active, ${snapshot.claims.ticketClaims} ticket`);
|
|
123
|
+
console.log(`Next: ${snapshot.nextAction}`);
|
|
124
|
+
if (snapshot.nextTicket) {
|
|
125
|
+
console.log(`Start: slope start --ticket=${snapshot.nextTicket.key}`);
|
|
126
|
+
}
|
|
127
|
+
console.log(`More: slope roadmap status --sprint=${formatSprintNumber(snapshot.sprint)}\n`);
|
|
128
|
+
}
|
|
129
|
+
function printUsage() {
|
|
130
|
+
console.log(`
|
|
131
|
+
slope now - Compact current-state cockpit
|
|
132
|
+
|
|
133
|
+
Usage:
|
|
134
|
+
slope now [--sprint=N] [--json]
|
|
135
|
+
|
|
136
|
+
Shows the current sprint, phase, sprint state, claim count, and next human action.
|
|
137
|
+
`);
|
|
138
|
+
}
|
|
139
|
+
export async function nowCommand(args) {
|
|
140
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
141
|
+
printUsage();
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
const flags = parseArgs(args);
|
|
145
|
+
const snapshot = await buildNowSnapshot(process.cwd(), flags);
|
|
146
|
+
if (flags.json === 'true') {
|
|
147
|
+
console.log(JSON.stringify(snapshot, null, 2));
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
printNowSnapshot(snapshot);
|
|
151
|
+
}
|
|
152
|
+
export const testInternals = {
|
|
153
|
+
buildNowSnapshot,
|
|
154
|
+
};
|
|
155
|
+
//# sourceMappingURL=now.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"now.js","sourceRoot":"","sources":["../../../src/cli/commands/now.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":"AAmsBA,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgDlE"}
|
|
@@ -15,12 +15,46 @@ function parseArgs(args) {
|
|
|
15
15
|
}
|
|
16
16
|
const DEFAULT_ROADMAP_PATH = 'docs/backlog/roadmap.json';
|
|
17
17
|
const TERMINAL_ROADMAP_STATUSES = new Set(['complete', 'superseded']);
|
|
18
|
+
const DEFAULT_UPCOMING_LIMIT = 3;
|
|
18
19
|
function getRoadmapStatus(sprint) {
|
|
19
20
|
return sprint.status;
|
|
20
21
|
}
|
|
21
22
|
function isTerminalRoadmapSprint(sprint, completedSprints) {
|
|
22
23
|
return completedSprints.has(sprint.id) || TERMINAL_ROADMAP_STATUSES.has(getRoadmapStatus(sprint) ?? '');
|
|
23
24
|
}
|
|
25
|
+
function blockedByForSprint(roadmap, sprint, completedSprints) {
|
|
26
|
+
return (sprint.depends_on ?? []).filter(dep => {
|
|
27
|
+
const dependency = roadmap.sprints.find(s => s.id === dep);
|
|
28
|
+
return dependency ? !isTerminalRoadmapSprint(dependency, completedSprints) : !completedSprints.has(dep);
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
function statusLabelForSprint(roadmap, sprint, currentSprint, completedSprints) {
|
|
32
|
+
const explicitStatus = getRoadmapStatus(sprint);
|
|
33
|
+
const isCompleted = completedSprints.has(sprint.id) || explicitStatus === 'complete';
|
|
34
|
+
const isSuperseded = explicitStatus === 'superseded';
|
|
35
|
+
const isCurrent = sprint.id === currentSprint;
|
|
36
|
+
const blockedBy = blockedByForSprint(roadmap, sprint, completedSprints);
|
|
37
|
+
if (isSuperseded)
|
|
38
|
+
return '\u21B7 superseded';
|
|
39
|
+
if (isCompleted)
|
|
40
|
+
return '\u2713 completed';
|
|
41
|
+
if (isCurrent)
|
|
42
|
+
return '\u25B6 active';
|
|
43
|
+
if (blockedBy.length > 0)
|
|
44
|
+
return `\u2718 blocked by ${blockedBy.map(formatSprintLabel).join(', ')}`;
|
|
45
|
+
return '\u25CB pending';
|
|
46
|
+
}
|
|
47
|
+
function phaseForSprint(roadmap, sprintId) {
|
|
48
|
+
return roadmap.phases.find(phase => phase.sprints?.includes(sprintId));
|
|
49
|
+
}
|
|
50
|
+
function formatPhaseProgress(roadmap, phase, completedSprints) {
|
|
51
|
+
const phaseSprints = roadmap.sprints.filter(s => phase.sprints.includes(s.id));
|
|
52
|
+
const completed = phaseSprints.filter(s => isTerminalRoadmapSprint(s, completedSprints)).length;
|
|
53
|
+
return `${phase.name || 'Unnamed Phase'} (${completed}/${phaseSprints.length})`;
|
|
54
|
+
}
|
|
55
|
+
function sortedRoadmapSprints(roadmap) {
|
|
56
|
+
return [...roadmap.sprints].sort((a, b) => compareSprintIds(a.id, b.id));
|
|
57
|
+
}
|
|
24
58
|
function resolveRoadmapPath(flags, cwd) {
|
|
25
59
|
if (flags.path)
|
|
26
60
|
return flags.path;
|
|
@@ -259,6 +293,14 @@ function statusSubcommand(flags, cwd) {
|
|
|
259
293
|
const scorecards = loadScorecards(config, cwd);
|
|
260
294
|
const currentSprint = resolveSprint(flags, cwd, roadmap, scorecards);
|
|
261
295
|
const completedSprints = new Set(scorecards.map(s => s.sprint_number));
|
|
296
|
+
if (flags.full === 'true' || flags.history === 'true') {
|
|
297
|
+
printFullRoadmapStatus(roadmap, currentSprint, completedSprints);
|
|
298
|
+
}
|
|
299
|
+
else {
|
|
300
|
+
printCompactRoadmapStatus(roadmap, currentSprint, completedSprints, cwd);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
function printFullRoadmapStatus(roadmap, currentSprint, completedSprints) {
|
|
262
304
|
console.log(`\n# Roadmap Status — ${roadmap.name}`);
|
|
263
305
|
console.log('\u2550'.repeat(40));
|
|
264
306
|
console.log(`\nCurrent sprint: ${formatSprintLabel(currentSprint)}`);
|
|
@@ -313,6 +355,82 @@ function statusSubcommand(flags, cwd) {
|
|
|
313
355
|
console.log('');
|
|
314
356
|
}
|
|
315
357
|
}
|
|
358
|
+
function printCompactRoadmapStatus(roadmap, currentSprint, completedSprints, cwd) {
|
|
359
|
+
const current = roadmap.sprints.find(s => s.id === currentSprint);
|
|
360
|
+
const currentLabel = current
|
|
361
|
+
? `${formatSprintLabel(current.id)} ${current.theme || 'Untitled Sprint'}`
|
|
362
|
+
: `${formatSprintLabel(currentSprint)} (not found in roadmap)`;
|
|
363
|
+
const currentIsPending = current ? isRoadmapSprintPending(current) : false;
|
|
364
|
+
const currentPhase = phaseForSprint(roadmap, currentSprint);
|
|
365
|
+
const pendingAfterCurrent = sortedRoadmapSprints(roadmap)
|
|
366
|
+
.filter(s => isRoadmapSprintPending(s) && s.id !== currentSprint && compareSprintIds(s.id, currentSprint) > 0);
|
|
367
|
+
const nextReady = pendingAfterCurrent.find(s => blockedByForSprint(roadmap, s, completedSprints).length === 0);
|
|
368
|
+
const upcoming = pendingAfterCurrent.slice(0, DEFAULT_UPCOMING_LIMIT);
|
|
369
|
+
const realityLines = formatRoadmapRealitySection(buildRoadmapReality(cwd, roadmap), undefined, 5).slice(1);
|
|
370
|
+
console.log(`\n# Roadmap Status - ${roadmap.name}`);
|
|
371
|
+
console.log('\u2550'.repeat(40));
|
|
372
|
+
console.log(`\nCurrent: ${currentLabel}`);
|
|
373
|
+
if (currentPhase)
|
|
374
|
+
console.log(`Phase: ${formatPhaseProgress(roadmap, currentPhase, completedSprints)}`);
|
|
375
|
+
console.log('\nReality checks:');
|
|
376
|
+
if (realityLines.length === 0) {
|
|
377
|
+
console.log(' None');
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
for (const line of realityLines)
|
|
381
|
+
console.log(` ${line.trim()}`);
|
|
382
|
+
}
|
|
383
|
+
console.log('\nActive sprint:');
|
|
384
|
+
if (!current) {
|
|
385
|
+
console.log(` ${formatSprintLabel(currentSprint)} is not defined in the roadmap.`);
|
|
386
|
+
}
|
|
387
|
+
else {
|
|
388
|
+
console.log(` ${formatSprintLabel(current.id)} ${current.theme || 'Untitled Sprint'} - ${statusLabelForSprint(roadmap, current, currentSprint, completedSprints)}`);
|
|
389
|
+
if ((current.depends_on ?? []).length > 0) {
|
|
390
|
+
const deps = current.depends_on.map(dep => {
|
|
391
|
+
const sprint = roadmap.sprints.find(s => s.id === dep);
|
|
392
|
+
if (!sprint)
|
|
393
|
+
return `${formatSprintLabel(dep)} missing`;
|
|
394
|
+
return `${formatSprintLabel(dep)} ${statusLabelForSprint(roadmap, sprint, currentSprint, completedSprints).replace(/^[^\w]+ /, '')}`;
|
|
395
|
+
});
|
|
396
|
+
console.log(` Dependencies: ${deps.join(', ')}`);
|
|
397
|
+
}
|
|
398
|
+
for (const ticket of current.tickets ?? []) {
|
|
399
|
+
console.log(` - ${ticket.key}: ${ticket.title}`);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
console.log('\nNext ready:');
|
|
403
|
+
if (nextReady) {
|
|
404
|
+
console.log(` ${formatSprintLabel(nextReady.id)} ${nextReady.theme || 'Untitled Sprint'} - ${statusLabelForSprint(roadmap, nextReady, currentSprint, completedSprints)}`);
|
|
405
|
+
}
|
|
406
|
+
else {
|
|
407
|
+
console.log(' None yet');
|
|
408
|
+
}
|
|
409
|
+
console.log(`\nUpcoming (${upcoming.length}/${Math.min(DEFAULT_UPCOMING_LIMIT, pendingAfterCurrent.length)}):`);
|
|
410
|
+
if (upcoming.length === 0) {
|
|
411
|
+
console.log(' None');
|
|
412
|
+
}
|
|
413
|
+
else {
|
|
414
|
+
for (const sprint of upcoming) {
|
|
415
|
+
console.log(` ${formatSprintLabel(sprint.id)} ${sprint.theme || 'Untitled Sprint'} - ${statusLabelForSprint(roadmap, sprint, currentSprint, completedSprints)}`);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
console.log('\nRecommended next action:');
|
|
419
|
+
if (realityLines.some(line => line.includes('[error]'))) {
|
|
420
|
+
console.log(' Resolve the first roadmap reality error before advancing the lane.');
|
|
421
|
+
}
|
|
422
|
+
else if (currentIsPending && current?.tickets?.length) {
|
|
423
|
+
const first = current.tickets[0];
|
|
424
|
+
console.log(` Work ${first.key}: ${first.title}`);
|
|
425
|
+
}
|
|
426
|
+
else if (nextReady) {
|
|
427
|
+
console.log(` Start ${formatSprintLabel(nextReady.id)}: ${nextReady.theme || 'Untitled Sprint'}`);
|
|
428
|
+
}
|
|
429
|
+
else {
|
|
430
|
+
console.log(' No roadmap action is currently ready.');
|
|
431
|
+
}
|
|
432
|
+
console.log('\nFor the full roadmap history, run: slope roadmap status --full\n');
|
|
433
|
+
}
|
|
316
434
|
function showSubcommand(flags, cwd) {
|
|
317
435
|
const roadmap = loadRoadmapFile(flags, cwd);
|
|
318
436
|
if (!roadmap) {
|
|
@@ -521,7 +639,7 @@ slope roadmap — Strategic planning tools
|
|
|
521
639
|
Usage:
|
|
522
640
|
slope roadmap validate [--path=<file>] Schema + dependency graph checks
|
|
523
641
|
slope roadmap review [--path=<file>] Automated architect review
|
|
524
|
-
slope roadmap status [--path=<file>] [--sprint=N]
|
|
642
|
+
slope roadmap status [--path=<file>] [--sprint=N] [--full] Compact current progress
|
|
525
643
|
slope roadmap show [--path=<file>] Render summary (critical path, parallel tracks)
|
|
526
644
|
slope roadmap sync [--path=<file>] [--dry-run] Sync scorecards into roadmap
|
|
527
645
|
slope roadmap generate [--path=<file>] [--dry-run] Generate from vision + concrete backlog signals
|
|
@@ -529,6 +647,7 @@ Usage:
|
|
|
529
647
|
Options:
|
|
530
648
|
--path=<file> Path to roadmap JSON (default: docs/backlog/roadmap.json)
|
|
531
649
|
--sprint=N Override current sprint number (for status)
|
|
650
|
+
--full Show full roadmap history for status
|
|
532
651
|
--dry-run Show what would change without writing (for sync and generate)
|
|
533
652
|
|
|
534
653
|
Generate requires concrete backlog signals from source TODO/FIXME/HACK comments
|