@slope-dev/slope 1.13.2 → 1.16.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/context.d.ts +2 -0
- package/dist/cli/commands/context.d.ts.map +1 -0
- package/dist/cli/commands/context.js +190 -0
- package/dist/cli/commands/context.js.map +1 -0
- package/dist/cli/commands/distill.d.ts.map +1 -1
- package/dist/cli/commands/distill.js +13 -4
- package/dist/cli/commands/distill.js.map +1 -1
- package/dist/cli/commands/docs.d.ts +5 -0
- package/dist/cli/commands/docs.d.ts.map +1 -0
- package/dist/cli/commands/docs.js +303 -0
- package/dist/cli/commands/docs.js.map +1 -0
- package/dist/cli/commands/enrich.d.ts +2 -0
- package/dist/cli/commands/enrich.d.ts.map +1 -0
- package/dist/cli/commands/enrich.js +140 -0
- package/dist/cli/commands/enrich.js.map +1 -0
- package/dist/cli/commands/guard.d.ts.map +1 -1
- package/dist/cli/commands/guard.js +2 -0
- package/dist/cli/commands/guard.js.map +1 -1
- package/dist/cli/commands/index-cmd.d.ts +2 -0
- package/dist/cli/commands/index-cmd.d.ts.map +1 -0
- package/dist/cli/commands/index-cmd.js +296 -0
- package/dist/cli/commands/index-cmd.js.map +1 -0
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +73 -182
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/initiative.d.ts +2 -0
- package/dist/cli/commands/initiative.d.ts.map +1 -0
- package/dist/cli/commands/initiative.js +207 -0
- package/dist/cli/commands/initiative.js.map +1 -0
- package/dist/cli/commands/loop.d.ts +2 -0
- package/dist/cli/commands/loop.d.ts.map +1 -0
- package/dist/cli/commands/loop.js +388 -0
- package/dist/cli/commands/loop.js.map +1 -0
- package/dist/cli/commands/prep.d.ts +2 -0
- package/dist/cli/commands/prep.d.ts.map +1 -0
- package/dist/cli/commands/prep.js +94 -0
- package/dist/cli/commands/prep.js.map +1 -0
- package/dist/cli/commands/roadmap.d.ts.map +1 -1
- package/dist/cli/commands/roadmap.js +134 -46
- package/dist/cli/commands/roadmap.js.map +1 -1
- package/dist/cli/commands/session.d.ts.map +1 -1
- package/dist/cli/commands/session.js +2 -0
- package/dist/cli/commands/session.js.map +1 -1
- package/dist/cli/commands/store.js +76 -10
- package/dist/cli/commands/store.js.map +1 -1
- package/dist/cli/commands/vision.d.ts.map +1 -1
- package/dist/cli/commands/vision.js +104 -7
- package/dist/cli/commands/vision.js.map +1 -1
- package/dist/cli/guards/stop-check.d.ts +6 -1
- package/dist/cli/guards/stop-check.d.ts.map +1 -1
- package/dist/cli/guards/stop-check.js +84 -5
- package/dist/cli/guards/stop-check.js.map +1 -1
- package/dist/cli/guards/worktree-check.d.ts +14 -0
- package/dist/cli/guards/worktree-check.d.ts.map +1 -0
- package/dist/cli/guards/worktree-check.js +137 -0
- package/dist/cli/guards/worktree-check.js.map +1 -0
- package/dist/cli/index.js +56 -0
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/interactive-init.d.ts +19 -0
- package/dist/cli/interactive-init.d.ts.map +1 -0
- package/dist/cli/interactive-init.js +132 -0
- package/dist/cli/interactive-init.js.map +1 -0
- package/dist/cli/loop/analyze.d.ts +8 -0
- package/dist/cli/loop/analyze.d.ts.map +1 -0
- package/dist/cli/loop/analyze.js +62 -0
- package/dist/cli/loop/analyze.js.map +1 -0
- package/dist/cli/loop/backlog.d.ts +26 -0
- package/dist/cli/loop/backlog.d.ts.map +1 -0
- package/dist/cli/loop/backlog.js +95 -0
- package/dist/cli/loop/backlog.js.map +1 -0
- package/dist/cli/loop/config.d.ts +10 -0
- package/dist/cli/loop/config.d.ts.map +1 -0
- package/dist/cli/loop/config.js +75 -0
- package/dist/cli/loop/config.js.map +1 -0
- package/dist/cli/loop/continuous.d.ts +6 -0
- package/dist/cli/loop/continuous.d.ts.map +1 -0
- package/dist/cli/loop/continuous.js +108 -0
- package/dist/cli/loop/continuous.js.map +1 -0
- package/dist/cli/loop/executor.d.ts +8 -0
- package/dist/cli/loop/executor.d.ts.map +1 -0
- package/dist/cli/loop/executor.js +600 -0
- package/dist/cli/loop/executor.js.map +1 -0
- package/dist/cli/loop/guard-runner.d.ts +14 -0
- package/dist/cli/loop/guard-runner.d.ts.map +1 -0
- package/dist/cli/loop/guard-runner.js +53 -0
- package/dist/cli/loop/guard-runner.js.map +1 -0
- package/dist/cli/loop/logger.d.ts +9 -0
- package/dist/cli/loop/logger.d.ts.map +1 -0
- package/dist/cli/loop/logger.js +37 -0
- package/dist/cli/loop/logger.js.map +1 -0
- package/dist/cli/loop/model-selector.d.ts +14 -0
- package/dist/cli/loop/model-selector.d.ts.map +1 -0
- package/dist/cli/loop/model-selector.js +59 -0
- package/dist/cli/loop/model-selector.js.map +1 -0
- package/dist/cli/loop/parallel.d.ts +6 -0
- package/dist/cli/loop/parallel.d.ts.map +1 -0
- package/dist/cli/loop/parallel.js +109 -0
- package/dist/cli/loop/parallel.js.map +1 -0
- package/dist/cli/loop/pr-lifecycle.d.ts +26 -0
- package/dist/cli/loop/pr-lifecycle.d.ts.map +1 -0
- package/dist/cli/loop/pr-lifecycle.js +244 -0
- package/dist/cli/loop/pr-lifecycle.js.map +1 -0
- package/dist/cli/loop/types.d.ts +98 -0
- package/dist/cli/loop/types.d.ts.map +1 -0
- package/dist/cli/loop/types.js +37 -0
- package/dist/cli/loop/types.js.map +1 -0
- package/dist/cli/loop/worktree.d.ts +30 -0
- package/dist/cli/loop/worktree.d.ts.map +1 -0
- package/dist/cli/loop/worktree.js +134 -0
- package/dist/cli/loop/worktree.js.map +1 -0
- package/dist/cli/registry.d.ts.map +1 -1
- package/dist/cli/registry.js +9 -0
- package/dist/cli/registry.js.map +1 -1
- package/dist/core/analyzers/stack.d.ts +2 -0
- package/dist/core/analyzers/stack.d.ts.map +1 -1
- package/dist/core/analyzers/stack.js +9 -6
- package/dist/core/analyzers/stack.js.map +1 -1
- package/dist/core/config.d.ts +6 -0
- package/dist/core/config.d.ts.map +1 -1
- package/dist/core/config.js.map +1 -1
- package/dist/core/constants.d.ts +2 -0
- package/dist/core/constants.d.ts.map +1 -1
- package/dist/core/constants.js +2 -0
- package/dist/core/constants.js.map +1 -1
- package/dist/core/context.d.ts +20 -0
- package/dist/core/context.d.ts.map +1 -0
- package/dist/core/context.js +59 -0
- package/dist/core/context.js.map +1 -0
- package/dist/core/docs.d.ts +50 -0
- package/dist/core/docs.d.ts.map +1 -0
- package/dist/core/docs.js +67 -0
- package/dist/core/docs.js.map +1 -0
- package/dist/core/embedding-client.d.ts +11 -0
- package/dist/core/embedding-client.d.ts.map +1 -0
- package/dist/core/embedding-client.js +92 -0
- package/dist/core/embedding-client.js.map +1 -0
- package/dist/core/embedding-store.d.ts +44 -0
- package/dist/core/embedding-store.d.ts.map +1 -0
- package/dist/core/embedding-store.js +7 -0
- package/dist/core/embedding-store.js.map +1 -0
- package/dist/core/embedding.d.ts +32 -0
- package/dist/core/embedding.d.ts.map +1 -0
- package/dist/core/embedding.js +114 -0
- package/dist/core/embedding.js.map +1 -0
- package/dist/core/enrich.d.ts +76 -0
- package/dist/core/enrich.d.ts.map +1 -0
- package/dist/core/enrich.js +115 -0
- package/dist/core/enrich.js.map +1 -0
- package/dist/core/generators/roadmap.d.ts +6 -1
- package/dist/core/generators/roadmap.d.ts.map +1 -1
- package/dist/core/generators/roadmap.js +150 -0
- package/dist/core/generators/roadmap.js.map +1 -1
- package/dist/core/guard.d.ts +1 -1
- package/dist/core/guard.d.ts.map +1 -1
- package/dist/core/guard.js +8 -0
- package/dist/core/guard.js.map +1 -1
- package/dist/core/index.d.ts +27 -5
- package/dist/core/index.d.ts.map +1 -1
- package/dist/core/index.js +25 -4
- package/dist/core/index.js.map +1 -1
- package/dist/core/initiative.d.ts +72 -0
- package/dist/core/initiative.d.ts.map +1 -0
- package/dist/core/initiative.js +421 -0
- package/dist/core/initiative.js.map +1 -0
- package/dist/core/interview-engine.d.ts +34 -0
- package/dist/core/interview-engine.d.ts.map +1 -0
- package/dist/core/interview-engine.js +195 -0
- package/dist/core/interview-engine.js.map +1 -0
- package/dist/core/interview-steps.d.ts +27 -0
- package/dist/core/interview-steps.d.ts.map +1 -0
- package/dist/core/interview-steps.js +157 -0
- package/dist/core/interview-steps.js.map +1 -0
- package/dist/core/interview.d.ts +20 -0
- package/dist/core/interview.d.ts.map +1 -1
- package/dist/core/interview.js +61 -34
- package/dist/core/interview.js.map +1 -1
- package/dist/core/metaphor-preview.d.ts +34 -0
- package/dist/core/metaphor-preview.d.ts.map +1 -0
- package/dist/core/metaphor-preview.js +94 -0
- package/dist/core/metaphor-preview.js.map +1 -0
- package/dist/core/prep.d.ts +88 -0
- package/dist/core/prep.d.ts.map +1 -0
- package/dist/core/prep.js +302 -0
- package/dist/core/prep.js.map +1 -0
- package/dist/core/roles.d.ts +3 -0
- package/dist/core/roles.d.ts.map +1 -1
- package/dist/core/roles.js +36 -0
- package/dist/core/roles.js.map +1 -1
- package/dist/core/store.d.ts +1 -1
- package/dist/core/store.d.ts.map +1 -1
- package/dist/core/vision.d.ts +10 -0
- package/dist/core/vision.d.ts.map +1 -1
- package/dist/core/vision.js +37 -0
- package/dist/core/vision.js.map +1 -1
- package/dist/mcp/index.d.ts.map +1 -1
- package/dist/mcp/index.js +55 -7
- package/dist/mcp/index.js.map +1 -1
- package/dist/mcp/registry.d.ts +1 -1
- package/dist/mcp/registry.d.ts.map +1 -1
- package/dist/mcp/registry.js +44 -0
- package/dist/mcp/registry.js.map +1 -1
- package/dist/mcp/sandbox.d.ts.map +1 -1
- package/dist/mcp/sandbox.js +12 -1
- package/dist/mcp/sandbox.js.map +1 -1
- package/dist/store/index.d.ts +26 -1
- package/dist/store/index.d.ts.map +1 -1
- package/dist/store/index.js +193 -1
- package/dist/store/index.js.map +1 -1
- package/dist/store-pg/index.d.ts.map +1 -1
- package/dist/store-pg/index.js +25 -0
- package/dist/store-pg/index.js.map +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { execSync, execFileSync } from 'node:child_process';
|
|
2
|
+
const SHA_PATTERN = /^[0-9a-f]{40}$/;
|
|
3
|
+
/**
|
|
4
|
+
* Run post-ticket guards: typecheck + tests.
|
|
5
|
+
* If either fails, auto-revert to preSha.
|
|
6
|
+
*
|
|
7
|
+
* @returns Guard result with pass/fail status
|
|
8
|
+
*/
|
|
9
|
+
export function runGuards(preSha, config, cwd, log) {
|
|
10
|
+
// Guard 1: Typecheck
|
|
11
|
+
try {
|
|
12
|
+
execSync('pnpm typecheck', { cwd, stdio: 'pipe', timeout: 120_000 });
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
const commitCount = countRevertable(preSha, cwd);
|
|
16
|
+
log.error(`REVERT: typecheck failing — reverting ${commitCount} commit(s)`);
|
|
17
|
+
revert(preSha, cwd);
|
|
18
|
+
return { passed: false, failedGuard: 'typecheck' };
|
|
19
|
+
}
|
|
20
|
+
// Guard 2: Tests (configurable command)
|
|
21
|
+
try {
|
|
22
|
+
execSync(config.loopTestCmd, { cwd, stdio: 'pipe', timeout: 300_000 });
|
|
23
|
+
}
|
|
24
|
+
catch {
|
|
25
|
+
const commitCount = countRevertable(preSha, cwd);
|
|
26
|
+
log.error(`REVERT: tests failing — reverting ${commitCount} commit(s)`);
|
|
27
|
+
revert(preSha, cwd);
|
|
28
|
+
return { passed: false, failedGuard: 'tests' };
|
|
29
|
+
}
|
|
30
|
+
return { passed: true };
|
|
31
|
+
}
|
|
32
|
+
/** Revert to a given SHA (hard reset + clean) */
|
|
33
|
+
function revert(sha, cwd) {
|
|
34
|
+
if (!SHA_PATTERN.test(sha))
|
|
35
|
+
throw new Error(`Invalid SHA: ${sha}`);
|
|
36
|
+
execFileSync('git', ['reset', '--hard', sha], { cwd, stdio: 'pipe' });
|
|
37
|
+
try {
|
|
38
|
+
execFileSync('git', ['clean', '-fd'], { cwd, stdio: 'pipe' });
|
|
39
|
+
}
|
|
40
|
+
catch { /* ok */ }
|
|
41
|
+
}
|
|
42
|
+
/** Count commits that would be reverted */
|
|
43
|
+
function countRevertable(preSha, cwd) {
|
|
44
|
+
try {
|
|
45
|
+
const head = execFileSync('git', ['rev-parse', 'HEAD'], { cwd, encoding: 'utf8' }).trim();
|
|
46
|
+
const count = execFileSync('git', ['rev-list', '--count', `${preSha}..${head}`], { cwd, encoding: 'utf8' }).trim();
|
|
47
|
+
return parseInt(count, 10) || 0;
|
|
48
|
+
}
|
|
49
|
+
catch {
|
|
50
|
+
return 0;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=guard-runner.js.map
|
|
@@ -0,0 +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;AAS5D,MAAM,WAAW,GAAG,gBAAgB,CAAC;AAErC;;;;;GAKG;AACH,MAAM,UAAU,SAAS,CACvB,MAAc,EACd,MAAkB,EAClB,GAAW,EACX,GAAW;IAEX,qBAAqB;IACrB,IAAI,CAAC;QACH,QAAQ,CAAC,gBAAgB,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,WAAW,GAAG,eAAe,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACjD,GAAG,CAAC,KAAK,CAAC,yCAAyC,WAAW,YAAY,CAAC,CAAC;QAC5E,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACpB,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,WAAW,EAAE,CAAC;IACrD,CAAC;IAED,wCAAwC;IACxC,IAAI,CAAC;QACH,QAAQ,CAAC,MAAM,CAAC,WAAW,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC,CAAC;IACzE,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,WAAW,GAAG,eAAe,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACjD,GAAG,CAAC,KAAK,CAAC,qCAAqC,WAAW,YAAY,CAAC,CAAC;QACxE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QACpB,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,WAAW,EAAE,OAAO,EAAE,CAAC;IACjD,CAAC;IAED,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,CAAC;AAC1B,CAAC;AAED,iDAAiD;AACjD,SAAS,MAAM,CAAC,GAAW,EAAE,GAAW;IACtC,IAAI,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC;QAAE,MAAM,IAAI,KAAK,CAAC,gBAAgB,GAAG,EAAE,CAAC,CAAC;IACnE,YAAY,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,QAAQ,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IACtE,IAAI,CAAC;QACH,YAAY,CAAC,KAAK,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAChE,CAAC;IAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,CAAC;AACtB,CAAC;AAED,2CAA2C;AAC3C,SAAS,eAAe,CAAC,MAAc,EAAE,GAAW;IAClD,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QAC1F,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,UAAU,EAAE,SAAS,EAAE,GAAG,MAAM,KAAK,IAAI,EAAE,CAAC,EAAE,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC;QACnH,OAAO,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,CAAC;IACX,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type LogLevel = 'info' | 'warn' | 'error';
|
|
2
|
+
export interface Logger {
|
|
3
|
+
info(msg: string): void;
|
|
4
|
+
warn(msg: string): void;
|
|
5
|
+
error(msg: string): void;
|
|
6
|
+
child(prefix: string): Logger;
|
|
7
|
+
}
|
|
8
|
+
export declare function createLogger(prefix?: string, logFile?: string): Logger;
|
|
9
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.d.ts","sourceRoot":"","sources":["../../../src/cli/loop/logger.ts"],"names":[],"mappings":"AAGA,MAAM,MAAM,QAAQ,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;AAEjD,MAAM,WAAW,MAAM;IACrB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,IAAI,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,KAAK,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,KAAK,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC;CAC/B;AAOD,wBAAgB,YAAY,CAAC,MAAM,GAAE,MAAe,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CA4B9E"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { appendFileSync, mkdirSync, existsSync } from 'node:fs';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
function timestamp() {
|
|
4
|
+
const d = new Date();
|
|
5
|
+
return `${String(d.getHours()).padStart(2, '0')}:${String(d.getMinutes()).padStart(2, '0')}:${String(d.getSeconds()).padStart(2, '0')}`;
|
|
6
|
+
}
|
|
7
|
+
export function createLogger(prefix = 'loop', logFile) {
|
|
8
|
+
if (logFile) {
|
|
9
|
+
const dir = dirname(logFile);
|
|
10
|
+
if (!existsSync(dir))
|
|
11
|
+
mkdirSync(dir, { recursive: true });
|
|
12
|
+
}
|
|
13
|
+
function write(level, msg) {
|
|
14
|
+
const line = `[${timestamp()}] [${prefix}] ${msg}`;
|
|
15
|
+
if (level === 'error' || level === 'warn') {
|
|
16
|
+
console.error(line);
|
|
17
|
+
}
|
|
18
|
+
else {
|
|
19
|
+
console.log(line);
|
|
20
|
+
}
|
|
21
|
+
if (logFile) {
|
|
22
|
+
try {
|
|
23
|
+
appendFileSync(logFile, line + '\n');
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
// Best-effort file logging
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return {
|
|
31
|
+
info: (msg) => write('info', msg),
|
|
32
|
+
warn: (msg) => write('warn', msg),
|
|
33
|
+
error: (msg) => write('error', msg),
|
|
34
|
+
child: (childPrefix) => createLogger(`${prefix}:${childPrefix}`, logFile),
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"logger.js","sourceRoot":"","sources":["../../../src/cli/loop/logger.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAWpC,SAAS,SAAS;IAChB,MAAM,CAAC,GAAG,IAAI,IAAI,EAAE,CAAC;IACrB,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;AAC1I,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,SAAiB,MAAM,EAAE,OAAgB;IACpE,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;QAC7B,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC5D,CAAC;IAED,SAAS,KAAK,CAAC,KAAe,EAAE,GAAW;QACzC,MAAM,IAAI,GAAG,IAAI,SAAS,EAAE,MAAM,MAAM,KAAK,GAAG,EAAE,CAAC;QACnD,IAAI,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,MAAM,EAAE,CAAC;YAC1C,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACtB,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QACpB,CAAC;QACD,IAAI,OAAO,EAAE,CAAC;YACZ,IAAI,CAAC;gBACH,cAAc,CAAC,OAAO,EAAE,IAAI,GAAG,IAAI,CAAC,CAAC;YACvC,CAAC;YAAC,MAAM,CAAC;gBACP,2BAA2B;YAC7B,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO;QACL,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC;QACzC,IAAI,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,KAAK,CAAC,MAAM,EAAE,GAAG,CAAC;QACzC,KAAK,EAAE,CAAC,GAAW,EAAE,EAAE,CAAC,KAAK,CAAC,OAAO,EAAE,GAAG,CAAC;QAC3C,KAAK,EAAE,CAAC,WAAmB,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,MAAM,IAAI,WAAW,EAAE,EAAE,OAAO,CAAC;KAClF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Club, LoopConfig } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Multi-factor model routing matching run.sh logic exactly:
|
|
4
|
+
* 1. Token-based: est_tokens > 24000 → API
|
|
5
|
+
* 2. File-based: max_files >= 2 → API
|
|
6
|
+
* 3. Data-driven: check model-config.json recommendations per club
|
|
7
|
+
* 4. Club defaults: putter/wedge/short_iron → local, long_iron/driver → API
|
|
8
|
+
*/
|
|
9
|
+
export declare function selectModel(club: Club, maxFiles: number, estTokens: number, config: LoopConfig, cwd: string): string;
|
|
10
|
+
/** Select timeout based on the resolved model */
|
|
11
|
+
export declare function selectTimeout(model: string, config: LoopConfig): number;
|
|
12
|
+
/** Check if a model string refers to a local (ollama) model */
|
|
13
|
+
export declare function isLocalModel(model: string): boolean;
|
|
14
|
+
//# sourceMappingURL=model-selector.d.ts.map
|
|
@@ -0,0 +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,MAAM,YAAY,CAAC;AAEhE;;;;;;GAMG;AACH,wBAAgB,WAAW,CACzB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,EACjB,MAAM,EAAE,UAAU,EAClB,GAAG,EAAE,MAAM,GACV,MAAM,CA2BR;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"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { readFileSync, existsSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Multi-factor model routing matching run.sh logic exactly:
|
|
5
|
+
* 1. Token-based: est_tokens > 24000 → API
|
|
6
|
+
* 2. File-based: max_files >= 2 → API
|
|
7
|
+
* 3. Data-driven: check model-config.json recommendations per club
|
|
8
|
+
* 4. Club defaults: putter/wedge/short_iron → local, long_iron/driver → API
|
|
9
|
+
*/
|
|
10
|
+
export function selectModel(club, maxFiles, estTokens, config, cwd) {
|
|
11
|
+
// 1. Token-based escalation: won't fit in Qwen 32K context
|
|
12
|
+
if (estTokens > 24000)
|
|
13
|
+
return config.modelApi;
|
|
14
|
+
// 2. Multi-file routing: 2+ files → API
|
|
15
|
+
if (maxFiles >= 2)
|
|
16
|
+
return config.modelApi;
|
|
17
|
+
// 3. Data-driven overrides from model-config.json
|
|
18
|
+
const modelConfig = loadModelConfig(cwd);
|
|
19
|
+
if (modelConfig) {
|
|
20
|
+
const rec = modelConfig.recommendations[club];
|
|
21
|
+
if (rec?.model === 'api')
|
|
22
|
+
return config.modelApi;
|
|
23
|
+
if (rec?.model === 'local')
|
|
24
|
+
return config.modelLocal;
|
|
25
|
+
}
|
|
26
|
+
// 4. Club defaults
|
|
27
|
+
switch (club) {
|
|
28
|
+
case 'putter':
|
|
29
|
+
case 'wedge':
|
|
30
|
+
case 'short_iron':
|
|
31
|
+
return config.modelLocal;
|
|
32
|
+
case 'long_iron':
|
|
33
|
+
case 'driver':
|
|
34
|
+
return config.modelApi;
|
|
35
|
+
default:
|
|
36
|
+
return config.modelLocal;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
/** Select timeout based on the resolved model */
|
|
40
|
+
export function selectTimeout(model, config) {
|
|
41
|
+
return isLocalModel(model) ? config.modelLocalTimeout : config.modelApiTimeout;
|
|
42
|
+
}
|
|
43
|
+
/** Check if a model string refers to a local (ollama) model */
|
|
44
|
+
export function isLocalModel(model) {
|
|
45
|
+
return model.includes('ollama');
|
|
46
|
+
}
|
|
47
|
+
/** Load model-config.json if it exists */
|
|
48
|
+
function loadModelConfig(cwd) {
|
|
49
|
+
const configPath = join(cwd, 'slope-loop/model-config.json');
|
|
50
|
+
if (!existsSync(configPath))
|
|
51
|
+
return null;
|
|
52
|
+
try {
|
|
53
|
+
return JSON.parse(readFileSync(configPath, 'utf8'));
|
|
54
|
+
}
|
|
55
|
+
catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=model-selector.js.map
|
|
@@ -0,0 +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;;;;;;GAMG;AACH,MAAM,UAAU,WAAW,CACzB,IAAU,EACV,QAAgB,EAChB,SAAiB,EACjB,MAAkB,EAClB,GAAW;IAEX,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,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 @@
|
|
|
1
|
+
{"version":3,"file":"parallel.d.ts","sourceRoot":"","sources":["../../../src/cli/loop/parallel.ts"],"names":[],"mappings":"AAQA;;;GAGG;AACH,wBAAsB,WAAW,CAAC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CA+E3F"}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { mkdirSync } from 'node:fs';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { resolveLoopConfig } from './config.js';
|
|
4
|
+
import { loadBacklog, getRemainingSprintIds } from './backlog.js';
|
|
5
|
+
import { runSprint, isShuttingDown } from './executor.js';
|
|
6
|
+
import { createLogger } from './logger.js';
|
|
7
|
+
/**
|
|
8
|
+
* Dual-sprint parallel execution with module overlap detection.
|
|
9
|
+
* Mirrors slope-loop/parallel.sh behavior.
|
|
10
|
+
*/
|
|
11
|
+
export async function runParallel(flags, cwd) {
|
|
12
|
+
const config = resolveLoopConfig(cwd);
|
|
13
|
+
const dryRun = flags['dry-run'] === 'true';
|
|
14
|
+
mkdirSync(join(cwd, config.resultsDir), { recursive: true });
|
|
15
|
+
mkdirSync(join(cwd, config.logDir), { recursive: true });
|
|
16
|
+
const log = createLogger('loop:parallel', join(cwd, config.logDir, 'parallel.log'));
|
|
17
|
+
log.info('=== Parallel Runner Starting ===');
|
|
18
|
+
if (dryRun)
|
|
19
|
+
log.info('DRY RUN mode');
|
|
20
|
+
const backlog = loadBacklog(cwd, config);
|
|
21
|
+
const remaining = getRemainingSprintIds(backlog, cwd, config);
|
|
22
|
+
if (remaining.length === 0) {
|
|
23
|
+
log.info('No sprints available in backlog.');
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const sprintA = remaining[0];
|
|
27
|
+
if (remaining.length < 2) {
|
|
28
|
+
log.info(`Only one sprint available (${sprintA}) — running sequentially`);
|
|
29
|
+
const runFlags = { sprint: sprintA };
|
|
30
|
+
if (dryRun)
|
|
31
|
+
runFlags['dry-run'] = 'true';
|
|
32
|
+
await runSprint(runFlags, cwd);
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
const sprintB = remaining[1];
|
|
36
|
+
log.info(`Candidate pair: ${sprintA} + ${sprintB}`);
|
|
37
|
+
// Check module overlap
|
|
38
|
+
const overlap = hasModuleOverlap(backlog, sprintA, sprintB);
|
|
39
|
+
if (overlap) {
|
|
40
|
+
log.info('Module overlap detected — falling back to sequential execution');
|
|
41
|
+
log.info(`Running ${sprintA} first...`);
|
|
42
|
+
const flagsA = { sprint: sprintA };
|
|
43
|
+
if (dryRun)
|
|
44
|
+
flagsA['dry-run'] = 'true';
|
|
45
|
+
await runSprint(flagsA, cwd);
|
|
46
|
+
if (!isShuttingDown()) {
|
|
47
|
+
log.info(`Running ${sprintB} second...`);
|
|
48
|
+
const flagsB = { sprint: sprintB };
|
|
49
|
+
if (dryRun)
|
|
50
|
+
flagsB['dry-run'] = 'true';
|
|
51
|
+
await runSprint(flagsB, cwd);
|
|
52
|
+
}
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
log.info('No module overlap — running in parallel');
|
|
56
|
+
// Run both sprints concurrently via Promise.allSettled
|
|
57
|
+
const flagsA = { sprint: sprintA };
|
|
58
|
+
const flagsB = { sprint: sprintB };
|
|
59
|
+
if (dryRun) {
|
|
60
|
+
flagsA['dry-run'] = 'true';
|
|
61
|
+
flagsB['dry-run'] = 'true';
|
|
62
|
+
}
|
|
63
|
+
const [resultA, resultB] = await Promise.allSettled([
|
|
64
|
+
runSprint(flagsA, cwd),
|
|
65
|
+
runSprint(flagsB, cwd),
|
|
66
|
+
]);
|
|
67
|
+
const statusA = resultA.status === 'fulfilled' ? 'PASS' : 'FAIL';
|
|
68
|
+
const statusB = resultB.status === 'fulfilled' ? 'PASS' : 'FAIL';
|
|
69
|
+
if (resultA.status === 'rejected') {
|
|
70
|
+
log.error(`Sprint A (${sprintA}) failed: ${resultA.reason}`);
|
|
71
|
+
}
|
|
72
|
+
if (resultB.status === 'rejected') {
|
|
73
|
+
log.error(`Sprint B (${sprintB}) failed: ${resultB.reason}`);
|
|
74
|
+
}
|
|
75
|
+
log.info('=== Parallel Runner Complete ===');
|
|
76
|
+
log.info(`Sprint A (${sprintA}): ${statusA}`);
|
|
77
|
+
log.info(`Sprint B (${sprintB}): ${statusB}`);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Check if two sprints have overlapping modules.
|
|
81
|
+
* Extracts module lists from tickets and computes set intersection.
|
|
82
|
+
*/
|
|
83
|
+
function hasModuleOverlap(backlog, sprintIdA, sprintIdB) {
|
|
84
|
+
const sprintA = backlog.sprints.find(s => s.id === sprintIdA);
|
|
85
|
+
const sprintB = backlog.sprints.find(s => s.id === sprintIdB);
|
|
86
|
+
if (!sprintA || !sprintB)
|
|
87
|
+
return false;
|
|
88
|
+
const modulesA = getSprintModules(sprintA);
|
|
89
|
+
const modulesB = getSprintModules(sprintB);
|
|
90
|
+
if (modulesA.size === 0 || modulesB.size === 0)
|
|
91
|
+
return false;
|
|
92
|
+
for (const mod of modulesA) {
|
|
93
|
+
if (modulesB.has(mod))
|
|
94
|
+
return true;
|
|
95
|
+
}
|
|
96
|
+
return false;
|
|
97
|
+
}
|
|
98
|
+
function getSprintModules(sprint) {
|
|
99
|
+
const modules = new Set();
|
|
100
|
+
for (const ticket of sprint.tickets) {
|
|
101
|
+
if (ticket.modules) {
|
|
102
|
+
for (const mod of ticket.modules) {
|
|
103
|
+
modules.add(mod);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return modules;
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=parallel.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parallel.js","sourceRoot":"","sources":["../../../src/cli/loop/parallel.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { LoopConfig, TicketResult } from './types.js';
|
|
2
|
+
import type { Logger } from './logger.js';
|
|
3
|
+
export interface PrInfo {
|
|
4
|
+
url: string;
|
|
5
|
+
number: number;
|
|
6
|
+
}
|
|
7
|
+
export interface MergeResult {
|
|
8
|
+
merged: boolean;
|
|
9
|
+
blockReason?: string;
|
|
10
|
+
}
|
|
11
|
+
/** Check if gh CLI is available and authenticated */
|
|
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;
|
|
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;
|
|
17
|
+
/**
|
|
18
|
+
* Run structural review on a PR diff.
|
|
19
|
+
* Returns number of findings added.
|
|
20
|
+
*/
|
|
21
|
+
export declare function runStructuralReview(prNumber: number, sprintId: string, sprintNum: number, cwd: string, log: Logger): number;
|
|
22
|
+
/**
|
|
23
|
+
* Run auto-merge safeguards and merge if all pass.
|
|
24
|
+
*/
|
|
25
|
+
export declare function autoMerge(prNumber: number, findingCount: number, passingCount: number, config: LoopConfig, cwd: string, log: Logger): MergeResult;
|
|
26
|
+
//# sourceMappingURL=pr-lifecycle.d.ts.map
|
|
@@ -0,0 +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,gDAAgD;AAChD,wBAAgB,eAAe,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAUpE;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,GACV,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,GACV,WAAW,CA8Db"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
import { execSync, execFileSync } from 'node:child_process';
|
|
2
|
+
/** Check if gh CLI is available and authenticated */
|
|
3
|
+
export function checkGhCli(log) {
|
|
4
|
+
try {
|
|
5
|
+
execFileSync('gh', ['--version'], { stdio: 'pipe' });
|
|
6
|
+
}
|
|
7
|
+
catch {
|
|
8
|
+
log.warn('gh CLI not found — PR creation will be skipped');
|
|
9
|
+
return false;
|
|
10
|
+
}
|
|
11
|
+
try {
|
|
12
|
+
execFileSync('gh', ['auth', 'status'], { stdio: 'pipe' });
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
log.warn('gh CLI not authenticated — PR creation will be skipped');
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
return true;
|
|
19
|
+
}
|
|
20
|
+
/** Check if branch has commits ahead of main */
|
|
21
|
+
export function hasCommitsAhead(branch, cwd) {
|
|
22
|
+
try {
|
|
23
|
+
const count = execFileSync('git', ['rev-list', '--count', `main..${branch}`], {
|
|
24
|
+
cwd,
|
|
25
|
+
encoding: 'utf8',
|
|
26
|
+
}).trim();
|
|
27
|
+
return parseInt(count, 10) > 0;
|
|
28
|
+
}
|
|
29
|
+
catch {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
/** Create a PR for the sprint branch */
|
|
34
|
+
export function createPr(branch, sprintId, title, strategy, ticketResults, cwd, log) {
|
|
35
|
+
const passingCount = ticketResults.filter(t => t.tests_passing && !t.noop).length;
|
|
36
|
+
const noopCount = ticketResults.filter(t => t.noop).length;
|
|
37
|
+
const totalCount = ticketResults.length;
|
|
38
|
+
const ticketLines = ticketResults.map(t => {
|
|
39
|
+
const status = t.noop ? 'no-op' : t.tests_passing ? 'pass' : 'fail';
|
|
40
|
+
const modelShort = t.final_model.split('/').pop();
|
|
41
|
+
return `- **${t.ticket}**: ${t.title} — ${status} (${modelShort})`;
|
|
42
|
+
}).join('\n');
|
|
43
|
+
const body = `## Sprint ${sprintId} — ${title}
|
|
44
|
+
|
|
45
|
+
**Strategy:** ${strategy} | **Tickets:** ${totalCount} | **Passing:** ${passingCount} | **No-ops:** ${noopCount}
|
|
46
|
+
|
|
47
|
+
### Tickets
|
|
48
|
+
${ticketLines}
|
|
49
|
+
|
|
50
|
+
### Verification
|
|
51
|
+
- Tests: ${passingCount > 0 ? 'passing' : 'failing'}
|
|
52
|
+
- Generated by autonomous loop (\`slope loop run\`)`;
|
|
53
|
+
try {
|
|
54
|
+
const url = execFileSync('gh', [
|
|
55
|
+
'pr', 'create',
|
|
56
|
+
'--base', 'main',
|
|
57
|
+
'--head', branch,
|
|
58
|
+
'--title', `feat(${sprintId}): ${title}`,
|
|
59
|
+
'--body', body,
|
|
60
|
+
], { cwd, encoding: 'utf8' }).trim();
|
|
61
|
+
const number = parseInt(url.match(/\d+$/)?.[0] ?? '0', 10);
|
|
62
|
+
log.info(`PR created: ${url} (PR #${number})`);
|
|
63
|
+
return { url, number };
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
log.warn(`PR creation failed: ${err.message}`);
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Run structural review on a PR diff.
|
|
72
|
+
* Returns number of findings added.
|
|
73
|
+
*/
|
|
74
|
+
export function runStructuralReview(prNumber, sprintId, sprintNum, cwd, log) {
|
|
75
|
+
let findingCount = 0;
|
|
76
|
+
let diff;
|
|
77
|
+
try {
|
|
78
|
+
diff = execFileSync('gh', ['pr', 'diff', String(prNumber)], { cwd, encoding: 'utf8' });
|
|
79
|
+
}
|
|
80
|
+
catch {
|
|
81
|
+
log.warn('Could not fetch PR diff');
|
|
82
|
+
return 0;
|
|
83
|
+
}
|
|
84
|
+
// Track current file context for file-aware checks
|
|
85
|
+
let currentFile = '';
|
|
86
|
+
const addedLines = [];
|
|
87
|
+
const prodAddedLines = [];
|
|
88
|
+
const changedFiles = [];
|
|
89
|
+
for (const line of diff.split('\n')) {
|
|
90
|
+
if (line.startsWith('diff --git')) {
|
|
91
|
+
currentFile = line.replace(/.*b\//, '');
|
|
92
|
+
changedFiles.push(currentFile);
|
|
93
|
+
}
|
|
94
|
+
if (line.startsWith('+') && !line.startsWith('+++')) {
|
|
95
|
+
addedLines.push(line);
|
|
96
|
+
// Only track production lines (not test files)
|
|
97
|
+
if (!currentFile.endsWith('.test.ts') && !currentFile.endsWith('.spec.ts')) {
|
|
98
|
+
prodAddedLines.push(line);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const changedTsFiles = changedFiles.filter(f => f.endsWith('.ts') && !f.endsWith('.test.ts') && !f.endsWith('.d.ts'));
|
|
103
|
+
const changedTestFiles = changedFiles.filter(f => f.endsWith('.test.ts'));
|
|
104
|
+
// Check 1: Type escapes
|
|
105
|
+
const typeEscapes = addedLines.filter(l => /as any|@ts-ignore|@ts-expect-error/.test(l)).length;
|
|
106
|
+
if (typeEscapes > 0) {
|
|
107
|
+
addFinding('code', sprintId, sprintNum, 'minor', `${typeEscapes} type escape(s) found (as any / @ts-ignore)`, cwd, log);
|
|
108
|
+
findingCount++;
|
|
109
|
+
}
|
|
110
|
+
// Check 2: Console.log in production code (excludes test files)
|
|
111
|
+
const prodConsoleLogs = prodAddedLines.filter(l => /console\.log/.test(l)).length;
|
|
112
|
+
if (prodConsoleLogs > 0) {
|
|
113
|
+
addFinding('code', sprintId, sprintNum, 'minor', `${prodConsoleLogs} console.log statement(s) in production code`, cwd, log);
|
|
114
|
+
findingCount++;
|
|
115
|
+
}
|
|
116
|
+
// Check 3: Source files changed without test changes
|
|
117
|
+
let untestedCount = 0;
|
|
118
|
+
for (const srcFile of changedTsFiles) {
|
|
119
|
+
const baseName = srcFile.replace(/\.ts$/, '');
|
|
120
|
+
if (!changedTestFiles.some(t => t.includes(baseName.split('/').pop() + '.test.ts'))) {
|
|
121
|
+
untestedCount++;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
if (untestedCount > 0) {
|
|
125
|
+
addFinding('code', sprintId, sprintNum, 'moderate', `${untestedCount} source file(s) changed without corresponding test changes`, cwd, log);
|
|
126
|
+
findingCount++;
|
|
127
|
+
}
|
|
128
|
+
// Check 4: Security-sensitive file changes
|
|
129
|
+
const securityFiles = changedFiles.filter(f => /auth\/|oauth|jwt|secret|crypto|password|credential/i.test(f));
|
|
130
|
+
if (securityFiles.length > 0) {
|
|
131
|
+
addFinding('security', sprintId, sprintNum, 'moderate', `${securityFiles.length} security-sensitive file(s) changed`, cwd, log);
|
|
132
|
+
findingCount++;
|
|
133
|
+
}
|
|
134
|
+
// Check 5: Large file diffs (>500 additions per file)
|
|
135
|
+
try {
|
|
136
|
+
const filesJson = execFileSync('gh', [
|
|
137
|
+
'pr', 'view', String(prNumber),
|
|
138
|
+
'--json', 'files',
|
|
139
|
+
'--jq', '[.files[] | select(.additions > 500)] | .[].path',
|
|
140
|
+
], { cwd, encoding: 'utf8' }).trim();
|
|
141
|
+
if (filesJson) {
|
|
142
|
+
const largeCount = filesJson.split('\n').filter(Boolean).length;
|
|
143
|
+
if (largeCount > 0) {
|
|
144
|
+
addFinding('architect', sprintId, sprintNum, 'minor', `${largeCount} file(s) with >500 lines added`, cwd, log);
|
|
145
|
+
findingCount++;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
catch { /* ok — gh view might fail */ }
|
|
150
|
+
return findingCount;
|
|
151
|
+
}
|
|
152
|
+
function addFinding(type, sprintId, sprintNum, severity, description, cwd, log) {
|
|
153
|
+
try {
|
|
154
|
+
execFileSync('pnpm', [
|
|
155
|
+
'slope', 'review', 'findings', 'add',
|
|
156
|
+
`--type=${type}`,
|
|
157
|
+
`--ticket=${sprintId}-0`,
|
|
158
|
+
`--severity=${severity}`,
|
|
159
|
+
`--description=${description}`,
|
|
160
|
+
`--sprint=${String(sprintNum)}`,
|
|
161
|
+
], { cwd, stdio: 'pipe' });
|
|
162
|
+
}
|
|
163
|
+
catch {
|
|
164
|
+
log.warn(`Failed to add finding: ${description}`);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Run auto-merge safeguards and merge if all pass.
|
|
169
|
+
*/
|
|
170
|
+
export function autoMerge(prNumber, findingCount, passingCount, config, cwd, log) {
|
|
171
|
+
// Safeguard 1: No critical/major findings
|
|
172
|
+
if (findingCount > 0) {
|
|
173
|
+
try {
|
|
174
|
+
const findingsList = execFileSync('pnpm', ['slope', 'review', 'findings', 'list'], {
|
|
175
|
+
cwd, encoding: 'utf8',
|
|
176
|
+
});
|
|
177
|
+
const criticalMajor = (findingsList.match(/\b(critical|major)\b/g) || []).length;
|
|
178
|
+
if (criticalMajor > 0) {
|
|
179
|
+
return block(prNumber, `${criticalMajor} critical/major finding(s)`, cwd, log);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
catch {
|
|
183
|
+
// If findings list fails, treat as a merge block (safety-critical path)
|
|
184
|
+
log.warn('Could not verify findings — blocking merge as precaution');
|
|
185
|
+
return block(prNumber, 'findings verification failed', cwd, log);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
// Safeguard 2: Tests pass
|
|
189
|
+
try {
|
|
190
|
+
execSync(config.loopTestCmd, { cwd, stdio: 'pipe', timeout: 300_000 });
|
|
191
|
+
}
|
|
192
|
+
catch {
|
|
193
|
+
return block(prNumber, 'tests failing', cwd, log);
|
|
194
|
+
}
|
|
195
|
+
// Safeguard 3: Typecheck passes
|
|
196
|
+
try {
|
|
197
|
+
execSync('pnpm typecheck', { cwd, stdio: 'pipe', timeout: 120_000 });
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
return block(prNumber, 'typecheck failing', cwd, log);
|
|
201
|
+
}
|
|
202
|
+
// Safeguard 4: PR not too large (<20 files changed)
|
|
203
|
+
try {
|
|
204
|
+
const filesChanged = execFileSync('gh', [
|
|
205
|
+
'pr', 'view', String(prNumber),
|
|
206
|
+
'--json', 'changedFiles',
|
|
207
|
+
'--jq', '.changedFiles',
|
|
208
|
+
], { cwd, encoding: 'utf8' }).trim();
|
|
209
|
+
const count = parseInt(filesChanged, 10) || 0;
|
|
210
|
+
if (count > 20) {
|
|
211
|
+
return block(prNumber, `${count} files changed (threshold: 20)`, cwd, log);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
catch { /* ok — proceed if check fails */ }
|
|
215
|
+
// Safeguard 5: At least one passing non-noop ticket
|
|
216
|
+
if (passingCount <= 0) {
|
|
217
|
+
return block(prNumber, 'no passing tickets', cwd, log);
|
|
218
|
+
}
|
|
219
|
+
// All safeguards passed — merge
|
|
220
|
+
log.info('All safeguards passed — auto-merging');
|
|
221
|
+
try {
|
|
222
|
+
execFileSync('gh', ['pr', 'merge', String(prNumber), '--squash', '--delete-branch'], {
|
|
223
|
+
cwd, stdio: 'pipe',
|
|
224
|
+
});
|
|
225
|
+
log.info('PR merged successfully');
|
|
226
|
+
return { merged: true };
|
|
227
|
+
}
|
|
228
|
+
catch {
|
|
229
|
+
log.warn('Auto-merge failed — merge manually');
|
|
230
|
+
return { merged: false, blockReason: 'merge command failed' };
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
function block(prNumber, reason, cwd, log) {
|
|
234
|
+
log.warn(`Auto-merge blocked: ${reason}`);
|
|
235
|
+
try {
|
|
236
|
+
execFileSync('gh', [
|
|
237
|
+
'pr', 'comment', String(prNumber),
|
|
238
|
+
'--body', `Auto-merge blocked: ${reason}. Manual review required.`,
|
|
239
|
+
], { cwd, stdio: 'pipe' });
|
|
240
|
+
}
|
|
241
|
+
catch { /* ok */ }
|
|
242
|
+
return { merged: false, blockReason: reason };
|
|
243
|
+
}
|
|
244
|
+
//# sourceMappingURL=pr-lifecycle.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pr-lifecycle.js","sourceRoot":"","sources":["../../../src/cli/loop/pr-lifecycle.ts"],"names":[],"mappings":"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"}
|