@rallycry/conveyor-agent 11.0.2 → 11.0.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.
@@ -5,21 +5,21 @@ import {
5
5
  readWorkspaceBytes,
6
6
  statWorkspacePath,
7
7
  workspacePathExists
8
- } from "./chunk-N4WSUTGV.js";
8
+ } from "./chunk-SLUBOIYE.js";
9
9
  import {
10
10
  reportBootMilestone
11
11
  } from "./chunk-GL2DIQEQ.js";
12
+ import {
13
+ runSetupCommand,
14
+ runStartCommand,
15
+ terminateProcessGroup
16
+ } from "./chunk-W4LZ7R6Z.js";
12
17
  import {
13
18
  getWorkbenchClient
14
19
  } from "./chunk-EXQ6AHOY.js";
15
20
  import {
16
21
  workbenchEnabled
17
22
  } from "./chunk-KMB3BU4S.js";
18
- import {
19
- runSetupCommand,
20
- runStartCommand,
21
- terminateProcessGroup
22
- } from "./chunk-W4LZ7R6Z.js";
23
23
 
24
24
  // src/setup/db-schema-sync.ts
25
25
  import { basename, dirname, join } from "path";
@@ -226,6 +226,30 @@ async function runDepsSync(options) {
226
226
  }
227
227
  }
228
228
 
229
+ // src/setup/turbo-cache-diagnostic.ts
230
+ import { join as join3 } from "path";
231
+ var TURBO_CACHE_ENV_VARS = [
232
+ "TURBO_API",
233
+ "TURBO_TOKEN",
234
+ "TURBO_TEAM",
235
+ "TURBO_REMOTE_CACHE_SIGNATURE_KEY"
236
+ ];
237
+ function describeTurboCacheEnv(env) {
238
+ const missing = TURBO_CACHE_ENV_VARS.filter((name) => !env[name]?.trim());
239
+ if (missing.length === 0) return "[turbo-cache] remote cache: configured";
240
+ return `[turbo-cache] remote cache: absent (missing ${missing.join(", ")}) \u2014 gates run turbo-cold; set the TURBO_* project secrets to restore remote cache hits`;
241
+ }
242
+ async function reportTurboCacheEnv(options) {
243
+ const pathExists = options.pathExists ?? workspacePathExists;
244
+ try {
245
+ if (!await pathExists(join3(options.workspaceDir, "turbo.json"))) return;
246
+ } catch {
247
+ return;
248
+ }
249
+ options.onOutput("stdout", `${describeTurboCacheEnv(options.env)}
250
+ `);
251
+ }
252
+
229
253
  // src/setup/sidecars.ts
230
254
  import net from "net";
231
255
  var POSTGRES_TIMEOUT_MS = 12e4;
@@ -409,6 +433,7 @@ var WorkspaceCommandSupervisor = class {
409
433
  runStartCommandFn;
410
434
  syncDbSchemaFn;
411
435
  syncDepsFn;
436
+ reportTurboCacheFn;
412
437
  loadForwardPortsFn;
413
438
  writeOutput;
414
439
  terminateStartCommand;
@@ -461,6 +486,11 @@ var WorkspaceCommandSupervisor = class {
461
486
  onOutput: opts.onOutput,
462
487
  signal: opts.signal
463
488
  }));
489
+ this.reportTurboCacheFn = options.reportTurboCache ?? ((opts) => reportTurboCacheEnv({
490
+ workspaceDir: this.workspaceDir,
491
+ env: this.env,
492
+ onOutput: opts.onOutput
493
+ }));
464
494
  this.loadForwardPortsFn = options.loadForwardPorts ?? loadForwardPorts;
465
495
  this.writeOutput = options.writeOutput ?? defaultWriteOutput;
466
496
  this.terminateStartCommand = options.terminateStartCommand ?? terminateProcessGroup;
@@ -521,6 +551,10 @@ var WorkspaceCommandSupervisor = class {
521
551
  this.reportBootMilestoneFn("sidecars_ready");
522
552
  await this.loopReady;
523
553
  if (this.stopped) return;
554
+ await this.reportTurboCacheFn({
555
+ onOutput: (stream, data) => this.forwardSetupOutput(stream, data)
556
+ });
557
+ if (this.stopped) return;
524
558
  await this.syncDeps();
525
559
  if (this.stopped) return;
526
560
  await this.syncDbSchema();
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  WorkspaceCommandSupervisor,
8
8
  startWorkspaceCommandsAfterConnect,
9
9
  stopWorkspaceCommands
10
- } from "./chunk-JQVAWRVL.js";
10
+ } from "./chunk-URYBO32C.js";
11
11
  import {
12
12
  DEFAULT_SONNET_MODEL,
13
13
  PtyHarness,
@@ -27,8 +27,13 @@ import {
27
27
  resolveTuiKindFromEnv,
28
28
  runUsageProbe,
29
29
  sampleKeyUsage
30
- } from "./chunk-QETNCXIR.js";
30
+ } from "./chunk-HYPX6FEX.js";
31
31
  import "./chunk-XORJ6SII.js";
32
+ import {
33
+ inheritedEnv,
34
+ resolvePtySpawn,
35
+ sessionTempBase
36
+ } from "./chunk-3F4ZZKCA.js";
32
37
  import {
33
38
  AgentConnection,
34
39
  CodespacePortVisibility,
@@ -39,17 +44,13 @@ import {
39
44
  createServiceLogger,
40
45
  fetchBootstrap,
41
46
  loadConveyorConfig
42
- } from "./chunk-N4WSUTGV.js";
47
+ } from "./chunk-SLUBOIYE.js";
43
48
  import "./chunk-GL2DIQEQ.js";
49
+ import "./chunk-W4LZ7R6Z.js";
50
+ import "./chunk-7P6QZHXZ.js";
44
51
  import "./chunk-IA45XHOA.js";
45
52
  import "./chunk-EXQ6AHOY.js";
46
53
  import "./chunk-KMB3BU4S.js";
47
- import {
48
- inheritedEnv,
49
- resolvePtySpawn,
50
- sessionTempBase
51
- } from "./chunk-3F4ZZKCA.js";
52
- import "./chunk-W4LZ7R6Z.js";
53
54
  import "./chunk-6Q6LQBWO.js";
54
55
 
55
56
  // src/cli.ts
@@ -237,7 +238,10 @@ var ProjectSessionRunner = class {
237
238
  async sampleAndReportKeyUsage() {
238
239
  if (this.stopped) return;
239
240
  const codingAgentKeyId = process.env.CONVEYOR_CODING_AGENT_KEY_ID;
240
- const { samples, unmeasurable } = await sampleKeyUsage(process.env.CLAUDE_CODE_OAUTH_TOKEN);
241
+ const { samples, unmeasurable } = await sampleKeyUsage(
242
+ process.env.CLAUDE_CODE_OAUTH_TOKEN,
243
+ () => runUsageProbe({ cwd: this.config.workspaceDir })
244
+ );
241
245
  if (unmeasurable) {
242
246
  this.connection.sendEvent(buildUnmeasurableEvent(unmeasurable.reason, codingAgentKeyId));
243
247
  return;
@@ -281,7 +285,7 @@ function gaugesToSamples(stdout) {
281
285
  }
282
286
  return samples;
283
287
  }
284
- async function isolatedProbe(token, now) {
288
+ async function isolatedProbe(token, now, cwd) {
285
289
  let dir = null;
286
290
  try {
287
291
  dir = await mkdtemp(join(sessionTempBase(), "conveyor-usage-"));
@@ -291,7 +295,7 @@ async function isolatedProbe(token, now) {
291
295
  });
292
296
  await copyFile(claudeJsonPath(), join(dir, ".claude.json")).catch(() => {
293
297
  });
294
- return await runUsageProbe({ env: { ...process.env, CLAUDE_CONFIG_DIR: dir } });
298
+ return await runUsageProbe({ cwd, env: { ...process.env, CLAUDE_CONFIG_DIR: dir } });
295
299
  } catch (error) {
296
300
  logger.info("isolated usage probe failed", {
297
301
  error: error instanceof Error ? error.message : String(error)
@@ -304,7 +308,7 @@ async function isolatedProbe(token, now) {
304
308
  }
305
309
  async function probeKeysUsage(keys, deps = {}) {
306
310
  const now = deps.now ?? Date.now;
307
- const probeOne = deps.probeOne ?? ((token) => isolatedProbe(token, now()));
311
+ const probeOne = deps.probeOne ?? ((token) => isolatedProbe(token, now(), deps.cwd));
308
312
  const results = [];
309
313
  for (const key of keys) {
310
314
  if (!key.oauthToken) continue;
@@ -558,7 +562,7 @@ var AdhocSessionRunner = class {
558
562
  await this.sampleAndReportOwnKey();
559
563
  return;
560
564
  }
561
- const probed = await probeKeysUsage(keys);
565
+ const probed = await probeKeysUsage(keys, { cwd: this.config.workspaceDir });
562
566
  for (const { codingAgentKeyId, samples } of probed) {
563
567
  for (const event of buildRateLimitEvents(samples, codingAgentKeyId)) {
564
568
  this.connection.sendEvent(event);
@@ -569,7 +573,10 @@ var AdhocSessionRunner = class {
569
573
  async sampleAndReportOwnKey() {
570
574
  if (this.stopped) return;
571
575
  const codingAgentKeyId = process.env.CONVEYOR_CODING_AGENT_KEY_ID;
572
- const { samples, unmeasurable } = await sampleKeyUsage(process.env.CLAUDE_CODE_OAUTH_TOKEN);
576
+ const { samples, unmeasurable } = await sampleKeyUsage(
577
+ process.env.CLAUDE_CODE_OAUTH_TOKEN,
578
+ () => runUsageProbe({ cwd: this.config.workspaceDir })
579
+ );
573
580
  if (unmeasurable) {
574
581
  this.connection.sendEvent(buildUnmeasurableEvent(unmeasurable.reason, codingAgentKeyId));
575
582
  return;
@@ -1194,7 +1201,7 @@ function wireSpawnChildren(mode, connection, supervisors, logger7) {
1194
1201
 
1195
1202
  // src/cli.ts
1196
1203
  if (process.argv[2] === "boot") {
1197
- const { runBoot } = await import("./boot-PKQ2I66D.js");
1204
+ const { runBoot } = await import("./boot-SWUVT5B4.js");
1198
1205
  process.exit(await runBoot(process.argv.slice(3)));
1199
1206
  }
1200
1207
  if (isLegacyEntrypointLaunch(process.env)) {
@@ -1398,6 +1405,7 @@ if (!CONVEYOR_TASK_ID && projectIdentity) {
1398
1405
  runnerMode: "pm"
1399
1406
  },
1400
1407
  projectId: projectIdentity.projectId,
1408
+ workspaceDir: CONVEYOR_WORKSPACE,
1401
1409
  // Same extended idle window claudespace task pods get.
1402
1410
  ...process.env.CLAUDESPACE_NAME ? { lifecycle: { idleTimeoutMs: 60 * 60 * 1e3 } } : {}
1403
1411
  },
@@ -1446,7 +1454,7 @@ if (!RUNNER_MODES.includes(CONVEYOR_MODE)) {
1446
1454
  process.exit(1);
1447
1455
  }
1448
1456
  if (CONVEYOR_MODE === "serving") {
1449
- const { runServingSession } = await import("./serve-boot-YPAUKENG.js");
1457
+ const { runServingSession } = await import("./serve-boot-B4BIZMNB.js");
1450
1458
  exitContext.runnerMode = "serving";
1451
1459
  exitContext.sessionId = process.env.CONVEYOR_SESSION_ID ?? exitContext.sessionId;
1452
1460
  const outcome = await runServingSession({
@@ -0,0 +1 @@
1
+ #!/usr/bin/env node
@@ -0,0 +1,85 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ gatesDir
4
+ } from "./chunk-7P6QZHXZ.js";
5
+
6
+ // src/runner/gate-wrapper.ts
7
+ import { mkdirSync, rmSync, writeFileSync } from "fs";
8
+ import { constants as osConstants } from "os";
9
+ import path from "path";
10
+ import { spawn } from "child_process";
11
+ var LABEL_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
12
+ function parseGateArgs(argv) {
13
+ const usage = "usage: conveyor-gate <label> -- <cmd> [args\u2026]";
14
+ const [label, separator, command, ...args] = argv;
15
+ if (!label || separator !== "--" || !command) throw new Error(usage);
16
+ if (!LABEL_RE.test(label)) {
17
+ throw new Error(`invalid gate label '${label}' \u2014 use letters, digits, '.', '_', '-'`);
18
+ }
19
+ return { label, command, args };
20
+ }
21
+ function exitCodeFor(code, signal) {
22
+ if (code !== null) return code;
23
+ if (signal) {
24
+ const num = osConstants.signals[signal];
25
+ if (typeof num === "number") return 128 + num;
26
+ }
27
+ return 1;
28
+ }
29
+ var FORWARDED_SIGNALS = ["SIGTERM", "SIGINT", "SIGHUP"];
30
+ function runGate(argv, options = {}) {
31
+ const log = options.log ?? ((message) => process.stderr.write(message));
32
+ const { label, command, args } = parseGateArgs(argv);
33
+ const dir = gatesDir();
34
+ mkdirSync(dir, { recursive: true });
35
+ const pidFile = path.join(dir, `${label}.pid`);
36
+ const exitFile = path.join(dir, `${label}.exit`);
37
+ rmSync(exitFile, { force: true });
38
+ return new Promise((resolve) => {
39
+ const child = spawn(command, args, { stdio: "inherit" });
40
+ const forward = (signal) => {
41
+ child.kill(signal);
42
+ };
43
+ const listeners = FORWARDED_SIGNALS.map((signal) => {
44
+ const listener = () => forward(signal);
45
+ process.on(signal, listener);
46
+ return { signal, listener };
47
+ });
48
+ const finish = (code) => {
49
+ for (const { signal, listener } of listeners) process.removeListener(signal, listener);
50
+ try {
51
+ writeFileSync(exitFile, `${JSON.stringify({ code, finishedAtMs: Date.now() })}
52
+ `);
53
+ } catch (error) {
54
+ log(`[conveyor-gate] failed to write ${exitFile}: ${String(error)}
55
+ `);
56
+ }
57
+ rmSync(pidFile, { force: true });
58
+ resolve(code);
59
+ };
60
+ child.once("error", (error) => {
61
+ log(`[conveyor-gate] failed to run ${command}: ${error.message}
62
+ `);
63
+ finish(127);
64
+ });
65
+ child.once("exit", (code, signal) => finish(exitCodeFor(code, signal)));
66
+ if (child.pid !== void 0) {
67
+ try {
68
+ writeFileSync(pidFile, `${child.pid}
69
+ `);
70
+ } catch (error) {
71
+ log(`[conveyor-gate] failed to write ${pidFile}: ${String(error)}
72
+ `);
73
+ }
74
+ }
75
+ });
76
+ }
77
+
78
+ // src/gate-cli.ts
79
+ try {
80
+ process.exitCode = await runGate(process.argv.slice(2));
81
+ } catch (error) {
82
+ process.stderr.write(`conveyor-gate: ${error instanceof Error ? error.message : String(error)}
83
+ `);
84
+ process.exitCode = 2;
85
+ }
package/dist/index.d.ts CHANGED
@@ -758,6 +758,53 @@ declare class SessionRunner {
758
758
  * live build costs work.
759
759
  */
760
760
  private deferShutdownForLiveChild;
761
+ /** Epoch ms of the first idle-shutdown deferral for background work in the
762
+ * current idle episode; null when nothing has deferred. Reset when a turn
763
+ * runs, so each idle episode gets its own bounded hold. */
764
+ private backgroundDeferStartedAt;
765
+ /**
766
+ * Suppress an idle shutdown while backgrounded work (`run_in_background`
767
+ * launches tracked by `BackgroundWorkTracker`) or a live gate process
768
+ * (`isHeavyGateActive` — singleton pidfiles plus the `conveyor-gate`
769
+ * contract dir) is still running. Without this the 30-minute idle timeout
770
+ * stopped the runner mid-gate: `shutdown()` cleared the tracker, heartbeats
771
+ * stopped, the activity clock expired, and the reconciler slept the pod and
772
+ * reverted the card to Open.
773
+ *
774
+ * Bounded: deferrals past the first one cap at `BACKGROUND_WORK_MAX_MS`, so
775
+ * a wedged gate process cannot pin a pod forever. Only the IDLE timeout is
776
+ * deferred — post-`completed` dormancy keeps today's behavior, and a parked
777
+ * prefill (`waiting_for_input`) contributes nothing here, so those cards
778
+ * still sleep on the ordinary window.
779
+ */
780
+ private deferShutdownForBackgroundWork;
781
+ /** When orphan evidence (tracked work pending, no live gate process) began
782
+ * holding continuously; null while the evidence is absent. */
783
+ private orphanGraceStartedAt;
784
+ /** One-shot latch: at most one watchdog wake per idle episode. Reset when a
785
+ * turn runs. */
786
+ private backgroundWakeFiredThisIdle;
787
+ /** When the current idle episode began — an exit sentinel older than this
788
+ * appeared while a turn could still have consumed it, so it never wakes. */
789
+ private idleEpisodeStartedAt;
790
+ /**
791
+ * Wake a parked agent whose background work finished — or died — without a
792
+ * consumed completion callback. Completion normally arrives as the CLI's
793
+ * `<task-notification>` transcript record; when that record is lost (SDK
794
+ * harness, torn transcript, a gate killed out from under the CLI) the
795
+ * tracker entry silently expires and the agent waits forever.
796
+ *
797
+ * This is NOT the removed auto-mode stuck-nudge: it fires only on positive
798
+ * evidence of orphaned background work — a tracked launch with no live gate
799
+ * process continuously past `ORPHAN_WAKE_GRACE_MS`, or an unconsumed
800
+ * `gates/<label>.exit` sentinel that appeared this idle episode — never on
801
+ * "the agent seems stuck". A `completed` agent is never woken (the
802
+ * completion guard holds), and a live pid always suppresses the wake.
803
+ */
804
+ private maybeWakeForOrphanedBackgroundWork;
805
+ /** Orphan evidence that has held past the grace, or null. Maintains the
806
+ * grace clock for the tracked-work condition as a side effect. */
807
+ private findOrphanEvidence;
761
808
  get sessionId(): string;
762
809
  get isStopped(): boolean;
763
810
  /** Wire the boot supervisor handle post-construction — cli.ts constructs it
@@ -802,18 +849,41 @@ declare class SessionRunner {
802
849
  /** Returns true if an initial query was executed, false otherwise. */
803
850
  private executeInitialMode;
804
851
  /**
805
- * The mid-turn wedge watchdog aborts a turn that produced no events for 30
806
- * minutes. Its documented recovery — "the next message respawns with
807
- * `--resume`" — assumes a human or a follow-up is coming, which is exactly
808
- * what an autonomous card does NOT have: after the abort the runner goes
809
- * idle and the card parks until a pack watchdog or a human notices.
852
+ * The mid-turn watchdog aborts a turn that produced no events for 30 minutes
853
+ * (or one whose config-home mount died). Its documented recovery — "the next
854
+ * message respawns with `--resume`" — assumes a human or a follow-up is
855
+ * coming. A KICKOFF turn has neither by construction: it is the turn that
856
+ * starts the conversation, so there is no next message, and the runner goes
857
+ * idle with the card parked until a human notices.
858
+ *
859
+ * Observed live 2026-08-28 (card cmtd78iql): a spawned builder child's
860
+ * kickoff turn produced nothing for 30 minutes, was aborted, and the child
861
+ * then heartbeated idle for another 43 minutes until a human typed
862
+ * "@[agent:builder] continue".
863
+ *
864
+ * So any submit-delivery INITIAL query killed by the watchdog is re-run once
865
+ * against the (durable, on-disk) resumed session. Bounded to a single retry:
866
+ * a second wedge is a real failure that should surface as a parked card
867
+ * rather than loop the pod.
868
+ *
869
+ * Nothing recovers a card from there automatically, and that is the honest
870
+ * state of it. The server's session sweep does NOT catch this shape: its
871
+ * predicate is `agentRunningAt` still null, and a turn that started and then
872
+ * wedged has already stamped it. The sweep covers a builder that never took a
873
+ * turn at all; this retry covers one whose first turn stalled. Twice-wedged
874
+ * needs a human, and a card left that way keeps its Builder tab and its
875
+ * heartbeat, so it is visible rather than silently gone.
876
+ *
877
+ * Skipped when a pending message already exists, because the core loop
878
+ * delivers that instead, which is the path the watchdog's original recovery
879
+ * assumed.
880
+ *
881
+ * A mount-death abort retries too, and must: the repair for a dead config
882
+ * home is the respawn that follows the abort, so a kickoff with nothing
883
+ * behind it would otherwise never get one.
810
884
  *
811
- * So for an autonomous card whose INITIAL query was killed as wedged, re-run
812
- * that initial query once against the (durable, on-disk) resumed session.
813
- * Bounded to a single retry: a second wedge is a real failure that should
814
- * surface as a parked card rather than loop the pod. Skipped when a pending
815
- * message already exists — the core loop delivers that instead, which is the
816
- * path the watchdog's original recovery assumed.
885
+ * NOT for follow-up turns there "the conversation resumes on the next
886
+ * message" is exactly right.
817
887
  */
818
888
  private requeueWedgedInitialQuery;
819
889
  /**
@@ -957,6 +1027,8 @@ declare class SessionRunner {
957
1027
  private _finalState;
958
1028
  /** The final status after run() completes. Use to determine exit code. */
959
1029
  get finalState(): AgentRunnerStatus | null;
1030
+ /** Does a transcript already exist for this session's lineage? */
1031
+ private resolvesToTranscriptResume;
960
1032
  private buildTaskContextSnapshot;
961
1033
  private buildInitializationContext;
962
1034
  private logInitialization;
package/dist/index.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import {
2
2
  SessionRunner,
3
3
  unshallowRepo
4
- } from "./chunk-QETNCXIR.js";
4
+ } from "./chunk-HYPX6FEX.js";
5
5
  import "./chunk-XORJ6SII.js";
6
+ import "./chunk-3F4ZZKCA.js";
6
7
  import {
7
8
  AgentConnection,
8
9
  GIT_TIMEOUT_MS,
@@ -16,8 +17,14 @@ import {
16
17
  stageAndCommit,
17
18
  updateRemoteToken,
18
19
  workspacePathExists
19
- } from "./chunk-N4WSUTGV.js";
20
+ } from "./chunk-SLUBOIYE.js";
20
21
  import "./chunk-GL2DIQEQ.js";
22
+ import {
23
+ runAuthTokenCommand,
24
+ runSetupCommand,
25
+ runStartCommand
26
+ } from "./chunk-W4LZ7R6Z.js";
27
+ import "./chunk-7P6QZHXZ.js";
21
28
  import "./chunk-IA45XHOA.js";
22
29
  import {
23
30
  getWorkbenchClient
@@ -25,12 +32,6 @@ import {
25
32
  import {
26
33
  workbenchEnabled
27
34
  } from "./chunk-KMB3BU4S.js";
28
- import "./chunk-3F4ZZKCA.js";
29
- import {
30
- runAuthTokenCommand,
31
- runSetupCommand,
32
- runStartCommand
33
- } from "./chunk-W4LZ7R6Z.js";
34
35
  import "./chunk-6Q6LQBWO.js";
35
36
 
36
37
  // src/runner/worktree.ts
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  WorkspaceCommandSupervisor
3
- } from "./chunk-JQVAWRVL.js";
3
+ } from "./chunk-URYBO32C.js";
4
4
  import {
5
5
  AgentConnection,
6
6
  CodespacePortVisibility,
@@ -11,12 +11,12 @@ import {
11
11
  createServiceLogger,
12
12
  ensureOnTaskBranch,
13
13
  loadConveyorConfig
14
- } from "./chunk-N4WSUTGV.js";
14
+ } from "./chunk-SLUBOIYE.js";
15
15
  import "./chunk-GL2DIQEQ.js";
16
+ import "./chunk-W4LZ7R6Z.js";
16
17
  import "./chunk-IA45XHOA.js";
17
18
  import "./chunk-EXQ6AHOY.js";
18
19
  import "./chunk-KMB3BU4S.js";
19
- import "./chunk-W4LZ7R6Z.js";
20
20
  import "./chunk-6Q6LQBWO.js";
21
21
 
22
22
  // src/runner/serve-session-runner.ts
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rallycry/conveyor-agent",
3
- "version": "11.0.2",
3
+ "version": "11.0.4",
4
4
  "description": "Conveyor Agent Runner v10 - PTY harness for the task chat (SDK harness for audit/project-chat). Agent-as-User architecture with BaseService patterns. Works locally too.",
5
5
  "keywords": [
6
6
  "agent",
@@ -11,7 +11,8 @@
11
11
  ],
12
12
  "license": "MIT",
13
13
  "bin": {
14
- "conveyor-agent": "dist/cli.js"
14
+ "conveyor-agent": "dist/cli.js",
15
+ "conveyor-gate": "dist/gate-cli.js"
15
16
  },
16
17
  "files": [
17
18
  "dist",
@@ -149,6 +149,16 @@ and never silence a failure with a filter, a `.skip`, or a "known flake" note:
149
149
  either your diff broke it, or the test is broken or environment-dependent and
150
150
  you fix the test.
151
151
 
152
+ **Long gates in a pod: background them the sanctioned way.** Launch a long
153
+ gate with the harness's `run_in_background` Bash option and end the turn — the
154
+ runner tracks the launch, holds pod liveness while a gate process is alive,
155
+ and wakes you when it finishes (or if its completion callback is lost). In a
156
+ repo without Conveyor's `scripts/singleton.sh`, wrap the command in the
157
+ shipped `conveyor-gate` bin — `conveyor-gate <label> -- <cmd…>` — which writes
158
+ the same pid/exit contract under `$CONVEYOR_RUN_DIR/gates/` so the runner can
159
+ see it. Hand-rolled backgrounding (`nohup`, `&`, `disown`) is invisible to the
160
+ runner: the pod can sleep mid-run and nothing will wake you.
161
+
152
162
  **A UI-visible change needs visual proof before the PR**, in both environments:
153
163
  capture a screenshot (static) or a short recording (interaction) with the host
154
164
  repo's own tooling and attach it with `mcp__conveyor__upload_attachment`, then
@@ -1,3 +1,6 @@
1
+ import {
2
+ startWorkbenchServer
3
+ } from "./chunk-UBDSLM44.js";
1
4
  import {
2
5
  TOMBSTONE_MESSAGE,
3
6
  isLegacyEntrypointLaunch
@@ -5,6 +8,7 @@ import {
5
8
  import {
6
9
  readAgentVersion
7
10
  } from "./chunk-XORJ6SII.js";
11
+ import "./chunk-3F4ZZKCA.js";
8
12
  import {
9
13
  GitPrepJob,
10
14
  defaultGit,
@@ -12,14 +16,10 @@ import {
12
16
  redactToken,
13
17
  reportBootMilestone
14
18
  } from "./chunk-GL2DIQEQ.js";
19
+ import "./chunk-W4LZ7R6Z.js";
15
20
  import {
16
21
  workbenchPort
17
22
  } from "./chunk-KMB3BU4S.js";
18
- import {
19
- startWorkbenchServer
20
- } from "./chunk-UBDSLM44.js";
21
- import "./chunk-3F4ZZKCA.js";
22
- import "./chunk-W4LZ7R6Z.js";
23
23
  import {
24
24
  DEFAULT_WORKBENCH_PORT
25
25
  } from "./chunk-6Q6LQBWO.js";
@@ -4,6 +4,12 @@ import {
4
4
  FETCH_TIMEOUT_MS,
5
5
  GIT_PREP_MAX_RETRIES
6
6
  } from "./chunk-GL2DIQEQ.js";
7
+ import {
8
+ gitCredentialHelper,
9
+ sleep,
10
+ syncGithubTokenFiles,
11
+ writeGitCredential
12
+ } from "./chunk-W4LZ7R6Z.js";
7
13
  import {
8
14
  buildConveyorSocketOptions,
9
15
  callWithAck,
@@ -18,12 +24,6 @@ import {
18
24
  import {
19
25
  workbenchEnabled
20
26
  } from "./chunk-KMB3BU4S.js";
21
- import {
22
- gitCredentialHelper,
23
- sleep,
24
- syncGithubTokenFiles,
25
- writeGitCredential
26
- } from "./chunk-W4LZ7R6Z.js";
27
27
 
28
28
  // src/setup/bootstrap.ts
29
29
  var BOOTSTRAP_TIMEOUT_MS = 3e4;