@rallycry/conveyor-agent 4.10.2 → 5.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -646,13 +646,6 @@ function runStartCommand(cmd, cwd, onOutput) {
646
646
 
647
647
  // src/setup/codespace.ts
648
648
  import { execSync as execSync3 } from "child_process";
649
- function initRtk() {
650
- try {
651
- execSync3("rtk --version", { stdio: "ignore" });
652
- execSync3("rtk init --global --auto-patch", { stdio: "ignore" });
653
- } catch {
654
- }
655
- }
656
649
  function unshallowRepo(workspaceDir) {
657
650
  try {
658
651
  execSync3("git fetch --unshallow", {
@@ -664,6 +657,33 @@ function unshallowRepo(workspaceDir) {
664
657
  }
665
658
  }
666
659
 
660
+ // src/utils/logger.ts
661
+ import winston from "winston";
662
+ var { combine, timestamp, printf, colorize } = winston.format;
663
+ var customFormat = printf(({ level, message, timestamp: ts, service, ...meta }) => {
664
+ const svc = service ? `[${service}] ` : "";
665
+ const metaStr = Object.keys(meta).length ? ` ${JSON.stringify(meta)}` : "";
666
+ return `${ts} [${level}]: ${svc}${message}${metaStr}`;
667
+ });
668
+ var logger = winston.createLogger({
669
+ level: process.env.LOG_LEVEL ?? "info",
670
+ format: combine(timestamp({ format: "YYYY-MM-DD HH:mm:ss" }), combine(colorize(), customFormat)),
671
+ transports: [new winston.transports.Console()]
672
+ });
673
+ function createServiceLogger(serviceName) {
674
+ return logger.child({ service: serviceName });
675
+ }
676
+ function errorMeta(error) {
677
+ if (error instanceof Error) {
678
+ return {
679
+ message: error.message,
680
+ stack: error.stack,
681
+ ..."code" in error && typeof error.code === "string" ? { code: error.code } : {}
682
+ };
683
+ }
684
+ return { message: String(error) };
685
+ }
686
+
667
687
  // src/runner/agent-runner.ts
668
688
  import { randomUUID as randomUUID2 } from "crypto";
669
689
  import { execSync as execSync4 } from "child_process";
@@ -2851,6 +2871,39 @@ async function executeSetupConfig(config, runnerConfig, connection, setupLog, ef
2851
2871
  }
2852
2872
  return deferredStartConfig;
2853
2873
  }
2874
+ async function checkoutTaskBranch(runnerConfig, connection, callbacks, setupLog) {
2875
+ const taskBranch = process.env.CONVEYOR_TASK_BRANCH;
2876
+ if (!taskBranch) return true;
2877
+ pushSetupLog(setupLog, `[conveyor] Switching to task branch ${taskBranch}...`);
2878
+ connection.sendEvent({
2879
+ type: "setup_output",
2880
+ stream: "stdout",
2881
+ data: `Switching to task branch ${taskBranch}...
2882
+ `
2883
+ });
2884
+ try {
2885
+ await runSetupCommand(
2886
+ `git fetch origin ${taskBranch} && git checkout ${taskBranch}`,
2887
+ runnerConfig.workspaceDir,
2888
+ (stream, data) => {
2889
+ connection.sendEvent({ type: "setup_output", stream, data });
2890
+ for (const line of data.split("\n").filter(Boolean)) {
2891
+ pushSetupLog(setupLog, `[${stream}] ${line}`);
2892
+ }
2893
+ }
2894
+ );
2895
+ pushSetupLog(setupLog, `[conveyor] Switched to ${taskBranch}`);
2896
+ return true;
2897
+ } catch (error) {
2898
+ const message = `Failed to checkout ${taskBranch}: ${error instanceof Error ? error.message : "unknown error"}`;
2899
+ connection.sendEvent({ type: "setup_error", message });
2900
+ await callbacks.onEvent({ type: "setup_error", message });
2901
+ connection.postChatMessage(`Failed to switch to task branch \`${taskBranch}\`.
2902
+
2903
+ ${message}`);
2904
+ return false;
2905
+ }
2906
+ }
2854
2907
  async function runSetupSafe(runnerConfig, connection, callbacks, setupLog, effectiveAgentMode, setState) {
2855
2908
  await setState("setup");
2856
2909
  const ports = await loadForwardPorts(runnerConfig.workspaceDir);
@@ -2862,18 +2915,21 @@ async function runSetupSafe(runnerConfig, connection, callbacks, setupLog, effec
2862
2915
  () => void 0
2863
2916
  );
2864
2917
  }
2865
- const pullBranch = process.env.CONVEYOR_PULL_BRANCH;
2866
- if (pullBranch) {
2867
- pushSetupLog(setupLog, `[conveyor] Merging latest from ${pullBranch}...`);
2918
+ if (!await checkoutTaskBranch(runnerConfig, connection, callbacks, setupLog)) {
2919
+ return { ok: false, deferredStartConfig: null };
2920
+ }
2921
+ const taskBranch = process.env.CONVEYOR_TASK_BRANCH;
2922
+ if (taskBranch) {
2923
+ pushSetupLog(setupLog, `[conveyor] Switching to task branch ${taskBranch}...`);
2868
2924
  connection.sendEvent({
2869
2925
  type: "setup_output",
2870
2926
  stream: "stdout",
2871
- data: `Merging latest from ${pullBranch}...
2927
+ data: `Switching to task branch ${taskBranch}...
2872
2928
  `
2873
2929
  });
2874
2930
  try {
2875
2931
  await runSetupCommand(
2876
- `git fetch origin ${pullBranch} && git merge origin/${pullBranch} --no-edit`,
2932
+ `git fetch origin ${taskBranch} && git checkout ${taskBranch}`,
2877
2933
  runnerConfig.workspaceDir,
2878
2934
  (stream, data) => {
2879
2935
  connection.sendEvent({ type: "setup_output", stream, data });
@@ -2882,13 +2938,13 @@ async function runSetupSafe(runnerConfig, connection, callbacks, setupLog, effec
2882
2938
  }
2883
2939
  }
2884
2940
  );
2885
- pushSetupLog(setupLog, `[conveyor] Merge complete`);
2941
+ pushSetupLog(setupLog, `[conveyor] Switched to ${taskBranch}`);
2886
2942
  } catch (error) {
2887
- const message = `Failed to merge ${pullBranch}: ${error instanceof Error ? error.message : "unknown error"}`;
2943
+ const message = `Failed to checkout ${taskBranch}: ${error instanceof Error ? error.message : "unknown error"}`;
2888
2944
  connection.sendEvent({ type: "setup_error", message });
2889
2945
  await callbacks.onEvent({ type: "setup_error", message });
2890
2946
  connection.postChatMessage(
2891
- `Failed to merge latest code from \`${pullBranch}\`. There may be conflicts between the prebuild branch and dev.
2947
+ `Failed to switch to task branch \`${taskBranch}\`.
2892
2948
 
2893
2949
  ${message}`
2894
2950
  );
@@ -3064,6 +3120,7 @@ function buildQueryHost(deps) {
3064
3120
  }
3065
3121
 
3066
3122
  // src/runner/agent-runner.ts
3123
+ var logger2 = createServiceLogger("AgentRunner");
3067
3124
  var HEARTBEAT_INTERVAL_MS = 3e4;
3068
3125
  var IDLE_TIMEOUT_MS = 30 * 60 * 1e3;
3069
3126
  var AgentRunner = class {
@@ -3164,7 +3221,6 @@ var AgentRunner = class {
3164
3221
  }
3165
3222
  this.deferredStartConfig = result.deferredStartConfig;
3166
3223
  }
3167
- initRtk();
3168
3224
  this.tryInitWorktree();
3169
3225
  if (!await this.fetchAndInitContext()) return;
3170
3226
  if (process.env.CODESPACES === "true" && this.taskContext) {
@@ -3245,8 +3301,10 @@ var AgentRunner = class {
3245
3301
  "Auto-nudge: Task is still In Progress with no PR. Prompting agent to continue..."
3246
3302
  );
3247
3303
  await this.setState("running");
3304
+ const ctx = this.taskContext ?? fresh;
3305
+ if (!ctx) return false;
3248
3306
  await this.runQuerySafe(
3249
- this.taskContext,
3307
+ ctx,
3250
3308
  "You are in Auto mode and your task is still In Progress with no pull request. You MUST create a pull request before finishing. Use the create_pull_request tool now to open a PR for your changes. If you are blocked, explain what is preventing you from creating a PR."
3251
3309
  );
3252
3310
  return true;
@@ -3336,7 +3394,12 @@ var AgentRunner = class {
3336
3394
  handleRunStartCommand() {
3337
3395
  if (!this.deferredStartConfig?.startCommand || this.startCommandStarted) return;
3338
3396
  this.startCommandStarted = true;
3339
- runDeferredStartCommand(this.deferredStartConfig, this.config, this.connection, this.setupLog);
3397
+ runDeferredStartCommand(
3398
+ this.deferredStartConfig,
3399
+ this.config,
3400
+ this.connection,
3401
+ this.setupLog
3402
+ );
3340
3403
  this.deferredStartConfig = null;
3341
3404
  }
3342
3405
  logEffectiveSettings() {
@@ -3344,18 +3407,17 @@ var AgentRunner = class {
3344
3407
  const s = this.taskContext.agentSettings ?? this.config.agentSettings ?? {};
3345
3408
  const model = this.taskContext.model || this.config.model;
3346
3409
  const thinking = formatThinkingSetting(s.thinking);
3347
- const parts = [
3348
- `model=${model}`,
3349
- `mode=${this.config.mode ?? "task"}`,
3350
- `effort=${s.effort ?? "default"}`,
3351
- `thinking=${thinking}`,
3352
- `maxBudget=$${s.maxBudgetUsd ?? 50}`,
3353
- `maxTurns=${s.maxTurns ?? "unlimited"}`
3354
- ];
3355
- if (s.betas?.length) parts.push(`betas=${s.betas.join(",")}`);
3356
- if (s.disallowedTools?.length) parts.push(`disallowed=[${s.disallowedTools.join(",")}]`);
3357
- if (s.enableFileCheckpointing) parts.push(`checkpointing=on`);
3358
- console.log(`[conveyor-agent] ${parts.join(", ")}`);
3410
+ logger2.info("Effective agent settings", {
3411
+ model,
3412
+ mode: this.config.mode ?? "task",
3413
+ effort: s.effort ?? "default",
3414
+ thinking,
3415
+ maxBudget: s.maxBudgetUsd ?? 50,
3416
+ maxTurns: s.maxTurns ?? "unlimited",
3417
+ ...s.betas?.length ? { betas: s.betas } : {},
3418
+ ...s.disallowedTools?.length ? { disallowedTools: s.disallowedTools } : {},
3419
+ ...s.enableFileCheckpointing ? { checkpointing: "on" } : {}
3420
+ });
3359
3421
  }
3360
3422
  injectHumanMessage(content, files) {
3361
3423
  const messageContent = buildMessageContent(content, files);
@@ -3386,9 +3448,9 @@ var AgentRunner = class {
3386
3448
  this.idleTimer = setTimeout(() => {
3387
3449
  this.clearIdleTimers();
3388
3450
  this.inputResolver = null;
3389
- console.log(
3390
- `[conveyor-agent] Idle for ${IDLE_TIMEOUT_MS / 6e4} minutes \u2014 shutting down.`
3391
- );
3451
+ logger2.info("Idle timeout reached, shutting down", {
3452
+ idleMinutes: IDLE_TIMEOUT_MS / 6e4
3453
+ });
3392
3454
  this.connection.postChatMessage(
3393
3455
  `Agent idle for ${IDLE_TIMEOUT_MS / 6e4} minutes with no new messages \u2014 shutting down.`
3394
3456
  );
@@ -3509,6 +3571,7 @@ import { fileURLToPath } from "url";
3509
3571
 
3510
3572
  // src/runner/project-chat-handler.ts
3511
3573
  import { query as query2 } from "@anthropic-ai/claude-agent-sdk";
3574
+ var logger3 = createServiceLogger("ProjectChat");
3512
3575
  var FALLBACK_MODEL = "claude-sonnet-4-20250514";
3513
3576
  function buildSystemPrompt2(projectDir, agentCtx) {
3514
3577
  const parts = [];
@@ -3561,7 +3624,7 @@ function processContentBlock(block, responseParts, turnToolCalls) {
3561
3624
  input: inputStr.slice(0, 1e4),
3562
3625
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
3563
3626
  });
3564
- console.log(`[project-chat] [tool_use] ${block.name}`);
3627
+ logger3.debug("Tool use", { tool: block.name });
3565
3628
  }
3566
3629
  }
3567
3630
  async function fetchContext(connection) {
@@ -3569,13 +3632,13 @@ async function fetchContext(connection) {
3569
3632
  try {
3570
3633
  agentCtx = await connection.fetchAgentContext();
3571
3634
  } catch {
3572
- console.log("[project-chat] Could not fetch agent context, using defaults");
3635
+ logger3.warn("Could not fetch agent context, using defaults");
3573
3636
  }
3574
3637
  let chatHistory = [];
3575
3638
  try {
3576
3639
  chatHistory = await connection.fetchChatHistory(30);
3577
3640
  } catch {
3578
- console.log("[project-chat] Could not fetch chat history, proceeding without it");
3641
+ logger3.warn("Could not fetch chat history, proceeding without it");
3579
3642
  }
3580
3643
  return { agentCtx, chatHistory };
3581
3644
  }
@@ -3649,10 +3712,7 @@ async function handleProjectChatMessage(message, connection, projectDir) {
3649
3712
  try {
3650
3713
  await runChatQuery(message, connection, projectDir);
3651
3714
  } catch (error) {
3652
- console.error(
3653
- "[project-chat] Failed to handle message:",
3654
- error instanceof Error ? error.message : error
3655
- );
3715
+ logger3.error("Failed to handle message", errorMeta(error));
3656
3716
  try {
3657
3717
  await connection.emitChatMessage(
3658
3718
  "I encountered an error processing your message. Please try again."
@@ -3665,6 +3725,7 @@ async function handleProjectChatMessage(message, connection, projectDir) {
3665
3725
  }
3666
3726
 
3667
3727
  // src/runner/project-runner.ts
3728
+ var logger4 = createServiceLogger("ProjectRunner");
3668
3729
  var __filename = fileURLToPath(import.meta.url);
3669
3730
  var __dirname = path.dirname(__filename);
3670
3731
  var HEARTBEAT_INTERVAL_MS2 = 3e4;
@@ -3687,7 +3748,7 @@ function setupWorkDir(projectDir, assignment) {
3687
3748
  try {
3688
3749
  execSync5(`git checkout -b ${branch}`, { cwd: workDir, stdio: "ignore" });
3689
3750
  } catch {
3690
- console.log(`[task:${shortId}] Warning: could not checkout branch ${branch}`);
3751
+ logger4.warn("Could not checkout branch", { taskId: shortId, branch });
3691
3752
  }
3692
3753
  }
3693
3754
  }
@@ -3725,13 +3786,13 @@ function spawnChildAgent(assignment, workDir) {
3725
3786
  child.stdout?.on("data", (data) => {
3726
3787
  const lines = data.toString().trimEnd().split("\n");
3727
3788
  for (const line of lines) {
3728
- console.log(`[task:${shortId}] ${line}`);
3789
+ logger4.info(line, { taskId: shortId });
3729
3790
  }
3730
3791
  });
3731
3792
  child.stderr?.on("data", (data) => {
3732
3793
  const lines = data.toString().trimEnd().split("\n");
3733
3794
  for (const line of lines) {
3734
- console.error(`[task:${shortId}] ${line}`);
3795
+ logger4.error(line, { taskId: shortId });
3735
3796
  }
3736
3797
  });
3737
3798
  return child;
@@ -3751,7 +3812,22 @@ var ProjectRunner = class {
3751
3812
  projectId: config.projectId
3752
3813
  });
3753
3814
  }
3815
+ async checkoutWorkspaceBranch() {
3816
+ const workspaceBranch = process.env.CONVEYOR_WORKSPACE_BRANCH;
3817
+ if (!workspaceBranch) return;
3818
+ try {
3819
+ execSync5(`git fetch origin ${workspaceBranch}`, { cwd: this.projectDir, stdio: "pipe" });
3820
+ execSync5(`git checkout ${workspaceBranch}`, { cwd: this.projectDir, stdio: "pipe" });
3821
+ logger4.info("Checked out workspace branch", { workspaceBranch });
3822
+ } catch (err) {
3823
+ logger4.warn("Failed to checkout workspace branch, continuing on current branch", {
3824
+ workspaceBranch,
3825
+ ...errorMeta(err)
3826
+ });
3827
+ }
3828
+ }
3754
3829
  async start() {
3830
+ await this.checkoutWorkspaceBranch();
3755
3831
  await this.connection.connect();
3756
3832
  this.connection.onTaskAssignment((assignment) => {
3757
3833
  this.handleAssignment(assignment);
@@ -3760,17 +3836,17 @@ var ProjectRunner = class {
3760
3836
  this.handleStopTask(data.taskId);
3761
3837
  });
3762
3838
  this.connection.onShutdown(() => {
3763
- console.log("[project-runner] Received shutdown signal from server");
3839
+ logger4.info("Received shutdown signal from server");
3764
3840
  void this.stop();
3765
3841
  });
3766
3842
  this.connection.onChatMessage((msg) => {
3767
- console.log("[project-runner] Received project chat message");
3843
+ logger4.debug("Received project chat message");
3768
3844
  void handleProjectChatMessage(msg, this.connection, this.projectDir);
3769
3845
  });
3770
3846
  this.heartbeatTimer = setInterval(() => {
3771
3847
  this.connection.sendHeartbeat();
3772
3848
  }, HEARTBEAT_INTERVAL_MS2);
3773
- console.log("[project-runner] Connected, waiting for task assignments...");
3849
+ logger4.info("Connected, waiting for task assignments");
3774
3850
  await new Promise((resolve2) => {
3775
3851
  this.resolveLifecycle = resolve2;
3776
3852
  process.on("SIGTERM", () => void this.stop());
@@ -3781,13 +3857,14 @@ var ProjectRunner = class {
3781
3857
  const { taskId, mode } = assignment;
3782
3858
  const shortId = taskId.slice(0, 8);
3783
3859
  if (this.activeAgents.has(taskId)) {
3784
- console.log(`[project-runner] Task ${shortId} already running, skipping`);
3860
+ logger4.info("Task already running, skipping", { taskId: shortId });
3785
3861
  return;
3786
3862
  }
3787
3863
  if (this.activeAgents.size >= MAX_CONCURRENT) {
3788
- console.log(
3789
- `[project-runner] Max concurrent agents (${MAX_CONCURRENT}) reached, rejecting task ${shortId}`
3790
- );
3864
+ logger4.warn("Max concurrent agents reached, rejecting task", {
3865
+ maxConcurrent: MAX_CONCURRENT,
3866
+ taskId: shortId
3867
+ });
3791
3868
  this.connection.emitTaskStopped(taskId, "max_concurrent_reached");
3792
3869
  return;
3793
3870
  }
@@ -3795,7 +3872,7 @@ var ProjectRunner = class {
3795
3872
  try {
3796
3873
  execSync5("git fetch origin", { cwd: this.projectDir, stdio: "ignore" });
3797
3874
  } catch {
3798
- console.log(`[task:${shortId}] Warning: git fetch failed`);
3875
+ logger4.warn("Git fetch failed", { taskId: shortId });
3799
3876
  }
3800
3877
  const { workDir, usesWorktree } = setupWorkDir(this.projectDir, assignment);
3801
3878
  const child = spawnChildAgent(assignment, workDir);
@@ -3806,12 +3883,12 @@ var ProjectRunner = class {
3806
3883
  usesWorktree
3807
3884
  });
3808
3885
  this.connection.emitTaskStarted(taskId);
3809
- console.log(`[project-runner] Started task ${shortId} in ${mode} mode at ${workDir}`);
3886
+ logger4.info("Started task", { taskId: shortId, mode, workDir });
3810
3887
  child.on("exit", (code) => {
3811
3888
  this.activeAgents.delete(taskId);
3812
3889
  const reason = code === 0 ? "completed" : `exited with code ${code}`;
3813
3890
  this.connection.emitTaskStopped(taskId, reason);
3814
- console.log(`[project-runner] Task ${shortId} ${reason}`);
3891
+ logger4.info("Task exited", { taskId: shortId, reason });
3815
3892
  if (code === 0 && usesWorktree) {
3816
3893
  try {
3817
3894
  removeWorktree(this.projectDir, taskId);
@@ -3820,10 +3897,10 @@ var ProjectRunner = class {
3820
3897
  }
3821
3898
  });
3822
3899
  } catch (error) {
3823
- console.error(
3824
- `[project-runner] Failed to start task ${shortId}:`,
3825
- error instanceof Error ? error.message : error
3826
- );
3900
+ logger4.error("Failed to start task", {
3901
+ taskId: shortId,
3902
+ ...errorMeta(error)
3903
+ });
3827
3904
  this.connection.emitTaskStopped(
3828
3905
  taskId,
3829
3906
  `start_failed: ${error instanceof Error ? error.message : "Unknown"}`
@@ -3834,7 +3911,7 @@ var ProjectRunner = class {
3834
3911
  const agent = this.activeAgents.get(taskId);
3835
3912
  if (!agent) return;
3836
3913
  const shortId = taskId.slice(0, 8);
3837
- console.log(`[project-runner] Stopping task ${shortId}`);
3914
+ logger4.info("Stopping task", { taskId: shortId });
3838
3915
  agent.process.kill("SIGTERM");
3839
3916
  const timer = setTimeout(() => {
3840
3917
  if (this.activeAgents.has(taskId)) {
@@ -3854,7 +3931,7 @@ var ProjectRunner = class {
3854
3931
  async stop() {
3855
3932
  if (this.stopping) return;
3856
3933
  this.stopping = true;
3857
- console.log("[project-runner] Shutting down...");
3934
+ logger4.info("Shutting down");
3858
3935
  if (this.heartbeatTimer) {
3859
3936
  clearInterval(this.heartbeatTimer);
3860
3937
  this.heartbeatTimer = null;
@@ -3879,7 +3956,7 @@ var ProjectRunner = class {
3879
3956
  })
3880
3957
  ]);
3881
3958
  this.connection.disconnect();
3882
- console.log("[project-runner] Shutdown complete");
3959
+ logger4.info("Shutdown complete");
3883
3960
  if (this.resolveLifecycle) {
3884
3961
  this.resolveLifecycle();
3885
3962
  this.resolveLifecycle = null;
@@ -3959,8 +4036,10 @@ export {
3959
4036
  loadConveyorConfig,
3960
4037
  runSetupCommand,
3961
4038
  runStartCommand,
4039
+ createServiceLogger,
4040
+ errorMeta,
3962
4041
  AgentRunner,
3963
4042
  ProjectRunner,
3964
4043
  FileCache
3965
4044
  };
3966
- //# sourceMappingURL=chunk-VJRAWAWQ.js.map
4045
+ //# sourceMappingURL=chunk-JI4AW4WX.js.map