@rallycry/conveyor-agent 10.13.57 → 10.13.59

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.
package/dist/cli.js CHANGED
@@ -24,17 +24,19 @@ import {
24
24
  loadConveyorConfig,
25
25
  loadForwardPorts,
26
26
  parseUsageGauges,
27
+ readWorkspaceBytes,
27
28
  resolvePlaywrightMcpServer,
28
29
  resolveSessionStart,
29
30
  resolveTuiAdapter,
30
31
  resolveTuiKindFromEnv,
31
32
  runUsageProbe,
32
33
  sampleKeyUsage,
34
+ statWorkspacePath,
33
35
  workspacePathExists
34
- } from "./chunk-VIEBOAJ7.js";
36
+ } from "./chunk-JCRP6K6T.js";
35
37
  import {
36
38
  reportBootMilestone
37
- } from "./chunk-WVUQ5CH5.js";
39
+ } from "./chunk-QZN6HVUY.js";
38
40
  import "./chunk-5OQQSDVT.js";
39
41
  import {
40
42
  getWorkbenchClient
@@ -49,12 +51,12 @@ import {
49
51
  runStartCommand,
50
52
  sessionTempBase,
51
53
  terminateProcessGroup
52
- } from "./chunk-PWYJZY3P.js";
54
+ } from "./chunk-NAK6FY5U.js";
53
55
  import "./chunk-JIGG755T.js";
54
56
 
55
57
  // src/cli.ts
56
58
  import { readFileSync } from "fs";
57
- import { join as join3, dirname as dirname2 } from "path";
59
+ import { join as join4, dirname as dirname2 } from "path";
58
60
  import { fileURLToPath } from "url";
59
61
 
60
62
  // src/setup/sidecars.ts
@@ -272,6 +274,143 @@ async function runDbSchemaSync(options) {
272
274
  }
273
275
  }
274
276
 
277
+ // src/setup/deps-sync.ts
278
+ import { join as join2 } from "path";
279
+ var INSTALLER_SCRIPT_CANDIDATES = ["scripts/install-deps.sh"];
280
+ var BUN_INSTALL = "bun install --frozen-lockfile";
281
+ var DEPS_SYNC_TIMEOUT_MS = 9e5;
282
+ var REGISTRY_KEY_ENV = "NPM_CACHE_READER_KEY";
283
+ function isDisabled2(env) {
284
+ const flag = env.CONVEYOR_DEPS_SYNC?.trim().toLowerCase();
285
+ return flag === "0" || flag === "false";
286
+ }
287
+ var CKSUM_POLYNOMIAL = 79764919;
288
+ var CKSUM_TABLE = (() => {
289
+ const table = new Uint32Array(256);
290
+ for (let index = 0; index < 256; index++) {
291
+ let value = index << 24;
292
+ for (let bit = 0; bit < 8; bit++) {
293
+ value = value & 2147483648 ? (value << 1 ^ CKSUM_POLYNOMIAL) >>> 0 : value << 1 >>> 0;
294
+ }
295
+ table[index] = value >>> 0;
296
+ }
297
+ return table;
298
+ })();
299
+ function posixCksum(bytes) {
300
+ let crc = 0;
301
+ for (const byte of bytes) {
302
+ crc = (crc << 8 ^ CKSUM_TABLE[(crc >>> 24 ^ byte) & 255]) >>> 0;
303
+ }
304
+ for (let length = bytes.length; length > 0; length >>>= 8) {
305
+ crc = (crc << 8 ^ CKSUM_TABLE[(crc >>> 24 ^ length & 255) & 255]) >>> 0;
306
+ }
307
+ return ~crc >>> 0;
308
+ }
309
+ function bunLockFingerprint(bytes) {
310
+ return `${posixCksum(bytes)}:${bytes.length}`;
311
+ }
312
+ async function defaultDirExists(path) {
313
+ return (await statWorkspacePath(path)).isDirectory;
314
+ }
315
+ async function readLockDrift(options) {
316
+ const { workspaceDir, readBytes } = options;
317
+ let baked;
318
+ try {
319
+ const raw = await readBytes(join2(workspaceDir, ".conveyor/prebake-cache.json"));
320
+ const parsed = JSON.parse(Buffer.from(raw).toString("utf8"));
321
+ const value = parsed?.bunLockCrc;
322
+ if (typeof value !== "string" || !value) return null;
323
+ baked = value;
324
+ } catch {
325
+ return null;
326
+ }
327
+ try {
328
+ const actual = bunLockFingerprint(await readBytes(join2(workspaceDir, "bun.lock")));
329
+ return actual === baked ? null : { baked, actual };
330
+ } catch {
331
+ return null;
332
+ }
333
+ }
334
+ async function resolveDepsSyncPlan(options) {
335
+ const { workspaceDir, env } = options;
336
+ const pathExists = options.pathExists ?? workspacePathExists;
337
+ const dirExists = options.dirExists ?? defaultDirExists;
338
+ const readBytes = options.readBytes ?? readWorkspaceBytes;
339
+ if (isDisabled2(env)) return null;
340
+ if (!await pathExists(join2(workspaceDir, "package.json"))) return null;
341
+ const override = env.CONVEYOR_DEPS_SYNC_COMMAND?.trim();
342
+ const resolveCommand = async () => {
343
+ if (override) return override;
344
+ for (const relative of INSTALLER_SCRIPT_CANDIDATES) {
345
+ if (await pathExists(join2(workspaceDir, relative))) return `bash ${relative}`;
346
+ }
347
+ return BUN_INSTALL;
348
+ };
349
+ if (!await dirExists(join2(workspaceDir, "node_modules"))) {
350
+ return {
351
+ command: await resolveCommand(),
352
+ cwd: workspaceDir,
353
+ reason: "missing_node_modules",
354
+ detail: "the pod booted with no node_modules \u2014 the baked dependency tree is absent"
355
+ };
356
+ }
357
+ const drift = await readLockDrift({ workspaceDir, readBytes });
358
+ if (drift) {
359
+ return {
360
+ command: await resolveCommand(),
361
+ cwd: workspaceDir,
362
+ reason: "lockfile_drift",
363
+ detail: `bun.lock changed since the image bake (baked ${drift.baked}, checked out ${drift.actual})`
364
+ };
365
+ }
366
+ return null;
367
+ }
368
+ function describeFailure(plan, error, env) {
369
+ const cause = error instanceof Error ? error.message : String(error);
370
+ const parts = [
371
+ `Dependency install failed (${plan.reason}): ${plan.detail}.`,
372
+ `Ran \`${plan.command}\` in ${plan.cwd} \u2014 ${cause}.`
373
+ ];
374
+ if (!env[REGISTRY_KEY_ENV]?.trim()) {
375
+ parts.push(
376
+ `${REGISTRY_KEY_ENV} is not set on this pod, so packages on the private registry cache cannot be fetched \u2014 set it as a project secret.`
377
+ );
378
+ }
379
+ return parts.join(" ");
380
+ }
381
+ async function runDepsSync(options) {
382
+ let plan = null;
383
+ try {
384
+ plan = await resolveDepsSyncPlan(options);
385
+ } catch {
386
+ return { outcome: "skipped" };
387
+ }
388
+ if (!plan) return { outcome: "skipped" };
389
+ const { onOutput, runCommand, env } = options;
390
+ onOutput("stdout", `[deps] ${plan.detail}
391
+ `);
392
+ onOutput("stdout", `[deps] installing (${plan.reason}): ${plan.command}
393
+ `);
394
+ const controller = new AbortController();
395
+ const abort = () => controller.abort();
396
+ options.signal?.addEventListener("abort", abort, { once: true });
397
+ const timer = setTimeout(abort, options.timeoutMs ?? DEPS_SYNC_TIMEOUT_MS);
398
+ timer.unref();
399
+ try {
400
+ await runCommand(plan.command, plan.cwd, onOutput, controller.signal);
401
+ onOutput("stdout", "[deps] dependencies installed\n");
402
+ return { outcome: "installed" };
403
+ } catch (error) {
404
+ const message = describeFailure(plan, error, env);
405
+ onOutput("stderr", `[deps] ${message}
406
+ `);
407
+ return { outcome: "failed", message };
408
+ } finally {
409
+ clearTimeout(timer);
410
+ options.signal?.removeEventListener("abort", abort);
411
+ }
412
+ }
413
+
275
414
  // src/setup/workspace-command-supervisor.ts
276
415
  function defaultCommandExecutors() {
277
416
  if (workbenchEnabled()) {
@@ -307,6 +446,7 @@ var WorkspaceCommandSupervisor = class {
307
446
  waitForSidecarsFn;
308
447
  runStartCommandFn;
309
448
  syncDbSchemaFn;
449
+ syncDepsFn;
310
450
  loadForwardPortsFn;
311
451
  writeOutput;
312
452
  terminateStartCommand;
@@ -352,6 +492,13 @@ var WorkspaceCommandSupervisor = class {
352
492
  onOutput: opts.onOutput,
353
493
  signal: opts.signal
354
494
  }));
495
+ this.syncDepsFn = options.syncDeps ?? ((opts) => runDepsSync({
496
+ workspaceDir: this.workspaceDir,
497
+ env: this.env,
498
+ runCommand: executors.runShellCommand,
499
+ onOutput: opts.onOutput,
500
+ signal: opts.signal
501
+ }));
355
502
  this.loadForwardPortsFn = options.loadForwardPorts ?? loadForwardPorts;
356
503
  this.writeOutput = options.writeOutput ?? defaultWriteOutput;
357
504
  this.terminateStartCommand = options.terminateStartCommand ?? terminateProcessGroup;
@@ -412,6 +559,8 @@ var WorkspaceCommandSupervisor = class {
412
559
  this.reportBootMilestoneFn("sidecars_ready");
413
560
  await this.loopReady;
414
561
  if (this.stopped) return;
562
+ await this.syncDeps();
563
+ if (this.stopped) return;
415
564
  await this.syncDbSchema();
416
565
  if (this.stopped) return;
417
566
  const startCommandRunning = this.config?.startCommand ? await this.ensureStartCommandLaunched(this.config.startCommand) : false;
@@ -426,6 +575,21 @@ var WorkspaceCommandSupervisor = class {
426
575
  ...previewPorts.length > 0 ? { previewPorts } : {}
427
576
  });
428
577
  }
578
+ /** Run the dependency sync, forwarding its output as setup output so it lands
579
+ * in the card's setup log. A failure is announced with its own cause rather
580
+ * than thrown: the start command still launches, but the card now carries
581
+ * the reason instead of a generic `start command exited with code 1`. */
582
+ async syncDeps() {
583
+ const result = await this.syncDepsFn({
584
+ onOutput: (stream, data) => this.forwardSetupOutput(stream, data),
585
+ signal: this.abortController.signal
586
+ });
587
+ if (result.outcome !== "failed" || this.stopped) return;
588
+ this.connection.sendEvent({
589
+ type: "setup_error",
590
+ message: result.message ?? "Dependency install failed \u2014 the start command will fail until dependencies are installed (see pod logs)"
591
+ });
592
+ }
429
593
  /** Run the schema sync, forwarding its output as setup output so it lands in
430
594
  * the card's setup log. A failure is announced rather than thrown: it is the
431
595
  * exact condition that used to render as a silent "Displaying 0 results". */
@@ -762,7 +926,7 @@ var ProjectSessionRunner = class {
762
926
 
763
927
  // src/usage/multi-key-probe.ts
764
928
  import { mkdtemp, writeFile, copyFile, rm } from "fs/promises";
765
- import { join as join2 } from "path";
929
+ import { join as join3 } from "path";
766
930
  var logger = createServiceLogger("multi-key-probe");
767
931
  function gaugesToSamples(stdout) {
768
932
  const { sessionUsage, weeklyUsage, sessionResetsAt, weeklyResetsAt, gauges } = parseUsageGauges(stdout);
@@ -790,12 +954,12 @@ function gaugesToSamples(stdout) {
790
954
  async function isolatedProbe(token, now) {
791
955
  let dir = null;
792
956
  try {
793
- dir = await mkdtemp(join2(sessionTempBase(), "conveyor-usage-"));
794
- await writeFile(join2(dir, ".credentials.json"), buildSynthesizedCredentials(token, now), {
957
+ dir = await mkdtemp(join3(sessionTempBase(), "conveyor-usage-"));
958
+ await writeFile(join3(dir, ".credentials.json"), buildSynthesizedCredentials(token, now), {
795
959
  encoding: "utf8",
796
960
  mode: 384
797
961
  });
798
- await copyFile(claudeJsonPath(), join2(dir, ".claude.json")).catch(() => {
962
+ await copyFile(claudeJsonPath(), join3(dir, ".claude.json")).catch(() => {
799
963
  });
800
964
  return await runUsageProbe({ env: { ...process.env, CLAUDE_CONFIG_DIR: dir } });
801
965
  } catch (error) {
@@ -1558,7 +1722,7 @@ function hostsSpawnedChildren(mode) {
1558
1722
 
1559
1723
  // src/cli.ts
1560
1724
  if (process.argv[2] === "boot") {
1561
- const { runBoot } = await import("./boot-37ZX7POR.js");
1725
+ const { runBoot } = await import("./boot-7OPX55AO.js");
1562
1726
  process.exit(await runBoot(process.argv.slice(3)));
1563
1727
  }
1564
1728
  if (isLegacyEntrypointLaunch(process.env)) {
@@ -1568,7 +1732,7 @@ if (isLegacyEntrypointLaunch(process.env)) {
1568
1732
  }
1569
1733
  if (process.argv.includes("--version")) {
1570
1734
  const __dirname = dirname2(fileURLToPath(import.meta.url));
1571
- const pkgPath = join3(__dirname, "..", "package.json");
1735
+ const pkgPath = join4(__dirname, "..", "package.json");
1572
1736
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
1573
1737
  process.stdout.write(pkg.version + "\n");
1574
1738
  process.exit(0);
@@ -1660,7 +1824,7 @@ process.on("unhandledRejection", (reason) => {
1660
1824
  process.exit(1);
1661
1825
  });
1662
1826
  if (process.env.CONVEYOR_MODE === "workbench") {
1663
- const { startWorkbenchServer } = await import("./server-7UW4X3XF.js");
1827
+ const { startWorkbenchServer } = await import("./server-ZACB5T5S.js");
1664
1828
  const { oomWatchdogOptionsFromEnv } = await import("./oom-watchdog-U7JERHA2.js");
1665
1829
  const { DEFAULT_WORKBENCH_PORT } = await import("./protocol-QLVS5W6O.js");
1666
1830
  const port = Number(process.env.CONVEYOR_WORKBENCH_PORT) || DEFAULT_WORKBENCH_PORT;
@@ -1670,7 +1834,7 @@ if (process.env.CONVEYOR_MODE === "workbench") {
1670
1834
  process.exit(1);
1671
1835
  }
1672
1836
  const pkgDir = dirname2(fileURLToPath(import.meta.url));
1673
- const pkg = JSON.parse(readFileSync(join3(pkgDir, "..", "package.json"), "utf-8"));
1837
+ const pkg = JSON.parse(readFileSync(join4(pkgDir, "..", "package.json"), "utf-8"));
1674
1838
  const handle = await startWorkbenchServer({
1675
1839
  port,
1676
1840
  token,