@rallycry/conveyor-agent 11.0.46 → 11.0.48

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.
@@ -11,7 +11,7 @@ import {
11
11
  readAgentVersion,
12
12
  refreshSkillsAfterCheckout,
13
13
  runPreReadyBinds
14
- } from "./chunk-6CKFZ4JG.js";
14
+ } from "./chunk-V5WR2F2P.js";
15
15
  import "./chunk-EKTPDG3G.js";
16
16
  import {
17
17
  GitPrepJob,
@@ -491,11 +491,15 @@ async function superviseRunner(opts) {
491
491
  // src/boot/user-home.ts
492
492
  import {
493
493
  chmodSync,
494
+ closeSync,
494
495
  copyFileSync,
495
496
  existsSync,
497
+ fsyncSync,
496
498
  lstatSync,
497
499
  mkdirSync,
500
+ openSync,
498
501
  readFileSync,
502
+ readlinkSync,
499
503
  readdirSync,
500
504
  rmSync,
501
505
  statSync as statSync2,
@@ -645,7 +649,10 @@ function seedClaudeJson(targetPath) {
645
649
  let merged = config ? deepMerge(config, SEED_GATES) : { ...SEED_GATES, theme: "dark" };
646
650
  const cache = Array.isArray(merged.additionalModelOptionsCache) ? merged.additionalModelOptionsCache : [];
647
651
  if (!hasFableEntry(cache)) {
648
- merged = { ...merged, additionalModelOptionsCache: [...cache, SEED_FABLE_OPTION] };
652
+ merged = {
653
+ ...merged,
654
+ additionalModelOptionsCache: [...cache, SEED_FABLE_OPTION]
655
+ };
649
656
  }
650
657
  writeFileSync2(targetPath, JSON.stringify(merged));
651
658
  } catch {
@@ -787,12 +794,60 @@ function wireUserHome(opts) {
787
794
  "mkdir agent scratch dir",
788
795
  () => mkdirSync(opts.scratchDir ?? "/tmp/claude-cmd", { recursive: true })
789
796
  );
797
+ if (opts.required && (!userId || !projectId || !isDir(userHomeMount))) {
798
+ throw new Error("Required persistent user home is unavailable or missing claim identity");
799
+ }
790
800
  if (userId && projectId && isDir(userHomeMount)) {
791
- return wireMountedUserHome({ home, userHomeMount, userId, projectId, sharedDir, log });
801
+ if (opts.required) assertHomeWritable(join3(userHomeMount, "users", userId, projectId));
802
+ const repair = wireMountedUserHome({
803
+ home,
804
+ userHomeMount,
805
+ userId,
806
+ projectId,
807
+ sharedDir,
808
+ log
809
+ });
810
+ if (opts.required) assertHomeLinks(opts, userId, projectId);
811
+ return repair;
792
812
  }
793
813
  wireNoMountUserHome({ home, sharedDir, log });
794
814
  return Promise.resolve();
795
815
  }
816
+ function assertHomeWritable(root) {
817
+ mkdirSync(root, { recursive: true });
818
+ const probe = join3(root, `.home-ready-${process.pid}-${crypto.randomUUID()}`);
819
+ const fd = openSync(probe, "wx", 384);
820
+ try {
821
+ fsyncSync(fd);
822
+ } finally {
823
+ closeSync(fd);
824
+ rmSync(probe);
825
+ }
826
+ }
827
+ function assertHomeLinks(opts, userId, projectId) {
828
+ const root = join3(opts.userHomeMount, "users", userId, projectId);
829
+ for (const relative of [
830
+ ".claude",
831
+ ".config/claude",
832
+ ".conveyor-codex",
833
+ ".local/share/opencode",
834
+ ".config/opencode"
835
+ ]) {
836
+ const link = join3(opts.home, relative);
837
+ if (!lstatSync(link).isSymbolicLink() || readlinkSync(link) !== join3(root, relative)) {
838
+ throw new Error(`Required persistent user home link ${relative} was not wired`);
839
+ }
840
+ }
841
+ const memory = join3(root, ".claude", "projects", AGENT_MEMORY_PROJECT_DIR, "memory");
842
+ if (readlinkSync(memory) !== join3(opts.userHomeMount, "users", "_shared", "memory", projectId)) {
843
+ throw new Error("Required persistent shared memory was not wired");
844
+ }
845
+ const credentials = join3(root, ".claude", ".credentials.json");
846
+ const podLocal = opts.sharedDir ? join3(opts.sharedDir, "claude-credentials.pod.json") : join3(opts.home, ".claude-credentials.pod.json");
847
+ if (readlinkSync(credentials) !== podLocal || !isRegularFile(join3(opts.home, ".claude.json"))) {
848
+ throw new Error("Required persistent home must keep credentials and CLI config pod-local");
849
+ }
850
+ }
796
851
  var RECLAIM_FIND_TIMEOUT_MS = 1e4;
797
852
  async function reclaimHomeOwnership(home, exec, log) {
798
853
  for (const dir of [join3(home, ".config"), join3(home, ".local")]) {
@@ -824,7 +879,7 @@ async function reclaimHomeOwnership(home, exec, log) {
824
879
  }
825
880
 
826
881
  // src/boot/sshd.ts
827
- import { chmodSync as chmodSync2, closeSync, copyFileSync as copyFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, openSync } from "fs";
882
+ import { chmodSync as chmodSync2, closeSync as closeSync2, copyFileSync as copyFileSync2, existsSync as existsSync2, mkdirSync as mkdirSync2, openSync as openSync2 } from "fs";
828
883
  import { join as join4 } from "path";
829
884
  function persistedAuthorizedKeys() {
830
885
  return join4(
@@ -843,7 +898,7 @@ async function startWorkspaceSshd(exec, log, port = process.env.CONVEYOR_WORKSPA
843
898
  if (existsSync2(persisted)) {
844
899
  copyFileSync2(persisted, authorizedKeys);
845
900
  } else if (!existsSync2(authorizedKeys)) {
846
- closeSync(openSync(authorizedKeys, "a"));
901
+ closeSync2(openSync2(authorizedKeys, "a"));
847
902
  }
848
903
  chmodSync2(authorizedKeys, 384);
849
904
  } catch (err) {
@@ -919,6 +974,7 @@ function defaultWorkbenchBootDeps() {
919
974
  void wireUserHome({
920
975
  home: HOME_DIR,
921
976
  userHomeMount: USER_HOME_MOUNT,
977
+ required: process.env.CONVEYOR_USER_HOME_REQUIRED === "1",
922
978
  userId: ctx.childEnv?.CONVEYOR_USER_ID,
923
979
  projectId: ctx.childEnv?.CONVEYOR_PROJECT_ID ?? ctx.childEnv?.PROJECT_ID,
924
980
  sharedDir: process.env.CONVEYOR_SHARED_DIR,
@@ -944,7 +1000,10 @@ function warnErr(ctx, label) {
944
1000
  };
945
1001
  }
946
1002
  async function runWorkbenchBoot(ctx, overrides = {}) {
947
- const deps = { ...defaultWorkbenchBootDeps(), ...overrides };
1003
+ const deps = {
1004
+ ...defaultWorkbenchBootDeps(),
1005
+ ...overrides
1006
+ };
948
1007
  const bundle = await deps.pollBundle(ctx);
949
1008
  if (!bundle) {
950
1009
  ctx.log.info("[boot] standby poll aborted \u2014 parking for shutdown");
@@ -952,6 +1011,8 @@ async function runWorkbenchBoot(ctx, overrides = {}) {
952
1011
  }
953
1012
  ctx.bundle = bundle;
954
1013
  ctx.childEnv = deps.unpack(ctx, bundle);
1014
+ const requiredHome = process.env.CONVEYOR_USER_HOME_REQUIRED === "1";
1015
+ if (requiredHome) deps.wireHome(ctx);
955
1016
  const job = new GitPrepJob(deps.gitPrepDeps(ctx, bundle), {
956
1017
  // Order pinned by the old entrypoint-grimoire test: binds BEFORE the
957
1018
  // ready flip (Claude must not spawn before skills exist), references after.
@@ -978,10 +1039,12 @@ async function runWorkbenchBoot(ctx, overrides = {}) {
978
1039
  warnErr(ctx, "ensureWorkspaceDir")(err);
979
1040
  }
980
1041
  job.start();
981
- try {
982
- deps.wireHome(ctx);
983
- } catch (err) {
984
- warnErr(ctx, "wireUserHome")(err);
1042
+ if (!requiredHome) {
1043
+ try {
1044
+ deps.wireHome(ctx);
1045
+ } catch (err) {
1046
+ warnErr(ctx, "wireUserHome")(err);
1047
+ }
985
1048
  }
986
1049
  void deps.startSshd(ctx).catch(warnErr(ctx, "startWorkspaceSshd"));
987
1050
  void deps.reclaimOwnership(ctx).catch(warnErr(ctx, "reclaimHomeOwnership"));
@@ -1079,6 +1142,7 @@ function agentBootSteps(deps = defaultBootDeps(), signal = new AbortController()
1079
1142
  void wireUserHome({
1080
1143
  home: HOME_DIR2,
1081
1144
  userHomeMount: USER_HOME_MOUNT2,
1145
+ required: process.env.CONVEYOR_USER_HOME_REQUIRED === "1",
1082
1146
  userId: ctx.childEnv?.CONVEYOR_USER_ID,
1083
1147
  projectId: ctx.childEnv?.CONVEYOR_PROJECT_ID ?? ctx.childEnv?.PROJECT_ID,
1084
1148
  sharedDir: process.env.CONVEYOR_SHARED_DIR,
@@ -1371,7 +1371,7 @@ ${q.question}${q.options.length ? "\n" + q.options.map((o) => `- ${o.label}: ${o
1371
1371
  }
1372
1372
  };
1373
1373
 
1374
- // ../shared/dist/chunk-SFSQ7NKP.js
1374
+ // ../shared/dist/chunk-DUZLPI2K.js
1375
1375
  import { z } from "zod";
1376
1376
  import { z as z2 } from "zod";
1377
1377
  var DEFAULT_SONNET_MODEL = "claude-sonnet-5-5";
@@ -1476,7 +1476,10 @@ var actionsPrebakeRegistrySchema = z.string().trim().min(1).regex(
1476
1476
  function uniqueSortedArray(item, minimum = 0) {
1477
1477
  return z.array(item).min(minimum).superRefine((values, ctx) => {
1478
1478
  if (new Set(values).size !== values.length) {
1479
- ctx.addIssue({ code: z.ZodIssueCode.custom, message: "Duplicate values are not allowed" });
1479
+ ctx.addIssue({
1480
+ code: z.ZodIssueCode.custom,
1481
+ message: "Duplicate values are not allowed"
1482
+ });
1480
1483
  }
1481
1484
  }).transform((values) => [...values].sort());
1482
1485
  }
@@ -2627,6 +2630,13 @@ var ListProjectTasksRequestSchema = z7.object({
2627
2630
  }).refine((p) => !(p.unassigned && p.assigneeId), {
2628
2631
  message: "Pass either assigneeId or unassigned, not both"
2629
2632
  });
2633
+ var ListCardStatesRequestSchema = z7.object({
2634
+ projectId: z7.string(),
2635
+ statuses: z7.array(z7.string()).min(1).max(32),
2636
+ types: z7.array(z7.string()).optional(),
2637
+ cursor: z7.string().nullable().optional(),
2638
+ limit: z7.number().int().positive().optional().default(500)
2639
+ });
2630
2640
  var GetProjectTaskRequestSchema = z7.object({
2631
2641
  projectId: z7.string(),
2632
2642
  taskId: z7.string()
@@ -2,7 +2,7 @@ import {
2
2
  mapChatHistory,
3
3
  readAgentVersion,
4
4
  refreshSkillsAfterCheckout
5
- } from "./chunk-6CKFZ4JG.js";
5
+ } from "./chunk-V5WR2F2P.js";
6
6
  import {
7
7
  MAX_BETWEEN_TURN_BUFFER,
8
8
  MAX_DIAGNOSTIC_OUTPUT,
@@ -97,7 +97,7 @@ import {
97
97
  statWorkspacePath,
98
98
  updateRemoteToken,
99
99
  verifyGitCredential
100
- } from "./chunk-SKAFB6DG.js";
100
+ } from "./chunk-4RE6G2DZ.js";
101
101
  import {
102
102
  reportBootMilestone
103
103
  } from "./chunk-VIUZS7V4.js";
@@ -859,6 +859,7 @@ function redact(input) {
859
859
 
860
860
  // src/harness/pty/jsonl-tailer.ts
861
861
  import { open } from "fs/promises";
862
+ import { StringDecoder } from "string_decoder";
862
863
 
863
864
  // src/harness/pty/record-mapper.ts
864
865
  function isRecord(value) {
@@ -994,7 +995,9 @@ function mapTranscriptRecord(raw) {
994
995
  }
995
996
 
996
997
  // src/harness/pty/jsonl-tailer.ts
997
- var POLL_INTERVAL_MS = 25;
998
+ var ACTIVE_POLL_INTERVAL_MS = 100;
999
+ var IDLE_POLL_INTERVAL_MS = 1e3;
1000
+ var logger = createServiceLogger("JsonlTailer");
998
1001
  var JsonlTailer = class {
999
1002
  constructor(path, onEvent, onRawRecord, mapRecord2 = mapTranscriptRecord) {
1000
1003
  this.path = path;
@@ -1008,35 +1011,59 @@ var JsonlTailer = class {
1008
1011
  mapRecord;
1009
1012
  offset = 0;
1010
1013
  buffer = "";
1014
+ decoder = new StringDecoder("utf8");
1011
1015
  timer = null;
1012
- chain = Promise.resolve();
1016
+ chain = Promise.resolve(false);
1017
+ started = false;
1018
+ pollIntervalMs = ACTIVE_POLL_INTERVAL_MS;
1019
+ readErrorLogged = false;
1013
1020
  _closed = false;
1014
1021
  /**
1015
1022
  * Begin tailing. Pass `fromOffset` to skip bytes already present when the
1016
1023
  * tail starts (used on resume so the prior session's records aren't replayed).
1017
1024
  */
1018
1025
  start(fromOffset = 0) {
1019
- if (this.timer) return;
1026
+ if (this.started || this._closed) return;
1027
+ this.started = true;
1020
1028
  this.offset = fromOffset;
1021
- this.timer = setInterval(() => {
1022
- if (this._closed) return;
1023
- void this.enqueueRead();
1024
- }, POLL_INTERVAL_MS);
1029
+ this.scheduleRead();
1025
1030
  }
1026
1031
  close() {
1027
1032
  this._closed = true;
1028
1033
  if (this.timer) {
1029
- clearInterval(this.timer);
1034
+ clearTimeout(this.timer);
1030
1035
  this.timer = null;
1031
1036
  }
1032
1037
  }
1033
1038
  /** Read any remaining bytes and flush a trailing line without a newline. */
1034
1039
  async flush() {
1035
- await this.enqueueRead();
1036
- if (this.buffer.length > 0) {
1037
- this.emitLine(this.buffer);
1038
- this.buffer = "";
1039
- }
1040
+ const flushed = this.chain.then(async () => {
1041
+ await this.readOnce();
1042
+ this.buffer += this.decoder.end();
1043
+ if (this.buffer.length > 0) {
1044
+ this.emitLine(this.buffer);
1045
+ this.buffer = "";
1046
+ }
1047
+ return false;
1048
+ });
1049
+ this.chain = flushed;
1050
+ await flushed;
1051
+ }
1052
+ scheduleRead() {
1053
+ if (this._closed) return;
1054
+ this.timer = setTimeout(() => {
1055
+ this.timer = null;
1056
+ void this.enqueueRead().then(
1057
+ (changed) => {
1058
+ this.pollIntervalMs = changed ? ACTIVE_POLL_INTERVAL_MS : Math.min(this.pollIntervalMs * 2, IDLE_POLL_INTERVAL_MS);
1059
+ this.scheduleRead();
1060
+ },
1061
+ (error) => {
1062
+ logger.error("Transcript polling failed", { error: String(error) });
1063
+ this.close();
1064
+ }
1065
+ );
1066
+ }, this.pollIntervalMs);
1040
1067
  }
1041
1068
  enqueueRead() {
1042
1069
  this.chain = this.chain.then(() => this.readOnce());
@@ -1044,19 +1071,42 @@ var JsonlTailer = class {
1044
1071
  }
1045
1072
  async readOnce() {
1046
1073
  let handle = null;
1074
+ let chunk = null;
1047
1075
  try {
1048
1076
  handle = await open(this.path, "r");
1049
1077
  const stats = await handle.stat();
1050
- if (stats.size <= this.offset) return;
1078
+ if (stats.size <= this.offset) {
1079
+ this.readErrorLogged = false;
1080
+ return false;
1081
+ }
1051
1082
  const length = stats.size - this.offset;
1052
1083
  const buf = Buffer.alloc(length);
1053
- await handle.read(buf, 0, length, this.offset);
1054
- this.offset = stats.size;
1055
- this.consume(buf.toString("utf8"));
1056
- } catch {
1084
+ let readBytes = 0;
1085
+ while (readBytes < length) {
1086
+ const { bytesRead } = await handle.read(
1087
+ buf,
1088
+ readBytes,
1089
+ length - readBytes,
1090
+ this.offset + readBytes
1091
+ );
1092
+ if (bytesRead === 0) break;
1093
+ readBytes += bytesRead;
1094
+ }
1095
+ chunk = buf.subarray(0, readBytes);
1096
+ this.readErrorLogged = false;
1097
+ } catch (error) {
1098
+ if (!this.readErrorLogged) {
1099
+ logger.warn("Transcript read failed; retrying", { error: String(error) });
1100
+ this.readErrorLogged = true;
1101
+ }
1102
+ return false;
1057
1103
  } finally {
1058
1104
  if (handle) await handle.close();
1059
1105
  }
1106
+ if (!chunk || chunk.length === 0) return false;
1107
+ this.offset += chunk.length;
1108
+ this.consume(this.decoder.write(chunk));
1109
+ return true;
1060
1110
  }
1061
1111
  consume(chunk) {
1062
1112
  this.buffer += chunk;
@@ -4319,6 +4369,9 @@ function isMountDisconnectError(err) {
4319
4369
  const lower = message.toLowerCase();
4320
4370
  return MOUNT_DISCONNECT_MESSAGES.some((needle) => lower.includes(needle));
4321
4371
  }
4372
+ function isRequiredHomeDisconnect(err) {
4373
+ return process.env.CONVEYOR_USER_HOME_REQUIRED === "1" && isMountDisconnectError(err);
4374
+ }
4322
4375
  function podLocalConfigHome() {
4323
4376
  return join9(homedir3(), ".claude-local");
4324
4377
  }
@@ -4367,6 +4420,7 @@ async function ensureUsableClaudeConfigHome(cwd, log) {
4367
4420
  return { configHome, fellBack: false };
4368
4421
  } catch (err) {
4369
4422
  if (!isMountDisconnectError(err)) throw err;
4423
+ if (isRequiredHomeDisconnect(err)) throw err;
4370
4424
  const fallback = podLocalConfigHome();
4371
4425
  log?.warn(
4372
4426
  "shared ~/.claude mount is unreachable; falling back to a pod-local config home. Session history will not persist across pods until the mount recovers.",
@@ -4577,7 +4631,7 @@ var PtyHarness = class _PtyHarness {
4577
4631
  async parkedHomeDied(options) {
4578
4632
  if (!this.ownsClaudeConfigHome) return false;
4579
4633
  try {
4580
- const { fellBack } = await ensureUsableClaudeConfigHome(options.cwd, _PtyHarness.log);
4634
+ const { fellBack } = await this.ensureConfigHome(options);
4581
4635
  if (!fellBack) return false;
4582
4636
  _PtyHarness.log.warn(
4583
4637
  "shared ~/.claude mount died while the CLI was parked \u2014 respawning on the pod-local config home instead of reusing a process bound to the dead mount"
@@ -4587,7 +4641,15 @@ var PtyHarness = class _PtyHarness {
4587
4641
  _PtyHarness.log.warn("parked-session config-home probe failed", {
4588
4642
  error: err instanceof Error ? err.message : String(err)
4589
4643
  });
4590
- return false;
4644
+ return isRequiredHomeDisconnect(err);
4645
+ }
4646
+ }
4647
+ async ensureConfigHome(options) {
4648
+ try {
4649
+ return await ensureUsableClaudeConfigHome(options.cwd, _PtyHarness.log);
4650
+ } catch (err) {
4651
+ if (isRequiredHomeDisconnect(err)) this.escalateToPodRecycle(true);
4652
+ throw err;
4591
4653
  }
4592
4654
  }
4593
4655
  /**
@@ -4599,7 +4661,7 @@ var PtyHarness = class _PtyHarness {
4599
4661
  const session = new PtySession(prompt, options, want, this.bridge, this.adapter);
4600
4662
  onAllocated?.(session);
4601
4663
  if (this.ownsClaudeConfigHome) {
4602
- await ensureUsableClaudeConfigHome(options.cwd, _PtyHarness.log);
4664
+ await this.ensureConfigHome(options);
4603
4665
  }
4604
4666
  await this.adapter.prepareEnvironment({ cwd: options.cwd });
4605
4667
  if (this.ownsClaudeConfigHome) {
@@ -4671,15 +4733,13 @@ var PtyHarness = class _PtyHarness {
4671
4733
  *
4672
4734
  * Fire-and-forget: the escalation must not gate ending the failed turn.
4673
4735
  */
4674
- escalateToPodRecycle() {
4736
+ escalateToPodRecycle(confirmedRequiredMountFailure = false) {
4675
4737
  if (this.recycleRequested || !this.bridge?.requestPodRecycle) return;
4676
- if (!isConfigHomeFallbackActive()) return;
4738
+ if (!confirmedRequiredMountFailure && !isConfigHomeFallbackActive()) return;
4677
4739
  this.recycleRequested = true;
4678
- _PtyHarness.log.error(
4679
- "Prompt delivery failed with the shared ~/.claude mount dead \u2014 requesting a pod recycle"
4680
- );
4740
+ _PtyHarness.log.error("Shared ~/.claude mount is unavailable \u2014 requesting a pod recycle");
4681
4741
  this.bridge.requestPodRecycle(
4682
- "The shared ~/.claude mount died and the Claude CLI will not accept a prompt on this pod. Only a new pod remounts it."
4742
+ "The shared ~/.claude mount died and the Claude CLI cannot safely continue on this pod. Only a new pod remounts it."
4683
4743
  );
4684
4744
  }
4685
4745
  /**
@@ -4846,7 +4906,7 @@ function findOnPath(binary, env = process.env) {
4846
4906
  import { promises as fs } from "fs";
4847
4907
  import { dirname as dirname2, join as join11 } from "path";
4848
4908
  import { homedir as homedir4 } from "os";
4849
- var logger = createServiceLogger("opencode-auth");
4909
+ var logger2 = createServiceLogger("opencode-auth");
4850
4910
  var OPENCODE_CODEX_PLUGIN = "opencode-openai-codex-auth@4.4.0";
4851
4911
  var PLUGIN_PACKAGE = "opencode-openai-codex-auth";
4852
4912
  function opencodeAuthPath(env) {
@@ -4893,7 +4953,7 @@ async function ensureAuthEntry(env, seed) {
4893
4953
  const path = opencodeAuthPath(env);
4894
4954
  const store = await readJsonFile(path);
4895
4955
  if (!shouldSeed(store.openai, seed)) {
4896
- logger.info("opencode oauth store is fresher than the seed; leaving it alone");
4956
+ logger2.info("opencode oauth store is fresher than the seed; leaving it alone");
4897
4957
  return;
4898
4958
  }
4899
4959
  store.openai = {
@@ -4903,7 +4963,7 @@ async function ensureAuthEntry(env, seed) {
4903
4963
  expires: seed.expires
4904
4964
  };
4905
4965
  await writeJsonFile(path, store);
4906
- logger.info("seeded opencode oauth store entry");
4966
+ logger2.info("seeded opencode oauth store entry");
4907
4967
  }
4908
4968
  async function ensurePluginConfig(env) {
4909
4969
  const path = opencodeConfigPath(env);
@@ -4916,7 +4976,7 @@ async function ensurePluginConfig(env) {
4916
4976
  const kept = plugins.filter((p) => !isOurs(p));
4917
4977
  config.plugin = [...kept, OPENCODE_CODEX_PLUGIN];
4918
4978
  await writeJsonFile(path, config);
4919
- logger.info("ensured opencode codex-auth plugin in config");
4979
+ logger2.info("ensured opencode codex-auth plugin in config");
4920
4980
  }
4921
4981
  async function seedOpenCodeOauth(env) {
4922
4982
  const seed = parseOauthSeed(env.CONVEYOR_OPENCODE_OAUTH);
@@ -4925,7 +4985,7 @@ async function seedOpenCodeOauth(env) {
4925
4985
  await ensureAuthEntry(env, seed);
4926
4986
  await ensurePluginConfig(env);
4927
4987
  } catch (err) {
4928
- logger.warn(
4988
+ logger2.warn(
4929
4989
  `failed to seed opencode oauth store: ${err instanceof Error ? err.message : String(err)}`
4930
4990
  );
4931
4991
  }
@@ -5538,14 +5598,14 @@ function resolveTuiAdapter(kind = "claude-code") {
5538
5598
 
5539
5599
  // src/harness/pty/stream-server.ts
5540
5600
  import net from "net";
5541
- var logger2 = createServiceLogger("PtyStreamServer");
5601
+ var logger3 = createServiceLogger("PtyStreamServer");
5542
5602
  var RING_MAX_CHARS = 256 * 1024;
5543
5603
  var PtyStreamServer = class {
5544
5604
  constructor(options) {
5545
5605
  this.options = options;
5546
5606
  this.server = net.createServer((socket) => this.handleConnection(socket));
5547
5607
  this.server.on("error", (err) => {
5548
- logger2.warn(`PTY stream server error: ${err.message}`);
5608
+ logger3.warn(`PTY stream server error: ${err.message}`);
5549
5609
  });
5550
5610
  }
5551
5611
  options;
@@ -5586,7 +5646,7 @@ var PtyStreamServer = class {
5586
5646
  return port;
5587
5647
  }
5588
5648
  }
5589
- logger2.warn(`PTY stream server could not bind any port in ${base}..${base + attempts - 1}`);
5649
+ logger3.warn(`PTY stream server could not bind any port in ${base}..${base + attempts - 1}`);
5590
5650
  return null;
5591
5651
  }
5592
5652
  tryListen(port) {
@@ -5707,7 +5767,7 @@ var PtyStreamServer = class {
5707
5767
  };
5708
5768
 
5709
5769
  // src/harness/pty/direct-stream.ts
5710
- var logger3 = createServiceLogger("PtyDirectStream");
5770
+ var logger4 = createServiceLogger("PtyDirectStream");
5711
5771
  var RELAY_COALESCE_MS = 2e3;
5712
5772
  var RELAY_MAX_BUFFER_CHARS = 48 * 1024;
5713
5773
  var DirectStreamController = class {
@@ -5759,7 +5819,7 @@ var DirectStreamController = class {
5759
5819
  });
5760
5820
  void created.listen().then((port) => this.onListening(created, port)).catch((err) => {
5761
5821
  this.starting = false;
5762
- logger3.warn(
5822
+ logger4.warn(
5763
5823
  `PTY stream server failed to start: ${err instanceof Error ? err.message : String(err)}`
5764
5824
  );
5765
5825
  });
@@ -5772,7 +5832,7 @@ var DirectStreamController = class {
5772
5832
  }
5773
5833
  this.server = created;
5774
5834
  this.reporter.reportPtyStream(port);
5775
- logger3.info(`PTY stream server listening on ${port} (session ${this.reporter.sessionId})`);
5835
+ logger4.info(`PTY stream server listening on ${port} (session ${this.reporter.sessionId})`);
5776
5836
  }
5777
5837
  /** Push the min box across both transports to the pty. */
5778
5838
  applyDims() {
@@ -5904,7 +5964,7 @@ Respond to them with post_to_chat (your turn output is NOT shown in chat).`
5904
5964
  // src/execution/relaunch-hold.ts
5905
5965
  function findLastAgentMessageIndex(history) {
5906
5966
  for (let i = history.length - 1; i >= 0; i--) {
5907
- if (history[i].role === "assistant") return i;
5967
+ if (history[i].role === "assistant" && history[i].kind !== "lifecycle") return i;
5908
5968
  }
5909
5969
  return -1;
5910
5970
  }
@@ -7498,9 +7558,9 @@ var searchFilterFields = {
7498
7558
  desc: "Only return cards with no assignee (mutually exclusive with assigneeId)"
7499
7559
  })
7500
7560
  ),
7501
- limit: f.optional(f.number({ desc: "Max results to return (default 20)" }))
7561
+ limit: f.optional(f.number({ desc: "Max results to return (default 20, at most 200)" }))
7502
7562
  };
7503
- var searchResultNote = "Every result lists the tags it carries, so you can see why it matched. Results are relevance-ordered: highest priority first then newest; suggestions-only queries rank by upvote score. Returns summaries \u2014 plan omitted, description truncated; use get_task for full details.";
7563
+ var searchResultNote = "Every result lists the tags it carries, so you can see why it matched. Searches every status, Complete and Cancelled included, unless statusFilters narrows it. Returns at most 200 results. Results are relevance-ordered: highest priority first then newest; suggestions-only queries rank by upvote score. Returns summaries \u2014 plan omitted, description truncated; use get_task for full details.";
7504
7564
  var searchTasksContract = defineToolContract({
7505
7565
  name: "search_tasks",
7506
7566
  agent: {
@@ -12437,7 +12497,7 @@ function resolvePlaywrightMcpServer(env = process.env) {
12437
12497
  }
12438
12498
 
12439
12499
  // src/execution/event-handlers.ts
12440
- var logger4 = createServiceLogger("event-handlers");
12500
+ var logger5 = createServiceLogger("event-handlers");
12441
12501
  function safeVoid(promise, context) {
12442
12502
  if (promise && typeof promise.catch === "function") {
12443
12503
  promise.catch((err) => {
@@ -12639,7 +12699,7 @@ async function emitResultEvent(event, host, context, startTime, lastAssistantUsa
12639
12699
  }
12640
12700
  function handleRateLimitEvent(event, host) {
12641
12701
  const { rate_limit_info } = event;
12642
- logger4.info("Rate limit event received", { rate_limit_info });
12702
+ logger5.info("Rate limit event received", { rate_limit_info });
12643
12703
  const status = rate_limit_info.status;
12644
12704
  const resetsAt = epochSecondsToISO(rate_limit_info.resetsAt);
12645
12705
  const utilization = rate_limit_info.utilization ?? (status === "rejected" ? 1 : void 0);
@@ -13418,7 +13478,7 @@ function buildCanUseTool(host) {
13418
13478
  }
13419
13479
 
13420
13480
  // src/execution/query-executor.ts
13421
- var logger5 = createServiceLogger("QueryExecutor");
13481
+ var logger6 = createServiceLogger("QueryExecutor");
13422
13482
  var IMAGE_ERROR_PATTERN2 = /Could not process image/i;
13423
13483
  var RETRY_DELAYS_MS = [6e4, 12e4, 18e4, 3e5];
13424
13484
  function buildHooks(host) {
@@ -13503,7 +13563,7 @@ function resolveSessionStart(lineageKey, cwd, tui = process.env.CONVEYOR_TUI) {
13503
13563
  repairTornSessionFile(path);
13504
13564
  if (isResumableTranscript(path)) return { resume: sessionUuid };
13505
13565
  rotateSessionFile(cwd, sessionUuid);
13506
- logger5.warn("Rotated a transcript with no conversation aside before resume", { path });
13566
+ logger6.warn("Rotated a transcript with no conversation aside before resume", { path });
13507
13567
  }
13508
13568
  markSpawnedTranscript(cwd, sessionUuid);
13509
13569
  return { sessionId: sessionUuid };
@@ -13562,7 +13622,7 @@ function repairTornSessionFile(path) {
13562
13622
  }
13563
13623
  if (keepEnd === content.length) return false;
13564
13624
  truncateSync(path, Buffer.byteLength(content.slice(0, keepEnd), "utf8"));
13565
- logger5.warn("Repaired torn transcript before resume", {
13625
+ logger6.warn("Repaired torn transcript before resume", {
13566
13626
  path,
13567
13627
  trimmedBytes: content.length - keepEnd
13568
13628
  });
@@ -13649,7 +13709,7 @@ function buildQueryOptions(host, context) {
13649
13709
  disallowedTools: buildDisallowedTools(settings, mode, host.hasExitedPlanMode),
13650
13710
  enableFileCheckpointing: settings.enableFileCheckpointing,
13651
13711
  stderr: (data) => {
13652
- logger5.warn("Claude Code stderr", { data: data.trimEnd() });
13712
+ logger6.warn("Claude Code stderr", { data: data.trimEnd() });
13653
13713
  }
13654
13714
  };
13655
13715
  }
@@ -14055,7 +14115,7 @@ function rotateSessionFile(cwd, sessionUuid) {
14055
14115
  renameSync2(path, `${path.replace(/\.jsonl$/, "")}.aborted-${Date.now()}.jsonl`);
14056
14116
  return true;
14057
14117
  } catch (error) {
14058
- logger5.warn("Could not rotate an aborted transcript aside", {
14118
+ logger6.warn("Could not rotate an aborted transcript aside", {
14059
14119
  path,
14060
14120
  error: error instanceof Error ? error.message : String(error)
14061
14121
  });
@@ -14119,7 +14179,7 @@ async function handleAuthError(context, host, options) {
14119
14179
  async function handleStaleSession(context, host, options) {
14120
14180
  context.claudeSessionId = null;
14121
14181
  host.connection.storeSessionId("");
14122
- logger5.warn("Resume target had no resumable conversation; rotating it aside and starting fresh", {
14182
+ logger6.warn("Resume target had no resumable conversation; rotating it aside and starting fresh", {
14123
14183
  taskId: context.taskId,
14124
14184
  runnerMode: host.config.mode,
14125
14185
  agentMode: host.agentMode
@@ -14309,7 +14369,7 @@ async function runWithRetry(initialQuery, context, host, options) {
14309
14369
  }
14310
14370
 
14311
14371
  // src/runner/query-bridge.ts
14312
- var logger6 = createServiceLogger("QueryBridge");
14372
+ var logger7 = createServiceLogger("QueryBridge");
14313
14373
  function resolveHarnessKind() {
14314
14374
  if (process.env.CONVEYOR_FORCE_SDK_CARDS === "1") return "sdk";
14315
14375
  return "pty";
@@ -14439,7 +14499,7 @@ var QueryBridge = class {
14439
14499
  this.freshPrewarmedInitial = warmed;
14440
14500
  return warmed;
14441
14501
  } catch (err) {
14442
- logger6.warn("TUI prewarm failed; continuing with normal startup", {
14502
+ logger7.warn("TUI prewarm failed; continuing with normal startup", {
14443
14503
  error: err instanceof Error ? err.message : String(err)
14444
14504
  });
14445
14505
  return false;
@@ -14524,9 +14584,9 @@ var QueryBridge = class {
14524
14584
  const msg = err instanceof Error ? err.message : String(err);
14525
14585
  const isAbort = this._stopped || /abort/i.test(msg);
14526
14586
  if (isAbort) {
14527
- logger6.info("Query stopped by user", { error: msg });
14587
+ logger7.info("Query stopped by user", { error: msg });
14528
14588
  } else {
14529
- logger6.error("Query execution failed", { error: msg });
14589
+ logger7.error("Query execution failed", { error: msg });
14530
14590
  this.connection.sendEvent({ type: "error", message: msg });
14531
14591
  }
14532
14592
  } finally {
@@ -14552,9 +14612,9 @@ var QueryBridge = class {
14552
14612
  const msg = err instanceof Error ? err.message : String(err);
14553
14613
  const isAbort = this._stopped || /abort/i.test(msg);
14554
14614
  if (isAbort) {
14555
- logger6.info("Passive turn stopped", { error: msg });
14615
+ logger7.info("Passive turn stopped", { error: msg });
14556
14616
  } else {
14557
- logger6.error("Passive turn failed", { error: msg });
14617
+ logger7.error("Passive turn failed", { error: msg });
14558
14618
  this.connection.sendEvent({ type: "error", message: msg });
14559
14619
  }
14560
14620
  } finally {
@@ -14915,7 +14975,7 @@ async function runUsageProbe(deps = {}) {
14915
14975
  }
14916
14976
 
14917
14977
  // src/execution/usage-sampler.ts
14918
- var logger7 = createServiceLogger("usage-sampler");
14978
+ var logger8 = createServiceLogger("usage-sampler");
14919
14979
  var NO_SAMPLES = { samples: [], unmeasurable: null };
14920
14980
  function usesNativeUsageReporting(env = process.env) {
14921
14981
  return env.CONVEYOR_TUI === "codex";
@@ -14935,7 +14995,7 @@ async function sampleKeyUsage(token, probe = () => runUsageProbe(), hasSubscript
14935
14995
  try {
14936
14996
  const attributable = isAttributable(await readIdentity(), token);
14937
14997
  if (!attributable.ok) {
14938
- logger7.info("usage sample skipped \u2014 credentials not attributable to this session's key", {
14998
+ logger8.info("usage sample skipped \u2014 credentials not attributable to this session's key", {
14939
14999
  reason: attributable.reason
14940
15000
  });
14941
15001
  return { samples: [], unmeasurable: { reason: attributable.reason ?? "unattributable" } };
@@ -14962,14 +15022,14 @@ async function sampleKeyUsage(token, probe = () => runUsageProbe(), hasSubscript
14962
15022
  });
14963
15023
  }
14964
15024
  if (samples.length === 0) {
14965
- logger7.info("usage sample produced no gauges", {
15025
+ logger8.info("usage sample produced no gauges", {
14966
15026
  stdoutLength: stdout.length,
14967
15027
  stdoutHead: stdout.slice(0, 200).replaceAll("\n", " ")
14968
15028
  });
14969
15029
  }
14970
15030
  return { samples, unmeasurable: null };
14971
15031
  } catch (error) {
14972
- logger7.info("usage sample failed", {
15032
+ logger8.info("usage sample failed", {
14973
15033
  error: error instanceof Error ? error.message : String(error)
14974
15034
  });
14975
15035
  return NO_SAMPLES;
@@ -8,7 +8,7 @@ import {
8
8
  readWorkspaceBytes,
9
9
  statWorkspacePath,
10
10
  workspacePathExists
11
- } from "./chunk-SKAFB6DG.js";
11
+ } from "./chunk-4RE6G2DZ.js";
12
12
  import {
13
13
  reportBootMilestone
14
14
  } from "./chunk-VIUZS7V4.js";
@@ -42,6 +42,9 @@ function mapChatHistory(messages) {
42
42
  userName: m.user?.name ?? void 0,
43
43
  createdAt: m.createdAt,
44
44
  ...m.source ? { source: m.source } : {},
45
+ // The relaunch batch reads `kind` to skip server bookkeeping rows; dropping
46
+ // it here made that check dead in every pod (relaunch-hold.ts).
47
+ ...m.kind ? { kind: m.kind } : {},
45
48
  ...m.files && m.files.length > 0 ? {
46
49
  files: m.files.map((f) => ({
47
50
  fileId: f.id,
package/dist/cli.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  WorkspaceCommandSupervisor,
8
8
  startWorkspaceCommandsAfterConnect,
9
9
  stopWorkspaceCommands
10
- } from "./chunk-A43UZ5RC.js";
10
+ } from "./chunk-UL6DAPTX.js";
11
11
  import {
12
12
  PtyHarness,
13
13
  SessionRunner,
@@ -27,8 +27,8 @@ import {
27
27
  runUsageProbe,
28
28
  sampleKeyUsage,
29
29
  usesNativeUsageReporting
30
- } from "./chunk-2SIMOUOD.js";
31
- import "./chunk-6CKFZ4JG.js";
30
+ } from "./chunk-JUEHUVSD.js";
31
+ import "./chunk-V5WR2F2P.js";
32
32
  import {
33
33
  inheritedEnv,
34
34
  resolvePtySpawn,
@@ -44,7 +44,7 @@ import {
44
44
  createServiceLogger,
45
45
  loadAndAnnotateDiscoveredPorts,
46
46
  loadConveyorConfig
47
- } from "./chunk-SKAFB6DG.js";
47
+ } from "./chunk-4RE6G2DZ.js";
48
48
  import "./chunk-VIUZS7V4.js";
49
49
  import "./chunk-W4LZ7R6Z.js";
50
50
  import "./chunk-372R6E4C.js";
@@ -1212,7 +1212,7 @@ function wireSpawnChildren(mode, connection, supervisors, logger7) {
1212
1212
 
1213
1213
  // src/cli.ts
1214
1214
  if (process.argv[2] === "boot") {
1215
- const { runBoot } = await import("./boot-5AZLXH5M.js");
1215
+ const { runBoot } = await import("./boot-KDC4OLVL.js");
1216
1216
  process.exit(await runBoot(process.argv.slice(3)));
1217
1217
  }
1218
1218
  if (isLegacyEntrypointLaunch(process.env)) {
@@ -1423,7 +1423,7 @@ if (!RUNNER_MODES.includes(CONVEYOR_MODE)) {
1423
1423
  process.exit(1);
1424
1424
  }
1425
1425
  if (CONVEYOR_MODE === "serving") {
1426
- const { runServingSession } = await import("./serve-boot-HRMFAX7H.js");
1426
+ const { runServingSession } = await import("./serve-boot-H72OIMFS.js");
1427
1427
  exitContext.runnerMode = "serving";
1428
1428
  exitContext.sessionId = process.env.CONVEYOR_SESSION_ID ?? exitContext.sessionId;
1429
1429
  const outcome = await runServingSession({
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import {
2
2
  SessionRunner,
3
3
  unshallowRepo
4
- } from "./chunk-2SIMOUOD.js";
5
- import "./chunk-6CKFZ4JG.js";
4
+ } from "./chunk-JUEHUVSD.js";
5
+ import "./chunk-V5WR2F2P.js";
6
6
  import "./chunk-EKTPDG3G.js";
7
7
  import {
8
8
  AgentConnection,
@@ -17,7 +17,7 @@ import {
17
17
  stageAndCommit,
18
18
  updateRemoteToken,
19
19
  workspacePathExists
20
- } from "./chunk-SKAFB6DG.js";
20
+ } from "./chunk-4RE6G2DZ.js";
21
21
  import "./chunk-VIUZS7V4.js";
22
22
  import {
23
23
  runAuthTokenCommand,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  WorkspaceCommandSupervisor
3
- } from "./chunk-A43UZ5RC.js";
3
+ } from "./chunk-UL6DAPTX.js";
4
4
  import {
5
5
  AgentConnection,
6
6
  DEFAULT_LIFECYCLE_CONFIG,
@@ -11,7 +11,7 @@ import {
11
11
  ensureOnTaskBranch,
12
12
  loadAndAnnotateDiscoveredPorts,
13
13
  loadConveyorConfig
14
- } from "./chunk-SKAFB6DG.js";
14
+ } from "./chunk-4RE6G2DZ.js";
15
15
  import "./chunk-VIUZS7V4.js";
16
16
  import "./chunk-W4LZ7R6Z.js";
17
17
  import "./chunk-IA45XHOA.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rallycry/conveyor-agent",
3
- "version": "11.0.46",
3
+ "version": "11.0.48",
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",