@agentvault/agentvault 0.19.58 → 0.19.59

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 (66) hide show
  1. package/dist/_cp.d.ts +10 -0
  2. package/dist/_cp.d.ts.map +1 -0
  3. package/dist/account-config.d.ts +20 -0
  4. package/dist/account-config.d.ts.map +1 -0
  5. package/dist/channel.d.ts +389 -0
  6. package/dist/channel.d.ts.map +1 -0
  7. package/dist/cli.d.ts +2 -0
  8. package/dist/cli.d.ts.map +1 -0
  9. package/dist/cli.js +42 -415
  10. package/dist/cli.js.map +2 -2
  11. package/dist/create-agent.d.ts +28 -0
  12. package/dist/create-agent.d.ts.map +1 -0
  13. package/dist/credential-store.d.ts +62 -0
  14. package/dist/credential-store.d.ts.map +1 -0
  15. package/dist/crypto-helpers.d.ts +2 -0
  16. package/dist/crypto-helpers.d.ts.map +1 -0
  17. package/dist/doctor.d.ts +41 -0
  18. package/dist/doctor.d.ts.map +1 -0
  19. package/dist/fetch-interceptor.d.ts +32 -0
  20. package/dist/fetch-interceptor.d.ts.map +1 -0
  21. package/dist/gateway-send.d.ts +98 -0
  22. package/dist/gateway-send.d.ts.map +1 -0
  23. package/dist/http-handlers.d.ts +53 -0
  24. package/dist/http-handlers.d.ts.map +1 -0
  25. package/dist/index.d.ts +27 -0
  26. package/dist/index.d.ts.map +1 -0
  27. package/dist/index.js +42 -415
  28. package/dist/index.js.map +2 -2
  29. package/dist/mcp-handlers.d.ts +26 -0
  30. package/dist/mcp-handlers.d.ts.map +1 -0
  31. package/dist/mcp-proxy-helpers.d.ts +9 -0
  32. package/dist/mcp-proxy-helpers.d.ts.map +1 -0
  33. package/dist/mcp-server.d.ts +91 -0
  34. package/dist/mcp-server.d.ts.map +1 -0
  35. package/dist/mls-state.d.ts +16 -0
  36. package/dist/mls-state.d.ts.map +1 -0
  37. package/dist/openclaw-compat.d.ts +33 -0
  38. package/dist/openclaw-compat.d.ts.map +1 -0
  39. package/dist/openclaw-entry.d.ts +32 -0
  40. package/dist/openclaw-entry.d.ts.map +1 -0
  41. package/dist/openclaw-plugin.d.ts +102 -0
  42. package/dist/openclaw-plugin.d.ts.map +1 -0
  43. package/dist/openclaw-types.d.ts +186 -0
  44. package/dist/openclaw-types.d.ts.map +1 -0
  45. package/dist/policy-enforcer.d.ts +78 -0
  46. package/dist/policy-enforcer.d.ts.map +1 -0
  47. package/dist/setup.d.ts +27 -0
  48. package/dist/setup.d.ts.map +1 -0
  49. package/dist/skill-invoker.d.ts +30 -0
  50. package/dist/skill-invoker.d.ts.map +1 -0
  51. package/dist/skill-manifest.d.ts +30 -0
  52. package/dist/skill-manifest.d.ts.map +1 -0
  53. package/dist/skill-telemetry.d.ts +36 -0
  54. package/dist/skill-telemetry.d.ts.map +1 -0
  55. package/dist/skills-publish.d.ts +8 -0
  56. package/dist/skills-publish.d.ts.map +1 -0
  57. package/dist/state.d.ts +32 -0
  58. package/dist/state.d.ts.map +1 -0
  59. package/dist/transport.d.ts +24 -0
  60. package/dist/transport.d.ts.map +1 -0
  61. package/dist/types.d.ts +421 -0
  62. package/dist/types.d.ts.map +1 -0
  63. package/dist/workspace-handlers.d.ts +62 -0
  64. package/dist/workspace-handlers.d.ts.map +1 -0
  65. package/openclaw.plugin.json +1 -1
  66. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -62647,6 +62647,24 @@ var init_channel = __esm({
62647
62647
  if (this._persisted.seenA2AMessageIds) {
62648
62648
  this._a2aSeenMessageIds = new Set(this._persisted.seenA2AMessageIds.slice(-_SecureChannel.A2A_SEEN_MAX));
62649
62649
  }
62650
+ if (this._persisted?.rooms) {
62651
+ const roomConvIds = /* @__PURE__ */ new Set();
62652
+ for (const room of Object.values(this._persisted.rooms)) {
62653
+ for (const cid of room.conversationIds || []) {
62654
+ roomConvIds.add(cid);
62655
+ }
62656
+ }
62657
+ let cleanedCount = 0;
62658
+ for (const cid of roomConvIds) {
62659
+ if (this._persisted.sessions[cid]) {
62660
+ delete this._persisted.sessions[cid];
62661
+ cleanedCount++;
62662
+ }
62663
+ }
62664
+ if (cleanedCount > 0) {
62665
+ console.log(`[SecureChannel] Cleaned ${cleanedCount} stale DR room sessions`);
62666
+ }
62667
+ }
62650
62668
  for (const [convId, sessionData] of Object.entries(
62651
62669
  this._persisted.sessions
62652
62670
  )) {
@@ -63019,89 +63037,21 @@ var init_channel = __esm({
63019
63037
  }
63020
63038
  // --- Multi-agent room methods ---
63021
63039
  /**
63022
- * Join a room by performing X3DH key exchange with each member
63023
- * for the pairwise conversations involving this device.
63040
+ * Join a room by collecting pairwise conversation IDs involving this device.
63041
+ * Encryption is handled by MLS group operations, not per-member DR sessions.
63024
63042
  */
63025
63043
  async joinRoom(roomData) {
63026
63044
  if (!this._persisted) {
63027
63045
  throw new Error("Channel not initialized");
63028
63046
  }
63029
63047
  await libsodium_wrappers_default.ready;
63030
- if (roomData.forceRekey) {
63031
- let cleared = 0;
63032
- const existingRoom = this._persisted.rooms?.[roomData.roomId];
63033
- if (existingRoom) {
63034
- for (const convId of existingRoom.conversationIds) {
63035
- if (this._sessions.has(convId)) {
63036
- this._sessions.delete(convId);
63037
- cleared++;
63038
- }
63039
- delete this._persisted.sessions[convId];
63040
- }
63041
- }
63042
- if (this._persisted) {
63043
- this._persisted.lastMessageTimestamp = (/* @__PURE__ */ new Date()).toISOString();
63044
- }
63045
- console.log(
63046
- `[SecureChannel] Force rekey: cleared ${cleared} sessions for room ${roomData.roomId.slice(0, 8)}...`
63047
- );
63048
- }
63049
- const identity = this._persisted.identityKeypair;
63050
- const ephemeral = this._persisted.ephemeralKeypair;
63051
63048
  const myDeviceId = this._deviceId;
63052
63049
  const conversationIds = [];
63053
63050
  for (const conv of roomData.conversations) {
63054
63051
  if (conv.participantA !== myDeviceId && conv.participantB !== myDeviceId) {
63055
63052
  continue;
63056
63053
  }
63057
- if (this._sessions.has(conv.id)) {
63058
- conversationIds.push(conv.id);
63059
- continue;
63060
- }
63061
- const otherDeviceId = conv.participantA === myDeviceId ? conv.participantB : conv.participantA;
63062
- const otherMember = roomData.members.find((m2) => m2.deviceId === otherDeviceId);
63063
- if (!otherMember?.identityPublicKey) {
63064
- console.warn(
63065
- `[SecureChannel] No public key for member ${otherDeviceId.slice(0, 8)}..., skipping`
63066
- );
63067
- continue;
63068
- }
63069
- const isInitiator = myDeviceId < otherDeviceId;
63070
- const theirEphKey = otherMember.ephemeralPublicKey ?? otherMember.identityPublicKey;
63071
- const sharedSecret = performX3DH({
63072
- myIdentityPrivate: hexToBytes(identity.privateKey),
63073
- myEphemeralPrivate: hexToBytes(ephemeral.privateKey),
63074
- theirIdentityPublic: hexToBytes(otherMember.identityPublicKey),
63075
- theirEphemeralPublic: hexToBytes(theirEphKey),
63076
- isInitiator
63077
- });
63078
- const peerIdentityPub = hexToBytes(otherMember.identityPublicKey);
63079
- const ratchet = isInitiator ? DoubleRatchet.initSender(sharedSecret, {
63080
- publicKey: hexToBytes(identity.publicKey),
63081
- privateKey: hexToBytes(identity.privateKey),
63082
- keyType: "ed25519"
63083
- }, peerIdentityPub) : DoubleRatchet.initReceiver(sharedSecret, {
63084
- publicKey: hexToBytes(identity.publicKey),
63085
- privateKey: hexToBytes(identity.privateKey),
63086
- keyType: "ed25519"
63087
- }, peerIdentityPub);
63088
- this._sessions.set(conv.id, {
63089
- ownerDeviceId: otherDeviceId,
63090
- ratchet,
63091
- activated: isInitiator,
63092
- // initiator can send immediately
63093
- epoch: 1
63094
- });
63095
- this._persisted.sessions[conv.id] = {
63096
- ownerDeviceId: otherDeviceId,
63097
- ratchetState: ratchet.serialize(),
63098
- activated: isInitiator,
63099
- epoch: 1
63100
- };
63101
63054
  conversationIds.push(conv.id);
63102
- console.log(
63103
- `[SecureChannel] Room session initialized: conv ${conv.id.slice(0, 8)}... with ${otherDeviceId.slice(0, 8)}... (initiator=${isInitiator})`
63104
- );
63105
63055
  }
63106
63056
  if (!this._persisted.rooms) {
63107
63057
  this._persisted.rooms = {};
@@ -63197,68 +63147,15 @@ var init_channel = __esm({
63197
63147
  }
63198
63148
  return;
63199
63149
  } catch (mlsErr) {
63200
- console.warn(`[SecureChannel] MLS encrypt failed for room ${roomId.slice(0, 8)}, falling through to legacy:`, mlsErr);
63201
- }
63202
- }
63203
- }
63204
- const recipients = [];
63205
- for (const convId of room.conversationIds) {
63206
- const session = this._sessions.get(convId);
63207
- if (!session) {
63208
- console.warn(`[SecureChannel] No session for room conv ${convId.slice(0, 8)}..., skipping`);
63209
- continue;
63210
- }
63211
- const encrypted = session.ratchet.encrypt(plaintext);
63212
- const transport = encryptedMessageToTransport(encrypted);
63213
- recipients.push({
63214
- device_id: session.ownerDeviceId,
63215
- header_blob: transport.header_blob,
63216
- ciphertext: transport.ciphertext
63217
- });
63218
- }
63219
- if (recipients.length === 0) {
63220
- throw new Error("No active sessions in room");
63221
- }
63222
- await this._persistState();
63223
- if (this._state === "ready" && this._ws) {
63224
- this._ws.send(
63225
- JSON.stringify({
63226
- event: "room_message",
63227
- data: {
63228
- room_id: roomId,
63229
- recipients,
63230
- message_type: messageType,
63231
- priority: opts?.priority ?? "normal",
63232
- metadata: opts?.metadata
63233
- }
63234
- })
63235
- );
63236
- } else {
63237
- try {
63238
- const res = await fetch(
63239
- `${this.config.apiUrl}/api/v1/rooms/${roomId}/messages`,
63240
- {
63241
- method: "POST",
63242
- headers: {
63243
- "Content-Type": "application/json",
63244
- Authorization: `Bearer ${this._deviceJwt}`
63245
- },
63246
- body: JSON.stringify({
63247
- recipients,
63248
- message_type: messageType,
63249
- priority: opts?.priority ?? "normal",
63250
- metadata: opts?.metadata
63251
- })
63252
- }
63253
- );
63254
- if (!res.ok) {
63255
- const detail = await res.text();
63256
- throw new Error(`Room message failed (${res.status}): ${detail}`);
63150
+ throw new Error(
63151
+ `MLS encrypt failed for room ${roomId.slice(0, 8)}... \u2014 MLS group must be initialized before sending. Error: ${mlsErr}`
63152
+ );
63257
63153
  }
63258
- } catch (err) {
63259
- throw new Error(`Failed to send room message: ${err}`);
63260
63154
  }
63261
63155
  }
63156
+ throw new Error(
63157
+ `Room ${roomId.slice(0, 8)}... has no initialized MLS group. MLS initialization must complete before messages can be sent.`
63158
+ );
63262
63159
  }
63263
63160
  /**
63264
63161
  * Leave a room: remove sessions and persisted room state.
@@ -65418,250 +65315,8 @@ ${messageText}`;
65418
65315
  this.emit("error", err);
65419
65316
  }
65420
65317
  }
65421
- /**
65422
- * Send a resync_request for a room conversation if the cooldown has elapsed.
65423
- * Shared by all room ratchet failure paths to avoid code duplication.
65424
- */
65425
- _sendRoomResyncIfCooled(convId, reason, session) {
65426
- const RESYNC_COOLDOWN_MS = 5 * 60 * 1e3;
65427
- const lastResync = this._lastResyncRequest.get(convId) ?? 0;
65428
- if (Date.now() - lastResync > RESYNC_COOLDOWN_MS && this._ws && this._persisted) {
65429
- this._lastResyncRequest.set(convId, Date.now());
65430
- this._ws.send(
65431
- JSON.stringify({
65432
- event: "resync_request",
65433
- data: {
65434
- conversation_id: convId,
65435
- reason,
65436
- identity_public_key: this._persisted.identityKeypair.publicKey,
65437
- ephemeral_public_key: this._persisted.ephemeralKeypair.publicKey,
65438
- epoch: session?.epoch
65439
- }
65440
- })
65441
- );
65442
- console.log(
65443
- `[SecureChannel] Room resync requested for conv ${convId.slice(0, 8)} (${reason})`
65444
- );
65445
- }
65446
- }
65447
- /**
65448
- * Handle an incoming room message (pairwise path — used by sync replay and pairwise room fallback).
65449
- * Finds the pairwise conversation for the sender, decrypts, and emits a room_message event.
65450
- */
65451
- async _handleRoomMessage(msgData) {
65452
- if (msgData.sender_device_id === this._deviceId) return;
65453
- this._lastInboundRoomId = msgData.room_id;
65454
- const convId = msgData.conversation_id ?? this._findConversationForSender(msgData.sender_device_id, msgData.room_id);
65455
- if (!convId) {
65456
- console.warn(
65457
- `[SecureChannel] No conversation found for sender ${msgData.sender_device_id.slice(0, 8)}... in room ${msgData.room_id}`
65458
- );
65459
- return;
65460
- }
65461
- let session = this._sessions.get(convId);
65462
- if (!session) {
65463
- console.warn(
65464
- `[SecureChannel] No session for room conv ${convId.slice(0, 8)}..., fetching room data`
65465
- );
65466
- try {
65467
- const roomRes = await fetch(
65468
- `${this.config.apiUrl}/api/v1/rooms/${msgData.room_id}`,
65469
- {
65470
- headers: {
65471
- Authorization: `Bearer ${this._persisted.deviceJwt}`
65472
- }
65473
- }
65474
- );
65475
- if (roomRes.ok) {
65476
- const roomData = await roomRes.json();
65477
- await this.joinRoom({
65478
- roomId: roomData.id,
65479
- name: roomData.name,
65480
- members: (roomData.members || []).map((m2) => ({
65481
- deviceId: m2.device_id,
65482
- entityType: m2.entity_type,
65483
- displayName: m2.display_name,
65484
- identityPublicKey: m2.identity_public_key,
65485
- ephemeralPublicKey: m2.ephemeral_public_key
65486
- })),
65487
- conversations: (roomData.conversations || []).map((c2) => ({
65488
- id: c2.id,
65489
- participantA: c2.participant_a,
65490
- participantB: c2.participant_b
65491
- }))
65492
- });
65493
- session = this._sessions.get(convId);
65494
- }
65495
- } catch (fetchErr) {
65496
- console.error(
65497
- `[SecureChannel] Failed to fetch room data for ${msgData.room_id}:`,
65498
- fetchErr
65499
- );
65500
- }
65501
- if (!session) {
65502
- console.warn(
65503
- `[SecureChannel] Still no session for room conv ${convId.slice(0, 8)}... after refresh, skipping`
65504
- );
65505
- return;
65506
- }
65507
- }
65508
- const encrypted = transportToEncryptedMessage({
65509
- header_blob: msgData.header_blob,
65510
- ciphertext: msgData.ciphertext
65511
- });
65512
- let plaintext;
65513
- const ratchetSnapshot = session.ratchet.serialize();
65514
- try {
65515
- plaintext = session.ratchet.decrypt(encrypted);
65516
- } catch (decryptErr) {
65517
- try {
65518
- session.ratchet = DoubleRatchet.deserialize(ratchetSnapshot);
65519
- } catch {
65520
- }
65521
- console.warn(
65522
- `[SecureChannel] Room decrypt failed for conv ${convId.slice(0, 8)}...: ${String(decryptErr)}, re-initializing ratchet`
65523
- );
65524
- try {
65525
- const roomEntry = this._persisted?.rooms ? Object.values(this._persisted.rooms).find(
65526
- (r2) => r2.conversationIds.includes(convId)
65527
- ) : null;
65528
- if (!roomEntry) throw new Error("Room not found for conversation");
65529
- const otherMember = roomEntry.members.find(
65530
- (m2) => m2.deviceId === msgData.sender_device_id
65531
- );
65532
- if (!otherMember?.identityPublicKey) throw new Error("No key for sender");
65533
- const isInitiator = this._deviceId < msgData.sender_device_id;
65534
- const identity = this._persisted.identityKeypair;
65535
- const ephemeral = this._persisted.ephemeralKeypair;
65536
- const sharedSecret = performX3DH({
65537
- myIdentityPrivate: hexToBytes(identity.privateKey),
65538
- myEphemeralPrivate: hexToBytes(ephemeral.privateKey),
65539
- theirIdentityPublic: hexToBytes(otherMember.identityPublicKey),
65540
- theirEphemeralPublic: hexToBytes(
65541
- otherMember.ephemeralPublicKey ?? otherMember.identityPublicKey
65542
- ),
65543
- isInitiator
65544
- });
65545
- const peerIdPub = hexToBytes(otherMember.identityPublicKey);
65546
- const newRatchet = isInitiator ? DoubleRatchet.initSender(sharedSecret, {
65547
- publicKey: hexToBytes(identity.publicKey),
65548
- privateKey: hexToBytes(identity.privateKey),
65549
- keyType: "ed25519"
65550
- }, peerIdPub) : DoubleRatchet.initReceiver(sharedSecret, {
65551
- publicKey: hexToBytes(identity.publicKey),
65552
- privateKey: hexToBytes(identity.privateKey),
65553
- keyType: "ed25519"
65554
- }, peerIdPub);
65555
- session.ratchet = newRatchet;
65556
- session.activated = false;
65557
- this._persisted.sessions[convId] = {
65558
- ownerDeviceId: session.ownerDeviceId,
65559
- ratchetState: newRatchet.serialize(),
65560
- activated: false
65561
- };
65562
- await this._persistState();
65563
- console.log(
65564
- `[SecureChannel] Room ratchet re-initialized for conv ${convId.slice(0, 8)}...`
65565
- );
65566
- const incomingMsgNum = encrypted.header.messageNumber;
65567
- if (incomingMsgNum <= 5) {
65568
- try {
65569
- plaintext = session.ratchet.decrypt(encrypted);
65570
- session.activated = true;
65571
- if (this._persisted.sessions[convId]) {
65572
- this._persisted.sessions[convId].activated = true;
65573
- }
65574
- await this._persistState();
65575
- console.log(
65576
- `[SecureChannel] Room session ${convId.slice(0, 8)}... re-activated after ratchet re-init`
65577
- );
65578
- } catch (retryErr) {
65579
- console.warn(
65580
- `[SecureChannel] Room re-init retry failed for conv ${convId.slice(0, 8)} (msgNum=${incomingMsgNum}):`,
65581
- retryErr
65582
- );
65583
- this._sendRoomResyncIfCooled(convId, "room_reinit_retry_failed", session);
65584
- return;
65585
- }
65586
- } else {
65587
- console.log(
65588
- `[SecureChannel] Room re-init: skipping message with msgNum=${incomingMsgNum} for conv ${convId.slice(0, 8)} (too far ahead for fresh ratchet)`
65589
- );
65590
- this._sendRoomResyncIfCooled(convId, "room_message_skip");
65591
- return;
65592
- }
65593
- } catch (reinitErr) {
65594
- console.error(
65595
- `[SecureChannel] Room ratchet re-init failed for conv ${convId.slice(0, 8)}...:`,
65596
- reinitErr
65597
- );
65598
- this._sendRoomResyncIfCooled(convId, "room_reinit_failed");
65599
- return;
65600
- }
65601
- }
65602
- let messageText;
65603
- let messageType;
65604
- try {
65605
- const parsed = JSON.parse(plaintext);
65606
- messageType = parsed.type || "message";
65607
- messageText = parsed.text || plaintext;
65608
- } catch {
65609
- messageType = "message";
65610
- messageText = plaintext;
65611
- }
65612
- if (CREDENTIAL_MESSAGE_TYPES.has(messageType)) {
65613
- this._handleCredentialMessage(msgData.room_id, messageType, messageText, msgData.message_id);
65614
- if (msgData.created_at && this._persisted) {
65615
- this._persisted.lastMessageTimestamp = msgData.created_at;
65616
- }
65617
- await this._persistState();
65618
- return;
65619
- }
65620
- if (!ROOM_AGENT_TYPES.has(messageType)) {
65621
- return;
65622
- }
65623
- if (!session.activated) {
65624
- session.activated = true;
65625
- console.log(
65626
- `[SecureChannel] Room session ${convId.slice(0, 8)}... activated by first message`
65627
- );
65628
- }
65629
- if (msgData.message_id) {
65630
- this._sendAck(msgData.message_id);
65631
- }
65632
- if (msgData.created_at && this._persisted) {
65633
- this._persisted.lastMessageTimestamp = msgData.created_at;
65634
- }
65635
- await this._persistState();
65636
- const legacyRoomMembers = this._persisted?.rooms?.[msgData.room_id]?.members ?? [];
65637
- const legacySenderMember = legacyRoomMembers.find((m2) => m2.deviceId === msgData.sender_device_id);
65638
- const legacySenderIsAgent = legacySenderMember?.entityType === "agent";
65639
- const legacySenderLabel = legacySenderMember?.displayName || "someone";
65640
- const metadata = {
65641
- messageId: msgData.message_id ?? "",
65642
- conversationId: convId,
65643
- timestamp: msgData.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
65644
- messageType,
65645
- roomId: msgData.room_id,
65646
- senderDeviceId: msgData.sender_device_id,
65647
- senderIsAgent: legacySenderIsAgent,
65648
- senderName: legacySenderLabel,
65649
- roomName: this._persisted?.rooms?.[msgData.room_id]?.name
65650
- };
65651
- this._appendHistory("owner", messageText, `room:${msgData.room_id}`);
65652
- this.emit("room_message", {
65653
- roomId: msgData.room_id,
65654
- senderDeviceId: msgData.sender_device_id,
65655
- senderName: legacySenderLabel,
65656
- plaintext: messageText,
65657
- messageType,
65658
- timestamp: msgData.created_at ?? (/* @__PURE__ */ new Date()).toISOString()
65659
- });
65660
- const legacyContextualMessage = legacySenderIsAgent ? messageText : `[${legacySenderLabel}]: ${messageText}`;
65661
- Promise.resolve(this.config.onMessage?.(legacyContextualMessage, metadata)).catch((err) => {
65662
- console.error("[SecureChannel] onMessage callback error:", err);
65663
- });
65664
- }
65318
+ // _sendRoomResyncIfCooled removed — rooms are MLS-only now
65319
+ // _handleRoomMessage removed rooms are MLS-only now
65665
65320
  /**
65666
65321
  * Handle credential protocol messages (grant, revoke, request).
65667
65322
  * These are intercepted before reaching the agent's onMessage callback.
@@ -65750,20 +65405,7 @@ ${messageText}`;
65750
65405
  purgeRoomCredentials(roomId) {
65751
65406
  this._credentialStore.purgeForRoom(roomId);
65752
65407
  }
65753
- /**
65754
- * Find the pairwise conversation ID for a given sender in a room.
65755
- */
65756
- _findConversationForSender(senderDeviceId, roomId) {
65757
- const room = this._persisted?.rooms?.[roomId];
65758
- if (!room) return null;
65759
- for (const convId of room.conversationIds) {
65760
- const session = this._sessions.get(convId);
65761
- if (session && session.ownerDeviceId === senderDeviceId) {
65762
- return convId;
65763
- }
65764
- }
65765
- return null;
65766
- }
65408
+ // _findConversationForSender removed — rooms are MLS-only now
65767
65409
  // ---------------------------------------------------------------------------
65768
65410
  // MLS room message handlers
65769
65411
  // ---------------------------------------------------------------------------
@@ -65787,11 +65429,12 @@ ${messageText}`;
65787
65429
  return;
65788
65430
  }
65789
65431
  }
65790
- this._lastInboundRoomId = roomId;
65791
- const mlsGroup = this._mlsGroups.get(roomId);
65792
- console.log(`[SecureChannel] MLS decrypt attempt room=${roomId.slice(0, 8)} group=${groupId?.slice(0, 8)} loaded=${!!mlsGroup} init=${mlsGroup?.isInitialized} mlsGroupsKeys=[${Array.from(this._mlsGroups.keys()).join(",")}]`);
65432
+ const resolvedRoomId = roomId;
65433
+ this._lastInboundRoomId = resolvedRoomId;
65434
+ const mlsGroup = this._mlsGroups.get(resolvedRoomId);
65435
+ console.log(`[SecureChannel] MLS decrypt attempt room=${resolvedRoomId.slice(0, 8)} group=${groupId?.slice(0, 8)} loaded=${!!mlsGroup} init=${mlsGroup?.isInitialized} mlsGroupsKeys=[${Array.from(this._mlsGroups.keys()).join(",")}]`);
65793
65436
  if (!mlsGroup?.isInitialized) {
65794
- console.warn(`[SecureChannel] MLS group not loaded for room ${roomId.slice(0, 8)}`);
65437
+ console.warn(`[SecureChannel] MLS group not loaded for room ${resolvedRoomId.slice(0, 8)}`);
65795
65438
  return;
65796
65439
  }
65797
65440
  try {
@@ -65813,7 +65456,7 @@ ${messageText}`;
65813
65456
  messageText = rawPlaintext;
65814
65457
  }
65815
65458
  if (CREDENTIAL_MESSAGE_TYPES.has(messageType)) {
65816
- this._handleCredentialMessage(roomId, messageType, messageText, data.message_id);
65459
+ this._handleCredentialMessage(resolvedRoomId, messageType, messageText, data.message_id);
65817
65460
  if (data.created_at && this._persisted) {
65818
65461
  this._persisted.lastMessageTimestamp = data.created_at;
65819
65462
  }
@@ -65828,13 +65471,13 @@ ${messageText}`;
65828
65471
  }
65829
65472
  if (data.created_at && this._persisted) {
65830
65473
  this._persisted.lastMessageTimestamp = data.created_at;
65831
- const roomState = this._persisted.rooms?.[roomId];
65474
+ const roomState = this._persisted.rooms?.[resolvedRoomId];
65832
65475
  if (roomState) {
65833
65476
  roomState.lastMlsMessageTs = data.created_at;
65834
65477
  }
65835
65478
  }
65836
65479
  await this._persistState();
65837
- const roomMembers = this._persisted?.rooms?.[roomId]?.members ?? [];
65480
+ const roomMembers = this._persisted?.rooms?.[resolvedRoomId]?.members ?? [];
65838
65481
  const senderMember = roomMembers.find((m2) => m2.deviceId === senderDeviceId);
65839
65482
  const senderIsAgent = senderMember?.entityType === "agent";
65840
65483
  const metadata = {
@@ -65842,16 +65485,16 @@ ${messageText}`;
65842
65485
  conversationId: "",
65843
65486
  timestamp: data.created_at ?? (/* @__PURE__ */ new Date()).toISOString(),
65844
65487
  messageType,
65845
- roomId,
65488
+ roomId: resolvedRoomId,
65846
65489
  senderDeviceId,
65847
65490
  senderIsAgent,
65848
65491
  senderName: senderMember?.displayName || "unknown",
65849
- roomName: this._persisted?.rooms?.[roomId]?.name
65492
+ roomName: this._persisted?.rooms?.[resolvedRoomId]?.name
65850
65493
  };
65851
65494
  const senderLabel = senderMember?.displayName || "someone";
65852
- this._appendHistory("owner", messageText, `room:${roomId}`);
65495
+ this._appendHistory("owner", messageText, `room:${resolvedRoomId}`);
65853
65496
  this.emit("room_message", {
65854
- roomId,
65497
+ roomId: resolvedRoomId,
65855
65498
  senderDeviceId,
65856
65499
  senderName: senderLabel,
65857
65500
  plaintext: messageText,
@@ -65863,7 +65506,7 @@ ${messageText}`;
65863
65506
  console.error("[SecureChannel] onMessage callback error (MLS):", err);
65864
65507
  });
65865
65508
  } catch (err) {
65866
- console.error(`[SecureChannel] MLS room decrypt failed for ${roomId.slice(0, 8)}:`, err);
65509
+ console.error(`[SecureChannel] MLS room decrypt failed for ${resolvedRoomId.slice(0, 8)}:`, err);
65867
65510
  }
65868
65511
  }
65869
65512
  async _handleMlsCommit(data) {
@@ -66190,22 +65833,6 @@ ${messageText}`;
66190
65833
  }
66191
65834
  }
66192
65835
  if (roomId) {
66193
- try {
66194
- await this._handleRoomMessage({
66195
- room_id: roomId,
66196
- sender_device_id: msg.sender_device_id,
66197
- conversation_id: msg.conversation_id,
66198
- header_blob: msg.header_blob,
66199
- ciphertext: msg.ciphertext,
66200
- message_id: msg.id,
66201
- created_at: msg.created_at
66202
- });
66203
- } catch (roomErr) {
66204
- console.warn(
66205
- `[SecureChannel] Sync room message failed for ${msg.conversation_id.slice(0, 8)}...:`,
66206
- roomErr
66207
- );
66208
- }
66209
65836
  this._persisted.lastMessageTimestamp = msg.created_at;
66210
65837
  since = msg.created_at;
66211
65838
  continue;