@slope-dev/slope 1.15.0 → 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.
Files changed (116) hide show
  1. package/dist/cli/commands/docs.d.ts +5 -0
  2. package/dist/cli/commands/docs.d.ts.map +1 -0
  3. package/dist/cli/commands/docs.js +303 -0
  4. package/dist/cli/commands/docs.js.map +1 -0
  5. package/dist/cli/commands/guard.d.ts.map +1 -1
  6. package/dist/cli/commands/guard.js +2 -0
  7. package/dist/cli/commands/guard.js.map +1 -1
  8. package/dist/cli/commands/init.d.ts.map +1 -1
  9. package/dist/cli/commands/init.js +56 -0
  10. package/dist/cli/commands/init.js.map +1 -1
  11. package/dist/cli/commands/loop.d.ts +2 -0
  12. package/dist/cli/commands/loop.d.ts.map +1 -0
  13. package/dist/cli/commands/loop.js +388 -0
  14. package/dist/cli/commands/loop.js.map +1 -0
  15. package/dist/cli/commands/roadmap.d.ts.map +1 -1
  16. package/dist/cli/commands/roadmap.js +51 -2
  17. package/dist/cli/commands/roadmap.js.map +1 -1
  18. package/dist/cli/commands/session.d.ts.map +1 -1
  19. package/dist/cli/commands/session.js +2 -0
  20. package/dist/cli/commands/session.js.map +1 -1
  21. package/dist/cli/commands/vision.d.ts.map +1 -1
  22. package/dist/cli/commands/vision.js +104 -7
  23. package/dist/cli/commands/vision.js.map +1 -1
  24. package/dist/cli/guards/stop-check.d.ts +5 -0
  25. package/dist/cli/guards/stop-check.d.ts.map +1 -1
  26. package/dist/cli/guards/stop-check.js +72 -5
  27. package/dist/cli/guards/stop-check.js.map +1 -1
  28. package/dist/cli/guards/worktree-check.d.ts +14 -0
  29. package/dist/cli/guards/worktree-check.d.ts.map +1 -0
  30. package/dist/cli/guards/worktree-check.js +137 -0
  31. package/dist/cli/guards/worktree-check.js.map +1 -0
  32. package/dist/cli/index.js +16 -0
  33. package/dist/cli/index.js.map +1 -1
  34. package/dist/cli/loop/analyze.d.ts +8 -0
  35. package/dist/cli/loop/analyze.d.ts.map +1 -0
  36. package/dist/cli/loop/analyze.js +62 -0
  37. package/dist/cli/loop/analyze.js.map +1 -0
  38. package/dist/cli/loop/backlog.d.ts +26 -0
  39. package/dist/cli/loop/backlog.d.ts.map +1 -0
  40. package/dist/cli/loop/backlog.js +95 -0
  41. package/dist/cli/loop/backlog.js.map +1 -0
  42. package/dist/cli/loop/config.d.ts +10 -0
  43. package/dist/cli/loop/config.d.ts.map +1 -0
  44. package/dist/cli/loop/config.js +75 -0
  45. package/dist/cli/loop/config.js.map +1 -0
  46. package/dist/cli/loop/continuous.d.ts +6 -0
  47. package/dist/cli/loop/continuous.d.ts.map +1 -0
  48. package/dist/cli/loop/continuous.js +108 -0
  49. package/dist/cli/loop/continuous.js.map +1 -0
  50. package/dist/cli/loop/executor.d.ts +8 -0
  51. package/dist/cli/loop/executor.d.ts.map +1 -0
  52. package/dist/cli/loop/executor.js +600 -0
  53. package/dist/cli/loop/executor.js.map +1 -0
  54. package/dist/cli/loop/guard-runner.d.ts +14 -0
  55. package/dist/cli/loop/guard-runner.d.ts.map +1 -0
  56. package/dist/cli/loop/guard-runner.js +53 -0
  57. package/dist/cli/loop/guard-runner.js.map +1 -0
  58. package/dist/cli/loop/logger.d.ts +9 -0
  59. package/dist/cli/loop/logger.d.ts.map +1 -0
  60. package/dist/cli/loop/logger.js +37 -0
  61. package/dist/cli/loop/logger.js.map +1 -0
  62. package/dist/cli/loop/model-selector.d.ts +14 -0
  63. package/dist/cli/loop/model-selector.d.ts.map +1 -0
  64. package/dist/cli/loop/model-selector.js +59 -0
  65. package/dist/cli/loop/model-selector.js.map +1 -0
  66. package/dist/cli/loop/parallel.d.ts +6 -0
  67. package/dist/cli/loop/parallel.d.ts.map +1 -0
  68. package/dist/cli/loop/parallel.js +109 -0
  69. package/dist/cli/loop/parallel.js.map +1 -0
  70. package/dist/cli/loop/pr-lifecycle.d.ts +26 -0
  71. package/dist/cli/loop/pr-lifecycle.d.ts.map +1 -0
  72. package/dist/cli/loop/pr-lifecycle.js +244 -0
  73. package/dist/cli/loop/pr-lifecycle.js.map +1 -0
  74. package/dist/cli/loop/types.d.ts +98 -0
  75. package/dist/cli/loop/types.d.ts.map +1 -0
  76. package/dist/cli/loop/types.js +37 -0
  77. package/dist/cli/loop/types.js.map +1 -0
  78. package/dist/cli/loop/worktree.d.ts +30 -0
  79. package/dist/cli/loop/worktree.d.ts.map +1 -0
  80. package/dist/cli/loop/worktree.js +134 -0
  81. package/dist/cli/loop/worktree.js.map +1 -0
  82. package/dist/cli/registry.d.ts.map +1 -1
  83. package/dist/cli/registry.js +3 -0
  84. package/dist/cli/registry.js.map +1 -1
  85. package/dist/core/analyzers/stack.d.ts +2 -0
  86. package/dist/core/analyzers/stack.d.ts.map +1 -1
  87. package/dist/core/analyzers/stack.js +9 -6
  88. package/dist/core/analyzers/stack.js.map +1 -1
  89. package/dist/core/constants.d.ts +2 -0
  90. package/dist/core/constants.d.ts.map +1 -1
  91. package/dist/core/constants.js +2 -0
  92. package/dist/core/constants.js.map +1 -1
  93. package/dist/core/docs.d.ts +50 -0
  94. package/dist/core/docs.d.ts.map +1 -0
  95. package/dist/core/docs.js +67 -0
  96. package/dist/core/docs.js.map +1 -0
  97. package/dist/core/generators/roadmap.d.ts +6 -1
  98. package/dist/core/generators/roadmap.d.ts.map +1 -1
  99. package/dist/core/generators/roadmap.js +150 -0
  100. package/dist/core/generators/roadmap.js.map +1 -1
  101. package/dist/core/guard.d.ts +1 -1
  102. package/dist/core/guard.d.ts.map +1 -1
  103. package/dist/core/guard.js +8 -0
  104. package/dist/core/guard.js.map +1 -1
  105. package/dist/core/index.d.ts +5 -2
  106. package/dist/core/index.d.ts.map +1 -1
  107. package/dist/core/index.js +5 -2
  108. package/dist/core/index.js.map +1 -1
  109. package/dist/core/vision.d.ts +10 -0
  110. package/dist/core/vision.d.ts.map +1 -1
  111. package/dist/core/vision.js +37 -0
  112. package/dist/core/vision.js.map +1 -1
  113. package/dist/mcp/registry.d.ts.map +1 -1
  114. package/dist/mcp/registry.js +29 -0
  115. package/dist/mcp/registry.js.map +1 -1
  116. package/package.json +1 -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,6 @@
1
+ /**
2
+ * Dual-sprint parallel execution with module overlap detection.
3
+ * Mirrors slope-loop/parallel.sh behavior.
4
+ */
5
+ export declare function runParallel(flags: Record<string, string>, cwd: string): Promise<void>;
6
+ //# sourceMappingURL=parallel.d.ts.map
@@ -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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"}