@slope-dev/slope 1.13.1 → 1.15.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 +118 -189
- package/dist/adapters.d.ts +3 -0
- package/dist/adapters.d.ts.map +1 -1
- package/dist/adapters.js +2 -0
- package/dist/adapters.js.map +1 -1
- package/dist/cli/commands/context.d.ts +2 -0
- package/dist/cli/commands/context.d.ts.map +1 -0
- package/dist/cli/commands/context.js +190 -0
- package/dist/cli/commands/context.js.map +1 -0
- package/dist/cli/commands/distill.d.ts.map +1 -1
- package/dist/cli/commands/distill.js +13 -4
- package/dist/cli/commands/distill.js.map +1 -1
- package/dist/cli/commands/enrich.d.ts +2 -0
- package/dist/cli/commands/enrich.d.ts.map +1 -0
- package/dist/cli/commands/enrich.js +140 -0
- package/dist/cli/commands/enrich.js.map +1 -0
- package/dist/cli/commands/guard.d.ts +19 -0
- package/dist/cli/commands/guard.d.ts.map +1 -1
- package/dist/cli/commands/guard.js +87 -1
- package/dist/cli/commands/guard.js.map +1 -1
- package/dist/cli/commands/hook.d.ts +1 -0
- package/dist/cli/commands/hook.d.ts.map +1 -1
- package/dist/cli/commands/hook.js +2 -0
- package/dist/cli/commands/hook.js.map +1 -1
- package/dist/cli/commands/index-cmd.d.ts +2 -0
- package/dist/cli/commands/index-cmd.d.ts.map +1 -0
- package/dist/cli/commands/index-cmd.js +296 -0
- package/dist/cli/commands/index-cmd.js.map +1 -0
- package/dist/cli/commands/init.d.ts +4 -2
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +204 -145
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/initiative.d.ts +2 -0
- package/dist/cli/commands/initiative.d.ts.map +1 -0
- package/dist/cli/commands/initiative.js +207 -0
- package/dist/cli/commands/initiative.js.map +1 -0
- package/dist/cli/commands/metaphor.d.ts +3 -0
- package/dist/cli/commands/metaphor.d.ts.map +1 -0
- package/dist/cli/commands/metaphor.js +100 -0
- package/dist/cli/commands/metaphor.js.map +1 -0
- package/dist/cli/commands/prep.d.ts +2 -0
- package/dist/cli/commands/prep.d.ts.map +1 -0
- package/dist/cli/commands/prep.js +94 -0
- package/dist/cli/commands/prep.js.map +1 -0
- package/dist/cli/commands/roadmap.d.ts.map +1 -1
- package/dist/cli/commands/roadmap.js +83 -44
- package/dist/cli/commands/roadmap.js.map +1 -1
- package/dist/cli/commands/store.d.ts +2 -0
- package/dist/cli/commands/store.d.ts.map +1 -0
- package/dist/cli/commands/store.js +270 -0
- package/dist/cli/commands/store.js.map +1 -0
- package/dist/cli/guards/stop-check.d.ts +1 -1
- package/dist/cli/guards/stop-check.d.ts.map +1 -1
- package/dist/cli/guards/stop-check.js +14 -2
- package/dist/cli/guards/stop-check.js.map +1 -1
- package/dist/cli/index.js +60 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/interactive-init.d.ts +19 -0
- package/dist/cli/interactive-init.d.ts.map +1 -0
- package/dist/cli/interactive-init.js +132 -0
- package/dist/cli/interactive-init.js.map +1 -0
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/cli/registry.js +8 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli/store.d.ts +9 -0
- package/dist/cli/store.d.ts.map +1 -1
- package/dist/cli/store.js +29 -0
- package/dist/cli/store.js.map +1 -1
- package/dist/cli/template-generator.d.ts +1 -1
- package/dist/cli/template-generator.d.ts.map +1 -1
- package/dist/cli/template-generator.js +5 -3
- package/dist/cli/template-generator.js.map +1 -1
- package/dist/core/adapters/claude-code.d.ts +3 -0
- package/dist/core/adapters/claude-code.d.ts.map +1 -1
- package/dist/core/adapters/claude-code.js +17 -2
- package/dist/core/adapters/claude-code.js.map +1 -1
- package/dist/core/adapters/cline.d.ts +36 -0
- package/dist/core/adapters/cline.d.ts.map +1 -0
- package/dist/core/adapters/cline.js +279 -0
- package/dist/core/adapters/cline.js.map +1 -0
- package/dist/core/adapters/cursor.d.ts +3 -0
- package/dist/core/adapters/cursor.d.ts.map +1 -1
- package/dist/core/adapters/cursor.js +5 -0
- package/dist/core/adapters/cursor.js.map +1 -1
- package/dist/core/adapters/generic.d.ts +3 -0
- package/dist/core/adapters/generic.d.ts.map +1 -1
- package/dist/core/adapters/generic.js +5 -0
- package/dist/core/adapters/generic.js.map +1 -1
- package/dist/core/adapters/windsurf.d.ts +3 -0
- package/dist/core/adapters/windsurf.d.ts.map +1 -1
- package/dist/core/adapters/windsurf.js +5 -0
- package/dist/core/adapters/windsurf.js.map +1 -1
- package/dist/core/config.d.ts +8 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js +9 -0
- package/dist/core/config.js.map +1 -1
- package/dist/core/context.d.ts +20 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +59 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/embedding-client.d.ts +11 -0
- package/dist/core/embedding-client.d.ts.map +1 -0
- package/dist/core/embedding-client.js +92 -0
- package/dist/core/embedding-client.js.map +1 -0
- package/dist/core/embedding-store.d.ts +44 -0
- package/dist/core/embedding-store.d.ts.map +1 -0
- package/dist/core/embedding-store.js +7 -0
- package/dist/core/embedding-store.js.map +1 -0
- package/dist/core/embedding.d.ts +32 -0
- package/dist/core/embedding.d.ts.map +1 -0
- package/dist/core/embedding.js +114 -0
- package/dist/core/embedding.js.map +1 -0
- package/dist/core/enrich.d.ts +76 -0
- package/dist/core/enrich.d.ts.map +1 -0
- package/dist/core/enrich.js +115 -0
- package/dist/core/enrich.js.map +1 -0
- package/dist/core/harness.d.ts +6 -0
- package/dist/core/harness.d.ts.map +1 -1
- package/dist/core/harness.js +1 -1
- package/dist/core/harness.js.map +1 -1
- package/dist/core/index.d.ts +30 -8
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +26 -5
- package/dist/core/index.js.map +1 -1
- package/dist/core/initiative.d.ts +72 -0
- package/dist/core/initiative.d.ts.map +1 -0
- package/dist/core/initiative.js +421 -0
- package/dist/core/initiative.js.map +1 -0
- package/dist/core/interview-engine.d.ts +34 -0
- package/dist/core/interview-engine.d.ts.map +1 -0
- package/dist/core/interview-engine.js +195 -0
- package/dist/core/interview-engine.js.map +1 -0
- package/dist/core/interview-steps.d.ts +27 -0
- package/dist/core/interview-steps.d.ts.map +1 -0
- package/dist/core/interview-steps.js +157 -0
- package/dist/core/interview-steps.js.map +1 -0
- package/dist/core/interview.d.ts +20 -0
- package/dist/core/interview.d.ts.map +1 -1
- package/dist/core/interview.js +62 -35
- package/dist/core/interview.js.map +1 -1
- package/dist/core/metaphor-preview.d.ts +34 -0
- package/dist/core/metaphor-preview.d.ts.map +1 -0
- package/dist/core/metaphor-preview.js +94 -0
- package/dist/core/metaphor-preview.js.map +1 -0
- package/dist/core/metaphor.d.ts +14 -0
- package/dist/core/metaphor.d.ts.map +1 -1
- package/dist/core/metaphor.js +14 -0
- package/dist/core/metaphor.js.map +1 -1
- package/dist/core/plugins.d.ts +12 -0
- package/dist/core/plugins.d.ts.map +1 -1
- package/dist/core/plugins.js +58 -1
- package/dist/core/plugins.js.map +1 -1
- package/dist/core/prep.d.ts +88 -0
- package/dist/core/prep.d.ts.map +1 -0
- package/dist/core/prep.js +302 -0
- package/dist/core/prep.js.map +1 -0
- package/dist/core/roadmap.d.ts.map +1 -1
- package/dist/core/roadmap.js +5 -4
- package/dist/core/roadmap.js.map +1 -1
- package/dist/core/roles.d.ts +3 -0
- package/dist/core/roles.d.ts.map +1 -1
- package/dist/core/roles.js +36 -0
- package/dist/core/roles.js.map +1 -1
- package/dist/core/store-health.d.ts +11 -0
- package/dist/core/store-health.d.ts.map +1 -0
- package/dist/core/store-health.js +26 -0
- package/dist/core/store-health.js.map +1 -0
- package/dist/core/store.d.ts +11 -1
- package/dist/core/store.d.ts.map +1 -1
- package/dist/core/store.js.map +1 -1
- package/dist/mcp/index.d.ts +2 -2
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +103 -6
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/index.test.js +7 -4
- package/dist/mcp/index.test.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 +47 -3
- package/dist/mcp/registry.js.map +1 -1
- package/dist/mcp/sandbox.d.ts.map +1 -1
- package/dist/mcp/sandbox.js +18 -1
- package/dist/mcp/sandbox.js.map +1 -1
- package/dist/store/index.d.ts +34 -3
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +220 -4
- package/dist/store/index.js.map +1 -1
- package/dist/store-pg/index.d.ts +3 -0
- package/dist/store-pg/index.d.ts.map +1 -1
- package/dist/store-pg/index.js +74 -1
- package/dist/store-pg/index.js.map +1 -1
- package/package.json +14 -7
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { loadInitiative, createInitiative, advanceSprint, recordReview, getNextSprint, getReviewChecklist, formatInitiativeStatus, } from '../../core/initiative.js';
|
|
2
|
+
// --- Helpers ---
|
|
3
|
+
function parseArgs(args) {
|
|
4
|
+
const result = {};
|
|
5
|
+
for (const arg of args) {
|
|
6
|
+
const match = arg.match(/^--(\w[\w-]*)(?:=(.+))?$/);
|
|
7
|
+
if (match)
|
|
8
|
+
result[match[1]] = match[2] ?? 'true';
|
|
9
|
+
}
|
|
10
|
+
return result;
|
|
11
|
+
}
|
|
12
|
+
// --- Subcommands ---
|
|
13
|
+
function createSubcommand(flags, cwd) {
|
|
14
|
+
const name = flags.name;
|
|
15
|
+
const roadmap = flags.roadmap;
|
|
16
|
+
if (!name || !roadmap) {
|
|
17
|
+
console.error('\nUsage: slope initiative create --name="..." --roadmap=<path>\n');
|
|
18
|
+
process.exit(1);
|
|
19
|
+
}
|
|
20
|
+
const description = flags.description ?? '';
|
|
21
|
+
try {
|
|
22
|
+
const initiative = createInitiative(name, description, roadmap, cwd);
|
|
23
|
+
console.log(`\n\u2713 Initiative created: ${initiative.name}`);
|
|
24
|
+
console.log(` Sprints: ${initiative.sprints.length}`);
|
|
25
|
+
console.log(` Plan gate: ${initiative.review_gates.plan.required.join(', ')} + ${initiative.review_gates.plan.specialists === 'auto' ? 'auto specialists' : initiative.review_gates.plan.specialists.join(', ')}`);
|
|
26
|
+
console.log(` PR gate: ${initiative.review_gates.pr.required.join(', ')}`);
|
|
27
|
+
console.log('');
|
|
28
|
+
}
|
|
29
|
+
catch (err) {
|
|
30
|
+
console.error(`\n\u2717 ${err.message}\n`);
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function loadOrExit(cwd) {
|
|
35
|
+
const initiative = loadInitiative(cwd);
|
|
36
|
+
if (!initiative) {
|
|
37
|
+
console.error('\nNo initiative found. Run "slope initiative create" first.\n');
|
|
38
|
+
process.exit(1);
|
|
39
|
+
}
|
|
40
|
+
return initiative;
|
|
41
|
+
}
|
|
42
|
+
function statusSubcommand(cwd) {
|
|
43
|
+
const initiative = loadOrExit(cwd);
|
|
44
|
+
console.log(formatInitiativeStatus(initiative));
|
|
45
|
+
}
|
|
46
|
+
function nextSubcommand(cwd) {
|
|
47
|
+
const initiative = loadOrExit(cwd);
|
|
48
|
+
const next = getNextSprint(initiative);
|
|
49
|
+
if (!next) {
|
|
50
|
+
console.log('\n\u2713 All sprints complete!\n');
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
console.log(`\n# Next: Sprint ${next.sprint_number}`);
|
|
54
|
+
console.log(` Phase: ${next.phase}`);
|
|
55
|
+
// Show required reviews for current gate
|
|
56
|
+
if (next.phase === 'plan_review') {
|
|
57
|
+
console.log('\n Plan reviews required:');
|
|
58
|
+
for (const r of next.plan_reviews) {
|
|
59
|
+
console.log(` ${r.completed ? '\u2713' : '\u2717'} ${r.reviewer} (${r.reviewer_mode})`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
else if (next.phase === 'pr_review') {
|
|
63
|
+
console.log('\n PR reviews required:');
|
|
64
|
+
for (const r of next.pr_reviews) {
|
|
65
|
+
console.log(` ${r.completed ? '\u2713' : '\u2717'} ${r.reviewer} (${r.reviewer_mode})`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
// Show selected specialists if plan_review pending
|
|
69
|
+
if (next.phase === 'pending' || next.phase === 'planning') {
|
|
70
|
+
if (initiative.review_gates.plan.specialists === 'auto') {
|
|
71
|
+
console.log('\n Specialists: auto-selected at plan_review phase');
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
console.log(`\n Specialists: ${initiative.review_gates.plan.specialists.join(', ')}`);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
console.log('');
|
|
78
|
+
}
|
|
79
|
+
function advanceSubcommand(flags, cwd) {
|
|
80
|
+
const sprintStr = flags.sprint;
|
|
81
|
+
if (!sprintStr) {
|
|
82
|
+
console.error('\nUsage: slope initiative advance --sprint=N\n');
|
|
83
|
+
process.exit(1);
|
|
84
|
+
}
|
|
85
|
+
const sprintNumber = parseInt(sprintStr, 10);
|
|
86
|
+
if (isNaN(sprintNumber)) {
|
|
87
|
+
console.error(`\n\u2717 Invalid sprint number: ${sprintStr}\n`);
|
|
88
|
+
process.exit(1);
|
|
89
|
+
}
|
|
90
|
+
try {
|
|
91
|
+
const result = advanceSprint(cwd, sprintNumber);
|
|
92
|
+
console.log(`\n\u2713 Sprint ${sprintNumber}: ${result.previous} \u2192 ${result.phase}\n`);
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
console.error(`\n\u2717 ${err.message}\n`);
|
|
96
|
+
process.exit(1);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
const VALID_REVIEWERS = new Set([
|
|
100
|
+
'architect', 'code', 'security', 'backend', 'ml-engineer', 'database', 'frontend', 'ux-designer',
|
|
101
|
+
]);
|
|
102
|
+
function reviewSubcommand(flags, cwd) {
|
|
103
|
+
const sprintStr = flags.sprint;
|
|
104
|
+
const gate = flags.gate;
|
|
105
|
+
const reviewer = flags.reviewer;
|
|
106
|
+
const findingsStr = flags.findings;
|
|
107
|
+
if (!sprintStr || !gate || !reviewer) {
|
|
108
|
+
console.error('\nUsage: slope initiative review --sprint=N --gate=<plan|pr> --reviewer=<type> [--findings=N]\n');
|
|
109
|
+
process.exit(1);
|
|
110
|
+
}
|
|
111
|
+
if (gate !== 'plan' && gate !== 'pr') {
|
|
112
|
+
console.error(`\n\u2717 Invalid gate: "${gate}". Must be "plan" or "pr".\n`);
|
|
113
|
+
process.exit(1);
|
|
114
|
+
}
|
|
115
|
+
if (!VALID_REVIEWERS.has(reviewer)) {
|
|
116
|
+
console.error(`\n\u2717 Invalid reviewer: "${reviewer}". Valid: ${[...VALID_REVIEWERS].join(', ')}\n`);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
}
|
|
119
|
+
const sprintNumber = parseInt(sprintStr, 10);
|
|
120
|
+
if (isNaN(sprintNumber)) {
|
|
121
|
+
console.error(`\n\u2717 Invalid sprint number: ${sprintStr}\n`);
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
const findingsCount = findingsStr ? parseInt(findingsStr, 10) : 0;
|
|
125
|
+
if (isNaN(findingsCount) || findingsCount < 0) {
|
|
126
|
+
console.error(`\n\u2717 Invalid findings count: ${findingsStr}\n`);
|
|
127
|
+
process.exit(1);
|
|
128
|
+
}
|
|
129
|
+
try {
|
|
130
|
+
recordReview(cwd, sprintNumber, gate, reviewer, findingsCount);
|
|
131
|
+
console.log(`\n\u2713 Recorded ${gate} review: ${reviewer} (${findingsCount} findings) for sprint ${sprintNumber}\n`);
|
|
132
|
+
}
|
|
133
|
+
catch (err) {
|
|
134
|
+
console.error(`\n\u2717 ${err.message}\n`);
|
|
135
|
+
process.exit(1);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
function checklistSubcommand(flags) {
|
|
139
|
+
const reviewer = flags.reviewer;
|
|
140
|
+
const gate = flags.gate;
|
|
141
|
+
if (!reviewer || !gate) {
|
|
142
|
+
console.error('\nUsage: slope initiative checklist --reviewer=<type> --gate=<plan|pr>\n');
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
const items = getReviewChecklist(reviewer, gate);
|
|
146
|
+
if (items.length === 0) {
|
|
147
|
+
console.log(`\nNo checklist defined for ${reviewer} at ${gate} gate.\n`);
|
|
148
|
+
return;
|
|
149
|
+
}
|
|
150
|
+
console.log(`\n# ${reviewer} — ${gate} review checklist\n`);
|
|
151
|
+
for (const item of items) {
|
|
152
|
+
console.log(` \u25A1 [${item.category}] ${item.question}`);
|
|
153
|
+
}
|
|
154
|
+
console.log('');
|
|
155
|
+
}
|
|
156
|
+
// --- Main Command ---
|
|
157
|
+
export async function initiativeCommand(args) {
|
|
158
|
+
const sub = args[0];
|
|
159
|
+
const flags = parseArgs(args.slice(1));
|
|
160
|
+
const cwd = process.cwd();
|
|
161
|
+
switch (sub) {
|
|
162
|
+
case 'create':
|
|
163
|
+
createSubcommand(flags, cwd);
|
|
164
|
+
break;
|
|
165
|
+
case 'status':
|
|
166
|
+
statusSubcommand(cwd);
|
|
167
|
+
break;
|
|
168
|
+
case 'next':
|
|
169
|
+
nextSubcommand(cwd);
|
|
170
|
+
break;
|
|
171
|
+
case 'advance':
|
|
172
|
+
advanceSubcommand(flags, cwd);
|
|
173
|
+
break;
|
|
174
|
+
case 'review':
|
|
175
|
+
reviewSubcommand(flags, cwd);
|
|
176
|
+
break;
|
|
177
|
+
case 'checklist':
|
|
178
|
+
checklistSubcommand(flags);
|
|
179
|
+
break;
|
|
180
|
+
default:
|
|
181
|
+
console.log(`
|
|
182
|
+
slope initiative — Multi-sprint initiative orchestration
|
|
183
|
+
|
|
184
|
+
Usage:
|
|
185
|
+
slope initiative create --name="..." --roadmap=<path> Create initiative from roadmap
|
|
186
|
+
slope initiative status Show initiative status table
|
|
187
|
+
slope initiative next Show next sprint + required reviews
|
|
188
|
+
slope initiative advance --sprint=N Move sprint to next phase
|
|
189
|
+
slope initiative review --sprint=N --gate=<plan|pr> --reviewer=<type> [--findings=N]
|
|
190
|
+
Record a review completion
|
|
191
|
+
slope initiative checklist --reviewer=<type> --gate=<plan|pr>
|
|
192
|
+
Show review checklist
|
|
193
|
+
|
|
194
|
+
Options:
|
|
195
|
+
--name=<str> Initiative name
|
|
196
|
+
--roadmap=<path> Path to roadmap JSON
|
|
197
|
+
--sprint=N Sprint number
|
|
198
|
+
--gate=plan|pr Review gate (plan or pr)
|
|
199
|
+
--reviewer=<type> Reviewer type (architect, code, backend, ml-engineer, etc.)
|
|
200
|
+
--findings=N Number of findings (default: 0)
|
|
201
|
+
--description=<s> Initiative description
|
|
202
|
+
`);
|
|
203
|
+
if (sub)
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
//# sourceMappingURL=initiative.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"initiative.js","sourceRoot":"","sources":["../../../src/cli/commands/initiative.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metaphor.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/metaphor.ts"],"names":[],"mappings":"AAKA,OAAO,+BAA+B,CAAC;AAIvC,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CA6CnE"}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
// SLOPE CLI — slope metaphor (list | set | show)
|
|
2
|
+
// Manage metaphor display themes.
|
|
3
|
+
import { loadConfig, saveConfig, loadPluginMetaphors, listMetaphors, hasMetaphor, getMetaphor } from '../../core/index.js';
|
|
4
|
+
// Ensure built-in metaphors are registered
|
|
5
|
+
import '../../core/metaphors/index.js';
|
|
6
|
+
const BUILTIN_IDS = ['golf', 'tennis', 'baseball', 'gaming', 'dnd', 'matrix', 'agile'];
|
|
7
|
+
export async function metaphorCommand(args) {
|
|
8
|
+
const sub = args[0];
|
|
9
|
+
const cwd = process.cwd();
|
|
10
|
+
// Load custom plugins so they appear in list/set/show
|
|
11
|
+
const config = loadConfig(cwd);
|
|
12
|
+
loadPluginMetaphors(cwd, config.plugins);
|
|
13
|
+
switch (sub) {
|
|
14
|
+
case 'list':
|
|
15
|
+
listSubcommand(config.metaphor);
|
|
16
|
+
break;
|
|
17
|
+
case 'set': {
|
|
18
|
+
const id = args[1];
|
|
19
|
+
if (!id) {
|
|
20
|
+
console.error('Usage: slope metaphor set <id>');
|
|
21
|
+
process.exit(1);
|
|
22
|
+
}
|
|
23
|
+
setSubcommand(id, cwd);
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
case 'show': {
|
|
27
|
+
const id = args[1];
|
|
28
|
+
if (!id) {
|
|
29
|
+
console.error('Usage: slope metaphor show <id>');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
showSubcommand(id);
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
default:
|
|
36
|
+
console.log(`
|
|
37
|
+
slope metaphor — Manage metaphor display themes
|
|
38
|
+
|
|
39
|
+
Usage:
|
|
40
|
+
slope metaphor list Show all available metaphors
|
|
41
|
+
slope metaphor set <id> Set the active metaphor
|
|
42
|
+
slope metaphor show <id> Show all terms for a metaphor
|
|
43
|
+
`);
|
|
44
|
+
if (sub) {
|
|
45
|
+
console.error(`Unknown subcommand "${sub}"`);
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
break;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function listSubcommand(activeId) {
|
|
52
|
+
const all = listMetaphors();
|
|
53
|
+
console.log('\nAvailable metaphors:\n');
|
|
54
|
+
for (const m of all) {
|
|
55
|
+
const active = m.id === activeId ? '[active] ' : ' ';
|
|
56
|
+
const custom = !BUILTIN_IDS.includes(m.id) ? ' [custom]' : '';
|
|
57
|
+
console.log(` ${active}${m.id.padEnd(12)} ${m.name.padEnd(14)} ${m.description}${custom}`);
|
|
58
|
+
}
|
|
59
|
+
console.log('');
|
|
60
|
+
}
|
|
61
|
+
function setSubcommand(id, cwd) {
|
|
62
|
+
if (!hasMetaphor(id)) {
|
|
63
|
+
const available = listMetaphors().map(m => m.id).join(', ');
|
|
64
|
+
console.error(`Unknown metaphor "${id}". Available: ${available}`);
|
|
65
|
+
process.exit(1);
|
|
66
|
+
}
|
|
67
|
+
const config = loadConfig(cwd);
|
|
68
|
+
saveConfig({ ...config, metaphor: id }, cwd);
|
|
69
|
+
console.log(`Metaphor set to "${id}". Restart your AI agent to see the change.`);
|
|
70
|
+
}
|
|
71
|
+
function showSubcommand(id) {
|
|
72
|
+
if (!hasMetaphor(id)) {
|
|
73
|
+
const available = listMetaphors().map(m => m.id).join(', ');
|
|
74
|
+
console.error(`Unknown metaphor "${id}". Available: ${available}`);
|
|
75
|
+
process.exit(1);
|
|
76
|
+
}
|
|
77
|
+
const m = getMetaphor(id);
|
|
78
|
+
console.log(`\nMetaphor: ${m.name}\n${m.description}\n`);
|
|
79
|
+
const sections = [
|
|
80
|
+
{ label: 'Vocabulary', entries: m.vocabulary },
|
|
81
|
+
{ label: 'Clubs', entries: m.clubs },
|
|
82
|
+
{ label: 'Shot Results', entries: m.shotResults },
|
|
83
|
+
{ label: 'Hazards', entries: m.hazards },
|
|
84
|
+
{ label: 'Conditions', entries: m.conditions },
|
|
85
|
+
{ label: 'Special Plays', entries: m.specialPlays },
|
|
86
|
+
{ label: 'Miss Directions', entries: m.missDirections },
|
|
87
|
+
{ label: 'Score Labels', entries: m.scoreLabels },
|
|
88
|
+
{ label: 'Sprint Types', entries: m.sprintTypes },
|
|
89
|
+
{ label: 'Training Types', entries: m.trainingTypes },
|
|
90
|
+
{ label: 'Nutrition', entries: m.nutrition },
|
|
91
|
+
];
|
|
92
|
+
for (const { label, entries } of sections) {
|
|
93
|
+
console.log(`${label}:`);
|
|
94
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
95
|
+
console.log(` ${key.padEnd(20)} → ${value}`);
|
|
96
|
+
}
|
|
97
|
+
console.log('');
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=metaphor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"metaphor.js","sourceRoot":"","sources":["../../../src/cli/commands/metaphor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prep.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/prep.ts"],"names":[],"mappings":"AAgCA,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAgE/D"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
// slope prep — Generate execution plan for a ticket
|
|
2
|
+
// Usage: slope prep <ticket-id> [--json] [--top=5]
|
|
3
|
+
import { loadConfig } from '../../core/config.js';
|
|
4
|
+
import { hasEmbeddingSupport } from '../../core/embedding-store.js';
|
|
5
|
+
import { loadScorecards } from '../../core/loader.js';
|
|
6
|
+
import { generatePrepPlan, formatPrepPlan } from '../../core/prep.js';
|
|
7
|
+
import { SqliteSlopeStore } from '../../store/index.js';
|
|
8
|
+
function parseArgs(args) {
|
|
9
|
+
let ticketId = null;
|
|
10
|
+
let json = false;
|
|
11
|
+
let top = 5;
|
|
12
|
+
for (const arg of args) {
|
|
13
|
+
if (arg === '--json') {
|
|
14
|
+
json = true;
|
|
15
|
+
}
|
|
16
|
+
else if (arg.startsWith('--top=')) {
|
|
17
|
+
top = parseInt(arg.slice('--top='.length), 10) || 5;
|
|
18
|
+
}
|
|
19
|
+
else if (!arg.startsWith('-')) {
|
|
20
|
+
ticketId = arg;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return { ticketId, json, top };
|
|
24
|
+
}
|
|
25
|
+
export async function prepCommand(args) {
|
|
26
|
+
const cwd = process.cwd();
|
|
27
|
+
const config = loadConfig(cwd);
|
|
28
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
29
|
+
printUsage();
|
|
30
|
+
return;
|
|
31
|
+
}
|
|
32
|
+
const flags = parseArgs(args);
|
|
33
|
+
if (!flags.ticketId) {
|
|
34
|
+
console.error('Error: Provide a ticket ID. Usage: slope prep <ticket-id>');
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
// Resolve embedding config
|
|
38
|
+
const emb = config.embedding;
|
|
39
|
+
if (!emb) {
|
|
40
|
+
console.error('Error: No embedding config in .slope/config.json. Run `slope index` first.');
|
|
41
|
+
process.exit(1);
|
|
42
|
+
}
|
|
43
|
+
const embConfig = {
|
|
44
|
+
endpoint: emb.endpoint,
|
|
45
|
+
model: emb.model,
|
|
46
|
+
dimensions: emb.dimensions,
|
|
47
|
+
apiKey: emb.apiKey,
|
|
48
|
+
};
|
|
49
|
+
// Open store
|
|
50
|
+
const storePath = config.store_path ?? '.slope/slope.db';
|
|
51
|
+
const store = new SqliteSlopeStore(`${cwd}/${storePath}`);
|
|
52
|
+
try {
|
|
53
|
+
if (!hasEmbeddingSupport(store)) {
|
|
54
|
+
throw new Error('Store does not support embeddings. Run `slope index` first.');
|
|
55
|
+
}
|
|
56
|
+
const stats = await store.getEmbeddingStats();
|
|
57
|
+
if (stats.chunkCount === 0) {
|
|
58
|
+
throw new Error('Semantic index is empty. Run `slope index` first.');
|
|
59
|
+
}
|
|
60
|
+
const scorecards = loadScorecards(config, cwd);
|
|
61
|
+
const plan = await generatePrepPlan({
|
|
62
|
+
ticketId: flags.ticketId,
|
|
63
|
+
store,
|
|
64
|
+
embeddingConfig: embConfig,
|
|
65
|
+
scorecards,
|
|
66
|
+
cwd,
|
|
67
|
+
roadmapPath: config.roadmapPath,
|
|
68
|
+
topK: flags.top,
|
|
69
|
+
});
|
|
70
|
+
if (flags.json) {
|
|
71
|
+
console.log(JSON.stringify(plan, null, 2));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
console.log(formatPrepPlan(plan));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
finally {
|
|
78
|
+
store.close();
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
function printUsage() {
|
|
82
|
+
console.log(`
|
|
83
|
+
slope prep — Generate execution plan for a ticket
|
|
84
|
+
|
|
85
|
+
Usage:
|
|
86
|
+
slope prep <ticket-id> Generate execution plan
|
|
87
|
+
slope prep <ticket-id> --json Output as JSON
|
|
88
|
+
slope prep <ticket-id> --top=5 Max context files (default: 5)
|
|
89
|
+
|
|
90
|
+
Requires a built semantic index. Run \`slope index\` first.
|
|
91
|
+
Looks up ticket in roadmap.json and slope-loop/backlog.json.
|
|
92
|
+
`);
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=prep.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prep.js","sourceRoot":"","sources":["../../../src/cli/commands/prep.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":"AA4ZA,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAuClE"}
|
|
@@ -19,18 +19,33 @@ function resolveRoadmapPath(flags, cwd) {
|
|
|
19
19
|
const config = loadConfig(cwd);
|
|
20
20
|
return join(cwd, config.roadmapPath);
|
|
21
21
|
}
|
|
22
|
-
function
|
|
22
|
+
function loadRawRoadmap(flags, cwd) {
|
|
23
23
|
const path = resolveRoadmapPath(flags, cwd);
|
|
24
|
-
let raw;
|
|
25
24
|
try {
|
|
26
|
-
|
|
25
|
+
const content = readFileSync(path, 'utf8');
|
|
26
|
+
if (!content.trim()) {
|
|
27
|
+
console.error(`\nRoadmap file is empty: ${path}\n`);
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
return { path, raw: JSON.parse(content) };
|
|
27
31
|
}
|
|
28
|
-
catch {
|
|
29
|
-
|
|
30
|
-
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (error.code === 'ENOENT') {
|
|
34
|
+
console.error(`\nNo roadmap file found at: ${path}`);
|
|
35
|
+
console.error('Create one with "slope init" or specify --path=<file>\n');
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
console.error(`\nFailed to parse roadmap file: ${path}`);
|
|
39
|
+
console.error(`Error: ${error.message}\n`);
|
|
40
|
+
}
|
|
31
41
|
return null;
|
|
32
42
|
}
|
|
33
|
-
|
|
43
|
+
}
|
|
44
|
+
function loadRoadmapFile(flags, cwd) {
|
|
45
|
+
const loaded = loadRawRoadmap(flags, cwd);
|
|
46
|
+
if (!loaded)
|
|
47
|
+
return null;
|
|
48
|
+
const { roadmap, validation } = parseRoadmap(loaded.raw);
|
|
34
49
|
if (!roadmap) {
|
|
35
50
|
console.error('\nRoadmap file has structural errors:\n');
|
|
36
51
|
for (const e of validation.errors) {
|
|
@@ -42,28 +57,31 @@ function loadRoadmapFile(flags, cwd) {
|
|
|
42
57
|
return roadmap;
|
|
43
58
|
}
|
|
44
59
|
function resolveSprint(flags, cwd) {
|
|
45
|
-
if (flags.sprint)
|
|
46
|
-
|
|
60
|
+
if (flags.sprint) {
|
|
61
|
+
const parsed = parseInt(flags.sprint, 10);
|
|
62
|
+
if (isNaN(parsed) || parsed < 1) {
|
|
63
|
+
console.error(`\nInvalid sprint number: ${flags.sprint}\n`);
|
|
64
|
+
process.exit(1);
|
|
65
|
+
}
|
|
66
|
+
return parsed;
|
|
67
|
+
}
|
|
47
68
|
const config = loadConfig(cwd);
|
|
48
|
-
if (config.currentSprint)
|
|
69
|
+
if (config.currentSprint && config.currentSprint > 0)
|
|
49
70
|
return config.currentSprint;
|
|
50
71
|
const scorecards = loadScorecards(config, cwd);
|
|
51
72
|
if (scorecards.length === 0)
|
|
52
73
|
return 1;
|
|
53
|
-
|
|
74
|
+
const sprintNumbers = scorecards.map(s => s.sprint_number).filter(n => typeof n === 'number' && n > 0);
|
|
75
|
+
if (sprintNumbers.length === 0)
|
|
76
|
+
return 1;
|
|
77
|
+
return Math.max(...sprintNumbers) + 1;
|
|
54
78
|
}
|
|
55
79
|
// --- Subcommands ---
|
|
56
80
|
function validateSubcommand(flags, cwd) {
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
try {
|
|
60
|
-
raw = JSON.parse(readFileSync(path, 'utf8'));
|
|
61
|
-
}
|
|
62
|
-
catch {
|
|
63
|
-
console.error(`\nNo roadmap file found at: ${path}`);
|
|
64
|
-
console.error('Create one with "slope init" or specify --path=<file>\n');
|
|
81
|
+
const loaded = loadRawRoadmap(flags, cwd);
|
|
82
|
+
if (!loaded)
|
|
65
83
|
process.exit(1);
|
|
66
|
-
}
|
|
84
|
+
const { path, raw } = loaded;
|
|
67
85
|
const { roadmap, validation } = parseRoadmap(raw);
|
|
68
86
|
console.log(`\nRoadmap: ${path}`);
|
|
69
87
|
console.log('\u2550'.repeat(40));
|
|
@@ -121,29 +139,41 @@ function reviewSubcommand(flags, cwd) {
|
|
|
121
139
|
}
|
|
122
140
|
// 2. Scope balance
|
|
123
141
|
console.log('\n## Scope Balance');
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
142
|
+
if (roadmap.sprints.length === 0) {
|
|
143
|
+
console.log(' No sprints defined');
|
|
144
|
+
}
|
|
145
|
+
else {
|
|
146
|
+
const ticketCounts = roadmap.sprints.map(s => s.tickets?.length ?? 0);
|
|
147
|
+
const avgTickets = ticketCounts.reduce((a, b) => a + b, 0) / ticketCounts.length;
|
|
148
|
+
const parValues = roadmap.sprints.map(s => s.par);
|
|
149
|
+
const avgPar = parValues.reduce((a, b) => a + b, 0) / parValues.length;
|
|
150
|
+
console.log(` Tickets per sprint: min=${Math.min(...ticketCounts)} avg=${avgTickets.toFixed(1)} max=${Math.max(...ticketCounts)}`);
|
|
151
|
+
console.log(` Par per sprint: min=${Math.min(...parValues)} avg=${avgPar.toFixed(1)} max=${Math.max(...parValues)}`);
|
|
152
|
+
// Flag outliers
|
|
153
|
+
for (const sprint of roadmap.sprints) {
|
|
154
|
+
const ticketCount = sprint.tickets?.length ?? 0;
|
|
155
|
+
if (ticketCount > 4) {
|
|
156
|
+
console.log(` \u26A0 S${sprint.id} has ${ticketCount} tickets (over recommended 4)`);
|
|
157
|
+
}
|
|
158
|
+
if (ticketCount < 3) {
|
|
159
|
+
console.log(` \u26A0 S${sprint.id} has ${ticketCount} tickets (under recommended 3)`);
|
|
160
|
+
}
|
|
134
161
|
}
|
|
135
|
-
|
|
136
|
-
|
|
162
|
+
// Club distribution
|
|
163
|
+
const clubCounts = {};
|
|
164
|
+
for (const sprint of roadmap.sprints) {
|
|
165
|
+
if (sprint.tickets) {
|
|
166
|
+
for (const ticket of sprint.tickets) {
|
|
167
|
+
if (ticket.club) {
|
|
168
|
+
clubCounts[ticket.club] = (clubCounts[ticket.club] ?? 0) + 1;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
137
172
|
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
const clubCounts = {};
|
|
141
|
-
for (const sprint of roadmap.sprints) {
|
|
142
|
-
for (const ticket of sprint.tickets) {
|
|
143
|
-
clubCounts[ticket.club] = (clubCounts[ticket.club] ?? 0) + 1;
|
|
173
|
+
if (Object.keys(clubCounts).length > 0) {
|
|
174
|
+
console.log(` Club distribution: ${Object.entries(clubCounts).map(([k, v]) => `${k}=${v}`).join(', ')}`);
|
|
144
175
|
}
|
|
145
176
|
}
|
|
146
|
-
console.log(` Club distribution: ${Object.entries(clubCounts).map(([k, v]) => `${k}=${v}`).join(', ')}`);
|
|
147
177
|
// 3. Critical path analysis
|
|
148
178
|
console.log('\n## Critical Path');
|
|
149
179
|
console.log(` Path: ${criticalPath.path.map(id => `S${id}`).join(' \u2192 ')}`);
|
|
@@ -158,12 +188,14 @@ function reviewSubcommand(flags, cwd) {
|
|
|
158
188
|
}
|
|
159
189
|
// 4. Parallel opportunities
|
|
160
190
|
console.log('\n## Parallelism');
|
|
161
|
-
if (parallelGroups.length === 0) {
|
|
191
|
+
if (!parallelGroups || parallelGroups.length === 0) {
|
|
162
192
|
console.log(' No parallel opportunities — all sprints are sequentially dependent');
|
|
163
193
|
}
|
|
164
194
|
else {
|
|
165
195
|
for (const group of parallelGroups) {
|
|
166
|
-
|
|
196
|
+
if (group.sprints && group.sprints.length > 0) {
|
|
197
|
+
console.log(` \u2713 ${group.sprints.map(id => `S${id}`).join(', ')}: ${group.reason || 'No dependencies'}`);
|
|
198
|
+
}
|
|
167
199
|
}
|
|
168
200
|
}
|
|
169
201
|
// 5. Dependency fan-in/fan-out
|
|
@@ -200,10 +232,16 @@ function statusSubcommand(flags, cwd) {
|
|
|
200
232
|
console.log('\u2550'.repeat(40));
|
|
201
233
|
console.log(`\nCurrent sprint: S${currentSprint}`);
|
|
202
234
|
console.log('');
|
|
203
|
-
for (const phase of roadmap.phases) {
|
|
235
|
+
for (const phase of roadmap.phases || []) {
|
|
236
|
+
if (!phase.sprints || !Array.isArray(phase.sprints)) {
|
|
237
|
+
console.log(`## ${phase.name || 'Unnamed Phase'} (0/0)`);
|
|
238
|
+
console.log(' No sprints defined for this phase');
|
|
239
|
+
console.log('');
|
|
240
|
+
continue;
|
|
241
|
+
}
|
|
204
242
|
const phaseSprints = roadmap.sprints.filter(s => phase.sprints.includes(s.id));
|
|
205
243
|
const completed = phaseSprints.filter(s => completedSprints.has(s.id)).length;
|
|
206
|
-
console.log(`## ${phase.name} (${completed}/${phaseSprints.length})`);
|
|
244
|
+
console.log(`## ${phase.name || 'Unnamed Phase'} (${completed}/${phaseSprints.length})`);
|
|
207
245
|
for (const sprint of phaseSprints) {
|
|
208
246
|
const isCompleted = completedSprints.has(sprint.id);
|
|
209
247
|
const isCurrent = sprint.id === currentSprint;
|
|
@@ -223,7 +261,8 @@ function statusSubcommand(flags, cwd) {
|
|
|
223
261
|
else {
|
|
224
262
|
status = '\u25CB pending';
|
|
225
263
|
}
|
|
226
|
-
|
|
264
|
+
const theme = sprint.theme || 'Untitled Sprint';
|
|
265
|
+
console.log(` S${sprint.id} ${theme.padEnd(30)} ${status}`);
|
|
227
266
|
}
|
|
228
267
|
console.log('');
|
|
229
268
|
}
|