@rallycry/conveyor-agent 2.3.0 → 2.4.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/{chunk-DABNCE36.js → chunk-US4HLRJA.js} +308 -94
- package/dist/chunk-US4HLRJA.js.map +1 -0
- package/dist/cli.js +1 -1
- package/dist/index.d.ts +34 -3
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-DABNCE36.js.map +0 -1
|
@@ -19,7 +19,7 @@ var ConveyorConnection = class _ConveyorConnection {
|
|
|
19
19
|
let attempts = 0;
|
|
20
20
|
const maxInitialAttempts = 30;
|
|
21
21
|
this.socket = io(this.config.conveyorApiUrl, {
|
|
22
|
-
auth: { taskToken: this.config.taskToken },
|
|
22
|
+
auth: { taskToken: this.config.taskToken, runnerMode: this.config.mode ?? "task" },
|
|
23
23
|
transports: ["websocket"],
|
|
24
24
|
reconnection: true,
|
|
25
25
|
reconnectionAttempts: Infinity,
|
|
@@ -177,6 +177,19 @@ var ConveyorConnection = class _ConveyorConnection {
|
|
|
177
177
|
...params
|
|
178
178
|
});
|
|
179
179
|
}
|
|
180
|
+
emitStatus(status) {
|
|
181
|
+
if (!this.socket) return;
|
|
182
|
+
this.socket.emit("agentRunner:statusUpdate", {
|
|
183
|
+
taskId: this.config.taskId,
|
|
184
|
+
status
|
|
185
|
+
});
|
|
186
|
+
}
|
|
187
|
+
sendHeartbeat() {
|
|
188
|
+
if (!this.socket) return;
|
|
189
|
+
this.socket.emit("agentRunner:heartbeat", {
|
|
190
|
+
taskId: this.config.taskId
|
|
191
|
+
});
|
|
192
|
+
}
|
|
180
193
|
sendTypingStart() {
|
|
181
194
|
this.sendEvent({ type: "agent_typing_start" });
|
|
182
195
|
}
|
|
@@ -306,79 +319,145 @@ import {
|
|
|
306
319
|
createSdkMcpServer
|
|
307
320
|
} from "@anthropic-ai/claude-agent-sdk";
|
|
308
321
|
import { z } from "zod";
|
|
322
|
+
var API_ERROR_PATTERN = /API Error: [45]\d\d/;
|
|
323
|
+
var RETRY_DELAYS_MS = [6e4, 12e4, 18e4, 3e5];
|
|
324
|
+
var HEARTBEAT_INTERVAL_MS = 3e4;
|
|
309
325
|
var AgentRunner = class _AgentRunner {
|
|
310
326
|
config;
|
|
311
327
|
connection;
|
|
312
328
|
callbacks;
|
|
329
|
+
_state = "connecting";
|
|
313
330
|
stopped = false;
|
|
314
331
|
inputResolver = null;
|
|
315
332
|
pendingMessages = [];
|
|
316
333
|
currentTurnToolCalls = [];
|
|
317
334
|
setupLog = [];
|
|
335
|
+
heartbeatTimer = null;
|
|
336
|
+
taskContext = null;
|
|
318
337
|
static MAX_SETUP_LOG_LINES = 50;
|
|
319
338
|
constructor(config, callbacks) {
|
|
320
339
|
this.config = config;
|
|
321
340
|
this.connection = new ConveyorConnection(config);
|
|
322
341
|
this.callbacks = callbacks;
|
|
323
342
|
}
|
|
343
|
+
get state() {
|
|
344
|
+
return this._state;
|
|
345
|
+
}
|
|
346
|
+
async setState(status) {
|
|
347
|
+
this._state = status;
|
|
348
|
+
this.connection.emitStatus(status);
|
|
349
|
+
await this.callbacks.onStatusChange(status);
|
|
350
|
+
}
|
|
351
|
+
startHeartbeat() {
|
|
352
|
+
this.heartbeatTimer = setInterval(() => {
|
|
353
|
+
if (!this.stopped) {
|
|
354
|
+
this.connection.sendHeartbeat();
|
|
355
|
+
}
|
|
356
|
+
}, HEARTBEAT_INTERVAL_MS);
|
|
357
|
+
}
|
|
358
|
+
stopHeartbeat() {
|
|
359
|
+
if (this.heartbeatTimer) {
|
|
360
|
+
clearInterval(this.heartbeatTimer);
|
|
361
|
+
this.heartbeatTimer = null;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
// oxlint-disable-next-line max-lines-per-function
|
|
324
365
|
async start() {
|
|
325
|
-
await this.
|
|
366
|
+
await this.setState("connecting");
|
|
326
367
|
await this.connection.connect();
|
|
327
368
|
this.connection.onStopRequested(() => {
|
|
328
|
-
this.
|
|
369
|
+
this.stop();
|
|
329
370
|
});
|
|
330
371
|
this.connection.onChatMessage((message) => {
|
|
331
372
|
this.injectHumanMessage(message.content);
|
|
332
373
|
});
|
|
374
|
+
await this.setState("connected");
|
|
333
375
|
this.connection.sendEvent({
|
|
334
376
|
type: "connected",
|
|
335
377
|
taskId: this.config.taskId
|
|
336
378
|
});
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
);
|
|
379
|
+
this.startHeartbeat();
|
|
380
|
+
if (this.config.mode !== "pm" && process.env.CODESPACES === "true") {
|
|
381
|
+
const setupOk = await this.runSetupSafe();
|
|
382
|
+
if (!setupOk) {
|
|
383
|
+
this.stopHeartbeat();
|
|
384
|
+
await this.setState("error");
|
|
385
|
+
this.connection.disconnect();
|
|
386
|
+
return;
|
|
346
387
|
}
|
|
347
|
-
await this.runProjectSetup();
|
|
348
388
|
}
|
|
349
389
|
this.initRtk();
|
|
350
|
-
await this.
|
|
351
|
-
|
|
352
|
-
|
|
390
|
+
await this.setState("fetching_context");
|
|
391
|
+
try {
|
|
392
|
+
this.taskContext = await this.connection.fetchTaskContext();
|
|
393
|
+
} catch (error) {
|
|
394
|
+
const message = error instanceof Error ? error.message : "Failed to fetch task context";
|
|
395
|
+
this.connection.sendEvent({ type: "error", message });
|
|
396
|
+
await this.callbacks.onEvent({ type: "error", message });
|
|
397
|
+
this.stopHeartbeat();
|
|
398
|
+
await this.setState("error");
|
|
399
|
+
this.connection.disconnect();
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
if (process.env.CODESPACES === "true" && this.taskContext.baseBranch) {
|
|
353
403
|
const result = cleanDevcontainerFromGit(
|
|
354
404
|
this.config.workspaceDir,
|
|
355
|
-
|
|
356
|
-
|
|
405
|
+
this.taskContext.githubBranch,
|
|
406
|
+
this.taskContext.baseBranch
|
|
357
407
|
);
|
|
358
408
|
if (result.cleaned) {
|
|
359
409
|
this.setupLog.push(`[conveyor] ${result.message}`);
|
|
360
410
|
}
|
|
361
411
|
}
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
await this.
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
this.
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
412
|
+
const isPm = this.config.mode === "pm";
|
|
413
|
+
if (isPm) {
|
|
414
|
+
await this.setState("idle");
|
|
415
|
+
} else {
|
|
416
|
+
await this.setState("running");
|
|
417
|
+
await this.runSdkQuery(this.taskContext);
|
|
418
|
+
if (!this.stopped) {
|
|
419
|
+
await this.setState("idle");
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
while (!this.stopped) {
|
|
423
|
+
if (this._state === "idle") {
|
|
424
|
+
const msg = await this.waitForUserContent();
|
|
425
|
+
if (!msg) break;
|
|
426
|
+
await this.setState("running");
|
|
427
|
+
await this.runSdkQuery(this.taskContext, msg);
|
|
428
|
+
if (!this.stopped) {
|
|
429
|
+
await this.setState("idle");
|
|
430
|
+
}
|
|
431
|
+
} else if (this._state === "error") {
|
|
432
|
+
await this.setState("idle");
|
|
433
|
+
} else {
|
|
434
|
+
break;
|
|
435
|
+
}
|
|
373
436
|
}
|
|
437
|
+
this.stopHeartbeat();
|
|
438
|
+
await this.setState("finished");
|
|
439
|
+
this.connection.disconnect();
|
|
374
440
|
}
|
|
375
|
-
|
|
376
|
-
|
|
441
|
+
/**
|
|
442
|
+
* Wraps project setup in try/catch. On failure, posts error to chat
|
|
443
|
+
* directly (no SDK needed) and streams to CLI. Returns false if setup failed.
|
|
444
|
+
*/
|
|
445
|
+
async runSetupSafe() {
|
|
446
|
+
await this.setState("setup");
|
|
447
|
+
const ports = await loadForwardPorts(this.config.workspaceDir);
|
|
448
|
+
if (ports.length > 0 && process.env.CODESPACE_NAME) {
|
|
449
|
+
const visibility = ports.map((p) => `${p}:public`).join(" ");
|
|
450
|
+
runStartCommand(
|
|
451
|
+
`gh codespace ports visibility ${visibility} -c "${process.env.CODESPACE_NAME}" 2>/dev/null`,
|
|
452
|
+
this.config.workspaceDir,
|
|
453
|
+
() => void 0
|
|
454
|
+
);
|
|
455
|
+
}
|
|
377
456
|
const config = await loadConveyorConfig(this.config.workspaceDir);
|
|
378
457
|
if (!config) {
|
|
379
458
|
this.connection.sendEvent({ type: "setup_complete" });
|
|
380
459
|
await this.callbacks.onEvent({ type: "setup_complete" });
|
|
381
|
-
return;
|
|
460
|
+
return true;
|
|
382
461
|
}
|
|
383
462
|
try {
|
|
384
463
|
await this.executeSetupConfig(config);
|
|
@@ -388,11 +467,16 @@ var AgentRunner = class _AgentRunner {
|
|
|
388
467
|
};
|
|
389
468
|
this.connection.sendEvent(setupEvent);
|
|
390
469
|
await this.callbacks.onEvent(setupEvent);
|
|
470
|
+
return true;
|
|
391
471
|
} catch (error) {
|
|
392
472
|
const message = error instanceof Error ? error.message : "Setup failed";
|
|
393
473
|
this.connection.sendEvent({ type: "setup_error", message });
|
|
394
474
|
await this.callbacks.onEvent({ type: "setup_error", message });
|
|
395
|
-
|
|
475
|
+
this.connection.postChatMessage(
|
|
476
|
+
`Environment setup failed: ${message}
|
|
477
|
+
The agent cannot start until this is resolved.`
|
|
478
|
+
);
|
|
479
|
+
return false;
|
|
396
480
|
}
|
|
397
481
|
}
|
|
398
482
|
pushSetupLog(line) {
|
|
@@ -441,13 +525,42 @@ var AgentRunner = class _AgentRunner {
|
|
|
441
525
|
this.pendingMessages.push(msg);
|
|
442
526
|
}
|
|
443
527
|
}
|
|
528
|
+
waitForMessage() {
|
|
529
|
+
return new Promise((resolve) => {
|
|
530
|
+
const checkStopped = setInterval(() => {
|
|
531
|
+
if (this.stopped) {
|
|
532
|
+
clearInterval(checkStopped);
|
|
533
|
+
this.inputResolver = null;
|
|
534
|
+
resolve(null);
|
|
535
|
+
}
|
|
536
|
+
}, 1e3);
|
|
537
|
+
this.inputResolver = (msg) => {
|
|
538
|
+
clearInterval(checkStopped);
|
|
539
|
+
resolve(msg);
|
|
540
|
+
};
|
|
541
|
+
});
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Wait for the next user message content string. Drains pendingMessages first.
|
|
545
|
+
* Returns null if stopped.
|
|
546
|
+
*/
|
|
547
|
+
async waitForUserContent() {
|
|
548
|
+
if (this.pendingMessages.length > 0) {
|
|
549
|
+
const next = this.pendingMessages.shift();
|
|
550
|
+
return next.message.content;
|
|
551
|
+
}
|
|
552
|
+
const msg = await this.waitForMessage();
|
|
553
|
+
if (!msg) return null;
|
|
554
|
+
return msg.message.content;
|
|
555
|
+
}
|
|
444
556
|
async *createInputStream(initialPrompt) {
|
|
445
|
-
|
|
557
|
+
const makeUserMessage = (content) => ({
|
|
446
558
|
type: "user",
|
|
447
559
|
session_id: "",
|
|
448
|
-
message: { role: "user", content
|
|
560
|
+
message: { role: "user", content },
|
|
449
561
|
parent_tool_use_id: null
|
|
450
|
-
};
|
|
562
|
+
});
|
|
563
|
+
yield makeUserMessage(initialPrompt);
|
|
451
564
|
while (!this.stopped) {
|
|
452
565
|
if (this.pendingMessages.length > 0) {
|
|
453
566
|
const next = this.pendingMessages.shift();
|
|
@@ -456,18 +569,11 @@ var AgentRunner = class _AgentRunner {
|
|
|
456
569
|
}
|
|
457
570
|
continue;
|
|
458
571
|
}
|
|
572
|
+
this.connection.emitStatus("waiting_for_input");
|
|
459
573
|
await this.callbacks.onStatusChange("waiting_for_input");
|
|
460
|
-
const msg = await
|
|
461
|
-
this.inputResolver = resolve;
|
|
462
|
-
const checkStopped = setInterval(() => {
|
|
463
|
-
if (this.stopped) {
|
|
464
|
-
clearInterval(checkStopped);
|
|
465
|
-
this.inputResolver = null;
|
|
466
|
-
resolve(null);
|
|
467
|
-
}
|
|
468
|
-
}, 1e3);
|
|
469
|
-
});
|
|
574
|
+
const msg = await this.waitForMessage();
|
|
470
575
|
if (!msg) break;
|
|
576
|
+
this.connection.emitStatus("running");
|
|
471
577
|
await this.callbacks.onStatusChange("running");
|
|
472
578
|
yield msg;
|
|
473
579
|
}
|
|
@@ -492,7 +598,23 @@ var AgentRunner = class _AgentRunner {
|
|
|
492
598
|
const parts = [];
|
|
493
599
|
const scenario = this.detectRelaunchScenario(context);
|
|
494
600
|
if (context.claudeSessionId && scenario !== "fresh") {
|
|
495
|
-
if (
|
|
601
|
+
if (this.config.mode === "pm") {
|
|
602
|
+
const lastAgentIdx = this.findLastAgentMessageIndex(context.chatHistory);
|
|
603
|
+
const newMessages = context.chatHistory.slice(lastAgentIdx + 1).filter((m) => m.role === "user");
|
|
604
|
+
if (newMessages.length > 0) {
|
|
605
|
+
parts.push(
|
|
606
|
+
`You have been relaunched. Here are new messages since your last session:`,
|
|
607
|
+
...newMessages.map((m) => `[${m.userName ?? "user"}]: ${m.content}`)
|
|
608
|
+
);
|
|
609
|
+
} else {
|
|
610
|
+
parts.push(`You have been relaunched. No new messages since your last session.`);
|
|
611
|
+
}
|
|
612
|
+
parts.push(
|
|
613
|
+
`
|
|
614
|
+
You are the project manager for this task.`,
|
|
615
|
+
`Review the context above and wait for the team to provide instructions before taking action.`
|
|
616
|
+
);
|
|
617
|
+
} else if (scenario === "feedback_relaunch") {
|
|
496
618
|
const lastAgentIdx = this.findLastAgentMessageIndex(context.chatHistory);
|
|
497
619
|
const newMessages = context.chatHistory.slice(lastAgentIdx + 1).filter((m) => m.role === "user");
|
|
498
620
|
parts.push(
|
|
@@ -579,36 +701,56 @@ ${context.plan}`);
|
|
|
579
701
|
);
|
|
580
702
|
}
|
|
581
703
|
} else if (scenario === "idle_relaunch") {
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
704
|
+
if (this.config.mode === "pm") {
|
|
705
|
+
parts.push(
|
|
706
|
+
`You were relaunched but no new instructions have been given since your last run.`,
|
|
707
|
+
`You are the project manager for this task.`,
|
|
708
|
+
`Wait for the team to provide instructions before taking action.`
|
|
709
|
+
);
|
|
710
|
+
} else {
|
|
711
|
+
parts.push(
|
|
712
|
+
`You were relaunched but no new instructions have been given since your last run.`,
|
|
713
|
+
`Work on the git branch "${context.githubBranch}".`,
|
|
714
|
+
`Review the current state of the codebase and verify everything is working correctly (e.g. tests pass, the web server starts on port 3000).`,
|
|
715
|
+
`Post a brief status update to the chat summarizing the current state.`,
|
|
716
|
+
`Then wait for further instructions \u2014 do NOT redo work that was already completed.`
|
|
717
|
+
);
|
|
718
|
+
if (context.githubPRUrl) {
|
|
719
|
+
parts.push(`An existing PR is open at ${context.githubPRUrl}. Do not create a new PR.`);
|
|
720
|
+
}
|
|
591
721
|
}
|
|
592
722
|
} else {
|
|
593
723
|
const lastAgentIdx = this.findLastAgentMessageIndex(context.chatHistory);
|
|
594
724
|
const newMessages = context.chatHistory.slice(lastAgentIdx + 1).filter((m) => m.role === "user");
|
|
595
|
-
|
|
596
|
-
`You were relaunched with new feedback since your last run.`,
|
|
597
|
-
`Work on the git branch "${context.githubBranch}".`,
|
|
598
|
-
`
|
|
599
|
-
New messages since your last run:`,
|
|
600
|
-
...newMessages.map((m) => `[${m.userName ?? "user"}]: ${m.content}`),
|
|
601
|
-
`
|
|
602
|
-
Address the requested changes. Commit and push your updates.`
|
|
603
|
-
);
|
|
604
|
-
if (context.githubPRUrl) {
|
|
725
|
+
if (this.config.mode === "pm") {
|
|
605
726
|
parts.push(
|
|
606
|
-
`
|
|
727
|
+
`You were relaunched with new feedback since your last run.`,
|
|
728
|
+
`You are the project manager for this task.`,
|
|
729
|
+
`
|
|
730
|
+
New messages since your last run:`,
|
|
731
|
+
...newMessages.map((m) => `[${m.userName ?? "user"}]: ${m.content}`),
|
|
732
|
+
`
|
|
733
|
+
Review these messages and wait for the team to provide instructions before taking action.`
|
|
607
734
|
);
|
|
608
735
|
} else {
|
|
609
736
|
parts.push(
|
|
610
|
-
`
|
|
737
|
+
`You were relaunched with new feedback since your last run.`,
|
|
738
|
+
`Work on the git branch "${context.githubBranch}".`,
|
|
739
|
+
`
|
|
740
|
+
New messages since your last run:`,
|
|
741
|
+
...newMessages.map((m) => `[${m.userName ?? "user"}]: ${m.content}`),
|
|
742
|
+
`
|
|
743
|
+
Address the requested changes. Commit and push your updates.`
|
|
611
744
|
);
|
|
745
|
+
if (context.githubPRUrl) {
|
|
746
|
+
parts.push(
|
|
747
|
+
`An existing PR is open at ${context.githubPRUrl} \u2014 push to the same branch to update it. Do NOT create a new PR.`
|
|
748
|
+
);
|
|
749
|
+
} else {
|
|
750
|
+
parts.push(
|
|
751
|
+
`When finished, use the create_pull_request tool to open a PR. Do NOT use gh CLI or any other method to create PRs.`
|
|
752
|
+
);
|
|
753
|
+
}
|
|
612
754
|
}
|
|
613
755
|
}
|
|
614
756
|
return parts.join("\n");
|
|
@@ -789,6 +931,7 @@ You have access to Conveyor MCP tools to interact with the task management syste
|
|
|
789
931
|
let totalCostUsd = 0;
|
|
790
932
|
let sessionIdStored = false;
|
|
791
933
|
let isTyping = false;
|
|
934
|
+
let retriable = false;
|
|
792
935
|
for await (const event of events) {
|
|
793
936
|
if (this.stopped) break;
|
|
794
937
|
switch (event.type) {
|
|
@@ -868,6 +1011,9 @@ You have access to Conveyor MCP tools to interact with the task management syste
|
|
|
868
1011
|
totalCostUsd = "total_cost_usd" in resultEvent ? resultEvent.total_cost_usd : 0;
|
|
869
1012
|
const durationMs = Date.now() - startTime;
|
|
870
1013
|
const summary = "result" in resultEvent ? String(resultEvent.result) : "Task completed.";
|
|
1014
|
+
if (API_ERROR_PATTERN.test(summary) && durationMs < 3e4) {
|
|
1015
|
+
retriable = true;
|
|
1016
|
+
}
|
|
871
1017
|
this.connection.sendEvent({
|
|
872
1018
|
type: "completed",
|
|
873
1019
|
summary,
|
|
@@ -884,7 +1030,7 @@ You have access to Conveyor MCP tools to interact with the task management syste
|
|
|
884
1030
|
outputTokens: estimatedOutputTokens,
|
|
885
1031
|
totalTokens: estimatedTotalTokens,
|
|
886
1032
|
totalCostUsd,
|
|
887
|
-
onSubscription: !!process.env.CLAUDE_CODE_OAUTH_TOKEN
|
|
1033
|
+
onSubscription: this.config.mode === "pm" || !!process.env.CLAUDE_CODE_OAUTH_TOKEN
|
|
888
1034
|
});
|
|
889
1035
|
}
|
|
890
1036
|
await this.callbacks.onEvent({
|
|
@@ -896,6 +1042,9 @@ You have access to Conveyor MCP tools to interact with the task management syste
|
|
|
896
1042
|
} else {
|
|
897
1043
|
const errors = "errors" in resultEvent ? resultEvent.errors : [];
|
|
898
1044
|
const errorMsg = errors.length > 0 ? errors.join(", ") : `Agent stopped: ${resultEvent.subtype}`;
|
|
1045
|
+
if (API_ERROR_PATTERN.test(errorMsg)) {
|
|
1046
|
+
retriable = true;
|
|
1047
|
+
}
|
|
899
1048
|
this.connection.sendEvent({ type: "error", message: errorMsg });
|
|
900
1049
|
await this.callbacks.onEvent({ type: "error", message: errorMsg });
|
|
901
1050
|
}
|
|
@@ -906,9 +1055,15 @@ You have access to Conveyor MCP tools to interact with the task management syste
|
|
|
906
1055
|
if (isTyping) {
|
|
907
1056
|
this.connection.sendTypingStop();
|
|
908
1057
|
}
|
|
1058
|
+
return { retriable };
|
|
909
1059
|
}
|
|
1060
|
+
/**
|
|
1061
|
+
* Runs one SDK query cycle. For PM mode this is a single-turn query per
|
|
1062
|
+
* user message. For task mode this uses the long-running input stream
|
|
1063
|
+
* (initial execution) or a single follow-up prompt.
|
|
1064
|
+
*/
|
|
910
1065
|
// oxlint-disable-next-line max-lines-per-function
|
|
911
|
-
async
|
|
1066
|
+
async runSdkQuery(context, followUpContent) {
|
|
912
1067
|
if (this.stopped) return;
|
|
913
1068
|
const settings = context.agentSettings ?? this.config.agentSettings ?? {};
|
|
914
1069
|
const systemPromptText = this.buildSystemPrompt(context);
|
|
@@ -922,13 +1077,14 @@ You have access to Conveyor MCP tools to interact with the task management syste
|
|
|
922
1077
|
const model = context.model || this.config.model;
|
|
923
1078
|
const pmDisallowedTools = this.config.mode === "pm" ? ["TodoWrite", "TodoRead"] : [];
|
|
924
1079
|
const disallowedTools = [...settings.disallowedTools ?? [], ...pmDisallowedTools];
|
|
1080
|
+
const isPm = this.config.mode === "pm";
|
|
925
1081
|
const commonOptions = {
|
|
926
1082
|
model,
|
|
927
1083
|
systemPrompt,
|
|
928
1084
|
settingSources,
|
|
929
1085
|
cwd: this.config.workspaceDir,
|
|
930
|
-
permissionMode: "bypassPermissions",
|
|
931
|
-
allowDangerouslySkipPermissions:
|
|
1086
|
+
permissionMode: isPm ? "plan" : "bypassPermissions",
|
|
1087
|
+
allowDangerouslySkipPermissions: !isPm,
|
|
932
1088
|
tools: { type: "preset", preset: "claude_code" },
|
|
933
1089
|
mcpServers: { conveyor: conveyorMcp },
|
|
934
1090
|
maxTurns: settings.maxTurns,
|
|
@@ -939,29 +1095,87 @@ You have access to Conveyor MCP tools to interact with the task management syste
|
|
|
939
1095
|
disallowedTools: disallowedTools.length > 0 ? disallowedTools : void 0,
|
|
940
1096
|
enableFileCheckpointing: settings.enableFileCheckpointing
|
|
941
1097
|
};
|
|
942
|
-
const
|
|
943
|
-
|
|
944
|
-
prompt
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1098
|
+
const resume = context.claudeSessionId ?? void 0;
|
|
1099
|
+
if (followUpContent) {
|
|
1100
|
+
const prompt = isPm ? `${this.buildInitialPrompt(context)}
|
|
1101
|
+
|
|
1102
|
+
---
|
|
1103
|
+
|
|
1104
|
+
The team says:
|
|
1105
|
+
${followUpContent}` : followUpContent;
|
|
1106
|
+
const agentQuery = query({
|
|
1107
|
+
prompt,
|
|
1108
|
+
options: { ...commonOptions, resume }
|
|
1109
|
+
});
|
|
1110
|
+
await this.runWithRetry(agentQuery, context, commonOptions);
|
|
1111
|
+
} else if (isPm) {
|
|
1112
|
+
return;
|
|
1113
|
+
} else {
|
|
1114
|
+
const initialPrompt = this.buildInitialPrompt(context);
|
|
1115
|
+
const agentQuery = query({
|
|
1116
|
+
prompt: this.createInputStream(initialPrompt),
|
|
1117
|
+
options: { ...commonOptions, resume }
|
|
1118
|
+
});
|
|
1119
|
+
await this.runWithRetry(agentQuery, context, commonOptions);
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* Run a query with retry logic for transient API errors.
|
|
1124
|
+
*/
|
|
1125
|
+
async runWithRetry(initialQuery, context, options) {
|
|
1126
|
+
for (let attempt = 0; attempt <= RETRY_DELAYS_MS.length; attempt++) {
|
|
1127
|
+
if (this.stopped) return;
|
|
1128
|
+
const agentQuery = attempt === 0 ? initialQuery : query({
|
|
1129
|
+
prompt: this.createInputStream(this.buildInitialPrompt(context)),
|
|
1130
|
+
options: { ...options, resume: void 0 }
|
|
1131
|
+
});
|
|
1132
|
+
try {
|
|
1133
|
+
const { retriable } = await this.processEvents(agentQuery, context);
|
|
1134
|
+
if (!retriable || this.stopped) return;
|
|
1135
|
+
} catch (error) {
|
|
1136
|
+
const isStaleSession = error instanceof Error && error.message.includes("No conversation found with session ID");
|
|
1137
|
+
if (isStaleSession && context.claudeSessionId) {
|
|
1138
|
+
this.connection.storeSessionId("");
|
|
1139
|
+
const freshCtx = { ...context, claudeSessionId: null };
|
|
1140
|
+
const freshQuery = query({
|
|
1141
|
+
prompt: this.createInputStream(this.buildInitialPrompt(freshCtx)),
|
|
1142
|
+
options: { ...options, resume: void 0 }
|
|
1143
|
+
});
|
|
1144
|
+
return this.runWithRetry(freshQuery, freshCtx, options);
|
|
1145
|
+
}
|
|
1146
|
+
const isApiError = error instanceof Error && API_ERROR_PATTERN.test(error.message);
|
|
1147
|
+
if (!isApiError) throw error;
|
|
948
1148
|
}
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
if (isStaleSession && context.claudeSessionId) {
|
|
955
|
-
this.connection.storeSessionId("");
|
|
956
|
-
const freshPrompt = this.buildInitialPrompt({ ...context, claudeSessionId: null });
|
|
957
|
-
const freshQuery = query({
|
|
958
|
-
prompt: this.createInputStream(freshPrompt),
|
|
959
|
-
options: { ...commonOptions, resume: void 0 }
|
|
960
|
-
});
|
|
961
|
-
await this.processEvents(freshQuery, context);
|
|
962
|
-
} else {
|
|
963
|
-
throw error;
|
|
1149
|
+
if (attempt >= RETRY_DELAYS_MS.length) {
|
|
1150
|
+
this.connection.postChatMessage(
|
|
1151
|
+
`Agent shutting down after ${RETRY_DELAYS_MS.length} failed retry attempts due to API errors. The task will resume automatically when the codespace restarts.`
|
|
1152
|
+
);
|
|
1153
|
+
return;
|
|
964
1154
|
}
|
|
1155
|
+
const delayMs = RETRY_DELAYS_MS[attempt];
|
|
1156
|
+
const delayMin = Math.round(delayMs / 6e4);
|
|
1157
|
+
this.connection.postChatMessage(
|
|
1158
|
+
`API error encountered. Retrying in ${delayMin} minute${delayMin > 1 ? "s" : ""}... (attempt ${attempt + 1}/${RETRY_DELAYS_MS.length})`
|
|
1159
|
+
);
|
|
1160
|
+
this.connection.sendEvent({
|
|
1161
|
+
type: "error",
|
|
1162
|
+
message: `API error, retrying in ${delayMin}m (${attempt + 1}/${RETRY_DELAYS_MS.length})`
|
|
1163
|
+
});
|
|
1164
|
+
this.connection.emitStatus("waiting_for_input");
|
|
1165
|
+
await this.callbacks.onStatusChange("waiting_for_input");
|
|
1166
|
+
await new Promise((resolve) => {
|
|
1167
|
+
const timer = setTimeout(resolve, delayMs);
|
|
1168
|
+
const checkStopped = setInterval(() => {
|
|
1169
|
+
if (this.stopped) {
|
|
1170
|
+
clearTimeout(timer);
|
|
1171
|
+
clearInterval(checkStopped);
|
|
1172
|
+
resolve();
|
|
1173
|
+
}
|
|
1174
|
+
}, 1e3);
|
|
1175
|
+
setTimeout(() => clearInterval(checkStopped), delayMs + 100);
|
|
1176
|
+
});
|
|
1177
|
+
this.connection.emitStatus("running");
|
|
1178
|
+
await this.callbacks.onStatusChange("running");
|
|
965
1179
|
}
|
|
966
1180
|
}
|
|
967
1181
|
stop() {
|
|
@@ -980,4 +1194,4 @@ export {
|
|
|
980
1194
|
runStartCommand,
|
|
981
1195
|
AgentRunner
|
|
982
1196
|
};
|
|
983
|
-
//# sourceMappingURL=chunk-
|
|
1197
|
+
//# sourceMappingURL=chunk-US4HLRJA.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/connection.ts","../src/setup.ts","../src/runner.ts"],"sourcesContent":["import { io, type Socket } from \"socket.io-client\";\nimport type { AgentRunnerConfig, TaskContext, AgentEvent } from \"./types.js\";\n\nexport class ConveyorConnection {\n private socket: Socket | null = null;\n private config: AgentRunnerConfig;\n private eventBuffer: { taskId: string; event: AgentEvent }[] = [];\n private flushTimer: ReturnType<typeof setTimeout> | null = null;\n private static readonly EVENT_BATCH_MS = 500;\n\n private earlyMessages: { content: string; userId: string }[] = [];\n private earlyStop = false;\n private chatMessageCallback: ((msg: { content: string; userId: string }) => void) | null = null;\n private stopCallback: (() => void) | null = null;\n\n constructor(config: AgentRunnerConfig) {\n this.config = config;\n }\n\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n let settled = false;\n let attempts = 0;\n const maxInitialAttempts = 30;\n\n this.socket = io(this.config.conveyorApiUrl, {\n auth: { taskToken: this.config.taskToken, runnerMode: this.config.mode ?? \"task\" },\n transports: [\"websocket\"],\n reconnection: true,\n reconnectionAttempts: Infinity,\n reconnectionDelay: 2000,\n reconnectionDelayMax: 30000,\n randomizationFactor: 0.3,\n extraHeaders: {\n \"ngrok-skip-browser-warning\": \"true\",\n },\n });\n\n // Register listeners immediately so we capture messages the server\n // flushes during registerHandlers (before connect() resolves).\n this.socket.on(\"agentRunner:incomingMessage\", (msg: { content: string; userId: string }) => {\n if (this.chatMessageCallback) {\n this.chatMessageCallback(msg);\n } else {\n this.earlyMessages.push(msg);\n }\n });\n\n this.socket.on(\"agentRunner:stop\", () => {\n if (this.stopCallback) {\n this.stopCallback();\n } else {\n this.earlyStop = true;\n }\n });\n\n this.socket.on(\"connect\", () => {\n if (!settled) {\n settled = true;\n resolve();\n }\n });\n\n this.socket.io.on(\"reconnect_attempt\", () => {\n attempts++;\n if (!settled && attempts >= maxInitialAttempts) {\n settled = true;\n reject(new Error(`Failed to connect after ${maxInitialAttempts} attempts`));\n }\n });\n });\n }\n\n fetchChatMessages(\n limit?: number,\n ): Promise<\n { role: string; content: string; userId: string | null; userName?: string; createdAt: string }[]\n > {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n\n return new Promise((resolve, reject) => {\n socket.emit(\n \"agentRunner:getChatMessages\",\n { taskId: this.config.taskId, limit },\n (response: {\n success: boolean;\n data?: {\n role: string;\n content: string;\n userId: string | null;\n userName?: string;\n createdAt: string;\n }[];\n error?: string;\n }): void => {\n if (response.success && response.data) {\n resolve(response.data);\n } else {\n reject(new Error(response.error ?? \"Failed to fetch chat messages\"));\n }\n },\n );\n });\n }\n\n fetchTaskContext(): Promise<TaskContext> {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n\n return new Promise((resolve, reject) => {\n socket.emit(\n \"agentRunner:getTaskContext\",\n { taskId: this.config.taskId },\n (response: { success: boolean; data?: TaskContext; error?: string }): void => {\n if (response.success && response.data) {\n resolve(response.data);\n } else {\n reject(new Error(response.error ?? \"Failed to fetch task context\"));\n }\n },\n );\n });\n }\n\n sendEvent(event: AgentEvent): void {\n if (!this.socket) throw new Error(\"Not connected\");\n\n this.eventBuffer.push({ taskId: this.config.taskId, event });\n if (!this.flushTimer) {\n this.flushTimer = setTimeout(() => this.flushEvents(), ConveyorConnection.EVENT_BATCH_MS);\n }\n }\n\n flushEvents(): void {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n if (!this.socket || this.eventBuffer.length === 0) return;\n for (const entry of this.eventBuffer) {\n this.socket.emit(\"agentRunner:event\", entry);\n }\n this.eventBuffer = [];\n }\n\n updateStatus(status: string): void {\n if (!this.socket) throw new Error(\"Not connected\");\n\n this.socket.emit(\"agentRunner:statusUpdate\", {\n taskId: this.config.taskId,\n status,\n });\n }\n\n postChatMessage(content: string): void {\n if (!this.socket) throw new Error(\"Not connected\");\n\n this.socket.emit(\"agentRunner:chatMessage\", {\n taskId: this.config.taskId,\n content,\n });\n }\n\n createPR(params: {\n title: string;\n body: string;\n baseBranch?: string;\n }): Promise<{ url: string; number: number }> {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n\n return new Promise((resolve, reject) => {\n socket.emit(\n \"agentRunner:createPR\",\n { taskId: this.config.taskId, ...params },\n (response: {\n success: boolean;\n data?: { url: string; number: number };\n error?: string;\n }): void => {\n if (response.success && response.data) {\n resolve(response.data);\n } else {\n reject(new Error(response.error ?? \"Failed to create pull request\"));\n }\n },\n );\n });\n }\n\n storeSessionId(sessionId: string): void {\n if (!this.socket) return;\n this.socket.emit(\"agentRunner:storeSessionId\", {\n taskId: this.config.taskId,\n sessionId,\n });\n }\n\n updateTaskFields(fields: { plan?: string; description?: string }): void {\n if (!this.socket) throw new Error(\"Not connected\");\n this.socket.emit(\"agentRunner:updateTaskFields\", {\n taskId: this.config.taskId,\n fields,\n });\n }\n\n onChatMessage(callback: (message: { content: string; userId: string }) => void): void {\n this.chatMessageCallback = callback;\n for (const msg of this.earlyMessages) {\n callback(msg);\n }\n this.earlyMessages = [];\n }\n\n onStopRequested(callback: () => void): void {\n this.stopCallback = callback;\n if (this.earlyStop) {\n callback();\n this.earlyStop = false;\n }\n }\n\n trackSpending(params: {\n agentId: string;\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n totalCostUsd: number;\n onSubscription: boolean;\n }): void {\n if (!this.socket) throw new Error(\"Not connected\");\n\n this.socket.emit(\"agentRunner:trackSpending\", {\n taskId: this.config.taskId,\n ...params,\n });\n }\n\n emitStatus(status: string): void {\n if (!this.socket) return;\n this.socket.emit(\"agentRunner:statusUpdate\", {\n taskId: this.config.taskId,\n status,\n });\n }\n\n sendHeartbeat(): void {\n if (!this.socket) return;\n this.socket.emit(\"agentRunner:heartbeat\", {\n taskId: this.config.taskId,\n });\n }\n\n sendTypingStart(): void {\n this.sendEvent({ type: \"agent_typing_start\" });\n }\n\n sendTypingStop(): void {\n this.sendEvent({ type: \"agent_typing_stop\" });\n }\n\n disconnect(): void {\n this.flushEvents();\n this.socket?.disconnect();\n this.socket = null;\n }\n}\n","import { execSync } from \"node:child_process\";\nimport { spawn, type ChildProcess } from \"node:child_process\";\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface ConveyorConfig {\n setupCommand?: string;\n startCommand?: string;\n previewPort?: number;\n}\n\nconst CONVEYOR_CONFIG_PATH = \".conveyor/config.json\";\nconst DEVCONTAINER_PATH = \".devcontainer/conveyor/devcontainer.json\";\n\nexport async function loadForwardPorts(workspaceDir: string): Promise<number[]> {\n try {\n const raw = await readFile(join(workspaceDir, DEVCONTAINER_PATH), \"utf-8\");\n const parsed = JSON.parse(raw) as { forwardPorts?: number[] };\n return parsed.forwardPorts ?? [];\n } catch {\n return [];\n }\n}\n\nexport async function loadConveyorConfig(workspaceDir: string): Promise<ConveyorConfig | null> {\n // Primary: .conveyor/config.json\n try {\n const raw = await readFile(join(workspaceDir, CONVEYOR_CONFIG_PATH), \"utf-8\");\n const parsed = JSON.parse(raw) as ConveyorConfig;\n if (parsed.setupCommand || parsed.startCommand) return parsed;\n } catch {\n // Not found or invalid — try fallback\n }\n\n // Fallback: devcontainer.json \"conveyor\" section\n try {\n const raw = await readFile(join(workspaceDir, DEVCONTAINER_PATH), \"utf-8\");\n const parsed = JSON.parse(raw) as { conveyor?: ConveyorConfig };\n if (parsed.conveyor && (parsed.conveyor.startCommand || parsed.conveyor.setupCommand)) {\n return parsed.conveyor;\n }\n } catch {\n // Not found or invalid\n }\n\n return null;\n}\n\n/**\n * Runs a command synchronously (waits for exit). Streams stdout/stderr\n * line-by-line via the onOutput callback.\n */\nexport function runSetupCommand(\n cmd: string,\n cwd: string,\n onOutput: (stream: \"stdout\" | \"stderr\", data: string) => void,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(\"sh\", [\"-c\", cmd], {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: { ...process.env },\n });\n\n child.stdout.on(\"data\", (chunk: Buffer) => {\n onOutput(\"stdout\", chunk.toString());\n });\n\n child.stderr.on(\"data\", (chunk: Buffer) => {\n onOutput(\"stderr\", chunk.toString());\n });\n\n child.on(\"close\", (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`Setup command exited with code ${code}`));\n }\n });\n\n child.on(\"error\", (err) => {\n reject(err);\n });\n });\n}\n\n/**\n * Runs a command in the background (does not wait for exit). Returns the\n * ChildProcess so it can be cleaned up on agent shutdown. Streams\n * stdout/stderr via the onOutput callback.\n */\nexport function runStartCommand(\n cmd: string,\n cwd: string,\n onOutput: (stream: \"stdout\" | \"stderr\", data: string) => void,\n): ChildProcess {\n const child = spawn(\"sh\", [\"-c\", cmd], {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n detached: true,\n env: { ...process.env },\n });\n\n child.stdout.on(\"data\", (chunk: Buffer) => {\n onOutput(\"stdout\", chunk.toString());\n });\n\n child.stderr.on(\"data\", (chunk: Buffer) => {\n onOutput(\"stderr\", chunk.toString());\n });\n\n child.unref();\n return child;\n}\n\n/**\n * Reset `.devcontainer/conveyor/devcontainer.json` to match the base branch\n * and remove the cloud-build \"configure\" commit from git history. This runs\n * AFTER the codespace has started (env vars are already in process memory)\n * so the agent sees a branch identical to base — no spurious diffs, no\n * rebase conflicts on devcontainer.json.\n */\nexport function cleanDevcontainerFromGit(\n workspaceDir: string,\n taskBranch: string,\n baseBranch: string,\n): { cleaned: boolean; message: string } {\n const git = (cmd: string): string =>\n execSync(cmd, { cwd: workspaceDir, encoding: \"utf-8\", timeout: 30_000 }).trim();\n\n try {\n git(`git fetch origin ${baseBranch}`);\n } catch {\n return { cleaned: false, message: `Failed to fetch origin/${baseBranch}` };\n }\n\n // Check if devcontainer.json differs from base\n try {\n git(`git diff --quiet origin/${baseBranch} -- ${DEVCONTAINER_PATH}`);\n return { cleaned: false, message: \"devcontainer.json already matches base\" };\n } catch {\n // diff --quiet exits non-zero when there IS a diff — expected path\n }\n\n try {\n const ahead = parseInt(git(`git rev-list --count origin/${baseBranch}..HEAD`), 10);\n\n if (ahead <= 1) {\n // Fresh start: only the devcontainer commit exists — hard reset to base\n git(`git reset --hard origin/${baseBranch}`);\n } else {\n // Relaunch: agent has prior commits — restore file and add fixup commit\n git(`git checkout origin/${baseBranch} -- ${DEVCONTAINER_PATH}`);\n git(`git add ${DEVCONTAINER_PATH}`);\n\n try {\n git(`git diff --cached --quiet -- ${DEVCONTAINER_PATH}`);\n return { cleaned: false, message: \"devcontainer.json already clean in working tree\" };\n } catch {\n git(`git commit -m \"chore: reset devcontainer config\"`);\n }\n }\n\n git(`git push --force-with-lease origin ${taskBranch}`);\n return { cleaned: true, message: \"devcontainer.json cleaned from git history\" };\n } catch (err) {\n const msg = err instanceof Error ? err.message : \"Unknown error\";\n return { cleaned: false, message: `Git cleanup failed: ${msg}` };\n }\n}\n","// oxlint-disable max-lines\nimport { execSync } from \"node:child_process\";\nimport {\n query,\n tool,\n createSdkMcpServer,\n type SDKMessage,\n type SDKUserMessage,\n} from \"@anthropic-ai/claude-agent-sdk\";\nimport { z } from \"zod\";\nimport type {\n AgentRunnerConfig,\n AgentRunnerCallbacks,\n AgentRunnerStatus,\n AgentEvent,\n TaskContext,\n ActivityEventSummary,\n} from \"./types.js\";\nimport { ConveyorConnection } from \"./connection.js\";\nimport {\n cleanDevcontainerFromGit,\n loadConveyorConfig,\n loadForwardPorts,\n runSetupCommand,\n runStartCommand,\n type ConveyorConfig,\n} from \"./setup.js\";\n\nconst API_ERROR_PATTERN = /API Error: [45]\\d\\d/;\nconst RETRY_DELAYS_MS = [60_000, 120_000, 180_000, 300_000]; // 1, 2, 3, 5 minutes\nconst HEARTBEAT_INTERVAL_MS = 30_000;\n\nexport class AgentRunner {\n private config: AgentRunnerConfig;\n private connection: ConveyorConnection;\n private callbacks: AgentRunnerCallbacks;\n private _state: AgentRunnerStatus = \"connecting\";\n private stopped = false;\n private inputResolver: ((msg: SDKUserMessage) => void) | null = null;\n private pendingMessages: SDKUserMessage[] = [];\n private currentTurnToolCalls: ActivityEventSummary[] = [];\n private setupLog: string[] = [];\n private heartbeatTimer: ReturnType<typeof setInterval> | null = null;\n private taskContext: TaskContext | null = null;\n private static readonly MAX_SETUP_LOG_LINES = 50;\n\n constructor(config: AgentRunnerConfig, callbacks: AgentRunnerCallbacks) {\n this.config = config;\n this.connection = new ConveyorConnection(config);\n this.callbacks = callbacks;\n }\n\n get state(): AgentRunnerStatus {\n return this._state;\n }\n\n private async setState(status: AgentRunnerStatus): Promise<void> {\n this._state = status;\n this.connection.emitStatus(status);\n await this.callbacks.onStatusChange(status);\n }\n\n private startHeartbeat(): void {\n this.heartbeatTimer = setInterval(() => {\n if (!this.stopped) {\n this.connection.sendHeartbeat();\n }\n }, HEARTBEAT_INTERVAL_MS);\n }\n\n private stopHeartbeat(): void {\n if (this.heartbeatTimer) {\n clearInterval(this.heartbeatTimer);\n this.heartbeatTimer = null;\n }\n }\n\n // oxlint-disable-next-line max-lines-per-function\n async start(): Promise<void> {\n // --- Phase 1: Connect ---\n await this.setState(\"connecting\");\n await this.connection.connect();\n\n this.connection.onStopRequested(() => {\n this.stop();\n });\n\n this.connection.onChatMessage((message) => {\n this.injectHumanMessage(message.content);\n });\n\n await this.setState(\"connected\");\n this.connection.sendEvent({\n type: \"connected\",\n taskId: this.config.taskId,\n });\n this.startHeartbeat();\n\n // --- Phase 2: Setup (task mode + codespace only) ---\n if (this.config.mode !== \"pm\" && process.env.CODESPACES === \"true\") {\n const setupOk = await this.runSetupSafe();\n if (!setupOk) {\n this.stopHeartbeat();\n await this.setState(\"error\");\n this.connection.disconnect();\n return;\n }\n }\n\n this.initRtk();\n\n // --- Phase 3: Fetch context ---\n await this.setState(\"fetching_context\");\n try {\n this.taskContext = await this.connection.fetchTaskContext();\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Failed to fetch task context\";\n this.connection.sendEvent({ type: \"error\", message });\n await this.callbacks.onEvent({ type: \"error\", message });\n this.stopHeartbeat();\n await this.setState(\"error\");\n this.connection.disconnect();\n return;\n }\n\n if (process.env.CODESPACES === \"true\" && this.taskContext.baseBranch) {\n const result = cleanDevcontainerFromGit(\n this.config.workspaceDir,\n this.taskContext.githubBranch,\n this.taskContext.baseBranch,\n );\n if (result.cleaned) {\n this.setupLog.push(`[conveyor] ${result.message}`);\n }\n }\n\n // --- Phase 4: Initial action ---\n const isPm = this.config.mode === \"pm\";\n if (isPm) {\n await this.setState(\"idle\");\n } else {\n await this.setState(\"running\");\n await this.runSdkQuery(this.taskContext);\n if (!this.stopped) {\n await this.setState(\"idle\");\n }\n }\n\n // --- Phase 5: Core loop — stay alive for follow-up messages ---\n while (!this.stopped) {\n if (this._state === \"idle\") {\n const msg = await this.waitForUserContent();\n if (!msg) break;\n\n await this.setState(\"running\");\n await this.runSdkQuery(this.taskContext, msg);\n\n if (!this.stopped) {\n await this.setState(\"idle\");\n }\n } else if (this._state === \"error\") {\n await this.setState(\"idle\");\n } else {\n break;\n }\n }\n\n // --- Cleanup ---\n this.stopHeartbeat();\n await this.setState(\"finished\");\n this.connection.disconnect();\n }\n\n /**\n * Wraps project setup in try/catch. On failure, posts error to chat\n * directly (no SDK needed) and streams to CLI. Returns false if setup failed.\n */\n private async runSetupSafe(): Promise<boolean> {\n await this.setState(\"setup\");\n\n const ports = await loadForwardPorts(this.config.workspaceDir);\n if (ports.length > 0 && process.env.CODESPACE_NAME) {\n const visibility = ports.map((p) => `${p}:public`).join(\" \");\n runStartCommand(\n `gh codespace ports visibility ${visibility} -c \"${process.env.CODESPACE_NAME}\" 2>/dev/null`,\n this.config.workspaceDir,\n () => undefined,\n );\n }\n\n const config = await loadConveyorConfig(this.config.workspaceDir);\n if (!config) {\n this.connection.sendEvent({ type: \"setup_complete\" });\n await this.callbacks.onEvent({ type: \"setup_complete\" });\n return true;\n }\n\n try {\n await this.executeSetupConfig(config);\n const setupEvent: AgentEvent = {\n type: \"setup_complete\",\n previewPort: config.previewPort ?? undefined,\n };\n this.connection.sendEvent(setupEvent);\n await this.callbacks.onEvent(setupEvent);\n return true;\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Setup failed\";\n this.connection.sendEvent({ type: \"setup_error\", message });\n await this.callbacks.onEvent({ type: \"setup_error\", message });\n this.connection.postChatMessage(\n `Environment setup failed: ${message}\\nThe agent cannot start until this is resolved.`,\n );\n return false;\n }\n }\n\n private pushSetupLog(line: string): void {\n this.setupLog.push(line);\n if (this.setupLog.length > AgentRunner.MAX_SETUP_LOG_LINES) {\n this.setupLog.splice(0, this.setupLog.length - AgentRunner.MAX_SETUP_LOG_LINES);\n }\n }\n\n private async executeSetupConfig(config: ConveyorConfig): Promise<void> {\n if (config.setupCommand) {\n this.pushSetupLog(`$ ${config.setupCommand}`);\n await runSetupCommand(config.setupCommand, this.config.workspaceDir, (stream, data) => {\n this.connection.sendEvent({ type: \"setup_output\", stream, data });\n for (const line of data.split(\"\\n\").filter(Boolean)) {\n this.pushSetupLog(`[${stream}] ${line}`);\n }\n });\n this.pushSetupLog(\"(exit 0)\");\n }\n\n if (config.startCommand) {\n this.pushSetupLog(`$ ${config.startCommand} & (background)`);\n runStartCommand(config.startCommand, this.config.workspaceDir, (stream, data) => {\n this.connection.sendEvent({ type: \"start_command_output\", stream, data });\n });\n }\n }\n\n private initRtk(): void {\n try {\n execSync(\"rtk --version\", { stdio: \"ignore\" });\n execSync(\"rtk init --global --auto-patch\", { stdio: \"ignore\" });\n } catch {\n // RTK not installed — skip silently\n }\n }\n\n private injectHumanMessage(content: string): void {\n const msg: SDKUserMessage = {\n type: \"user\" as const,\n session_id: \"\",\n message: { role: \"user\" as const, content },\n parent_tool_use_id: null,\n };\n\n if (this.inputResolver) {\n const resolve = this.inputResolver;\n this.inputResolver = null;\n resolve(msg);\n } else {\n this.pendingMessages.push(msg);\n }\n }\n\n private waitForMessage(): Promise<SDKUserMessage | null> {\n return new Promise<SDKUserMessage | null>((resolve) => {\n const checkStopped = setInterval(() => {\n if (this.stopped) {\n clearInterval(checkStopped);\n this.inputResolver = null;\n resolve(null);\n }\n }, 1000);\n\n this.inputResolver = (msg: SDKUserMessage) => {\n clearInterval(checkStopped);\n resolve(msg);\n };\n });\n }\n\n /**\n * Wait for the next user message content string. Drains pendingMessages first.\n * Returns null if stopped.\n */\n private async waitForUserContent(): Promise<string | null> {\n if (this.pendingMessages.length > 0) {\n const next = this.pendingMessages.shift()!;\n return (next.message as { content: string }).content;\n }\n\n const msg = await this.waitForMessage();\n if (!msg) return null;\n return (msg.message as { content: string }).content;\n }\n\n private async *createInputStream(\n initialPrompt: string,\n ): AsyncGenerator<SDKUserMessage, void, unknown> {\n const makeUserMessage = (content: string): SDKUserMessage => ({\n type: \"user\" as const,\n session_id: \"\",\n message: { role: \"user\" as const, content },\n parent_tool_use_id: null,\n });\n\n yield makeUserMessage(initialPrompt);\n\n while (!this.stopped) {\n if (this.pendingMessages.length > 0) {\n const next = this.pendingMessages.shift();\n if (next) {\n yield next;\n }\n continue;\n }\n\n this.connection.emitStatus(\"waiting_for_input\");\n await this.callbacks.onStatusChange(\"waiting_for_input\");\n const msg = await this.waitForMessage();\n\n if (!msg) break;\n this.connection.emitStatus(\"running\");\n await this.callbacks.onStatusChange(\"running\");\n yield msg;\n }\n }\n\n private findLastAgentMessageIndex(history: TaskContext[\"chatHistory\"]): number {\n for (let i = history.length - 1; i >= 0; i--) {\n if (history[i].role === \"assistant\") return i;\n }\n return -1;\n }\n\n private detectRelaunchScenario(\n context: TaskContext,\n ): \"fresh\" | \"idle_relaunch\" | \"feedback_relaunch\" {\n const lastAgentIdx = this.findLastAgentMessageIndex(context.chatHistory);\n if (lastAgentIdx === -1) return \"fresh\";\n\n const hasPriorWork = !!context.githubPRUrl || !!context.claudeSessionId;\n if (!hasPriorWork) return \"fresh\";\n\n const messagesAfterAgent = context.chatHistory.slice(lastAgentIdx + 1);\n const hasNewUserMessages = messagesAfterAgent.some((m) => m.role === \"user\");\n return hasNewUserMessages ? \"feedback_relaunch\" : \"idle_relaunch\";\n }\n\n // eslint-disable-next-line max-lines-per-function\n private buildInitialPrompt(context: TaskContext): string {\n const parts: string[] = [];\n const scenario = this.detectRelaunchScenario(context);\n\n if (context.claudeSessionId && scenario !== \"fresh\") {\n if (this.config.mode === \"pm\") {\n const lastAgentIdx = this.findLastAgentMessageIndex(context.chatHistory);\n const newMessages = context.chatHistory\n .slice(lastAgentIdx + 1)\n .filter((m) => m.role === \"user\");\n if (newMessages.length > 0) {\n parts.push(\n `You have been relaunched. Here are new messages since your last session:`,\n ...newMessages.map((m) => `[${m.userName ?? \"user\"}]: ${m.content}`),\n );\n } else {\n parts.push(`You have been relaunched. No new messages since your last session.`);\n }\n parts.push(\n `\\nYou are the project manager for this task.`,\n `Review the context above and wait for the team to provide instructions before taking action.`,\n );\n } else if (scenario === \"feedback_relaunch\") {\n const lastAgentIdx = this.findLastAgentMessageIndex(context.chatHistory);\n const newMessages = context.chatHistory\n .slice(lastAgentIdx + 1)\n .filter((m) => m.role === \"user\");\n parts.push(\n `You have been relaunched with new feedback.`,\n `Work on the git branch \"${context.githubBranch}\".`,\n `\\nNew messages since your last run:`,\n ...newMessages.map((m) => `[${m.userName ?? \"user\"}]: ${m.content}`),\n `\\nAddress the requested changes. Commit and push your updates.`,\n );\n if (context.githubPRUrl) {\n parts.push(\n `An existing PR is open at ${context.githubPRUrl} — push to the same branch. Do NOT create a new PR.`,\n );\n } else {\n parts.push(\n `When finished, use the create_pull_request tool to open a PR. Do NOT use gh CLI.`,\n );\n }\n } else {\n parts.push(\n `You were relaunched but no new instructions have been given since your last run.`,\n `Work on the git branch \"${context.githubBranch}\".`,\n `Review the current state of the codebase and verify everything is working correctly.`,\n `Post a brief status update to the chat, then wait for further instructions.`,\n );\n if (context.githubPRUrl) {\n parts.push(`An existing PR is open at ${context.githubPRUrl}. Do not create a new PR.`);\n }\n }\n return parts.join(\"\\n\");\n }\n\n parts.push(`# Task: ${context.title}`);\n if (context.description) {\n parts.push(`\\n## Description\\n${context.description}`);\n }\n if (context.plan) {\n parts.push(`\\n## Plan\\n${context.plan}`);\n }\n\n if (context.files && context.files.length > 0) {\n parts.push(`\\n## Attached Files`);\n for (const file of context.files) {\n parts.push(`- **${file.fileName}** (${file.mimeType}): ${file.downloadUrl}`);\n }\n }\n\n if (context.repoRefs && context.repoRefs.length > 0) {\n parts.push(`\\n## Repository References`);\n for (const ref of context.repoRefs) {\n const icon = ref.refType === \"folder\" ? \"folder\" : \"file\";\n parts.push(`- [${icon}] \\`${ref.path}\\``);\n }\n }\n\n if (context.chatHistory.length > 0) {\n const relevant = context.chatHistory.slice(-20);\n parts.push(`\\n## Recent Chat Context`);\n for (const msg of relevant) {\n const sender = msg.userName ?? msg.role;\n parts.push(`[${sender}]: ${msg.content}`);\n }\n }\n\n parts.push(`\\n## Instructions`);\n\n if (scenario === \"fresh\") {\n if (this.config.mode === \"pm\") {\n parts.push(\n `You are the project manager for this task.`,\n `The task details are provided above. Wait for the team to ask questions or provide additional requirements before starting to plan.`,\n );\n } else {\n parts.push(\n `Begin executing the task plan above immediately.`,\n `Your FIRST action should be reading the relevant source files mentioned in the plan, then writing code. Do NOT run install, build, lint, test, or dev server commands first — the environment is already set up.`,\n `Work on the git branch \"${context.githubBranch}\".`,\n `Post a brief message to chat when you begin meaningful implementation, and again when the PR is ready.`,\n `When finished, commit your changes, push the branch, and use the create_pull_request tool to open a PR. Do NOT use gh CLI or any other method to create PRs.`,\n );\n }\n } else if (scenario === \"idle_relaunch\") {\n if (this.config.mode === \"pm\") {\n parts.push(\n `You were relaunched but no new instructions have been given since your last run.`,\n `You are the project manager for this task.`,\n `Wait for the team to provide instructions before taking action.`,\n );\n } else {\n parts.push(\n `You were relaunched but no new instructions have been given since your last run.`,\n `Work on the git branch \"${context.githubBranch}\".`,\n `Review the current state of the codebase and verify everything is working correctly (e.g. tests pass, the web server starts on port 3000).`,\n `Post a brief status update to the chat summarizing the current state.`,\n `Then wait for further instructions — do NOT redo work that was already completed.`,\n );\n if (context.githubPRUrl) {\n parts.push(`An existing PR is open at ${context.githubPRUrl}. Do not create a new PR.`);\n }\n }\n } else {\n const lastAgentIdx = this.findLastAgentMessageIndex(context.chatHistory);\n const newMessages = context.chatHistory\n .slice(lastAgentIdx + 1)\n .filter((m) => m.role === \"user\");\n if (this.config.mode === \"pm\") {\n parts.push(\n `You were relaunched with new feedback since your last run.`,\n `You are the project manager for this task.`,\n `\\nNew messages since your last run:`,\n ...newMessages.map((m) => `[${m.userName ?? \"user\"}]: ${m.content}`),\n `\\nReview these messages and wait for the team to provide instructions before taking action.`,\n );\n } else {\n parts.push(\n `You were relaunched with new feedback since your last run.`,\n `Work on the git branch \"${context.githubBranch}\".`,\n `\\nNew messages since your last run:`,\n ...newMessages.map((m) => `[${m.userName ?? \"user\"}]: ${m.content}`),\n `\\nAddress the requested changes. Commit and push your updates.`,\n );\n if (context.githubPRUrl) {\n parts.push(\n `An existing PR is open at ${context.githubPRUrl} — push to the same branch to update it. Do NOT create a new PR.`,\n );\n } else {\n parts.push(\n `When finished, use the create_pull_request tool to open a PR. Do NOT use gh CLI or any other method to create PRs.`,\n );\n }\n }\n }\n\n return parts.join(\"\\n\");\n }\n\n private buildSystemPrompt(context: TaskContext): string {\n const parts =\n this.config.mode === \"pm\"\n ? [\n `You are an AI project manager helping to plan tasks for the \"${context.title}\" project.`,\n `You are running locally with full access to the repository.`,\n `\\nEnvironment (ready, no setup required):`,\n `- Repository is cloned at your current working directory.`,\n `- You can read files to understand the codebase before writing task plans.`,\n `- Check the dev branch (e.g. run: git fetch && git checkout dev || git checkout main) to understand the current state of the codebase that agents will branch off of.`,\n ]\n : [\n `You are an AI agent working on a task for the \"${context.title}\" project.`,\n `You are running inside a GitHub Codespace with full access to the repository.`,\n `\\nEnvironment (fully ready — do NOT verify or set up):`,\n `- Repository is cloned at your current working directory.`,\n `- Branch \\`${context.githubBranch}\\` is already checked out.`,\n `- All dependencies are installed, database is migrated, and the dev server is running.`,\n `- Git is configured. Commit and push directly to this branch.`,\n `\\nIMPORTANT — Skip all environment verification. Do NOT run any of the following:`,\n `- bun/npm install, pip install, or any dependency installation`,\n `- bun build, bun lint, bun test, bun typecheck, or any build/check commands as a \"first step\"`,\n `- bun db:generate, bun db:push, prisma migrate, or any database setup`,\n `- bun dev, npm start, or any dev server startup commands`,\n `- pwd, ls, echo, or exploratory shell commands to \"check\" the environment`,\n `Only run these if you encounter a specific error that requires it.`,\n `Start reading the task plan and writing code immediately.`,\n ];\n\n if (this.setupLog.length > 0) {\n parts.push(\n `\\nEnvironment setup log (already executed before you started — proof that setup succeeded):`,\n \"```\",\n ...this.setupLog,\n \"```\",\n );\n }\n\n if (context.agentInstructions) {\n parts.push(`\\nAgent Instructions:\\n${context.agentInstructions}`);\n }\n if (this.config.instructions) {\n parts.push(`\\nAdditional Instructions:\\n${this.config.instructions}`);\n }\n parts.push(\n `\\nYou have access to Conveyor MCP tools to interact with the task management system.`,\n `Use the post_to_chat tool to communicate progress or ask questions.`,\n `Use the read_task_chat tool to check for new messages from the team.`,\n );\n if (this.config.mode !== \"pm\") {\n parts.push(\n `Use the create_pull_request tool to open PRs — do NOT use gh CLI or shell commands for PR creation.`,\n );\n }\n return parts.join(\"\\n\");\n }\n\n // oxlint-disable-next-line typescript/explicit-function-return-type, max-lines-per-function\n private createConveyorMcpServer(context: TaskContext) {\n const connection = this.connection;\n const config = this.config;\n\n const textResult = (text: string): { content: { type: \"text\"; text: string }[] } => ({\n content: [{ type: \"text\" as const, text }],\n });\n\n const commonTools = [\n tool(\n \"read_task_chat\",\n \"Read recent messages from the task chat to see team feedback or instructions\",\n {\n limit: z.number().optional().describe(\"Number of recent messages to fetch (default 20)\"),\n },\n async ({ limit }) => {\n try {\n const messages = await connection.fetchChatMessages(limit);\n return textResult(JSON.stringify(messages, null, 2));\n } catch {\n return textResult(\n JSON.stringify({\n note: \"Could not fetch live chat. Chat history was provided in the initial context.\",\n }),\n );\n }\n },\n { annotations: { readOnly: true } },\n ),\n tool(\n \"post_to_chat\",\n \"Post a message to the task chat visible to all team members\",\n { message: z.string().describe(\"The message to post to the team\") },\n ({ message }) => {\n connection.postChatMessage(message);\n return Promise.resolve(textResult(\"Message posted to task chat.\"));\n },\n ),\n tool(\n \"update_task_status\",\n \"Update the task status on the Kanban board\",\n {\n status: z\n .enum([\"InProgress\", \"ReviewPR\", \"Complete\"])\n .describe(\"The new status for the task\"),\n },\n ({ status }) => {\n connection.updateStatus(status);\n return Promise.resolve(textResult(`Task status updated to ${status}.`));\n },\n ),\n tool(\n \"get_task_plan\",\n \"Re-read the latest task plan in case it was updated\",\n {},\n async () => {\n try {\n const ctx = await connection.fetchTaskContext();\n return textResult(ctx.plan ?? \"No plan available.\");\n } catch {\n return textResult(`Task ID: ${config.taskId} - could not fetch updated plan.`);\n }\n },\n { annotations: { readOnly: true } },\n ),\n ];\n\n const modeTools =\n config.mode === \"pm\"\n ? [\n tool(\n \"update_task\",\n \"Save the finalized task plan and/or description\",\n {\n plan: z.string().optional().describe(\"The task plan in markdown\"),\n description: z.string().optional().describe(\"Updated task description\"),\n },\n async ({ plan, description }) => {\n try {\n connection.updateTaskFields({ plan, description });\n return textResult(\"Task updated successfully.\");\n } catch {\n return textResult(\"Failed to update task.\");\n }\n },\n ),\n ]\n : [\n tool(\n \"create_pull_request\",\n \"Create a GitHub pull request for this task. Use this instead of gh CLI or git commands to create PRs.\",\n {\n title: z.string().describe(\"The PR title\"),\n body: z.string().describe(\"The PR description/body in markdown\"),\n },\n async ({ title, body }) => {\n try {\n const result = await connection.createPR({ title, body });\n connection.sendEvent({\n type: \"pr_created\",\n url: result.url,\n number: result.number,\n });\n return textResult(`Pull request #${result.number} created: ${result.url}`);\n } catch (error) {\n const msg = error instanceof Error ? error.message : \"Unknown error\";\n return textResult(`Failed to create pull request: ${msg}`);\n }\n },\n ),\n ];\n\n return createSdkMcpServer({\n name: \"conveyor\",\n tools: [...commonTools, ...modeTools],\n });\n\n void context;\n }\n\n // oxlint-disable-next-line max-lines-per-function, complexity\n private async processEvents(\n events: AsyncGenerator<SDKMessage, void>,\n context: TaskContext,\n ): Promise<{ retriable: boolean }> {\n const startTime = Date.now();\n let totalCostUsd = 0;\n let sessionIdStored = false;\n let isTyping = false;\n let retriable = false;\n\n for await (const event of events) {\n if (this.stopped) break;\n\n switch (event.type) {\n case \"system\": {\n if (event.subtype === \"init\") {\n const sessionId = (event as unknown as Record<string, unknown>).session_id as\n | string\n | undefined;\n if (sessionId && !sessionIdStored) {\n sessionIdStored = true;\n this.connection.storeSessionId(sessionId);\n }\n await this.callbacks.onEvent({\n type: \"thinking\",\n message: `Agent initialized (model: ${event.model})`,\n });\n }\n break;\n }\n\n case \"assistant\": {\n if (!isTyping) {\n setTimeout(() => {\n this.connection.sendTypingStart();\n }, 200);\n isTyping = true;\n }\n\n const msg = event.message as unknown as Record<string, unknown>;\n const content = msg.content as Record<string, unknown>[];\n const turnTextParts: string[] = [];\n for (const block of content) {\n const blockType = block.type as string;\n if (blockType === \"text\") {\n const text = block.text as string;\n turnTextParts.push(text);\n this.connection.sendEvent({ type: \"message\", content: text });\n await this.callbacks.onEvent({ type: \"message\", content: text });\n } else if (blockType === \"tool_use\") {\n const name = block.name as string;\n const inputStr =\n typeof block.input === \"string\" ? block.input : JSON.stringify(block.input);\n const isContentTool = [\"edit\", \"write\"].includes(name.toLowerCase());\n const inputLimit = isContentTool ? 10_000 : 500;\n const summary: ActivityEventSummary = {\n tool: name,\n input: inputStr.slice(0, inputLimit),\n timestamp: new Date().toISOString(),\n };\n this.currentTurnToolCalls.push(summary);\n this.connection.sendEvent({\n type: \"tool_use\",\n tool: name,\n input: inputStr,\n });\n await this.callbacks.onEvent({\n type: \"tool_use\",\n tool: name,\n input: inputStr,\n });\n }\n }\n\n if (turnTextParts.length > 0) {\n this.connection.postChatMessage(turnTextParts.join(\"\\n\\n\"));\n }\n\n if (this.currentTurnToolCalls.length > 0) {\n this.connection.sendEvent({\n type: \"turn_end\",\n toolCalls: [...this.currentTurnToolCalls],\n });\n this.currentTurnToolCalls = [];\n }\n break;\n }\n\n case \"result\": {\n if (isTyping) {\n this.connection.sendTypingStop();\n isTyping = false;\n }\n\n const resultEvent = event as SDKMessage & { type: \"result\"; subtype: string };\n if (resultEvent.subtype === \"success\") {\n totalCostUsd =\n \"total_cost_usd\" in resultEvent\n ? ((resultEvent as Record<string, unknown>).total_cost_usd as number)\n : 0;\n const durationMs = Date.now() - startTime;\n const summary =\n \"result\" in resultEvent\n ? String((resultEvent as Record<string, unknown>).result)\n : \"Task completed.\";\n\n if (API_ERROR_PATTERN.test(summary) && durationMs < 30_000) {\n retriable = true;\n }\n\n this.connection.sendEvent({\n type: \"completed\",\n summary,\n costUsd: totalCostUsd,\n durationMs,\n });\n\n if (totalCostUsd > 0 && context.agentId) {\n const estimatedTotalTokens = Math.round(totalCostUsd * 100000);\n const estimatedInputTokens = Math.round(estimatedTotalTokens * 0.7);\n const estimatedOutputTokens = Math.round(estimatedTotalTokens * 0.3);\n\n this.connection.trackSpending({\n agentId: context.agentId,\n inputTokens: estimatedInputTokens,\n outputTokens: estimatedOutputTokens,\n totalTokens: estimatedTotalTokens,\n totalCostUsd,\n onSubscription: this.config.mode === \"pm\" || !!process.env.CLAUDE_CODE_OAUTH_TOKEN,\n });\n }\n\n await this.callbacks.onEvent({\n type: \"completed\",\n summary,\n costUsd: totalCostUsd,\n durationMs,\n });\n } else {\n const errors =\n \"errors\" in resultEvent\n ? ((resultEvent as Record<string, unknown>).errors as string[])\n : [];\n const errorMsg =\n errors.length > 0 ? errors.join(\", \") : `Agent stopped: ${resultEvent.subtype}`;\n\n if (API_ERROR_PATTERN.test(errorMsg)) {\n retriable = true;\n }\n\n this.connection.sendEvent({ type: \"error\", message: errorMsg });\n await this.callbacks.onEvent({ type: \"error\", message: errorMsg });\n }\n break;\n }\n }\n }\n\n if (isTyping) {\n this.connection.sendTypingStop();\n }\n\n return { retriable };\n }\n\n /**\n * Runs one SDK query cycle. For PM mode this is a single-turn query per\n * user message. For task mode this uses the long-running input stream\n * (initial execution) or a single follow-up prompt.\n */\n // oxlint-disable-next-line max-lines-per-function\n private async runSdkQuery(context: TaskContext, followUpContent?: string): Promise<void> {\n if (this.stopped) return;\n\n const settings = context.agentSettings ?? this.config.agentSettings ?? {};\n const systemPromptText = this.buildSystemPrompt(context);\n const conveyorMcp = this.createConveyorMcpServer(context);\n\n const systemPrompt: { type: \"preset\"; preset: \"claude_code\"; append?: string } = {\n type: \"preset\",\n preset: \"claude_code\",\n append: systemPromptText || undefined,\n };\n const settingSources = (settings.settingSources ?? [\"user\", \"project\"]) as (\n | \"user\"\n | \"project\"\n | \"local\"\n )[];\n\n const model = context.model || this.config.model;\n const pmDisallowedTools = this.config.mode === \"pm\" ? [\"TodoWrite\", \"TodoRead\"] : [];\n const disallowedTools = [...(settings.disallowedTools ?? []), ...pmDisallowedTools];\n\n const isPm = this.config.mode === \"pm\";\n const commonOptions = {\n model,\n systemPrompt,\n settingSources,\n cwd: this.config.workspaceDir,\n permissionMode: (isPm ? \"plan\" : \"bypassPermissions\") as \"plan\" | \"bypassPermissions\",\n allowDangerouslySkipPermissions: !isPm,\n tools: { type: \"preset\" as const, preset: \"claude_code\" as const },\n mcpServers: { conveyor: conveyorMcp },\n maxTurns: settings.maxTurns,\n effort: settings.effort,\n thinking: settings.thinking,\n betas: settings.betas,\n maxBudgetUsd: settings.maxBudgetUsd ?? 50,\n disallowedTools: disallowedTools.length > 0 ? disallowedTools : undefined,\n enableFileCheckpointing: settings.enableFileCheckpointing,\n };\n\n const resume = context.claudeSessionId ?? undefined;\n\n if (followUpContent) {\n // Follow-up message: single prompt, resume session\n const prompt = isPm\n ? `${this.buildInitialPrompt(context)}\\n\\n---\\n\\nThe team says:\\n${followUpContent}`\n : followUpContent;\n\n const agentQuery = query({\n prompt,\n options: { ...commonOptions, resume },\n });\n await this.runWithRetry(agentQuery, context, commonOptions);\n } else if (isPm) {\n // PM initial: no-op, we go straight to idle and wait for messages\n return;\n } else {\n // Task initial: long-running query with input stream\n const initialPrompt = this.buildInitialPrompt(context);\n const agentQuery = query({\n prompt: this.createInputStream(initialPrompt),\n options: { ...commonOptions, resume },\n });\n await this.runWithRetry(agentQuery, context, commonOptions);\n }\n }\n\n /**\n * Run a query with retry logic for transient API errors.\n */\n private async runWithRetry(\n initialQuery: AsyncGenerator<SDKMessage, void>,\n context: TaskContext,\n // oxlint-disable-next-line typescript/no-explicit-any\n options: Record<string, any>,\n ): Promise<void> {\n for (let attempt = 0; attempt <= RETRY_DELAYS_MS.length; attempt++) {\n if (this.stopped) return;\n\n const agentQuery =\n attempt === 0\n ? initialQuery\n : query({\n prompt: this.createInputStream(this.buildInitialPrompt(context)),\n options: { ...options, resume: undefined },\n });\n\n try {\n const { retriable } = await this.processEvents(agentQuery, context);\n if (!retriable || this.stopped) return;\n } catch (error) {\n const isStaleSession =\n error instanceof Error && error.message.includes(\"No conversation found with session ID\");\n\n if (isStaleSession && context.claudeSessionId) {\n this.connection.storeSessionId(\"\");\n const freshCtx = { ...context, claudeSessionId: null };\n const freshQuery = query({\n prompt: this.createInputStream(this.buildInitialPrompt(freshCtx)),\n options: { ...options, resume: undefined },\n });\n return this.runWithRetry(freshQuery, freshCtx, options);\n }\n\n const isApiError = error instanceof Error && API_ERROR_PATTERN.test(error.message);\n if (!isApiError) throw error;\n }\n\n if (attempt >= RETRY_DELAYS_MS.length) {\n this.connection.postChatMessage(\n `Agent shutting down after ${RETRY_DELAYS_MS.length} failed retry attempts due to API errors. ` +\n `The task will resume automatically when the codespace restarts.`,\n );\n return;\n }\n\n const delayMs = RETRY_DELAYS_MS[attempt];\n const delayMin = Math.round(delayMs / 60_000);\n this.connection.postChatMessage(\n `API error encountered. Retrying in ${delayMin} minute${delayMin > 1 ? \"s\" : \"\"}... (attempt ${attempt + 1}/${RETRY_DELAYS_MS.length})`,\n );\n this.connection.sendEvent({\n type: \"error\",\n message: `API error, retrying in ${delayMin}m (${attempt + 1}/${RETRY_DELAYS_MS.length})`,\n });\n this.connection.emitStatus(\"waiting_for_input\");\n await this.callbacks.onStatusChange(\"waiting_for_input\");\n\n await new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, delayMs);\n const checkStopped = setInterval(() => {\n if (this.stopped) {\n clearTimeout(timer);\n clearInterval(checkStopped);\n resolve();\n }\n }, 1000);\n setTimeout(() => clearInterval(checkStopped), delayMs + 100);\n });\n\n this.connection.emitStatus(\"running\");\n await this.callbacks.onStatusChange(\"running\");\n }\n }\n\n stop(): void {\n this.stopped = true;\n if (this.inputResolver) {\n this.inputResolver(null as unknown as SDKUserMessage);\n this.inputResolver = null;\n }\n }\n}\n"],"mappings":"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","names":["execSync","execSync"]}
|
package/dist/cli.js
CHANGED
package/dist/index.d.ts
CHANGED
|
@@ -68,6 +68,9 @@ interface ChatMessage {
|
|
|
68
68
|
type AgentEvent = {
|
|
69
69
|
type: "connected";
|
|
70
70
|
taskId: string;
|
|
71
|
+
} | {
|
|
72
|
+
type: "heartbeat";
|
|
73
|
+
taskId: string;
|
|
71
74
|
} | {
|
|
72
75
|
type: "thinking";
|
|
73
76
|
message: string;
|
|
@@ -125,7 +128,7 @@ interface ActivityEventSummary {
|
|
|
125
128
|
output?: string;
|
|
126
129
|
timestamp: string;
|
|
127
130
|
}
|
|
128
|
-
type AgentRunnerStatus = "connecting" | "setup" | "fetching_context" | "running" | "waiting_for_input" | "stopping" | "finished" | "error";
|
|
131
|
+
type AgentRunnerStatus = "connecting" | "connected" | "setup" | "fetching_context" | "running" | "idle" | "waiting_for_input" | "stopping" | "finished" | "disconnected" | "error";
|
|
129
132
|
interface AgentRunnerCallbacks {
|
|
130
133
|
onEvent: (event: AgentEvent) => void | Promise<void>;
|
|
131
134
|
onStatusChange: (status: AgentRunnerStatus) => void | Promise<void>;
|
|
@@ -135,19 +138,36 @@ declare class AgentRunner {
|
|
|
135
138
|
private config;
|
|
136
139
|
private connection;
|
|
137
140
|
private callbacks;
|
|
141
|
+
private _state;
|
|
138
142
|
private stopped;
|
|
139
143
|
private inputResolver;
|
|
140
144
|
private pendingMessages;
|
|
141
145
|
private currentTurnToolCalls;
|
|
142
146
|
private setupLog;
|
|
147
|
+
private heartbeatTimer;
|
|
148
|
+
private taskContext;
|
|
143
149
|
private static readonly MAX_SETUP_LOG_LINES;
|
|
144
150
|
constructor(config: AgentRunnerConfig, callbacks: AgentRunnerCallbacks);
|
|
151
|
+
get state(): AgentRunnerStatus;
|
|
152
|
+
private setState;
|
|
153
|
+
private startHeartbeat;
|
|
154
|
+
private stopHeartbeat;
|
|
145
155
|
start(): Promise<void>;
|
|
146
|
-
|
|
156
|
+
/**
|
|
157
|
+
* Wraps project setup in try/catch. On failure, posts error to chat
|
|
158
|
+
* directly (no SDK needed) and streams to CLI. Returns false if setup failed.
|
|
159
|
+
*/
|
|
160
|
+
private runSetupSafe;
|
|
147
161
|
private pushSetupLog;
|
|
148
162
|
private executeSetupConfig;
|
|
149
163
|
private initRtk;
|
|
150
164
|
private injectHumanMessage;
|
|
165
|
+
private waitForMessage;
|
|
166
|
+
/**
|
|
167
|
+
* Wait for the next user message content string. Drains pendingMessages first.
|
|
168
|
+
* Returns null if stopped.
|
|
169
|
+
*/
|
|
170
|
+
private waitForUserContent;
|
|
151
171
|
private createInputStream;
|
|
152
172
|
private findLastAgentMessageIndex;
|
|
153
173
|
private detectRelaunchScenario;
|
|
@@ -155,7 +175,16 @@ declare class AgentRunner {
|
|
|
155
175
|
private buildSystemPrompt;
|
|
156
176
|
private createConveyorMcpServer;
|
|
157
177
|
private processEvents;
|
|
158
|
-
|
|
178
|
+
/**
|
|
179
|
+
* Runs one SDK query cycle. For PM mode this is a single-turn query per
|
|
180
|
+
* user message. For task mode this uses the long-running input stream
|
|
181
|
+
* (initial execution) or a single follow-up prompt.
|
|
182
|
+
*/
|
|
183
|
+
private runSdkQuery;
|
|
184
|
+
/**
|
|
185
|
+
* Run a query with retry logic for transient API errors.
|
|
186
|
+
*/
|
|
187
|
+
private runWithRetry;
|
|
159
188
|
stop(): void;
|
|
160
189
|
}
|
|
161
190
|
|
|
@@ -209,6 +238,8 @@ declare class ConveyorConnection {
|
|
|
209
238
|
totalCostUsd: number;
|
|
210
239
|
onSubscription: boolean;
|
|
211
240
|
}): void;
|
|
241
|
+
emitStatus(status: string): void;
|
|
242
|
+
sendHeartbeat(): void;
|
|
212
243
|
sendTypingStart(): void;
|
|
213
244
|
sendTypingStop(): void;
|
|
214
245
|
disconnect(): void;
|
package/dist/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/connection.ts","../src/setup.ts","../src/runner.ts"],"sourcesContent":["import { io, type Socket } from \"socket.io-client\";\nimport type { AgentRunnerConfig, TaskContext, AgentEvent } from \"./types.js\";\n\nexport class ConveyorConnection {\n private socket: Socket | null = null;\n private config: AgentRunnerConfig;\n private eventBuffer: { taskId: string; event: AgentEvent }[] = [];\n private flushTimer: ReturnType<typeof setTimeout> | null = null;\n private static readonly EVENT_BATCH_MS = 500;\n\n private earlyMessages: { content: string; userId: string }[] = [];\n private earlyStop = false;\n private chatMessageCallback: ((msg: { content: string; userId: string }) => void) | null = null;\n private stopCallback: (() => void) | null = null;\n\n constructor(config: AgentRunnerConfig) {\n this.config = config;\n }\n\n connect(): Promise<void> {\n return new Promise((resolve, reject) => {\n let settled = false;\n let attempts = 0;\n const maxInitialAttempts = 30;\n\n this.socket = io(this.config.conveyorApiUrl, {\n auth: { taskToken: this.config.taskToken },\n transports: [\"websocket\"],\n reconnection: true,\n reconnectionAttempts: Infinity,\n reconnectionDelay: 2000,\n reconnectionDelayMax: 30000,\n randomizationFactor: 0.3,\n extraHeaders: {\n \"ngrok-skip-browser-warning\": \"true\",\n },\n });\n\n // Register listeners immediately so we capture messages the server\n // flushes during registerHandlers (before connect() resolves).\n this.socket.on(\"agentRunner:incomingMessage\", (msg: { content: string; userId: string }) => {\n if (this.chatMessageCallback) {\n this.chatMessageCallback(msg);\n } else {\n this.earlyMessages.push(msg);\n }\n });\n\n this.socket.on(\"agentRunner:stop\", () => {\n if (this.stopCallback) {\n this.stopCallback();\n } else {\n this.earlyStop = true;\n }\n });\n\n this.socket.on(\"connect\", () => {\n if (!settled) {\n settled = true;\n resolve();\n }\n });\n\n this.socket.io.on(\"reconnect_attempt\", () => {\n attempts++;\n if (!settled && attempts >= maxInitialAttempts) {\n settled = true;\n reject(new Error(`Failed to connect after ${maxInitialAttempts} attempts`));\n }\n });\n });\n }\n\n fetchChatMessages(\n limit?: number,\n ): Promise<\n { role: string; content: string; userId: string | null; userName?: string; createdAt: string }[]\n > {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n\n return new Promise((resolve, reject) => {\n socket.emit(\n \"agentRunner:getChatMessages\",\n { taskId: this.config.taskId, limit },\n (response: {\n success: boolean;\n data?: {\n role: string;\n content: string;\n userId: string | null;\n userName?: string;\n createdAt: string;\n }[];\n error?: string;\n }): void => {\n if (response.success && response.data) {\n resolve(response.data);\n } else {\n reject(new Error(response.error ?? \"Failed to fetch chat messages\"));\n }\n },\n );\n });\n }\n\n fetchTaskContext(): Promise<TaskContext> {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n\n return new Promise((resolve, reject) => {\n socket.emit(\n \"agentRunner:getTaskContext\",\n { taskId: this.config.taskId },\n (response: { success: boolean; data?: TaskContext; error?: string }): void => {\n if (response.success && response.data) {\n resolve(response.data);\n } else {\n reject(new Error(response.error ?? \"Failed to fetch task context\"));\n }\n },\n );\n });\n }\n\n sendEvent(event: AgentEvent): void {\n if (!this.socket) throw new Error(\"Not connected\");\n\n this.eventBuffer.push({ taskId: this.config.taskId, event });\n if (!this.flushTimer) {\n this.flushTimer = setTimeout(() => this.flushEvents(), ConveyorConnection.EVENT_BATCH_MS);\n }\n }\n\n flushEvents(): void {\n if (this.flushTimer) {\n clearTimeout(this.flushTimer);\n this.flushTimer = null;\n }\n if (!this.socket || this.eventBuffer.length === 0) return;\n for (const entry of this.eventBuffer) {\n this.socket.emit(\"agentRunner:event\", entry);\n }\n this.eventBuffer = [];\n }\n\n updateStatus(status: string): void {\n if (!this.socket) throw new Error(\"Not connected\");\n\n this.socket.emit(\"agentRunner:statusUpdate\", {\n taskId: this.config.taskId,\n status,\n });\n }\n\n postChatMessage(content: string): void {\n if (!this.socket) throw new Error(\"Not connected\");\n\n this.socket.emit(\"agentRunner:chatMessage\", {\n taskId: this.config.taskId,\n content,\n });\n }\n\n createPR(params: {\n title: string;\n body: string;\n baseBranch?: string;\n }): Promise<{ url: string; number: number }> {\n const socket = this.socket;\n if (!socket) throw new Error(\"Not connected\");\n\n return new Promise((resolve, reject) => {\n socket.emit(\n \"agentRunner:createPR\",\n { taskId: this.config.taskId, ...params },\n (response: {\n success: boolean;\n data?: { url: string; number: number };\n error?: string;\n }): void => {\n if (response.success && response.data) {\n resolve(response.data);\n } else {\n reject(new Error(response.error ?? \"Failed to create pull request\"));\n }\n },\n );\n });\n }\n\n storeSessionId(sessionId: string): void {\n if (!this.socket) return;\n this.socket.emit(\"agentRunner:storeSessionId\", {\n taskId: this.config.taskId,\n sessionId,\n });\n }\n\n updateTaskFields(fields: { plan?: string; description?: string }): void {\n if (!this.socket) throw new Error(\"Not connected\");\n this.socket.emit(\"agentRunner:updateTaskFields\", {\n taskId: this.config.taskId,\n fields,\n });\n }\n\n onChatMessage(callback: (message: { content: string; userId: string }) => void): void {\n this.chatMessageCallback = callback;\n for (const msg of this.earlyMessages) {\n callback(msg);\n }\n this.earlyMessages = [];\n }\n\n onStopRequested(callback: () => void): void {\n this.stopCallback = callback;\n if (this.earlyStop) {\n callback();\n this.earlyStop = false;\n }\n }\n\n trackSpending(params: {\n agentId: string;\n inputTokens: number;\n outputTokens: number;\n totalTokens: number;\n totalCostUsd: number;\n onSubscription: boolean;\n }): void {\n if (!this.socket) throw new Error(\"Not connected\");\n\n this.socket.emit(\"agentRunner:trackSpending\", {\n taskId: this.config.taskId,\n ...params,\n });\n }\n\n sendTypingStart(): void {\n this.sendEvent({ type: \"agent_typing_start\" });\n }\n\n sendTypingStop(): void {\n this.sendEvent({ type: \"agent_typing_stop\" });\n }\n\n disconnect(): void {\n this.flushEvents();\n this.socket?.disconnect();\n this.socket = null;\n }\n}\n","import { execSync } from \"node:child_process\";\nimport { spawn, type ChildProcess } from \"node:child_process\";\nimport { readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\n\nexport interface ConveyorConfig {\n setupCommand?: string;\n startCommand?: string;\n previewPort?: number;\n}\n\nconst CONVEYOR_CONFIG_PATH = \".conveyor/config.json\";\nconst DEVCONTAINER_PATH = \".devcontainer/conveyor/devcontainer.json\";\n\nexport async function loadForwardPorts(workspaceDir: string): Promise<number[]> {\n try {\n const raw = await readFile(join(workspaceDir, DEVCONTAINER_PATH), \"utf-8\");\n const parsed = JSON.parse(raw) as { forwardPorts?: number[] };\n return parsed.forwardPorts ?? [];\n } catch {\n return [];\n }\n}\n\nexport async function loadConveyorConfig(workspaceDir: string): Promise<ConveyorConfig | null> {\n // Primary: .conveyor/config.json\n try {\n const raw = await readFile(join(workspaceDir, CONVEYOR_CONFIG_PATH), \"utf-8\");\n const parsed = JSON.parse(raw) as ConveyorConfig;\n if (parsed.setupCommand || parsed.startCommand) return parsed;\n } catch {\n // Not found or invalid — try fallback\n }\n\n // Fallback: devcontainer.json \"conveyor\" section\n try {\n const raw = await readFile(join(workspaceDir, DEVCONTAINER_PATH), \"utf-8\");\n const parsed = JSON.parse(raw) as { conveyor?: ConveyorConfig };\n if (parsed.conveyor && (parsed.conveyor.startCommand || parsed.conveyor.setupCommand)) {\n return parsed.conveyor;\n }\n } catch {\n // Not found or invalid\n }\n\n return null;\n}\n\n/**\n * Runs a command synchronously (waits for exit). Streams stdout/stderr\n * line-by-line via the onOutput callback.\n */\nexport function runSetupCommand(\n cmd: string,\n cwd: string,\n onOutput: (stream: \"stdout\" | \"stderr\", data: string) => void,\n): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(\"sh\", [\"-c\", cmd], {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n env: { ...process.env },\n });\n\n child.stdout.on(\"data\", (chunk: Buffer) => {\n onOutput(\"stdout\", chunk.toString());\n });\n\n child.stderr.on(\"data\", (chunk: Buffer) => {\n onOutput(\"stderr\", chunk.toString());\n });\n\n child.on(\"close\", (code) => {\n if (code === 0) {\n resolve();\n } else {\n reject(new Error(`Setup command exited with code ${code}`));\n }\n });\n\n child.on(\"error\", (err) => {\n reject(err);\n });\n });\n}\n\n/**\n * Runs a command in the background (does not wait for exit). Returns the\n * ChildProcess so it can be cleaned up on agent shutdown. Streams\n * stdout/stderr via the onOutput callback.\n */\nexport function runStartCommand(\n cmd: string,\n cwd: string,\n onOutput: (stream: \"stdout\" | \"stderr\", data: string) => void,\n): ChildProcess {\n const child = spawn(\"sh\", [\"-c\", cmd], {\n cwd,\n stdio: [\"ignore\", \"pipe\", \"pipe\"],\n detached: true,\n env: { ...process.env },\n });\n\n child.stdout.on(\"data\", (chunk: Buffer) => {\n onOutput(\"stdout\", chunk.toString());\n });\n\n child.stderr.on(\"data\", (chunk: Buffer) => {\n onOutput(\"stderr\", chunk.toString());\n });\n\n child.unref();\n return child;\n}\n\n/**\n * Reset `.devcontainer/conveyor/devcontainer.json` to match the base branch\n * and remove the cloud-build \"configure\" commit from git history. This runs\n * AFTER the codespace has started (env vars are already in process memory)\n * so the agent sees a branch identical to base — no spurious diffs, no\n * rebase conflicts on devcontainer.json.\n */\nexport function cleanDevcontainerFromGit(\n workspaceDir: string,\n taskBranch: string,\n baseBranch: string,\n): { cleaned: boolean; message: string } {\n const git = (cmd: string): string =>\n execSync(cmd, { cwd: workspaceDir, encoding: \"utf-8\", timeout: 30_000 }).trim();\n\n try {\n git(`git fetch origin ${baseBranch}`);\n } catch {\n return { cleaned: false, message: `Failed to fetch origin/${baseBranch}` };\n }\n\n // Check if devcontainer.json differs from base\n try {\n git(`git diff --quiet origin/${baseBranch} -- ${DEVCONTAINER_PATH}`);\n return { cleaned: false, message: \"devcontainer.json already matches base\" };\n } catch {\n // diff --quiet exits non-zero when there IS a diff — expected path\n }\n\n try {\n const ahead = parseInt(git(`git rev-list --count origin/${baseBranch}..HEAD`), 10);\n\n if (ahead <= 1) {\n // Fresh start: only the devcontainer commit exists — hard reset to base\n git(`git reset --hard origin/${baseBranch}`);\n } else {\n // Relaunch: agent has prior commits — restore file and add fixup commit\n git(`git checkout origin/${baseBranch} -- ${DEVCONTAINER_PATH}`);\n git(`git add ${DEVCONTAINER_PATH}`);\n\n try {\n git(`git diff --cached --quiet -- ${DEVCONTAINER_PATH}`);\n return { cleaned: false, message: \"devcontainer.json already clean in working tree\" };\n } catch {\n git(`git commit -m \"chore: reset devcontainer config\"`);\n }\n }\n\n git(`git push --force-with-lease origin ${taskBranch}`);\n return { cleaned: true, message: \"devcontainer.json cleaned from git history\" };\n } catch (err) {\n const msg = err instanceof Error ? err.message : \"Unknown error\";\n return { cleaned: false, message: `Git cleanup failed: ${msg}` };\n }\n}\n","// oxlint-disable max-lines\nimport { execSync } from \"node:child_process\";\nimport {\n query,\n tool,\n createSdkMcpServer,\n type SDKMessage,\n type SDKUserMessage,\n} from \"@anthropic-ai/claude-agent-sdk\";\nimport { z } from \"zod\";\nimport type {\n AgentRunnerConfig,\n AgentRunnerCallbacks,\n AgentEvent,\n TaskContext,\n ActivityEventSummary,\n} from \"./types.js\";\nimport { ConveyorConnection } from \"./connection.js\";\nimport {\n cleanDevcontainerFromGit,\n loadConveyorConfig,\n loadForwardPorts,\n runSetupCommand,\n runStartCommand,\n type ConveyorConfig,\n} from \"./setup.js\";\n\nexport class AgentRunner {\n private config: AgentRunnerConfig;\n private connection: ConveyorConnection;\n private callbacks: AgentRunnerCallbacks;\n private stopped = false;\n private inputResolver: ((msg: SDKUserMessage) => void) | null = null;\n private pendingMessages: SDKUserMessage[] = [];\n private currentTurnToolCalls: ActivityEventSummary[] = [];\n private setupLog: string[] = [];\n private static readonly MAX_SETUP_LOG_LINES = 50;\n\n constructor(config: AgentRunnerConfig, callbacks: AgentRunnerCallbacks) {\n this.config = config;\n this.connection = new ConveyorConnection(config);\n this.callbacks = callbacks;\n }\n\n async start(): Promise<void> {\n await this.callbacks.onStatusChange(\"connecting\");\n await this.connection.connect();\n\n this.connection.onStopRequested(() => {\n this.stopped = true;\n });\n\n this.connection.onChatMessage((message) => {\n this.injectHumanMessage(message.content);\n });\n\n this.connection.sendEvent({\n type: \"connected\",\n taskId: this.config.taskId,\n });\n\n if (process.env.CODESPACES === \"true\") {\n const ports = await loadForwardPorts(this.config.workspaceDir);\n if (ports.length > 0 && process.env.CODESPACE_NAME) {\n const visibility = ports.map((p) => `${p}:public`).join(\" \");\n runStartCommand(\n `gh codespace ports visibility ${visibility} -c \"${process.env.CODESPACE_NAME}\" 2>/dev/null`,\n this.config.workspaceDir,\n () => undefined,\n );\n }\n await this.runProjectSetup();\n }\n\n this.initRtk();\n\n await this.callbacks.onStatusChange(\"fetching_context\");\n const context = await this.connection.fetchTaskContext();\n\n if (process.env.CODESPACES === \"true\" && context.baseBranch) {\n const result = cleanDevcontainerFromGit(\n this.config.workspaceDir,\n context.githubBranch,\n context.baseBranch,\n );\n if (result.cleaned) {\n this.setupLog.push(`[conveyor] ${result.message}`);\n }\n }\n\n await this.callbacks.onStatusChange(\"running\");\n\n try {\n await this.executeTask(context);\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Unknown error\";\n this.connection.sendEvent({ type: \"error\", message });\n await this.callbacks.onEvent({ type: \"error\", message });\n throw error;\n } finally {\n await this.callbacks.onStatusChange(\"finished\");\n this.connection.disconnect();\n }\n }\n\n private async runProjectSetup(): Promise<void> {\n await this.callbacks.onStatusChange(\"setup\");\n\n const config = await loadConveyorConfig(this.config.workspaceDir);\n if (!config) {\n this.connection.sendEvent({ type: \"setup_complete\" });\n await this.callbacks.onEvent({ type: \"setup_complete\" });\n return;\n }\n\n try {\n await this.executeSetupConfig(config);\n const setupEvent: AgentEvent = {\n type: \"setup_complete\",\n previewPort: config.previewPort ?? undefined,\n };\n this.connection.sendEvent(setupEvent);\n await this.callbacks.onEvent(setupEvent);\n } catch (error) {\n const message = error instanceof Error ? error.message : \"Setup failed\";\n this.connection.sendEvent({ type: \"setup_error\", message });\n await this.callbacks.onEvent({ type: \"setup_error\", message });\n throw error;\n }\n }\n\n private pushSetupLog(line: string): void {\n this.setupLog.push(line);\n if (this.setupLog.length > AgentRunner.MAX_SETUP_LOG_LINES) {\n this.setupLog.splice(0, this.setupLog.length - AgentRunner.MAX_SETUP_LOG_LINES);\n }\n }\n\n private async executeSetupConfig(config: ConveyorConfig): Promise<void> {\n if (config.setupCommand) {\n this.pushSetupLog(`$ ${config.setupCommand}`);\n await runSetupCommand(config.setupCommand, this.config.workspaceDir, (stream, data) => {\n this.connection.sendEvent({ type: \"setup_output\", stream, data });\n for (const line of data.split(\"\\n\").filter(Boolean)) {\n this.pushSetupLog(`[${stream}] ${line}`);\n }\n });\n this.pushSetupLog(\"(exit 0)\");\n }\n\n if (config.startCommand) {\n this.pushSetupLog(`$ ${config.startCommand} & (background)`);\n runStartCommand(config.startCommand, this.config.workspaceDir, (stream, data) => {\n this.connection.sendEvent({ type: \"start_command_output\", stream, data });\n });\n }\n }\n\n private initRtk(): void {\n try {\n execSync(\"rtk --version\", { stdio: \"ignore\" });\n execSync(\"rtk init --global --auto-patch\", { stdio: \"ignore\" });\n } catch {\n // RTK not installed — skip silently\n }\n }\n\n private injectHumanMessage(content: string): void {\n const msg: SDKUserMessage = {\n type: \"user\" as const,\n session_id: \"\",\n message: { role: \"user\" as const, content },\n parent_tool_use_id: null,\n };\n\n if (this.inputResolver) {\n const resolve = this.inputResolver;\n this.inputResolver = null;\n resolve(msg);\n } else {\n this.pendingMessages.push(msg);\n }\n }\n\n private async *createInputStream(\n initialPrompt: string,\n ): AsyncGenerator<SDKUserMessage, void, unknown> {\n yield {\n type: \"user\" as const,\n session_id: \"\",\n message: { role: \"user\" as const, content: initialPrompt },\n parent_tool_use_id: null,\n };\n\n while (!this.stopped) {\n if (this.pendingMessages.length > 0) {\n const next = this.pendingMessages.shift();\n if (next) {\n yield next;\n }\n continue;\n }\n\n await this.callbacks.onStatusChange(\"waiting_for_input\");\n const msg = await new Promise<SDKUserMessage | null>((resolve) => {\n this.inputResolver = resolve as (msg: SDKUserMessage) => void;\n\n const checkStopped = setInterval(() => {\n if (this.stopped) {\n clearInterval(checkStopped);\n this.inputResolver = null;\n resolve(null);\n }\n }, 1000);\n });\n\n if (!msg) break;\n await this.callbacks.onStatusChange(\"running\");\n yield msg;\n }\n }\n\n private findLastAgentMessageIndex(history: TaskContext[\"chatHistory\"]): number {\n for (let i = history.length - 1; i >= 0; i--) {\n if (history[i].role === \"assistant\") return i;\n }\n return -1;\n }\n\n private detectRelaunchScenario(\n context: TaskContext,\n ): \"fresh\" | \"idle_relaunch\" | \"feedback_relaunch\" {\n const lastAgentIdx = this.findLastAgentMessageIndex(context.chatHistory);\n if (lastAgentIdx === -1) return \"fresh\";\n\n const hasPriorWork = !!context.githubPRUrl || !!context.claudeSessionId;\n if (!hasPriorWork) return \"fresh\";\n\n const messagesAfterAgent = context.chatHistory.slice(lastAgentIdx + 1);\n const hasNewUserMessages = messagesAfterAgent.some((m) => m.role === \"user\");\n return hasNewUserMessages ? \"feedback_relaunch\" : \"idle_relaunch\";\n }\n\n // eslint-disable-next-line max-lines-per-function\n private buildInitialPrompt(context: TaskContext): string {\n const parts: string[] = [];\n const scenario = this.detectRelaunchScenario(context);\n\n // When resuming a session, the context is already in the session history —\n // just inject a brief orientation message.\n if (context.claudeSessionId && scenario !== \"fresh\") {\n if (scenario === \"feedback_relaunch\") {\n const lastAgentIdx = this.findLastAgentMessageIndex(context.chatHistory);\n const newMessages = context.chatHistory\n .slice(lastAgentIdx + 1)\n .filter((m) => m.role === \"user\");\n parts.push(\n `You have been relaunched with new feedback.`,\n `Work on the git branch \"${context.githubBranch}\".`,\n `\\nNew messages since your last run:`,\n ...newMessages.map((m) => `[${m.userName ?? \"user\"}]: ${m.content}`),\n `\\nAddress the requested changes. Commit and push your updates.`,\n );\n if (context.githubPRUrl) {\n parts.push(\n `An existing PR is open at ${context.githubPRUrl} — push to the same branch. Do NOT create a new PR.`,\n );\n } else {\n parts.push(\n `When finished, use the create_pull_request tool to open a PR. Do NOT use gh CLI.`,\n );\n }\n } else {\n parts.push(\n `You were relaunched but no new instructions have been given since your last run.`,\n `Work on the git branch \"${context.githubBranch}\".`,\n `Review the current state of the codebase and verify everything is working correctly.`,\n `Post a brief status update to the chat, then wait for further instructions.`,\n );\n if (context.githubPRUrl) {\n parts.push(`An existing PR is open at ${context.githubPRUrl}. Do not create a new PR.`);\n }\n }\n return parts.join(\"\\n\");\n }\n\n parts.push(`# Task: ${context.title}`);\n if (context.description) {\n parts.push(`\\n## Description\\n${context.description}`);\n }\n if (context.plan) {\n parts.push(`\\n## Plan\\n${context.plan}`);\n }\n\n if (context.files && context.files.length > 0) {\n parts.push(`\\n## Attached Files`);\n for (const file of context.files) {\n parts.push(`- **${file.fileName}** (${file.mimeType}): ${file.downloadUrl}`);\n }\n }\n\n if (context.repoRefs && context.repoRefs.length > 0) {\n parts.push(`\\n## Repository References`);\n for (const ref of context.repoRefs) {\n const icon = ref.refType === \"folder\" ? \"folder\" : \"file\";\n parts.push(`- [${icon}] \\`${ref.path}\\``);\n }\n }\n\n if (context.chatHistory.length > 0) {\n const relevant = context.chatHistory.slice(-20);\n parts.push(`\\n## Recent Chat Context`);\n for (const msg of relevant) {\n const sender = msg.userName ?? msg.role;\n parts.push(`[${sender}]: ${msg.content}`);\n }\n }\n\n parts.push(`\\n## Instructions`);\n\n if (scenario === \"fresh\") {\n if (this.config.mode === \"pm\") {\n // For fresh PM scenarios, provide minimal context and explicitly wait for user input\n parts.push(\n `You are the project manager for this task.`,\n `The task details are provided above. Wait for the team to ask questions or provide additional requirements before starting to plan.`,\n );\n } else {\n parts.push(\n `Begin executing the task plan above immediately.`,\n `Your FIRST action should be reading the relevant source files mentioned in the plan, then writing code. Do NOT run install, build, lint, test, or dev server commands first — the environment is already set up.`,\n `Work on the git branch \"${context.githubBranch}\".`,\n `Post a brief message to chat when you begin meaningful implementation, and again when the PR is ready.`,\n `When finished, commit your changes, push the branch, and use the create_pull_request tool to open a PR. Do NOT use gh CLI or any other method to create PRs.`,\n );\n }\n } else if (scenario === \"idle_relaunch\") {\n parts.push(\n `You were relaunched but no new instructions have been given since your last run.`,\n `Work on the git branch \"${context.githubBranch}\".`,\n `Review the current state of the codebase and verify everything is working correctly (e.g. tests pass, the web server starts on port 3000).`,\n `Post a brief status update to the chat summarizing the current state.`,\n `Then wait for further instructions — do NOT redo work that was already completed.`,\n );\n if (context.githubPRUrl) {\n parts.push(`An existing PR is open at ${context.githubPRUrl}. Do not create a new PR.`);\n }\n } else {\n const lastAgentIdx = this.findLastAgentMessageIndex(context.chatHistory);\n const newMessages = context.chatHistory\n .slice(lastAgentIdx + 1)\n .filter((m) => m.role === \"user\");\n parts.push(\n `You were relaunched with new feedback since your last run.`,\n `Work on the git branch \"${context.githubBranch}\".`,\n `\\nNew messages since your last run:`,\n ...newMessages.map((m) => `[${m.userName ?? \"user\"}]: ${m.content}`),\n `\\nAddress the requested changes. Commit and push your updates.`,\n );\n if (context.githubPRUrl) {\n parts.push(\n `An existing PR is open at ${context.githubPRUrl} — push to the same branch to update it. Do NOT create a new PR.`,\n );\n } else {\n parts.push(\n `When finished, use the create_pull_request tool to open a PR. Do NOT use gh CLI or any other method to create PRs.`,\n );\n }\n }\n\n return parts.join(\"\\n\");\n }\n\n private buildSystemPrompt(context: TaskContext): string {\n const parts =\n this.config.mode === \"pm\"\n ? [\n `You are an AI project manager helping to plan tasks for the \"${context.title}\" project.`,\n `You are running locally with full access to the repository.`,\n `\\nEnvironment (ready, no setup required):`,\n `- Repository is cloned at your current working directory.`,\n `- You can read files to understand the codebase before writing task plans.`,\n `- Check the dev branch (e.g. run: git fetch && git checkout dev || git checkout main) to understand the current state of the codebase that agents will branch off of.`,\n ]\n : [\n `You are an AI agent working on a task for the \"${context.title}\" project.`,\n `You are running inside a GitHub Codespace with full access to the repository.`,\n `\\nEnvironment (fully ready — do NOT verify or set up):`,\n `- Repository is cloned at your current working directory.`,\n `- Branch \\`${context.githubBranch}\\` is already checked out.`,\n `- All dependencies are installed, database is migrated, and the dev server is running.`,\n `- Git is configured. Commit and push directly to this branch.`,\n `\\nIMPORTANT — Skip all environment verification. Do NOT run any of the following:`,\n `- bun/npm install, pip install, or any dependency installation`,\n `- bun build, bun lint, bun test, bun typecheck, or any build/check commands as a \"first step\"`,\n `- bun db:generate, bun db:push, prisma migrate, or any database setup`,\n `- bun dev, npm start, or any dev server startup commands`,\n `- pwd, ls, echo, or exploratory shell commands to \"check\" the environment`,\n `Only run these if you encounter a specific error that requires it.`,\n `Start reading the task plan and writing code immediately.`,\n ];\n\n if (this.setupLog.length > 0) {\n parts.push(\n `\\nEnvironment setup log (already executed before you started — proof that setup succeeded):`,\n \"```\",\n ...this.setupLog,\n \"```\",\n );\n }\n\n if (context.agentInstructions) {\n parts.push(`\\nAgent Instructions:\\n${context.agentInstructions}`);\n }\n if (this.config.instructions) {\n parts.push(`\\nAdditional Instructions:\\n${this.config.instructions}`);\n }\n parts.push(\n `\\nYou have access to Conveyor MCP tools to interact with the task management system.`,\n `Use the post_to_chat tool to communicate progress or ask questions.`,\n `Use the read_task_chat tool to check for new messages from the team.`,\n );\n if (this.config.mode !== \"pm\") {\n parts.push(\n `Use the create_pull_request tool to open PRs — do NOT use gh CLI or shell commands for PR creation.`,\n );\n }\n return parts.join(\"\\n\");\n }\n\n // oxlint-disable-next-line typescript/explicit-function-return-type, max-lines-per-function\n private createConveyorMcpServer(context: TaskContext) {\n const connection = this.connection;\n const config = this.config;\n\n const textResult = (text: string): { content: { type: \"text\"; text: string }[] } => ({\n content: [{ type: \"text\" as const, text }],\n });\n\n const commonTools = [\n tool(\n \"read_task_chat\",\n \"Read recent messages from the task chat to see team feedback or instructions\",\n {\n limit: z.number().optional().describe(\"Number of recent messages to fetch (default 20)\"),\n },\n async ({ limit }) => {\n try {\n const messages = await connection.fetchChatMessages(limit);\n return textResult(JSON.stringify(messages, null, 2));\n } catch {\n return textResult(\n JSON.stringify({\n note: \"Could not fetch live chat. Chat history was provided in the initial context.\",\n }),\n );\n }\n },\n { annotations: { readOnly: true } },\n ),\n tool(\n \"post_to_chat\",\n \"Post a message to the task chat visible to all team members\",\n { message: z.string().describe(\"The message to post to the team\") },\n ({ message }) => {\n connection.postChatMessage(message);\n return Promise.resolve(textResult(\"Message posted to task chat.\"));\n },\n ),\n tool(\n \"update_task_status\",\n \"Update the task status on the Kanban board\",\n {\n status: z\n .enum([\"InProgress\", \"ReviewPR\", \"Complete\"])\n .describe(\"The new status for the task\"),\n },\n ({ status }) => {\n connection.updateStatus(status);\n return Promise.resolve(textResult(`Task status updated to ${status}.`));\n },\n ),\n tool(\n \"get_task_plan\",\n \"Re-read the latest task plan in case it was updated\",\n {},\n async () => {\n try {\n const ctx = await connection.fetchTaskContext();\n return textResult(ctx.plan ?? \"No plan available.\");\n } catch {\n return textResult(`Task ID: ${config.taskId} - could not fetch updated plan.`);\n }\n },\n { annotations: { readOnly: true } },\n ),\n ];\n\n // PM mode gets update_task tool; task mode gets create_pull_request\n const modeTools =\n config.mode === \"pm\"\n ? [\n tool(\n \"update_task\",\n \"Save the finalized task plan and/or description\",\n {\n plan: z.string().optional().describe(\"The task plan in markdown\"),\n description: z.string().optional().describe(\"Updated task description\"),\n },\n async ({ plan, description }) => {\n try {\n connection.updateTaskFields({ plan, description });\n return textResult(\"Task updated successfully.\");\n } catch {\n return textResult(\"Failed to update task.\");\n }\n },\n ),\n ]\n : [\n tool(\n \"create_pull_request\",\n \"Create a GitHub pull request for this task. Use this instead of gh CLI or git commands to create PRs.\",\n {\n title: z.string().describe(\"The PR title\"),\n body: z.string().describe(\"The PR description/body in markdown\"),\n },\n async ({ title, body }) => {\n try {\n const result = await connection.createPR({ title, body });\n connection.sendEvent({\n type: \"pr_created\",\n url: result.url,\n number: result.number,\n });\n return textResult(`Pull request #${result.number} created: ${result.url}`);\n } catch (error) {\n const msg = error instanceof Error ? error.message : \"Unknown error\";\n return textResult(`Failed to create pull request: ${msg}`);\n }\n },\n ),\n ];\n\n return createSdkMcpServer({\n name: \"conveyor\",\n tools: [...commonTools, ...modeTools],\n });\n\n // Suppress unused warning — context used by callers for session ID\n void context;\n }\n\n // oxlint-disable-next-line max-lines-per-function, complexity\n private async processEvents(\n events: AsyncGenerator<SDKMessage, void>,\n context: TaskContext,\n ): Promise<void> {\n const startTime = Date.now();\n let totalCostUsd = 0;\n let sessionIdStored = false;\n let isTyping = false;\n\n for await (const event of events) {\n if (this.stopped) break;\n\n switch (event.type) {\n case \"system\": {\n if (event.subtype === \"init\") {\n const sessionId = (event as unknown as Record<string, unknown>).session_id as\n | string\n | undefined;\n if (sessionId && !sessionIdStored) {\n sessionIdStored = true;\n this.connection.storeSessionId(sessionId);\n }\n await this.callbacks.onEvent({\n type: \"thinking\",\n message: `Agent initialized (model: ${event.model})`,\n });\n }\n break;\n }\n\n case \"assistant\": {\n // Send typing start event with 200ms delay (like Cloud PM Agent)\n if (!isTyping) {\n setTimeout(() => {\n this.connection.sendTypingStart();\n }, 200);\n isTyping = true;\n }\n\n const msg = event.message as unknown as Record<string, unknown>;\n const content = msg.content as Record<string, unknown>[];\n const turnTextParts: string[] = [];\n for (const block of content) {\n const blockType = block.type as string;\n if (blockType === \"text\") {\n const text = block.text as string;\n turnTextParts.push(text);\n this.connection.sendEvent({ type: \"message\", content: text });\n await this.callbacks.onEvent({ type: \"message\", content: text });\n } else if (blockType === \"tool_use\") {\n const name = block.name as string;\n const inputStr =\n typeof block.input === \"string\" ? block.input : JSON.stringify(block.input);\n const isContentTool = [\"edit\", \"write\"].includes(name.toLowerCase());\n const inputLimit = isContentTool ? 10_000 : 500;\n const summary: ActivityEventSummary = {\n tool: name,\n input: inputStr.slice(0, inputLimit),\n timestamp: new Date().toISOString(),\n };\n this.currentTurnToolCalls.push(summary);\n this.connection.sendEvent({\n type: \"tool_use\",\n tool: name,\n input: inputStr,\n });\n await this.callbacks.onEvent({\n type: \"tool_use\",\n tool: name,\n input: inputStr,\n });\n }\n }\n\n if (turnTextParts.length > 0) {\n this.connection.postChatMessage(turnTextParts.join(\"\\n\\n\"));\n }\n\n if (this.currentTurnToolCalls.length > 0) {\n this.connection.sendEvent({\n type: \"turn_end\",\n toolCalls: [...this.currentTurnToolCalls],\n });\n this.currentTurnToolCalls = [];\n }\n break;\n }\n\n case \"result\": {\n // Send typing stop event when processing completes\n if (isTyping) {\n this.connection.sendTypingStop();\n isTyping = false;\n }\n\n const resultEvent = event as SDKMessage & { type: \"result\"; subtype: string };\n if (resultEvent.subtype === \"success\") {\n totalCostUsd =\n \"total_cost_usd\" in resultEvent\n ? ((resultEvent as Record<string, unknown>).total_cost_usd as number)\n : 0;\n const durationMs = Date.now() - startTime;\n const summary =\n \"result\" in resultEvent\n ? String((resultEvent as Record<string, unknown>).result)\n : \"Task completed.\";\n\n this.connection.sendEvent({\n type: \"completed\",\n summary,\n costUsd: totalCostUsd,\n durationMs,\n });\n\n // Track spending if cost information is available and we have an agent ID\n if (totalCostUsd > 0 && context.agentId) {\n // For now, estimate token usage from cost since SDK doesn't provide detailed breakdown\n // We'll use the agent's default model to reverse-calculate approximate tokens\n // Rough estimation: assume average token cost and split evenly between input/output\n // This is a temporary solution until we can get actual token counts from SDK\n const estimatedTotalTokens = Math.round(totalCostUsd * 100000); // Very rough estimate\n const estimatedInputTokens = Math.round(estimatedTotalTokens * 0.7); // 70% input\n const estimatedOutputTokens = Math.round(estimatedTotalTokens * 0.3); // 30% output\n\n this.connection.trackSpending({\n agentId: context.agentId,\n inputTokens: estimatedInputTokens,\n outputTokens: estimatedOutputTokens,\n totalTokens: estimatedTotalTokens,\n totalCostUsd,\n onSubscription: !!process.env.CLAUDE_CODE_OAUTH_TOKEN,\n });\n }\n\n await this.callbacks.onEvent({\n type: \"completed\",\n summary,\n costUsd: totalCostUsd,\n durationMs,\n });\n } else {\n const errors =\n \"errors\" in resultEvent\n ? ((resultEvent as Record<string, unknown>).errors as string[])\n : [];\n const errorMsg =\n errors.length > 0 ? errors.join(\", \") : `Agent stopped: ${resultEvent.subtype}`;\n this.connection.sendEvent({ type: \"error\", message: errorMsg });\n await this.callbacks.onEvent({ type: \"error\", message: errorMsg });\n }\n break;\n }\n }\n }\n\n // Ensure typing stops when processing ends\n if (isTyping) {\n this.connection.sendTypingStop();\n }\n }\n\n // oxlint-disable-next-line max-lines-per-function\n private async executeTask(context: TaskContext): Promise<void> {\n if (this.stopped) return;\n\n const settings = context.agentSettings ?? this.config.agentSettings ?? {};\n const systemPromptText = this.buildSystemPrompt(context);\n const conveyorMcp = this.createConveyorMcpServer(context);\n\n const systemPrompt: { type: \"preset\"; preset: \"claude_code\"; append?: string } = {\n type: \"preset\",\n preset: \"claude_code\",\n append: systemPromptText || undefined,\n };\n const settingSources = (settings.settingSources ?? [\"user\", \"project\"]) as (\n | \"user\"\n | \"project\"\n | \"local\"\n )[];\n\n const model = context.model || this.config.model;\n const pmDisallowedTools = this.config.mode === \"pm\" ? [\"TodoWrite\", \"TodoRead\"] : [];\n const disallowedTools = [...(settings.disallowedTools ?? []), ...pmDisallowedTools];\n\n const commonOptions = {\n model,\n systemPrompt,\n settingSources,\n cwd: this.config.workspaceDir,\n permissionMode: \"bypassPermissions\" as const,\n allowDangerouslySkipPermissions: true,\n tools: { type: \"preset\" as const, preset: \"claude_code\" as const },\n mcpServers: { conveyor: conveyorMcp },\n maxTurns: settings.maxTurns,\n effort: settings.effort,\n thinking: settings.thinking,\n betas: settings.betas,\n maxBudgetUsd: settings.maxBudgetUsd ?? 50,\n disallowedTools: disallowedTools.length > 0 ? disallowedTools : undefined,\n enableFileCheckpointing: settings.enableFileCheckpointing,\n };\n\n const initialPrompt = this.buildInitialPrompt(context);\n const agentQuery = query({\n prompt: this.createInputStream(initialPrompt),\n options: {\n ...commonOptions,\n resume: context.claudeSessionId ?? undefined,\n },\n });\n\n try {\n await this.processEvents(agentQuery, context);\n } catch (error) {\n const isStaleSession =\n error instanceof Error && error.message.includes(\"No conversation found with session ID\");\n\n if (isStaleSession && context.claudeSessionId) {\n this.connection.storeSessionId(\"\");\n const freshPrompt = this.buildInitialPrompt({ ...context, claudeSessionId: null });\n const freshQuery = query({\n prompt: this.createInputStream(freshPrompt),\n options: { ...commonOptions, resume: undefined },\n });\n await this.processEvents(freshQuery, context);\n } else {\n throw error;\n }\n }\n }\n\n stop(): void {\n this.stopped = true;\n if (this.inputResolver) {\n this.inputResolver(null as unknown as SDKUserMessage);\n this.inputResolver = null;\n }\n }\n}\n"],"mappings":"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","names":["execSync","execSync"]}
|