@rallycry/conveyor-agent 10.13.71 → 10.13.72

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
@@ -4,732 +4,57 @@ import {
4
4
  isLegacyEntrypointLaunch
5
5
  } from "./chunk-R3FDJQL6.js";
6
6
  import {
7
- AgentConnection,
8
- CodespacePortVisibility,
9
- DEFAULT_LIFECYCLE_CONFIG,
7
+ WorkspaceCommandSupervisor,
8
+ startWorkspaceCommandsAfterConnect,
9
+ stopWorkspaceCommands
10
+ } from "./chunk-2L5THOWD.js";
11
+ import {
10
12
  DEFAULT_SONNET_MODEL,
11
- Lifecycle,
12
- PortDiscovery,
13
13
  PtyHarness,
14
14
  SessionRunner,
15
- applyBootstrapToEnv,
16
- awaitGitReady,
17
15
  buildProjectTools,
18
16
  buildRateLimitEvents,
19
- buildSessionPreviewPorts,
20
17
  buildSynthesizedCredentials,
21
18
  buildUnmeasurableEvent,
22
19
  claudeJsonPath,
23
- createServiceLogger,
24
- fetchBootstrap,
25
20
  isPermissionDeniedError,
26
- loadConveyorConfig,
27
- loadForwardPorts,
28
21
  parseUsageGauges,
29
- readWorkspaceBytes,
30
22
  resolvePlaywrightMcpServer,
31
23
  resolveSessionStart,
32
24
  resolveTuiAdapter,
33
25
  resolveTuiKindFromEnv,
34
26
  runUsageProbe,
35
- sampleKeyUsage,
36
- statWorkspacePath,
37
- workspacePathExists
38
- } from "./chunk-7MMECTTJ.js";
27
+ sampleKeyUsage
28
+ } from "./chunk-2SN32LM6.js";
29
+ import "./chunk-XORJ6SII.js";
39
30
  import {
40
- reportBootMilestone
41
- } from "./chunk-QU53HND5.js";
31
+ AgentConnection,
32
+ CodespacePortVisibility,
33
+ DEFAULT_LIFECYCLE_CONFIG,
34
+ Lifecycle,
35
+ PortDiscovery,
36
+ applyBootstrapToEnv,
37
+ createServiceLogger,
38
+ fetchBootstrap,
39
+ loadConveyorConfig
40
+ } from "./chunk-LSZ2KLJY.js";
41
+ import "./chunk-WMMBAKPE.js";
42
42
  import "./chunk-IA45XHOA.js";
43
- import {
44
- getWorkbenchClient
45
- } from "./chunk-EXQ6AHOY.js";
46
- import {
47
- workbenchEnabled
48
- } from "./chunk-KMB3BU4S.js";
43
+ import "./chunk-EXQ6AHOY.js";
44
+ import "./chunk-KMB3BU4S.js";
49
45
  import {
50
46
  inheritedEnv,
51
47
  resolvePtySpawn,
52
- runSetupCommand,
53
- runStartCommand,
54
- sessionTempBase,
55
- terminateProcessGroup
56
- } from "./chunk-GJXAAPJ6.js";
48
+ sessionTempBase
49
+ } from "./chunk-3F4ZZKCA.js";
50
+ import "./chunk-W4LZ7R6Z.js";
57
51
  import "./chunk-6Q6LQBWO.js";
58
52
 
59
53
  // src/cli.ts
60
54
  import { readFileSync } from "fs";
61
- import { join as join4, dirname as dirname2 } from "path";
55
+ import { join as join2, dirname } from "path";
62
56
  import { fileURLToPath } from "url";
63
57
 
64
- // src/setup/sidecars.ts
65
- import net from "net";
66
- var POSTGRES_TIMEOUT_MS = 12e4;
67
- var FIREBASE_TIMEOUT_MS = 6e4;
68
- var FALLBACK_TIMEOUT_MS = 3e4;
69
- var DEFAULT_SIDECAR_POLL_INTERVAL_MS = 1e3;
70
- var DEFAULT_PROBE_TIMEOUT_MS = 2e3;
71
- var POSTGRES_DEFAULT_PORT = 5432;
72
- var FIREBASE_DEFAULT_PORT = 9099;
73
- function parseHostPort(value, defaultPort) {
74
- const trimmed = value.trim().replace(/^[a-z]+:\/\//i, "");
75
- if (!trimmed) return null;
76
- const idx = trimmed.lastIndexOf(":");
77
- if (idx === -1) {
78
- return { host: trimmed, port: defaultPort };
79
- }
80
- const host = trimmed.slice(0, idx) || "localhost";
81
- const port = Number(trimmed.slice(idx + 1));
82
- return { host, port: Number.isFinite(port) ? port : defaultPort };
83
- }
84
- function resolveSidecarTargets(env = process.env) {
85
- const targets = [];
86
- const databaseUrl = env.DATABASE_URL;
87
- if (databaseUrl) {
88
- try {
89
- const url = new URL(databaseUrl);
90
- const host = url.hostname || "localhost";
91
- const port = url.port ? Number(url.port) : POSTGRES_DEFAULT_PORT;
92
- if (Number.isFinite(port)) {
93
- targets.push({ name: "postgres", host, port, timeoutMs: POSTGRES_TIMEOUT_MS });
94
- }
95
- } catch {
96
- }
97
- }
98
- const firebaseHost = env.FIREBASE_AUTH_EMULATOR_HOST;
99
- if (firebaseHost) {
100
- const parsed = parseHostPort(firebaseHost, FIREBASE_DEFAULT_PORT);
101
- if (parsed) {
102
- targets.push({
103
- name: "firebase auth emulator",
104
- host: parsed.host,
105
- port: parsed.port,
106
- timeoutMs: FIREBASE_TIMEOUT_MS
107
- });
108
- }
109
- }
110
- return targets;
111
- }
112
- function abortError() {
113
- const error = new Error("Operation aborted");
114
- error.name = "AbortError";
115
- return error;
116
- }
117
- function throwIfAborted(signal) {
118
- if (signal?.aborted) throw abortError();
119
- }
120
- function defaultProbe(target, signal) {
121
- throwIfAborted(signal);
122
- return new Promise((resolve) => {
123
- let settled = false;
124
- const socket = net.createConnection({ host: target.host, port: target.port });
125
- const done = (ok) => {
126
- if (settled) return;
127
- settled = true;
128
- socket.destroy();
129
- signal?.removeEventListener("abort", onAbort);
130
- resolve(ok);
131
- };
132
- const onAbort = () => done(false);
133
- socket.once("connect", () => done(true));
134
- socket.once("error", () => done(false));
135
- socket.setTimeout(DEFAULT_PROBE_TIMEOUT_MS, () => done(false));
136
- signal?.addEventListener("abort", onAbort, { once: true });
137
- });
138
- }
139
- var delay = (ms, signal) => {
140
- throwIfAborted(signal);
141
- return new Promise((resolve, reject) => {
142
- const timer = setTimeout(() => {
143
- signal?.removeEventListener("abort", onAbort);
144
- resolve();
145
- }, ms);
146
- const onAbort = () => {
147
- clearTimeout(timer);
148
- reject(abortError());
149
- };
150
- signal?.addEventListener("abort", onAbort, { once: true });
151
- });
152
- };
153
- function raceWithAbort(promise, signal) {
154
- if (!signal) return promise;
155
- throwIfAborted(signal);
156
- return new Promise((resolve, reject) => {
157
- const onAbort = () => reject(abortError());
158
- signal.addEventListener("abort", onAbort, { once: true });
159
- void promise.then(
160
- (value) => {
161
- signal.removeEventListener("abort", onAbort);
162
- resolve(value);
163
- },
164
- (error) => {
165
- signal.removeEventListener("abort", onAbort);
166
- reject(error);
167
- }
168
- );
169
- });
170
- }
171
- async function waitForTarget(target, opts) {
172
- const { onLog, pollIntervalMs, probe, signal } = opts;
173
- const timeoutMs = opts.timeoutMs ?? target.timeoutMs ?? FALLBACK_TIMEOUT_MS;
174
- const deadline = Date.now() + timeoutMs;
175
- onLog(`Waiting for ${target.name} on ${target.host}:${target.port}...`);
176
- while (true) {
177
- throwIfAborted(signal);
178
- if (await raceWithAbort(probe(target, signal), signal)) {
179
- onLog(`${target.name} is ready`);
180
- return;
181
- }
182
- if (Date.now() >= deadline) {
183
- onLog(
184
- `WARNING: ${target.name} not ready after ${Math.round(timeoutMs / 1e3)}s, continuing anyway`
185
- );
186
- return;
187
- }
188
- await delay(pollIntervalMs, signal);
189
- }
190
- }
191
- async function waitForSidecars(opts = {}) {
192
- const {
193
- env = process.env,
194
- onLog = () => {
195
- },
196
- timeoutMs,
197
- pollIntervalMs = DEFAULT_SIDECAR_POLL_INTERVAL_MS,
198
- probe = defaultProbe,
199
- signal
200
- } = opts;
201
- throwIfAborted(signal);
202
- const targets = resolveSidecarTargets(env);
203
- if (targets.length === 0) return;
204
- await Promise.all(
205
- targets.map(
206
- (target) => waitForTarget(target, { onLog, timeoutMs, pollIntervalMs, probe, signal })
207
- )
208
- );
209
- }
210
-
211
- // src/setup/db-schema-sync.ts
212
- import { basename, dirname, join } from "path";
213
- var PRISMA_SCHEMA_CANDIDATES = [
214
- "packages/db/prisma/schema.prisma",
215
- "prisma/schema.prisma",
216
- "apps/api/prisma/schema.prisma",
217
- "packages/db/schema.prisma"
218
- ];
219
- var PRISMA_DB_PUSH = "bunx prisma db push";
220
- var SCHEMA_SYNC_TIMEOUT_MS = 18e4;
221
- function depsInclude(rawDeps, dep) {
222
- return (rawDeps ?? "").split(",").map((entry) => entry.trim()).includes(dep);
223
- }
224
- function isDisabled(env) {
225
- const flag = env.CONVEYOR_DB_SCHEMA_SYNC?.trim().toLowerCase();
226
- return flag === "0" || flag === "false";
227
- }
228
- function packageRootForSchema(schemaPath) {
229
- const dir = dirname(schemaPath);
230
- return basename(dir) === "prisma" ? dirname(dir) : dir;
231
- }
232
- async function resolveSchemaSyncPlan(options) {
233
- const { workspaceDir, env } = options;
234
- const pathExists = options.pathExists ?? workspacePathExists;
235
- if (isDisabled(env)) return null;
236
- const override = env.CONVEYOR_DB_SCHEMA_SYNC_COMMAND?.trim();
237
- if (override) return { command: override, cwd: workspaceDir, source: "override" };
238
- if (!depsInclude(env.CONVEYOR_DEPS, "postgresql")) return null;
239
- if (!env.DATABASE_URL?.trim()) return null;
240
- for (const relative of PRISMA_SCHEMA_CANDIDATES) {
241
- const schemaPath = join(workspaceDir, relative);
242
- if (await pathExists(schemaPath)) {
243
- return { command: PRISMA_DB_PUSH, cwd: packageRootForSchema(schemaPath), source: "prisma" };
244
- }
245
- }
246
- return null;
247
- }
248
- async function runDbSchemaSync(options) {
249
- let plan = null;
250
- try {
251
- plan = await resolveSchemaSyncPlan(options);
252
- } catch {
253
- return "skipped";
254
- }
255
- if (!plan) return "skipped";
256
- const { onOutput, runCommand } = options;
257
- onOutput("stdout", `[db] syncing schema (${plan.source}): ${plan.command}
258
- `);
259
- const controller = new AbortController();
260
- const abort = () => controller.abort();
261
- options.signal?.addEventListener("abort", abort, { once: true });
262
- const timer = setTimeout(abort, options.timeoutMs ?? SCHEMA_SYNC_TIMEOUT_MS);
263
- timer.unref();
264
- try {
265
- await runCommand(plan.command, plan.cwd, onOutput, controller.signal);
266
- onOutput("stdout", "[db] schema in sync\n");
267
- return "synced";
268
- } catch (error) {
269
- const message = error instanceof Error ? error.message : String(error);
270
- onOutput("stderr", `[db] schema sync failed: ${message}
271
- `);
272
- return "failed";
273
- } finally {
274
- clearTimeout(timer);
275
- options.signal?.removeEventListener("abort", abort);
276
- }
277
- }
278
-
279
- // src/setup/deps-sync.ts
280
- import { join as join2 } from "path";
281
- var INSTALLER_SCRIPT_CANDIDATES = ["scripts/install-deps.sh"];
282
- var BUN_INSTALL = "bun install --frozen-lockfile";
283
- var DEPS_SYNC_TIMEOUT_MS = 9e5;
284
- var REGISTRY_KEY_ENV = "NPM_CACHE_READER_KEY";
285
- function isDisabled2(env) {
286
- const flag = env.CONVEYOR_DEPS_SYNC?.trim().toLowerCase();
287
- return flag === "0" || flag === "false";
288
- }
289
- var CKSUM_POLYNOMIAL = 79764919;
290
- var CKSUM_TABLE = (() => {
291
- const table = new Uint32Array(256);
292
- for (let index = 0; index < 256; index++) {
293
- let value = index << 24;
294
- for (let bit = 0; bit < 8; bit++) {
295
- value = value & 2147483648 ? (value << 1 ^ CKSUM_POLYNOMIAL) >>> 0 : value << 1 >>> 0;
296
- }
297
- table[index] = value >>> 0;
298
- }
299
- return table;
300
- })();
301
- function posixCksum(bytes) {
302
- let crc = 0;
303
- for (const byte of bytes) {
304
- crc = (crc << 8 ^ CKSUM_TABLE[(crc >>> 24 ^ byte) & 255]) >>> 0;
305
- }
306
- for (let length = bytes.length; length > 0; length >>>= 8) {
307
- crc = (crc << 8 ^ CKSUM_TABLE[(crc >>> 24 ^ length & 255) & 255]) >>> 0;
308
- }
309
- return ~crc >>> 0;
310
- }
311
- function bunLockFingerprint(bytes) {
312
- return `${posixCksum(bytes)}:${bytes.length}`;
313
- }
314
- async function defaultDirExists(path) {
315
- return (await statWorkspacePath(path)).isDirectory;
316
- }
317
- async function readLockDrift(options) {
318
- const { workspaceDir, readBytes } = options;
319
- let baked;
320
- try {
321
- const raw = await readBytes(join2(workspaceDir, ".conveyor/prebake-cache.json"));
322
- const parsed = JSON.parse(Buffer.from(raw).toString("utf8"));
323
- const value = parsed?.bunLockCrc;
324
- if (typeof value !== "string" || !value) return null;
325
- baked = value;
326
- } catch {
327
- return null;
328
- }
329
- try {
330
- const actual = bunLockFingerprint(await readBytes(join2(workspaceDir, "bun.lock")));
331
- return actual === baked ? null : { baked, actual };
332
- } catch {
333
- return null;
334
- }
335
- }
336
- async function resolveDepsSyncPlan(options) {
337
- const { workspaceDir, env } = options;
338
- const pathExists = options.pathExists ?? workspacePathExists;
339
- const dirExists = options.dirExists ?? defaultDirExists;
340
- const readBytes = options.readBytes ?? readWorkspaceBytes;
341
- if (isDisabled2(env)) return null;
342
- if (!await pathExists(join2(workspaceDir, "package.json"))) return null;
343
- const override = env.CONVEYOR_DEPS_SYNC_COMMAND?.trim();
344
- const resolveCommand = async () => {
345
- if (override) return override;
346
- for (const relative of INSTALLER_SCRIPT_CANDIDATES) {
347
- if (await pathExists(join2(workspaceDir, relative))) return `bash ${relative}`;
348
- }
349
- return BUN_INSTALL;
350
- };
351
- if (!await dirExists(join2(workspaceDir, "node_modules"))) {
352
- return {
353
- command: await resolveCommand(),
354
- cwd: workspaceDir,
355
- reason: "missing_node_modules",
356
- detail: "the pod booted with no node_modules \u2014 the baked dependency tree is absent"
357
- };
358
- }
359
- const drift = await readLockDrift({ workspaceDir, readBytes });
360
- if (drift) {
361
- return {
362
- command: await resolveCommand(),
363
- cwd: workspaceDir,
364
- reason: "lockfile_drift",
365
- detail: `bun.lock changed since the image bake (baked ${drift.baked}, checked out ${drift.actual})`
366
- };
367
- }
368
- return null;
369
- }
370
- function describeFailure(plan, error, env) {
371
- const cause = error instanceof Error ? error.message : String(error);
372
- const parts = [
373
- `Dependency install failed (${plan.reason}): ${plan.detail}.`,
374
- `Ran \`${plan.command}\` in ${plan.cwd} \u2014 ${cause}.`
375
- ];
376
- if (!env[REGISTRY_KEY_ENV]?.trim()) {
377
- parts.push(
378
- `${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.`
379
- );
380
- }
381
- return parts.join(" ");
382
- }
383
- async function runDepsSync(options) {
384
- let plan = null;
385
- try {
386
- plan = await resolveDepsSyncPlan(options);
387
- } catch {
388
- return { outcome: "skipped" };
389
- }
390
- if (!plan) return { outcome: "skipped" };
391
- const { onOutput, runCommand, env } = options;
392
- onOutput("stdout", `[deps] ${plan.detail}
393
- `);
394
- onOutput("stdout", `[deps] installing (${plan.reason}): ${plan.command}
395
- `);
396
- const controller = new AbortController();
397
- const abort = () => controller.abort();
398
- options.signal?.addEventListener("abort", abort, { once: true });
399
- const timer = setTimeout(abort, options.timeoutMs ?? DEPS_SYNC_TIMEOUT_MS);
400
- timer.unref();
401
- try {
402
- await runCommand(plan.command, plan.cwd, onOutput, controller.signal);
403
- onOutput("stdout", "[deps] dependencies installed\n");
404
- return { outcome: "installed" };
405
- } catch (error) {
406
- const message = describeFailure(plan, error, env);
407
- onOutput("stderr", `[deps] ${message}
408
- `);
409
- return { outcome: "failed", message };
410
- } finally {
411
- clearTimeout(timer);
412
- options.signal?.removeEventListener("abort", abort);
413
- }
414
- }
415
-
416
- // src/setup/workspace-command-supervisor.ts
417
- function defaultCommandExecutors() {
418
- if (workbenchEnabled()) {
419
- const client = getWorkbenchClient();
420
- return {
421
- runStartCommand: (cmd, cwd, onOutput) => client.runStartCommand(cmd, cwd, onOutput),
422
- runShellCommand: (cmd, cwd, onOutput, signal) => client.runSetupCommand(cmd, cwd, onOutput, signal)
423
- };
424
- }
425
- return { runStartCommand, runShellCommand: runSetupCommand };
426
- }
427
- var defaultWriteOutput = (stream, data) => {
428
- (stream === "stderr" ? process.stderr : process.stdout).write(data);
429
- };
430
- function stopWorkspaceCommands(supervisor) {
431
- return supervisor?.stop() ?? Promise.resolve();
432
- }
433
- async function startWorkspaceCommandsAfterConnect(options) {
434
- const connected = await options.connect();
435
- if (!connected || options.isShuttingDown()) return null;
436
- const supervisor = options.create();
437
- supervisor.start();
438
- return supervisor;
439
- }
440
- var WorkspaceCommandSupervisor = class {
441
- abortController = new AbortController();
442
- expectedStartCommandStops = /* @__PURE__ */ new WeakSet();
443
- config;
444
- workspaceDir;
445
- connection;
446
- env;
447
- awaitGitReadyFn;
448
- waitForSidecarsFn;
449
- runStartCommandFn;
450
- syncDbSchemaFn;
451
- syncDepsFn;
452
- loadForwardPortsFn;
453
- writeOutput;
454
- terminateStartCommand;
455
- reportBootMilestoneFn;
456
- startCommandChild = null;
457
- liveStartCommandChildren = /* @__PURE__ */ new Set();
458
- startCommandTerminations = /* @__PURE__ */ new WeakMap();
459
- startCommandEndPromises = /* @__PURE__ */ new WeakMap();
460
- resolveStartCommandEnd = /* @__PURE__ */ new WeakMap();
461
- backgroundTasks = /* @__PURE__ */ new Set();
462
- startCommandQueue = Promise.resolve();
463
- shutdownPromise = null;
464
- startCommandLaunchRequested = false;
465
- started = false;
466
- stopped = false;
467
- /** Resolved by notifyLoopReady() once the PTY is live — the runner fires it
468
- * on the first harness event of the initial query (or when a prefill
469
- * parks), NOT after the first turn completes, so the app's start command
470
- * isn't held behind a long working turn. Also resolved by stop() if
471
- * shutdown arrives first — either way unblocks the awaiter in
472
- * runSetupAndStart so a supervisor stopped before the loop ever signals
473
- * doesn't hang its background task (and therefore stop()) forever. */
474
- resolveLoopReady;
475
- loopReady = new Promise((resolve) => {
476
- this.resolveLoopReady = resolve;
477
- });
478
- constructor(options) {
479
- this.config = options.config;
480
- this.workspaceDir = options.workspaceDir;
481
- this.connection = options.connection;
482
- this.env = options.env ?? process.env;
483
- this.awaitGitReadyFn = options.awaitGitReady ?? ((opts) => awaitGitReady({
484
- onLog: opts.onLog,
485
- signal: opts.signal
486
- }));
487
- this.waitForSidecarsFn = options.waitForSidecars ?? ((opts) => waitForSidecars({ onLog: opts.onLog, signal: opts.signal }));
488
- const executors = defaultCommandExecutors();
489
- this.runStartCommandFn = options.runStartCommand ?? executors.runStartCommand;
490
- this.syncDbSchemaFn = options.syncDbSchema ?? ((opts) => runDbSchemaSync({
491
- workspaceDir: this.workspaceDir,
492
- env: this.env,
493
- runCommand: executors.runShellCommand,
494
- onOutput: opts.onOutput,
495
- signal: opts.signal
496
- }));
497
- this.syncDepsFn = options.syncDeps ?? ((opts) => runDepsSync({
498
- workspaceDir: this.workspaceDir,
499
- env: this.env,
500
- runCommand: executors.runShellCommand,
501
- onOutput: opts.onOutput,
502
- signal: opts.signal
503
- }));
504
- this.loadForwardPortsFn = options.loadForwardPorts ?? loadForwardPorts;
505
- this.writeOutput = options.writeOutput ?? defaultWriteOutput;
506
- this.terminateStartCommand = options.terminateStartCommand ?? terminateProcessGroup;
507
- this.reportBootMilestoneFn = options.reportBootMilestone ?? ((key) => {
508
- void reportBootMilestone({ key, env: this.env });
509
- });
510
- }
511
- start() {
512
- if (this.started || this.stopped) return;
513
- this.started = true;
514
- this.connection.onRunStartCommand(() => this.restartStartCommand());
515
- if (this.config) {
516
- this.trackBackgroundTask(
517
- this.runSetupAndStart().catch((error) => this.reportUnexpectedError(error))
518
- );
519
- }
520
- }
521
- /** Release the start-command launch — called once the runner's core loop
522
- * (the PTY) is live. Idempotent; resolving an already-settled promise is a
523
- * no-op, so a late/duplicate call (or one after stop() already resolved
524
- * it) is harmless. */
525
- notifyLoopReady() {
526
- this.resolveLoopReady();
527
- }
528
- stop() {
529
- if (this.shutdownPromise) return this.shutdownPromise;
530
- this.stopped = true;
531
- this.resolveLoopReady();
532
- this.abortController.abort();
533
- const backgroundTasks = [...this.backgroundTasks];
534
- const termination = this.terminateAllStartCommands();
535
- this.shutdownPromise = (async () => {
536
- await Promise.allSettled([termination, this.startCommandQueue, ...backgroundTasks]);
537
- await this.terminateAllStartCommands();
538
- })();
539
- return this.shutdownPromise;
540
- }
541
- async runSetupAndStart() {
542
- const gitState = await this.awaitGitReadyFn({
543
- onLog: (message) => this.forwardSetupOutput("stdout", `[git] ${message}
544
- `),
545
- signal: this.abortController.signal
546
- });
547
- if (this.stopped) return;
548
- if (gitState === "failed" || gitState === "timeout") {
549
- this.connection.sendEvent({
550
- type: "setup_error",
551
- message: "Workspace not ready \u2014 skipping setup/start"
552
- });
553
- return;
554
- }
555
- await this.waitForSidecarsFn({
556
- onLog: (message) => this.forwardSetupOutput("stdout", `[sidecars] ${message}
557
- `),
558
- signal: this.abortController.signal
559
- });
560
- if (this.stopped) return;
561
- this.reportBootMilestoneFn("sidecars_ready");
562
- await this.loopReady;
563
- if (this.stopped) return;
564
- await this.syncDeps();
565
- if (this.stopped) return;
566
- await this.syncDbSchema();
567
- if (this.stopped) return;
568
- const startCommandRunning = this.config?.startCommand ? await this.ensureStartCommandLaunched(this.config.startCommand) : false;
569
- if (this.stopped) return;
570
- this.reportBootMilestoneFn("start_command_launched");
571
- const forwardPorts = await this.loadForwardPortsFn(this.workspaceDir);
572
- if (this.stopped) return;
573
- const previewPorts = buildSessionPreviewPorts(forwardPorts);
574
- this.connection.sendEvent({
575
- type: "setup_complete",
576
- startCommandRunning,
577
- // Reported separately so the server can tell "nothing to run" apart from
578
- // "the dev server failed to launch" — both report startCommandRunning:false.
579
- startCommandConfigured: Boolean(this.config?.startCommand),
580
- ...previewPorts.length > 0 ? { previewPorts } : {}
581
- });
582
- }
583
- /** Run the dependency sync, forwarding its output as setup output so it lands
584
- * in the card's setup log. A failure is announced with its own cause rather
585
- * than thrown: the start command still launches, but the card now carries
586
- * the reason instead of a generic `start command exited with code 1`. */
587
- async syncDeps() {
588
- const result = await this.syncDepsFn({
589
- onOutput: (stream, data) => this.forwardSetupOutput(stream, data),
590
- signal: this.abortController.signal
591
- });
592
- if (result.outcome !== "failed" || this.stopped) return;
593
- this.connection.sendEvent({
594
- type: "setup_error",
595
- message: result.message ?? "Dependency install failed \u2014 the start command will fail until dependencies are installed (see pod logs)"
596
- });
597
- }
598
- /** Run the schema sync, forwarding its output as setup output so it lands in
599
- * the card's setup log. A failure is announced rather than thrown: it is the
600
- * exact condition that used to render as a silent "Displaying 0 results". */
601
- async syncDbSchema() {
602
- const outcome = await this.syncDbSchemaFn({
603
- onOutput: (stream, data) => this.forwardSetupOutput(stream, data),
604
- signal: this.abortController.signal
605
- });
606
- if (outcome !== "failed" || this.stopped) return;
607
- this.connection.sendEvent({
608
- type: "setup_error",
609
- message: "Database schema sync failed \u2014 the app may error on queries touching recently added columns (see pod logs)"
610
- });
611
- }
612
- restartStartCommand() {
613
- if (this.stopped || !this.config?.startCommand) return;
614
- this.connection.sendEvent({
615
- type: "start_command_output",
616
- stream: "stdout",
617
- data: "[conveyor-agent] Restarting start command...\n"
618
- });
619
- void this.enqueueStartCommandReplacement(this.config.startCommand);
620
- }
621
- async ensureStartCommandLaunched(command) {
622
- if (!this.startCommandLaunchRequested) {
623
- return this.enqueueStartCommandReplacement(command);
624
- }
625
- await this.startCommandQueue;
626
- return !this.stopped && this.liveStartCommandChildren.size > 0;
627
- }
628
- enqueueStartCommandReplacement(command) {
629
- this.startCommandLaunchRequested = true;
630
- const operation = this.startCommandQueue.then(async () => {
631
- if (this.stopped) return false;
632
- await this.terminateAllStartCommands();
633
- if (this.stopped) return false;
634
- return this.launchStartCommand(command);
635
- });
636
- this.startCommandQueue = operation.then(
637
- () => void 0,
638
- () => void 0
639
- );
640
- return operation;
641
- }
642
- launchStartCommand(command) {
643
- if (this.stopped) return false;
644
- this.connection.sendEvent({ type: "start_command_started" });
645
- try {
646
- const child = this.runStartCommandFn(command, this.workspaceDir, (stream, data) => {
647
- if (this.stopped) return;
648
- this.connection.sendEvent({ type: "start_command_output", stream, data });
649
- this.writeOutput(stream, data);
650
- });
651
- this.liveStartCommandChildren.add(child);
652
- const ended = new Promise((resolve) => {
653
- this.resolveStartCommandEnd.set(child, resolve);
654
- });
655
- this.startCommandEndPromises.set(child, ended);
656
- if (this.stopped) {
657
- void this.terminateStartCommandChild(child);
658
- return false;
659
- }
660
- this.startCommandChild = child;
661
- child.on("exit", (code, signal) => {
662
- if (this.startCommandChild === child) this.startCommandChild = null;
663
- this.liveStartCommandChildren.delete(child);
664
- this.settleStartCommandEnd(child);
665
- if (this.stopped || this.expectedStartCommandStops.has(child)) return;
666
- const message = `start command exited${code === null ? "" : ` with code ${code}`}${signal ? ` (signal: ${signal})` : ""}`;
667
- this.connection.sendEvent({ type: "start_command_exited", code, signal, message });
668
- if (code !== null && code !== 0) {
669
- this.connection.sendEvent({
670
- type: "start_command_error",
671
- message: `start command exited with code ${code}${signal ? ` (signal: ${signal})` : ""}`
672
- });
673
- }
674
- });
675
- child.on("error", (error) => {
676
- if (child.pid === void 0) {
677
- if (this.startCommandChild === child) this.startCommandChild = null;
678
- this.liveStartCommandChildren.delete(child);
679
- this.settleStartCommandEnd(child);
680
- this.startCommandTerminations.delete(child);
681
- }
682
- if (this.stopped) return;
683
- this.connection.sendEvent({ type: "start_command_error", message: error.message });
684
- });
685
- return true;
686
- } catch (error) {
687
- if (!this.stopped) {
688
- this.connection.sendEvent({
689
- type: "start_command_error",
690
- message: error instanceof Error ? error.message : String(error)
691
- });
692
- }
693
- return false;
694
- }
695
- }
696
- terminateStartCommandChild(child) {
697
- const existing = this.startCommandTerminations.get(child);
698
- if (existing) return existing;
699
- this.expectedStartCommandStops.add(child);
700
- const processTermination = Promise.resolve(this.terminateStartCommand(child));
701
- const ended = this.startCommandEndPromises.get(child);
702
- const termination = (ended ? Promise.race([processTermination, ended]) : processTermination).then(() => void 0).finally(() => this.startCommandTerminations.delete(child));
703
- this.startCommandTerminations.set(child, termination);
704
- return termination;
705
- }
706
- async terminateAllStartCommands() {
707
- const live = [...this.liveStartCommandChildren].filter((child) => child.exitCode === null);
708
- await Promise.all(live.map((child) => this.terminateStartCommandChild(child)));
709
- }
710
- settleStartCommandEnd(child) {
711
- this.resolveStartCommandEnd.get(child)?.();
712
- this.resolveStartCommandEnd.delete(child);
713
- this.startCommandEndPromises.delete(child);
714
- }
715
- trackBackgroundTask(task) {
716
- this.backgroundTasks.add(task);
717
- void task.finally(() => this.backgroundTasks.delete(task));
718
- }
719
- forwardSetupOutput(stream, data) {
720
- if (this.stopped) return;
721
- this.connection.sendEvent({ type: "setup_output", stream, data });
722
- this.writeOutput(stream, data);
723
- }
724
- reportUnexpectedError(error) {
725
- if (this.stopped) return;
726
- this.connection.sendEvent({
727
- type: "setup_error",
728
- message: error instanceof Error ? error.message : String(error)
729
- });
730
- }
731
- };
732
-
733
58
  // src/utils/session-identity.ts
734
59
  async function checkSessionTaskIdentity(params) {
735
60
  const { sessionId, taskId, fetchSessionTaskId, logger: logger6 } = params;
@@ -929,7 +254,7 @@ var ProjectSessionRunner = class {
929
254
 
930
255
  // src/usage/multi-key-probe.ts
931
256
  import { mkdtemp, writeFile, copyFile, rm } from "fs/promises";
932
- import { join as join3 } from "path";
257
+ import { join } from "path";
933
258
  var logger = createServiceLogger("multi-key-probe");
934
259
  function gaugesToSamples(stdout) {
935
260
  const { sessionUsage, weeklyUsage, sessionResetsAt, weeklyResetsAt, gauges } = parseUsageGauges(stdout);
@@ -957,12 +282,12 @@ function gaugesToSamples(stdout) {
957
282
  async function isolatedProbe(token, now) {
958
283
  let dir = null;
959
284
  try {
960
- dir = await mkdtemp(join3(sessionTempBase(), "conveyor-usage-"));
961
- await writeFile(join3(dir, ".credentials.json"), buildSynthesizedCredentials(token, now), {
285
+ dir = await mkdtemp(join(sessionTempBase(), "conveyor-usage-"));
286
+ await writeFile(join(dir, ".credentials.json"), buildSynthesizedCredentials(token, now), {
962
287
  encoding: "utf8",
963
288
  mode: 384
964
289
  });
965
- await copyFile(claudeJsonPath(), join3(dir, ".claude.json")).catch(() => {
290
+ await copyFile(claudeJsonPath(), join(dir, ".claude.json")).catch(() => {
966
291
  });
967
292
  return await runUsageProbe({ env: { ...process.env, CLAUDE_CONFIG_DIR: dir } });
968
293
  } catch (error) {
@@ -1715,7 +1040,7 @@ function hostsSpawnedChildren(mode) {
1715
1040
 
1716
1041
  // src/cli.ts
1717
1042
  if (process.argv[2] === "boot") {
1718
- const { runBoot } = await import("./boot-PKHZUDAC.js");
1043
+ const { runBoot } = await import("./boot-ZNL7X5LQ.js");
1719
1044
  process.exit(await runBoot(process.argv.slice(3)));
1720
1045
  }
1721
1046
  if (isLegacyEntrypointLaunch(process.env)) {
@@ -1724,8 +1049,8 @@ if (isLegacyEntrypointLaunch(process.env)) {
1724
1049
  process.exit(1);
1725
1050
  }
1726
1051
  if (process.argv.includes("--version")) {
1727
- const __dirname = dirname2(fileURLToPath(import.meta.url));
1728
- const pkgPath = join4(__dirname, "..", "package.json");
1052
+ const __dirname = dirname(fileURLToPath(import.meta.url));
1053
+ const pkgPath = join2(__dirname, "..", "package.json");
1729
1054
  const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
1730
1055
  process.stdout.write(pkg.version + "\n");
1731
1056
  process.exit(0);
@@ -1817,7 +1142,7 @@ process.on("unhandledRejection", (reason) => {
1817
1142
  process.exit(1);
1818
1143
  });
1819
1144
  if (process.env.CONVEYOR_MODE === "workbench") {
1820
- const { startWorkbenchServer } = await import("./server-CC7KUJOK.js");
1145
+ const { startWorkbenchServer } = await import("./server-7XH7RYUX.js");
1821
1146
  const { oomWatchdogOptionsFromEnv } = await import("./oom-watchdog-PAC5OJJG.js");
1822
1147
  const { DEFAULT_WORKBENCH_PORT } = await import("./protocol-QBCYO4GI.js");
1823
1148
  const port = Number(process.env.CONVEYOR_WORKBENCH_PORT) || DEFAULT_WORKBENCH_PORT;
@@ -1826,8 +1151,8 @@ if (process.env.CONVEYOR_MODE === "workbench") {
1826
1151
  logger5.error("workbench mode requires POD_BOOTSTRAP_TOKEN (or CONVEYOR_WORKBENCH_TOKEN)");
1827
1152
  process.exit(1);
1828
1153
  }
1829
- const pkgDir = dirname2(fileURLToPath(import.meta.url));
1830
- const pkg = JSON.parse(readFileSync(join4(pkgDir, "..", "package.json"), "utf-8"));
1154
+ const pkgDir = dirname(fileURLToPath(import.meta.url));
1155
+ const pkg = JSON.parse(readFileSync(join2(pkgDir, "..", "package.json"), "utf-8"));
1831
1156
  const handle = await startWorkbenchServer({
1832
1157
  port,
1833
1158
  token,
@@ -1962,13 +1287,31 @@ if (!CONVEYOR_TASK_TOKEN || !CONVEYOR_TASK_ID) {
1962
1287
  );
1963
1288
  process.exit(1);
1964
1289
  }
1965
- if (CONVEYOR_MODE !== "task" && CONVEYOR_MODE !== "pm" && CONVEYOR_MODE !== "code-review" && CONVEYOR_MODE !== "adhoc" && CONVEYOR_MODE !== "pack" && CONVEYOR_MODE !== "shell") {
1290
+ if (CONVEYOR_MODE !== "task" && CONVEYOR_MODE !== "pm" && CONVEYOR_MODE !== "code-review" && CONVEYOR_MODE !== "adhoc" && CONVEYOR_MODE !== "pack" && CONVEYOR_MODE !== "shell" && CONVEYOR_MODE !== "serving") {
1966
1291
  logger5.error("Invalid CONVEYOR_MODE", {
1967
1292
  mode: CONVEYOR_MODE,
1968
- expected: ["task", "pm", "code-review", "adhoc", "pack", "shell"]
1293
+ expected: ["task", "pm", "code-review", "adhoc", "pack", "shell", "serving"]
1969
1294
  });
1970
1295
  process.exit(1);
1971
1296
  }
1297
+ if (CONVEYOR_MODE === "serving") {
1298
+ const { runServingSession } = await import("./serve-boot-4N3FRXVQ.js");
1299
+ exitContext.runnerMode = "serving";
1300
+ exitContext.sessionId = process.env.CONVEYOR_SESSION_ID ?? exitContext.sessionId;
1301
+ const outcome = await runServingSession({
1302
+ apiUrl: conveyorApiUrl ?? "",
1303
+ taskToken: CONVEYOR_TASK_TOKEN,
1304
+ sessionId: process.env.CONVEYOR_SESSION_ID,
1305
+ taskId: CONVEYOR_TASK_ID,
1306
+ workspaceDir: CONVEYOR_WORKSPACE,
1307
+ // BRANCH is the bundle gitPlan's branch (boot/bundle.ts buildChildEnv):
1308
+ // the branch the preview must check out and serve.
1309
+ branch: process.env.BRANCH,
1310
+ onSignal: () => void (shuttingDown = true)
1311
+ });
1312
+ logAgentExit(outcome.reason, { exitCode: outcome.exitCode, finalState: outcome.finalState });
1313
+ process.exit(outcome.exitCode);
1314
+ }
1972
1315
  if (CONVEYOR_MODE === "shell" || CONVEYOR_MODE === "adhoc") {
1973
1316
  const spawnedSessionId = process.env.CONVEYOR_SESSION_ID;
1974
1317
  if (!spawnedSessionId) {