@rallycry/conveyor-agent 7.0.11 → 7.1.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.
@@ -9,12 +9,15 @@ import {
9
9
  // src/connection/agent-connection.ts
10
10
  import { io } from "socket.io-client";
11
11
  var EVENT_BATCH_MS = 500;
12
+ var MAX_EVENT_BUFFER = 5e3;
12
13
  var AgentConnection = class _AgentConnection {
13
14
  socket = null;
14
15
  config;
15
16
  eventBuffer = [];
16
17
  flushTimer = null;
17
18
  lastEmittedStatus = null;
19
+ lastReportedStatus = null;
20
+ droppedEventCount = 0;
18
21
  // Pending answer resolvers for askUserQuestion room-event fallback
19
22
  pendingAnswerResolvers = /* @__PURE__ */ new Map();
20
23
  // Dedup: suppress near-identical messages within a short window
@@ -186,10 +189,13 @@ var AgentConnection = class _AgentConnection {
186
189
  });
187
190
  this.drainPendingMessages(pendingMessages);
188
191
  process.stderr.write("[conveyor-agent] Reconnected to session successfully\n");
189
- if (this.lastEmittedStatus) {
192
+ if (this.lastEmittedStatus && this.lastEmittedStatus !== this.lastReportedStatus) {
193
+ const status = this.lastEmittedStatus;
190
194
  void this.call("reportAgentStatus", {
191
195
  sessionId: this.config.sessionId,
192
- status: this.lastEmittedStatus
196
+ status
197
+ }).then(() => {
198
+ this.lastReportedStatus = status;
193
199
  }).catch(() => {
194
200
  });
195
201
  }
@@ -260,6 +266,8 @@ var AgentConnection = class _AgentConnection {
260
266
  void this.call("reportAgentStatus", {
261
267
  sessionId: this.config.sessionId,
262
268
  status
269
+ }).then(() => {
270
+ this.lastReportedStatus = status;
263
271
  }).catch(() => {
264
272
  });
265
273
  }
@@ -401,12 +409,13 @@ ${q.question}${q.options.length ? "\n" + q.options.map((o) => `- ${o.label}: ${o
401
409
  triggerIdentification() {
402
410
  return this.call("triggerIdentification", { sessionId: this.config.sessionId });
403
411
  }
404
- requestScaleUp(tier, reason) {
405
- return this.call("scaleUpResources", {
412
+ async requestScaleUp(tier, reason) {
413
+ const r = await this.call("scaleUpResources", {
406
414
  sessionId: this.config.sessionId,
407
415
  tier,
408
416
  reason
409
- }).then((r) => ({ scaled: r.success }));
417
+ });
418
+ return { scaled: r.success };
410
419
  }
411
420
  async refreshAuthToken() {
412
421
  const codespaceName = process.env.CODESPACE_NAME || process.env.CLAUDESPACE_NAME;
@@ -428,6 +437,16 @@ ${q.question}${q.options.length ? "\n" + q.options.map((o) => `- ${o.label}: ${o
428
437
  // ── Event buffering ────────────────────────────────────────────────
429
438
  sendEvent(event) {
430
439
  if (!this.socket) return;
440
+ if (this.eventBuffer.length >= MAX_EVENT_BUFFER) {
441
+ this.eventBuffer.shift();
442
+ this.droppedEventCount++;
443
+ if (this.droppedEventCount === 1 || this.droppedEventCount % 500 === 0) {
444
+ process.stderr.write(
445
+ `[conveyor-agent] eventBuffer overflow \u2014 dropped ${this.droppedEventCount} event(s) (cap: ${MAX_EVENT_BUFFER})
446
+ `
447
+ );
448
+ }
449
+ }
431
450
  this.eventBuffer.push({ event });
432
451
  if (!this.flushTimer) {
433
452
  this.flushTimer = setTimeout(() => void this.flushEvents(), EVENT_BATCH_MS);
@@ -993,6 +1012,10 @@ var ReportAgentStatusRequestSchema = z.object({
993
1012
  sessionId: z.string(),
994
1013
  status: z.string()
995
1014
  });
1015
+ var NotifyAgentVersionRequestSchema = z.object({
1016
+ sessionId: z.string(),
1017
+ agentVersion: z.string()
1018
+ });
996
1019
  var CreateSubtaskRequestSchema = z.object({
997
1020
  sessionId: z.string(),
998
1021
  title: z.string().min(1),
@@ -1794,8 +1817,8 @@ function buildAutoPrompt(context) {
1794
1817
  `### Transitioning to Building:`,
1795
1818
  `When your plan is complete and all required properties are set, call the **ExitPlanMode** tool.`,
1796
1819
  `- If any required properties are missing, ExitPlanMode will be denied with details on what's missing`,
1797
- `- Once ExitPlanMode succeeds, the system will automatically restart your session in Building mode with the appropriate model`,
1798
- `- You do NOT need to do anything after calling ExitPlanMode \u2014 the transition is handled for you`,
1820
+ `- Once ExitPlanMode succeeds, you will seamlessly transition to full build access within the same session`,
1821
+ `- Continue directly with implementation \u2014 no restart or waiting is needed`,
1799
1822
  ``,
1800
1823
  `### Subtask Plan Requirements`,
1801
1824
  `When creating subtasks, each MUST include a detailed \`plan\` field:`,
@@ -3199,9 +3222,9 @@ function buildVoteSuggestionTool(connection) {
3199
3222
  function buildScaleUpResourcesTool(connection) {
3200
3223
  return defineTool(
3201
3224
  "scale_up_resources",
3202
- "Scale up the pod's CPU and memory resources. Use before running dev servers, tests, builds, or other resource-intensive operations. Phases: 'setup' (installs, basic dev servers), 'build' (full dev servers, test suites, typecheck, builds). Actual CPU/memory values are configured per-project. Scaling is one-way (up only).",
3225
+ "Scale up the pod's CPU and memory resources to the 'build' tier. Use before running heavy operations like full test suites, integration tests, typechecks, or production builds. Pods start at the 'setup' tier by default \u2014 only call this when you actually need more. Scaling is one-way (up only).",
3203
3226
  {
3204
- tier: z2.enum(["initial", "setup", "build"]).describe("The resource phase to scale up to"),
3227
+ tier: z2.literal("build").describe("The resource phase to scale up to"),
3205
3228
  reason: z2.string().optional().describe("Brief reason for scaling (e.g., 'running test suite')")
3206
3229
  },
3207
3230
  async ({ tier, reason }) => {
@@ -5404,16 +5427,13 @@ async function handleExitPlanMode(host, input) {
5404
5427
  host.connection.postChatMessage(
5405
5428
  "Plan complete. Running identification \u2014 icon and agent assignment will be set automatically."
5406
5429
  );
5407
- host.requestSoftStop();
5408
5430
  return { behavior: "allow", updatedInput: input };
5409
5431
  }
5410
5432
  await host.connection.triggerIdentification();
5411
5433
  host.hasExitedPlanMode = true;
5412
5434
  const newMode = host.isParentTask ? "review" : "building";
5413
- host.pendingModeRestart = true;
5414
- if (host.onModeTransition) {
5415
- host.onModeTransition(newMode);
5416
- }
5435
+ host.connection.sendEvent({ type: "mode_transition", from: "auto", to: newMode });
5436
+ host.connection.emitModeChanged(newMode);
5417
5437
  return { behavior: "allow", updatedInput: input };
5418
5438
  } catch (err) {
5419
5439
  return {
@@ -6055,7 +6075,10 @@ var QueryBridge = class {
6055
6075
  }
6056
6076
  };
6057
6077
 
6058
- // src/runner/session-runner.ts
6078
+ // src/runner/session-runner-helpers.ts
6079
+ import { readFileSync as readFileSync2 } from "fs";
6080
+ import { dirname, join as join2 } from "path";
6081
+ import { fileURLToPath } from "url";
6059
6082
  function mapChatHistory(messages) {
6060
6083
  if (!messages) return [];
6061
6084
  return messages.map((m) => ({
@@ -6077,6 +6100,22 @@ function mapChatHistory(messages) {
6077
6100
  } : {}
6078
6101
  }));
6079
6102
  }
6103
+ function readAgentVersion() {
6104
+ try {
6105
+ const here = dirname(fileURLToPath(import.meta.url));
6106
+ for (const rel of ["../package.json", "../../package.json"]) {
6107
+ try {
6108
+ const pkg = JSON.parse(readFileSync2(join2(here, rel), "utf-8"));
6109
+ if (pkg.version) return pkg.version;
6110
+ } catch {
6111
+ }
6112
+ }
6113
+ } catch {
6114
+ }
6115
+ return null;
6116
+ }
6117
+
6118
+ // src/runner/session-runner.ts
6080
6119
  var SessionRunner = class _SessionRunner {
6081
6120
  connection;
6082
6121
  mode;
@@ -6154,6 +6193,11 @@ var SessionRunner = class _SessionRunner {
6154
6193
  this.pendingMessages.push({ content: msg.content, userId: msg.userId });
6155
6194
  }
6156
6195
  }
6196
+ const agentVersion = readAgentVersion();
6197
+ if (agentVersion) {
6198
+ this.connection.call("notifyAgentVersion", { sessionId: this.sessionId, agentVersion }).catch(() => {
6199
+ });
6200
+ }
6157
6201
  }
6158
6202
  /**
6159
6203
  * Run the main agent lifecycle: fetch context, resolve mode, execute, loop.
@@ -6193,8 +6237,8 @@ var SessionRunner = class _SessionRunner {
6193
6237
  this.queryBridge = this.createQueryBridge();
6194
6238
  this.logInitialization();
6195
6239
  const staleMessageCount = this.pendingMessages.length;
6196
- await this.executeInitialMode();
6197
- if (staleMessageCount > 0) {
6240
+ const didExecuteInitialQuery = await this.executeInitialMode();
6241
+ if (staleMessageCount > 0 && didExecuteInitialQuery) {
6198
6242
  this.pendingMessages.splice(0, staleMessageCount);
6199
6243
  }
6200
6244
  if (!this.stopped && this._state !== "error") {
@@ -6289,15 +6333,16 @@ var SessionRunner = class _SessionRunner {
6289
6333
  }
6290
6334
  }
6291
6335
  // ── Initial mode execution ─────────────────────────────────────────
6336
+ /** Returns true if an initial query was executed, false otherwise. */
6292
6337
  async executeInitialMode() {
6293
- if (!this.taskContext || !this.fullContext) return;
6338
+ if (!this.taskContext || !this.fullContext) return false;
6294
6339
  const effectiveMode = this.mode.effectiveMode;
6295
6340
  if (effectiveMode === "code-review") {
6296
6341
  await this.setState("running");
6297
6342
  await this.callbacks.onEvent({ type: "execute_mode", mode: effectiveMode });
6298
6343
  await this.executeQuery();
6299
6344
  this.stopped = true;
6300
- return;
6345
+ return true;
6301
6346
  }
6302
6347
  const shouldRun = effectiveMode === "building" || effectiveMode === "auto" || effectiveMode === "review" && this.mode.isPackRunner(this.taskContext);
6303
6348
  if (shouldRun) {
@@ -6305,9 +6350,10 @@ var SessionRunner = class _SessionRunner {
6305
6350
  await this.callbacks.onEvent({ type: "execute_mode", mode: effectiveMode });
6306
6351
  await this.executeQuery();
6307
6352
  if (!this.stopped) await this.setState("idle");
6308
- } else {
6309
- await this.setState("idle");
6353
+ return true;
6310
6354
  }
6355
+ await this.setState("idle");
6356
+ return false;
6311
6357
  }
6312
6358
  // ── Message waiting ────────────────────────────────────────────────
6313
6359
  waitForMessage() {
@@ -6884,13 +6930,13 @@ var CommitWatcher = class {
6884
6930
  // src/runner/worktree.ts
6885
6931
  import { execSync as execSync4 } from "child_process";
6886
6932
  import { existsSync } from "fs";
6887
- import { join as join2 } from "path";
6933
+ import { join as join3 } from "path";
6888
6934
  var WORKTREE_DIR = ".worktrees";
6889
6935
  function ensureWorktree(projectDir, taskId, branch) {
6890
6936
  if (projectDir.includes(`/${WORKTREE_DIR}/`)) {
6891
6937
  return projectDir;
6892
6938
  }
6893
- const worktreePath = join2(projectDir, WORKTREE_DIR, taskId);
6939
+ const worktreePath = join3(projectDir, WORKTREE_DIR, taskId);
6894
6940
  if (existsSync(worktreePath)) {
6895
6941
  if (branch) {
6896
6942
  if (hasUncommittedChanges(worktreePath)) {
@@ -6936,7 +6982,7 @@ function detachWorktreeBranch(projectDir, branch) {
6936
6982
  }
6937
6983
  }
6938
6984
  function removeWorktree(projectDir, taskId) {
6939
- const worktreePath = join2(projectDir, WORKTREE_DIR, taskId);
6985
+ const worktreePath = join3(projectDir, WORKTREE_DIR, taskId);
6940
6986
  if (!existsSync(worktreePath)) return;
6941
6987
  try {
6942
6988
  execSync4(`git worktree remove "${worktreePath}" --force`, {
@@ -6951,7 +6997,7 @@ function removeWorktree(projectDir, taskId) {
6951
6997
  import { fork } from "child_process";
6952
6998
  import { execSync as execSync5 } from "child_process";
6953
6999
  import * as path from "path";
6954
- import { fileURLToPath } from "url";
7000
+ import { fileURLToPath as fileURLToPath2 } from "url";
6955
7001
 
6956
7002
  // src/tools/project-tools.ts
6957
7003
  import { z as z9 } from "zod";
@@ -7303,7 +7349,7 @@ async function handleProjectChatMessage(message, connection, projectDir, session
7303
7349
 
7304
7350
  // src/runner/project-runner.ts
7305
7351
  var logger7 = createServiceLogger("ProjectRunner");
7306
- var __filename = fileURLToPath(import.meta.url);
7352
+ var __filename = fileURLToPath2(import.meta.url);
7307
7353
  var __dirname = path.dirname(__filename);
7308
7354
  var HEARTBEAT_INTERVAL_MS = 3e4;
7309
7355
  var MAX_CONCURRENT = Math.max(1, parseInt(process.env.CONVEYOR_MAX_CONCURRENT ?? "10", 10) || 10);
@@ -7906,11 +7952,11 @@ var ProjectRunner = class {
7906
7952
 
7907
7953
  // src/setup/config.ts
7908
7954
  import { readFile as readFile2 } from "fs/promises";
7909
- import { join as join3 } from "path";
7955
+ import { join as join4 } from "path";
7910
7956
  var DEVCONTAINER_PATH = ".devcontainer/conveyor/devcontainer.json";
7911
7957
  async function loadForwardPorts(workspaceDir) {
7912
7958
  try {
7913
- const raw = await readFile2(join3(workspaceDir, DEVCONTAINER_PATH), "utf-8");
7959
+ const raw = await readFile2(join4(workspaceDir, DEVCONTAINER_PATH), "utf-8");
7914
7960
  const parsed = JSON.parse(raw);
7915
7961
  return parsed.forwardPorts ?? [];
7916
7962
  } catch {
@@ -7957,4 +8003,4 @@ export {
7957
8003
  loadForwardPorts,
7958
8004
  loadConveyorConfig
7959
8005
  };
7960
- //# sourceMappingURL=chunk-OUARAX27.js.map
8006
+ //# sourceMappingURL=chunk-QLY35BX7.js.map