commonswarm 0.1.27 → 0.1.29

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.
Files changed (2) hide show
  1. package/cswarm.cjs +315 -130
  2. package/package.json +1 -1
package/cswarm.cjs CHANGED
@@ -28337,6 +28337,8 @@ function describeServerError(prefix, envelope) {
28337
28337
  // src/cloud/signals.ts
28338
28338
  var UUID_RE7 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
28339
28339
  var SIGNAL_KINDS = /* @__PURE__ */ new Set(["working-on", "note", "ask"]);
28340
+ var SIGNAL_BODY_DISPLAY_MAX = 8e3;
28341
+ var SIGNAL_ABOUT_DISPLAY_MAX = 500;
28340
28342
  var SIGNAL_READ_TIMEOUT_MS = 3e4;
28341
28343
  var SignalReadTimeoutError = class extends Error {
28342
28344
  constructor(message = "signal read timed out") {
@@ -28443,7 +28445,7 @@ function parseSignalRecord(value) {
28443
28445
  throw new Error("signal read returned a malformed row");
28444
28446
  }
28445
28447
  const row = value;
28446
- if (typeof row.from_kind !== "string" || !["user", "agent"].includes(row.from_kind) || typeof row.kind !== "string" || !SIGNAL_KINDS.has(row.kind) || typeof row.body !== "string" || row.body.length < 1 || row.body.length > 2e3 || !(row.about === null || typeof row.about === "string" && row.about.length <= 500)) {
28448
+ if (typeof row.from_kind !== "string" || !["user", "agent"].includes(row.from_kind) || typeof row.kind !== "string" || !SIGNAL_KINDS.has(row.kind) || typeof row.body !== "string" || row.body.length < 1 || !(row.about === null || typeof row.about === "string")) {
28447
28449
  throw new Error("signal read returned malformed signal data");
28448
28450
  }
28449
28451
  let senderOwnerRelation = "unknown";
@@ -29175,13 +29177,27 @@ function renderSignals(signals, options) {
29175
29177
  const authorName = signal.from_kind === "agent" ? options.authors?.agents.get(signal.from) : options.authors?.users.get(signal.from);
29176
29178
  const author = authorName === void 0 ? `${authorKind} ${signal.from}` : `${authorKind} ${authorName} (${signal.from})${signal.from_kind === "user" && options.authors?.currentUserId === signal.from ? " \u2014 you" : ""}`;
29177
29179
  const expired = Date.parse(signal.until) <= now ? " (expired)" : "";
29178
- const about = signal.about === null ? "" : ` about ${JSON.stringify(signal.about)}`;
29180
+ const aboutClipped = signal.about !== null && signal.about.length > SIGNAL_ABOUT_DISPLAY_MAX;
29181
+ const displayedAbout = aboutClipped ? signal.about.slice(0, SIGNAL_ABOUT_DISPLAY_MAX) : signal.about;
29182
+ const about = displayedAbout === null ? "" : ` about ${JSON.stringify(displayedAbout)}`;
29179
29183
  const replyTo = (signal.in_reply_to ?? null) === null ? "" : ` \u2014 in reply to ${signal.in_reply_to}`;
29180
29184
  const replyable = signal.kind === "ask";
29181
29185
  const idHint = replyable ? ` \u2014 reply with: cswarm reply ${signal.id}` : "";
29186
+ const bodyClipped = signal.body.length > SIGNAL_BODY_DISPLAY_MAX;
29187
+ const displayedBody = bodyClipped ? signal.body.slice(0, SIGNAL_BODY_DISPLAY_MAX) : signal.body;
29182
29188
  lines.push(
29183
- `- [${signal.kind}] ${author} \u2014 ${relativeAge(signal.created_at, now)} \u2014 ${relativeExpiry(signal.until, now)}${expired}${about}${replyTo}: ${JSON.stringify(signal.body)}${idHint}`
29189
+ `- [${signal.kind}] ${author} \u2014 ${relativeAge(signal.created_at, now)} \u2014 ${relativeExpiry(signal.until, now)}${expired}${about}${replyTo}: ${JSON.stringify(displayedBody)}${idHint}`
29184
29190
  );
29191
+ if (bodyClipped) {
29192
+ lines.push(
29193
+ ` WARNING: Body clipped for display. Showing ${SIGNAL_BODY_DISPLAY_MAX} of ${signal.body.length} characters. Use --json to read the full body.`
29194
+ );
29195
+ }
29196
+ if (aboutClipped) {
29197
+ lines.push(
29198
+ ` WARNING: About reference clipped for display. Showing ${SIGNAL_ABOUT_DISPLAY_MAX} of ${signal.about.length} characters. Use --json to read the full reference.`
29199
+ );
29200
+ }
29185
29201
  }
29186
29202
  return lines.join("\n");
29187
29203
  }
@@ -29570,11 +29586,15 @@ var ACP_MAX_ACCUMULATED_TEXT_CHARS = 4194304;
29570
29586
  var ACP_DEFAULT_REQUEST_TIMEOUT_MS = 12e4;
29571
29587
  var ACP_VERSION_CHECK_TIMEOUT_MS = 5e3;
29572
29588
  var ACP_CANARY_TIMEOUT_MS = 3e4;
29573
- var GROK_MEASURED_VERSION = "0.2.117";
29574
- var OPENCODE_MEASURED_VERSION = "1.18.10";
29575
- var CLAUDE_ACP_MEASURED_VERSION = "0.64.2";
29589
+ var GROK_MIN_VERSION = "0.2.117";
29590
+ var GROK_LAST_MEASURED_VERSION = "0.2.117";
29591
+ var OPENCODE_MIN_VERSION = "1.18.10";
29592
+ var OPENCODE_LAST_MEASURED_VERSION = "1.18.10";
29593
+ var CLAUDE_ACP_MIN_VERSION = "0.64.2";
29594
+ var CLAUDE_ACP_LAST_MEASURED_VERSION = "0.64.2";
29576
29595
  var CLAUDE_PERMISSION_MODE_ID = "default";
29577
- var CODEX_ACP_MEASURED_VERSION = "1.1.9";
29596
+ var CODEX_ACP_MIN_VERSION = "1.1.9";
29597
+ var CODEX_ACP_LAST_MEASURED_VERSION = "1.1.9";
29578
29598
  var CODEX_PERMISSION_MODE_ID = "read-only";
29579
29599
  var ACP_PROTOCOL_VERSION = 1;
29580
29600
  var OPENCODE_FORCED_PERMISSION_TOOLS = [
@@ -29789,21 +29809,30 @@ var AcpTransportError = class extends AcpHostError {
29789
29809
  cause;
29790
29810
  };
29791
29811
  var AcpVersionError = class extends AcpHostError {
29792
- constructor(message) {
29793
- super("version_refused", message);
29812
+ constructor(message, code = "version_refused") {
29813
+ super(code, message);
29794
29814
  this.name = "AcpVersionError";
29795
29815
  }
29796
29816
  };
29797
- var AcpVersionMismatchError = class extends AcpVersionError {
29798
- constructor(expected, actual) {
29817
+ var AcpVersionParseError = class extends AcpVersionError {
29818
+ constructor(message) {
29819
+ super(message, "version_unparseable");
29820
+ this.name = "AcpVersionParseError";
29821
+ }
29822
+ };
29823
+ var AcpVersionBelowFloorError = class extends AcpVersionError {
29824
+ constructor(provider, minimum, actual) {
29799
29825
  super(
29800
- `refusing claude-agent-acp ${actual}; host core is measured for ${expected} only`
29826
+ `refusing ${provider} ${actual}; CommonSwarm requires ${minimum} or newer`,
29827
+ "version_below_floor"
29801
29828
  );
29802
- this.expected = expected;
29829
+ this.provider = provider;
29830
+ this.minimum = minimum;
29803
29831
  this.actual = actual;
29804
- this.name = "AcpVersionMismatchError";
29832
+ this.name = "AcpVersionBelowFloorError";
29805
29833
  }
29806
- expected;
29834
+ provider;
29835
+ minimum;
29807
29836
  actual;
29808
29837
  };
29809
29838
  var AcpPermissionCanaryError = class extends AcpHostError {
@@ -30711,6 +30740,98 @@ function createBoundTransport(options) {
30711
30740
  });
30712
30741
  }
30713
30742
 
30743
+ // src/host/version.ts
30744
+ var CORE_IDENTIFIER = "(?:0|[1-9]\\d*)";
30745
+ var PRERELEASE_IDENTIFIER = "(?:0|[1-9]\\d*|[A-Za-z-][0-9A-Za-z-]*)";
30746
+ var BUILD_IDENTIFIER = "[0-9A-Za-z-]+";
30747
+ var SEMVER_SOURCE = `${CORE_IDENTIFIER}\\.${CORE_IDENTIFIER}\\.${CORE_IDENTIFIER}(?:-${PRERELEASE_IDENTIFIER}(?:\\.${PRERELEASE_IDENTIFIER})*)?(?:\\+${BUILD_IDENTIFIER}(?:\\.${BUILD_IDENTIFIER})*)?`;
30748
+ var SEMVER_RE = new RegExp(`^${SEMVER_SOURCE}$`);
30749
+ function parseSemVer(value) {
30750
+ if (!SEMVER_RE.test(value)) return null;
30751
+ const withoutBuild = value.split("+", 1)[0];
30752
+ const dash = withoutBuild.indexOf("-");
30753
+ const coreText = dash === -1 ? withoutBuild : withoutBuild.slice(0, dash);
30754
+ const prereleaseText = dash === -1 ? null : withoutBuild.slice(dash + 1);
30755
+ const coreParts = coreText.split(".");
30756
+ if (coreParts.length !== 3) return null;
30757
+ return {
30758
+ core: [BigInt(coreParts[0]), BigInt(coreParts[1]), BigInt(coreParts[2])],
30759
+ prerelease: prereleaseText === null ? null : prereleaseText.split(".")
30760
+ };
30761
+ }
30762
+ function compareSemVer(left, right) {
30763
+ const a = parseSemVer(left);
30764
+ const b2 = parseSemVer(right);
30765
+ if (!a || !b2) {
30766
+ throw new AcpVersionParseError(
30767
+ `cannot compare invalid semantic versions: ${JSON.stringify(left)} and ${JSON.stringify(right)}`
30768
+ );
30769
+ }
30770
+ for (let index = 0; index < 3; index += 1) {
30771
+ if (a.core[index] < b2.core[index]) return -1;
30772
+ if (a.core[index] > b2.core[index]) return 1;
30773
+ }
30774
+ if (a.prerelease === null && b2.prerelease === null) return 0;
30775
+ if (a.prerelease === null) return 1;
30776
+ if (b2.prerelease === null) return -1;
30777
+ const length = Math.max(a.prerelease.length, b2.prerelease.length);
30778
+ for (let index = 0; index < length; index += 1) {
30779
+ const leftPart = a.prerelease[index];
30780
+ const rightPart = b2.prerelease[index];
30781
+ if (leftPart === void 0) return -1;
30782
+ if (rightPart === void 0) return 1;
30783
+ if (leftPart === rightPart) continue;
30784
+ const leftNumeric = /^\d+$/.test(leftPart);
30785
+ const rightNumeric = /^\d+$/.test(rightPart);
30786
+ if (leftNumeric && rightNumeric) {
30787
+ return BigInt(leftPart) < BigInt(rightPart) ? -1 : 1;
30788
+ }
30789
+ if (leftNumeric) return -1;
30790
+ if (rightNumeric) return 1;
30791
+ return leftPart < rightPart ? -1 : 1;
30792
+ }
30793
+ return 0;
30794
+ }
30795
+ function parseProviderVersionOutput(stdout, productPattern, allowBare = true) {
30796
+ const lines = stdout.split(/\r?\n/);
30797
+ for (const line of lines) {
30798
+ const pattern = new RegExp(productPattern.source, productPattern.flags.replace("g", ""));
30799
+ const product = pattern.exec(line);
30800
+ if (!product) continue;
30801
+ const after = line.slice(product.index + product[0].length);
30802
+ const afterMatch = new RegExp(
30803
+ `^\\s+(${SEMVER_SOURCE})(?=$|\\s|\\()`
30804
+ ).exec(after);
30805
+ if (afterMatch?.[1]) return afterMatch[1];
30806
+ const before = line.slice(0, product.index);
30807
+ const beforeMatch = new RegExp(`(${SEMVER_SOURCE})\\s*\\($`).exec(before);
30808
+ if (beforeMatch?.[1]) return beforeMatch[1];
30809
+ }
30810
+ if (!allowBare) return null;
30811
+ for (const line of lines) {
30812
+ const trimmed = line.trim();
30813
+ const match = new RegExp(`^(${SEMVER_SOURCE})$`).exec(trimmed);
30814
+ if (match?.[1]) return match[1];
30815
+ }
30816
+ return null;
30817
+ }
30818
+ function assertProviderVersionFloor(options) {
30819
+ if (compareSemVer(options.version, options.minimumVersion) < 0) {
30820
+ throw new AcpVersionBelowFloorError(
30821
+ options.provider,
30822
+ options.minimumVersion,
30823
+ options.version
30824
+ );
30825
+ }
30826
+ if (compareSemVer(options.version, options.lastMeasuredVersion) > 0) {
30827
+ options.onNewerVersion?.({
30828
+ provider: options.provider,
30829
+ runningVersion: options.version,
30830
+ lastMeasuredVersion: options.lastMeasuredVersion
30831
+ });
30832
+ }
30833
+ }
30834
+
30714
30835
  // src/host/opencode.ts
30715
30836
  var OPENCODE_HOME_OWNER_FILE = ".cswarm-opencode-owner.json";
30716
30837
  var MAX_OPENCODE_AUTH_BYTES = 256 * 1024;
@@ -30819,11 +30940,11 @@ async function releaseOpenCodeHome(home, instanceId) {
30819
30940
  }
30820
30941
  }
30821
30942
  function parseOpenCodeVersionOutput(stdout) {
30822
- const m = stdout.match(/\b(\d+\.\d+\.\d+)\b/);
30823
- return m?.[1] ?? null;
30943
+ return parseProviderVersionOutput(stdout, /\bopencode\b/i);
30824
30944
  }
30825
- async function assertOpenCodeMeasuredVersion(executable, options) {
30826
- const expected = options?.expected ?? OPENCODE_MEASURED_VERSION;
30945
+ async function assertOpenCodeVersionFloor(executable, options) {
30946
+ const minimumVersion = options?.minimumVersion ?? OPENCODE_MIN_VERSION;
30947
+ const lastMeasuredVersion = options?.lastMeasuredVersion ?? OPENCODE_LAST_MEASURED_VERSION;
30827
30948
  const timeoutMs = options?.timeoutMs ?? ACP_VERSION_CHECK_TIMEOUT_MS;
30828
30949
  const env = sanitizeChildEnv(options?.env ?? process.env);
30829
30950
  const stdout = await new Promise((resolve, reject) => {
@@ -30846,15 +30967,17 @@ async function assertOpenCodeMeasuredVersion(executable, options) {
30846
30967
  });
30847
30968
  const version3 = parseOpenCodeVersionOutput(stdout);
30848
30969
  if (!version3) {
30849
- throw new AcpVersionError(
30970
+ throw new AcpVersionParseError(
30850
30971
  `could not parse opencode version from: ${stdout.trim().slice(0, 200)}`
30851
30972
  );
30852
30973
  }
30853
- if (version3 !== expected) {
30854
- throw new AcpVersionError(
30855
- `refusing opencode ${version3}; host core is measured for ${expected} only`
30856
- );
30857
- }
30974
+ assertProviderVersionFloor({
30975
+ provider: "opencode",
30976
+ version: version3,
30977
+ minimumVersion,
30978
+ lastMeasuredVersion,
30979
+ ...options?.onNewerVersion ? { onNewerVersion: options.onNewerVersion } : {}
30980
+ });
30858
30981
  return version3;
30859
30982
  }
30860
30983
  function buildOpenCodeAcpArgs() {
@@ -31221,8 +31344,9 @@ async function openOpenCodeAcpSession(options) {
31221
31344
  };
31222
31345
  try {
31223
31346
  if (!options.skipVersionCheck) {
31224
- await assertOpenCodeMeasuredVersion(executable, {
31225
- env
31347
+ await assertOpenCodeVersionFloor(executable, {
31348
+ env,
31349
+ ...options.onVersionNotice ? { onNewerVersion: options.onVersionNotice } : {}
31226
31350
  });
31227
31351
  }
31228
31352
  if (!options.skipConfigProbe) {
@@ -31350,7 +31474,7 @@ function resolvePackagedClaudeBridge(pathEnv, platform = process.platform) {
31350
31474
  }
31351
31475
  throw new AcpHostError(
31352
31476
  "executable_missing",
31353
- "packaged claude-agent-acp executable not found; install @agentclientprotocol/claude-agent-acp@0.64.2"
31477
+ "packaged claude-agent-acp executable not found; install @agentclientprotocol/claude-agent-acp@latest (minimum 0.64.2)"
31354
31478
  );
31355
31479
  }
31356
31480
  function resolveWindowsNpmShim(shim) {
@@ -31422,14 +31546,10 @@ function buildClaudeLaunch(executable, args, platform = process.platform) {
31422
31546
  return platform === "win32" && (0, import_node_path6.extname)(executable).toLowerCase() === ".js" ? { command: process.execPath, args: [executable, ...args] } : { command: executable, args: [...args] };
31423
31547
  }
31424
31548
  function parseClaudeVersionOutput(stdout) {
31425
- const match = stdout.trim().match(/^(\d+\.\d+\.\d+)$/);
31426
- return match?.[1] ?? null;
31549
+ return parseProviderVersionOutput(stdout, /\bclaude-agent-acp\b/i);
31427
31550
  }
31428
31551
  function parseClaudeCodeVersionOutput(stdout) {
31429
- const match = stdout.match(
31430
- /^(\d+\.\d+\.\d+(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?) \(Claude Code\)\s*$/m
31431
- );
31432
- return match?.[1] ?? null;
31552
+ return parseProviderVersionOutput(stdout, /\bClaude Code\b/i, false);
31433
31553
  }
31434
31554
  async function readClaudeVersionOutput(executable, options) {
31435
31555
  const timeoutMs = options?.timeoutMs ?? ACP_VERSION_CHECK_TIMEOUT_MS;
@@ -31454,18 +31574,23 @@ async function readClaudeVersionOutput(executable, options) {
31454
31574
  );
31455
31575
  });
31456
31576
  }
31457
- async function assertClaudeMeasuredVersion(executable, options) {
31458
- const expected = options?.expected ?? CLAUDE_ACP_MEASURED_VERSION;
31577
+ async function assertClaudeVersionFloor(executable, options) {
31578
+ const minimumVersion = options?.minimumVersion ?? CLAUDE_ACP_MIN_VERSION;
31579
+ const lastMeasuredVersion = options?.lastMeasuredVersion ?? CLAUDE_ACP_LAST_MEASURED_VERSION;
31459
31580
  const stdout = await readClaudeVersionOutput(executable, options);
31460
31581
  const version3 = parseClaudeVersionOutput(stdout);
31461
31582
  if (!version3) {
31462
- throw new AcpVersionError(
31583
+ throw new AcpVersionParseError(
31463
31584
  `could not parse claude-agent-acp version from: ${stdout.trim().slice(0, 200)}`
31464
31585
  );
31465
31586
  }
31466
- if (version3 !== expected) {
31467
- throw new AcpVersionMismatchError(expected, version3);
31468
- }
31587
+ assertProviderVersionFloor({
31588
+ provider: "claude-agent-acp",
31589
+ version: version3,
31590
+ minimumVersion,
31591
+ lastMeasuredVersion,
31592
+ ...options?.onNewerVersion ? { onNewerVersion: options.onNewerVersion } : {}
31593
+ });
31469
31594
  return version3;
31470
31595
  }
31471
31596
  function buildClaudeAcpArgs() {
@@ -31537,18 +31662,22 @@ async function openClaudeAcpSession(options) {
31537
31662
  });
31538
31663
  const bridgeVersion = parseClaudeVersionOutput(output);
31539
31664
  if (bridgeVersion) {
31540
- if (bridgeVersion !== CLAUDE_ACP_MEASURED_VERSION) {
31541
- throw new AcpVersionMismatchError(
31542
- CLAUDE_ACP_MEASURED_VERSION,
31543
- bridgeVersion
31544
- );
31545
- }
31665
+ assertProviderVersionFloor({
31666
+ provider: "claude-agent-acp",
31667
+ version: bridgeVersion,
31668
+ minimumVersion: CLAUDE_ACP_MIN_VERSION,
31669
+ lastMeasuredVersion: CLAUDE_ACP_LAST_MEASURED_VERSION,
31670
+ ...options.onVersionNotice ? { onNewerVersion: options.onVersionNotice } : {}
31671
+ });
31546
31672
  executable = requestedExecutable;
31547
31673
  } else if (parseClaudeCodeVersionOutput(output)) {
31548
31674
  claudeCodeExecutable = requestedExecutable;
31549
31675
  executable = resolvePackagedClaudeBridge(resolvedPathEnv);
31550
31676
  env = buildClaudeChildEnv(parentEnv, claudeCodeExecutable);
31551
- await assertClaudeMeasuredVersion(executable, { env });
31677
+ await assertClaudeVersionFloor(executable, {
31678
+ env,
31679
+ ...options.onVersionNotice ? { onNewerVersion: options.onVersionNotice } : {}
31680
+ });
31552
31681
  } else {
31553
31682
  throw new AcpVersionError(
31554
31683
  `could not identify Claude executable from: ${output.trim().slice(0, 200)}`
@@ -31560,7 +31689,10 @@ async function openClaudeAcpSession(options) {
31560
31689
  resolvedPathEnv
31561
31690
  );
31562
31691
  if (!options.skipVersionCheck) {
31563
- await assertClaudeMeasuredVersion(executable, { env: baseEnv });
31692
+ await assertClaudeVersionFloor(executable, {
31693
+ env: baseEnv,
31694
+ ...options.onVersionNotice ? { onNewerVersion: options.onVersionNotice } : {}
31695
+ });
31564
31696
  }
31565
31697
  }
31566
31698
  if (options.signal?.aborted) {
@@ -31761,13 +31893,11 @@ function buildCodexLaunch(executable, args, platform = process.platform) {
31761
31893
  return platform === "win32" && (0, import_node_path7.extname)(executable).toLowerCase() === ".js" ? { command: process.execPath, args: [executable, ...args] } : { command: executable, args: [...args] };
31762
31894
  }
31763
31895
  function parseCodexVersionOutput(stdout) {
31764
- const match = stdout.trim().match(
31765
- /^@agentclientprotocol\/codex-acp (\d+\.\d+\.\d+)$/
31766
- );
31767
- return match?.[1] ?? null;
31896
+ return parseProviderVersionOutput(stdout, /@agentclientprotocol\/codex-acp\b/i);
31768
31897
  }
31769
- async function assertCodexMeasuredVersion(executable, options) {
31770
- const expected = options?.expected ?? CODEX_ACP_MEASURED_VERSION;
31898
+ async function assertCodexVersionFloor(executable, options) {
31899
+ const minimumVersion = options?.minimumVersion ?? CODEX_ACP_MIN_VERSION;
31900
+ const lastMeasuredVersion = options?.lastMeasuredVersion ?? CODEX_ACP_LAST_MEASURED_VERSION;
31771
31901
  const timeoutMs = options?.timeoutMs ?? ACP_VERSION_CHECK_TIMEOUT_MS;
31772
31902
  const env = options?.env ?? sanitizeChildEnv(process.env);
31773
31903
  const launch = buildCodexLaunch(executable, ["--version"], options?.platform);
@@ -31791,15 +31921,17 @@ async function assertCodexMeasuredVersion(executable, options) {
31791
31921
  });
31792
31922
  const version3 = parseCodexVersionOutput(stdout);
31793
31923
  if (!version3) {
31794
- throw new AcpVersionError(
31924
+ throw new AcpVersionParseError(
31795
31925
  `could not parse codex-acp version from: ${stdout.trim().slice(0, 200)}`
31796
31926
  );
31797
31927
  }
31798
- if (version3 !== expected) {
31799
- throw new AcpVersionError(
31800
- `refusing codex-acp ${version3}; host core is measured for ${expected} only`
31801
- );
31802
- }
31928
+ assertProviderVersionFloor({
31929
+ provider: "codex-acp",
31930
+ version: version3,
31931
+ minimumVersion,
31932
+ lastMeasuredVersion,
31933
+ ...options?.onNewerVersion ? { onNewerVersion: options.onNewerVersion } : {}
31934
+ });
31803
31935
  return version3;
31804
31936
  }
31805
31937
  function buildCodexAcpArgs() {
@@ -31855,7 +31987,10 @@ async function openCodexAcpSession(options) {
31855
31987
  );
31856
31988
  const env = buildCodexChildEnv(parentEnv);
31857
31989
  if (!options.skipVersionCheck) {
31858
- await assertCodexMeasuredVersion(executable, { env });
31990
+ await assertCodexVersionFloor(executable, {
31991
+ env,
31992
+ ...options.onVersionNotice ? { onNewerVersion: options.onVersionNotice } : {}
31993
+ });
31859
31994
  }
31860
31995
  if (options.signal?.aborted) {
31861
31996
  throw new AcpHostError(
@@ -32452,7 +32587,7 @@ var import_node_path8 = require("node:path");
32452
32587
  var import_node_util = require("node:util");
32453
32588
  var UUID_RE9 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
32454
32589
  var COMMAND_ID_RE2 = /^[A-Za-z0-9_-]{8,72}$/;
32455
- var MAX_EFFECT_BYTES = 32 * 1024;
32590
+ var MAX_EFFECT_BYTES = 1024 * 1024;
32456
32591
  var STATES = /* @__PURE__ */ new Set([
32457
32592
  "received",
32458
32593
  "prompting",
@@ -32534,7 +32669,7 @@ function parseListenerEffectRecord(raw, expectedId) {
32534
32669
  return parseV2Record(row);
32535
32670
  }
32536
32671
  function upcastV1Ask(row) {
32537
- if (row.effectOrdinal !== 0 || typeof row.commandId !== "string" || !COMMAND_ID_RE2.test(row.commandId) || typeof row.askBody !== "string" || row.askBody.length < 1 || row.askBody.length > 2e3 || typeof row.askUntil !== "string" || !Number.isFinite(Date.parse(row.askUntil)) || typeof row.senderOwnerRelation !== "string" || !RELATIONS.has(row.senderOwnerRelation) || typeof row.state !== "string" || !STATES.has(row.state) || !integer(row.promptAttempts) || !integer(row.postAttempts) || !nullableString(row.replyBody, 2e3) || typeof row.replyTruncated !== "boolean" || !nullableString(row.replySignalId, 64) || !nullableString(row.failureCode, 96) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt))) {
32672
+ if (row.effectOrdinal !== 0 || typeof row.commandId !== "string" || !COMMAND_ID_RE2.test(row.commandId) || typeof row.askBody !== "string" || row.askBody.length < 1 || typeof row.askUntil !== "string" || !Number.isFinite(Date.parse(row.askUntil)) || typeof row.senderOwnerRelation !== "string" || !RELATIONS.has(row.senderOwnerRelation) || typeof row.state !== "string" || !STATES.has(row.state) || !integer(row.promptAttempts) || !integer(row.postAttempts) || !nullableString(row.replyBody, 2e3) || typeof row.replyTruncated !== "boolean" || !nullableString(row.replySignalId, 64) || !nullableString(row.failureCode, 96) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt))) {
32538
32673
  throw new Error("stored listener effect is malformed");
32539
32674
  }
32540
32675
  if (row.replySignalId !== null && !UUID_RE9.test(row.replySignalId)) {
@@ -32561,7 +32696,7 @@ function upcastV1Ask(row) {
32561
32696
  }
32562
32697
  function parseV2Record(row) {
32563
32698
  const signalKind2 = row.signalKind;
32564
- if (typeof signalKind2 !== "string" || !SIGNAL_KINDS2.has(signalKind2) || row.effectOrdinal !== 0 || typeof row.askBody !== "string" || row.askBody.length < 1 || row.askBody.length > 2e3 || typeof row.askUntil !== "string" || !Number.isFinite(Date.parse(row.askUntil)) || typeof row.senderOwnerRelation !== "string" || !RELATIONS.has(row.senderOwnerRelation) || typeof row.state !== "string" || !STATES.has(row.state) || !integer(row.promptAttempts) || !integer(row.postAttempts) || !nullableString(row.replyBody, 2e3) || typeof row.replyTruncated !== "boolean" || !nullableString(row.replySignalId, 64) || !nullableString(row.failureCode, 96) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt))) {
32699
+ if (typeof signalKind2 !== "string" || !SIGNAL_KINDS2.has(signalKind2) || row.effectOrdinal !== 0 || typeof row.askBody !== "string" || row.askBody.length < 1 || typeof row.askUntil !== "string" || !Number.isFinite(Date.parse(row.askUntil)) || typeof row.senderOwnerRelation !== "string" || !RELATIONS.has(row.senderOwnerRelation) || typeof row.state !== "string" || !STATES.has(row.state) || !integer(row.promptAttempts) || !integer(row.postAttempts) || !nullableString(row.replyBody, 2e3) || typeof row.replyTruncated !== "boolean" || !nullableString(row.replySignalId, 64) || !nullableString(row.failureCode, 96) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt))) {
32565
32700
  throw new Error("stored listener effect is malformed");
32566
32701
  }
32567
32702
  if (signalKind2 === "note") {
@@ -32603,7 +32738,7 @@ function newObservedNoteRecord(input) {
32603
32738
  if (!UUID_RE9.test(input.signalId)) {
32604
32739
  throw new Error("listener note signal id must be a UUID");
32605
32740
  }
32606
- if (input.body.length < 1 || input.body.length > 2e3) {
32741
+ if (input.body.length < 1) {
32607
32742
  throw new Error("listener note body is invalid");
32608
32743
  }
32609
32744
  if (!Number.isFinite(Date.parse(input.until))) {
@@ -32765,10 +32900,12 @@ function resolveGrokExecutable(executable = "grok") {
32765
32900
  return executable;
32766
32901
  }
32767
32902
  function parseGrokVersionOutput(stdout) {
32768
- const m = stdout.match(/\bgrok\s+(\d+\.\d+\.\d+)\b/i);
32769
- return m?.[1] ?? null;
32903
+ return parseProviderVersionOutput(stdout, /\bgrok\b/i);
32770
32904
  }
32771
- async function assertGrokMeasuredVersion(executable, expected = GROK_MEASURED_VERSION, timeoutMs = ACP_VERSION_CHECK_TIMEOUT_MS) {
32905
+ async function assertGrokVersionFloor(executable, options) {
32906
+ const minimumVersion = options?.minimumVersion ?? GROK_MIN_VERSION;
32907
+ const lastMeasuredVersion = options?.lastMeasuredVersion ?? GROK_LAST_MEASURED_VERSION;
32908
+ const timeoutMs = options?.timeoutMs ?? ACP_VERSION_CHECK_TIMEOUT_MS;
32772
32909
  const stdout = await new Promise((resolve, reject) => {
32773
32910
  (0, import_node_child_process6.execFile)(
32774
32911
  executable,
@@ -32789,15 +32926,17 @@ async function assertGrokMeasuredVersion(executable, expected = GROK_MEASURED_VE
32789
32926
  });
32790
32927
  const version3 = parseGrokVersionOutput(stdout);
32791
32928
  if (!version3) {
32792
- throw new AcpVersionError(
32929
+ throw new AcpVersionParseError(
32793
32930
  `could not parse grok version from: ${stdout.trim().slice(0, 200)}`
32794
32931
  );
32795
32932
  }
32796
- if (version3 !== expected) {
32797
- throw new AcpVersionError(
32798
- `refusing grok ${version3}; host core is measured for ${expected} only`
32799
- );
32800
- }
32933
+ assertProviderVersionFloor({
32934
+ provider: "grok",
32935
+ version: version3,
32936
+ minimumVersion,
32937
+ lastMeasuredVersion,
32938
+ ...options?.onNewerVersion ? { onNewerVersion: options.onNewerVersion } : {}
32939
+ });
32801
32940
  return version3;
32802
32941
  }
32803
32942
  function buildGrokAcpArgs(options) {
@@ -32855,7 +32994,9 @@ async function terminateGrokChild(child) {
32855
32994
  async function openGrokAcpSession(options) {
32856
32995
  const executable = resolveGrokExecutable(options.executable ?? "grok");
32857
32996
  if (!options.skipVersionCheck) {
32858
- await assertGrokMeasuredVersion(executable);
32997
+ await assertGrokVersionFloor(executable, {
32998
+ ...options.onVersionNotice ? { onNewerVersion: options.onVersionNotice } : {}
32999
+ });
32859
33000
  }
32860
33001
  const args = buildGrokAcpArgs({
32861
33002
  model: options.model,
@@ -32984,6 +33125,7 @@ var GrokListenerModel = class {
32984
33125
  ...this.options.model ? { model: this.options.model } : {},
32985
33126
  ...this.options.effort ? { effort: this.options.effort } : {},
32986
33127
  ...this.options.env ? { env: this.options.env } : {},
33128
+ ...this.options.onVersionNotice ? { onVersionNotice: this.options.onVersionNotice } : {},
32987
33129
  ...this.options.onWorkerStderrTail ? { onStderrTail: this.options.onWorkerStderrTail } : {},
32988
33130
  clientName: "cswarm-listener"
32989
33131
  });
@@ -33392,6 +33534,7 @@ var OpenCodeListenerModel = class {
33392
33534
  ...this.options.executable ? { executable: this.options.executable } : {},
33393
33535
  ...this.options.model ? { model: this.options.model } : {},
33394
33536
  ...this.options.env ? { env: this.options.env } : {},
33537
+ ...this.options.onVersionNotice ? { onVersionNotice: this.options.onVersionNotice } : {},
33395
33538
  ...this.options.allowMissingAuth === true ? { allowMissingAuth: true } : {},
33396
33539
  ...this.options.onWorkerStderrTail ? { onStderrTail: this.options.onWorkerStderrTail } : {},
33397
33540
  clientName: "cswarm-listener"
@@ -33601,6 +33744,7 @@ var ClaudeListenerModel = class {
33601
33744
  permissionCallback,
33602
33745
  ...this.options.executable ? { executable: this.options.executable } : {},
33603
33746
  ...this.options.env ? { env: this.options.env } : {},
33747
+ ...this.options.onVersionNotice ? { onVersionNotice: this.options.onVersionNotice } : {},
33604
33748
  signal: controller.signal,
33605
33749
  ...this.options.onWorkerStderrTail ? { onStderrTail: this.options.onWorkerStderrTail } : {},
33606
33750
  clientName: "cswarm-listener"
@@ -33769,6 +33913,7 @@ var CodexListenerModel = class {
33769
33913
  permissionCallback,
33770
33914
  ...this.options.executable ? { executable: this.options.executable } : {},
33771
33915
  ...this.options.env ? { env: this.options.env } : {},
33916
+ ...this.options.onVersionNotice ? { onVersionNotice: this.options.onVersionNotice } : {},
33772
33917
  signal: controller.signal,
33773
33918
  ...this.options.onWorkerStderrTail ? { onStderrTail: this.options.onWorkerStderrTail } : {},
33774
33919
  clientName: "cswarm-listener"
@@ -34427,7 +34572,7 @@ function parseEntry(value) {
34427
34572
  if (Object.keys(row).some((key2) => !allowed.has(key2))) {
34428
34573
  throw new Error("stored pending-for-main entry is malformed");
34429
34574
  }
34430
- if (typeof row.signalId !== "string" || !UUID_RE11.test(row.signalId) || typeof row.workspaceId !== "string" || !UUID_RE11.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE11.test(row.principalId) || typeof row.fromId !== "string" || !UUID_RE11.test(row.fromId) || row.fromKind !== "user" && row.fromKind !== "agent" || !(row.kind === void 0 || row.kind === "ask" || row.kind === "note") || !(row.senderName === null || typeof row.senderName === "string" && row.senderName.length <= 200) || typeof row.body !== "string" || row.body.length < 1 || row.body.length > 2e3 || !checkedTimestamp2(row.createdAt) || !checkedTimestamp2(row.queuedAt)) {
34575
+ if (typeof row.signalId !== "string" || !UUID_RE11.test(row.signalId) || typeof row.workspaceId !== "string" || !UUID_RE11.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE11.test(row.principalId) || typeof row.fromId !== "string" || !UUID_RE11.test(row.fromId) || row.fromKind !== "user" && row.fromKind !== "agent" || !(row.kind === void 0 || row.kind === "ask" || row.kind === "note") || !(row.senderName === null || typeof row.senderName === "string" && row.senderName.length <= 200) || typeof row.body !== "string" || row.body.length < 1 || !checkedTimestamp2(row.createdAt) || !checkedTimestamp2(row.queuedAt)) {
34431
34576
  throw new Error("stored pending-for-main entry is malformed");
34432
34577
  }
34433
34578
  return {
@@ -35662,6 +35807,7 @@ var import_node_net = require("node:net");
35662
35807
  var import_promises9 = require("node:fs/promises");
35663
35808
  var import_node_path15 = require("node:path");
35664
35809
  var UUID_RE13 = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i;
35810
+ var SEMVER_RE2 = /^(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)\.(?:0|[1-9]\d*)(?:-(?:0|[1-9]\d*|[A-Za-z-][0-9A-Za-z-]*)(?:\.(?:0|[1-9]\d*|[A-Za-z-][0-9A-Za-z-]*))*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?$/;
35665
35811
  var MAX_STATUS_BYTES = 16 * 1024;
35666
35812
  var MAX_CONTROL_BYTES = 8 * 1024;
35667
35813
  var CONTROL_TIMEOUT_MS = 2e3;
@@ -35708,6 +35854,8 @@ var STATUS_ALLOWED_KEYS = /* @__PURE__ */ new Set([
35708
35854
  "stoppedAt",
35709
35855
  "lastSignalId",
35710
35856
  "lastErrorCode",
35857
+ "providerVersion",
35858
+ "providerLastMeasuredVersion",
35711
35859
  "lastWorkerStderrTail",
35712
35860
  "logPath",
35713
35861
  "deliveryMode",
@@ -35767,7 +35915,7 @@ function parseStatus(raw) {
35767
35915
  const nullableUuid2 = (candidate) => candidate === null || typeof candidate === "string" && UUID_RE13.test(candidate);
35768
35916
  const nullableCount = (candidate) => candidate === null || typeof candidate === "number" && Number.isSafeInteger(candidate) && candidate >= 0;
35769
35917
  const nullableTimestamp = (candidate) => candidate === null || typeof candidate === "string" && Number.isFinite(Date.parse(candidate));
35770
- if (row.version !== 1 || typeof row.instanceId !== "string" || !UUID_RE13.test(row.instanceId) || row.provider !== "grok" && row.provider !== "opencode" && row.provider !== "claude" && row.provider !== "codex" || typeof row.profileId !== "string" || typeof row.workspaceId !== "string" || !UUID_RE13.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE13.test(row.principalId) || !Number.isSafeInteger(row.pid) || row.pid < 1 || typeof row.state !== "string" || !["starting", "ready", "stopping", "stopped", "failed"].includes(row.state) || typeof row.startedAt !== "string" || !Number.isFinite(Date.parse(row.startedAt)) || !(row.readyAt === null || typeof row.readyAt === "string" && Number.isFinite(Date.parse(row.readyAt))) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt)) || !(row.stoppedAt === null || typeof row.stoppedAt === "string" && Number.isFinite(Date.parse(row.stoppedAt))) || !nullableUuid2(row.lastSignalId) || !(row.lastErrorCode === null || typeof row.lastErrorCode === "string" && /^[a-z0-9_-]{1,96}$/.test(row.lastErrorCode)) || !(row.lastWorkerStderrTail === void 0 || row.lastWorkerStderrTail === null || typeof row.lastWorkerStderrTail === "string" && row.lastWorkerStderrTail.length > 0 && row.lastWorkerStderrTail.length <= 2048 && !/swm_(?:agt|inv|cap)_/i.test(row.lastWorkerStderrTail)) || typeof row.logPath !== "string" || !(0, import_node_path15.isAbsolute)(row.logPath) || !(row.deliveryMode === void 0 || row.deliveryMode === null || typeof row.deliveryMode === "string" && STATUS_DELIVERY_MODES.has(row.deliveryMode)) || !(row.pendingDeliveryCount === void 0 || nullableCount(row.pendingDeliveryCount)) || !(row.lastTerminalDeliveryFailureCount === void 0 || nullableCount(row.lastTerminalDeliveryFailureCount)) || !(row.lastTerminalDeliveryFailureAt === void 0 || nullableTimestamp(row.lastTerminalDeliveryFailureAt)) || !(row.lastClaimAt === void 0 || nullableTimestamp(row.lastClaimAt)) || !(row.lastAckAt === void 0 || nullableTimestamp(row.lastAckAt)) || !(row.routeMode === void 0 || row.routeMode === "worker" || row.routeMode === "main" || row.routeMode === "split") || !(row.deferOverChars === void 0 || row.deferOverChars === null || typeof row.deferOverChars === "number" && Number.isSafeInteger(row.deferOverChars) && row.deferOverChars >= 1 && row.deferOverChars <= 1e4) || !(row.pendingForMainCount === void 0 || typeof row.pendingForMainCount === "number" && Number.isSafeInteger(row.pendingForMainCount) && row.pendingForMainCount >= 0) || !(row.droppedForMainCount === void 0 || typeof row.droppedForMainCount === "number" && Number.isSafeInteger(row.droppedForMainCount) && row.droppedForMainCount >= 0)) {
35918
+ if (row.version !== 1 || typeof row.instanceId !== "string" || !UUID_RE13.test(row.instanceId) || row.provider !== "grok" && row.provider !== "opencode" && row.provider !== "claude" && row.provider !== "codex" || typeof row.profileId !== "string" || typeof row.workspaceId !== "string" || !UUID_RE13.test(row.workspaceId) || typeof row.principalId !== "string" || !UUID_RE13.test(row.principalId) || !Number.isSafeInteger(row.pid) || row.pid < 1 || typeof row.state !== "string" || !["starting", "ready", "stopping", "stopped", "failed"].includes(row.state) || typeof row.startedAt !== "string" || !Number.isFinite(Date.parse(row.startedAt)) || !(row.readyAt === null || typeof row.readyAt === "string" && Number.isFinite(Date.parse(row.readyAt))) || typeof row.updatedAt !== "string" || !Number.isFinite(Date.parse(row.updatedAt)) || !(row.stoppedAt === null || typeof row.stoppedAt === "string" && Number.isFinite(Date.parse(row.stoppedAt))) || !nullableUuid2(row.lastSignalId) || !(row.lastErrorCode === null || typeof row.lastErrorCode === "string" && /^[a-z0-9_-]{1,96}$/.test(row.lastErrorCode)) || !(row.providerVersion === void 0 || row.providerVersion === null || typeof row.providerVersion === "string" && SEMVER_RE2.test(row.providerVersion)) || !(row.providerLastMeasuredVersion === void 0 || row.providerLastMeasuredVersion === null || typeof row.providerLastMeasuredVersion === "string" && SEMVER_RE2.test(row.providerLastMeasuredVersion)) || (row.providerVersion === null || row.providerVersion === void 0) !== (row.providerLastMeasuredVersion === null || row.providerLastMeasuredVersion === void 0) || !(row.lastWorkerStderrTail === void 0 || row.lastWorkerStderrTail === null || typeof row.lastWorkerStderrTail === "string" && row.lastWorkerStderrTail.length > 0 && row.lastWorkerStderrTail.length <= 2048 && !/swm_(?:agt|inv|cap)_/i.test(row.lastWorkerStderrTail)) || typeof row.logPath !== "string" || !(0, import_node_path15.isAbsolute)(row.logPath) || !(row.deliveryMode === void 0 || row.deliveryMode === null || typeof row.deliveryMode === "string" && STATUS_DELIVERY_MODES.has(row.deliveryMode)) || !(row.pendingDeliveryCount === void 0 || nullableCount(row.pendingDeliveryCount)) || !(row.lastTerminalDeliveryFailureCount === void 0 || nullableCount(row.lastTerminalDeliveryFailureCount)) || !(row.lastTerminalDeliveryFailureAt === void 0 || nullableTimestamp(row.lastTerminalDeliveryFailureAt)) || !(row.lastClaimAt === void 0 || nullableTimestamp(row.lastClaimAt)) || !(row.lastAckAt === void 0 || nullableTimestamp(row.lastAckAt)) || !(row.routeMode === void 0 || row.routeMode === "worker" || row.routeMode === "main" || row.routeMode === "split") || !(row.deferOverChars === void 0 || row.deferOverChars === null || typeof row.deferOverChars === "number" && Number.isSafeInteger(row.deferOverChars) && row.deferOverChars >= 1 && row.deferOverChars <= 1e4) || !(row.pendingForMainCount === void 0 || typeof row.pendingForMainCount === "number" && Number.isSafeInteger(row.pendingForMainCount) && row.pendingForMainCount >= 0) || !(row.droppedForMainCount === void 0 || typeof row.droppedForMainCount === "number" && Number.isSafeInteger(row.droppedForMainCount) && row.droppedForMainCount >= 0)) {
35771
35919
  throw new Error("stored listener status is malformed");
35772
35920
  }
35773
35921
  const routeMode = row.routeMode ?? "worker";
@@ -35784,6 +35932,8 @@ function parseStatus(raw) {
35784
35932
  lastClaimAt: row.lastClaimAt ?? null,
35785
35933
  lastAckAt: row.lastAckAt ?? null,
35786
35934
  lastWorkerStderrTail: row.lastWorkerStderrTail ?? null,
35935
+ providerVersion: row.providerVersion ?? null,
35936
+ providerLastMeasuredVersion: row.providerLastMeasuredVersion ?? null,
35787
35937
  routeMode,
35788
35938
  deferOverChars,
35789
35939
  pendingForMainCount: row.pendingForMainCount ?? 0,
@@ -36195,6 +36345,8 @@ async function runListenerSupervisor(options) {
36195
36345
  stoppedAt: null,
36196
36346
  lastSignalId: null,
36197
36347
  lastErrorCode: null,
36348
+ providerVersion: null,
36349
+ providerLastMeasuredVersion: null,
36198
36350
  lastWorkerStderrTail: null,
36199
36351
  deliveryMode: null,
36200
36352
  pendingDeliveryCount: null,
@@ -36264,10 +36416,13 @@ async function runListenerSupervisor(options) {
36264
36416
  };
36265
36417
  const onEvent = (event) => {
36266
36418
  if (event.type === "ready") {
36419
+ const versionNotice = options.getProviderVersionNotice?.() ?? null;
36267
36420
  transition("ready", {
36268
36421
  readyAt: event.ts,
36269
36422
  lastErrorCode: null,
36270
- lastWorkerStderrTail: null
36423
+ lastWorkerStderrTail: null,
36424
+ providerVersion: versionNotice?.runningVersion ?? null,
36425
+ providerLastMeasuredVersion: versionNotice?.lastMeasuredVersion ?? null
36271
36426
  });
36272
36427
  log({ ts: event.ts, event: "listener_ready" });
36273
36428
  return;
@@ -36465,7 +36620,9 @@ async function runListenerSupervisor(options) {
36465
36620
  transition("starting", {
36466
36621
  readyAt: null,
36467
36622
  lastErrorCode: restartCode,
36468
- lastWorkerStderrTail: restartStderrTail
36623
+ lastWorkerStderrTail: restartStderrTail,
36624
+ providerVersion: null,
36625
+ providerLastMeasuredVersion: null
36469
36626
  });
36470
36627
  await restartSleep(delayMs, controller.signal);
36471
36628
  if (controller.signal.aborted) {
@@ -37994,8 +38151,8 @@ var ACCEPTED_AGENT_CREDENTIAL_MESSAGES = [
37994
38151
  AGENT_CREDENTIAL_MESSAGE_D088
37995
38152
  ];
37996
38153
  function packageVersion() {
37997
- if ("0.1.27".length > 0) {
37998
- return "0.1.27";
38154
+ if ("0.1.29".length > 0) {
38155
+ return "0.1.29";
37999
38156
  }
38000
38157
  try {
38001
38158
  const value = JSON.parse(
@@ -38111,8 +38268,8 @@ Usage:
38111
38268
  cswarm status [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--json]
38112
38269
  cswarm members [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--agent-token-stdin] [--json]
38113
38270
  cswarm working-on "<what>" [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--about <ref>] [--until <dur>] [--json]
38114
- cswarm note "<text>" [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--to <member|agent>] [--about <ref>] [--until <dur>] [--json]
38115
- cswarm ask "<text>" [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--to <member|agent>] [--about <ref>] [--until <dur>] [--wait <seconds>] [--json]
38271
+ cswarm note "<text>" [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--to <member|agent>] [--about <ref>] [--until <dur>] [--json] # text: 1..8000 characters
38272
+ cswarm ask "<text>" [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--to <member|agent>] [--about <ref>] [--until <dur>] [--wait <seconds>] [--json] # text: 1..8000 characters
38116
38273
  cswarm reply <signal-id> "<text>" [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--until <dur>] [--json]
38117
38274
  cswarm feed [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--about <ref>] [--kind <kind>] [--since <timestamp>] [--limit <n>] [--include-stale] [--json]
38118
38275
  cswarm inbox [--url <url> --anon-key <key>] [--workspace-id <uuid>] [--kind <kind>] [--about <ref>] [--since <timestamp>] [--limit <n>] [--include-stale] [--wait <seconds>] [--json]
@@ -38178,7 +38335,7 @@ Signals (intention sharing) accept the same credential selection. Agent mode
38178
38335
  never opens a browser or infers a human's saved workspace. Durations use a whole
38179
38336
  number plus m, h, or d (for example 90m, 24h, or 7d) and are capped at 30d.
38180
38337
  Place -- before signal text that itself begins with -- to stop option parsing.
38181
- Signal text is at most 2000 characters and --about at most 500; a longer body is
38338
+ Signal text is at most 8000 characters and --about at most 500; a longer body is
38182
38339
  refused locally before any network call, so compose within the limit.
38183
38340
 
38184
38341
  listen start --turn-budget bounds ONE worker prompt turn (default 10m): how long
@@ -39662,13 +39819,18 @@ function resolveTurnBudgetOrDefer(configuredBudgetMs, credentialExpiresAt, nowMs
39662
39819
  }
39663
39820
  return clampTurnBudgetToCredential(configuredBudgetMs, credentialExpiresAt, nowMs);
39664
39821
  }
39665
- var SIGNAL_BODY_MAX = 2e3;
39822
+ var SIGNAL_BODY_MAX = 8e3;
39666
39823
  var SIGNAL_ABOUT_MAX = 500;
39667
39824
  function signalText(value, label) {
39668
39825
  const maximum = label === "body" ? SIGNAL_BODY_MAX : SIGNAL_ABOUT_MAX;
39669
39826
  if (value.length < (label === "body" ? 1 : 0) || value.length > maximum) {
39827
+ if (label === "body") {
39828
+ throw new Error(
39829
+ `signal text is ${value.length} characters; the maximum is ${maximum}`
39830
+ );
39831
+ }
39670
39832
  throw new Error(
39671
- `${label === "body" ? "signal text" : "--about"} must be ${label === "body" ? "1.." : "at most "}${maximum} characters`
39833
+ `--about must be at most ${maximum} characters`
39672
39834
  );
39673
39835
  }
39674
39836
  return value;
@@ -40329,7 +40491,7 @@ function listenerModelLabel(provider) {
40329
40491
  }
40330
40492
  function listenerProvider(args) {
40331
40493
  const provider = args.optional("provider");
40332
- const hints = "supported providers: grok \u2014 install Grok CLI 0.2.117 and run grok login; opencode \u2014 install OpenCode 1.18.10 and authenticate it; claude \u2014 npm install -g @agentclientprotocol/claude-agent-acp@0.64.2; codex \u2014 npm install -g @agentclientprotocol/codex-acp@1.1.9. You can use working-on, note, ask, and feed now; detached live receipt needs one of these adapters";
40494
+ const hints = "supported providers: grok \u2014 install Grok CLI 0.2.117 or newer and run grok login; opencode \u2014 install OpenCode 1.18.10 or newer and authenticate it; claude \u2014 npm install -g @agentclientprotocol/claude-agent-acp@latest (minimum 0.64.2); codex \u2014 npm install -g @agentclientprotocol/codex-acp@latest (minimum 1.1.9). You can use working-on, note, ask, and feed now; detached live receipt needs one of these adapters";
40333
40495
  if (provider === void 0) {
40334
40496
  throw new Error(`--provider is required; ${hints}`);
40335
40497
  }
@@ -40390,7 +40552,7 @@ function listenerHostLimits(provider) {
40390
40552
  };
40391
40553
  }
40392
40554
  if (provider === "claude") {
40393
- const host_configuration2 = "The Claude worker uses the operator-selected cwd and the normal Claude Code home through claude-agent-acp 0.64.2. Keychain/OAuth auth was measured; ANTHROPIC_API_KEY is stripped by the listener environment sanitizer.";
40555
+ const host_configuration2 = "The Claude worker uses the operator-selected cwd and the normal Claude Code home through claude-agent-acp 0.64.2 or newer. Keychain/OAuth auth was measured; ANTHROPIC_API_KEY is stripped by the listener environment sanitizer.";
40394
40556
  const deny_canary_scope2 = "The deny canary proves host reject + correlated terminal deny only.";
40395
40557
  const steady_allow_unproven2 = "The deny canary does not prove steady-state --permissions allow behavior.";
40396
40558
  const cross_owner_context2 = "All sender relations reach that same worker and local context; each prompt carries sender and operator provenance.";
@@ -40414,7 +40576,7 @@ function listenerHostLimits(provider) {
40414
40576
  };
40415
40577
  }
40416
40578
  if (provider === "codex") {
40417
- const host_configuration2 = "The Codex worker uses the operator-selected cwd and normal ChatGPT/Codex auth through codex-acp 1.1.9. CommonSwarm explicitly selects read-only mode after every session/new; API-key variables are stripped by the listener environment sanitizer.";
40579
+ const host_configuration2 = "The Codex worker uses the operator-selected cwd and normal ChatGPT/Codex auth through codex-acp 1.1.9 or newer. CommonSwarm explicitly selects read-only mode after every session/new; API-key variables are stripped by the listener environment sanitizer.";
40418
40580
  const deny_canary_scope2 = "The deny canary proves host reject + correlated terminal deny only.";
40419
40581
  const steady_allow_unproven2 = "The deny canary does not prove steady-state --permissions allow behavior.";
40420
40582
  const cross_owner_context2 = "All sender relations reach that same worker and local context; each prompt carries sender and operator provenance.";
@@ -40503,6 +40665,11 @@ function renderListenerStatus(status) {
40503
40665
  lines.push(` ${line}`);
40504
40666
  }
40505
40667
  }
40668
+ if (status.providerVersion && status.providerLastMeasuredVersion) {
40669
+ lines.push(
40670
+ `Provider version ${status.providerVersion} is newer than the last measured version ${status.providerLastMeasuredVersion}. It is unverified but allowed because the startup permission canary passed. Next: verify this provider release with CommonSwarm and update the last-measured version.`
40671
+ );
40672
+ }
40506
40673
  if (status.deliveryMode === "durable_claim") {
40507
40674
  lines.push("Delivery mode: durable claim and acknowledgement.");
40508
40675
  } else if (status.deliveryMode === "cursor_fallback") {
@@ -40545,29 +40712,35 @@ function renderListenerStatus(status) {
40545
40712
  return lines.join("\n");
40546
40713
  }
40547
40714
  function listenerFailureMessage(code, provider) {
40548
- if (code === "version_refused") {
40715
+ if (code === "version_below_floor") {
40549
40716
  if (provider === "codex") {
40550
- return "the Codex listener requires codex-acp 1.1.9; run npm install -g @agentclientprotocol/codex-acp@1.1.9, then retry";
40717
+ return "the Codex listener requires codex-acp 1.1.9 or newer; update the bridge, then retry";
40551
40718
  }
40552
40719
  if (provider === "claude") {
40553
- return "the Claude listener requires claude-agent-acp 0.64.2; run npm install -g @agentclientprotocol/claude-agent-acp@0.64.2, then retry";
40720
+ return "the Claude listener requires claude-agent-acp 0.64.2 or newer; update the bridge, then retry";
40554
40721
  }
40555
40722
  if (provider === "opencode") {
40556
- return "the OpenCode listener requires OpenCode 1.18.10; install that pinned build, then retry";
40723
+ return "the OpenCode listener requires OpenCode 1.18.10 or newer; update OpenCode, then retry";
40557
40724
  }
40558
- return "the Grok listener requires Grok 0.2.117; install that pinned build and run grok login, then retry";
40725
+ return "the Grok listener requires Grok 0.2.117 or newer; update Grok, confirm grok login, then retry";
40726
+ }
40727
+ if (code === "version_unparseable") {
40728
+ return `the ${provider ?? "provider"} version output was not valid semantic version data, so startup stopped. Next: run the provider's --version command, then update or reinstall it`;
40729
+ }
40730
+ if (code === "version_refused") {
40731
+ return `the ${provider ?? "provider"} version check could not run, so startup stopped. Next: run the provider's --version command and fix that error, then retry`;
40559
40732
  }
40560
40733
  if (code === "executable_missing" && provider === "claude") {
40561
- return "claude-agent-acp is not installed; run npm install -g @agentclientprotocol/claude-agent-acp@0.64.2, then retry";
40734
+ return "claude-agent-acp is not installed; run npm install -g @agentclientprotocol/claude-agent-acp@latest (minimum 0.64.2), then retry";
40562
40735
  }
40563
40736
  if (code === "executable_missing" && provider === "codex") {
40564
- return "codex-acp is not installed; run npm install -g @agentclientprotocol/codex-acp@1.1.9, then retry";
40737
+ return "codex-acp is not installed; run npm install -g @agentclientprotocol/codex-acp@latest (minimum 1.1.9), then retry";
40565
40738
  }
40566
40739
  if (code === "permission_mode_unavailable" && provider === "claude") {
40567
- return "the Claude bridge does not expose the required manual permission mode; reinstall claude-agent-acp 0.64.2, then retry";
40740
+ return "the Claude bridge does not expose the required manual permission mode; update or reinstall claude-agent-acp, then retry";
40568
40741
  }
40569
40742
  if (code === "permission_mode_unavailable" && provider === "codex") {
40570
- return "the Codex bridge does not expose the required read-only permission mode; reinstall codex-acp 1.1.9, then retry";
40743
+ return "the Codex bridge does not expose the required read-only permission mode; update or reinstall codex-acp, then retry";
40571
40744
  }
40572
40745
  if (provider === "claude" && (code === "rpc_error" || code === "child_exit" || code === "timeout")) {
40573
40746
  return `the Claude bridge could not start (${code}); confirm Claude Code keychain/OAuth sign-in and network access, then retry. ANTHROPIC_API_KEY is not forwarded to detached listeners`;
@@ -40619,7 +40792,7 @@ function resolveDetachedClaudeExecutable(executable = "claude-agent-acp", pathEn
40619
40792
  if ((0, import_node_path19.isAbsolute)(executable) || executable.includes("/") || executable.includes("\\")) {
40620
40793
  const detail = error instanceof Error ? error.message : code;
40621
40794
  throw new Error(
40622
- `could not use --claude-executable: ${detail}; reinstall the measured bridge with npm install -g @agentclientprotocol/claude-agent-acp@0.64.2 if this path should be replaced`
40795
+ `could not use --claude-executable: ${detail}; install the current bridge with npm install -g @agentclientprotocol/claude-agent-acp@latest if this path should be replaced`
40623
40796
  );
40624
40797
  }
40625
40798
  throw new Error(listenerFailureMessage(code, "claude"));
@@ -40636,7 +40809,7 @@ function resolveDetachedCodexExecutable(executable = "codex-acp", pathEnv = proc
40636
40809
  if ((0, import_node_path19.isAbsolute)(executable) || executable.includes("/") || executable.includes("\\")) {
40637
40810
  const detail = error instanceof Error ? error.message : code;
40638
40811
  throw new Error(
40639
- `could not use --codex-executable: ${detail}; reinstall the measured bridge with npm install -g @agentclientprotocol/codex-acp@1.1.9 if this path should be replaced`
40812
+ `could not use --codex-executable: ${detail}; install the current bridge with npm install -g @agentclientprotocol/codex-acp@latest if this path should be replaced`
40640
40813
  );
40641
40814
  }
40642
40815
  throw new Error(listenerFailureMessage(code, "codex"));
@@ -40740,6 +40913,10 @@ async function runConfiguredListener(options) {
40740
40913
  };
40741
40914
  let lastWorkerStderrTail = null;
40742
40915
  let workerStderrGeneration = 0;
40916
+ let providerVersionNotice = null;
40917
+ const onVersionNotice = (notice) => {
40918
+ providerVersionNotice = notice;
40919
+ };
40743
40920
  const newWorkerStderrTailSink = () => {
40744
40921
  const generation = ++workerStderrGeneration;
40745
40922
  lastWorkerStderrTail = null;
@@ -40748,34 +40925,41 @@ async function runConfiguredListener(options) {
40748
40925
  lastWorkerStderrTail = tail.length > 0 ? tail : null;
40749
40926
  };
40750
40927
  };
40751
- const newModel = () => options.provider === "opencode" ? new OpenCodeListenerModel({
40752
- cwd: options.cwd,
40753
- permissionMode: options.permissionMode,
40754
- promptTimeoutMs: resolveTurnBudgetMs,
40755
- onWorkerStderrTail: newWorkerStderrTailSink(),
40756
- ...options.model ? { model: options.model } : {},
40757
- ...options.opencodeExecutable ? { executable: options.opencodeExecutable } : options.executable ? { executable: options.executable } : {}
40758
- }) : options.provider === "claude" ? new ClaudeListenerModel({
40759
- cwd: options.cwd,
40760
- permissionMode: options.permissionMode,
40761
- promptTimeoutMs: resolveTurnBudgetMs,
40762
- onWorkerStderrTail: newWorkerStderrTailSink(),
40763
- ...options.claudeExecutable ? { executable: options.claudeExecutable } : options.executable ? { executable: options.executable } : {}
40764
- }) : options.provider === "codex" ? new CodexListenerModel({
40765
- cwd: options.cwd,
40766
- permissionMode: options.permissionMode,
40767
- promptTimeoutMs: resolveTurnBudgetMs,
40768
- onWorkerStderrTail: newWorkerStderrTailSink(),
40769
- ...options.codexExecutable ? { executable: options.codexExecutable } : options.executable ? { executable: options.executable } : {}
40770
- }) : new GrokListenerModel({
40771
- cwd: options.cwd,
40772
- permissionMode: options.permissionMode,
40773
- promptTimeoutMs: resolveTurnBudgetMs,
40774
- onWorkerStderrTail: newWorkerStderrTailSink(),
40775
- ...options.model ? { model: options.model } : {},
40776
- ...options.effort ? { effort: options.effort } : {},
40777
- ...options.executable ? { executable: options.executable } : {}
40778
- });
40928
+ const newModel = () => {
40929
+ providerVersionNotice = null;
40930
+ return options.provider === "opencode" ? new OpenCodeListenerModel({
40931
+ cwd: options.cwd,
40932
+ permissionMode: options.permissionMode,
40933
+ promptTimeoutMs: resolveTurnBudgetMs,
40934
+ onWorkerStderrTail: newWorkerStderrTailSink(),
40935
+ onVersionNotice,
40936
+ ...options.model ? { model: options.model } : {},
40937
+ ...options.opencodeExecutable ? { executable: options.opencodeExecutable } : options.executable ? { executable: options.executable } : {}
40938
+ }) : options.provider === "claude" ? new ClaudeListenerModel({
40939
+ cwd: options.cwd,
40940
+ permissionMode: options.permissionMode,
40941
+ promptTimeoutMs: resolveTurnBudgetMs,
40942
+ onWorkerStderrTail: newWorkerStderrTailSink(),
40943
+ onVersionNotice,
40944
+ ...options.claudeExecutable ? { executable: options.claudeExecutable } : options.executable ? { executable: options.executable } : {}
40945
+ }) : options.provider === "codex" ? new CodexListenerModel({
40946
+ cwd: options.cwd,
40947
+ permissionMode: options.permissionMode,
40948
+ promptTimeoutMs: resolveTurnBudgetMs,
40949
+ onWorkerStderrTail: newWorkerStderrTailSink(),
40950
+ onVersionNotice,
40951
+ ...options.codexExecutable ? { executable: options.codexExecutable } : options.executable ? { executable: options.executable } : {}
40952
+ }) : new GrokListenerModel({
40953
+ cwd: options.cwd,
40954
+ permissionMode: options.permissionMode,
40955
+ promptTimeoutMs: resolveTurnBudgetMs,
40956
+ onWorkerStderrTail: newWorkerStderrTailSink(),
40957
+ onVersionNotice,
40958
+ ...options.model ? { model: options.model } : {},
40959
+ ...options.effort ? { effort: options.effort } : {},
40960
+ ...options.executable ? { executable: options.executable } : {}
40961
+ });
40962
+ };
40779
40963
  const onProcessSignal = () => {
40780
40964
  void stopListener(paths);
40781
40965
  };
@@ -40799,6 +40983,7 @@ async function runConfiguredListener(options) {
40799
40983
  // The bound a timeout event reports: the last turn's clamped budget when
40800
40984
  // one has run, else the configured cap.
40801
40985
  getTurnBudgetMs: () => lastAppliedTurnBudgetMs ?? turnBudgetMs,
40986
+ getProviderVersionNotice: () => providerVersionNotice,
40802
40987
  takeWorkerStderrTail: () => {
40803
40988
  const tail = lastWorkerStderrTail;
40804
40989
  lastWorkerStderrTail = null;
@@ -41017,8 +41202,8 @@ async function runListenStart(args) {
41017
41202
  ` : "";
41018
41203
  const workerAudience = routing.routeMode === "main" ? "Directed asks do not reach that worker." : routing.routeMode === "split" ? "Only asks at or below the split threshold reach that worker, with sender and operator provenance in the prompt." : "Every sender reaches that worker with sender and operator provenance in the prompt.";
41019
41204
  const hostNote = provider === "opencode" ? `The OpenCode worker uses one private auth/config home and your selected project cwd. ${workerAudience} Tool requests are approved one at a time by default, when the worker asks and the host offers a one-time approval; --permissions deny refuses them. The deny canary does not cover steady-state allow.
41020
- ` : provider === "claude" ? `The Claude worker uses your selected cwd and normal Claude Code keychain/OAuth state through claude-agent-acp 0.64.2. ${workerAudience}
41021
- ` : provider === "codex" ? `The Codex worker uses your selected cwd and normal ChatGPT/Codex auth through codex-acp 1.1.9. CommonSwarm selects read-only mode before its deny canary. ${workerAudience}
41205
+ ` : provider === "claude" ? `The Claude worker uses your selected cwd and normal Claude Code keychain/OAuth state through claude-agent-acp 0.64.2 or newer. ${workerAudience}
41206
+ ` : provider === "codex" ? `The Codex worker uses your selected cwd and normal ChatGPT/Codex auth through codex-acp 1.1.9 or newer. CommonSwarm selects read-only mode before its deny canary. ${workerAudience}
41022
41207
  ` : `The Grok worker uses your selected cwd and local Grok configuration, including user and cmux hooks. ${workerAudience}
41023
41208
  `;
41024
41209
  process.stdout.write(
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commonswarm",
3
- "version": "0.1.27",
3
+ "version": "0.1.29",
4
4
  "description": "CommonSwarm CLI — coordination for teams where people and AI agents work side by side.",
5
5
  "bin": {
6
6
  "cswarm": "cswarm.cjs"