@snowyroad/braid 0.96.4 → 0.96.5

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.
@@ -205,9 +205,9 @@ function newBeyondFile(list) {
205
205
  flag: list.flag.filter((x) => !file.has(x))
206
206
  };
207
207
  }
208
- function seg(n, singular, plural) {
208
+ function seg(n, singular, plural2) {
209
209
  if (n === 0) return null;
210
- return `+${n} ${n === 1 ? singular : plural}`;
210
+ return `+${n} ${n === 1 ? singular : plural2}`;
211
211
  }
212
212
  function computePostureWarnings(flags, env, stored) {
213
213
  if (stored === void 0) return [];
@@ -400,7 +400,7 @@ var InviteExpiredError = class extends Error {
400
400
  }
401
401
  };
402
402
  async function redeemInvite(relayHttpUrl, code) {
403
- const { boundedJsonFetch: boundedJsonFetch2 } = await import("./http-N3HN44KC.js");
403
+ const { boundedJsonFetch: boundedJsonFetch2 } = await import("./http-DZ3ZHOHX.js");
404
404
  const r = await boundedJsonFetch2(`${relayHttpUrl.replace(/\/$/, "")}/invites/redeem`, {
405
405
  method: "POST",
406
406
  headers: { "content-type": "application/json" },
@@ -492,7 +492,7 @@ function validateReplacementToken(newToken, currentToken, nowMs = Date.now()) {
492
492
  return { ok: true };
493
493
  }
494
494
  async function mintAccessToken(relayHttpUrl, agentKey, fetchFn = fetch, dpopProof) {
495
- const { boundedJsonFetch: boundedJsonFetch2 } = await import("./http-N3HN44KC.js");
495
+ const { boundedJsonFetch: boundedJsonFetch2 } = await import("./http-DZ3ZHOHX.js");
496
496
  const r = await boundedJsonFetch2(`${relayHttpUrl.replace(/\/$/, "")}/agents/token`, {
497
497
  method: "POST",
498
498
  headers: {
@@ -1770,6 +1770,44 @@ function dropVendorNotifications(input) {
1770
1770
  });
1771
1771
  }
1772
1772
 
1773
+ // src/acp/stderrNoise.ts
1774
+ var TEARDOWN_HEAD = /cancellation failed during teardown/;
1775
+ var CONTINUATION = /^(\s+at\s|\s*[{}]\s*$|\s+(telemetryMessage|errorClass|exitCode)\s*:)/;
1776
+ function createTeardownNoiseFilter(isStopping) {
1777
+ let pending = "";
1778
+ let dropping = false;
1779
+ function line(l) {
1780
+ if (dropping) {
1781
+ if (CONTINUATION.test(l)) return "";
1782
+ dropping = false;
1783
+ }
1784
+ if (isStopping() && TEARDOWN_HEAD.test(l)) {
1785
+ dropping = true;
1786
+ return "";
1787
+ }
1788
+ return l + "\n";
1789
+ }
1790
+ return {
1791
+ push(chunk) {
1792
+ pending += chunk;
1793
+ let out = "";
1794
+ let nl;
1795
+ while ((nl = pending.indexOf("\n")) !== -1) {
1796
+ out += line(pending.slice(0, nl));
1797
+ pending = pending.slice(nl + 1);
1798
+ }
1799
+ return out;
1800
+ },
1801
+ flush() {
1802
+ const rest = pending;
1803
+ pending = "";
1804
+ if (!rest) return "";
1805
+ if (dropping && CONTINUATION.test(rest)) return "";
1806
+ return rest;
1807
+ }
1808
+ };
1809
+ }
1810
+
1773
1811
  // src/acp/client.ts
1774
1812
  import { randomUUID } from "crypto";
1775
1813
 
@@ -2106,7 +2144,17 @@ var AcpClient = class {
2106
2144
  detached: true
2107
2145
  });
2108
2146
  this.child = child;
2109
- pipeSanitizedToTty(child.stderr);
2147
+ const noise = createTeardownNoiseFilter(() => this.stopping);
2148
+ pipeSanitizedToTty(child.stderr, {
2149
+ write: (s) => {
2150
+ const kept = noise.push(s);
2151
+ if (kept) process.stderr.write(kept);
2152
+ }
2153
+ });
2154
+ child.on("close", () => {
2155
+ const rest = noise.flush();
2156
+ if (rest) process.stderr.write(rest);
2157
+ });
2110
2158
  child.on("error", (err) => {
2111
2159
  this.failPending(new Error(`ACP agent subprocess error: ${err.message}`));
2112
2160
  });
@@ -3437,6 +3485,137 @@ function classifyCatchUp(messages, agentName, nowMs, opts) {
3437
3485
  return { context: inWindow, mentions: capped };
3438
3486
  }
3439
3487
 
3488
+ // src/connStatus.ts
3489
+ var ESCALATE_FIRST_MS = 6e4;
3490
+ var ESCALATE_REPEAT_MS = 3e5;
3491
+ var CLOSE_TRY_AGAIN_LATER = 1013;
3492
+ function fmtDur(ms) {
3493
+ const s = Math.max(0, Math.floor(ms / 1e3));
3494
+ if (s < 60) return `${s}s`;
3495
+ const m = Math.floor(s / 60);
3496
+ if (m < 60) return `${m}m${String(s % 60).padStart(2, "0")}s`;
3497
+ return `${Math.floor(m / 60)}h${String(m % 60).padStart(2, "0")}m`;
3498
+ }
3499
+ function fmtClock(epochMs) {
3500
+ const d = new Date(epochMs);
3501
+ return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
3502
+ }
3503
+ function plural(n, one, many) {
3504
+ return `${n} ${n === 1 ? one : many}`;
3505
+ }
3506
+ function createConnStatus(opts) {
3507
+ const now = opts.now ?? Date.now;
3508
+ const startedAt = now();
3509
+ let state = "starting";
3510
+ let connectedSince = null;
3511
+ let offlineSince = null;
3512
+ let attempts = 0;
3513
+ let reconnects = 0;
3514
+ let lastReconnectAt = null;
3515
+ let tokenExp = null;
3516
+ let lastCloseCode = null;
3517
+ let nextEscalateAt = null;
3518
+ let tryAgainLaterSaid = false;
3519
+ function noteDrop() {
3520
+ if (state !== "offline") {
3521
+ offlineSince = now();
3522
+ attempts = 0;
3523
+ nextEscalateAt = offlineSince + ESCALATE_FIRST_MS;
3524
+ }
3525
+ state = "offline";
3526
+ connectedSince = null;
3527
+ attempts++;
3528
+ }
3529
+ function closeEpisode(t) {
3530
+ if (offlineSince === null || attempts === 0) return null;
3531
+ const down = fmtDur(t - offlineSince);
3532
+ const suffix = attempts > 1 ? `${down}, ${plural(attempts, "attempt", "attempts")}` : down;
3533
+ offlineSince = null;
3534
+ nextEscalateAt = null;
3535
+ tryAgainLaterSaid = false;
3536
+ return suffix;
3537
+ }
3538
+ function adoptExp(exp) {
3539
+ if (exp !== void 0) tokenExp = exp;
3540
+ }
3541
+ function handle(e) {
3542
+ switch (e.kind) {
3543
+ case "connected": {
3544
+ const t = now();
3545
+ const hadRetries = offlineSince !== null && attempts > 0;
3546
+ const n = attempts;
3547
+ const since = offlineSince;
3548
+ const ep = closeEpisode(t);
3549
+ state = "connected";
3550
+ connectedSince = t;
3551
+ adoptExp(e.tokenExp);
3552
+ if (hadRetries && ep !== null && since !== null) {
3553
+ opts.log(`[braid] connected (after ${plural(n, "attempt", "attempts")}, ${fmtDur(t - since)})`);
3554
+ }
3555
+ break;
3556
+ }
3557
+ case "reconnected": {
3558
+ const t = now();
3559
+ const ep = closeEpisode(t);
3560
+ state = "connected";
3561
+ connectedSince = t;
3562
+ reconnects++;
3563
+ lastReconnectAt = t;
3564
+ adoptExp(e.tokenExp);
3565
+ opts.log(`[braid] reconnected${ep !== null ? ` (offline ${ep})` : ""}`);
3566
+ break;
3567
+ }
3568
+ case "disconnected":
3569
+ lastCloseCode = e.code;
3570
+ noteDrop();
3571
+ if (e.code === CLOSE_TRY_AGAIN_LATER) {
3572
+ if (!tryAgainLaterSaid) {
3573
+ tryAgainLaterSaid = true;
3574
+ opts.warn(
3575
+ `[braid] relay asked us to try again later${e.reason ? ` (${e.reason})` : ""}; reconnecting automatically`
3576
+ );
3577
+ }
3578
+ } else if (opts.verbose) {
3579
+ opts.log(`[braid] disconnected (close ${e.code})${e.reason ? `: ${e.reason}` : ""}`);
3580
+ }
3581
+ break;
3582
+ case "connectTimeout":
3583
+ noteDrop();
3584
+ if (opts.verbose) {
3585
+ opts.log(
3586
+ `[braid] connect attempt timed out after ${e.timeoutSecs}s (socket accepted but the relay never completed the handshake); retrying`
3587
+ );
3588
+ }
3589
+ break;
3590
+ case "remintStarted":
3591
+ if (opts.verbose) opts.log("[braid] access token rejected; re-minting from agent key");
3592
+ break;
3593
+ case "tokenRefreshed":
3594
+ adoptExp(e.tokenExp);
3595
+ if (opts.verbose) opts.log("[braid] token refreshed");
3596
+ break;
3597
+ case "tokenReminted":
3598
+ adoptExp(e.tokenExp);
3599
+ if (opts.verbose) opts.log("[braid] token proactively re-minted before expiry");
3600
+ break;
3601
+ }
3602
+ }
3603
+ function tick() {
3604
+ if (state !== "offline" || offlineSince === null || nextEscalateAt === null) return;
3605
+ const t = now();
3606
+ if (t >= nextEscalateAt) {
3607
+ opts.warn(
3608
+ `[braid] still reconnecting: offline ${fmtDur(t - offlineSince)} (${plural(attempts, "attempt", "attempts")})`
3609
+ );
3610
+ nextEscalateAt = t + ESCALATE_REPEAT_MS;
3611
+ }
3612
+ }
3613
+ function snapshot() {
3614
+ return { state, startedAt, connectedSince, offlineSince, attempts, reconnects, lastReconnectAt, tokenExp, lastCloseCode };
3615
+ }
3616
+ return { handle, tick, snapshot };
3617
+ }
3618
+
3440
3619
  // src/cardIdentity.ts
3441
3620
  import { createRemoteJWKSet, jwtVerify } from "jose";
3442
3621
 
@@ -4160,7 +4339,7 @@ var RelayClient = class {
4160
4339
  this.fatalCb?.(code, reason);
4161
4340
  return;
4162
4341
  }
4163
- if (!this.helloReceived) {
4342
+ if (!this.helloReceived && code !== CLOSE_TRY_AGAIN_LATER) {
4164
4343
  this.preHelloFailures++;
4165
4344
  if (this.preHelloFailures >= PRE_HELLO_HINT_AFTER && !this.handshakeHintShown) {
4166
4345
  this.handshakeHintShown = true;
@@ -7715,6 +7894,9 @@ export {
7715
7894
  isAddressed,
7716
7895
  isAddressedByReply,
7717
7896
  classifyCatchUp,
7897
+ fmtDur,
7898
+ fmtClock,
7899
+ createConnStatus,
7718
7900
  WS_MAX_PAYLOAD_BYTES,
7719
7901
  RelayClient,
7720
7902
  SourceBroker,
package/dist/cli.js CHANGED
@@ -29,12 +29,15 @@ import {
29
29
  classifyFatal,
30
30
  configDir,
31
31
  createAdapter,
32
+ createConnStatus,
32
33
  createEphemeralLisaAdapter,
33
34
  createWorkspaceNoticeGate,
34
35
  decodeInvite,
35
36
  describeClaudeBinary,
36
37
  distinctWorkspaceNames,
37
38
  effectiveAnthropicCredential,
39
+ fmtClock,
40
+ fmtDur,
38
41
  handoffCwdFor,
39
42
  hasSubscriptionLogin,
40
43
  initScopeRuntime,
@@ -78,7 +81,7 @@ import {
78
81
  updateAgentWorkspace,
79
82
  validateRelayWsUrl,
80
83
  wsToHttp
81
- } from "./chunk-4BKQMFLW.js";
84
+ } from "./chunk-DIUVFB7Z.js";
82
85
  import {
83
86
  clampUntrusted,
84
87
  externalSourceLabel,
@@ -5714,127 +5717,6 @@ function installTee(outWriter, errWriter) {
5714
5717
  // src/cli.ts
5715
5718
  import { homedir as homedir6 } from "os";
5716
5719
 
5717
- // src/connStatus.ts
5718
- var ESCALATE_FIRST_MS = 6e4;
5719
- var ESCALATE_REPEAT_MS = 3e5;
5720
- function fmtDur(ms) {
5721
- const s = Math.max(0, Math.floor(ms / 1e3));
5722
- if (s < 60) return `${s}s`;
5723
- const m = Math.floor(s / 60);
5724
- if (m < 60) return `${m}m${String(s % 60).padStart(2, "0")}s`;
5725
- return `${Math.floor(m / 60)}h${String(m % 60).padStart(2, "0")}m`;
5726
- }
5727
- function fmtClock(epochMs) {
5728
- const d = new Date(epochMs);
5729
- return `${String(d.getHours()).padStart(2, "0")}:${String(d.getMinutes()).padStart(2, "0")}`;
5730
- }
5731
- function plural(n, one, many) {
5732
- return `${n} ${n === 1 ? one : many}`;
5733
- }
5734
- function createConnStatus(opts) {
5735
- const now = opts.now ?? Date.now;
5736
- const startedAt = now();
5737
- let state = "starting";
5738
- let connectedSince = null;
5739
- let offlineSince = null;
5740
- let attempts = 0;
5741
- let reconnects = 0;
5742
- let lastReconnectAt = null;
5743
- let tokenExp = null;
5744
- let lastCloseCode = null;
5745
- let nextEscalateAt = null;
5746
- function noteDrop() {
5747
- if (state !== "offline") {
5748
- offlineSince = now();
5749
- attempts = 0;
5750
- nextEscalateAt = offlineSince + ESCALATE_FIRST_MS;
5751
- }
5752
- state = "offline";
5753
- connectedSince = null;
5754
- attempts++;
5755
- }
5756
- function closeEpisode(t) {
5757
- if (offlineSince === null || attempts === 0) return null;
5758
- const down = fmtDur(t - offlineSince);
5759
- const suffix = attempts > 1 ? `${down}, ${plural(attempts, "attempt", "attempts")}` : down;
5760
- offlineSince = null;
5761
- nextEscalateAt = null;
5762
- return suffix;
5763
- }
5764
- function adoptExp(exp) {
5765
- if (exp !== void 0) tokenExp = exp;
5766
- }
5767
- function handle(e) {
5768
- switch (e.kind) {
5769
- case "connected": {
5770
- const t = now();
5771
- const hadRetries = offlineSince !== null && attempts > 0;
5772
- const n = attempts;
5773
- const since = offlineSince;
5774
- const ep = closeEpisode(t);
5775
- state = "connected";
5776
- connectedSince = t;
5777
- adoptExp(e.tokenExp);
5778
- if (hadRetries && ep !== null && since !== null) {
5779
- opts.log(`[braid] connected (after ${plural(n, "attempt", "attempts")}, ${fmtDur(t - since)})`);
5780
- }
5781
- break;
5782
- }
5783
- case "reconnected": {
5784
- const t = now();
5785
- const ep = closeEpisode(t);
5786
- state = "connected";
5787
- connectedSince = t;
5788
- reconnects++;
5789
- lastReconnectAt = t;
5790
- adoptExp(e.tokenExp);
5791
- opts.log(`[braid] reconnected${ep !== null ? ` (offline ${ep})` : ""}`);
5792
- break;
5793
- }
5794
- case "disconnected":
5795
- lastCloseCode = e.code;
5796
- noteDrop();
5797
- if (opts.verbose) {
5798
- opts.log(`[braid] disconnected (close ${e.code})${e.reason ? `: ${e.reason}` : ""}`);
5799
- }
5800
- break;
5801
- case "connectTimeout":
5802
- noteDrop();
5803
- if (opts.verbose) {
5804
- opts.log(
5805
- `[braid] connect attempt timed out after ${e.timeoutSecs}s (socket accepted but the relay never completed the handshake); retrying`
5806
- );
5807
- }
5808
- break;
5809
- case "remintStarted":
5810
- if (opts.verbose) opts.log("[braid] access token rejected; re-minting from agent key");
5811
- break;
5812
- case "tokenRefreshed":
5813
- adoptExp(e.tokenExp);
5814
- if (opts.verbose) opts.log("[braid] token refreshed");
5815
- break;
5816
- case "tokenReminted":
5817
- adoptExp(e.tokenExp);
5818
- if (opts.verbose) opts.log("[braid] token proactively re-minted before expiry");
5819
- break;
5820
- }
5821
- }
5822
- function tick() {
5823
- if (state !== "offline" || offlineSince === null || nextEscalateAt === null) return;
5824
- const t = now();
5825
- if (t >= nextEscalateAt) {
5826
- opts.warn(
5827
- `[braid] still reconnecting: offline ${fmtDur(t - offlineSince)} (${plural(attempts, "attempt", "attempts")})`
5828
- );
5829
- nextEscalateAt = t + ESCALATE_REPEAT_MS;
5830
- }
5831
- }
5832
- function snapshot() {
5833
- return { state, startedAt, connectedSince, offlineSince, attempts, reconnects, lastReconnectAt, tokenExp, lastCloseCode };
5834
- }
5835
- return { handle, tick, snapshot };
5836
- }
5837
-
5838
5720
  // src/statusLine.ts
5839
5721
  var ESC = String.fromCharCode(27);
5840
5722
  var CLEAR = `\r${ESC}[2K`;
@@ -4,7 +4,7 @@ import {
4
4
  boundedJsonFetch,
5
5
  resetHttpMetricsForTest,
6
6
  snapshotHttpMetrics
7
- } from "./chunk-4BKQMFLW.js";
7
+ } from "./chunk-DIUVFB7Z.js";
8
8
  import "./chunk-HQNAAXUM.js";
9
9
  export {
10
10
  assertHttpEndpoint,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snowyroad/braid",
3
- "version": "0.96.4",
3
+ "version": "0.96.5",
4
4
  "description": "Braid: connect your own coding agent (Claude Code, Codex, Gemini, Grok) to a Braid channel and collaborate with other agents and humans.",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "author": "SnowyRoad",
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@snowyroad/braid",
3
- "version": "0.96.4",
3
+ "version": "0.96.5",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@snowyroad/braid",
9
- "version": "0.96.4",
9
+ "version": "0.96.5",
10
10
  "license": "SEE LICENSE IN LICENSE.md",
11
11
  "dependencies": {
12
12
  "@agentclientprotocol/sdk": "0.25.1",