@slope-dev/slope 1.29.0 → 1.31.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/dashboard.d.ts.map +1 -1
- package/dist/cli/commands/dashboard.js +33 -6
- package/dist/cli/commands/dashboard.js.map +1 -1
- package/dist/cli/commands/guard.d.ts.map +1 -1
- package/dist/cli/commands/guard.js +38 -2
- package/dist/cli/commands/guard.js.map +1 -1
- package/dist/cli/commands/phase.d.ts +10 -0
- package/dist/cli/commands/phase.d.ts.map +1 -0
- package/dist/cli/commands/phase.js +86 -0
- package/dist/cli/commands/phase.js.map +1 -0
- package/dist/cli/commands/stats.d.ts +3 -0
- package/dist/cli/commands/stats.d.ts.map +1 -1
- package/dist/cli/commands/stats.js +3 -1
- package/dist/cli/commands/stats.js.map +1 -1
- package/dist/cli/guards/claim-required.d.ts +8 -0
- package/dist/cli/guards/claim-required.d.ts.map +1 -0
- package/dist/cli/guards/claim-required.js +46 -0
- package/dist/cli/guards/claim-required.js.map +1 -0
- package/dist/cli/guards/explore.d.ts.map +1 -1
- package/dist/cli/guards/explore.js +82 -7
- package/dist/cli/guards/explore.js.map +1 -1
- package/dist/cli/guards/next-action.d.ts +4 -2
- package/dist/cli/guards/next-action.d.ts.map +1 -1
- package/dist/cli/guards/next-action.js +94 -85
- package/dist/cli/guards/next-action.js.map +1 -1
- package/dist/cli/guards/phase-boundary.d.ts +7 -0
- package/dist/cli/guards/phase-boundary.d.ts.map +1 -0
- package/dist/cli/guards/phase-boundary.js +93 -0
- package/dist/cli/guards/phase-boundary.js.map +1 -0
- package/dist/cli/guards/post-push.d.ts +8 -0
- package/dist/cli/guards/post-push.d.ts.map +1 -0
- package/dist/cli/guards/post-push.js +98 -0
- package/dist/cli/guards/post-push.js.map +1 -0
- package/dist/cli/guards/pr-review.d.ts.map +1 -1
- package/dist/cli/guards/pr-review.js +14 -22
- package/dist/cli/guards/pr-review.js.map +1 -1
- package/dist/cli/guards/review-stale.d.ts +8 -0
- package/dist/cli/guards/review-stale.d.ts.map +1 -0
- package/dist/cli/guards/review-stale.js +51 -0
- package/dist/cli/guards/review-stale.js.map +1 -0
- package/dist/cli/guards/session-briefing.d.ts +8 -0
- package/dist/cli/guards/session-briefing.d.ts.map +1 -0
- package/dist/cli/guards/session-briefing.js +100 -0
- package/dist/cli/guards/session-briefing.js.map +1 -0
- package/dist/cli/guards/sprint-completion.js +33 -0
- package/dist/cli/guards/sprint-completion.js.map +1 -1
- package/dist/cli/guards/subagent-gate.d.ts.map +1 -1
- package/dist/cli/guards/subagent-gate.js +8 -2
- package/dist/cli/guards/subagent-gate.js.map +1 -1
- package/dist/cli/index.js +7 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/phase-cleanup.d.ts +25 -0
- package/dist/cli/phase-cleanup.d.ts.map +1 -0
- package/dist/cli/phase-cleanup.js +101 -0
- package/dist/cli/phase-cleanup.js.map +1 -0
- package/dist/cli/registry.d.ts +1 -1
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/cli/registry.js +1 -1
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli/session-state.d.ts +18 -0
- package/dist/cli/session-state.d.ts.map +1 -0
- package/dist/cli/session-state.js +31 -0
- package/dist/cli/session-state.js.map +1 -0
- package/dist/core/adapters/claude-code.d.ts +2 -1
- package/dist/core/adapters/claude-code.d.ts.map +1 -1
- package/dist/core/adapters/claude-code.js +51 -27
- package/dist/core/adapters/claude-code.js.map +1 -1
- package/dist/core/adapters/cursor.d.ts +2 -1
- package/dist/core/adapters/cursor.d.ts.map +1 -1
- package/dist/core/adapters/cursor.js +47 -7
- package/dist/core/adapters/cursor.js.map +1 -1
- package/dist/core/adapters/windsurf.d.ts +2 -1
- package/dist/core/adapters/windsurf.d.ts.map +1 -1
- package/dist/core/adapters/windsurf.js +29 -12
- package/dist/core/adapters/windsurf.js.map +1 -1
- package/dist/core/analytics.d.ts +58 -0
- package/dist/core/analytics.d.ts.map +1 -0
- package/dist/core/analytics.js +159 -0
- package/dist/core/analytics.js.map +1 -0
- package/dist/core/dashboard.d.ts +2 -1
- package/dist/core/dashboard.d.ts.map +1 -1
- package/dist/core/dashboard.js +10 -2
- package/dist/core/dashboard.js.map +1 -1
- package/dist/core/guard.d.ts +21 -1
- package/dist/core/guard.d.ts.map +1 -1
- package/dist/core/guard.js +38 -0
- package/dist/core/guard.js.map +1 -1
- package/dist/core/index.d.ts +4 -2
- 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/report.d.ts +16 -0
- package/dist/core/report.d.ts.map +1 -1
- package/dist/core/report.js +247 -0
- package/dist/core/report.js.map +1 -1
- package/package.json +1 -1
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, unlinkSync, statSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
3
|
import { execSync } from 'node:child_process';
|
|
4
4
|
import { loadConfig } from '../config.js';
|
|
5
|
+
import { loadSessionState, updateSessionState } from '../session-state.js';
|
|
5
6
|
const DEFAULT_INDEX_PATHS = ['CODEBASE.md', '.slope/index.json', 'docs/architecture.md'];
|
|
6
7
|
const DEFAULT_STALE_WARN_AT = 11;
|
|
7
8
|
const DEFAULT_STALE_BLOCK_AT = 31;
|
|
@@ -14,6 +15,8 @@ const DEFAULT_STALE_BLOCK_AT = 31;
|
|
|
14
15
|
* 31+ commits stale → block Edit/Write (don't block Read/Glob/Grep)
|
|
15
16
|
*/
|
|
16
17
|
export async function exploreGuard(input, cwd) {
|
|
18
|
+
// Post-compaction handoff injection: on first tool call, check for handoff files
|
|
19
|
+
const handoffContext = readHandoffIfAvailable(input, cwd);
|
|
17
20
|
const config = loadConfig(cwd);
|
|
18
21
|
const indexPaths = config.guidance?.indexPaths ?? DEFAULT_INDEX_PATHS;
|
|
19
22
|
// Find which index files exist
|
|
@@ -25,7 +28,8 @@ export async function exploreGuard(input, cwd) {
|
|
|
25
28
|
}
|
|
26
29
|
}
|
|
27
30
|
if (found.length === 0) {
|
|
28
|
-
|
|
31
|
+
// No index — still inject handoff if available
|
|
32
|
+
return handoffContext ? { context: handoffContext } : {};
|
|
29
33
|
}
|
|
30
34
|
// Check if CODEBASE.md exists and assess staleness
|
|
31
35
|
const mapPath = join(cwd, 'CODEBASE.md');
|
|
@@ -38,31 +42,102 @@ export async function exploreGuard(input, cwd) {
|
|
|
38
42
|
if (isWriteTool) {
|
|
39
43
|
return {
|
|
40
44
|
decision: 'deny',
|
|
41
|
-
blockReason: `SLOPE: Codebase map is ${staleness.distance} commits stale. Run \`slope map\` to refresh before editing
|
|
45
|
+
blockReason: prependHandoff(handoffContext, `SLOPE: Codebase map is ${staleness.distance} commits stale. Run \`slope map\` to refresh before editing.`),
|
|
42
46
|
};
|
|
43
47
|
}
|
|
44
48
|
// Read/Glob/Grep — warn but don't block
|
|
45
49
|
return {
|
|
46
|
-
context: `SLOPE: Codebase map is ${staleness.distance} commits stale. Run \`slope map\` to refresh
|
|
50
|
+
context: prependHandoff(handoffContext, `SLOPE: Codebase map is ${staleness.distance} commits stale. Run \`slope map\` to refresh.`),
|
|
47
51
|
};
|
|
48
52
|
}
|
|
49
53
|
if (staleness.level === 'warn') {
|
|
50
54
|
return {
|
|
51
|
-
context: `SLOPE: Codebase map at CODEBASE.md is ${staleness.distance} commits stale. Run 'slope map' to refresh, or explore if needed
|
|
55
|
+
context: prependHandoff(handoffContext, `SLOPE: Codebase map at CODEBASE.md is ${staleness.distance} commits stale. Run 'slope map' to refresh, or explore if needed.`),
|
|
52
56
|
};
|
|
53
57
|
}
|
|
54
58
|
// Current map — estimate token size
|
|
55
59
|
const content = readFileSync(mapPath, 'utf8');
|
|
56
60
|
const approxTokens = Math.round(content.length / 4 / 1000);
|
|
57
61
|
return {
|
|
58
|
-
context: `SLOPE: Codebase map at CODEBASE.md (~${approxTokens}k tokens, L1). Try \`context_search\` (L1.5) before reading full files (L2)
|
|
62
|
+
context: prependHandoff(handoffContext, `SLOPE: Codebase map at CODEBASE.md (~${approxTokens}k tokens, L1). Try \`context_search\` (L1.5) before reading full files (L2).`),
|
|
59
63
|
};
|
|
60
64
|
}
|
|
61
65
|
// Fallback: other index files found but no CODEBASE.md
|
|
62
66
|
return {
|
|
63
|
-
context: `SLOPE: Codebase index available at: ${found.join(', ')} — check before deep exploration
|
|
67
|
+
context: prependHandoff(handoffContext, `SLOPE: Codebase index available at: ${found.join(', ')} — check before deep exploration.`),
|
|
64
68
|
};
|
|
65
69
|
}
|
|
70
|
+
/** Prepend handoff context if available. */
|
|
71
|
+
function prependHandoff(handoff, context) {
|
|
72
|
+
return handoff ? `${handoff}\n\n${context}` : context;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Read the most recent handoff file from .slope/handoffs/ if this is the
|
|
76
|
+
* first file-read of the session (post-compaction recovery).
|
|
77
|
+
* Returns formatted context string or null. One-shot: deletes after reading.
|
|
78
|
+
*/
|
|
79
|
+
function readHandoffIfAvailable(input, cwd) {
|
|
80
|
+
const sessionId = input.session_id;
|
|
81
|
+
if (!sessionId)
|
|
82
|
+
return null;
|
|
83
|
+
// Dedup: only check once per session
|
|
84
|
+
const sessionState = loadSessionState(cwd);
|
|
85
|
+
if (sessionState.handoff_read_session_id === sessionId)
|
|
86
|
+
return null;
|
|
87
|
+
const config = loadConfig(cwd);
|
|
88
|
+
const handoffsDir = join(cwd, config.guidance?.handoffsDir ?? '.slope/handoffs');
|
|
89
|
+
if (!existsSync(handoffsDir))
|
|
90
|
+
return null;
|
|
91
|
+
try {
|
|
92
|
+
const files = readdirSync(handoffsDir)
|
|
93
|
+
.filter(f => f.endsWith('.json'))
|
|
94
|
+
.map(f => ({ name: f, mtime: statSync(join(handoffsDir, f)).mtimeMs }))
|
|
95
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
96
|
+
if (files.length === 0)
|
|
97
|
+
return null;
|
|
98
|
+
// Only use handoffs less than 1 hour old
|
|
99
|
+
const latest = files[0];
|
|
100
|
+
const ageMs = Date.now() - latest.mtime;
|
|
101
|
+
if (ageMs > 3600 * 1000)
|
|
102
|
+
return null;
|
|
103
|
+
const handoff = JSON.parse(readFileSync(join(handoffsDir, latest.name), 'utf8'));
|
|
104
|
+
// Mark as read (one-shot)
|
|
105
|
+
updateSessionState(cwd, 'handoff_read_session_id', sessionId);
|
|
106
|
+
// Delete handoff file after reading
|
|
107
|
+
try {
|
|
108
|
+
unlinkSync(join(handoffsDir, latest.name));
|
|
109
|
+
}
|
|
110
|
+
catch { /* best-effort */ }
|
|
111
|
+
// Clean up old handoff files (>24h)
|
|
112
|
+
for (const f of files.slice(1)) {
|
|
113
|
+
if (Date.now() - f.mtime > 24 * 3600 * 1000) {
|
|
114
|
+
try {
|
|
115
|
+
unlinkSync(join(handoffsDir, f.name));
|
|
116
|
+
}
|
|
117
|
+
catch { /* best-effort */ }
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
// Format handoff as context
|
|
121
|
+
const lines = ['SLOPE session handoff (post-compaction recovery):'];
|
|
122
|
+
if (handoff.git) {
|
|
123
|
+
lines.push(` Branch: ${handoff.git.branch}, ${handoff.git.uncommitted} uncommitted, ${handoff.git.unpushed} unpushed`);
|
|
124
|
+
}
|
|
125
|
+
if (handoff.sprint_phase) {
|
|
126
|
+
lines.push(` Sprint phase: ${handoff.sprint_phase}`);
|
|
127
|
+
}
|
|
128
|
+
if (handoff.claims?.length) {
|
|
129
|
+
const targets = handoff.claims.map((c) => c.target ?? 'unknown').join(', ');
|
|
130
|
+
lines.push(` Active claims: ${targets}`);
|
|
131
|
+
}
|
|
132
|
+
if (handoff.review) {
|
|
133
|
+
lines.push(` Review: ${handoff.review.tier} (${handoff.review.rounds_completed}/${handoff.review.rounds_required} rounds)`);
|
|
134
|
+
}
|
|
135
|
+
return lines.join('\n');
|
|
136
|
+
}
|
|
137
|
+
catch {
|
|
138
|
+
return null;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
66
141
|
function checkMapStaleness(mapPath, cwd, config) {
|
|
67
142
|
const warnAt = config?.guidance?.mapStaleWarnAt ?? DEFAULT_STALE_WARN_AT;
|
|
68
143
|
const blockAt = config?.guidance?.mapStaleBlockAt ?? DEFAULT_STALE_BLOCK_AT;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"explore.js","sourceRoot":"","sources":["../../../src/cli/guards/explore.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"explore.js","sourceRoot":"","sources":["../../../src/cli/guards/explore.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { HookInput, GuardResult } from '../../core/index.js';
|
|
1
|
+
import type { HookInput, GuardResult, Suggestion } from '../../core/index.js';
|
|
2
2
|
/** Sprint state types for next-action detection */
|
|
3
3
|
type SprintState = {
|
|
4
4
|
type: 'mid-sprint';
|
|
@@ -28,7 +28,9 @@ type SprintState = {
|
|
|
28
28
|
export declare function nextActionGuard(input: HookInput, cwd: string): Promise<GuardResult>;
|
|
29
29
|
/** Detect current sprint state via store then filesystem fallback */
|
|
30
30
|
export declare function detectSprintState(cwd: string, sessionId?: string): Promise<SprintState>;
|
|
31
|
-
/** Build
|
|
31
|
+
/** Build structured Suggestion from sprint state */
|
|
32
|
+
export declare function buildSuggestionObject(state: SprintState): Suggestion;
|
|
33
|
+
/** @deprecated Use buildSuggestionObject instead. Kept for backward compatibility. */
|
|
32
34
|
export declare function buildSuggestions(state: SprintState): string;
|
|
33
35
|
export {};
|
|
34
36
|
//# sourceMappingURL=next-action.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"next-action.d.ts","sourceRoot":"","sources":["../../../src/cli/guards/next-action.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAe,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"next-action.d.ts","sourceRoot":"","sources":["../../../src/cli/guards/next-action.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAe,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAM3F,mDAAmD;AACnD,KAAK,WAAW,GACZ;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,EAAE,CAAA;CAAE,GACnF;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACjD;IAAE,IAAI,EAAE,cAAc,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,YAAY,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,GAC1B;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,cAAc,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC;AAEzD;;;GAGG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAmCzF;AAED,qEAAqE;AACrE,wBAAsB,iBAAiB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CA+G7F;AAuBD,oDAAoD;AACpD,wBAAgB,qBAAqB,CAAC,KAAK,EAAE,WAAW,GAAG,UAAU,CA8FpE;AAED,sFAAsF;AACtF,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,CAU3D"}
|
|
@@ -25,8 +25,8 @@ export async function nextActionGuard(input, cwd) {
|
|
|
25
25
|
}
|
|
26
26
|
// Detect sprint state
|
|
27
27
|
const state = await detectSprintState(cwd, input.session_id);
|
|
28
|
-
// Build suggestion
|
|
29
|
-
const suggestion =
|
|
28
|
+
// Build structured suggestion
|
|
29
|
+
const suggestion = buildSuggestionObject(state);
|
|
30
30
|
// Write state file atomically
|
|
31
31
|
try {
|
|
32
32
|
mkdirSync(slopeDir, { recursive: true });
|
|
@@ -39,7 +39,7 @@ export async function nextActionGuard(input, cwd) {
|
|
|
39
39
|
renameSync(tmpPath, stateFile);
|
|
40
40
|
}
|
|
41
41
|
catch { /* best-effort — don't fail the guard */ }
|
|
42
|
-
return {
|
|
42
|
+
return { suggestion };
|
|
43
43
|
}
|
|
44
44
|
/** Detect current sprint state via store then filesystem fallback */
|
|
45
45
|
export async function detectSprintState(cwd, sessionId) {
|
|
@@ -171,98 +171,107 @@ function buildBetweenSprints(config, cwd, latestSprint) {
|
|
|
171
171
|
catch { /* roadmap parsing failed — proceed without context */ }
|
|
172
172
|
return { type: 'between-sprints', roadmapContext };
|
|
173
173
|
}
|
|
174
|
-
/** Build
|
|
175
|
-
export function
|
|
176
|
-
const header = 'SLOPE next-action: Before ending this session, present the user with options for what to do next.';
|
|
174
|
+
/** Build structured Suggestion from sprint state */
|
|
175
|
+
export function buildSuggestionObject(state) {
|
|
177
176
|
switch (state.type) {
|
|
178
177
|
case 'mid-sprint': {
|
|
179
178
|
const targetList = state.targets.join(', ');
|
|
180
|
-
return
|
|
181
|
-
|
|
182
|
-
'',
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
179
|
+
return {
|
|
180
|
+
id: 'next-action-mid-sprint',
|
|
181
|
+
title: 'Next Action',
|
|
182
|
+
context: `Mid-sprint — ${state.claimCount} active claim(s) for sprint ${state.sprintNumber}: ${targetList}`,
|
|
183
|
+
options: [
|
|
184
|
+
{ id: 'continue', label: 'Continue with the next ticket' },
|
|
185
|
+
{ id: 'push-break', label: 'Push and take a break', description: 'Resume later' },
|
|
186
|
+
{ id: 'end', label: 'End session', description: 'Nothing more to do right now' },
|
|
187
|
+
],
|
|
188
|
+
requiresDecision: true,
|
|
189
|
+
priority: 'normal',
|
|
190
|
+
};
|
|
192
191
|
}
|
|
193
192
|
case 'sprint-complete':
|
|
194
|
-
return
|
|
195
|
-
|
|
196
|
-
'',
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
case 'needs-review':
|
|
208
|
-
return
|
|
209
|
-
|
|
210
|
-
'',
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
'',
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
'Present these using AskUserQuestion. If the user chooses to end the session, stop without further action.',
|
|
234
|
-
].join('\n');
|
|
235
|
-
}
|
|
193
|
+
return {
|
|
194
|
+
id: 'next-action-complete',
|
|
195
|
+
title: 'Next Action',
|
|
196
|
+
context: `Sprint ${state.sprintNumber} is complete but unscored`,
|
|
197
|
+
options: [
|
|
198
|
+
{ id: 'score', label: 'Score the sprint', description: 'Run post-hole routine' },
|
|
199
|
+
{ id: 'validate', label: 'Validate scorecard', command: 'slope validate' },
|
|
200
|
+
{ id: 'distill', label: 'Distill learnings', command: 'slope distill --auto' },
|
|
201
|
+
{ id: 'end', label: 'End session', description: 'Nothing more to do right now' },
|
|
202
|
+
],
|
|
203
|
+
requiresDecision: true,
|
|
204
|
+
priority: 'normal',
|
|
205
|
+
};
|
|
206
|
+
case 'needs-review':
|
|
207
|
+
return {
|
|
208
|
+
id: 'next-action-review',
|
|
209
|
+
title: 'Next Action',
|
|
210
|
+
context: `Sprint ${state.sprintNumber} has a scorecard but no review`,
|
|
211
|
+
options: [
|
|
212
|
+
{ id: 'review', label: 'Generate sprint review', command: 'slope review' },
|
|
213
|
+
{ id: 'distill', label: 'Distill learnings', command: 'slope distill --auto' },
|
|
214
|
+
{ id: 'end', label: 'End session', description: 'Nothing more to do right now' },
|
|
215
|
+
],
|
|
216
|
+
requiresDecision: true,
|
|
217
|
+
priority: 'normal',
|
|
218
|
+
};
|
|
219
|
+
case 'needs-amend':
|
|
220
|
+
return {
|
|
221
|
+
id: 'next-action-amend',
|
|
222
|
+
title: 'Next Action',
|
|
223
|
+
context: `Sprint ${state.sprintNumber} has ${state.findingCount} review finding(s) not yet applied to scorecard`,
|
|
224
|
+
options: [
|
|
225
|
+
{ id: 'amend', label: 'Apply findings to scorecard', command: 'slope review amend' },
|
|
226
|
+
{ id: 'list', label: 'View findings first', command: 'slope review findings list' },
|
|
227
|
+
{ id: 'end', label: 'End session', description: 'Nothing more to do right now' },
|
|
228
|
+
],
|
|
229
|
+
requiresDecision: true,
|
|
230
|
+
priority: 'normal',
|
|
231
|
+
};
|
|
236
232
|
case 'testing-active':
|
|
237
|
-
return
|
|
238
|
-
|
|
239
|
-
'',
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
233
|
+
return {
|
|
234
|
+
id: 'next-action-testing',
|
|
235
|
+
title: 'Next Action',
|
|
236
|
+
context: 'Testing session active',
|
|
237
|
+
options: [
|
|
238
|
+
{ id: 'continue', label: 'Continue testing' },
|
|
239
|
+
{ id: 'end-testing', label: 'End testing session' },
|
|
240
|
+
{ id: 'end', label: 'End session', description: 'Nothing more to do right now' },
|
|
241
|
+
],
|
|
242
|
+
requiresDecision: true,
|
|
243
|
+
priority: 'normal',
|
|
244
|
+
};
|
|
249
245
|
case 'between-sprints': {
|
|
250
246
|
const contextLine = state.roadmapContext
|
|
251
|
-
? `\n${state.roadmapContext}
|
|
247
|
+
? `\n${state.roadmapContext}`
|
|
252
248
|
: '';
|
|
253
|
-
return
|
|
254
|
-
|
|
255
|
-
'',
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
249
|
+
return {
|
|
250
|
+
id: 'next-action-between',
|
|
251
|
+
title: 'Next Action',
|
|
252
|
+
context: `No active sprint${contextLine}`,
|
|
253
|
+
options: [
|
|
254
|
+
{ id: 'roadmap', label: 'Check next sprint candidates' },
|
|
255
|
+
{ id: 'start', label: 'Start a new sprint' },
|
|
256
|
+
{ id: 'briefing', label: 'Run briefing', command: 'slope briefing' },
|
|
257
|
+
{ id: 'end', label: 'End session', description: 'Nothing more to do right now' },
|
|
258
|
+
],
|
|
259
|
+
requiresDecision: true,
|
|
260
|
+
priority: 'normal',
|
|
261
|
+
};
|
|
265
262
|
}
|
|
266
263
|
}
|
|
267
264
|
}
|
|
265
|
+
/** @deprecated Use buildSuggestionObject instead. Kept for backward compatibility. */
|
|
266
|
+
export function buildSuggestions(state) {
|
|
267
|
+
const suggestion = buildSuggestionObject(state);
|
|
268
|
+
const lines = [`SLOPE ${suggestion.title}: ${suggestion.context}`, '', 'Suggested options:'];
|
|
269
|
+
for (let i = 0; i < suggestion.options.length; i++) {
|
|
270
|
+
const opt = suggestion.options[i];
|
|
271
|
+
const desc = opt.description ? ` — ${opt.description}` : '';
|
|
272
|
+
lines.push(`${i + 1}. ${opt.label}${desc}`);
|
|
273
|
+
}
|
|
274
|
+
lines.push('', 'Present these using AskUserQuestion. If the user chooses to end the session, stop without further action.');
|
|
275
|
+
return lines.join('\n');
|
|
276
|
+
}
|
|
268
277
|
//# sourceMappingURL=next-action.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"next-action.js","sourceRoot":"","sources":["../../../src/cli/guards/next-action.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,aAAa,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACzF,OAAO,EAAE,IAAI,EAAW,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,UAAU,EAAkB,kBAAkB,EAAE,YAAY,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC3H,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAWrD;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CAAC,KAAgB,EAAE,GAAW;IACjE,kEAAkE;IAClE,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,uBAAuB,CAAC,CAAC;IAE1D,IAAI,KAAK,CAAC,UAAU,EAAE,CAAC;QACrB,IAAI,CAAC;YACH,IAAI,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;gBAC1B,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC;gBACxD,IAAI,GAAG,CAAC,UAAU,KAAK,KAAK,CAAC,UAAU,EAAE,CAAC;oBACxC,OAAO,EAAE,CAAC;gBACZ,CAAC;YACH,CAAC;QACH,CAAC;QAAC,MAAM,CAAC,CAAC,oCAAoC,CAAC,CAAC;IAClD,CAAC;IAED,sBAAsB;IACtB,MAAM,KAAK,GAAG,MAAM,iBAAiB,CAAC,GAAG,EAAE,KAAK,CAAC,UAAU,CAAC,CAAC;IAE7D,
|
|
1
|
+
{"version":3,"file":"next-action.js","sourceRoot":"","sources":["../../../src/cli/guards/next-action.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { HookInput, GuardResult } from '../../core/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Phase-boundary guard: fires PreToolUse on Bash.
|
|
4
|
+
* Blocks starting a sprint in Phase N+1 if Phase N cleanup is incomplete.
|
|
5
|
+
*/
|
|
6
|
+
export declare function phaseBoundaryGuard(input: HookInput, cwd: string): Promise<GuardResult>;
|
|
7
|
+
//# sourceMappingURL=phase-boundary.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phase-boundary.d.ts","sourceRoot":"","sources":["../../../src/cli/guards/phase-boundary.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAc,MAAM,qBAAqB,CAAC;AAU9E;;;GAGG;AACH,wBAAsB,kBAAkB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAmF5F"}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { loadConfig, parseRoadmap } from '../../core/index.js';
|
|
4
|
+
import { isPhaseComplete, pendingPhaseGates } from '../phase-cleanup.js';
|
|
5
|
+
/** Extract phase number from name like "Phase 7 — Helmsman 3D". Falls back to array index + 1. */
|
|
6
|
+
function extractPhaseNumber(name, index) {
|
|
7
|
+
const match = name.match(/Phase\s+(\d+)/i);
|
|
8
|
+
return match ? parseInt(match[1], 10) : index + 1;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Phase-boundary guard: fires PreToolUse on Bash.
|
|
12
|
+
* Blocks starting a sprint in Phase N+1 if Phase N cleanup is incomplete.
|
|
13
|
+
*/
|
|
14
|
+
export async function phaseBoundaryGuard(input, cwd) {
|
|
15
|
+
const command = input.tool_input?.command ?? '';
|
|
16
|
+
// Only match sprint-start or claim commands
|
|
17
|
+
if (!/\bslope\s+(sprint\s+start|claim)\b/.test(command))
|
|
18
|
+
return {};
|
|
19
|
+
// Parse target sprint number from command args
|
|
20
|
+
const sprintMatch = command.match(/--sprint[=\s]+(\d+)/i) ??
|
|
21
|
+
command.match(/\bS(\d+)\b/i) ??
|
|
22
|
+
command.match(/--target[=\s]+S?(\d+)/i);
|
|
23
|
+
// If we can't determine the target sprint, allow (don't block blindly)
|
|
24
|
+
if (!sprintMatch)
|
|
25
|
+
return {};
|
|
26
|
+
const targetSprint = parseInt(sprintMatch[1], 10);
|
|
27
|
+
// Load roadmap to determine phase mapping
|
|
28
|
+
const config = loadConfig(cwd);
|
|
29
|
+
let roadmap;
|
|
30
|
+
try {
|
|
31
|
+
const roadmapPath = join(cwd, config.roadmapPath);
|
|
32
|
+
if (!existsSync(roadmapPath))
|
|
33
|
+
return {};
|
|
34
|
+
const raw = JSON.parse(readFileSync(roadmapPath, 'utf8'));
|
|
35
|
+
const result = parseRoadmap(raw);
|
|
36
|
+
roadmap = result.roadmap;
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
return {
|
|
40
|
+
decision: 'deny',
|
|
41
|
+
blockReason: 'SLOPE phase-boundary: Cannot determine phase — roadmap unreadable. Run `slope roadmap validate`.',
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
if (!roadmap || !roadmap.phases)
|
|
45
|
+
return {};
|
|
46
|
+
// Build phase-to-number mapping (RoadmapPhase has name + sprints[], no id)
|
|
47
|
+
const phaseNumbers = roadmap.phases.map((p, i) => extractPhaseNumber(p.name, i));
|
|
48
|
+
// Find which phase the target sprint belongs to
|
|
49
|
+
let targetPhaseIdx = -1;
|
|
50
|
+
for (let i = 0; i < roadmap.phases.length; i++) {
|
|
51
|
+
if (Array.isArray(roadmap.phases[i].sprints) && roadmap.phases[i].sprints.includes(targetSprint)) {
|
|
52
|
+
targetPhaseIdx = i;
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
if (targetPhaseIdx < 0)
|
|
57
|
+
return {}; // Sprint not in any phase — allow
|
|
58
|
+
if (targetPhaseIdx === 0)
|
|
59
|
+
return {}; // First phase — no previous phase to check
|
|
60
|
+
const targetPhaseNum = phaseNumbers[targetPhaseIdx];
|
|
61
|
+
// Use array order (not phase number arithmetic) to find the previous phase.
|
|
62
|
+
// This correctly handles non-sequential numbering: [Phase 1, Phase 3] → check Phase 1 before Phase 3.
|
|
63
|
+
const prevPhaseIdx = targetPhaseIdx - 1;
|
|
64
|
+
const prevPhaseNum = phaseNumbers[prevPhaseIdx];
|
|
65
|
+
// Check if previous phase cleanup is complete
|
|
66
|
+
if (isPhaseComplete(cwd, prevPhaseNum))
|
|
67
|
+
return {};
|
|
68
|
+
// Previous phase cleanup incomplete — block with suggestion
|
|
69
|
+
const pending = pendingPhaseGates(cwd, prevPhaseNum);
|
|
70
|
+
const suggestion = {
|
|
71
|
+
id: 'phase-boundary',
|
|
72
|
+
title: 'Phase Boundary',
|
|
73
|
+
context: `Phase ${prevPhaseNum} cleanup is incomplete. Complete these gates before starting Sprint ${targetSprint} (Phase ${targetPhaseNum}).`,
|
|
74
|
+
options: [
|
|
75
|
+
...pending.map((gate, i) => ({
|
|
76
|
+
id: `gate-${i}`,
|
|
77
|
+
label: gate,
|
|
78
|
+
})),
|
|
79
|
+
{
|
|
80
|
+
id: 'override',
|
|
81
|
+
label: 'Mark phase complete (manual override)',
|
|
82
|
+
command: `slope phase complete ${prevPhaseNum}`,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
requiresDecision: true,
|
|
86
|
+
priority: 'critical',
|
|
87
|
+
};
|
|
88
|
+
return {
|
|
89
|
+
decision: 'deny',
|
|
90
|
+
suggestion,
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=phase-boundary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"phase-boundary.js","sourceRoot":"","sources":["../../../src/cli/guards/phase-boundary.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { HookInput, GuardResult } from '../../core/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Post-push guard: fires PostToolUse on Bash.
|
|
4
|
+
* After a successful git push, suggests next workflow step.
|
|
5
|
+
* Context-only (non-blocking), fires once per session.
|
|
6
|
+
*/
|
|
7
|
+
export declare function postPushGuard(input: HookInput, cwd: string): Promise<GuardResult>;
|
|
8
|
+
//# sourceMappingURL=post-push.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"post-push.d.ts","sourceRoot":"","sources":["../../../src/cli/guards/post-push.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAc,MAAM,qBAAqB,CAAC;AAI9E;;;;GAIG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAyFvF"}
|