@coralai/sps-cli 0.10.2 → 0.11.1

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 (62) hide show
  1. package/README.md +63 -23
  2. package/dist/commands/workerDashboard.d.ts.map +1 -1
  3. package/dist/commands/workerDashboard.js +39 -11
  4. package/dist/commands/workerDashboard.js.map +1 -1
  5. package/dist/core/config.d.ts +1 -0
  6. package/dist/core/config.d.ts.map +1 -1
  7. package/dist/core/config.js +1 -0
  8. package/dist/core/config.js.map +1 -1
  9. package/dist/core/state.d.ts +10 -0
  10. package/dist/core/state.d.ts.map +1 -1
  11. package/dist/core/state.js +5 -0
  12. package/dist/core/state.js.map +1 -1
  13. package/dist/engines/CloseoutEngine.d.ts.map +1 -1
  14. package/dist/engines/CloseoutEngine.js +79 -28
  15. package/dist/engines/CloseoutEngine.js.map +1 -1
  16. package/dist/engines/ExecutionEngine.d.ts +5 -0
  17. package/dist/engines/ExecutionEngine.d.ts.map +1 -1
  18. package/dist/engines/ExecutionEngine.js +80 -16
  19. package/dist/engines/ExecutionEngine.js.map +1 -1
  20. package/dist/engines/MonitorEngine.d.ts.map +1 -1
  21. package/dist/engines/MonitorEngine.js +6 -1
  22. package/dist/engines/MonitorEngine.js.map +1 -1
  23. package/dist/interfaces/WorkerProvider.d.ts +68 -15
  24. package/dist/interfaces/WorkerProvider.d.ts.map +1 -1
  25. package/dist/models/types.d.ts +3 -1
  26. package/dist/models/types.d.ts.map +1 -1
  27. package/dist/providers/ClaudePrintProvider.d.ts +54 -0
  28. package/dist/providers/ClaudePrintProvider.d.ts.map +1 -0
  29. package/dist/providers/ClaudePrintProvider.js +279 -0
  30. package/dist/providers/ClaudePrintProvider.js.map +1 -0
  31. package/dist/providers/ClaudeTmuxProvider.d.ts +94 -0
  32. package/dist/providers/ClaudeTmuxProvider.d.ts.map +1 -0
  33. package/dist/providers/ClaudeTmuxProvider.js +331 -0
  34. package/dist/providers/ClaudeTmuxProvider.js.map +1 -0
  35. package/dist/providers/ClaudeWorkerProvider.d.ts +5 -93
  36. package/dist/providers/ClaudeWorkerProvider.d.ts.map +1 -1
  37. package/dist/providers/ClaudeWorkerProvider.js +3 -303
  38. package/dist/providers/ClaudeWorkerProvider.js.map +1 -1
  39. package/dist/providers/CodexExecProvider.d.ts +36 -0
  40. package/dist/providers/CodexExecProvider.d.ts.map +1 -0
  41. package/dist/providers/CodexExecProvider.js +238 -0
  42. package/dist/providers/CodexExecProvider.js.map +1 -0
  43. package/dist/providers/CodexTmuxProvider.d.ts +71 -0
  44. package/dist/providers/CodexTmuxProvider.d.ts.map +1 -0
  45. package/dist/providers/CodexTmuxProvider.js +351 -0
  46. package/dist/providers/CodexTmuxProvider.js.map +1 -0
  47. package/dist/providers/CodexWorkerProvider.d.ts +5 -70
  48. package/dist/providers/CodexWorkerProvider.d.ts.map +1 -1
  49. package/dist/providers/CodexWorkerProvider.js +3 -328
  50. package/dist/providers/CodexWorkerProvider.js.map +1 -1
  51. package/dist/providers/outputParser.d.ts +50 -0
  52. package/dist/providers/outputParser.d.ts.map +1 -0
  53. package/dist/providers/outputParser.js +219 -0
  54. package/dist/providers/outputParser.js.map +1 -0
  55. package/dist/providers/registry.d.ts.map +1 -1
  56. package/dist/providers/registry.js +18 -6
  57. package/dist/providers/registry.js.map +1 -1
  58. package/dist/providers/streamRenderer.d.ts +13 -0
  59. package/dist/providers/streamRenderer.d.ts.map +1 -0
  60. package/dist/providers/streamRenderer.js +106 -0
  61. package/dist/providers/streamRenderer.js.map +1 -0
  62. package/package.json +1 -1
@@ -1,331 +1,6 @@
1
- import { execFileSync } from 'node:child_process';
2
- import { existsSync, readFileSync } from 'node:fs';
3
1
  /**
4
- * Codex CLI patterns (differs from Claude):
5
- *
6
- * Ready prompt: › <placeholder>
7
- * gpt-5.3-codex default · ...
8
- *
9
- * Completion: returns to › prompt after task
10
- *
11
- * Update blocker: ✨ Update available!
12
- * › 1. Update now
13
- * 2. Skip
14
- * 3. Skip until next version
15
- * Press enter to continue
16
- *
17
- * Confirmation: (none with --dangerously-bypass-approvals-and-sandbox)
18
- *
19
- * Exit command: /quit (Claude uses /exit)
2
+ * @deprecated Use CodexTmuxProvider or CodexExecProvider directly.
3
+ * This re-export exists for backward compatibility with existing imports.
20
4
  */
21
- /** Completion keywords in codex pane text. */
22
- const COMPLETION_KEYWORDS = /\b(done|completed|finished|Next step:|committed|pushed|MR created|merge request)\b/i;
23
- /** Codex ready prompt: › at start of line + model info line */
24
- const CODEX_READY = /›\s.*$/m;
25
- const CODEX_MODEL_LINE = /codex.*default.*·/i;
26
- /** Codex update blocker pattern */
27
- const CODEX_UPDATE_PROMPT = /Update available|Skip until next version/i;
28
- /** Codex rate-limit model switch prompt */
29
- const CODEX_RATE_LIMIT_PROMPT = /rate limit|Switch to .+codex-mini|Keep current model/i;
30
- /**
31
- * Run a tmux command. Returns null on failure.
32
- */
33
- function tmux(args) {
34
- try {
35
- return execFileSync('tmux', args, {
36
- encoding: 'utf-8',
37
- timeout: 10_000,
38
- stdio: ['ignore', 'pipe', 'pipe'],
39
- });
40
- }
41
- catch (err) {
42
- const stderr = err.stderr ?? '';
43
- if (stderr.includes('server exited unexpectedly') || stderr.includes('no server running')) {
44
- try {
45
- const uid = process.getuid?.() ?? 1000;
46
- const { rmSync } = require('node:fs');
47
- rmSync(`/tmp/tmux-${uid}`, { recursive: true, force: true });
48
- process.stderr.write('[codex-worker] Cleaned stale tmux socket, retrying\n');
49
- return execFileSync('tmux', args, {
50
- encoding: 'utf-8',
51
- timeout: 10_000,
52
- stdio: ['ignore', 'pipe', 'pipe'],
53
- });
54
- }
55
- catch {
56
- return null;
57
- }
58
- }
59
- return null;
60
- }
61
- }
62
- function sessionExists(session) {
63
- return tmux(['has-session', '-t', session]) !== null;
64
- }
65
- function capturePaneText(session, lines) {
66
- return tmux(['capture-pane', '-t', session, '-p', '-S', `-${lines}`]) ?? '';
67
- }
68
- export class CodexWorkerProvider {
69
- config;
70
- constructor(config) {
71
- this.config = config;
72
- }
73
- async prepareEnv(worktree, _seq) {
74
- if (!existsSync(worktree)) {
75
- throw new Error(`Worktree directory does not exist: ${worktree}`);
76
- }
77
- try {
78
- execFileSync('git', ['-C', worktree, 'rev-parse', '--is-inside-work-tree'], {
79
- encoding: 'utf-8', timeout: 5_000, stdio: ['ignore', 'pipe', 'pipe'],
80
- });
81
- }
82
- catch {
83
- throw new Error(`Directory is not a git worktree: ${worktree}`);
84
- }
85
- }
86
- /**
87
- * Launch Codex in a tmux session (interactive mode).
88
- * Handles session reuse and update prompt auto-skip.
89
- */
90
- async launch(session, worktree) {
91
- const codexCmd = 'codex --sandbox danger-full-access -a never --no-alt-screen';
92
- if (sessionExists(session)) {
93
- const pane = capturePaneText(session, 10);
94
- const codexAlive = CODEX_READY.test(pane) && CODEX_MODEL_LINE.test(pane);
95
- if (codexAlive) {
96
- // Codex running — clear conversation + switch worktree
97
- process.stderr.write(`[codex-worker] Reusing live Codex session ${session}\n`);
98
- tmux(['send-keys', '-t', session, '/clear', 'Enter']);
99
- await this.sleep(1_000);
100
- // Codex doesn't support cd mid-session, but we can try
101
- tmux(['send-keys', '-t', session, `/cd ${worktree}`, 'Enter']);
102
- await this.sleep(500);
103
- return;
104
- }
105
- // Session exists but Codex not running
106
- process.stderr.write(`[codex-worker] Reusing tmux session ${session}\n`);
107
- tmux(['send-keys', '-t', session, `cd ${worktree}`, 'Enter']);
108
- await this.sleep(500);
109
- tmux(['send-keys', '-t', session, codexCmd, 'Enter']);
110
- return;
111
- }
112
- // New session
113
- const result = tmux(['new-session', '-d', '-s', session, '-c', worktree]);
114
- if (result === null && !sessionExists(session)) {
115
- throw new Error(`Failed to create tmux session: ${session}`);
116
- }
117
- tmux(['send-keys', '-t', session, codexCmd, 'Enter']);
118
- }
119
- /**
120
- * Wait for Codex to be ready.
121
- * Must handle the update prompt blocker (auto-skip).
122
- */
123
- async waitReady(session, timeoutMs = 90_000) {
124
- const pollInterval = 3_000;
125
- const deadline = Date.now() + timeoutMs;
126
- let updateSkipped = false;
127
- // Codex is slower to start than Claude — wait longer before first check
128
- await this.sleep(5_000);
129
- while (Date.now() < deadline) {
130
- const text = capturePaneText(session, 30);
131
- // Handle update prompt — send Enter to dismiss, then skip
132
- if (!updateSkipped && CODEX_UPDATE_PROMPT.test(text)) {
133
- process.stderr.write('[codex-worker] Detected update prompt, skipping\n');
134
- // If showing numbered options (1/2/3), select 3 "Skip until next version"
135
- if (/1\. Update now/i.test(text)) {
136
- tmux(['send-keys', '-t', session, 'Down']);
137
- await this.sleep(300);
138
- tmux(['send-keys', '-t', session, 'Down']);
139
- await this.sleep(300);
140
- }
141
- tmux(['send-keys', '-t', session, 'Enter']);
142
- updateSkipped = true;
143
- await this.sleep(5_000);
144
- continue;
145
- }
146
- // Handle "Press enter to continue" after update banner
147
- if (/Press enter to continue/i.test(text)) {
148
- tmux(['send-keys', '-t', session, 'Enter']);
149
- await this.sleep(3_000);
150
- continue;
151
- }
152
- // Handle rate-limit model switch prompt — select "Keep current model"
153
- if (CODEX_RATE_LIMIT_PROMPT.test(text)) {
154
- process.stderr.write('[codex-worker] Detected rate-limit model switch prompt, keeping current model\n');
155
- this.dismissRateLimitPrompt(session);
156
- await this.sleep(3_000);
157
- continue;
158
- }
159
- // Check if Codex is ready: › prompt + model info line
160
- if (CODEX_MODEL_LINE.test(text) && CODEX_READY.test(text)) {
161
- process.stderr.write('[codex-worker] Codex ready\n');
162
- return true;
163
- }
164
- // Also match "OpenAI Codex" banner + › prompt
165
- if (/OpenAI Codex/i.test(text) && /›/m.test(text)) {
166
- process.stderr.write('[codex-worker] Codex ready (banner match)\n');
167
- return true;
168
- }
169
- await this.sleep(pollInterval);
170
- }
171
- process.stderr.write(`[codex-worker] waitReady timed out after ${timeoutMs}ms\n`);
172
- return false;
173
- }
174
- /**
175
- * Send task prompt to Codex via tmux paste-buffer.
176
- */
177
- async sendTask(session, promptFile) {
178
- if (!existsSync(promptFile)) {
179
- throw new Error(`Prompt file does not exist: ${promptFile}`);
180
- }
181
- const content = readFileSync(promptFile, 'utf-8').trim();
182
- const bufferFile = `/tmp/sps-task-${Date.now()}.txt`;
183
- const { writeFileSync: writeTmp, unlinkSync } = await import('node:fs');
184
- writeTmp(bufferFile, content);
185
- tmux(['load-buffer', bufferFile]);
186
- tmux(['paste-buffer', '-t', session]);
187
- try {
188
- unlinkSync(bufferFile);
189
- }
190
- catch { /* cleanup */ }
191
- await this.sleep(500);
192
- tmux(['send-keys', '-t', session, 'Enter']);
193
- }
194
- async inspect(session) {
195
- const alive = sessionExists(session);
196
- const paneText = alive ? capturePaneText(session, 50) : '';
197
- return { alive, paneText };
198
- }
199
- /**
200
- * Codex with --dangerously-bypass-approvals-and-sandbox doesn't need confirmation.
201
- * But if run without that flag, it may show approval prompts.
202
- * For now, always return not waiting since we use bypass mode.
203
- */
204
- async detectWaiting(session) {
205
- // Codex in bypass mode doesn't have confirmation prompts
206
- // But check for any "Press enter" or similar blockers
207
- const pane = capturePaneText(session, 15);
208
- // Update prompt blocker
209
- if (CODEX_UPDATE_PROMPT.test(pane)) {
210
- return { waiting: true, destructive: false, prompt: 'Codex update prompt' };
211
- }
212
- // Rate-limit model switch prompt — auto-dismiss
213
- if (CODEX_RATE_LIMIT_PROMPT.test(pane)) {
214
- process.stderr.write('[codex-worker] Auto-dismissing rate-limit model switch prompt\n');
215
- this.dismissRateLimitPrompt(session);
216
- return { waiting: false, destructive: false, prompt: '' }; // handled, not waiting
217
- }
218
- return { waiting: false, destructive: false, prompt: '' };
219
- }
220
- /**
221
- * Detect completion by checking if Codex returned to › prompt after working.
222
- */
223
- async detectCompleted(session, logDir, _branch) {
224
- // Priority 1: task_completed marker file (same as Claude)
225
- const markerPath = `${logDir}/task_completed`;
226
- if (existsSync(markerPath)) {
227
- return 'COMPLETED';
228
- }
229
- // Priority 2: check for interactive prompts (needs auto-skip, not completion)
230
- const pane = capturePaneText(session, 20);
231
- if (CODEX_UPDATE_PROMPT.test(pane)) {
232
- return 'NEEDS_INPUT'; // will trigger auto-confirm to skip update
233
- }
234
- if (CODEX_RATE_LIMIT_PROMPT.test(pane)) {
235
- // Auto-dismiss and report ALIVE (not completed, not blocked)
236
- process.stderr.write('[codex-worker] Rate-limit prompt detected during completion check, dismissing\n');
237
- this.dismissRateLimitPrompt(session);
238
- return 'ALIVE';
239
- }
240
- // Priority 3: completion keywords + back at › prompt
241
- if (COMPLETION_KEYWORDS.test(pane) && CODEX_READY.test(pane) && CODEX_MODEL_LINE.test(pane)) {
242
- return 'COMPLETED';
243
- }
244
- // Priority 4: session alive
245
- if (sessionExists(session)) {
246
- return 'ALIVE';
247
- }
248
- return 'DEAD';
249
- }
250
- async detectBlocked(session) {
251
- const pane = capturePaneText(session, 30);
252
- return /(error|fatal|rate.?limit|quota exceeded)/i.test(pane);
253
- }
254
- async sendFix(session, fixPrompt) {
255
- const escaped = fixPrompt.replace(/'/g, "'\\''");
256
- tmux(['send-keys', '-t', session, escaped, 'Enter']);
257
- }
258
- async resolveConflict(session, worktree, branch) {
259
- const instruction = [
260
- `There is a merge conflict on branch ${branch}.`,
261
- `Working directory: ${worktree}`,
262
- 'Please resolve the conflict:',
263
- `1. Run: git fetch origin && git rebase origin/${this.config.GITLAB_MERGE_BRANCH}`,
264
- '2. Resolve any conflicts in the affected files',
265
- '3. Run: git add . && git rebase --continue',
266
- '4. Run: git push --force-with-lease',
267
- ].join('\n');
268
- tmux(['send-keys', '-t', session, instruction, 'Enter']);
269
- }
270
- /**
271
- * Release a worker session after task completion.
272
- *
273
- * WORKER_SESSION_REUSE=true: do nothing — keep Codex running so the
274
- * next task can hot-reuse the session via /clear + cd.
275
- *
276
- * WORKER_SESSION_REUSE=false: quit Codex but keep tmux session alive.
277
- */
278
- async release(session) {
279
- if (!sessionExists(session))
280
- return;
281
- if (this.config.WORKER_SESSION_REUSE) {
282
- // Keep everything alive — next launch() will /clear + /cd + send prompt
283
- process.stderr.write(`[codex-worker] Session ${session} kept alive for reuse\n`);
284
- return;
285
- }
286
- // Quit Codex but keep tmux session
287
- tmux(['send-keys', '-t', session, '/quit', 'Enter']);
288
- }
289
- /**
290
- * Force-stop a worker session (error recovery, cleanup).
291
- * Always quits Codex and kills the tmux session.
292
- */
293
- async stop(session) {
294
- if (!sessionExists(session))
295
- return;
296
- tmux(['send-keys', '-t', session, '/quit', 'Enter']);
297
- for (let i = 0; i < 5; i++) {
298
- await this.sleep(1_000);
299
- if (!sessionExists(session))
300
- return;
301
- }
302
- tmux(['kill-session', '-t', session]);
303
- }
304
- async collectSummary(session) {
305
- return capturePaneText(session, 100);
306
- }
307
- /**
308
- * Dismiss the rate-limit model switch prompt by selecting "Keep current model".
309
- *
310
- * The prompt shows:
311
- * › 1. Switch to gpt-5.1-codex-mini
312
- * 2. Keep current model
313
- * 3. Keep current model (never show again)
314
- *
315
- * Strategy: press Down once to select option 2, then Enter.
316
- */
317
- dismissRateLimitPrompt(session) {
318
- // Navigate to "Keep current model" (option 2)
319
- tmux(['send-keys', '-t', session, 'Down']);
320
- // Small delay to let the UI register the selection
321
- tmux(['send-keys', '-t', session, '']);
322
- // Confirm selection
323
- setTimeout(() => {
324
- tmux(['send-keys', '-t', session, 'Enter']);
325
- }, 500);
326
- }
327
- sleep(ms) {
328
- return new Promise((resolve) => setTimeout(resolve, ms));
329
- }
330
- }
5
+ export { CodexTmuxProvider as CodexWorkerProvider } from './CodexTmuxProvider.js';
331
6
  //# sourceMappingURL=CodexWorkerProvider.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"CodexWorkerProvider.js","sourceRoot":"","sources":["../../src/providers/CodexWorkerProvider.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"CodexWorkerProvider.js","sourceRoot":"","sources":["../../src/providers/CodexWorkerProvider.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,iBAAiB,IAAI,mBAAmB,EAAE,MAAM,wBAAwB,CAAC"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Read the last N lines from a file efficiently.
3
+ * Returns empty string if file doesn't exist.
4
+ */
5
+ export declare function tailFile(filePath: string, lines: number): string;
6
+ /**
7
+ * Get file size in bytes (for checking if output is being written).
8
+ */
9
+ export declare function fileSize(filePath: string): number;
10
+ /**
11
+ * Parse session ID from a Claude stream-json output file.
12
+ *
13
+ * Claude --output-format stream-json emits lines like:
14
+ * {"type":"result",...,"session_id":"uuid",...}
15
+ *
16
+ * We also check the very first system message.
17
+ */
18
+ export declare function parseClaudeSessionId(filePath: string): string | null;
19
+ /**
20
+ * Parse session ID from a Codex exec --json JSONL output file.
21
+ *
22
+ * Codex emits JSONL events. Look for session/conversation ID.
23
+ */
24
+ export declare function parseCodexSessionId(filePath: string): string | null;
25
+ /**
26
+ * Check if a process is alive by sending signal 0.
27
+ */
28
+ export declare function isProcessAlive(pid: number): boolean;
29
+ /**
30
+ * Kill a process group. First SIGTERM, then SIGKILL after timeout.
31
+ * Uses negative PID to signal the entire process group.
32
+ */
33
+ export declare function killProcessGroup(pid: number, timeoutMs?: number): Promise<void>;
34
+ /**
35
+ * Check if a branch has commits ahead of a base branch.
36
+ * This is the most reliable signal that the worker actually did work.
37
+ *
38
+ * Returns the number of commits ahead, or -1 on error.
39
+ */
40
+ export declare function branchCommitsAhead(worktree: string, branch: string, baseBranch: string): number;
41
+ /**
42
+ * Check if branch has been pushed to remote (remote tracking ref exists).
43
+ */
44
+ export declare function branchPushed(worktree: string, branch: string): boolean;
45
+ /**
46
+ * Extract the last assistant message text from Claude stream-json output.
47
+ * Useful for verifying task completion.
48
+ */
49
+ export declare function extractLastAssistantText(filePath: string): string;
50
+ //# sourceMappingURL=outputParser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outputParser.d.ts","sourceRoot":"","sources":["../../src/providers/outputParser.ts"],"names":[],"mappings":"AAOA;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAShE;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMjD;AAED;;;;;;;GAOG;AACH,wBAAgB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAiBpE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoBnE;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAQnD;AAED;;;GAGG;AACH,wBAAsB,gBAAgB,CAAC,GAAG,EAAE,MAAM,EAAE,SAAS,SAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAqBpF;AAID;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAkB/F;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAWtE;AAED;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CA2BjE"}
@@ -0,0 +1,219 @@
1
+ /**
2
+ * Shared utilities for print-mode worker providers.
3
+ * Handles output file tailing, session ID parsing, and process inspection.
4
+ */
5
+ import { readFileSync, existsSync, statSync } from 'node:fs';
6
+ import { execFileSync } from 'node:child_process';
7
+ /**
8
+ * Read the last N lines from a file efficiently.
9
+ * Returns empty string if file doesn't exist.
10
+ */
11
+ export function tailFile(filePath, lines) {
12
+ if (!existsSync(filePath))
13
+ return '';
14
+ try {
15
+ const content = readFileSync(filePath, 'utf-8');
16
+ const allLines = content.split('\n');
17
+ return allLines.slice(-lines).join('\n');
18
+ }
19
+ catch {
20
+ return '';
21
+ }
22
+ }
23
+ /**
24
+ * Get file size in bytes (for checking if output is being written).
25
+ */
26
+ export function fileSize(filePath) {
27
+ try {
28
+ return statSync(filePath).size;
29
+ }
30
+ catch {
31
+ return 0;
32
+ }
33
+ }
34
+ /**
35
+ * Parse session ID from a Claude stream-json output file.
36
+ *
37
+ * Claude --output-format stream-json emits lines like:
38
+ * {"type":"result",...,"session_id":"uuid",...}
39
+ *
40
+ * We also check the very first system message.
41
+ */
42
+ export function parseClaudeSessionId(filePath) {
43
+ if (!existsSync(filePath))
44
+ return null;
45
+ try {
46
+ const content = readFileSync(filePath, 'utf-8');
47
+ for (const line of content.split('\n')) {
48
+ if (!line.trim())
49
+ continue;
50
+ try {
51
+ const obj = JSON.parse(line);
52
+ if (obj.session_id)
53
+ return obj.session_id;
54
+ }
55
+ catch {
56
+ // not valid JSON, skip
57
+ }
58
+ }
59
+ }
60
+ catch {
61
+ // file read error
62
+ }
63
+ return null;
64
+ }
65
+ /**
66
+ * Parse session ID from a Codex exec --json JSONL output file.
67
+ *
68
+ * Codex emits JSONL events. Look for session/conversation ID.
69
+ */
70
+ export function parseCodexSessionId(filePath) {
71
+ if (!existsSync(filePath))
72
+ return null;
73
+ try {
74
+ const content = readFileSync(filePath, 'utf-8');
75
+ for (const line of content.split('\n')) {
76
+ if (!line.trim())
77
+ continue;
78
+ try {
79
+ const obj = JSON.parse(line);
80
+ // Codex uses conversation_id or session_id
81
+ if (obj.conversation_id)
82
+ return obj.conversation_id;
83
+ if (obj.session_id)
84
+ return obj.session_id;
85
+ if (obj.id && typeof obj.id === 'string' && obj.type === 'session_start')
86
+ return obj.id;
87
+ }
88
+ catch {
89
+ // not valid JSON
90
+ }
91
+ }
92
+ }
93
+ catch {
94
+ // file read error
95
+ }
96
+ return null;
97
+ }
98
+ /**
99
+ * Check if a process is alive by sending signal 0.
100
+ */
101
+ export function isProcessAlive(pid) {
102
+ if (!pid || pid <= 0)
103
+ return false;
104
+ try {
105
+ process.kill(pid, 0);
106
+ return true;
107
+ }
108
+ catch {
109
+ return false;
110
+ }
111
+ }
112
+ /**
113
+ * Kill a process group. First SIGTERM, then SIGKILL after timeout.
114
+ * Uses negative PID to signal the entire process group.
115
+ */
116
+ export async function killProcessGroup(pid, timeoutMs = 5_000) {
117
+ if (!isProcessAlive(pid))
118
+ return;
119
+ try {
120
+ // Signal the process group
121
+ process.kill(-pid, 'SIGTERM');
122
+ }
123
+ catch {
124
+ // Process group may not exist, try direct kill
125
+ try {
126
+ process.kill(pid, 'SIGTERM');
127
+ }
128
+ catch {
129
+ return;
130
+ }
131
+ }
132
+ // Wait for graceful shutdown
133
+ const deadline = Date.now() + timeoutMs;
134
+ while (Date.now() < deadline) {
135
+ if (!isProcessAlive(pid))
136
+ return;
137
+ await new Promise((r) => setTimeout(r, 500));
138
+ }
139
+ // Force kill
140
+ try {
141
+ process.kill(-pid, 'SIGKILL');
142
+ }
143
+ catch { /* ignore */ }
144
+ try {
145
+ process.kill(pid, 'SIGKILL');
146
+ }
147
+ catch { /* ignore */ }
148
+ }
149
+ // ─── Git Artifact Verification ─────────────────────────────────────
150
+ /**
151
+ * Check if a branch has commits ahead of a base branch.
152
+ * This is the most reliable signal that the worker actually did work.
153
+ *
154
+ * Returns the number of commits ahead, or -1 on error.
155
+ */
156
+ export function branchCommitsAhead(worktree, branch, baseBranch) {
157
+ try {
158
+ // Fetch latest remote state (best-effort, may fail offline)
159
+ try {
160
+ execFileSync('git', ['-C', worktree, 'fetch', 'origin', '--quiet'], {
161
+ timeout: 10_000, stdio: ['ignore', 'pipe', 'pipe'],
162
+ });
163
+ }
164
+ catch { /* offline or no remote — ok, use local state */ }
165
+ const output = execFileSync('git', ['-C', worktree, 'rev-list', '--count', `origin/${baseBranch}..${branch}`], { encoding: 'utf-8', timeout: 5_000, stdio: ['ignore', 'pipe', 'pipe'] }).trim();
166
+ return parseInt(output, 10) || 0;
167
+ }
168
+ catch {
169
+ return -1; // git error
170
+ }
171
+ }
172
+ /**
173
+ * Check if branch has been pushed to remote (remote tracking ref exists).
174
+ */
175
+ export function branchPushed(worktree, branch) {
176
+ try {
177
+ execFileSync('git', ['-C', worktree, 'rev-parse', '--verify', `origin/${branch}`], { encoding: 'utf-8', timeout: 5_000, stdio: ['ignore', 'pipe', 'pipe'] });
178
+ return true;
179
+ }
180
+ catch {
181
+ return false;
182
+ }
183
+ }
184
+ /**
185
+ * Extract the last assistant message text from Claude stream-json output.
186
+ * Useful for verifying task completion.
187
+ */
188
+ export function extractLastAssistantText(filePath) {
189
+ if (!existsSync(filePath))
190
+ return '';
191
+ try {
192
+ const content = readFileSync(filePath, 'utf-8');
193
+ const lines = content.split('\n').filter((l) => l.trim());
194
+ let lastText = '';
195
+ for (const line of lines) {
196
+ try {
197
+ const obj = JSON.parse(line);
198
+ // Claude stream-json assistant content messages
199
+ if (obj.type === 'assistant' && typeof obj.message?.content === 'string') {
200
+ lastText = obj.message.content;
201
+ }
202
+ // Also check result type
203
+ if (obj.type === 'result' && typeof obj.result === 'string') {
204
+ lastText = obj.result;
205
+ }
206
+ // Content block text
207
+ if (obj.type === 'content_block_delta' && obj.delta?.text) {
208
+ lastText += obj.delta.text;
209
+ }
210
+ }
211
+ catch { /* skip */ }
212
+ }
213
+ return lastText;
214
+ }
215
+ catch {
216
+ return '';
217
+ }
218
+ }
219
+ //# sourceMappingURL=outputParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"outputParser.js","sourceRoot":"","sources":["../../src/providers/outputParser.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAS1D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAOpE;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,GAAG,cAAc,CAM1E;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAEpE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,QAAQ,CAE9D"}
1
+ {"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/providers/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAC;AAChE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAW1D,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAOpE;AAED,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,aAAa,GAAG,cAAc,CAkB1E;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,WAAW,CAEpE;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,aAAa,GAAG,QAAQ,CAE9D"}