@slope-dev/slope 1.62.3 → 1.63.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/dist/cli/commands/map.d.ts.map +1 -1
- package/dist/cli/commands/map.js +17 -12
- package/dist/cli/commands/map.js.map +1 -1
- package/dist/cli/commands/next.js +2 -2
- package/dist/cli/commands/next.js.map +1 -1
- package/dist/cli/commands/retro.d.ts.map +1 -1
- package/dist/cli/commands/retro.js +4 -0
- package/dist/cli/commands/retro.js.map +1 -1
- package/dist/cli/commands/review-packet.d.ts +18 -0
- package/dist/cli/commands/review-packet.d.ts.map +1 -0
- package/dist/cli/commands/review-packet.js +159 -0
- package/dist/cli/commands/review-packet.js.map +1 -0
- package/dist/cli/commands/review-state.d.ts.map +1 -1
- package/dist/cli/commands/review-state.js +17 -1
- package/dist/cli/commands/review-state.js.map +1 -1
- package/dist/cli/commands/roadmap.d.ts.map +1 -1
- package/dist/cli/commands/roadmap.js +54 -2
- 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 +154 -20
- package/dist/cli/commands/sprint.js.map +1 -1
- package/dist/cli/commands/validate.d.ts.map +1 -1
- package/dist/cli/commands/validate.js +25 -2
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/guards/sprint-completion.js +1 -1
- package/dist/cli/guards/sprint-completion.js.map +1 -1
- package/dist/cli/registry.d.ts +1 -1
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/cli/registry.js +16 -1
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli/roadmap-source-store.d.ts +10 -0
- package/dist/cli/roadmap-source-store.d.ts.map +1 -1
- package/dist/cli/roadmap-source-store.js +48 -0
- package/dist/cli/roadmap-source-store.js.map +1 -1
- package/dist/cli/sprint-inference.d.ts +3 -0
- package/dist/cli/sprint-inference.d.ts.map +1 -1
- package/dist/cli/sprint-inference.js +62 -23
- package/dist/cli/sprint-inference.js.map +1 -1
- package/dist/cli/sprint-state.d.ts +14 -0
- package/dist/cli/sprint-state.d.ts.map +1 -1
- package/dist/cli/sprint-state.js +30 -0
- package/dist/cli/sprint-state.js.map +1 -1
- package/dist/core/adapters/codex.d.ts.map +1 -1
- package/dist/core/adapters/codex.js +8 -2
- package/dist/core/adapters/codex.js.map +1 -1
- package/dist/core/index.d.ts +1 -1
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +1 -1
- package/dist/core/index.js.map +1 -1
- package/package.json +1 -1
- package/templates/codex/plugins/slope/.codex-plugin/plugin.json +1 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { loadSprintState, loadSprintStateResult, createSprintState, initializeSprintState, mutateSprintState, updateGate, updateSprintPhase, updateSprintPhaseForSprint, clearSprintState, isSprintComplete, isReviewGateSatisfied, isRequiredReviewGate, waivedReviewGateNames, pendingGateNames, pendingGates, isSprintPhase, isReviewGateName, validateReviewGateCompletion, SPRINT_PHASES, } from '../sprint-state.js';
|
|
2
|
-
import { WorkflowEngine, loadWorkflow, resolveVariables, validateWorkflow, loadConfig, parseRoadmap, castRoadmapStructure, formatSprintLabel, formatSprintNumber, parseSprintNumber } from '../../core/index.js';
|
|
1
|
+
import { loadSprintState, loadSprintStateResult, createSprintState, initializeSprintState, mutateSprintState, updateGate, updateSprintPhase, updateSprintPhaseForSprint, clearSprintState, isSprintComplete, isReviewGateSatisfied, isRequiredReviewGate, waivedReviewGateNames, pendingGateNames, pendingGates, isSprintPhase, isReviewGateName, isReviewGateVerdict, validateReviewGateCompletion, SPRINT_PHASES, } from '../sprint-state.js';
|
|
2
|
+
import { WorkflowEngine, loadWorkflow, resolveVariables, validateWorkflow, loadConfig, parseRoadmap, castRoadmapStructure, formatSprintLabel, formatSprintNumber, formatRoadmapSprintLabel, parseSprintNumber } from '../../core/index.js';
|
|
3
3
|
import { createHash } from 'node:crypto';
|
|
4
4
|
import { formatActorName, formatActorSource, formatConflictSummary, resolveActor } from '../actor.js';
|
|
5
5
|
import { inspectSprintRollover, performSprintRollover, SprintRolloverError, verifySprintRolloverLineage, } from '../sprint-rollover.js';
|
|
@@ -103,6 +103,12 @@ function parseGateOptions(args) {
|
|
|
103
103
|
let notes;
|
|
104
104
|
let reason;
|
|
105
105
|
let overrideReason;
|
|
106
|
+
let verdict;
|
|
107
|
+
let packet;
|
|
108
|
+
let reviewedCommit;
|
|
109
|
+
let tokenBudget;
|
|
110
|
+
let tokensUsed;
|
|
111
|
+
let overBudgetReason;
|
|
106
112
|
let help = false;
|
|
107
113
|
for (let i = 0; i < args.length; i++) {
|
|
108
114
|
const arg = args[i];
|
|
@@ -137,6 +143,69 @@ function parseGateOptions(args) {
|
|
|
137
143
|
i = prReviewValue.next;
|
|
138
144
|
continue;
|
|
139
145
|
}
|
|
146
|
+
const verdictValue = optionValue(args, i, '--verdict');
|
|
147
|
+
if (verdictValue) {
|
|
148
|
+
const normalized = verdictValue.value?.trim().toLowerCase().replace(/[\s-]+/g, '_');
|
|
149
|
+
if (!normalized || normalized.startsWith('--'))
|
|
150
|
+
errors.push('--verdict requires pass, changes_requested, or blocked');
|
|
151
|
+
else if (!isReviewGateVerdict(normalized))
|
|
152
|
+
errors.push('--verdict must be pass, changes_requested, or blocked');
|
|
153
|
+
else
|
|
154
|
+
verdict = normalized;
|
|
155
|
+
i = verdictValue.next;
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
const packetValue = optionValue(args, i, '--packet');
|
|
159
|
+
if (packetValue) {
|
|
160
|
+
if (!packetValue.value || packetValue.value.startsWith('--'))
|
|
161
|
+
errors.push('--packet requires a value');
|
|
162
|
+
else
|
|
163
|
+
packet = packetValue.value;
|
|
164
|
+
i = packetValue.next;
|
|
165
|
+
continue;
|
|
166
|
+
}
|
|
167
|
+
const reviewedCommitValue = optionValue(args, i, '--reviewed-commit') ?? optionValue(args, i, '--head');
|
|
168
|
+
if (reviewedCommitValue) {
|
|
169
|
+
if (!reviewedCommitValue.value || reviewedCommitValue.value.startsWith('--'))
|
|
170
|
+
errors.push('--reviewed-commit requires a value');
|
|
171
|
+
else
|
|
172
|
+
reviewedCommit = reviewedCommitValue.value;
|
|
173
|
+
i = reviewedCommitValue.next;
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
const tokenBudgetValue = optionValue(args, i, '--token-budget');
|
|
177
|
+
if (tokenBudgetValue) {
|
|
178
|
+
if (!tokenBudgetValue.value || tokenBudgetValue.value.startsWith('--'))
|
|
179
|
+
errors.push('--token-budget requires a value');
|
|
180
|
+
else
|
|
181
|
+
tokenBudget = tokenBudgetValue.value;
|
|
182
|
+
i = tokenBudgetValue.next;
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
const tokensUsedValue = optionValue(args, i, '--tokens-used');
|
|
186
|
+
if (tokensUsedValue) {
|
|
187
|
+
if (!tokensUsedValue.value || tokensUsedValue.value.startsWith('--')) {
|
|
188
|
+
errors.push('--tokens-used requires a numeric value');
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
const parsed = Number(tokensUsedValue.value);
|
|
192
|
+
if (!Number.isFinite(parsed) || parsed < 0)
|
|
193
|
+
errors.push('--tokens-used must be a non-negative number');
|
|
194
|
+
else
|
|
195
|
+
tokensUsed = parsed;
|
|
196
|
+
}
|
|
197
|
+
i = tokensUsedValue.next;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
const overBudgetValue = optionValue(args, i, '--over-budget-reason');
|
|
201
|
+
if (overBudgetValue) {
|
|
202
|
+
if (!overBudgetValue.value || overBudgetValue.value.startsWith('--'))
|
|
203
|
+
errors.push('--over-budget-reason requires a value');
|
|
204
|
+
else
|
|
205
|
+
overBudgetReason = overBudgetValue.value;
|
|
206
|
+
i = overBudgetValue.next;
|
|
207
|
+
continue;
|
|
208
|
+
}
|
|
140
209
|
if (arg === '--self-review') {
|
|
141
210
|
selfReview = true;
|
|
142
211
|
continue;
|
|
@@ -183,6 +252,7 @@ function parseGateOptions(args) {
|
|
|
183
252
|
if (modeCount > 1) {
|
|
184
253
|
errors.push('Use only one review provenance mode: --reviewer/--evidence, --pr-review, --self-review, --waive-independent-review, or --override.');
|
|
185
254
|
}
|
|
255
|
+
const inferredVerdict = verdict ?? inferVerdictFromEvidence(evidence);
|
|
186
256
|
let review;
|
|
187
257
|
if (modeCount === 1) {
|
|
188
258
|
if (hasPrReview) {
|
|
@@ -200,9 +270,45 @@ function parseGateOptions(args) {
|
|
|
200
270
|
else {
|
|
201
271
|
review = { provenance: 'independent_review', evidence, reviewer, notes: notes ?? reason };
|
|
202
272
|
}
|
|
273
|
+
review = {
|
|
274
|
+
...review,
|
|
275
|
+
...(inferredVerdict ? { verdict: inferredVerdict } : {}),
|
|
276
|
+
...(packet ? { packet } : {}),
|
|
277
|
+
...(reviewedCommit ? { reviewed_commit: reviewedCommit } : {}),
|
|
278
|
+
...(tokenBudget ? { token_budget: tokenBudget } : {}),
|
|
279
|
+
...(tokensUsed !== undefined ? { tokens_used: tokensUsed } : {}),
|
|
280
|
+
...(overBudgetReason ? { over_budget_reason: overBudgetReason } : {}),
|
|
281
|
+
};
|
|
203
282
|
}
|
|
204
283
|
return { review, errors, help };
|
|
205
284
|
}
|
|
285
|
+
function inferVerdictFromEvidence(evidence) {
|
|
286
|
+
const verdicts = [];
|
|
287
|
+
for (const item of evidence) {
|
|
288
|
+
if (/^https?:\/\//i.test(item))
|
|
289
|
+
continue;
|
|
290
|
+
const path = isAbsolute(item) ? item : join(process.cwd(), item);
|
|
291
|
+
if (!existsSync(path))
|
|
292
|
+
continue;
|
|
293
|
+
try {
|
|
294
|
+
const content = readFileSync(path, 'utf8');
|
|
295
|
+
const match = content.match(/^\s*verdict\s*:\s*([A-Za-z _-]+)/im);
|
|
296
|
+
const value = match?.[1]?.trim().toLowerCase().replace(/[\s-]+/g, '_');
|
|
297
|
+
if (isReviewGateVerdict(value))
|
|
298
|
+
verdicts.push(value);
|
|
299
|
+
}
|
|
300
|
+
catch {
|
|
301
|
+
continue;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
if (verdicts.includes('blocked'))
|
|
305
|
+
return 'blocked';
|
|
306
|
+
if (verdicts.includes('changes_requested'))
|
|
307
|
+
return 'changes_requested';
|
|
308
|
+
if (verdicts.includes('pass'))
|
|
309
|
+
return 'pass';
|
|
310
|
+
return undefined;
|
|
311
|
+
}
|
|
206
312
|
function printGateUsage(gateName) {
|
|
207
313
|
const gate = gateName && isReviewGateName(gateName) ? gateName : 'code_review';
|
|
208
314
|
console.error('');
|
|
@@ -210,6 +316,7 @@ function printGateUsage(gateName) {
|
|
|
210
316
|
console.error(' slope sprint gate <name>');
|
|
211
317
|
console.error(` slope sprint gate ${gate} --reviewer=<agent-or-person> --evidence=<transcript-or-output>`);
|
|
212
318
|
console.error(` slope sprint gate ${gate} --pr-review=<url-or-id>`);
|
|
319
|
+
console.error(` slope sprint gate ${gate} --reviewer=<id> --evidence=<file> --verdict=pass --packet=<review-packet.json>`);
|
|
213
320
|
console.error(` slope sprint gate ${gate} --self-review --reason="why self-review is acceptable"`);
|
|
214
321
|
console.error(` slope sprint gate ${gate} --waive-independent-review --reason="why the required independent review is being waived"`);
|
|
215
322
|
console.error(` slope sprint gate ${gate} --override="manual override reason"`);
|
|
@@ -220,6 +327,7 @@ function printGateUsage(gateName) {
|
|
|
220
327
|
console.error(' self_review (weaker): requires --self-review and --reason');
|
|
221
328
|
console.error(' independent_review_waived: explicit waiver for a required review; requires --waive-independent-review and --reason');
|
|
222
329
|
console.error(' manual_override (weaker): requires --override');
|
|
330
|
+
console.error(' verdict metadata: --verdict=pass|changes_requested|blocked; local evidence files with "Verdict:" are parsed automatically');
|
|
223
331
|
console.error('');
|
|
224
332
|
}
|
|
225
333
|
function commandValue(value) {
|
|
@@ -229,6 +337,28 @@ function commandValue(value) {
|
|
|
229
337
|
? `'${value.replaceAll("'", "''")}'`
|
|
230
338
|
: `'${value.replaceAll("'", `'"'"'`)}`;
|
|
231
339
|
}
|
|
340
|
+
function loadRoadmapForSprintLabels(cwd) {
|
|
341
|
+
const config = loadConfig(cwd);
|
|
342
|
+
const roadmapPath = join(cwd, config.roadmapPath);
|
|
343
|
+
if (!existsSync(roadmapPath))
|
|
344
|
+
return null;
|
|
345
|
+
try {
|
|
346
|
+
const raw = JSON.parse(readFileSync(roadmapPath, 'utf8'));
|
|
347
|
+
const parsed = parseRoadmap(raw);
|
|
348
|
+
return parsed.roadmap ?? castRoadmapStructure(raw);
|
|
349
|
+
}
|
|
350
|
+
catch {
|
|
351
|
+
return null;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
function sprintLabelForCwd(cwd, sprint) {
|
|
355
|
+
const roadmap = loadRoadmapForSprintLabels(cwd);
|
|
356
|
+
return roadmap ? formatRoadmapSprintLabel(roadmap, sprint) : formatSprintLabel(sprint);
|
|
357
|
+
}
|
|
358
|
+
function sprintNumberForCwd(cwd, sprint) {
|
|
359
|
+
const label = sprintLabelForCwd(cwd, sprint);
|
|
360
|
+
return label.startsWith('S') ? label.slice(1) : label;
|
|
361
|
+
}
|
|
232
362
|
function actorRetryOption(args) {
|
|
233
363
|
for (const flag of ['--actor', '--player']) {
|
|
234
364
|
const value = findOptionValue(args, flag);
|
|
@@ -450,6 +580,8 @@ async function beginCommand(args, cwd) {
|
|
|
450
580
|
process.exit(1);
|
|
451
581
|
}
|
|
452
582
|
// Step 1: initialize without overwriting existing or corrupt local state.
|
|
583
|
+
const sprintLabel = sprintLabelForCwd(cwd, sprint);
|
|
584
|
+
const sprintNumber = sprintNumberForCwd(cwd, sprint);
|
|
453
585
|
const initialized = initializeSprintState(cwd, createSprintState(sprint, 'planning'));
|
|
454
586
|
if (initialized.status === 'corrupt') {
|
|
455
587
|
console.error(`Refusing to begin: corrupt sprint evidence was preserved at ${relative(cwd, initialized.path)}.`);
|
|
@@ -457,11 +589,11 @@ async function beginCommand(args, cwd) {
|
|
|
457
589
|
}
|
|
458
590
|
let state = initialized.state;
|
|
459
591
|
const retryActor = actorRetryOption(args);
|
|
460
|
-
if (initialized.status === 'existing' && requireMatchingSprintOrRollover(cwd, state, sprint, `begin ${
|
|
461
|
-
console.log(`Sprint ${
|
|
592
|
+
if (initialized.status === 'existing' && requireMatchingSprintOrRollover(cwd, state, sprint, `begin ${sprintLabel}`, `slope sprint begin --sprint=${sprintNumber} --ticket=${commandValue(ticket)}${retryActor ? ` ${retryActor}` : ''}`)) {
|
|
593
|
+
console.log(`Sprint ${sprintNumber}: already started (phase: ${state.phase}).`);
|
|
462
594
|
}
|
|
463
595
|
else {
|
|
464
|
-
console.log(`Sprint ${
|
|
596
|
+
console.log(`Sprint ${sprintNumber}: started (phase: planning).`);
|
|
465
597
|
}
|
|
466
598
|
// Step 2: claim
|
|
467
599
|
const { resolveStore } = await import('../store.js');
|
|
@@ -491,7 +623,7 @@ async function beginCommand(args, cwd) {
|
|
|
491
623
|
console.error(`\nClaim blocked — overlap conflict(s) detected:`);
|
|
492
624
|
for (const c of overlaps)
|
|
493
625
|
console.error(` [!!] ${formatConflictSummary(c)}`);
|
|
494
|
-
console.error(`\nResolve conflicts or run \`slope claim --target=${ticket} --sprint=${
|
|
626
|
+
console.error(`\nResolve conflicts or run \`slope claim --target=${ticket} --sprint=${sprintNumber} --force\` to override.`);
|
|
495
627
|
process.exit(1);
|
|
496
628
|
}
|
|
497
629
|
const claim = await store.claim({ sprint_number: sprint, player, target: ticket, scope: 'ticket' });
|
|
@@ -508,11 +640,11 @@ async function beginCommand(args, cwd) {
|
|
|
508
640
|
console.log('\n' + '─'.repeat(50));
|
|
509
641
|
try {
|
|
510
642
|
const { briefingCommand } = await import('./briefing.js');
|
|
511
|
-
await briefingCommand([`--sprint=${
|
|
643
|
+
await briefingCommand([`--sprint=${sprintNumber}`]);
|
|
512
644
|
}
|
|
513
645
|
catch (err) {
|
|
514
646
|
console.error(` Could not run briefing: ${err.message}`);
|
|
515
|
-
console.error(` Sprint state was already created; retry with: slope briefing --sprint=${
|
|
647
|
+
console.error(` Sprint state was already created; retry with: slope briefing --sprint=${sprintNumber}`);
|
|
516
648
|
}
|
|
517
649
|
// Step 4: prep --lite
|
|
518
650
|
console.log('\n' + '─'.repeat(50));
|
|
@@ -582,28 +714,30 @@ async function startCommand(args, cwd) {
|
|
|
582
714
|
...(retryActor ? [retryActor] : []),
|
|
583
715
|
...(force ? ['--force'] : []),
|
|
584
716
|
];
|
|
585
|
-
const
|
|
717
|
+
const sprintLabel = sprintLabelForCwd(cwd, sprint);
|
|
718
|
+
const sprintNumber = sprintNumberForCwd(cwd, sprint);
|
|
719
|
+
const retryStart = `slope sprint start --number=${sprintNumber} --phase=${phase}${retryExtras.length > 0 ? ` ${retryExtras.join(' ')}` : ''}`;
|
|
586
720
|
failOnCorruptSprintState(cwd);
|
|
587
721
|
const existingResult = loadSprintStateResult(cwd);
|
|
588
722
|
const existing = existingResult.status === 'valid' ? existingResult.state : null;
|
|
589
723
|
if (existing) {
|
|
590
|
-
requireMatchingSprintOrRollover(cwd, existing, sprint, `start ${
|
|
724
|
+
requireMatchingSprintOrRollover(cwd, existing, sprint, `start ${sprintLabel}`, retryStart);
|
|
591
725
|
if (phaseValue && existing.phase !== phase) {
|
|
592
726
|
const updated = updateSprintPhaseForSprint(cwd, existing.sprint, phase);
|
|
593
727
|
if (!updated.matched) {
|
|
594
728
|
console.error('Refusing to update phase because sprint state changed concurrently; retry the start command.');
|
|
595
729
|
process.exit(1);
|
|
596
730
|
}
|
|
597
|
-
console.log(`Sprint ${
|
|
731
|
+
console.log(`Sprint ${sprintNumber} phase updated: ${phase}.`);
|
|
598
732
|
return;
|
|
599
733
|
}
|
|
600
|
-
console.log(`Sprint ${
|
|
734
|
+
console.log(`Sprint ${sprintNumber} state already exists (phase: ${existing.phase}).`);
|
|
601
735
|
return;
|
|
602
736
|
}
|
|
603
737
|
const roadmapReality = loadRoadmapReality(cwd);
|
|
604
738
|
const blockingRoadmapIssues = blockingRoadmapIssuesForSprint(roadmapReality, sprint);
|
|
605
739
|
if (blockingRoadmapIssues.length > 0 && !force) {
|
|
606
|
-
console.error(`\nPre-sprint reality check failed for ${
|
|
740
|
+
console.error(`\nPre-sprint reality check failed for ${sprintLabel}:`);
|
|
607
741
|
for (const issue of blockingRoadmapIssues) {
|
|
608
742
|
console.error(` [${issue.type}] ${issue.message}`);
|
|
609
743
|
}
|
|
@@ -629,12 +763,12 @@ async function startCommand(args, cwd) {
|
|
|
629
763
|
process.exit(1);
|
|
630
764
|
}
|
|
631
765
|
if (initialized.status === 'existing') {
|
|
632
|
-
requireMatchingSprintOrRollover(cwd, initialized.state, sprint, `start ${
|
|
633
|
-
console.log(`Sprint ${
|
|
766
|
+
requireMatchingSprintOrRollover(cwd, initialized.state, sprint, `start ${sprintLabel}`, retryStart);
|
|
767
|
+
console.log(`Sprint ${sprintNumber} state already exists (phase: ${initialized.state.phase}).`);
|
|
634
768
|
return;
|
|
635
769
|
}
|
|
636
770
|
const autoClaim = await autoClaimSprint(cwd, sprint, actorOverride(args));
|
|
637
|
-
console.log(`Sprint ${
|
|
771
|
+
console.log(`Sprint ${sprintNumber} started (phase: ${phase}). Use 'slope sprint gate <name>' to mark gates; review gates require evidence options.`);
|
|
638
772
|
if (autoClaim)
|
|
639
773
|
console.log(autoClaim);
|
|
640
774
|
}
|
|
@@ -643,7 +777,7 @@ async function autoClaimSprint(cwd, sprint, explicitActor) {
|
|
|
643
777
|
const actor = resolveActor(cwd, { explicitActor });
|
|
644
778
|
const player = actor.name;
|
|
645
779
|
const playerDisplay = formatActorName(actor);
|
|
646
|
-
const target = `sprint:${
|
|
780
|
+
const target = `sprint:${sprintLabelForCwd(cwd, sprint)}`;
|
|
647
781
|
try {
|
|
648
782
|
const store = await resolveStore(cwd);
|
|
649
783
|
try {
|
|
@@ -681,10 +815,10 @@ function phaseCommand(args, cwd) {
|
|
|
681
815
|
}
|
|
682
816
|
updateSprintPhase(cwd, phaseInput);
|
|
683
817
|
if (before.phase === phaseInput) {
|
|
684
|
-
console.log(`Sprint ${
|
|
818
|
+
console.log(`Sprint ${sprintNumberForCwd(cwd, before.sprint)} already in ${phaseInput} phase.`);
|
|
685
819
|
}
|
|
686
820
|
else {
|
|
687
|
-
console.log(`Sprint ${
|
|
821
|
+
console.log(`Sprint ${sprintNumberForCwd(cwd, before.sprint)} phase updated: ${before.phase} -> ${phaseInput}.`);
|
|
688
822
|
}
|
|
689
823
|
}
|
|
690
824
|
function gateCommand(args, cwd) {
|
|
@@ -800,7 +934,7 @@ function statusCommand(cwd) {
|
|
|
800
934
|
? waivedReviews.length > 0 ? 'ready_for_pr_with_review_waiver' : 'ready_for_pr'
|
|
801
935
|
: state.phase;
|
|
802
936
|
const phaseContext = complete ? ' (all gates complete)' : ` (phase: ${state.phase})`;
|
|
803
|
-
console.log(`Sprint ${
|
|
937
|
+
console.log(`Sprint ${sprintNumberForCwd(cwd, state.sprint)} - status: ${derivedStatus}${phaseContext}`);
|
|
804
938
|
console.log(`Started: ${state.started_at}`);
|
|
805
939
|
console.log(`Updated: ${state.updated_at}`);
|
|
806
940
|
console.log('');
|