@rallycry/conveyor-agent 4.5.0 → 4.6.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.
@@ -103,9 +103,11 @@ var ConveyorConnection = class _ConveyorConnection {
103
103
  static EVENT_BATCH_MS = 500;
104
104
  earlyMessages = [];
105
105
  earlyStop = false;
106
+ earlySoftStop = false;
106
107
  earlyModeChanges = [];
107
108
  chatMessageCallback = null;
108
109
  stopCallback = null;
110
+ softStopCallback = null;
109
111
  modeChangeCallback = null;
110
112
  runStartCommandCallback = null;
111
113
  pendingQuestionResolvers = /* @__PURE__ */ new Map();
@@ -135,6 +137,10 @@ var ConveyorConnection = class _ConveyorConnection {
135
137
  if (this.stopCallback) this.stopCallback();
136
138
  else this.earlyStop = true;
137
139
  });
140
+ this.socket.on("agentRunner:softStop", () => {
141
+ if (this.softStopCallback) this.softStopCallback();
142
+ else this.earlySoftStop = true;
143
+ });
138
144
  this.socket.on("agentRunner:questionAnswer", (data) => {
139
145
  const resolver = this.pendingQuestionResolvers.get(data.requestId);
140
146
  if (resolver) {
@@ -233,6 +239,13 @@ var ConveyorConnection = class _ConveyorConnection {
233
239
  this.earlyStop = false;
234
240
  }
235
241
  }
242
+ onSoftStopRequested(callback) {
243
+ this.softStopCallback = callback;
244
+ if (this.earlySoftStop) {
245
+ callback();
246
+ this.earlySoftStop = false;
247
+ }
248
+ }
236
249
  onModeChange(callback) {
237
250
  this.modeChangeCallback = callback;
238
251
  for (const data of this.earlyModeChanges) callback(data);
@@ -538,14 +551,6 @@ async function loadConveyorConfig(workspaceDir) {
538
551
  if (parsed.setupCommand || parsed.startCommand) return parsed;
539
552
  } catch {
540
553
  }
541
- try {
542
- const raw = await readFile(join2(workspaceDir, DEVCONTAINER_PATH), "utf-8");
543
- const parsed = JSON.parse(raw);
544
- if (parsed.conveyor && (parsed.conveyor.startCommand || parsed.conveyor.setupCommand)) {
545
- return parsed.conveyor;
546
- }
547
- } catch {
548
- }
549
554
  return null;
550
555
  }
551
556
 
@@ -2406,7 +2411,12 @@ async function runSdkQuery(host, context, followUpContent) {
2406
2411
  prompt: typeof prompt === "string" ? prompt : host.createInputStream(prompt),
2407
2412
  options: { ...options, resume }
2408
2413
  });
2409
- await runWithRetry(agentQuery, context, host, options);
2414
+ host.activeQuery = agentQuery;
2415
+ try {
2416
+ await runWithRetry(agentQuery, context, host, options);
2417
+ } finally {
2418
+ host.activeQuery = null;
2419
+ }
2410
2420
  } else if (isDiscoveryLike) {
2411
2421
  return;
2412
2422
  } else {
@@ -2416,7 +2426,12 @@ async function runSdkQuery(host, context, followUpContent) {
2416
2426
  prompt: host.createInputStream(prompt),
2417
2427
  options: { ...options, resume }
2418
2428
  });
2419
- await runWithRetry(agentQuery, context, host, options);
2429
+ host.activeQuery = agentQuery;
2430
+ try {
2431
+ await runWithRetry(agentQuery, context, host, options);
2432
+ } finally {
2433
+ host.activeQuery = null;
2434
+ }
2420
2435
  }
2421
2436
  if (isDiscoveryLike) {
2422
2437
  host.syncPlanFile();
@@ -2702,6 +2717,39 @@ async function runSetupSafe(runnerConfig, connection, callbacks, setupLog, effec
2702
2717
  () => void 0
2703
2718
  );
2704
2719
  }
2720
+ const pullBranch = process.env.CONVEYOR_PULL_BRANCH;
2721
+ if (pullBranch) {
2722
+ pushSetupLog(setupLog, `[conveyor] Merging latest from ${pullBranch}...`);
2723
+ connection.sendEvent({
2724
+ type: "setup_output",
2725
+ stream: "stdout",
2726
+ data: `Merging latest from ${pullBranch}...
2727
+ `
2728
+ });
2729
+ try {
2730
+ await runSetupCommand(
2731
+ `git fetch origin ${pullBranch} && git merge origin/${pullBranch} --no-edit`,
2732
+ runnerConfig.workspaceDir,
2733
+ (stream, data) => {
2734
+ connection.sendEvent({ type: "setup_output", stream, data });
2735
+ for (const line of data.split("\n").filter(Boolean)) {
2736
+ pushSetupLog(setupLog, `[${stream}] ${line}`);
2737
+ }
2738
+ }
2739
+ );
2740
+ pushSetupLog(setupLog, `[conveyor] Merge complete`);
2741
+ } catch (error) {
2742
+ const message = `Failed to merge ${pullBranch}: ${error instanceof Error ? error.message : "unknown error"}`;
2743
+ connection.sendEvent({ type: "setup_error", message });
2744
+ await callbacks.onEvent({ type: "setup_error", message });
2745
+ connection.postChatMessage(
2746
+ `Failed to merge latest code from \`${pullBranch}\`. There may be conflicts between the prebuild branch and dev.
2747
+
2748
+ ${message}`
2749
+ );
2750
+ return { ok: false, deferredStartConfig: null };
2751
+ }
2752
+ }
2705
2753
  const config = await loadConveyorConfig(runnerConfig.workspaceDir);
2706
2754
  if (!config) {
2707
2755
  connection.sendEvent({ type: "setup_complete" });
@@ -2850,6 +2898,7 @@ function buildQueryHost(deps) {
2850
2898
  deps.setPendingModeRestart(val);
2851
2899
  },
2852
2900
  sessionIds: deps.sessionIds,
2901
+ activeQuery: null,
2853
2902
  isStopped: deps.isStopped,
2854
2903
  createInputStream: deps.createInputStream,
2855
2904
  snapshotPlanFiles: () => deps.planSync.snapshotPlanFiles(),
@@ -2867,6 +2916,7 @@ var AgentRunner = class {
2867
2916
  callbacks;
2868
2917
  _state = "connecting";
2869
2918
  stopped = false;
2919
+ interrupted = false;
2870
2920
  inputResolver = null;
2871
2921
  pendingMessages = [];
2872
2922
  setupLog = [];
@@ -2884,6 +2934,7 @@ var AgentRunner = class {
2884
2934
  idleTimer = null;
2885
2935
  idleCheckInterval = null;
2886
2936
  deferredStartConfig = null;
2937
+ _queryHost = null;
2887
2938
  constructor(config, callbacks) {
2888
2939
  this.config = config;
2889
2940
  this.connection = new ConveyorConnection(config);
@@ -2930,6 +2981,7 @@ var AgentRunner = class {
2930
2981
  await this.setState("connecting");
2931
2982
  await this.connection.connect();
2932
2983
  this.connection.onStopRequested(() => this.stop());
2984
+ this.connection.onSoftStopRequested(() => this.softStop());
2933
2985
  this.connection.onChatMessage(
2934
2986
  (message) => this.injectHumanMessage(message.content, message.files)
2935
2987
  );
@@ -3072,9 +3124,17 @@ var AgentRunner = class {
3072
3124
  }
3073
3125
  if (this._state === "idle") {
3074
3126
  const msg = await this.waitForUserContent();
3075
- if (!msg) break;
3127
+ if (!msg) {
3128
+ if (this.interrupted && !this.stopped) {
3129
+ this.interrupted = false;
3130
+ continue;
3131
+ }
3132
+ break;
3133
+ }
3076
3134
  await this.setState("running");
3135
+ this.interrupted = false;
3077
3136
  await this.runQuerySafe(this.taskContext, msg);
3137
+ if (this.interrupted) this.interrupted = false;
3078
3138
  if (!this.stopped && this._state !== "error") await this.setState("idle");
3079
3139
  } else if (this._state === "error") {
3080
3140
  await this.setState("idle");
@@ -3127,7 +3187,7 @@ var AgentRunner = class {
3127
3187
  this.clearIdleTimers();
3128
3188
  return new Promise((resolve2) => {
3129
3189
  this.idleCheckInterval = setInterval(() => {
3130
- if (this.stopped) {
3190
+ if (this.stopped || this.interrupted) {
3131
3191
  this.clearIdleTimers();
3132
3192
  this.inputResolver = null;
3133
3193
  resolve2(null);
@@ -3167,7 +3227,7 @@ var AgentRunner = class {
3167
3227
  });
3168
3228
  yield makeUserMessage(initialPrompt);
3169
3229
  try {
3170
- while (!this.stopped) {
3230
+ while (!this.stopped && !this.interrupted) {
3171
3231
  if (this.pendingMessages.length > 0) {
3172
3232
  const next = this.pendingMessages.shift();
3173
3233
  if (next) yield next;
@@ -3186,7 +3246,7 @@ var AgentRunner = class {
3186
3246
  }
3187
3247
  }
3188
3248
  asQueryHost() {
3189
- return buildQueryHost({
3249
+ const host = buildQueryHost({
3190
3250
  config: this.config,
3191
3251
  connection: this.connection,
3192
3252
  callbacks: this.callbacks,
@@ -3204,12 +3264,14 @@ var AgentRunner = class {
3204
3264
  setPendingModeRestart: (val) => {
3205
3265
  this.pendingModeRestart = val;
3206
3266
  },
3207
- isStopped: () => this.stopped,
3267
+ isStopped: () => this.stopped || this.interrupted,
3208
3268
  createInputStream: (prompt) => this.createInputStream(prompt),
3209
3269
  onModeTransition: (newMode) => {
3210
3270
  this.agentMode = newMode;
3211
3271
  }
3212
3272
  });
3273
+ this._queryHost = host;
3274
+ return host;
3213
3275
  }
3214
3276
  handleModeChange(newAgentMode) {
3215
3277
  if (this.config.mode !== "pm") return;
@@ -3224,6 +3286,21 @@ var AgentRunner = class {
3224
3286
  this.taskContext.status = "InProgress";
3225
3287
  }
3226
3288
  }
3289
+ softStop() {
3290
+ this.interrupted = true;
3291
+ const host = this._queryHost;
3292
+ if (host?.activeQuery) {
3293
+ const q = host.activeQuery;
3294
+ if (typeof q.interrupt === "function") {
3295
+ void q.interrupt();
3296
+ }
3297
+ host.activeQuery = null;
3298
+ }
3299
+ if (this.inputResolver) {
3300
+ this.inputResolver(null);
3301
+ this.inputResolver = null;
3302
+ }
3303
+ }
3227
3304
  stop() {
3228
3305
  this.stopped = true;
3229
3306
  this.clearIdleTimers();
@@ -3696,4 +3773,4 @@ export {
3696
3773
  ProjectRunner,
3697
3774
  FileCache
3698
3775
  };
3699
- //# sourceMappingURL=chunk-7Y3RP3ZA.js.map
3776
+ //# sourceMappingURL=chunk-XG5DMOJX.js.map