@agentvault/grok-bridge 0.4.29 → 0.4.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/dist/index.js +98 -9
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -11731,11 +11731,11 @@ async function joinWithFirstMatchingKp(welcomeBytes, candidates) {
11731
11731
  return null;
11732
11732
  }
11733
11733
  function ownIdentity() {
11734
- const v2 = true ? "0.23.62" : FALLBACK;
11734
+ const v2 = true ? "0.23.63" : FALLBACK;
11735
11735
  return `${PACKAGE}@${v2}`;
11736
11736
  }
11737
11737
  function buildSha() {
11738
- const raw = true ? "4db8d51" : "";
11738
+ const raw = true ? "52249f2" : "";
11739
11739
  const cleaned = (raw ?? "").trim();
11740
11740
  return !cleaned || cleaned === "unknown" ? null : cleaned;
11741
11741
  }
@@ -70996,6 +70996,16 @@ var init_dist = __esm({
70996
70996
  */
70997
70997
  static _KP_REPLENISH_INTERVAL_MS = 6 * 60 * 60 * 1e3;
70998
70998
  _kpReplenishTimer = null;
70999
+ /**
71000
+ * #1094: how often each live group's key proof is re-reported — the web
71001
+ * reporter's cadence (`use-key-proof-reporter.ts`), against the server's 24h
71002
+ * staleness window. Re-reading the CURRENT epoch on a timer is self-correcting
71003
+ * whatever moved it, which is why no commit site is hooked.
71004
+ */
71005
+ static _KEY_PROOF_INTERVAL_MS = 10 * 60 * 1e3;
71006
+ /** #1094: never let one slow report hold up the rest. */
71007
+ static _KEY_PROOF_FETCH_TIMEOUT_MS = 1e4;
71008
+ _keyProofTimer = null;
70999
71009
  _a2aReconcileTimer = null;
71000
71010
  _deliveryPulling = false;
71001
71011
  _drDeliveryPulling = false;
@@ -73237,7 +73247,7 @@ ${text}`,
73237
73247
  */
73238
73248
  sendActivitySpan(spanData) {
73239
73249
  if (!this._ws || this._ws.readyState !== WebSocket.OPEN) return;
73240
- const pluginVersion = true ? "0.23.62" : "0.0.0-dev";
73250
+ const pluginVersion = true ? "0.23.63" : "0.0.0-dev";
73241
73251
  const agentName = this.config.agentName ?? "Agent";
73242
73252
  const resource = {
73243
73253
  "service.name": "agentvault-agent",
@@ -74441,6 +74451,7 @@ ${text}`,
74441
74451
  this._telemetryReporter = null;
74442
74452
  }
74443
74453
  this._stopA2aReconcileTimer();
74454
+ this._stopKeyProofTimer();
74444
74455
  if (this._ws) {
74445
74456
  this._ws.removeAllListeners();
74446
74457
  this._ws.close();
@@ -75447,7 +75458,7 @@ ${text}`,
75447
75458
  agentVersion: this.config.agentVersion ?? "0.0.0",
75448
75459
  // __AV_VERSION__ is injected by esbuild from package.json at build time.
75449
75460
  // Falls back to "0.0.0-dev" in non-bundled contexts (tests).
75450
- pluginVersion: true ? "0.23.62" : "0.0.0-dev"
75461
+ pluginVersion: true ? "0.23.63" : "0.0.0-dev"
75451
75462
  });
75452
75463
  this._telemetryReporter.startAutoFlush(3e4);
75453
75464
  }
@@ -75458,6 +75469,7 @@ ${text}`,
75458
75469
  if (aborted2()) return;
75459
75470
  await this._ensureKpPoolPublished();
75460
75471
  this._startKpReplenishTimer();
75472
+ this._startKeyProofTimer();
75461
75473
  this._pullDeliveryQueue().catch((err) => {
75462
75474
  console.warn("[SecureChannel] Initial delivery pull failed:", err);
75463
75475
  });
@@ -75779,7 +75791,7 @@ ${text}`,
75779
75791
  agentVersion: this.config.agentVersion ?? "0.0.0",
75780
75792
  // __AV_VERSION__ is injected by esbuild from package.json at build time.
75781
75793
  // Falls back to "0.0.0-dev" in non-bundled contexts (tests).
75782
- pluginVersion: true ? "0.23.62" : "0.0.0-dev"
75794
+ pluginVersion: true ? "0.23.63" : "0.0.0-dev"
75783
75795
  });
75784
75796
  this._telemetryReporter.startAutoFlush(3e4);
75785
75797
  }
@@ -76158,6 +76170,7 @@ ${text}`,
76158
76170
  }
76159
76171
  this._stopA2aReconcileTimer();
76160
76172
  this._stopKpReplenishTimer();
76173
+ this._stopKeyProofTimer();
76161
76174
  if (this._stopped) return;
76162
76175
  this._setState("disconnected");
76163
76176
  this._scheduleReconnect();
@@ -78648,6 +78661,82 @@ ${baseText}`;
78648
78661
  this._kpReplenishTimer = null;
78649
78662
  }
78650
78663
  }
78664
+ /** #1094: start reporting key proofs (now, then every interval). Idempotent. */
78665
+ _startKeyProofTimer() {
78666
+ this._stopKeyProofTimer();
78667
+ void this._reportKeyProofs();
78668
+ this._keyProofTimer = setInterval(() => {
78669
+ void this._reportKeyProofs();
78670
+ }, _SecureChannel._KEY_PROOF_INTERVAL_MS);
78671
+ }
78672
+ _stopKeyProofTimer() {
78673
+ if (this._keyProofTimer) {
78674
+ clearInterval(this._keyProofTimer);
78675
+ this._keyProofTimer = null;
78676
+ }
78677
+ }
78678
+ /**
78679
+ * #1094: prove, per live MLS group, that this agent can read it.
78680
+ *
78681
+ * `mls_key_proofs` answers "can this roster member actually decrypt?" — the
78682
+ * question nothing else can — but until now only browsers ever wrote one, so
78683
+ * a stuck agent (smartcode sat at epoch 1 in a group at 71 for two days,
78684
+ * #991) was invisible to the server. Same payload as the web reporter: the
78685
+ * epoch and RFC 9420 §8.2's `epoch_authenticator`, which only a holder of
78686
+ * the group's current state can compute and every member computes alike.
78687
+ *
78688
+ * A manager with no usable state reports nothing: the server reads that
78689
+ * absence as "cannot be shown to read", which is the honest signal. Each
78690
+ * group is reported once even when several keys share one manager. Never
78691
+ * throws; a failed report is logged at debug and changes nothing.
78692
+ */
78693
+ async _reportKeyProofs() {
78694
+ const deviceId = this._deviceId;
78695
+ const jwt = this._deviceJwt;
78696
+ if (!deviceId || !jwt) return;
78697
+ const best = /* @__PURE__ */ new Map();
78698
+ for (const mgr of this._mlsGroups.values()) {
78699
+ try {
78700
+ if (!mgr.isInitialized) continue;
78701
+ const epoch = Number(mgr.epoch);
78702
+ if (epoch <= 0) continue;
78703
+ const groupId = _SecureChannel._mlsGroupIdString(mgr.groupId);
78704
+ if (!groupId) continue;
78705
+ const prev = best.get(groupId);
78706
+ if (prev && epoch <= prev.epoch) continue;
78707
+ best.set(groupId, { epoch, authenticator: Buffer.from(mgr.epochAuthenticator).toString("hex") });
78708
+ } catch {
78709
+ continue;
78710
+ }
78711
+ }
78712
+ for (const [groupId, { epoch, authenticator }] of best) {
78713
+ try {
78714
+ const res = await fetch(`${this.config.apiUrl}/api/v1/mls/groups/${groupId}/key-proof`, {
78715
+ method: "POST",
78716
+ headers: { Authorization: `Bearer ${jwt}`, "Content-Type": "application/json" },
78717
+ body: JSON.stringify({ device_id: deviceId, epoch, authenticator }),
78718
+ signal: AbortSignal.timeout(_SecureChannel._KEY_PROOF_FETCH_TIMEOUT_MS)
78719
+ });
78720
+ if (!res.ok) console.debug(`[key-proof] ${groupId.slice(0, 8)}: HTTP ${res.status}`);
78721
+ } catch (err) {
78722
+ console.debug(`[key-proof] ${groupId.slice(0, 8)}: report failed (non-critical):`, err);
78723
+ }
78724
+ }
78725
+ }
78726
+ /**
78727
+ * The wire MLS group id as a UUID string, or null. Every founder today —
78728
+ * ts-mls and Hermes alike — uses the server's UUID string as UTF-8 (36
78729
+ * bytes). A 16-byte id (the UUID's raw bytes) is mapped too, defensively:
78730
+ * dropping one would leave this agent "never proved" in that group.
78731
+ */
78732
+ static _mlsGroupIdString(raw) {
78733
+ if (raw.length === 16) {
78734
+ const h2 = Buffer.from(raw).toString("hex");
78735
+ return `${h2.slice(0, 8)}-${h2.slice(8, 12)}-${h2.slice(12, 16)}-${h2.slice(16, 20)}-${h2.slice(20)}`;
78736
+ }
78737
+ const s2 = new TextDecoder().decode(raw).toLowerCase();
78738
+ return UUID_RE4.test(s2) ? s2 : null;
78739
+ }
78651
78740
  /**
78652
78741
  * The server's EXPIRY-AWARE usable KeyPackage count, or null when unknown.
78653
78742
  *
@@ -102286,7 +102375,7 @@ data:
102286
102375
  await init_policy_enforcer();
102287
102376
  init_room_protocol();
102288
102377
  init_tool_telemetry();
102289
- VERSION = true ? "0.23.62" : "0.0.0-dev";
102378
+ VERSION = true ? "0.23.63" : "0.0.0-dev";
102290
102379
  }
102291
102380
  });
102292
102381
  await init_index();
@@ -104557,7 +104646,7 @@ async function main() {
104557
104646
  const info = parseInfoFlags(process.argv.slice(2));
104558
104647
  if (info.showVersion || info.showHelp) {
104559
104648
  const version2 = buildClientVersion2(
104560
- true ? "0.4.29" : void 0
104649
+ true ? "0.4.30" : void 0
104561
104650
  );
104562
104651
  if (info.showVersion) printLine(version2);
104563
104652
  if (info.showHelp) {
@@ -104596,7 +104685,7 @@ async function main() {
104596
104685
  process.exit(0);
104597
104686
  }
104598
104687
  const cfg = loadConfig(process.env, process.argv.slice(2));
104599
- logLine(`[grok-bridge] version: ${true ? "0.4.29" : "dev"}`);
104688
+ logLine(`[grok-bridge] version: ${true ? "0.4.30" : "dev"}`);
104600
104689
  mkdirSync7(cfg.workspaceDir, { recursive: true });
104601
104690
  mkdirSync7(cfg.fenceHome, { recursive: true });
104602
104691
  seedFenceCredential({
@@ -104611,7 +104700,7 @@ async function main() {
104611
104700
  agentName: cfg.agentName,
104612
104701
  platform: "node",
104613
104702
  clientVersion: buildClientVersion2(
104614
- true ? "0.4.29" : void 0
104703
+ true ? "0.4.30" : void 0
104615
104704
  )
104616
104705
  });
104617
104706
  channelRef = channel;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentvault/grok-bridge",
3
- "version": "0.4.29",
3
+ "version": "0.4.30",
4
4
  "type": "module",
5
5
  "description": "AgentVault Grok Bridge — daemon bridging a Grok agent into E2E-encrypted AgentVault direct messages and rooms.",
6
6
  "main": "dist/index.js",