@agentvault/claude-bridge 0.6.0 → 0.6.2

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.
package/dist/index.js CHANGED
@@ -65555,7 +65555,7 @@ var init_channel = __esm2({
65555
65555
  */
65556
65556
  sendActivitySpan(spanData) {
65557
65557
  if (!this._ws || this._ws.readyState !== WebSocket2.OPEN) return;
65558
- const pluginVersion = true ? "0.23.7" : "0.0.0-dev";
65558
+ const pluginVersion = true ? "0.23.8" : "0.0.0-dev";
65559
65559
  const agentName = this.config.agentName ?? "Agent";
65560
65560
  const resource = {
65561
65561
  "service.name": "agentvault-agent",
@@ -67172,7 +67172,7 @@ var init_channel = __esm2({
67172
67172
  agentVersion: this.config.agentVersion ?? "0.0.0",
67173
67173
  // __AV_VERSION__ is injected by esbuild from package.json at build time.
67174
67174
  // Falls back to "0.0.0-dev" in non-bundled contexts (tests).
67175
- pluginVersion: true ? "0.23.7" : "0.0.0-dev"
67175
+ pluginVersion: true ? "0.23.8" : "0.0.0-dev"
67176
67176
  });
67177
67177
  this._telemetryReporter.startAutoFlush(3e4);
67178
67178
  }
@@ -67251,6 +67251,10 @@ var init_channel = __esm2({
67251
67251
  await this._handleDeviceRevoked();
67252
67252
  return;
67253
67253
  }
67254
+ if (data.event === "connection_rejected") {
67255
+ await this._handleConnectionRejected(data);
67256
+ return;
67257
+ }
67254
67258
  if (data.event === "device_linked") {
67255
67259
  await this._handleDeviceLinked(data.data);
67256
67260
  return;
@@ -67486,7 +67490,7 @@ var init_channel = __esm2({
67486
67490
  agentVersion: this.config.agentVersion ?? "0.0.0",
67487
67491
  // __AV_VERSION__ is injected by esbuild from package.json at build time.
67488
67492
  // Falls back to "0.0.0-dev" in non-bundled contexts (tests).
67489
- pluginVersion: true ? "0.23.7" : "0.0.0-dev"
67493
+ pluginVersion: true ? "0.23.8" : "0.0.0-dev"
67490
67494
  });
67491
67495
  this._telemetryReporter.startAutoFlush(3e4);
67492
67496
  }
@@ -70678,6 +70682,37 @@ ${messageText}`;
70678
70682
  * re-enrollment, which SHOULD wipe creds, goes through setup --force /
70679
70683
  * _forceReEnroll in start().
70680
70684
  */
70685
+ /**
70686
+ * Handle a WS `connection_rejected` event.
70687
+ *
70688
+ * The server accepts the WS upgrade, then — for a device it will not serve —
70689
+ * emits `{event:"connection_rejected", reason, retryable}` and closes with
70690
+ * code 4403. `retryable:false` (e.g. `device_revoked`) is a TERMINAL
70691
+ * credential failure: retrying can only reconnect, get rejected, and close
70692
+ * again. Left unhandled, that generic close drove the reconnect classifier
70693
+ * into "reconnect loop detected", which the bridge treats as a restartable
70694
+ * exit — so launchd/systemd relaunched us every ~30s to hammer the backend
70695
+ * with the same rejected handshake (empirically ~1150 rejects / 2h).
70696
+ *
70697
+ * So we route a non-retryable rejection to the SAME `auth_failed` surface the
70698
+ * proactive/reactive reissue paths use (see channel.ts emit sites). The
70699
+ * bridge wires `auth_failed` to a clean exit(0) (packages/claude-room-bridge
70700
+ * /src/bridge.ts), so launchd stops relaunching. Mirrors those emitters:
70701
+ * emit only + mark the session; the consumer decides how to stop. A
70702
+ * `retryable` rejection is transient — fall through to a normal reconnect.
70703
+ */
70704
+ async _handleConnectionRejected(data) {
70705
+ if (data?.retryable === true) {
70706
+ this._scheduleReconnect();
70707
+ return;
70708
+ }
70709
+ this._authFailedThisSession = true;
70710
+ const authReason = data?.reason === "device_jwt_expired" ? "device_jwt_expired" : "device_revoked";
70711
+ console.warn(
70712
+ `[SecureChannel] connection_rejected (reason=${data?.reason ?? "unknown"}, retryable=false) \u2014 terminal; surfacing auth_failed`
70713
+ );
70714
+ this.emit("auth_failed", { reason: authReason });
70715
+ }
70681
70716
  async _handleDeviceRevoked() {
70682
70717
  const now = Date.now();
70683
70718
  this._revokeRecoveries = this._revokeRecoveries.filter(
@@ -97233,7 +97268,7 @@ var init_index = __esm2({
97233
97268
  init_skill_invoker();
97234
97269
  await init_skill_telemetry();
97235
97270
  await init_policy_enforcer();
97236
- VERSION = true ? "0.23.7" : "0.0.0-dev";
97271
+ VERSION = true ? "0.23.8" : "0.0.0-dev";
97237
97272
  }
97238
97273
  });
97239
97274
  await init_index();
@@ -132510,6 +132545,12 @@ var PersistentClaudeSession = class {
132510
132545
  currentReplyExpected = false;
132511
132546
  saidThisTurn = false;
132512
132547
  turnText = "";
132548
+ /** #630 drop-probe: did a `result` event arrive for the CURRENT turn? Reset per
132549
+ * turn in input(), set in the result block. Distinguishes a turn that never
132550
+ * reached a result boundary (the silent-drop prime suspect) from a healthy
132551
+ * #416 fallback delivery (which delivers via `void reply(...)` WITHOUT setting
132552
+ * saidThisTurn, so !saidThisTurn alone would false-flag it). */
132553
+ sawResultThisTurn = false;
132513
132554
  /** In-process room MCP server — hoisted so buildSdkOptions can reference it. */
132514
132555
  roomServer;
132515
132556
  /** AbortController for the in-flight query(); abort() triggers it (queue timeout). */
@@ -132578,6 +132619,7 @@ var PersistentClaudeSession = class {
132578
132619
  this.currentArmedGetter = item.armed ?? (() => false);
132579
132620
  this.saidThisTurn = false;
132580
132621
  this.turnText = "";
132622
+ this.sawResultThisTurn = false;
132581
132623
  yield item.msg;
132582
132624
  }
132583
132625
  }
@@ -132697,20 +132739,35 @@ var PersistentClaudeSession = class {
132697
132739
  prompt: this.input(),
132698
132740
  options: sdkOptions
132699
132741
  });
132700
- for await (const m6 of q10) {
132701
- if (m6.type === "assistant") {
132702
- const blocks = m6.message?.content ?? [];
132703
- const text = blocks.filter((b5) => b5.type === "text").map((b5) => b5.text ?? "").join("");
132704
- if (text.trim()) {
132705
- this.turnText += text;
132706
- this.opts.onObserve?.(text);
132707
- }
132708
- } else if (m6.type === "result") {
132709
- const reply = this.activeReply;
132710
- if (this.currentReplyExpected && !this.saidThisTurn && this.turnText.trim() && reply) {
132711
- void reply(this.turnText);
132742
+ try {
132743
+ for await (const m6 of q10) {
132744
+ if (m6.type === "assistant") {
132745
+ const blocks = m6.message?.content ?? [];
132746
+ const text = blocks.filter((b5) => b5.type === "text").map((b5) => b5.text ?? "").join("");
132747
+ if (text.trim()) {
132748
+ this.turnText += text;
132749
+ this.opts.onObserve?.(text);
132750
+ }
132751
+ } else if (m6.type === "result") {
132752
+ this.sawResultThisTurn = true;
132753
+ const reply = this.activeReply;
132754
+ if (this.currentReplyExpected && !this.saidThisTurn && this.turnText.trim()) {
132755
+ if (reply) {
132756
+ void reply(this.turnText);
132757
+ } else {
132758
+ console.error(
132759
+ `[drop-probe] BLOCKED at result: composed ${this.turnText.length} chars, reply expected but activeReply unset \u2014 reply DROPPED`
132760
+ );
132761
+ }
132762
+ }
132712
132763
  }
132713
132764
  }
132765
+ } finally {
132766
+ if (this.currentReplyExpected && !this.saidThisTurn && !this.sawResultThisTurn && this.turnText.trim()) {
132767
+ console.error(
132768
+ `[drop-probe] STREAM ENDED before result: composed ${this.turnText.length} chars, reply expected, said=false \u2014 reply DROPPED (no result event)`
132769
+ );
132770
+ }
132714
132771
  }
132715
132772
  }
132716
132773
  };
@@ -133246,7 +133303,7 @@ async function main() {
133246
133303
  "[bridge] warning: passing the invite token on the command line is visible to other local users via 'ps'. Prefer: AV_INVITE_TOKEN=\u2026 npx @agentvault/claude-bridge"
133247
133304
  );
133248
133305
  }
133249
- console.error(`[bridge] version: ${true ? "0.6.0" : "dev"}`);
133306
+ console.error(`[bridge] version: ${true ? "0.6.2" : "dev"}`);
133250
133307
  console.error(`[bridge] data dir: ${cfg.dataDir} (${cfg.dataDirSource})`);
133251
133308
  console.error(`[bridge] workspace: ${cfg.workspaceDir} \xB7 permissions: ${cfg.permissionMode} \xB7 enclave dir fenced`);
133252
133309
  if (cfg.armRoom) {
package/dist/session.d.ts CHANGED
@@ -137,6 +137,12 @@ export declare class PersistentClaudeSession {
137
137
  private currentReplyExpected;
138
138
  private saidThisTurn;
139
139
  private turnText;
140
+ /** #630 drop-probe: did a `result` event arrive for the CURRENT turn? Reset per
141
+ * turn in input(), set in the result block. Distinguishes a turn that never
142
+ * reached a result boundary (the silent-drop prime suspect) from a healthy
143
+ * #416 fallback delivery (which delivers via `void reply(...)` WITHOUT setting
144
+ * saidThisTurn, so !saidThisTurn alone would false-flag it). */
145
+ private sawResultThisTurn;
140
146
  /** In-process room MCP server — hoisted so buildSdkOptions can reference it. */
141
147
  private roomServer;
142
148
  /** AbortController for the in-flight query(); abort() triggers it (queue timeout). */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentvault/claude-bridge",
3
- "version": "0.6.0",
3
+ "version": "0.6.2",
4
4
  "type": "module",
5
5
  "description": "AgentVault Claude Bridge — daemon for bridging a Claude agent into secure E2E-encrypted AgentVault 1:1 direct messages and rooms.",
6
6
  "main": "dist/index.js",