@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,12 +1,83 @@
|
|
|
1
1
|
import { execSync, execFileSync } from 'node:child_process';
|
|
2
2
|
const SHA_PATTERN = /^[0-9a-f]{40}$/;
|
|
3
|
+
/**
|
|
4
|
+
* Check if the diff since preSha is within the ticket's module scope.
|
|
5
|
+
* A file is in scope if it matches a module path, is under a module directory,
|
|
6
|
+
* or is a test file for an in-scope module.
|
|
7
|
+
*/
|
|
8
|
+
export function isDiffInScope(preSha, modules, cwd) {
|
|
9
|
+
if (modules.length === 0)
|
|
10
|
+
return { inScope: true, outOfScopeFiles: [] };
|
|
11
|
+
let changedFiles;
|
|
12
|
+
try {
|
|
13
|
+
const output = execFileSync('git', ['diff', '--name-only', preSha, 'HEAD'], {
|
|
14
|
+
cwd,
|
|
15
|
+
encoding: 'utf8',
|
|
16
|
+
});
|
|
17
|
+
changedFiles = output.split('\n').map(f => f.trim()).filter(Boolean);
|
|
18
|
+
}
|
|
19
|
+
catch {
|
|
20
|
+
// If diff fails, assume in scope (don't block on errors)
|
|
21
|
+
return { inScope: true, outOfScopeFiles: [] };
|
|
22
|
+
}
|
|
23
|
+
if (changedFiles.length === 0)
|
|
24
|
+
return { inScope: true, outOfScopeFiles: [] };
|
|
25
|
+
const outOfScopeFiles = [];
|
|
26
|
+
for (const file of changedFiles) {
|
|
27
|
+
const fileInScope = modules.some(mod => {
|
|
28
|
+
// Direct path match
|
|
29
|
+
if (file === mod)
|
|
30
|
+
return true;
|
|
31
|
+
// File is under a module directory
|
|
32
|
+
if (file.startsWith(mod.endsWith('/') ? mod : mod + '/'))
|
|
33
|
+
return true;
|
|
34
|
+
// Test file for an in-scope module: test path mirrors src path
|
|
35
|
+
// e.g., "tests/cli/loop/planner.test.ts" is in scope for "src/cli/loop/planner.ts"
|
|
36
|
+
if (file.includes('.test.')) {
|
|
37
|
+
const srcEquiv = file
|
|
38
|
+
.replace(/^tests\//, 'src/')
|
|
39
|
+
.replace(/\.test\.(ts|js)$/, '.$1');
|
|
40
|
+
if (srcEquiv === mod)
|
|
41
|
+
return true;
|
|
42
|
+
if (srcEquiv.startsWith(mod + '/'))
|
|
43
|
+
return true;
|
|
44
|
+
// Also check if the test is under a module directory in tests/
|
|
45
|
+
const testDir = mod.replace(/^src\//, 'tests/');
|
|
46
|
+
if (file.startsWith(testDir + '/') || file.startsWith(testDir))
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
});
|
|
51
|
+
if (!fileInScope) {
|
|
52
|
+
outOfScopeFiles.push(file);
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
// Threshold: more than half of files must be out of scope to flag (warn-only)
|
|
56
|
+
const SCOPE_THRESHOLD = 0.5;
|
|
57
|
+
const inScope = outOfScopeFiles.length / changedFiles.length <= SCOPE_THRESHOLD;
|
|
58
|
+
return { inScope, outOfScopeFiles };
|
|
59
|
+
}
|
|
3
60
|
/**
|
|
4
61
|
* Run post-ticket guards: typecheck + tests.
|
|
5
62
|
* If either fails, auto-revert to preSha.
|
|
6
63
|
*
|
|
7
64
|
* @returns Guard result with pass/fail status
|
|
8
65
|
*/
|
|
9
|
-
export function runGuards(preSha, config, cwd, log) {
|
|
66
|
+
export function runGuards(preSha, config, cwd, log, ticket) {
|
|
67
|
+
// Guard 0a: Diff scope — warn if changes are outside ticket modules
|
|
68
|
+
if (ticket && ticket.modules.length > 0) {
|
|
69
|
+
const scopeResult = isDiffInScope(preSha, ticket.modules, cwd);
|
|
70
|
+
if (!scopeResult.inScope) {
|
|
71
|
+
log.warn(`Diff scope warning: ${scopeResult.outOfScopeFiles.length} file(s) outside ticket modules: ${scopeResult.outOfScopeFiles.join(', ')}`);
|
|
72
|
+
// Warn only — do NOT return failure
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
// Guard 0b: Substantiveness — detect stub/whitespace-only changes
|
|
76
|
+
if (!isSubstantive(preSha, cwd)) {
|
|
77
|
+
log.warn('Changes are not substantive (comments/whitespace only) — reverting');
|
|
78
|
+
revert(preSha, cwd);
|
|
79
|
+
return { passed: false, failedGuard: 'substantiveness' };
|
|
80
|
+
}
|
|
10
81
|
// Guard 1: Typecheck
|
|
11
82
|
try {
|
|
12
83
|
execSync('pnpm typecheck', { cwd, stdio: 'pipe', timeout: 120_000 });
|
|
@@ -39,6 +110,42 @@ function revert(sha, cwd) {
|
|
|
39
110
|
}
|
|
40
111
|
catch { /* ok */ }
|
|
41
112
|
}
|
|
113
|
+
/**
|
|
114
|
+
* Check if changes since preSha are substantive (not just comments/whitespace).
|
|
115
|
+
* Uses `git diff --stat` to count insertions/deletions, then checks
|
|
116
|
+
* if the non-comment/non-whitespace diff is meaningful.
|
|
117
|
+
*/
|
|
118
|
+
export function isSubstantive(preSha, cwd) {
|
|
119
|
+
try {
|
|
120
|
+
// Get the actual code diff (ignore whitespace changes)
|
|
121
|
+
const diff = execFileSync('git', ['diff', '-w', '--no-color', preSha, 'HEAD'], {
|
|
122
|
+
cwd,
|
|
123
|
+
encoding: 'utf8',
|
|
124
|
+
maxBuffer: 1024 * 1024,
|
|
125
|
+
});
|
|
126
|
+
// Extract only added/removed lines (not diff headers)
|
|
127
|
+
const changedLines = diff.split('\n').filter(line => (line.startsWith('+') || line.startsWith('-')) &&
|
|
128
|
+
!line.startsWith('+++') && !line.startsWith('---'));
|
|
129
|
+
// Filter out comment-only and empty lines
|
|
130
|
+
const substantiveLines = changedLines.filter(line => {
|
|
131
|
+
const content = line.slice(1).trim(); // Remove +/- prefix
|
|
132
|
+
if (content === '')
|
|
133
|
+
return false;
|
|
134
|
+
// Skip pure comment lines
|
|
135
|
+
if (content.startsWith('//') || content.startsWith('/*') || content.startsWith('*') || content.startsWith('#'))
|
|
136
|
+
return false;
|
|
137
|
+
// Skip JSDoc-only lines
|
|
138
|
+
if (content.startsWith('/**') || content === '*/')
|
|
139
|
+
return false;
|
|
140
|
+
return true;
|
|
141
|
+
});
|
|
142
|
+
return substantiveLines.length >= 3;
|
|
143
|
+
}
|
|
144
|
+
catch {
|
|
145
|
+
// If diff fails, assume substantive (don't block on errors)
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
42
149
|
/** Count commits that would be reverted */
|
|
43
150
|
function countRevertable(preSha, cwd) {
|
|
44
151
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"guard-runner.js","sourceRoot":"","sources":["../../../src/cli/loop/guard-runner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"guard-runner.js","sourceRoot":"","sources":["../../../src/cli/loop/guard-runner.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-selector.d.ts","sourceRoot":"","sources":["../../../src/cli/loop/model-selector.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAe,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/E;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,aAAa,CAAC,UAAU,CAAC,GACnC,MAAM,
|
|
1
|
+
{"version":3,"file":"model-selector.d.ts","sourceRoot":"","sources":["../../../src/cli/loop/model-selector.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,IAAI,EAAE,UAAU,EAAe,aAAa,EAAE,MAAM,YAAY,CAAC;AAE/E;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,aAAa,CAAC,UAAU,CAAC,GACnC,MAAM,CA+BR;AAED,iDAAiD;AACjD,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,MAAM,CAEvE;AAED,+DAA+D;AAC/D,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAEnD"}
|
|
@@ -15,8 +15,9 @@ export function selectModel(club, maxFiles, estTokens, config, cwd, strategy) {
|
|
|
15
15
|
// 2. Multi-file routing: 2+ files → API
|
|
16
16
|
if (maxFiles >= 2)
|
|
17
17
|
return config.modelApi;
|
|
18
|
-
// 3. Strategy-based: documentation tickets need API model
|
|
19
|
-
|
|
18
|
+
// 3. Strategy-based: documentation and roadmap tickets need API model
|
|
19
|
+
// (local models struggle with prose; roadmap tickets are curated features)
|
|
20
|
+
if (strategy === 'documentation' || strategy === 'roadmap')
|
|
20
21
|
return config.modelApi;
|
|
21
22
|
// 4. Data-driven overrides from model-config.json
|
|
22
23
|
const modelConfig = loadModelConfig(cwd);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"model-selector.js","sourceRoot":"","sources":["../../../src/cli/loop/model-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CACzB,IAAU,EACV,QAAgB,EAChB,SAAiB,EACjB,MAAkB,EAClB,GAAW,EACX,QAAoC;IAEpC,2DAA2D;IAC3D,IAAI,SAAS,GAAG,KAAK;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC;IAE9C,wCAAwC;IACxC,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC;IAE1C,
|
|
1
|
+
{"version":3,"file":"model-selector.js","sourceRoot":"","sources":["../../../src/cli/loop/model-selector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACnD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAGjC;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CACzB,IAAU,EACV,QAAgB,EAChB,SAAiB,EACjB,MAAkB,EAClB,GAAW,EACX,QAAoC;IAEpC,2DAA2D;IAC3D,IAAI,SAAS,GAAG,KAAK;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC;IAE9C,wCAAwC;IACxC,IAAI,QAAQ,IAAI,CAAC;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC;IAE1C,sEAAsE;IACtE,8EAA8E;IAC9E,IAAI,QAAQ,KAAK,eAAe,IAAI,QAAQ,KAAK,SAAS;QAAE,OAAO,MAAM,CAAC,QAAQ,CAAC;IAEnF,kDAAkD;IAClD,MAAM,WAAW,GAAG,eAAe,CAAC,GAAG,CAAC,CAAC;IACzC,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,GAAG,GAAG,WAAW,CAAC,eAAe,CAAC,IAAI,CAAC,CAAC;QAC9C,IAAI,GAAG,EAAE,KAAK,KAAK,KAAK;YAAE,OAAO,MAAM,CAAC,QAAQ,CAAC;QACjD,IAAI,GAAG,EAAE,KAAK,KAAK,OAAO;YAAE,OAAO,MAAM,CAAC,UAAU,CAAC;IACvD,CAAC;IAED,mBAAmB;IACnB,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,QAAQ,CAAC;QACd,KAAK,OAAO,CAAC;QACb,KAAK,YAAY;YACf,OAAO,MAAM,CAAC,UAAU,CAAC;QAC3B,KAAK,WAAW,CAAC;QACjB,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,QAAQ,CAAC;QACzB;YACE,OAAO,MAAM,CAAC,UAAU,CAAC;IAC7B,CAAC;AACH,CAAC;AAED,iDAAiD;AACjD,MAAM,UAAU,aAAa,CAAC,KAAa,EAAE,MAAkB;IAC7D,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,MAAM,CAAC,eAAe,CAAC;AACjF,CAAC;AAED,+DAA+D;AAC/D,MAAM,UAAU,YAAY,CAAC,KAAa;IACxC,OAAO,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;AAClC,CAAC;AAED,0CAA0C;AAC1C,SAAS,eAAe,CAAC,GAAW;IAClC,MAAM,UAAU,GAAG,IAAI,CAAC,GAAG,EAAE,8BAA8B,CAAC,CAAC;IAC7D,IAAI,CAAC,UAAU,CAAC,UAAU,CAAC;QAAE,OAAO,IAAI,CAAC;IACzC,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,UAAU,EAAE,MAAM,CAAC,CAAgB,CAAC;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { BacklogTicket, ExecutionPlan, PlanFileEntry } from './types.js';
|
|
2
|
+
import type { Logger } from './logger.js';
|
|
3
|
+
/**
|
|
4
|
+
* Extract top keywords from text for grep discovery.
|
|
5
|
+
*/
|
|
6
|
+
export declare function extractKeywords(text: string, max?: number): string[];
|
|
7
|
+
/**
|
|
8
|
+
* Tier 1.5: Use ticket.modules for scoped file discovery.
|
|
9
|
+
* Includes module files themselves (if they exist on disk) plus grep within module paths.
|
|
10
|
+
*/
|
|
11
|
+
export declare function tier15Modules(ticket: BacklogTicket, cwd: string): PlanFileEntry[] | null;
|
|
12
|
+
/**
|
|
13
|
+
* Generate a concrete execution plan for a ticket using 4-tier file discovery.
|
|
14
|
+
* No embeddings required.
|
|
15
|
+
*/
|
|
16
|
+
export declare function generatePlan(ticket: BacklogTicket, model: string, cwd: string, log: Logger): ExecutionPlan;
|
|
17
|
+
/**
|
|
18
|
+
* Format an ExecutionPlan as a structured Aider --message prompt.
|
|
19
|
+
*/
|
|
20
|
+
export declare function formatPlanAsPrompt(plan: ExecutionPlan, ticket: BacklogTicket): string;
|
|
21
|
+
//# sourceMappingURL=planner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../../src/cli/loop/planner.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,aAAa,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC9E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAY1C;;GAEG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,SAAI,GAAG,MAAM,EAAE,CAgB/D;AA8CD;;;GAGG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,EAAE,MAAM,GAAG,aAAa,EAAE,GAAG,IAAI,CAoDxF;AA8ED;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,MAAM,EAAE,aAAa,EACrB,KAAK,EAAE,MAAM,EACb,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,aAAa,CAqDf;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,aAAa,EAAE,MAAM,EAAE,aAAa,GAAG,MAAM,CA2CrF"}
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
// Planner — generates concrete execution plans for Aider without embeddings.
|
|
2
|
+
// 4-tier file discovery: enriched → modules → grep → generic.
|
|
3
|
+
import { execFileSync } from 'node:child_process';
|
|
4
|
+
import { existsSync, readFileSync } from 'node:fs';
|
|
5
|
+
import { join } from 'node:path';
|
|
6
|
+
import { collectTestFiles } from '../../core/prep.js';
|
|
7
|
+
import { isLocalModel } from './model-selector.js';
|
|
8
|
+
// Stop words for keyword extraction
|
|
9
|
+
const STOP_WORDS = new Set([
|
|
10
|
+
'the', 'a', 'an', 'and', 'or', 'but', 'in', 'on', 'at', 'to', 'for',
|
|
11
|
+
'of', 'with', 'by', 'from', 'is', 'are', 'was', 'were', 'be', 'been',
|
|
12
|
+
'has', 'have', 'had', 'do', 'does', 'did', 'will', 'would', 'could',
|
|
13
|
+
'should', 'may', 'might', 'can', 'this', 'that', 'these', 'those',
|
|
14
|
+
'it', 'its', 'as', 'if', 'not', 'no', 'so', 'up', 'out', 'all',
|
|
15
|
+
'add', 'update', 'fix', 'remove', 'change', 'make', 'use', 'new',
|
|
16
|
+
]);
|
|
17
|
+
/**
|
|
18
|
+
* Extract top keywords from text for grep discovery.
|
|
19
|
+
*/
|
|
20
|
+
export function extractKeywords(text, max = 3) {
|
|
21
|
+
const words = text.toLowerCase()
|
|
22
|
+
.replace(/[^a-z0-9\s_-]/g, ' ')
|
|
23
|
+
.split(/\s+/)
|
|
24
|
+
.filter(w => w.length > 2 && !STOP_WORDS.has(w));
|
|
25
|
+
// Count frequency
|
|
26
|
+
const freq = new Map();
|
|
27
|
+
for (const w of words) {
|
|
28
|
+
freq.set(w, (freq.get(w) ?? 0) + 1);
|
|
29
|
+
}
|
|
30
|
+
return [...freq.entries()]
|
|
31
|
+
.sort((a, b) => b[1] - a[1])
|
|
32
|
+
.slice(0, max)
|
|
33
|
+
.map(([w]) => w);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Read the first N lines of a file and match against acceptance criteria
|
|
37
|
+
* to produce a specific action description.
|
|
38
|
+
*/
|
|
39
|
+
function inferAction(filePath, ticket, cwd) {
|
|
40
|
+
const fullPath = join(cwd, filePath);
|
|
41
|
+
let header = '';
|
|
42
|
+
try {
|
|
43
|
+
const content = readFileSync(fullPath, 'utf8');
|
|
44
|
+
header = content.split('\n').slice(0, 50).join('\n');
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return { action: 'Modify as described in ticket', reason: ticket.acceptance_criteria[0] ?? ticket.title };
|
|
48
|
+
}
|
|
49
|
+
// Try to match acceptance criteria keywords against file content
|
|
50
|
+
for (const ac of ticket.acceptance_criteria) {
|
|
51
|
+
const acWords = ac.toLowerCase().split(/\s+/).filter(w => w.length > 3);
|
|
52
|
+
for (const word of acWords) {
|
|
53
|
+
if (header.toLowerCase().includes(word)) {
|
|
54
|
+
return { action: `Modify to satisfy: ${ac}`, reason: ac };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// Fallback: use ticket description keywords
|
|
59
|
+
return { action: `Update per ticket requirements`, reason: ticket.acceptance_criteria[0] ?? ticket.title };
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Tier 1: Use enriched primary files from the ticket.
|
|
63
|
+
*/
|
|
64
|
+
function tier1Enriched(ticket, cwd) {
|
|
65
|
+
if (!ticket.files?.primary || ticket.files.primary.length === 0)
|
|
66
|
+
return null;
|
|
67
|
+
const entries = [];
|
|
68
|
+
for (const f of ticket.files.primary) {
|
|
69
|
+
if (!f || !existsSync(join(cwd, f)))
|
|
70
|
+
continue;
|
|
71
|
+
const { action, reason } = inferAction(f, ticket, cwd);
|
|
72
|
+
entries.push({ path: f, action, reason });
|
|
73
|
+
}
|
|
74
|
+
return entries.length > 0 ? entries : null;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Tier 1.5: Use ticket.modules for scoped file discovery.
|
|
78
|
+
* Includes module files themselves (if they exist on disk) plus grep within module paths.
|
|
79
|
+
*/
|
|
80
|
+
export function tier15Modules(ticket, cwd) {
|
|
81
|
+
if (!ticket.modules || ticket.modules.length === 0)
|
|
82
|
+
return null;
|
|
83
|
+
const matchedFiles = new Set();
|
|
84
|
+
for (const mod of ticket.modules) {
|
|
85
|
+
const fullPath = join(cwd, mod);
|
|
86
|
+
// Include the module file itself if it exists
|
|
87
|
+
if (existsSync(fullPath) && !mod.endsWith('/')) {
|
|
88
|
+
matchedFiles.add(mod);
|
|
89
|
+
}
|
|
90
|
+
// Grep keywords within the module path (file's parent dir or directory itself)
|
|
91
|
+
const keywords = extractKeywords(`${ticket.title} ${ticket.description}`);
|
|
92
|
+
// Use relative path for grep so output is relative to cwd
|
|
93
|
+
const relSearchDir = existsSync(fullPath) && !mod.endsWith('/')
|
|
94
|
+
? join(mod, '..') // parent dir of file (relative)
|
|
95
|
+
: mod; // directory itself (relative)
|
|
96
|
+
if (!existsSync(join(cwd, relSearchDir)))
|
|
97
|
+
continue;
|
|
98
|
+
for (const keyword of keywords) {
|
|
99
|
+
if (matchedFiles.size >= 5)
|
|
100
|
+
break;
|
|
101
|
+
try {
|
|
102
|
+
const output = execFileSync('grep', [
|
|
103
|
+
'-rl', '--include=*.ts', '--include=*.js',
|
|
104
|
+
keyword,
|
|
105
|
+
relSearchDir,
|
|
106
|
+
], { cwd, encoding: 'utf8', timeout: 5000 });
|
|
107
|
+
for (const line of output.split('\n')) {
|
|
108
|
+
const trimmed = line.trim();
|
|
109
|
+
if (!trimmed || trimmed.includes('.test.') || trimmed.includes('node_modules'))
|
|
110
|
+
continue;
|
|
111
|
+
matchedFiles.add(trimmed);
|
|
112
|
+
if (matchedFiles.size >= 5)
|
|
113
|
+
break;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
catch {
|
|
117
|
+
// grep returns exit code 1 when no matches — not an error
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
if (matchedFiles.size === 0)
|
|
122
|
+
return null;
|
|
123
|
+
const entries = [];
|
|
124
|
+
for (const f of matchedFiles) {
|
|
125
|
+
const { action, reason } = inferAction(f, ticket, cwd);
|
|
126
|
+
entries.push({ path: f, action, reason });
|
|
127
|
+
}
|
|
128
|
+
return entries;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Tier 2: Grep for keywords from ticket title/description.
|
|
132
|
+
*/
|
|
133
|
+
function tier2Grep(ticket, cwd) {
|
|
134
|
+
const keywords = extractKeywords(`${ticket.title} ${ticket.description}`);
|
|
135
|
+
if (keywords.length === 0)
|
|
136
|
+
return null;
|
|
137
|
+
const matchedFiles = new Set();
|
|
138
|
+
for (const keyword of keywords) {
|
|
139
|
+
if (matchedFiles.size >= 5)
|
|
140
|
+
break;
|
|
141
|
+
try {
|
|
142
|
+
const output = execFileSync('grep', [
|
|
143
|
+
'-rl', '--include=*.ts', '--include=*.js',
|
|
144
|
+
keyword,
|
|
145
|
+
'src/', 'packages/',
|
|
146
|
+
], { cwd, encoding: 'utf8', timeout: 5000 });
|
|
147
|
+
for (const line of output.split('\n')) {
|
|
148
|
+
const trimmed = line.trim();
|
|
149
|
+
if (trimmed && !trimmed.includes('.test.') && !trimmed.includes('node_modules')) {
|
|
150
|
+
matchedFiles.add(trimmed);
|
|
151
|
+
}
|
|
152
|
+
if (matchedFiles.size >= 5)
|
|
153
|
+
break;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// grep returns exit code 1 when no matches — not an error
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (matchedFiles.size === 0)
|
|
161
|
+
return null;
|
|
162
|
+
const entries = [];
|
|
163
|
+
for (const f of matchedFiles) {
|
|
164
|
+
const { action, reason } = inferAction(f, ticket, cwd);
|
|
165
|
+
entries.push({ path: f, action, reason });
|
|
166
|
+
}
|
|
167
|
+
return entries;
|
|
168
|
+
}
|
|
169
|
+
/**
|
|
170
|
+
* Tier 3: Generic fallback using modules or description.
|
|
171
|
+
*/
|
|
172
|
+
function tier3Generic(ticket) {
|
|
173
|
+
if (ticket.modules.length > 0) {
|
|
174
|
+
return ticket.modules.slice(0, 5).map(m => ({
|
|
175
|
+
path: m,
|
|
176
|
+
action: 'Identify and modify relevant files in this module',
|
|
177
|
+
reason: ticket.acceptance_criteria[0] ?? ticket.title,
|
|
178
|
+
}));
|
|
179
|
+
}
|
|
180
|
+
return [{
|
|
181
|
+
path: '(read description to identify target files)',
|
|
182
|
+
action: ticket.title,
|
|
183
|
+
reason: ticket.acceptance_criteria[0] ?? ticket.title,
|
|
184
|
+
}];
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Build model-specific approach text.
|
|
188
|
+
*/
|
|
189
|
+
function buildApproach(model) {
|
|
190
|
+
if (isLocalModel(model)) {
|
|
191
|
+
return `## Approach (local model — keep it simple)
|
|
192
|
+
- Focus on ONE file at a time
|
|
193
|
+
- Make the smallest possible change that satisfies the criteria
|
|
194
|
+
- Prefer editing existing code over adding new files`;
|
|
195
|
+
}
|
|
196
|
+
return `## Approach (plan then execute)
|
|
197
|
+
1. List the specific changes needed per file
|
|
198
|
+
2. For each file: read it, make the change, verify
|
|
199
|
+
3. Run verification commands after all changes`;
|
|
200
|
+
}
|
|
201
|
+
/**
|
|
202
|
+
* Generate a concrete execution plan for a ticket using 4-tier file discovery.
|
|
203
|
+
* No embeddings required.
|
|
204
|
+
*/
|
|
205
|
+
export function generatePlan(ticket, model, cwd, log) {
|
|
206
|
+
// Tier 1: enriched files
|
|
207
|
+
const enriched = tier1Enriched(ticket, cwd);
|
|
208
|
+
if (enriched) {
|
|
209
|
+
log.info(`Plan tier: enriched (${enriched.length} files)`);
|
|
210
|
+
return {
|
|
211
|
+
ticket: ticket.key,
|
|
212
|
+
title: ticket.title,
|
|
213
|
+
files: enriched,
|
|
214
|
+
testFiles: collectTestFiles(enriched.map(e => e.path), cwd),
|
|
215
|
+
approach: buildApproach(model),
|
|
216
|
+
generated: 'enriched',
|
|
217
|
+
};
|
|
218
|
+
}
|
|
219
|
+
// Tier 1.5: module-scoped discovery
|
|
220
|
+
const modules = tier15Modules(ticket, cwd);
|
|
221
|
+
if (modules) {
|
|
222
|
+
log.info(`Plan tier: modules (${modules.length} files)`);
|
|
223
|
+
return {
|
|
224
|
+
ticket: ticket.key,
|
|
225
|
+
title: ticket.title,
|
|
226
|
+
files: modules,
|
|
227
|
+
testFiles: collectTestFiles(modules.map(e => e.path), cwd),
|
|
228
|
+
approach: buildApproach(model),
|
|
229
|
+
generated: 'modules',
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
// Tier 2: grep discovery
|
|
233
|
+
const grepped = tier2Grep(ticket, cwd);
|
|
234
|
+
if (grepped) {
|
|
235
|
+
log.info(`Plan tier: grep (${grepped.length} files)`);
|
|
236
|
+
return {
|
|
237
|
+
ticket: ticket.key,
|
|
238
|
+
title: ticket.title,
|
|
239
|
+
files: grepped,
|
|
240
|
+
testFiles: collectTestFiles(grepped.map(e => e.path), cwd),
|
|
241
|
+
approach: buildApproach(model),
|
|
242
|
+
generated: 'grep',
|
|
243
|
+
};
|
|
244
|
+
}
|
|
245
|
+
// Tier 3: generic
|
|
246
|
+
log.info('Plan tier: generic');
|
|
247
|
+
return {
|
|
248
|
+
ticket: ticket.key,
|
|
249
|
+
title: ticket.title,
|
|
250
|
+
files: tier3Generic(ticket),
|
|
251
|
+
testFiles: [],
|
|
252
|
+
approach: buildApproach(model),
|
|
253
|
+
generated: 'generic',
|
|
254
|
+
};
|
|
255
|
+
}
|
|
256
|
+
/**
|
|
257
|
+
* Format an ExecutionPlan as a structured Aider --message prompt.
|
|
258
|
+
*/
|
|
259
|
+
export function formatPlanAsPrompt(plan, ticket) {
|
|
260
|
+
const fileSection = plan.files.map(f => `### ${f.path}\n**Action:** ${f.action}\n**Reason:** ${f.reason}`).join('\n\n');
|
|
261
|
+
const testSection = plan.testFiles.length > 0
|
|
262
|
+
? plan.testFiles.map(t => `- ${t}`).join('\n')
|
|
263
|
+
: '- (run full test suite)';
|
|
264
|
+
const acSection = ticket.acceptance_criteria
|
|
265
|
+
.map(ac => ` [ ] ${ac}`)
|
|
266
|
+
.join('\n');
|
|
267
|
+
return `You are working on the SLOPE project (TypeScript monorepo, pnpm, vitest).
|
|
268
|
+
|
|
269
|
+
## Task
|
|
270
|
+
${ticket.key}: ${ticket.title}
|
|
271
|
+
|
|
272
|
+
## Description
|
|
273
|
+
${ticket.description}
|
|
274
|
+
|
|
275
|
+
## Execution Plan
|
|
276
|
+
For each file below, make the specified change:
|
|
277
|
+
|
|
278
|
+
${fileSection}
|
|
279
|
+
|
|
280
|
+
## Test Files to Verify
|
|
281
|
+
${testSection}
|
|
282
|
+
|
|
283
|
+
## Acceptance Criteria (ALL must pass)
|
|
284
|
+
${acSection}
|
|
285
|
+
|
|
286
|
+
## Verification
|
|
287
|
+
1. pnpm typecheck
|
|
288
|
+
2. pnpm test
|
|
289
|
+
|
|
290
|
+
## Rules
|
|
291
|
+
- Read each file BEFORE modifying — understand existing patterns
|
|
292
|
+
- Make real, substantive changes — no comment-only or whitespace edits
|
|
293
|
+
- If a file already satisfies criteria, skip it
|
|
294
|
+
- Commit: '${ticket.key}: <what you changed>'
|
|
295
|
+
|
|
296
|
+
${plan.approach}`;
|
|
297
|
+
}
|
|
298
|
+
//# sourceMappingURL=planner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"planner.js","sourceRoot":"","sources":["../../../src/cli/loop/planner.ts"],"names":[],"mappings":"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"}
|
|
@@ -10,10 +10,10 @@ export interface MergeResult {
|
|
|
10
10
|
}
|
|
11
11
|
/** Check if gh CLI is available and authenticated */
|
|
12
12
|
export declare function checkGhCli(log: Logger): boolean;
|
|
13
|
-
/** Check if branch has commits ahead of main */
|
|
14
|
-
export declare function hasCommitsAhead(branch: string, cwd: string): boolean;
|
|
13
|
+
/** Check if branch has commits ahead of base (default: main) */
|
|
14
|
+
export declare function hasCommitsAhead(branch: string, cwd: string, baseBranch?: string): boolean;
|
|
15
15
|
/** Create a PR for the sprint branch */
|
|
16
|
-
export declare function createPr(branch: string, sprintId: string, title: string, strategy: string, ticketResults: TicketResult[], cwd: string, log: Logger): PrInfo | null;
|
|
16
|
+
export declare function createPr(branch: string, sprintId: string, title: string, strategy: string, ticketResults: TicketResult[], cwd: string, log: Logger, baseBranch?: string): PrInfo | null;
|
|
17
17
|
/**
|
|
18
18
|
* Run structural review on a PR diff.
|
|
19
19
|
* Returns number of findings added.
|
|
@@ -22,5 +22,7 @@ export declare function runStructuralReview(prNumber: number, sprintId: string,
|
|
|
22
22
|
/**
|
|
23
23
|
* Run auto-merge safeguards and merge if all pass.
|
|
24
24
|
*/
|
|
25
|
-
export declare function autoMerge(prNumber: number, findingCount: number, passingCount: number, config: LoopConfig, cwd: string, log: Logger
|
|
25
|
+
export declare function autoMerge(prNumber: number, findingCount: number, passingCount: number, config: LoopConfig, cwd: string, log: Logger, opts?: {
|
|
26
|
+
isStagingMerge?: boolean;
|
|
27
|
+
}): MergeResult;
|
|
26
28
|
//# sourceMappingURL=pr-lifecycle.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pr-lifecycle.d.ts","sourceRoot":"","sources":["../../../src/cli/loop/pr-lifecycle.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qDAAqD;AACrD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAc/C;AAED,
|
|
1
|
+
{"version":3,"file":"pr-lifecycle.d.ts","sourceRoot":"","sources":["../../../src/cli/loop/pr-lifecycle.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAC3D,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAE1C,MAAM,WAAW,MAAM;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,OAAO,CAAC;IAChB,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,qDAAqD;AACrD,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAc/C;AAED,gEAAgE;AAChE,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,UAAU,SAAS,GAAG,OAAO,CAUzF;AAED,wCAAwC;AACxC,wBAAgB,QAAQ,CACtB,MAAM,EAAE,MAAM,EACd,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,aAAa,EAAE,YAAY,EAAE,EAC7B,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,UAAU,SAAS,GAClB,MAAM,GAAG,IAAI,CAqCf;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,GACV,MAAM,CAqFR;AAyBD;;GAEG;AACH,wBAAgB,SAAS,CACvB,QAAQ,EAAE,MAAM,EAChB,YAAY,EAAE,MAAM,EACpB,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,MAAM,EACX,IAAI,CAAC,EAAE;IAAE,cAAc,CAAC,EAAE,OAAO,CAAA;CAAE,GAClC,WAAW,CAgEb"}
|
|
@@ -17,10 +17,10 @@ export function checkGhCli(log) {
|
|
|
17
17
|
}
|
|
18
18
|
return true;
|
|
19
19
|
}
|
|
20
|
-
/** Check if branch has commits ahead of main */
|
|
21
|
-
export function hasCommitsAhead(branch, cwd) {
|
|
20
|
+
/** Check if branch has commits ahead of base (default: main) */
|
|
21
|
+
export function hasCommitsAhead(branch, cwd, baseBranch = 'main') {
|
|
22
22
|
try {
|
|
23
|
-
const count = execFileSync('git', ['rev-list', '--count',
|
|
23
|
+
const count = execFileSync('git', ['rev-list', '--count', `${baseBranch}..${branch}`], {
|
|
24
24
|
cwd,
|
|
25
25
|
encoding: 'utf8',
|
|
26
26
|
}).trim();
|
|
@@ -31,7 +31,7 @@ export function hasCommitsAhead(branch, cwd) {
|
|
|
31
31
|
}
|
|
32
32
|
}
|
|
33
33
|
/** Create a PR for the sprint branch */
|
|
34
|
-
export function createPr(branch, sprintId, title, strategy, ticketResults, cwd, log) {
|
|
34
|
+
export function createPr(branch, sprintId, title, strategy, ticketResults, cwd, log, baseBranch = 'main') {
|
|
35
35
|
const passingCount = ticketResults.filter(t => t.tests_passing && !t.noop).length;
|
|
36
36
|
const noopCount = ticketResults.filter(t => t.noop).length;
|
|
37
37
|
const totalCount = ticketResults.length;
|
|
@@ -53,7 +53,7 @@ ${ticketLines}
|
|
|
53
53
|
try {
|
|
54
54
|
const url = execFileSync('gh', [
|
|
55
55
|
'pr', 'create',
|
|
56
|
-
'--base',
|
|
56
|
+
'--base', baseBranch,
|
|
57
57
|
'--head', branch,
|
|
58
58
|
'--title', `feat(${sprintId}): ${title}`,
|
|
59
59
|
'--body', body,
|
|
@@ -167,7 +167,7 @@ function addFinding(type, sprintId, sprintNum, severity, description, cwd, log)
|
|
|
167
167
|
/**
|
|
168
168
|
* Run auto-merge safeguards and merge if all pass.
|
|
169
169
|
*/
|
|
170
|
-
export function autoMerge(prNumber, findingCount, passingCount, config, cwd, log) {
|
|
170
|
+
export function autoMerge(prNumber, findingCount, passingCount, config, cwd, log, opts) {
|
|
171
171
|
// Safeguard 1: No critical/major findings
|
|
172
172
|
if (findingCount > 0) {
|
|
173
173
|
try {
|
|
@@ -199,19 +199,21 @@ export function autoMerge(prNumber, findingCount, passingCount, config, cwd, log
|
|
|
199
199
|
catch {
|
|
200
200
|
return block(prNumber, 'typecheck failing', cwd, log);
|
|
201
201
|
}
|
|
202
|
-
// Safeguard 4: PR not too large (<20 files changed)
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
202
|
+
// Safeguard 4: PR not too large (<20 files changed) — skip for staging merges
|
|
203
|
+
if (!opts?.isStagingMerge) {
|
|
204
|
+
try {
|
|
205
|
+
const filesChanged = execFileSync('gh', [
|
|
206
|
+
'pr', 'view', String(prNumber),
|
|
207
|
+
'--json', 'changedFiles',
|
|
208
|
+
'--jq', '.changedFiles',
|
|
209
|
+
], { cwd, encoding: 'utf8' }).trim();
|
|
210
|
+
const count = parseInt(filesChanged, 10) || 0;
|
|
211
|
+
if (count > 20) {
|
|
212
|
+
return block(prNumber, `${count} files changed (threshold: 20)`, cwd, log);
|
|
213
|
+
}
|
|
212
214
|
}
|
|
215
|
+
catch { /* ok — proceed if check fails */ }
|
|
213
216
|
}
|
|
214
|
-
catch { /* ok — proceed if check fails */ }
|
|
215
217
|
// Safeguard 5: At least one passing non-noop ticket
|
|
216
218
|
if (passingCount <= 0) {
|
|
217
219
|
return block(prNumber, 'no passing tickets', cwd, log);
|