@slope-dev/slope 1.17.0 → 1.20.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/guard.d.ts.map +1 -1
- package/dist/cli/commands/guard.js +36 -11
- package/dist/cli/commands/guard.js.map +1 -1
- package/dist/cli/commands/loop.js +1 -1
- package/dist/cli/commands/review-state.d.ts.map +1 -1
- package/dist/cli/commands/review-state.js +6 -45
- package/dist/cli/commands/review-state.js.map +1 -1
- package/dist/cli/commands/review.d.ts.map +1 -1
- package/dist/cli/commands/review.js +3 -0
- package/dist/cli/commands/review.js.map +1 -1
- package/dist/cli/commands/sprint.d.ts +2 -0
- package/dist/cli/commands/sprint.d.ts.map +1 -0
- package/dist/cli/commands/sprint.js +96 -0
- package/dist/cli/commands/sprint.js.map +1 -0
- package/dist/cli/commands/validate.d.ts.map +1 -1
- package/dist/cli/commands/validate.js +7 -1
- package/dist/cli/commands/validate.js.map +1 -1
- package/dist/cli/guards/next-action.d.ts.map +1 -1
- package/dist/cli/guards/next-action.js +15 -0
- package/dist/cli/guards/next-action.js.map +1 -1
- package/dist/cli/guards/plan-analysis.d.ts +34 -0
- package/dist/cli/guards/plan-analysis.d.ts.map +1 -0
- package/dist/cli/guards/plan-analysis.js +102 -0
- package/dist/cli/guards/plan-analysis.js.map +1 -0
- package/dist/cli/guards/pr-review.d.ts.map +1 -1
- package/dist/cli/guards/pr-review.js +7 -0
- package/dist/cli/guards/pr-review.js.map +1 -1
- package/dist/cli/guards/review-tier.d.ts +4 -2
- package/dist/cli/guards/review-tier.d.ts.map +1 -1
- package/dist/cli/guards/review-tier.js +104 -60
- package/dist/cli/guards/review-tier.js.map +1 -1
- package/dist/cli/guards/sprint-completion.d.ts +11 -0
- package/dist/cli/guards/sprint-completion.d.ts.map +1 -0
- package/dist/cli/guards/sprint-completion.js +121 -0
- package/dist/cli/guards/sprint-completion.js.map +1 -0
- package/dist/cli/guards/workflow-gate.d.ts.map +1 -1
- package/dist/cli/guards/workflow-gate.js +9 -1
- package/dist/cli/guards/workflow-gate.js.map +1 -1
- package/dist/cli/index.js +8 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/loop/continuous.d.ts.map +1 -1
- package/dist/cli/loop/continuous.js +36 -0
- package/dist/cli/loop/continuous.js.map +1 -1
- package/dist/cli/loop/executor.d.ts.map +1 -1
- package/dist/cli/loop/executor.js +92 -50
- package/dist/cli/loop/executor.js.map +1 -1
- package/dist/cli/loop/guard-runner.d.ts +19 -3
- package/dist/cli/loop/guard-runner.d.ts.map +1 -1
- package/dist/cli/loop/guard-runner.js +108 -1
- package/dist/cli/loop/guard-runner.js.map +1 -1
- package/dist/cli/loop/model-selector.d.ts.map +1 -1
- package/dist/cli/loop/model-selector.js +3 -2
- package/dist/cli/loop/model-selector.js.map +1 -1
- package/dist/cli/loop/planner.d.ts +21 -0
- package/dist/cli/loop/planner.d.ts.map +1 -0
- package/dist/cli/loop/planner.js +298 -0
- package/dist/cli/loop/planner.js.map +1 -0
- package/dist/cli/loop/pr-lifecycle.d.ts +6 -4
- package/dist/cli/loop/pr-lifecycle.d.ts.map +1 -1
- package/dist/cli/loop/pr-lifecycle.js +19 -17
- package/dist/cli/loop/pr-lifecycle.js.map +1 -1
- package/dist/cli/loop/staging.d.ts +19 -0
- package/dist/cli/loop/staging.d.ts.map +1 -0
- package/dist/cli/loop/staging.js +125 -0
- package/dist/cli/loop/staging.js.map +1 -0
- package/dist/cli/loop/types.d.ts +31 -1
- package/dist/cli/loop/types.d.ts.map +1 -1
- package/dist/cli/loop/worktree.d.ts +1 -1
- package/dist/cli/loop/worktree.d.ts.map +1 -1
- package/dist/cli/loop/worktree.js +5 -2
- package/dist/cli/loop/worktree.js.map +1 -1
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/cli/registry.js +1 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/cli/sprint-state.d.ts +27 -0
- package/dist/cli/sprint-state.d.ts.map +1 -0
- package/dist/cli/sprint-state.js +88 -0
- package/dist/cli/sprint-state.js.map +1 -0
- package/dist/core/guard.d.ts +1 -1
- package/dist/core/guard.d.ts.map +1 -1
- package/dist/core/guard.js +26 -4
- package/dist/core/guard.js.map +1 -1
- package/package.json +1 -1
|
@@ -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;
|
|
1
|
+
{"version":3,"file":"next-action.js","sourceRoot":"","sources":["../../../src/cli/guards/next-action.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/** Result of finding a plan file */
|
|
2
|
+
export interface PlanFile {
|
|
3
|
+
path: string;
|
|
4
|
+
content: string;
|
|
5
|
+
}
|
|
6
|
+
/** Extracted ticket info for specialist selection */
|
|
7
|
+
export interface TicketInfo {
|
|
8
|
+
title: string;
|
|
9
|
+
filePatterns: string[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Find the most recently modified plan file in .claude/plans/.
|
|
13
|
+
* Searches repo-local first ({cwd}/.claude/plans/), then falls back
|
|
14
|
+
* to global (~/.claude/plans/) since Claude Code writes plans there.
|
|
15
|
+
*/
|
|
16
|
+
export declare function findPlanContent(cwd: string): PlanFile | null;
|
|
17
|
+
/**
|
|
18
|
+
* Count tickets in plan content.
|
|
19
|
+
* Matches `### T\d+:` or `### S\d+-\d+:` patterns, falls back to all H3 headers.
|
|
20
|
+
*/
|
|
21
|
+
export declare function countTickets(content: string): number;
|
|
22
|
+
/**
|
|
23
|
+
* Count distinct packages/ references in plan content.
|
|
24
|
+
*/
|
|
25
|
+
export declare function countPackageRefs(content: string): number;
|
|
26
|
+
/**
|
|
27
|
+
* Extract backtick-wrapped file paths from plan content.
|
|
28
|
+
*/
|
|
29
|
+
export declare function extractFilePatterns(content: string): string[];
|
|
30
|
+
/**
|
|
31
|
+
* Extract ticket titles and their associated file references for specialist selection.
|
|
32
|
+
*/
|
|
33
|
+
export declare function extractTicketInfo(content: string): TicketInfo[];
|
|
34
|
+
//# sourceMappingURL=plan-analysis.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-analysis.d.ts","sourceRoot":"","sources":["../../../src/cli/guards/plan-analysis.ts"],"names":[],"mappings":"AAIA,oCAAoC;AACpC,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,qDAAqD;AACrD,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,YAAY,EAAE,MAAM,EAAE,CAAC;CACxB;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAqC5D;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAOpD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAKxD;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAK7D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,GAAG,UAAU,EAAE,CAoB/D"}
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { existsSync, readFileSync, readdirSync, statSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
/**
|
|
5
|
+
* Find the most recently modified plan file in .claude/plans/.
|
|
6
|
+
* Searches repo-local first ({cwd}/.claude/plans/), then falls back
|
|
7
|
+
* to global (~/.claude/plans/) since Claude Code writes plans there.
|
|
8
|
+
*/
|
|
9
|
+
export function findPlanContent(cwd) {
|
|
10
|
+
const repoLocal = join(cwd, '.claude', 'plans');
|
|
11
|
+
const global = join(homedir(), '.claude', 'plans');
|
|
12
|
+
// Deduplicate when cwd is the home directory
|
|
13
|
+
const searchDirs = [
|
|
14
|
+
{ dir: repoLocal, relative: true },
|
|
15
|
+
];
|
|
16
|
+
if (global.replace(/\\/g, '/') !== repoLocal.replace(/\\/g, '/')) {
|
|
17
|
+
searchDirs.push({ dir: global, relative: false });
|
|
18
|
+
}
|
|
19
|
+
for (const { dir: plansDir, relative } of searchDirs) {
|
|
20
|
+
if (!existsSync(plansDir))
|
|
21
|
+
continue;
|
|
22
|
+
try {
|
|
23
|
+
const files = readdirSync(plansDir)
|
|
24
|
+
.filter(f => f.endsWith('.md'))
|
|
25
|
+
.map(f => ({
|
|
26
|
+
name: f,
|
|
27
|
+
// Repo-local: relative path (preserves original behavior for review-state storage)
|
|
28
|
+
// Global: absolute path (needed since it's outside the repo)
|
|
29
|
+
path: relative
|
|
30
|
+
? join('.claude', 'plans', f).replace(/\\/g, '/')
|
|
31
|
+
: join(plansDir, f).replace(/\\/g, '/'),
|
|
32
|
+
fullPath: join(plansDir, f),
|
|
33
|
+
mtime: (() => { try {
|
|
34
|
+
return statSync(join(plansDir, f)).mtimeMs;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
return 0;
|
|
38
|
+
} })(),
|
|
39
|
+
}))
|
|
40
|
+
.sort((a, b) => b.mtime - a.mtime);
|
|
41
|
+
if (files.length > 0) {
|
|
42
|
+
return { path: files[0].path, content: readFileSync(files[0].fullPath, 'utf8') };
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch { /* can't read plans dir */ }
|
|
46
|
+
}
|
|
47
|
+
return null;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Count tickets in plan content.
|
|
51
|
+
* Matches `### T\d+:` or `### S\d+-\d+:` patterns, falls back to all H3 headers.
|
|
52
|
+
*/
|
|
53
|
+
export function countTickets(content) {
|
|
54
|
+
const ticketHeaders = content.match(/^###\s+(?:T\d+|S\d+-\d+):/gm) ?? [];
|
|
55
|
+
if (ticketHeaders.length > 0)
|
|
56
|
+
return ticketHeaders.length;
|
|
57
|
+
// Fallback: count ### level headers that look like tickets
|
|
58
|
+
const h3Headers = content.match(/^###\s+/gm) ?? [];
|
|
59
|
+
return h3Headers.length;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Count distinct packages/ references in plan content.
|
|
63
|
+
*/
|
|
64
|
+
export function countPackageRefs(content) {
|
|
65
|
+
const refs = new Set();
|
|
66
|
+
const matches = content.matchAll(/packages\/(\w[\w-]*)/g);
|
|
67
|
+
for (const m of matches)
|
|
68
|
+
refs.add(m[1]);
|
|
69
|
+
return refs.size;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Extract backtick-wrapped file paths from plan content.
|
|
73
|
+
*/
|
|
74
|
+
export function extractFilePatterns(content) {
|
|
75
|
+
const patterns = [];
|
|
76
|
+
const matches = content.matchAll(/`([^`]+\.[a-z]+)`/g);
|
|
77
|
+
for (const m of matches)
|
|
78
|
+
patterns.push(m[1]);
|
|
79
|
+
return patterns;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Extract ticket titles and their associated file references for specialist selection.
|
|
83
|
+
*/
|
|
84
|
+
export function extractTicketInfo(content) {
|
|
85
|
+
const tickets = [];
|
|
86
|
+
// Split on ticket headers (### T\d+: or ### S\d+-\d+:)
|
|
87
|
+
const headerPattern = /^###\s+(?:T\d+|S\d+-\d+):\s*(.+)$/gm;
|
|
88
|
+
const headers = [];
|
|
89
|
+
let match;
|
|
90
|
+
while ((match = headerPattern.exec(content)) !== null) {
|
|
91
|
+
headers.push({ title: match[1].trim(), index: match.index });
|
|
92
|
+
}
|
|
93
|
+
for (let i = 0; i < headers.length; i++) {
|
|
94
|
+
const start = headers[i].index;
|
|
95
|
+
const end = i + 1 < headers.length ? headers[i + 1].index : content.length;
|
|
96
|
+
const section = content.slice(start, end);
|
|
97
|
+
const filePatterns = extractFilePatterns(section);
|
|
98
|
+
tickets.push({ title: headers[i].title, filePatterns });
|
|
99
|
+
}
|
|
100
|
+
return tickets;
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=plan-analysis.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-analysis.js","sourceRoot":"","sources":["../../../src/cli/guards/plan-analysis.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-review.d.ts","sourceRoot":"","sources":["../../../src/cli/guards/pr-review.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElE;;;GAGG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,
|
|
1
|
+
{"version":3,"file":"pr-review.d.ts","sourceRoot":"","sources":["../../../src/cli/guards/pr-review.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElE;;;GAGG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAqCxF"}
|
|
@@ -28,6 +28,13 @@ export async function prReviewGuard(input, _cwd) {
|
|
|
28
28
|
'5. Skip / Merge Now — No review needed, proceed to merge',
|
|
29
29
|
'',
|
|
30
30
|
'Wait for the user\'s choice before taking any further action.',
|
|
31
|
+
'',
|
|
32
|
+
'After the review is complete, capture findings:',
|
|
33
|
+
'1. For each issue found: `slope review findings add --type=<type> --ticket=<key> --severity=<sev> --description="..."`',
|
|
34
|
+
'2. After all findings recorded: `slope review amend` to apply to scorecard',
|
|
35
|
+
'3. Run `slope distill --auto` to promote recurring patterns',
|
|
36
|
+
'',
|
|
37
|
+
'Review type to finding type mapping: architect→architect, code→code',
|
|
31
38
|
].join('\n'),
|
|
32
39
|
};
|
|
33
40
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-review.js","sourceRoot":"","sources":["../../../src/cli/guards/pr-review.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAgB,EAAE,IAAY;IAChE,MAAM,OAAO,GAAI,KAAK,CAAC,UAAU,EAAE,OAAkB,IAAI,EAAE,CAAC;IAC5D,MAAM,QAAQ,GAAI,KAAK,CAAC,aAAa,EAAE,MAAiB,IAAK,KAAK,CAAC,aAAa,EAAE,MAAiB,IAAI,EAAE,CAAC;IAE1G,wCAAwC;IACxC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;QAAE,OAAO,EAAE,CAAC;IAEjD,qDAAqD;IACrD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IAEjF,+BAA+B;IAC/B,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAC9E,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAEhD,OAAO;QACL,OAAO,EAAE;YACP,qDAAqD,KAAK,IAAI;YAC9D,EAAE;YACF,mGAAmG;YACnG,wBAAwB;YACxB,EAAE;YACF,gEAAgE;YAChE,iEAAiE;YACjE,wDAAwD;YACxD,mEAAmE;YACnE,0DAA0D;YAC1D,EAAE;YACF,+DAA+D;
|
|
1
|
+
{"version":3,"file":"pr-review.js","sourceRoot":"","sources":["../../../src/cli/guards/pr-review.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAgB,EAAE,IAAY;IAChE,MAAM,OAAO,GAAI,KAAK,CAAC,UAAU,EAAE,OAAkB,IAAI,EAAE,CAAC;IAC5D,MAAM,QAAQ,GAAI,KAAK,CAAC,aAAa,EAAE,MAAiB,IAAK,KAAK,CAAC,aAAa,EAAE,MAAiB,IAAI,EAAE,CAAC;IAE1G,wCAAwC;IACxC,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC;QAAE,OAAO,EAAE,CAAC;IAEjD,qDAAqD;IACrD,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,QAAQ,CAAC;QAAE,OAAO,EAAE,CAAC;IAEjF,+BAA+B;IAC/B,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;IAC9E,MAAM,KAAK,GAAG,QAAQ,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC;IAEhD,OAAO;QACL,OAAO,EAAE;YACP,qDAAqD,KAAK,IAAI;YAC9D,EAAE;YACF,mGAAmG;YACnG,wBAAwB;YACxB,EAAE;YACF,gEAAgE;YAChE,iEAAiE;YACjE,wDAAwD;YACxD,mEAAmE;YACnE,0DAA0D;YAC1D,EAAE;YACF,+DAA+D;YAC/D,EAAE;YACF,iDAAiD;YACjD,wHAAwH;YACxH,4EAA4E;YAC5E,6DAA6D;YAC7D,EAAE;YACF,qEAAqE;SACtE,CAAC,IAAI,CAAC,IAAI,CAAC;KACb,CAAC;AACJ,CAAC"}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { HookInput, GuardResult } from '../../core/index.js';
|
|
2
2
|
/**
|
|
3
|
-
* Review-tier guard: fires
|
|
4
|
-
*
|
|
3
|
+
* Review-tier guard: fires PostToolUse on Write.
|
|
4
|
+
* When a plan file is written to .claude/plans/*.md, recommends review tier
|
|
5
|
+
* with specialist reviewers, surfaces relevant gotchas, and instructs
|
|
6
|
+
* Claude to use AskUserQuestion for review setup.
|
|
5
7
|
*/
|
|
6
8
|
export declare function reviewTierGuard(input: HookInput, cwd: string): Promise<GuardResult>;
|
|
7
9
|
//# sourceMappingURL=review-tier.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review-tier.d.ts","sourceRoot":"","sources":["../../../src/cli/guards/review-tier.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"review-tier.d.ts","sourceRoot":"","sources":["../../../src/cli/guards/review-tier.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAoBlE;;;;;GAKG;AACH,wBAAsB,eAAe,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAgHzF"}
|
|
@@ -1,20 +1,45 @@
|
|
|
1
|
-
import { existsSync, readFileSync
|
|
1
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
2
2
|
import { join } from 'node:path';
|
|
3
|
+
import { selectSpecialists } from '../../core/index.js';
|
|
4
|
+
import { loadConfig } from '../config.js';
|
|
5
|
+
import { loadSprintState, saveSprintState, createSprintState } from '../sprint-state.js';
|
|
6
|
+
import { findPlanContent, countTickets, countPackageRefs, extractFilePatterns, extractTicketInfo, } from './plan-analysis.js';
|
|
3
7
|
/**
|
|
4
|
-
* Review-tier guard: fires
|
|
5
|
-
*
|
|
8
|
+
* Review-tier guard: fires PostToolUse on Write.
|
|
9
|
+
* When a plan file is written to .claude/plans/*.md, recommends review tier
|
|
10
|
+
* with specialist reviewers, surfaces relevant gotchas, and instructs
|
|
11
|
+
* Claude to use AskUserQuestion for review setup.
|
|
6
12
|
*/
|
|
7
13
|
export async function reviewTierGuard(input, cwd) {
|
|
8
|
-
//
|
|
9
|
-
const
|
|
10
|
-
if (!
|
|
14
|
+
// Only fire when a plan file is written
|
|
15
|
+
const filePath = input.tool_input?.file_path;
|
|
16
|
+
if (!filePath)
|
|
17
|
+
return {};
|
|
18
|
+
// Check if the written file is a plan file
|
|
19
|
+
const normalizedPath = filePath.replace(/\\/g, '/');
|
|
20
|
+
if (!normalizedPath.includes('.claude/plans/') || !normalizedPath.endsWith('.md')) {
|
|
21
|
+
return {};
|
|
22
|
+
}
|
|
23
|
+
// Read the plan content — prefer the just-written file path directly,
|
|
24
|
+
// since findPlanContent(cwd) only searches repo-local .claude/plans/ and
|
|
25
|
+
// Claude Code writes plans to ~/.claude/plans/ (global user directory).
|
|
26
|
+
let plan = null;
|
|
27
|
+
try {
|
|
28
|
+
const content = readFileSync(filePath, 'utf8');
|
|
29
|
+
plan = { path: normalizedPath, content };
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
// File not readable — fall back to directory scan
|
|
33
|
+
plan = findPlanContent(cwd);
|
|
34
|
+
}
|
|
35
|
+
if (!plan)
|
|
11
36
|
return {};
|
|
12
37
|
// Analyze the plan
|
|
13
|
-
const ticketCount = countTickets(
|
|
14
|
-
const packageRefs = countPackageRefs(
|
|
15
|
-
const hasSchemaOrApi = /\b(schema|migration|api|endpoint)\b/i.test(
|
|
16
|
-
const hasInfra = /\b(infrastructure|new package|new service|architect)\b/i.test(
|
|
17
|
-
const isResearchOrDocs = /^#+\s*(research|docs|documentation|infra|spike)\b/im.test(
|
|
38
|
+
const ticketCount = countTickets(plan.content);
|
|
39
|
+
const packageRefs = countPackageRefs(plan.content);
|
|
40
|
+
const hasSchemaOrApi = /\b(schema|migration|api|endpoint)\b/i.test(plan.content);
|
|
41
|
+
const hasInfra = /\b(infrastructure|new package|new service|architect)\b/i.test(plan.content);
|
|
42
|
+
const isResearchOrDocs = /^#+\s*(research|docs|documentation|infra|spike)\b/im.test(plan.content)
|
|
18
43
|
&& ticketCount === 0;
|
|
19
44
|
// Determine recommended tier
|
|
20
45
|
let tier;
|
|
@@ -32,77 +57,96 @@ export async function reviewTierGuard(input, cwd) {
|
|
|
32
57
|
rounds = 3;
|
|
33
58
|
}
|
|
34
59
|
else {
|
|
35
|
-
// 3-4 tickets, or multi-package, or schema/API changes
|
|
36
60
|
tier = 'Standard';
|
|
37
61
|
rounds = 2;
|
|
38
62
|
}
|
|
39
|
-
// Check if review-state.json already
|
|
63
|
+
// Check if review-state.json already meets/exceeds tier
|
|
40
64
|
const statePath = join(cwd, '.slope', 'review-state.json');
|
|
41
65
|
if (existsSync(statePath)) {
|
|
42
66
|
try {
|
|
43
67
|
const state = JSON.parse(readFileSync(statePath, 'utf8'));
|
|
44
68
|
if (state.rounds_required >= rounds) {
|
|
45
|
-
// Already set to at least the recommended level — silent passthrough
|
|
46
69
|
return {};
|
|
47
70
|
}
|
|
48
71
|
}
|
|
49
|
-
catch { /* malformed — proceed
|
|
72
|
+
catch { /* malformed — proceed */ }
|
|
50
73
|
}
|
|
51
|
-
// Build
|
|
74
|
+
// Build scope description
|
|
52
75
|
const scopeDesc = [
|
|
53
76
|
`${ticketCount} ticket${ticketCount !== 1 ? 's' : ''}`,
|
|
54
77
|
packageRefs > 1 ? `${packageRefs} packages` : null,
|
|
55
78
|
hasSchemaOrApi ? 'schema/API changes' : null,
|
|
56
79
|
hasInfra ? 'new infrastructure' : null,
|
|
57
80
|
].filter(Boolean).join(', ');
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
81
|
+
// Select specialists from ticket info
|
|
82
|
+
const ticketInfo = extractTicketInfo(plan.content);
|
|
83
|
+
const specialists = selectSpecialists(ticketInfo);
|
|
84
|
+
const specialistList = specialists.length > 0 ? specialists.join(', ') : 'none detected';
|
|
85
|
+
// Load relevant gotchas (capped at 5)
|
|
86
|
+
const gotchas = loadRelevantGotchas(cwd, plan.content);
|
|
87
|
+
// Build context
|
|
88
|
+
const lines = [
|
|
89
|
+
`SLOPE plan-review: Plan detected with ${ticketCount} tickets, ${scopeDesc}.`,
|
|
90
|
+
`Recommended tier: ${tier} (${rounds} round${rounds !== 1 ? 's' : ''}).`,
|
|
91
|
+
`Recommended reviewers: architect + ${specialistList}.`,
|
|
92
|
+
];
|
|
93
|
+
if (gotchas.length > 0) {
|
|
94
|
+
lines.push('');
|
|
95
|
+
lines.push('Relevant gotchas from past sprints:');
|
|
96
|
+
for (const g of gotchas) {
|
|
97
|
+
lines.push(` - ${g}`);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
lines.push('');
|
|
101
|
+
lines.push('IMPORTANT: You MUST now ask the user how they want to handle the plan review using AskUserQuestion.');
|
|
102
|
+
lines.push('Present these options:');
|
|
103
|
+
lines.push(`1. Architect + ${specialistList} review (Recommended)`);
|
|
104
|
+
lines.push('2. Architect review only');
|
|
105
|
+
lines.push('3. Custom reviewers — user specifies');
|
|
106
|
+
lines.push('4. Skip review');
|
|
107
|
+
// Create sprint-state if it doesn't already exist
|
|
108
|
+
if (!loadSprintState(cwd)) {
|
|
109
|
+
// Try to extract sprint number from plan content
|
|
110
|
+
const sprintMatch = plan.content.match(/Sprint\s+(\d+)/i);
|
|
111
|
+
const sprintNumber = sprintMatch ? parseInt(sprintMatch[1], 10) : 0;
|
|
112
|
+
if (sprintNumber > 0) {
|
|
113
|
+
const state = createSprintState(sprintNumber, 'planning');
|
|
114
|
+
saveSprintState(cwd, state);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return { context: lines.join('\n') };
|
|
61
118
|
}
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
if (
|
|
83
|
-
|
|
119
|
+
/**
|
|
120
|
+
* Load gotchas from common-issues.json that are relevant to plan file patterns.
|
|
121
|
+
* Returns at most 5 entries.
|
|
122
|
+
*/
|
|
123
|
+
function loadRelevantGotchas(cwd, planContent) {
|
|
124
|
+
try {
|
|
125
|
+
const config = loadConfig(cwd);
|
|
126
|
+
const issuesPath = join(cwd, config.commonIssuesPath);
|
|
127
|
+
if (!existsSync(issuesPath))
|
|
128
|
+
return [];
|
|
129
|
+
const issues = JSON.parse(readFileSync(issuesPath, 'utf8'));
|
|
130
|
+
const filePatterns = extractFilePatterns(planContent);
|
|
131
|
+
const warnings = [];
|
|
132
|
+
for (const pattern of issues.recurring_patterns) {
|
|
133
|
+
const text = `${pattern.title} ${pattern.description} ${pattern.prevention}`.toLowerCase();
|
|
134
|
+
// Check if any plan file pattern segments match the issue
|
|
135
|
+
const isRelevant = filePatterns.some(fp => {
|
|
136
|
+
const segments = fp.toLowerCase().split('/').filter(Boolean);
|
|
137
|
+
return segments.some(seg => text.includes(seg));
|
|
138
|
+
});
|
|
139
|
+
if (isRelevant) {
|
|
140
|
+
const lastSprint = Math.max(...pattern.sprints_hit);
|
|
141
|
+
warnings.push(`[${pattern.category}] ${pattern.title} (last: S${lastSprint}) — ${pattern.prevention.slice(0, 100)}`);
|
|
84
142
|
}
|
|
143
|
+
if (warnings.length >= 5)
|
|
144
|
+
break;
|
|
85
145
|
}
|
|
86
|
-
|
|
146
|
+
return warnings;
|
|
87
147
|
}
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
function countTickets(content) {
|
|
91
|
-
// Match ticket patterns: ### S\d+-\d+, ### Ticket, numbered ticket headers
|
|
92
|
-
const ticketHeaders = content.match(/^###\s+S\d+-\d+/gm) ?? [];
|
|
93
|
-
if (ticketHeaders.length > 0)
|
|
94
|
-
return ticketHeaders.length;
|
|
95
|
-
// Fallback: count ### level headers that look like tickets
|
|
96
|
-
const h3Headers = content.match(/^###\s+/gm) ?? [];
|
|
97
|
-
return h3Headers.length;
|
|
98
|
-
}
|
|
99
|
-
function countPackageRefs(content) {
|
|
100
|
-
// Count distinct packages/ references
|
|
101
|
-
const refs = new Set();
|
|
102
|
-
const matches = content.matchAll(/packages\/(\w[\w-]*)/g);
|
|
103
|
-
for (const m of matches) {
|
|
104
|
-
refs.add(m[1]);
|
|
148
|
+
catch {
|
|
149
|
+
return [];
|
|
105
150
|
}
|
|
106
|
-
return refs.size;
|
|
107
151
|
}
|
|
108
152
|
//# sourceMappingURL=review-tier.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"review-tier.js","sourceRoot":"","sources":["../../../src/cli/guards/review-tier.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EAAE,
|
|
1
|
+
{"version":3,"file":"review-tier.js","sourceRoot":"","sources":["../../../src/cli/guards/review-tier.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { HookInput, GuardResult } from '../../core/index.js';
|
|
2
|
+
/**
|
|
3
|
+
* Sprint-completion guard: enforces post-implementation gates.
|
|
4
|
+
*
|
|
5
|
+
* Single handler, three hook points (branches on hook_event_name):
|
|
6
|
+
* - PreToolUse:Bash — blocks `gh pr create` if gates incomplete
|
|
7
|
+
* - Stop — blocks session end if mid-sprint with incomplete gates
|
|
8
|
+
* - PostToolUse:Bash — auto-detects test pass and marks gate
|
|
9
|
+
*/
|
|
10
|
+
export declare function sprintCompletionGuard(input: HookInput, cwd: string): Promise<GuardResult>;
|
|
11
|
+
//# sourceMappingURL=sprint-completion.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sprint-completion.d.ts","sourceRoot":"","sources":["../../../src/cli/guards/sprint-completion.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAGlE;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAgB/F"}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { loadSprintState, updateGate, isSprintComplete, pendingGates } from '../sprint-state.js';
|
|
3
|
+
/**
|
|
4
|
+
* Sprint-completion guard: enforces post-implementation gates.
|
|
5
|
+
*
|
|
6
|
+
* Single handler, three hook points (branches on hook_event_name):
|
|
7
|
+
* - PreToolUse:Bash — blocks `gh pr create` if gates incomplete
|
|
8
|
+
* - Stop — blocks session end if mid-sprint with incomplete gates
|
|
9
|
+
* - PostToolUse:Bash — auto-detects test pass and marks gate
|
|
10
|
+
*/
|
|
11
|
+
export async function sprintCompletionGuard(input, cwd) {
|
|
12
|
+
const event = input.hook_event_name;
|
|
13
|
+
if (event === 'PreToolUse') {
|
|
14
|
+
return handlePreToolUse(input, cwd);
|
|
15
|
+
}
|
|
16
|
+
if (event === 'Stop') {
|
|
17
|
+
return handleStop(cwd);
|
|
18
|
+
}
|
|
19
|
+
if (event === 'PostToolUse') {
|
|
20
|
+
return handlePostToolUse(input, cwd);
|
|
21
|
+
}
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
/** Check if sprint-state matches the current branch. Returns a warning string or null. */
|
|
25
|
+
function checkStaleness(sprint, cwd) {
|
|
26
|
+
try {
|
|
27
|
+
const branch = execSync('git rev-parse --abbrev-ref HEAD', { cwd, encoding: 'utf8' }).trim();
|
|
28
|
+
// Match patterns like S22, s22, sprint-22, worktree-s22-*
|
|
29
|
+
const branchMatch = branch.match(/(?:^|[-/])s(?:print-?)?(\d+)/i);
|
|
30
|
+
if (branchMatch) {
|
|
31
|
+
const branchSprint = parseInt(branchMatch[1], 10);
|
|
32
|
+
if (branchSprint !== sprint) {
|
|
33
|
+
return `Warning: sprint-state is for Sprint ${sprint} but branch "${branch}" suggests Sprint ${branchSprint}. Run \`slope sprint reset\` if stale.`;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
// No sprint number in branch name — can't verify, don't warn
|
|
37
|
+
}
|
|
38
|
+
catch {
|
|
39
|
+
// git not available — skip check
|
|
40
|
+
}
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
/** Block `gh pr create` when gates are incomplete. */
|
|
44
|
+
function handlePreToolUse(input, cwd) {
|
|
45
|
+
const command = input.tool_input?.command;
|
|
46
|
+
if (!command || !command.includes('gh pr create'))
|
|
47
|
+
return {};
|
|
48
|
+
const state = loadSprintState(cwd);
|
|
49
|
+
if (!state)
|
|
50
|
+
return {};
|
|
51
|
+
if (state.phase === 'complete' || isSprintComplete(state))
|
|
52
|
+
return {};
|
|
53
|
+
const staleWarning = checkStaleness(state.sprint, cwd);
|
|
54
|
+
const pending = pendingGates(state);
|
|
55
|
+
const lines = [
|
|
56
|
+
`SLOPE sprint-completion: Cannot create PR — Sprint ${state.sprint} has incomplete gates:`,
|
|
57
|
+
...pending.map(g => ` - ${g}`),
|
|
58
|
+
'',
|
|
59
|
+
'Complete these gates before creating the PR.',
|
|
60
|
+
];
|
|
61
|
+
if (staleWarning)
|
|
62
|
+
lines.push('', staleWarning);
|
|
63
|
+
return {
|
|
64
|
+
decision: 'deny',
|
|
65
|
+
blockReason: lines.join('\n'),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/** Block session end when mid-sprint with incomplete gates. */
|
|
69
|
+
function handleStop(cwd) {
|
|
70
|
+
const state = loadSprintState(cwd);
|
|
71
|
+
if (!state)
|
|
72
|
+
return {};
|
|
73
|
+
if (state.phase === 'complete' || isSprintComplete(state))
|
|
74
|
+
return {};
|
|
75
|
+
// Only block during implementing/scoring phases — don't block during planning/reviewing
|
|
76
|
+
if (state.phase !== 'implementing' && state.phase !== 'scoring')
|
|
77
|
+
return {};
|
|
78
|
+
const staleWarning = checkStaleness(state.sprint, cwd);
|
|
79
|
+
const pending = pendingGates(state);
|
|
80
|
+
const lines = [
|
|
81
|
+
`SLOPE sprint-completion: Sprint ${state.sprint} is incomplete. Remaining gates:`,
|
|
82
|
+
...pending.map(g => ` - ${g}`),
|
|
83
|
+
'',
|
|
84
|
+
'Complete these before ending the session:',
|
|
85
|
+
' - `slope sprint gate tests` — mark tests passing',
|
|
86
|
+
' - `slope sprint gate code_review` — mark code review done',
|
|
87
|
+
' - `slope sprint gate architect_review` — mark architect review done',
|
|
88
|
+
' - `slope validate` — validates scorecard (auto-marks gate)',
|
|
89
|
+
' - `slope review` — generates review markdown (auto-marks gate)',
|
|
90
|
+
'',
|
|
91
|
+
'Or use `slope sprint reset` to clear sprint state if this sprint was abandoned.',
|
|
92
|
+
];
|
|
93
|
+
if (staleWarning)
|
|
94
|
+
lines.push('', staleWarning);
|
|
95
|
+
return { blockReason: lines.join('\n') };
|
|
96
|
+
}
|
|
97
|
+
/** Auto-detect test pass from Bash output and mark gate. */
|
|
98
|
+
function handlePostToolUse(input, cwd) {
|
|
99
|
+
const command = input.tool_input?.command;
|
|
100
|
+
if (!command)
|
|
101
|
+
return {};
|
|
102
|
+
// Check if command looks like a test runner
|
|
103
|
+
const isTestCommand = /\b(jest|vitest|bun\s+test|npx\s+jest|npx\s+vitest)\b/.test(command);
|
|
104
|
+
if (!isTestCommand)
|
|
105
|
+
return {};
|
|
106
|
+
const state = loadSprintState(cwd);
|
|
107
|
+
if (!state)
|
|
108
|
+
return {};
|
|
109
|
+
if (state.gates.tests)
|
|
110
|
+
return {}; // Already marked
|
|
111
|
+
// Check exit code — tool_response for Bash includes exit_code or stdout
|
|
112
|
+
const response = input.tool_response ?? {};
|
|
113
|
+
const exitCode = response.exit_code ?? response.exitCode;
|
|
114
|
+
// If exit code is explicitly 0, or if stdout contains pass indicators without failures
|
|
115
|
+
if (exitCode === 0 || exitCode === '0') {
|
|
116
|
+
updateGate(cwd, 'tests', true);
|
|
117
|
+
return { context: 'SLOPE: Tests passed — gate marked complete.' };
|
|
118
|
+
}
|
|
119
|
+
return {};
|
|
120
|
+
}
|
|
121
|
+
//# sourceMappingURL=sprint-completion.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sprint-completion.js","sourceRoot":"","sources":["../../../src/cli/guards/sprint-completion.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workflow-gate.d.ts","sourceRoot":"","sources":["../../../src/cli/guards/workflow-gate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;
|
|
1
|
+
{"version":3,"file":"workflow-gate.d.ts","sourceRoot":"","sources":["../../../src/cli/guards/workflow-gate.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AASlE;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,KAAK,EAAE,SAAS,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,CAAC,CAiC3F"}
|