@rallycry/conveyor-agent 7.0.2 → 7.0.3

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.
@@ -141,25 +141,7 @@ var AgentConnection = class {
141
141
  });
142
142
  this.socket.io.on("reconnect", () => {
143
143
  process.stderr.write("[conveyor-agent] Reconnected\n");
144
- this.call("connectAgent", { sessionId: this.config.sessionId }).then(({ pendingMessages }) => {
145
- for (const msg of pendingMessages) {
146
- if (msg.content) {
147
- if (this.messageCallback) {
148
- this.messageCallback({ content: msg.content, userId: msg.userId });
149
- } else {
150
- this.earlyMessages.push({ content: msg.content, userId: msg.userId });
151
- }
152
- }
153
- }
154
- }).catch(() => {
155
- });
156
- if (this.lastEmittedStatus) {
157
- void this.call("reportAgentStatus", {
158
- sessionId: this.config.sessionId,
159
- status: this.lastEmittedStatus
160
- }).catch(() => {
161
- });
162
- }
144
+ void this.reconnectToSession();
163
145
  });
164
146
  this.socket.io.on("reconnect_attempt", () => {
165
147
  });
@@ -174,6 +156,53 @@ var AgentConnection = class {
174
156
  this.socket = null;
175
157
  }
176
158
  }
159
+ // ── Reconnect with retry ────────────────────────────────────────────
160
+ async reconnectToSession() {
161
+ const maxRetries = 5;
162
+ const baseDelayMs = 2e3;
163
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
164
+ try {
165
+ const { pendingMessages } = await this.call("connectAgent", {
166
+ sessionId: this.config.sessionId
167
+ });
168
+ this.drainPendingMessages(pendingMessages);
169
+ process.stderr.write("[conveyor-agent] Reconnected to session successfully\n");
170
+ if (this.lastEmittedStatus) {
171
+ void this.call("reportAgentStatus", {
172
+ sessionId: this.config.sessionId,
173
+ status: this.lastEmittedStatus
174
+ }).catch(() => {
175
+ });
176
+ }
177
+ return;
178
+ } catch (err) {
179
+ const errMsg = err instanceof Error ? err.message : String(err);
180
+ const delayMs = baseDelayMs * 2 ** (attempt - 1);
181
+ process.stderr.write(
182
+ `[conveyor-agent] connectAgent failed (attempt ${attempt}/${maxRetries}): ${errMsg} \u2014 retrying in ${delayMs / 1e3}s
183
+ `
184
+ );
185
+ await new Promise((resolve2) => {
186
+ setTimeout(resolve2, delayMs);
187
+ });
188
+ }
189
+ }
190
+ process.stderr.write(
191
+ `[conveyor-agent] Failed to reconnect to session after ${maxRetries} attempts, exiting
192
+ `
193
+ );
194
+ process.exit(1);
195
+ }
196
+ drainPendingMessages(messages) {
197
+ for (const msg of messages) {
198
+ if (!msg.content) continue;
199
+ if (this.messageCallback) {
200
+ this.messageCallback({ content: msg.content, userId: msg.userId });
201
+ } else {
202
+ this.earlyMessages.push({ content: msg.content, userId: msg.userId });
203
+ }
204
+ }
205
+ }
177
206
  // ── Callback registration with early-buffer draining ───────────────
178
207
  onMessage(callback) {
179
208
  this.messageCallback = callback;
@@ -2305,6 +2334,7 @@ Co-Authored-By: Claude Sonnet 4 <noreply@anthropic.com>`;
2305
2334
  }
2306
2335
  }
2307
2336
  const result = await connection.call("createPullRequest", {
2337
+ sessionId: connection.sessionId,
2308
2338
  title,
2309
2339
  body,
2310
2340
  head: branch,
@@ -4657,6 +4687,9 @@ function handleAutoToolAccess(toolName, input, hasExitedPlanMode, isParentTask)
4657
4687
  return { behavior: "allow", updatedInput: input };
4658
4688
  }
4659
4689
  async function handleExitPlanMode(host, input) {
4690
+ if (host.hasExitedPlanMode) {
4691
+ return { behavior: "allow", updatedInput: input };
4692
+ }
4660
4693
  try {
4661
4694
  host.syncPlanFile();
4662
4695
  const taskProps = await host.connection.getTaskProperties();
@@ -5223,6 +5256,8 @@ var QueryBridge = class {
5223
5256
  const msg = err instanceof Error ? err.message : String(err);
5224
5257
  logger2.error("Query execution failed", { error: msg });
5225
5258
  this.connection.sendEvent({ type: "error", message: msg });
5259
+ } finally {
5260
+ this.mode.pendingModeRestart = false;
5226
5261
  }
5227
5262
  }
5228
5263
  // ── QueryHost construction ──────────────────────────────────────────
@@ -5431,6 +5466,7 @@ var SessionRunner = class _SessionRunner {
5431
5466
  if (!this.stopped && this.pendingMessages.length === 0) {
5432
5467
  await this.maybeSendPRNudge();
5433
5468
  }
5469
+ this.hasCompleted = true;
5434
5470
  if (!this.stopped) await this.setState("idle");
5435
5471
  } else if (this._state === "error") {
5436
5472
  await this.setState("idle");
@@ -6624,7 +6660,7 @@ var ProjectRunner = class {
6624
6660
  }
6625
6661
  // ── Event wiring ───────────────────────────────────────────────────────
6626
6662
  wireEventHandlers() {
6627
- this.connection.onTaskAssignment((assignment) => this.handleAssignment(assignment));
6663
+ this.connection.onTaskAssignment((assignment) => void this.handleAssignment(assignment));
6628
6664
  this.connection.onStopTask((data) => this.handleStopTask(data.taskId));
6629
6665
  this.connection.onShutdown(() => void this.stop());
6630
6666
  this.connection.onChatMessage((msg) => {
@@ -6682,13 +6718,42 @@ var ProjectRunner = class {
6682
6718
  }
6683
6719
  }
6684
6720
  // ── Task management ────────────────────────────────────────────────────
6685
- handleAssignment(assignment) {
6721
+ async killAgent(agent, taskId) {
6722
+ const shortId = taskId.slice(0, 8);
6723
+ if (agent.process.exitCode !== null) {
6724
+ logger6.info("Agent process already exited", { taskId: shortId });
6725
+ return;
6726
+ }
6727
+ logger6.info("Killing agent process", { taskId: shortId });
6728
+ agent.process.kill("SIGTERM");
6729
+ await new Promise((resolve2) => {
6730
+ const timer = setTimeout(() => {
6731
+ if (agent.process.exitCode === null) {
6732
+ logger6.warn("Agent did not exit after SIGTERM, sending SIGKILL", { taskId: shortId });
6733
+ agent.process.kill("SIGKILL");
6734
+ }
6735
+ resolve2();
6736
+ }, STOP_TIMEOUT_MS);
6737
+ agent.process.on("exit", () => {
6738
+ clearTimeout(timer);
6739
+ resolve2();
6740
+ });
6741
+ });
6742
+ }
6743
+ // oxlint-disable-next-line max-lines-per-function -- re-assignment logic requires sequential checks
6744
+ async handleAssignment(assignment) {
6686
6745
  const { taskId, mode } = assignment;
6687
6746
  const shortId = taskId.slice(0, 8);
6688
6747
  const agentKey = assignment.agentMode === "code-review" ? `${taskId}:code-review` : taskId;
6689
- if (this.activeAgents.has(agentKey)) {
6690
- logger6.info("Task already running, skipping", { taskId: shortId });
6691
- return;
6748
+ const existing = this.activeAgents.get(agentKey);
6749
+ if (existing) {
6750
+ if (existing.process.exitCode === null) {
6751
+ logger6.info("Re-assignment received, killing existing agent", { taskId: shortId });
6752
+ await this.killAgent(existing, taskId);
6753
+ } else {
6754
+ logger6.info("Stale agent entry (process already exited), cleaning up", { taskId: shortId });
6755
+ }
6756
+ this.activeAgents.delete(agentKey);
6692
6757
  }
6693
6758
  if (this.activeAgents.size >= MAX_CONCURRENT) {
6694
6759
  logger6.warn("Max concurrent agents reached", { maxConcurrent: MAX_CONCURRENT });
@@ -6730,16 +6795,11 @@ var ProjectRunner = class {
6730
6795
  }
6731
6796
  }
6732
6797
  handleStopTask(taskId) {
6733
- let agent = this.activeAgents.get(taskId);
6734
- if (!agent) agent = this.activeAgents.get(`${taskId}:code-review`);
6798
+ const agentKey = this.activeAgents.has(taskId) ? taskId : `${taskId}:code-review`;
6799
+ const agent = this.activeAgents.get(agentKey);
6735
6800
  if (!agent) return;
6736
6801
  logger6.info("Stopping task", { taskId: taskId.slice(0, 8) });
6737
- agent.process.kill("SIGTERM");
6738
- const timer = setTimeout(() => {
6739
- if (this.activeAgents.has(taskId)) agent.process.kill("SIGKILL");
6740
- }, STOP_TIMEOUT_MS);
6741
- agent.process.on("exit", () => {
6742
- clearTimeout(timer);
6802
+ void this.killAgent(agent, taskId).then(() => {
6743
6803
  if (agent.usesWorktree) {
6744
6804
  try {
6745
6805
  removeWorktree(this.projectDir, taskId);
@@ -7027,4 +7087,4 @@ export {
7027
7087
  removeWorktree,
7028
7088
  ProjectRunner
7029
7089
  };
7030
- //# sourceMappingURL=chunk-NZ3IPMLO.js.map
7090
+ //# sourceMappingURL=chunk-L7ZH423N.js.map