@agentvault/muse-bridge 0.1.35 → 0.1.36

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/dist/index.js +96 -7
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11812,11 +11812,11 @@ async function joinWithFirstMatchingKp(welcomeBytes, candidates) {
11812
11812
  return null;
11813
11813
  }
11814
11814
  function ownIdentity() {
11815
- const v2 = true ? "0.23.62" : FALLBACK;
11815
+ const v2 = true ? "0.23.63" : FALLBACK;
11816
11816
  return `${PACKAGE}@${v2}`;
11817
11817
  }
11818
11818
  function buildSha() {
11819
- const raw = true ? "4db8d51" : "";
11819
+ const raw = true ? "52249f2" : "";
11820
11820
  const cleaned = (raw ?? "").trim();
11821
11821
  return !cleaned || cleaned === "unknown" ? null : cleaned;
11822
11822
  }
@@ -71703,6 +71703,16 @@ var init_dist = __esm({
71703
71703
  */
71704
71704
  static _KP_REPLENISH_INTERVAL_MS = 6 * 60 * 60 * 1e3;
71705
71705
  _kpReplenishTimer = null;
71706
+ /**
71707
+ * #1094: how often each live group's key proof is re-reported — the web
71708
+ * reporter's cadence (`use-key-proof-reporter.ts`), against the server's 24h
71709
+ * staleness window. Re-reading the CURRENT epoch on a timer is self-correcting
71710
+ * whatever moved it, which is why no commit site is hooked.
71711
+ */
71712
+ static _KEY_PROOF_INTERVAL_MS = 10 * 60 * 1e3;
71713
+ /** #1094: never let one slow report hold up the rest. */
71714
+ static _KEY_PROOF_FETCH_TIMEOUT_MS = 1e4;
71715
+ _keyProofTimer = null;
71706
71716
  _a2aReconcileTimer = null;
71707
71717
  _deliveryPulling = false;
71708
71718
  _drDeliveryPulling = false;
@@ -73944,7 +73954,7 @@ ${text}`,
73944
73954
  */
73945
73955
  sendActivitySpan(spanData) {
73946
73956
  if (!this._ws || this._ws.readyState !== WebSocket.OPEN) return;
73947
- const pluginVersion = true ? "0.23.62" : "0.0.0-dev";
73957
+ const pluginVersion = true ? "0.23.63" : "0.0.0-dev";
73948
73958
  const agentName = this.config.agentName ?? "Agent";
73949
73959
  const resource = {
73950
73960
  "service.name": "agentvault-agent",
@@ -75148,6 +75158,7 @@ ${text}`,
75148
75158
  this._telemetryReporter = null;
75149
75159
  }
75150
75160
  this._stopA2aReconcileTimer();
75161
+ this._stopKeyProofTimer();
75151
75162
  if (this._ws) {
75152
75163
  this._ws.removeAllListeners();
75153
75164
  this._ws.close();
@@ -76154,7 +76165,7 @@ ${text}`,
76154
76165
  agentVersion: this.config.agentVersion ?? "0.0.0",
76155
76166
  // __AV_VERSION__ is injected by esbuild from package.json at build time.
76156
76167
  // Falls back to "0.0.0-dev" in non-bundled contexts (tests).
76157
- pluginVersion: true ? "0.23.62" : "0.0.0-dev"
76168
+ pluginVersion: true ? "0.23.63" : "0.0.0-dev"
76158
76169
  });
76159
76170
  this._telemetryReporter.startAutoFlush(3e4);
76160
76171
  }
@@ -76165,6 +76176,7 @@ ${text}`,
76165
76176
  if (aborted2()) return;
76166
76177
  await this._ensureKpPoolPublished();
76167
76178
  this._startKpReplenishTimer();
76179
+ this._startKeyProofTimer();
76168
76180
  this._pullDeliveryQueue().catch((err) => {
76169
76181
  console.warn("[SecureChannel] Initial delivery pull failed:", err);
76170
76182
  });
@@ -76486,7 +76498,7 @@ ${text}`,
76486
76498
  agentVersion: this.config.agentVersion ?? "0.0.0",
76487
76499
  // __AV_VERSION__ is injected by esbuild from package.json at build time.
76488
76500
  // Falls back to "0.0.0-dev" in non-bundled contexts (tests).
76489
- pluginVersion: true ? "0.23.62" : "0.0.0-dev"
76501
+ pluginVersion: true ? "0.23.63" : "0.0.0-dev"
76490
76502
  });
76491
76503
  this._telemetryReporter.startAutoFlush(3e4);
76492
76504
  }
@@ -76865,6 +76877,7 @@ ${text}`,
76865
76877
  }
76866
76878
  this._stopA2aReconcileTimer();
76867
76879
  this._stopKpReplenishTimer();
76880
+ this._stopKeyProofTimer();
76868
76881
  if (this._stopped) return;
76869
76882
  this._setState("disconnected");
76870
76883
  this._scheduleReconnect();
@@ -79355,6 +79368,82 @@ ${baseText}`;
79355
79368
  this._kpReplenishTimer = null;
79356
79369
  }
79357
79370
  }
79371
+ /** #1094: start reporting key proofs (now, then every interval). Idempotent. */
79372
+ _startKeyProofTimer() {
79373
+ this._stopKeyProofTimer();
79374
+ void this._reportKeyProofs();
79375
+ this._keyProofTimer = setInterval(() => {
79376
+ void this._reportKeyProofs();
79377
+ }, _SecureChannel._KEY_PROOF_INTERVAL_MS);
79378
+ }
79379
+ _stopKeyProofTimer() {
79380
+ if (this._keyProofTimer) {
79381
+ clearInterval(this._keyProofTimer);
79382
+ this._keyProofTimer = null;
79383
+ }
79384
+ }
79385
+ /**
79386
+ * #1094: prove, per live MLS group, that this agent can read it.
79387
+ *
79388
+ * `mls_key_proofs` answers "can this roster member actually decrypt?" — the
79389
+ * question nothing else can — but until now only browsers ever wrote one, so
79390
+ * a stuck agent (smartcode sat at epoch 1 in a group at 71 for two days,
79391
+ * #991) was invisible to the server. Same payload as the web reporter: the
79392
+ * epoch and RFC 9420 §8.2's `epoch_authenticator`, which only a holder of
79393
+ * the group's current state can compute and every member computes alike.
79394
+ *
79395
+ * A manager with no usable state reports nothing: the server reads that
79396
+ * absence as "cannot be shown to read", which is the honest signal. Each
79397
+ * group is reported once even when several keys share one manager. Never
79398
+ * throws; a failed report is logged at debug and changes nothing.
79399
+ */
79400
+ async _reportKeyProofs() {
79401
+ const deviceId = this._deviceId;
79402
+ const jwt = this._deviceJwt;
79403
+ if (!deviceId || !jwt) return;
79404
+ const best = /* @__PURE__ */ new Map();
79405
+ for (const mgr of this._mlsGroups.values()) {
79406
+ try {
79407
+ if (!mgr.isInitialized) continue;
79408
+ const epoch = Number(mgr.epoch);
79409
+ if (epoch <= 0) continue;
79410
+ const groupId = _SecureChannel._mlsGroupIdString(mgr.groupId);
79411
+ if (!groupId) continue;
79412
+ const prev = best.get(groupId);
79413
+ if (prev && epoch <= prev.epoch) continue;
79414
+ best.set(groupId, { epoch, authenticator: Buffer.from(mgr.epochAuthenticator).toString("hex") });
79415
+ } catch {
79416
+ continue;
79417
+ }
79418
+ }
79419
+ for (const [groupId, { epoch, authenticator }] of best) {
79420
+ try {
79421
+ const res = await fetch(`${this.config.apiUrl}/api/v1/mls/groups/${groupId}/key-proof`, {
79422
+ method: "POST",
79423
+ headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
79424
+ body: JSON.stringify({ device_id: deviceId, epoch, authenticator }),
79425
+ signal: AbortSignal.timeout(_SecureChannel._KEY_PROOF_FETCH_TIMEOUT_MS)
79426
+ });
79427
+ if (!res.ok) console.debug(`[key-proof] ${groupId.slice(0, 8)}: HTTP ${res.status}`);
79428
+ } catch (err) {
79429
+ console.debug(`[key-proof] ${groupId.slice(0, 8)}: report failed (non-critical):`, err);
79430
+ }
79431
+ }
79432
+ }
79433
+ /**
79434
+ * The wire MLS group id as a UUID string, or null. Every founder today —
79435
+ * ts-mls and Hermes alike — uses the server's UUID string as UTF-8 (36
79436
+ * bytes). A 16-byte id (the UUID's raw bytes) is mapped too, defensively:
79437
+ * dropping one would leave this agent "never proved" in that group.
79438
+ */
79439
+ static _mlsGroupIdString(raw) {
79440
+ if (raw.length === 16) {
79441
+ const h2 = Buffer.from(raw).toString("hex");
79442
+ return `${h2.slice(0, 8)}-${h2.slice(8, 12)}-${h2.slice(12, 16)}-${h2.slice(16, 20)}-${h2.slice(20)}`;
79443
+ }
79444
+ const s2 = new TextDecoder().decode(raw).toLowerCase();
79445
+ return UUID_RE4.test(s2) ? s2 : null;
79446
+ }
79358
79447
  /**
79359
79448
  * The server's EXPIRY-AWARE usable KeyPackage count, or null when unknown.
79360
79449
  *
@@ -102993,7 +103082,7 @@ data:
102993
103082
  await init_policy_enforcer();
102994
103083
  init_room_protocol();
102995
103084
  init_tool_telemetry();
102996
- VERSION = true ? "0.23.62" : "0.0.0-dev";
103085
+ VERSION = true ? "0.23.63" : "0.0.0-dev";
102997
103086
  }
102998
103087
  });
102999
103088
  await init_index();
@@ -105191,7 +105280,7 @@ function mkdir700(path2) {
105191
105280
  chmodSync5(path2, 448);
105192
105281
  }
105193
105282
  function packageVersion() {
105194
- return true ? "0.1.35" : void 0;
105283
+ return true ? "0.1.36" : void 0;
105195
105284
  }
105196
105285
  function helpText(version2) {
105197
105286
  return [
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentvault/muse-bridge",
3
- "version": "0.1.35",
3
+ "version": "0.1.36",
4
4
  "type": "module",
5
5
  "description": "AgentVault Muse Bridge — daemon bridging a Muse agent into E2E-encrypted AgentVault direct messages and rooms.",
6
6
  "main": "dist/index.js",