@agentvault/agentvault 0.20.23 → 0.20.25

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/cli.js CHANGED
@@ -62727,6 +62727,48 @@ function mlsFileName(groupId) {
62727
62727
  const safe = groupId.replace(/[^a-zA-Z0-9_-]/g, "_");
62728
62728
  return `mls-${safe}.json`;
62729
62729
  }
62730
+ async function hasPendingWelcome(dataDir2, groupId) {
62731
+ try {
62732
+ await readFile(pendingKpPath(dataDir2, groupId));
62733
+ return true;
62734
+ } catch {
62735
+ return false;
62736
+ }
62737
+ }
62738
+ async function savePendingKpBundle(dataDir2, groupId, kp) {
62739
+ await mkdir(dataDir2, { recursive: true, mode: DIR_MODE });
62740
+ const serialized = {
62741
+ publicPackage: Buffer.from(kp.publicPackage).toString("base64"),
62742
+ privatePackage: {
62743
+ initPrivateKey: Buffer.from(kp.privatePackage.initPrivateKey).toString("base64"),
62744
+ hpkePrivateKey: Buffer.from(kp.privatePackage.hpkePrivateKey).toString("base64"),
62745
+ signaturePrivateKey: Buffer.from(kp.privatePackage.signaturePrivateKey).toString("base64")
62746
+ }
62747
+ };
62748
+ await writeFile(pendingKpPath(dataDir2, groupId), JSON.stringify(serialized), { encoding: "utf-8", mode: FILE_MODE });
62749
+ }
62750
+ async function loadPendingKpBundle(dataDir2, groupId) {
62751
+ try {
62752
+ const raw = await readFile(pendingKpPath(dataDir2, groupId), "utf-8");
62753
+ const parsed = JSON.parse(raw);
62754
+ return {
62755
+ publicPackage: new Uint8Array(Buffer.from(parsed.publicPackage, "base64")),
62756
+ privatePackage: {
62757
+ initPrivateKey: new Uint8Array(Buffer.from(parsed.privatePackage.initPrivateKey, "base64")),
62758
+ hpkePrivateKey: new Uint8Array(Buffer.from(parsed.privatePackage.hpkePrivateKey, "base64")),
62759
+ signaturePrivateKey: new Uint8Array(Buffer.from(parsed.privatePackage.signaturePrivateKey, "base64"))
62760
+ }
62761
+ };
62762
+ } catch {
62763
+ return null;
62764
+ }
62765
+ }
62766
+ async function clearPendingWelcome(dataDir2, groupId) {
62767
+ try {
62768
+ await rm(pendingKpPath(dataDir2, groupId));
62769
+ } catch {
62770
+ }
62771
+ }
62730
62772
  async function saveMlsState(dataDir2, groupId, state) {
62731
62773
  await mkdir(dataDir2, { recursive: true, mode: DIR_MODE });
62732
62774
  const filePath = join(dataDir2, mlsFileName(groupId));
@@ -62747,12 +62789,13 @@ async function deleteMlsState(dataDir2, groupId) {
62747
62789
  } catch {
62748
62790
  }
62749
62791
  }
62750
- var FILE_MODE, DIR_MODE;
62792
+ var FILE_MODE, DIR_MODE, pendingKpPath;
62751
62793
  var init_mls_state = __esm({
62752
62794
  "src/mls-state.ts"() {
62753
62795
  "use strict";
62754
62796
  FILE_MODE = 384;
62755
62797
  DIR_MODE = 448;
62798
+ pendingKpPath = (dataDir2, groupId) => join(dataDir2, `mls-kp-pending-${groupId.replace(/[^a-zA-Z0-9_-]/g, "_")}.json`);
62756
62799
  }
62757
62800
  });
62758
62801
 
@@ -63640,9 +63683,6 @@ var init_channel = __esm({
63640
63683
  _mlsKeyPackage = null;
63641
63684
  /** Pending KeyPackage bundle from request-Welcome flow (used by _handleMlsWelcome). */
63642
63685
  _pendingMlsKpBundle;
63643
- /** Channels that have already had their sync fallback KeyPackage published this connect cycle.
63644
- * Prevents multiple agents from overwriting each other's KP for the same channel. */
63645
- _pendingWelcomeChannels = /* @__PURE__ */ new Set();
63646
63686
  /** In-memory credential store for renter-provided credentials (never persisted). */
63647
63687
  _credentialStore = new CredentialStore();
63648
63688
  /** Dedup buffer for A2A message IDs (prevents double-delivery via direct + Redis) */
@@ -65203,8 +65243,7 @@ var init_channel = __esm({
65203
65243
  }
65204
65244
  }
65205
65245
  const memberMlsGroup = chState.mlsGroupId ? this._mlsGroups.get(`a2a:${chId}`) : void 0;
65206
- if (chState.role === "member" && !memberMlsGroup?.isInitialized && !this._pendingWelcomeChannels.has(chId)) {
65207
- this._pendingWelcomeChannels.add(chId);
65246
+ if (chState.role === "member" && !memberMlsGroup?.isInitialized) {
65208
65247
  try {
65209
65248
  let groupId = chState.mlsGroupId;
65210
65249
  let memberIds = [];
@@ -65238,10 +65277,16 @@ var init_channel = __esm({
65238
65277
  if (memberIds.includes(this._persisted.deviceId)) {
65239
65278
  console.log(`[SecureChannel] A2A ${chId.slice(0, 8)} member in server membership but no local MLS state \u2014 requesting Welcome`);
65240
65279
  }
65280
+ if (await hasPendingWelcome(this.config.dataDir, groupId)) {
65281
+ console.log(`[SecureChannel] A2A ${chId.slice(0, 8)} sync fallback: skipping \u2014 Welcome already pending for group=${groupId.slice(0, 8)}`);
65282
+ continue;
65283
+ }
65284
+ await setPendingWelcome(this.config.dataDir, groupId);
65241
65285
  const mgr = new MLSGroupManager();
65242
65286
  const identity = new TextEncoder().encode(this._persisted.deviceId);
65243
65287
  const kp = await mgr.generateKeyPackage(identity);
65244
65288
  this._pendingMlsKpBundle = kp;
65289
+ await savePendingKpBundle(this.config.dataDir, groupId, kp);
65245
65290
  const kpBytes = MLSGroupManager.serializeKeyPackage(kp.publicPackage);
65246
65291
  await fetch(`${this.config.apiUrl}/api/v1/mls/key-packages`, {
65247
65292
  method: "POST",
@@ -66116,7 +66161,6 @@ var init_channel = __esm({
66116
66161
  clearInterval(this._deliveryHeartbeat);
66117
66162
  this._deliveryHeartbeat = null;
66118
66163
  }
66119
- this._pendingWelcomeChannels.clear();
66120
66164
  if (this._stopped) return;
66121
66165
  this._setState("disconnected");
66122
66166
  this._scheduleReconnect();
@@ -67106,12 +67150,14 @@ ${messageText}`;
67106
67150
  async _handleMlsWelcome(data) {
67107
67151
  const groupId = data.group_id;
67108
67152
  const conversationId = data.conversation_id;
67109
- const kpSource = this._pendingMlsKpBundle ? "pending" : this._mlsKeyPackage ? "connect" : "generated";
67153
+ const persistedKpAvailable = await hasPendingWelcome(this.config.dataDir, groupId);
67154
+ const kpSource = this._pendingMlsKpBundle ? "pending" : persistedKpAvailable ? "persisted" : this._mlsKeyPackage ? "connect" : "generated";
67110
67155
  console.log(`[SecureChannel] Received MLS welcome for group ${groupId?.slice(0, 8)}${conversationId ? ` conv=${conversationId.slice(0, 8)}` : ""} kpSource=${kpSource}`);
67111
67156
  try {
67112
67157
  const welcomeBytes = new Uint8Array(Buffer.from(data.payload, "hex"));
67113
67158
  const mgr = new MLSGroupManager();
67114
- const kp = this._pendingMlsKpBundle ?? this._mlsKeyPackage ?? await (async () => {
67159
+ const persistedKp = await loadPendingKpBundle(this.config.dataDir, groupId);
67160
+ const kp = this._pendingMlsKpBundle ?? persistedKp ?? this._mlsKeyPackage ?? await (async () => {
67115
67161
  const identity = new TextEncoder().encode(this._deviceId);
67116
67162
  return mgr.generateKeyPackage(identity);
67117
67163
  })();
@@ -67148,7 +67194,8 @@ ${messageText}`;
67148
67194
  this._mlsGroups.set(`a2a:${channelId}`, mgr);
67149
67195
  await saveMlsState(this.config.dataDir, groupId, JSON.stringify(mgr.exportState()));
67150
67196
  await this._persistState();
67151
- this._pendingWelcomeChannels.delete(channelId);
67197
+ await clearPendingWelcome(this.config.dataDir, groupId).catch(() => {
67198
+ });
67152
67199
  this._pendingMlsKpBundle = void 0;
67153
67200
  console.log(`[SecureChannel] Joined MLS group for A2A ${channelId.slice(0, 8)} via Welcome (epoch=${mgr.epoch})`);
67154
67201
  if (this.config.onA2AChannelReady && entry.conversationId) {
@@ -88917,7 +88964,7 @@ var init_index = __esm({
88917
88964
  init_skill_invoker();
88918
88965
  await init_skill_telemetry();
88919
88966
  await init_policy_enforcer();
88920
- VERSION = true ? "0.20.23" : "0.0.0-dev";
88967
+ VERSION = true ? "0.20.25" : "0.0.0-dev";
88921
88968
  }
88922
88969
  });
88923
88970