commonswarm 0.1.29 → 0.1.30

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 +203 -157
  2. package/package.json +1 -1
package/cswarm.cjs CHANGED
@@ -22125,6 +22125,8 @@ var WORKSPACE_NAME_MAX_LENGTH = 80;
22125
22125
  var CAPABILITY_MIN_TTL_MS = 6e4;
22126
22126
  var CAPABILITY_MAX_TTL_MS = 7 * 24 * 60 * 60 * 1e3;
22127
22127
  var SIGNAL_REQUEST_TIMEOUT_MS = 3e4;
22128
+ var SIGNAL_WRITE_MAX_ATTEMPTS = 3;
22129
+ var SIGNAL_WRITE_RETRY_BASE_MS = 500;
22128
22130
  var CommandTransportError = class extends Error {
22129
22131
  constructor(message) {
22130
22132
  super(message);
@@ -22380,6 +22382,27 @@ async function raceSignalDeadline(work, deadline, callerAbort) {
22380
22382
  }
22381
22383
  return await Promise.race(arms);
22382
22384
  }
22385
+ function signalRetryDelayMs(retry, baseMs, random) {
22386
+ const exponential = baseMs * 2 ** (retry - 1);
22387
+ const jitter = 0.5 + Math.min(1, Math.max(0, random()));
22388
+ return Math.round(exponential * jitter);
22389
+ }
22390
+ async function waitForSignalRetry(delayMs, deadline, callerAbort) {
22391
+ if (delayMs === 0) return "elapsed";
22392
+ let timer2;
22393
+ const elapsed = new Promise((resolve) => {
22394
+ timer2 = setTimeout(() => resolve("elapsed"), delayMs);
22395
+ });
22396
+ try {
22397
+ const outcome = await raceSignalDeadline(elapsed, deadline, callerAbort);
22398
+ if (outcome.kind === "value") return outcome.value;
22399
+ if (outcome.kind === "callerAbort") return "callerAbort";
22400
+ if (outcome.kind === "deadline") return "deadline";
22401
+ throw outcome.error;
22402
+ } finally {
22403
+ if (timer2 !== void 0) clearTimeout(timer2);
22404
+ }
22405
+ }
22383
22406
  async function declareAgentModel(target2, request, fetcher = fetch) {
22384
22407
  const controller = new AbortController();
22385
22408
  const timer2 = setTimeout(() => controller.abort(), 3e4);
@@ -22416,12 +22439,14 @@ async function declareAgentModel(target2, request, fetcher = fetch) {
22416
22439
  return { httpStatus: response.status };
22417
22440
  }
22418
22441
  var ThinCommandClient = class {
22419
- constructor(target2, fetcher = fetch) {
22442
+ constructor(target2, fetcher = fetch, options = {}) {
22420
22443
  this.target = target2;
22421
22444
  this.fetcher = fetcher;
22445
+ this.options = options;
22422
22446
  }
22423
22447
  target;
22424
22448
  fetcher;
22449
+ options;
22425
22450
  projections = /* @__PURE__ */ new Map();
22426
22451
  projection(taskId) {
22427
22452
  return this.projections.get(taskId) ?? null;
@@ -22681,10 +22706,12 @@ var ThinCommandClient = class {
22681
22706
  const callerAbort = new Promise((resolve) => {
22682
22707
  releaseCallerAbort = resolve;
22683
22708
  });
22709
+ let deadlineReached = false;
22684
22710
  const timer2 = setTimeout(() => {
22711
+ deadlineReached = true;
22685
22712
  releaseDeadline?.();
22686
22713
  controller.abort();
22687
- }, SIGNAL_REQUEST_TIMEOUT_MS);
22714
+ }, this.options.signalRequestTimeoutMs ?? SIGNAL_REQUEST_TIMEOUT_MS);
22688
22715
  const onCallerAbort = () => {
22689
22716
  releaseCallerAbort?.();
22690
22717
  controller.abort();
@@ -22695,90 +22722,117 @@ var ThinCommandClient = class {
22695
22722
  controller.abort();
22696
22723
  }
22697
22724
  try {
22698
- let fetchWork;
22699
- try {
22700
- fetchWork = Promise.resolve(
22701
- this.fetcher(commandEndpoint(this.target), {
22702
- method: "POST",
22703
- headers: {
22704
- authorization: `Bearer ${request.credential}`,
22705
- apikey: this.target.anonKey,
22706
- "content-type": "application/json"
22707
- },
22708
- body: JSON.stringify({
22709
- command_id: commandId,
22710
- client_version: CLIENT_PROTOCOL_VERSION,
22711
- workspace_id: request.workspaceId,
22712
- stream: { kind: "workspace" },
22713
- command: command2
22714
- }),
22715
- signal: controller.signal
22716
- })
22717
- );
22718
- } catch (error) {
22719
- fetchWork = Promise.reject(error);
22720
- }
22721
- const fetchOutcome = await raceSignalDeadline(
22722
- fetchWork,
22723
- deadline,
22724
- callerSignal === void 0 ? void 0 : callerAbort
22725
- );
22726
- if (fetchOutcome.kind === "callerAbort") {
22727
- throw signalAbortError();
22728
- }
22729
- if (fetchOutcome.kind === "deadline") {
22730
- throw new CommandTransportError("signal request timed out");
22731
- }
22732
- if (fetchOutcome.kind === "error") {
22733
- throw new CommandTransportError(
22734
- "signal request failed before a response"
22735
- );
22736
- }
22737
- const response = fetchOutcome.value;
22738
- const bodyOutcome = await raceSignalDeadline(
22739
- parsedJson(response),
22740
- deadline,
22741
- callerSignal === void 0 ? void 0 : callerAbort
22742
- );
22743
- if (bodyOutcome.kind === "callerAbort") {
22744
- throw signalAbortError();
22745
- }
22746
- if (bodyOutcome.kind === "deadline") {
22747
- throw new CommandTransportError("signal request timed out");
22748
- }
22749
- if (bodyOutcome.kind === "error") {
22750
- if (response.status >= 400) {
22751
- throw new CommandHttpError(
22752
- response.status,
22753
- `signal failed (HTTP ${response.status})`
22754
- );
22725
+ for (let attempt = 1; attempt <= SIGNAL_WRITE_MAX_ATTEMPTS; attempt += 1) {
22726
+ if (callerSignal?.aborted) throw signalAbortError();
22727
+ if (deadlineReached) {
22728
+ throw new CommandTransportError("signal request timed out");
22755
22729
  }
22756
- throw bodyOutcome.error;
22757
- }
22758
- const raw = bodyOutcome.value;
22759
- if (!response.ok) {
22760
- const error = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
22761
- throw new CommandHttpError(
22762
- response.status,
22763
- typeof error.message === "string" ? error.message : `signal failed (HTTP ${response.status}): ${typeof error.error === "string" ? error.error : "unknown_error"}`
22764
- );
22765
- }
22766
- const body = responseBody(raw);
22767
- if (body.status !== "accepted" || body.signal === void 0) {
22768
- throw new Error("signal endpoint accepted without a signal receipt");
22769
- }
22770
- if (body.min_client_version !== void 0) {
22771
- const order = compareVersion(CLIENT_PROTOCOL_VERSION, body.min_client_version);
22772
- if (order === null) {
22773
- throw new Error("server returned a malformed min_client_version");
22774
- }
22775
- if (order < 0) {
22776
- throw new Error(
22777
- `client upgrade required (minimum ${body.min_client_version})`
22730
+ try {
22731
+ let fetchWork;
22732
+ try {
22733
+ fetchWork = Promise.resolve(
22734
+ this.fetcher(commandEndpoint(this.target), {
22735
+ method: "POST",
22736
+ headers: {
22737
+ authorization: `Bearer ${request.credential}`,
22738
+ apikey: this.target.anonKey,
22739
+ "content-type": "application/json"
22740
+ },
22741
+ body: JSON.stringify({
22742
+ // One id is minted outside the loop. Every retry is a replay.
22743
+ command_id: commandId,
22744
+ client_version: CLIENT_PROTOCOL_VERSION,
22745
+ workspace_id: request.workspaceId,
22746
+ stream: { kind: "workspace" },
22747
+ command: command2
22748
+ }),
22749
+ signal: controller.signal
22750
+ })
22751
+ );
22752
+ } catch (error) {
22753
+ fetchWork = Promise.reject(error);
22754
+ }
22755
+ const fetchOutcome = await raceSignalDeadline(
22756
+ fetchWork,
22757
+ deadline,
22758
+ callerSignal === void 0 ? void 0 : callerAbort
22759
+ );
22760
+ if (fetchOutcome.kind === "callerAbort") throw signalAbortError();
22761
+ if (fetchOutcome.kind === "deadline") {
22762
+ throw new CommandTransportError("signal request timed out");
22763
+ }
22764
+ if (fetchOutcome.kind === "error") {
22765
+ throw new CommandTransportError(
22766
+ "signal request failed before a response"
22767
+ );
22768
+ }
22769
+ const response = fetchOutcome.value;
22770
+ const bodyOutcome = await raceSignalDeadline(
22771
+ parsedJson(response),
22772
+ deadline,
22773
+ callerSignal === void 0 ? void 0 : callerAbort
22778
22774
  );
22775
+ if (bodyOutcome.kind === "callerAbort") throw signalAbortError();
22776
+ if (bodyOutcome.kind === "deadline") {
22777
+ throw new CommandTransportError("signal request timed out");
22778
+ }
22779
+ if (bodyOutcome.kind === "error") {
22780
+ if (response.status >= 400) {
22781
+ throw new CommandHttpError(
22782
+ response.status,
22783
+ `signal failed (HTTP ${response.status})`
22784
+ );
22785
+ }
22786
+ throw bodyOutcome.error;
22787
+ }
22788
+ const raw = bodyOutcome.value;
22789
+ if (!response.ok) {
22790
+ const error = raw && typeof raw === "object" && !Array.isArray(raw) ? raw : {};
22791
+ throw new CommandHttpError(
22792
+ response.status,
22793
+ typeof error.message === "string" ? error.message : `signal failed (HTTP ${response.status}): ${typeof error.error === "string" ? error.error : "unknown_error"}`
22794
+ );
22795
+ }
22796
+ const body = responseBody(raw);
22797
+ if (body.status !== "accepted" || body.signal === void 0) {
22798
+ throw new Error("signal endpoint accepted without a signal receipt");
22799
+ }
22800
+ if (body.min_client_version !== void 0) {
22801
+ const order = compareVersion(CLIENT_PROTOCOL_VERSION, body.min_client_version);
22802
+ if (order === null) {
22803
+ throw new Error("server returned a malformed min_client_version");
22804
+ }
22805
+ if (order < 0) {
22806
+ throw new Error(
22807
+ `client upgrade required (minimum ${body.min_client_version})`
22808
+ );
22809
+ }
22810
+ }
22811
+ return {
22812
+ httpStatus: response.status,
22813
+ response: body,
22814
+ attempts: attempt,
22815
+ retried: attempt > 1
22816
+ };
22817
+ } catch (error) {
22818
+ const transient = error instanceof CommandTransportError || error instanceof CommandHttpError && error.status >= 500;
22819
+ if (!transient || attempt === SIGNAL_WRITE_MAX_ATTEMPTS) throw error;
22820
+ const waitOutcome = await waitForSignalRetry(
22821
+ signalRetryDelayMs(
22822
+ attempt,
22823
+ this.options.signalRetryBaseMs ?? SIGNAL_WRITE_RETRY_BASE_MS,
22824
+ this.options.signalRetryRandom ?? Math.random
22825
+ ),
22826
+ deadline,
22827
+ callerSignal === void 0 ? void 0 : callerAbort
22828
+ );
22829
+ if (waitOutcome === "callerAbort") throw signalAbortError();
22830
+ if (waitOutcome === "deadline") {
22831
+ throw new CommandTransportError("signal request timed out");
22832
+ }
22779
22833
  }
22780
22834
  }
22781
- return { httpStatus: response.status, response: body };
22835
+ throw new Error("signal retry loop ended without an outcome");
22782
22836
  } finally {
22783
22837
  clearTimeout(timer2);
22784
22838
  callerSignal?.removeEventListener("abort", onCallerAbort);
@@ -29524,6 +29578,8 @@ var import_node_crypto12 = require("node:crypto");
29524
29578
  // src/host/stderr-tail.ts
29525
29579
  var RING_CAPACITY_BYTES = 4096;
29526
29580
  var TAIL_MAX_CHARS = 2048;
29581
+ var STDERR_EXIT_GRACE_MS = 100;
29582
+ var STDERR_READABLE_END_GRACE_MS = STDERR_EXIT_GRACE_MS + 50;
29527
29583
  var EXOTIC_SEPARATORS = "\\u00a0\\u1680\\u2000-\\u200d\\u2028\\u2029\\u202a-\\u202e\\u2060\\u2066-\\u2069\\u202f\\u205f\\u3000\\ufeff";
29528
29584
  var SEPARATOR_CLASS_SOURCE = "\\t\\n\\x0b\\f\\r " + EXOTIC_SEPARATORS;
29529
29585
  var ANSI_ESCAPE_GLOBAL_RE2 = new RegExp("\\u001b\\[[0-?]*[ -\\/]*[@-~]", "g");
@@ -29571,6 +29627,34 @@ function attachStderrTailRing(stderr) {
29571
29627
  }
29572
29628
  };
29573
29629
  }
29630
+ function attachStderrTailExitObserver(child, onStderrTail) {
29631
+ const stderrTail = attachStderrTailRing(child.stderr);
29632
+ return (handler) => {
29633
+ const observeExit = (code, signal) => {
29634
+ let completed = false;
29635
+ let timer2 = null;
29636
+ const complete = () => {
29637
+ if (completed) return;
29638
+ completed = true;
29639
+ if (timer2) clearTimeout(timer2);
29640
+ child.removeListener("close", complete);
29641
+ try {
29642
+ onStderrTail?.(stderrTail.read());
29643
+ } finally {
29644
+ handler(code, signal);
29645
+ }
29646
+ };
29647
+ child.once("close", complete);
29648
+ timer2 = setTimeout(complete, STDERR_EXIT_GRACE_MS);
29649
+ timer2.unref();
29650
+ };
29651
+ if (child.exitCode !== null || child.signalCode !== null) {
29652
+ observeExit(child.exitCode, child.signalCode);
29653
+ } else {
29654
+ child.once("exit", observeExit);
29655
+ }
29656
+ };
29657
+ }
29574
29658
 
29575
29659
  // src/host/opencode.ts
29576
29660
  var import_node_fs3 = require("node:fs");
@@ -31367,27 +31451,18 @@ async function openOpenCodeAcpSession(options) {
31367
31451
  await disposeHome();
31368
31452
  throw new AcpHostError("spawn_failed", "child missing stdio pipes");
31369
31453
  }
31370
- const stderrTail = attachStderrTailRing(child.stderr);
31371
- if (options.onStderrTail) {
31372
- const deliverTail = options.onStderrTail;
31373
- let tailDelivered = false;
31374
- const publishTail = () => {
31375
- if (tailDelivered) return;
31376
- tailDelivered = true;
31377
- deliverTail(stderrTail.read());
31378
- };
31379
- child.once("exit", publishTail);
31380
- child.once("close", publishTail);
31381
- }
31454
+ const observeStderrTailOnExit = attachStderrTailExitObserver(
31455
+ child,
31456
+ options.onStderrTail
31457
+ );
31382
31458
  let sessionRef = null;
31383
31459
  const transport = createBoundTransport({
31384
31460
  readable: child.stdout,
31385
31461
  writable: child.stdin,
31386
31462
  requestTimeoutMs: options.requestTimeoutMs ?? ACP_DEFAULT_REQUEST_TIMEOUT_MS,
31463
+ readableEndGraceMs: STDERR_READABLE_END_GRACE_MS,
31387
31464
  getSession: () => sessionRef,
31388
- onChildExit: (handler) => {
31389
- child.on("exit", (code, signal) => handler(code, signal));
31390
- }
31465
+ onChildExit: observeStderrTailOnExit
31391
31466
  });
31392
31467
  try {
31393
31468
  const session = await AcpHostSession.connect({
@@ -31443,8 +31518,6 @@ var import_node_fs4 = require("node:fs");
31443
31518
  var import_node_path6 = require("node:path");
31444
31519
  var CHILD_EXIT_WAIT_MS2 = 3e3;
31445
31520
  var CHILD_KILL_WAIT_MS2 = 1e3;
31446
- var STDERR_EXIT_GRACE_MS = 100;
31447
- var READABLE_END_GRACE_MS = STDERR_EXIT_GRACE_MS + 50;
31448
31521
  var WINDOWS_NPM_SHIM_MAX_BYTES = 64 * 1024;
31449
31522
  var WINDOWS_NPM_ENTRYPOINT = [
31450
31523
  "node_modules",
@@ -31741,35 +31814,18 @@ async function openClaudeAcpSession(options) {
31741
31814
  await terminateClaudeChild(child);
31742
31815
  throw new AcpHostError("spawn_failed", "child missing stdio pipes");
31743
31816
  }
31744
- const stderrTail = attachStderrTailRing(child.stderr);
31817
+ const observeStderrTailOnExit = attachStderrTailExitObserver(
31818
+ child,
31819
+ options.onStderrTail
31820
+ );
31745
31821
  let sessionRef = null;
31746
31822
  const transport = createBoundTransport({
31747
31823
  readable: child.stdout,
31748
31824
  writable: child.stdin,
31749
31825
  requestTimeoutMs: options.requestTimeoutMs ?? ACP_DEFAULT_REQUEST_TIMEOUT_MS,
31750
- readableEndGraceMs: READABLE_END_GRACE_MS,
31826
+ readableEndGraceMs: STDERR_READABLE_END_GRACE_MS,
31751
31827
  getSession: () => sessionRef,
31752
- onChildExit: (handler) => {
31753
- const observeExit = (code, signal) => {
31754
- let completed = false;
31755
- let timer2 = null;
31756
- const complete = () => {
31757
- if (completed) return;
31758
- completed = true;
31759
- if (timer2) clearTimeout(timer2);
31760
- child.removeListener("close", complete);
31761
- options.onStderrTail?.(stderrTail.read());
31762
- handler(code, signal);
31763
- };
31764
- child.once("close", complete);
31765
- timer2 = setTimeout(complete, STDERR_EXIT_GRACE_MS);
31766
- };
31767
- if (child.exitCode !== null || child.signalCode !== null) {
31768
- observeExit(child.exitCode, child.signalCode);
31769
- } else {
31770
- child.once("exit", observeExit);
31771
- }
31772
- }
31828
+ onChildExit: observeStderrTailOnExit
31773
31829
  });
31774
31830
  try {
31775
31831
  const session = await Promise.race([
@@ -32038,27 +32094,18 @@ async function openCodexAcpSession(options) {
32038
32094
  await terminateCodexChild(child);
32039
32095
  throw new AcpHostError("spawn_failed", "child missing stdio pipes");
32040
32096
  }
32041
- const stderrTail = attachStderrTailRing(child.stderr);
32042
- if (options.onStderrTail) {
32043
- const deliverTail = options.onStderrTail;
32044
- let tailDelivered = false;
32045
- const publishTail = () => {
32046
- if (tailDelivered) return;
32047
- tailDelivered = true;
32048
- deliverTail(stderrTail.read());
32049
- };
32050
- child.once("exit", publishTail);
32051
- child.once("close", publishTail);
32052
- }
32097
+ const observeStderrTailOnExit = attachStderrTailExitObserver(
32098
+ child,
32099
+ options.onStderrTail
32100
+ );
32053
32101
  let sessionRef = null;
32054
32102
  const transport = createBoundTransport({
32055
32103
  readable: child.stdout,
32056
32104
  writable: child.stdin,
32057
32105
  requestTimeoutMs: options.requestTimeoutMs ?? ACP_DEFAULT_REQUEST_TIMEOUT_MS,
32106
+ readableEndGraceMs: STDERR_READABLE_END_GRACE_MS,
32058
32107
  getSession: () => sessionRef,
32059
- onChildExit: (handler) => {
32060
- child.on("exit", (code, signal) => handler(code, signal));
32061
- }
32108
+ onChildExit: observeStderrTailOnExit
32062
32109
  });
32063
32110
  try {
32064
32111
  const session = await Promise.race([
@@ -33012,27 +33059,18 @@ async function openGrokAcpSession(options) {
33012
33059
  child.kill("SIGKILL");
33013
33060
  throw new AcpHostError("spawn_failed", "child missing stdio pipes");
33014
33061
  }
33015
- const stderrTail = attachStderrTailRing(child.stderr);
33016
- if (options.onStderrTail) {
33017
- const deliverTail = options.onStderrTail;
33018
- let tailDelivered = false;
33019
- const publishTail = () => {
33020
- if (tailDelivered) return;
33021
- tailDelivered = true;
33022
- deliverTail(stderrTail.read());
33023
- };
33024
- child.once("exit", publishTail);
33025
- child.once("close", publishTail);
33026
- }
33062
+ const observeStderrTailOnExit = attachStderrTailExitObserver(
33063
+ child,
33064
+ options.onStderrTail
33065
+ );
33027
33066
  let sessionRef = null;
33028
33067
  const transport = createBoundTransport({
33029
33068
  readable: child.stdout,
33030
33069
  writable: child.stdin,
33031
33070
  requestTimeoutMs: options.requestTimeoutMs ?? ACP_DEFAULT_REQUEST_TIMEOUT_MS,
33071
+ readableEndGraceMs: STDERR_READABLE_END_GRACE_MS,
33032
33072
  getSession: () => sessionRef,
33033
- onChildExit: (handler) => {
33034
- child.on("exit", (code, signal) => handler(code, signal));
33035
- }
33073
+ onChildExit: observeStderrTailOnExit
33036
33074
  });
33037
33075
  try {
33038
33076
  const session = await AcpHostSession.connect({
@@ -38151,8 +38189,8 @@ var ACCEPTED_AGENT_CREDENTIAL_MESSAGES = [
38151
38189
  AGENT_CREDENTIAL_MESSAGE_D088
38152
38190
  ];
38153
38191
  function packageVersion() {
38154
- if ("0.1.29".length > 0) {
38155
- return "0.1.29";
38192
+ if ("0.1.30".length > 0) {
38193
+ return "0.1.30";
38156
38194
  }
38157
38195
  try {
38158
38196
  const value = JSON.parse(
@@ -40039,7 +40077,11 @@ async function runPostSignal(args, kind) {
40039
40077
  }
40040
40078
  const reply = waitResult.signals[0] ?? null;
40041
40079
  if (args.has("json")) {
40042
- printJson(askWaitJsonPayload(signal, reply, waitResult.timedOut));
40080
+ printJson({
40081
+ ...askWaitJsonPayload(signal, reply, waitResult.timedOut),
40082
+ retried: result.retried,
40083
+ attempts: result.attempts
40084
+ });
40043
40085
  return;
40044
40086
  }
40045
40087
  const authors2 = await settleSignalAuthorLabels(
@@ -40076,7 +40118,9 @@ ${renderSignals([signal, reply], {
40076
40118
  printJson({
40077
40119
  status: result.response.status,
40078
40120
  message: "Signal shared. It is immutable, tenancy-scoped, and will quietly expire at its horizon.",
40079
- signal
40121
+ signal,
40122
+ retried: result.retried,
40123
+ attempts: result.attempts
40080
40124
  });
40081
40125
  return;
40082
40126
  }
@@ -40166,7 +40210,9 @@ async function runReply(args) {
40166
40210
  printJson({
40167
40211
  status: result.response.status,
40168
40212
  message: "Reply shared. It is immutable, tenancy-scoped, and will quietly expire at its horizon.",
40169
- signal
40213
+ signal,
40214
+ retried: result.retried,
40215
+ attempts: result.attempts
40170
40216
  });
40171
40217
  return;
40172
40218
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "commonswarm",
3
- "version": "0.1.29",
3
+ "version": "0.1.30",
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"