@rallycry/conveyor-agent 10.7.3 → 10.7.4

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.
@@ -1540,52 +1540,6 @@ async function backupOtherBranches(cwd, currentBranch) {
1540
1540
  return count;
1541
1541
  }
1542
1542
 
1543
- // src/setup/git-ready.ts
1544
- import { access, stat } from "fs/promises";
1545
- var DEFAULT_FAILED_PATH = "/workspaces/.conveyor-git-failed";
1546
- var DEFAULT_TIMEOUT_MS = 6e5;
1547
- var DEFAULT_POLL_MS = 200;
1548
- async function fileExists(path4) {
1549
- try {
1550
- await access(path4);
1551
- const s = await stat(path4);
1552
- return s.isFile();
1553
- } catch {
1554
- return false;
1555
- }
1556
- }
1557
- function awaitGitReady(opts = {}) {
1558
- const markerPath = opts.markerPath ?? process.env.CONVEYOR_GIT_READY_MARKER;
1559
- if (!markerPath) {
1560
- return Promise.resolve("not-gated");
1561
- }
1562
- const failedPath = opts.failedPath ?? process.env.CONVEYOR_GIT_FAILED_MARKER ?? DEFAULT_FAILED_PATH;
1563
- const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
1564
- const pollMs = opts.pollMs ?? DEFAULT_POLL_MS;
1565
- opts.onLog?.(`waiting for workspace git (marker=${markerPath})`);
1566
- return pollForMarkers(markerPath, failedPath, timeoutMs, pollMs, opts.onLog);
1567
- }
1568
- async function pollForMarkers(markerPath, failedPath, timeoutMs, pollMs, onLog) {
1569
- const deadline = Date.now() + timeoutMs;
1570
- for (; ; ) {
1571
- if (await fileExists(markerPath)) {
1572
- onLog?.("workspace git ready");
1573
- return "ready";
1574
- }
1575
- if (await fileExists(failedPath)) {
1576
- onLog?.("workspace git preparation failed (marker present)");
1577
- return "failed";
1578
- }
1579
- if (Date.now() >= deadline) {
1580
- onLog?.(`workspace git not ready after ${timeoutMs}ms \u2014 giving up`);
1581
- return "timeout";
1582
- }
1583
- await new Promise((resolve) => {
1584
- setTimeout(resolve, pollMs);
1585
- });
1586
- }
1587
- }
1588
-
1589
1543
  // src/runner/work-preservation/index.ts
1590
1544
  import { rm as rm3 } from "fs/promises";
1591
1545
 
@@ -1599,7 +1553,7 @@ function selectRestoreSource(probe) {
1599
1553
  // src/runner/work-preservation/snapshot-tar.ts
1600
1554
  import { execFile as execFile2 } from "child_process";
1601
1555
  import { createReadStream, createWriteStream } from "fs";
1602
- import { mkdtemp, rm, stat as stat2, writeFile } from "fs/promises";
1556
+ import { mkdtemp, rm, stat, writeFile } from "fs/promises";
1603
1557
  import { tmpdir } from "os";
1604
1558
  import path from "path";
1605
1559
  import { pipeline } from "stream/promises";
@@ -1691,7 +1645,7 @@ async function buildSnapshotTar(cwd) {
1691
1645
  const tarPath = path.join(staging, "snapshot.tar.gz");
1692
1646
  await pipeline(createReadStream(rawTarPath), createGzip(), createWriteStream(tarPath));
1693
1647
  await rm(rawTarPath, { force: true });
1694
- const { size } = await stat2(tarPath);
1648
+ const { size } = await stat(tarPath);
1695
1649
  return {
1696
1650
  tarPath,
1697
1651
  sizeBytes: size,
@@ -4389,7 +4343,7 @@ async function removeConveyorCredentials(env = process.env) {
4389
4343
  }
4390
4344
 
4391
4345
  // src/harness/pty/pty-support.ts
4392
- import { stat as stat3 } from "fs/promises";
4346
+ import { stat as stat2 } from "fs/promises";
4393
4347
  var MAX_DIAGNOSTIC_OUTPUT = 4e3;
4394
4348
  var MAX_BETWEEN_TURN_BUFFER = 500;
4395
4349
  var SUBMIT_SETTLE_MS = 300;
@@ -4488,7 +4442,7 @@ function sleep3(ms) {
4488
4442
  }
4489
4443
  async function transcriptSize(path4) {
4490
4444
  try {
4491
- return (await stat3(path4)).size;
4445
+ return (await stat2(path4)).size;
4492
4446
  } catch {
4493
4447
  return 0;
4494
4448
  }
@@ -5606,7 +5560,7 @@ function formatIncidents(incidents) {
5606
5560
  }
5607
5561
 
5608
5562
  // src/execution/tag-context-resolver.ts
5609
- import { readFile as readFile2, readdir, stat as stat4 } from "fs/promises";
5563
+ import { readFile as readFile2, readdir, stat as stat3 } from "fs/promises";
5610
5564
  var TYPE_PRIORITY = { rule: 0, file: 1, folder: 2, doc: 3 };
5611
5565
  var SUMMARY_SCAN_CHARS = 4e3;
5612
5566
  var SUMMARY_MAX_CHARS = 160;
@@ -5680,7 +5634,7 @@ async function readFileSummary(filePath) {
5680
5634
  if (isBinaryPath(filePath)) return null;
5681
5635
  let mtimeMs;
5682
5636
  try {
5683
- const st = await stat4(filePath);
5637
+ const st = await stat3(filePath);
5684
5638
  mtimeMs = st.mtimeMs;
5685
5639
  } catch {
5686
5640
  return null;
@@ -5702,7 +5656,7 @@ async function readFolderListing(folderPath) {
5702
5656
  try {
5703
5657
  let mtimeMs;
5704
5658
  try {
5705
- const st = await stat4(folderPath);
5659
+ const st = await stat3(folderPath);
5706
5660
  mtimeMs = st.mtimeMs;
5707
5661
  } catch {
5708
5662
  return null;
@@ -7306,7 +7260,7 @@ function buildMutationTools(connection, config) {
7306
7260
  }
7307
7261
 
7308
7262
  // src/tools/attachment-tools.ts
7309
- import { readFile as readFile3, stat as stat5 } from "fs/promises";
7263
+ import { readFile as readFile3, stat as stat4 } from "fs/promises";
7310
7264
  import { basename, extname, isAbsolute, join as join5 } from "path";
7311
7265
  import { z as z7 } from "zod";
7312
7266
  var IMAGE_MIME_BY_EXT = {
@@ -7333,7 +7287,7 @@ function buildUploadAttachmentTool(connection, config) {
7333
7287
  `Unsupported file type "${extname(filePath) || "(none)"}". Supported: ${Object.keys(IMAGE_MIME_BY_EXT).join(", ")}`
7334
7288
  );
7335
7289
  }
7336
- const info = await stat5(filePath).catch(() => null);
7290
+ const info = await stat4(filePath).catch(() => null);
7337
7291
  if (!info?.isFile()) {
7338
7292
  return textResult(`File not found: ${filePath}`);
7339
7293
  }
@@ -9734,6 +9688,76 @@ async function sampleKeyUsage(token, probe = runUsageProbe) {
9734
9688
  }
9735
9689
  }
9736
9690
 
9691
+ // src/setup/git-ready.ts
9692
+ import { access, stat as stat5 } from "fs/promises";
9693
+ var DEFAULT_FAILED_PATH = "/workspaces/.conveyor-git-failed";
9694
+ var DEFAULT_TIMEOUT_MS = 6e5;
9695
+ var DEFAULT_POLL_MS = 200;
9696
+ async function fileExists(path4) {
9697
+ try {
9698
+ await access(path4);
9699
+ const s = await stat5(path4);
9700
+ return s.isFile();
9701
+ } catch {
9702
+ return false;
9703
+ }
9704
+ }
9705
+ function awaitGitReady(opts = {}) {
9706
+ if (opts.signal?.aborted) return Promise.reject(abortError());
9707
+ const markerPath = opts.markerPath ?? process.env.CONVEYOR_GIT_READY_MARKER;
9708
+ if (!markerPath) {
9709
+ return Promise.resolve("not-gated");
9710
+ }
9711
+ const failedPath = opts.failedPath ?? process.env.CONVEYOR_GIT_FAILED_MARKER ?? DEFAULT_FAILED_PATH;
9712
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_TIMEOUT_MS;
9713
+ const pollMs = opts.pollMs ?? DEFAULT_POLL_MS;
9714
+ opts.onLog?.(`waiting for workspace git (marker=${markerPath})`);
9715
+ return pollForMarkers(markerPath, failedPath, timeoutMs, pollMs, opts.onLog, opts.signal);
9716
+ }
9717
+ function abortError() {
9718
+ const error = new Error("Operation aborted");
9719
+ error.name = "AbortError";
9720
+ return error;
9721
+ }
9722
+ function abortableDelay(ms, signal) {
9723
+ if (!signal) {
9724
+ return new Promise((resolve) => {
9725
+ setTimeout(resolve, ms);
9726
+ });
9727
+ }
9728
+ if (signal.aborted) return Promise.reject(abortError());
9729
+ return new Promise((resolve, reject) => {
9730
+ const timer = setTimeout(() => {
9731
+ signal.removeEventListener("abort", onAbort);
9732
+ resolve();
9733
+ }, ms);
9734
+ const onAbort = () => {
9735
+ clearTimeout(timer);
9736
+ reject(abortError());
9737
+ };
9738
+ signal.addEventListener("abort", onAbort, { once: true });
9739
+ });
9740
+ }
9741
+ async function pollForMarkers(markerPath, failedPath, timeoutMs, pollMs, onLog, signal) {
9742
+ const deadline = Date.now() + timeoutMs;
9743
+ for (; ; ) {
9744
+ if (signal?.aborted) throw abortError();
9745
+ if (await fileExists(markerPath)) {
9746
+ onLog?.("workspace git ready");
9747
+ return "ready";
9748
+ }
9749
+ if (await fileExists(failedPath)) {
9750
+ onLog?.("workspace git preparation failed (marker present)");
9751
+ return "failed";
9752
+ }
9753
+ if (Date.now() >= deadline) {
9754
+ onLog?.(`workspace git not ready after ${timeoutMs}ms \u2014 giving up`);
9755
+ return "timeout";
9756
+ }
9757
+ await abortableDelay(pollMs, signal);
9758
+ }
9759
+ }
9760
+
9737
9761
  // src/runner/port-discovery.ts
9738
9762
  import { readFile as readFile4 } from "fs/promises";
9739
9763
  import { execFile as execFile3 } from "child_process";
@@ -9847,6 +9871,7 @@ var PortDiscovery = class {
9847
9871
  timer = null;
9848
9872
  ticking = false;
9849
9873
  disabled = false;
9874
+ stopped = false;
9850
9875
  /** Set when the confirmed set changed (or a report failed) — cleared only
9851
9876
  * after a successful report, so transient RPC failures retry next tick. */
9852
9877
  reportPending = false;
@@ -9864,8 +9889,9 @@ var PortDiscovery = class {
9864
9889
  }
9865
9890
  /** Take the baseline scan and start polling. Safe to call once. */
9866
9891
  async start() {
9867
- if (this.timer || this.disabled) return;
9892
+ if (this.timer || this.disabled || this.stopped) return;
9868
9893
  const baseline = await this.scanSafe();
9894
+ if (this.stopped) return;
9869
9895
  if (baseline === null) {
9870
9896
  this.disabled = true;
9871
9897
  this.log("Port discovery disabled: no listening-socket source available");
@@ -9876,6 +9902,7 @@ var PortDiscovery = class {
9876
9902
  this.timer.unref?.();
9877
9903
  }
9878
9904
  stop() {
9905
+ this.stopped = true;
9879
9906
  if (this.timer) {
9880
9907
  clearInterval(this.timer);
9881
9908
  this.timer = null;
@@ -10071,13 +10098,16 @@ var SessionRunner = class _SessionRunner {
10071
10098
  /** Max consecutive gate-deferred ticks (~2 min each) before flushing anyway. */
10072
10099
  static MAX_GATE_SKIPS = 10;
10073
10100
  /** Runtime preview-port poller (v3 dynamic port discovery). */
10074
- portDiscovery = null;
10101
+ portDiscovery;
10075
10102
  /** Main event-loop lag measurement, shared with the heartbeat worker. */
10076
10103
  loopLag = new LoopLagMonitor();
10077
- constructor(config, callbacks) {
10104
+ constructor(config, callbacks, deps = {}) {
10078
10105
  this.config = config;
10079
10106
  this.callbacks = callbacks;
10080
10107
  this.connection = new AgentConnection(config.connection);
10108
+ this.portDiscovery = deps.portDiscovery ?? new PortDiscovery({
10109
+ report: (ports) => this.connection.reportDiscoveredPorts(ports)
10110
+ });
10081
10111
  const initialMode = config.agentMode ?? (config.runnerMode === "pm" ? config.isAuto ? "auto" : "discovery" : "building");
10082
10112
  this.mode = new ModeController(initialMode, config.runnerMode, config.isAuto);
10083
10113
  const lifecycleConfig = { ...DEFAULT_LIFECYCLE_CONFIG, ...config.lifecycle };
@@ -10142,16 +10172,18 @@ var SessionRunner = class _SessionRunner {
10142
10172
  this.pendingMessages.push({ content: msg.content, userId: msg.userId });
10143
10173
  }
10144
10174
  }
10145
- this.portDiscovery = new PortDiscovery({
10146
- report: (ports) => this.connection.reportDiscoveredPorts(ports)
10147
- });
10148
- void this.portDiscovery.start().catch(() => {
10149
- });
10175
+ if (this.stopped) return false;
10176
+ try {
10177
+ await this.portDiscovery.start();
10178
+ } catch {
10179
+ }
10180
+ if (this.stopped) return false;
10150
10181
  const agentVersion = readAgentVersion();
10151
10182
  if (agentVersion) {
10152
10183
  this.connection.call("notifyAgentVersion", { sessionId: this.sessionId, agentVersion }).catch(() => {
10153
10184
  });
10154
10185
  }
10186
+ return true;
10155
10187
  }
10156
10188
  /**
10157
10189
  * Run the main agent lifecycle: fetch context, resolve mode, execute, loop.
@@ -10267,7 +10299,7 @@ var SessionRunner = class _SessionRunner {
10267
10299
  }
10268
10300
  /** Convenience wrapper: connect() then run(). */
10269
10301
  async start() {
10270
- await this.connect();
10302
+ if (!await this.connect()) return;
10271
10303
  await this.run();
10272
10304
  }
10273
10305
  // ── Core loop ──────────────────────────────────────────────────────
@@ -10661,7 +10693,7 @@ var SessionRunner = class _SessionRunner {
10661
10693
  this.queryBridge?.stop();
10662
10694
  void this.queryBridge?.dispose().catch(() => {
10663
10695
  });
10664
- this.portDiscovery?.stop();
10696
+ this.portDiscovery.stop();
10665
10697
  this.loopLag.stop();
10666
10698
  this.lifecycle.destroy();
10667
10699
  this.connection.disconnect();
@@ -10873,7 +10905,7 @@ var SessionRunner = class _SessionRunner {
10873
10905
  process.stderr.write(`[conveyor-agent] Shutdown: reason=${finalState}
10874
10906
  `);
10875
10907
  this.connection.sendEvent({ type: "shutdown", reason: finalState });
10876
- this.portDiscovery?.stop();
10908
+ this.portDiscovery.stop();
10877
10909
  this.loopLag.stop();
10878
10910
  this.lifecycle.destroy();
10879
10911
  try {
@@ -10972,28 +11004,83 @@ function loadConveyorConfig() {
10972
11004
 
10973
11005
  // src/setup/commands.ts
10974
11006
  import { spawn as spawn2, execSync } from "child_process";
10975
- function runSetupCommand(cmd, cwd, onOutput) {
11007
+ var PROCESS_TERMINATION_GRACE_MS = 5e3;
11008
+ function abortError2() {
11009
+ const error = new Error("Operation aborted");
11010
+ error.name = "AbortError";
11011
+ return error;
11012
+ }
11013
+ function signalProcessGroup(child, signal) {
11014
+ try {
11015
+ if (child.pid) process.kill(-child.pid, signal);
11016
+ else child.kill(signal);
11017
+ } catch {
11018
+ try {
11019
+ child.kill(signal);
11020
+ } catch {
11021
+ }
11022
+ }
11023
+ }
11024
+ function terminateProcessGroup(child, graceMs = PROCESS_TERMINATION_GRACE_MS) {
11025
+ if (child.exitCode !== null) return Promise.resolve();
11026
+ return new Promise((resolve) => {
11027
+ let settled = false;
11028
+ const finish = () => {
11029
+ if (settled) return;
11030
+ settled = true;
11031
+ clearTimeout(timer);
11032
+ child.removeListener("exit", finish);
11033
+ resolve();
11034
+ };
11035
+ const timer = setTimeout(() => {
11036
+ signalProcessGroup(child, "SIGKILL");
11037
+ finish();
11038
+ }, graceMs);
11039
+ timer.unref();
11040
+ child.once("exit", finish);
11041
+ signalProcessGroup(child, "SIGTERM");
11042
+ });
11043
+ }
11044
+ function runSetupCommand(cmd, cwd, onOutput, signal) {
11045
+ if (signal?.aborted) return Promise.reject(abortError2());
10976
11046
  return new Promise((resolve, reject) => {
10977
11047
  const child = spawn2("sh", ["-c", cmd], {
10978
11048
  cwd,
10979
11049
  stdio: ["ignore", "pipe", "pipe"],
11050
+ detached: true,
10980
11051
  env: { ...process.env }
10981
11052
  });
11053
+ let settled = false;
11054
+ let aborting = false;
11055
+ const cleanup = () => signal?.removeEventListener("abort", onAbort);
11056
+ const settle = (error) => {
11057
+ if (settled) return;
11058
+ settled = true;
11059
+ cleanup();
11060
+ if (error) reject(error);
11061
+ else resolve();
11062
+ };
11063
+ const onAbort = () => {
11064
+ if (settled || aborting) return;
11065
+ aborting = true;
11066
+ void terminateProcessGroup(child).then(() => settle(abortError2()));
11067
+ };
11068
+ signal?.addEventListener("abort", onAbort, { once: true });
11069
+ if (signal?.aborted) onAbort();
10982
11070
  child.stdout.on("data", (chunk) => {
11071
+ if (aborting || signal?.aborted) return;
10983
11072
  onOutput("stdout", chunk.toString());
10984
11073
  });
10985
11074
  child.stderr.on("data", (chunk) => {
11075
+ if (aborting || signal?.aborted) return;
10986
11076
  onOutput("stderr", chunk.toString());
10987
11077
  });
10988
11078
  child.on("close", (code) => {
10989
- if (code === 0) {
10990
- resolve();
10991
- } else {
10992
- reject(new Error(`Setup command exited with code ${code}`));
10993
- }
11079
+ if (aborting) return;
11080
+ settle(code === 0 ? void 0 : new Error(`Setup command exited with code ${code}`));
10994
11081
  });
10995
11082
  child.on("error", (err) => {
10996
- reject(err);
11083
+ if (!aborting) settle(err);
10997
11084
  });
10998
11085
  });
10999
11086
  }
@@ -11070,6 +11157,7 @@ export {
11070
11157
  resolveSessionStart,
11071
11158
  sampleKeyUsage,
11072
11159
  awaitGitReady,
11160
+ PortDiscovery,
11073
11161
  uploadSnapshotToGcs,
11074
11162
  captureSnapshot,
11075
11163
  startPeriodic,
@@ -11080,9 +11168,10 @@ export {
11080
11168
  loadForwardPorts,
11081
11169
  buildSessionPreviewPorts,
11082
11170
  loadConveyorConfig,
11171
+ terminateProcessGroup,
11083
11172
  runSetupCommand,
11084
11173
  runAuthTokenCommand,
11085
11174
  runStartCommand,
11086
11175
  unshallowRepo
11087
11176
  };
11088
- //# sourceMappingURL=chunk-UOHROQ6A.js.map
11177
+ //# sourceMappingURL=chunk-WJWMLZKR.js.map