@agentvault/agentvault 0.19.34 → 0.19.35
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 +112 -34
- package/dist/cli.js.map +2 -2
- package/dist/index.js +112 -34
- package/dist/index.js.map +2 -2
- package/dist/openclaw-entry.js.map +2 -2
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -44744,7 +44744,7 @@ var init_ratchet = __esm({
|
|
|
44744
44744
|
async "../crypto/dist/ratchet.js"() {
|
|
44745
44745
|
"use strict";
|
|
44746
44746
|
await init_libsodium_wrappers();
|
|
44747
|
-
MAX_SKIP =
|
|
44747
|
+
MAX_SKIP = 1e3;
|
|
44748
44748
|
CHAIN_KEY_SEED = new Uint8Array([1]);
|
|
44749
44749
|
MSG_KEY_SEED = new Uint8Array([2]);
|
|
44750
44750
|
HEADER_KEY_SEED = new Uint8Array([3]);
|
|
@@ -47175,6 +47175,12 @@ var init_channel = __esm({
|
|
|
47175
47175
|
this._primaryConversationId = this._persisted.primaryConversationId;
|
|
47176
47176
|
this._fingerprint = this._persisted.fingerprint;
|
|
47177
47177
|
this._lastInboundRoomId = this._persisted.lastInboundRoomId;
|
|
47178
|
+
if (this._persisted.seenMessageIds) {
|
|
47179
|
+
this._seenMessageIds = new Set(this._persisted.seenMessageIds.slice(-_SecureChannel.SEEN_MSG_MAX));
|
|
47180
|
+
}
|
|
47181
|
+
if (this._persisted.seenA2AMessageIds) {
|
|
47182
|
+
this._a2aSeenMessageIds = new Set(this._persisted.seenA2AMessageIds.slice(-_SecureChannel.A2A_SEEN_MAX));
|
|
47183
|
+
}
|
|
47178
47184
|
for (const [convId, sessionData] of Object.entries(
|
|
47179
47185
|
this._persisted.sessions
|
|
47180
47186
|
)) {
|
|
@@ -47321,6 +47327,7 @@ var init_channel = __esm({
|
|
|
47321
47327
|
}
|
|
47322
47328
|
const messageGroupId = randomUUID2();
|
|
47323
47329
|
let sentCount = 0;
|
|
47330
|
+
const pendingWsSends = [];
|
|
47324
47331
|
for (const [convId, session] of this._sessions) {
|
|
47325
47332
|
if (!session.activated) continue;
|
|
47326
47333
|
if (roomConvIds.has(convId)) continue;
|
|
@@ -47353,7 +47360,7 @@ var init_channel = __esm({
|
|
|
47353
47360
|
if (this._persisted?.hubId) {
|
|
47354
47361
|
payload.sender_hub_id = this._persisted.hubId;
|
|
47355
47362
|
}
|
|
47356
|
-
|
|
47363
|
+
pendingWsSends.push(
|
|
47357
47364
|
JSON.stringify({
|
|
47358
47365
|
event: "message",
|
|
47359
47366
|
data: payload
|
|
@@ -47379,6 +47386,9 @@ var init_channel = __esm({
|
|
|
47379
47386
|
console.warn("[SecureChannel] send() delivered to 0 sessions (all skipped or failed)");
|
|
47380
47387
|
}
|
|
47381
47388
|
await this._persistState();
|
|
47389
|
+
for (const frame of pendingWsSends) {
|
|
47390
|
+
this._ws.send(frame);
|
|
47391
|
+
}
|
|
47382
47392
|
}
|
|
47383
47393
|
/**
|
|
47384
47394
|
* Send a typing indicator to all owner devices.
|
|
@@ -47657,6 +47667,7 @@ var init_channel = __esm({
|
|
|
47657
47667
|
if (recipients.length === 0) {
|
|
47658
47668
|
throw new Error("No active sessions in room");
|
|
47659
47669
|
}
|
|
47670
|
+
await this._persistState();
|
|
47660
47671
|
if (this._state === "ready" && this._ws) {
|
|
47661
47672
|
this._ws.send(
|
|
47662
47673
|
JSON.stringify({
|
|
@@ -47696,7 +47707,6 @@ var init_channel = __esm({
|
|
|
47696
47707
|
throw new Error(`Failed to send room message: ${err}`);
|
|
47697
47708
|
}
|
|
47698
47709
|
}
|
|
47699
|
-
await this._persistState();
|
|
47700
47710
|
}
|
|
47701
47711
|
/**
|
|
47702
47712
|
* Leave a room: remove sessions and persisted room state.
|
|
@@ -47795,11 +47805,12 @@ var init_channel = __esm({
|
|
|
47795
47805
|
attachment: attachMeta
|
|
47796
47806
|
});
|
|
47797
47807
|
const messageGroupId = randomUUID2();
|
|
47808
|
+
const pendingWsSends = [];
|
|
47798
47809
|
for (const [convId, session] of this._sessions) {
|
|
47799
47810
|
if (!session.activated) continue;
|
|
47800
47811
|
const encrypted = session.ratchet.encrypt(envelope);
|
|
47801
47812
|
const transport = encryptedMessageToTransport(encrypted);
|
|
47802
|
-
|
|
47813
|
+
pendingWsSends.push(
|
|
47803
47814
|
JSON.stringify({
|
|
47804
47815
|
event: "message",
|
|
47805
47816
|
data: {
|
|
@@ -47813,6 +47824,9 @@ var init_channel = __esm({
|
|
|
47813
47824
|
);
|
|
47814
47825
|
}
|
|
47815
47826
|
await this._persistState();
|
|
47827
|
+
for (const frame of pendingWsSends) {
|
|
47828
|
+
this._ws.send(frame);
|
|
47829
|
+
}
|
|
47816
47830
|
}
|
|
47817
47831
|
async sendActionConfirmation(confirmation) {
|
|
47818
47832
|
const envelope = {
|
|
@@ -49629,11 +49643,12 @@ ${messageText}`;
|
|
|
49629
49643
|
});
|
|
49630
49644
|
this._appendHistory("agent", plaintext, topicId);
|
|
49631
49645
|
const messageGroupId = randomUUID2();
|
|
49646
|
+
const pendingWsSends = [];
|
|
49632
49647
|
for (const [convId, session] of this._sessions) {
|
|
49633
49648
|
if (!session.activated) continue;
|
|
49634
49649
|
const encrypted = session.ratchet.encrypt(envelope);
|
|
49635
49650
|
const transport = encryptedMessageToTransport(encrypted);
|
|
49636
|
-
|
|
49651
|
+
pendingWsSends.push(
|
|
49637
49652
|
JSON.stringify({
|
|
49638
49653
|
event: "message",
|
|
49639
49654
|
data: {
|
|
@@ -49647,6 +49662,9 @@ ${messageText}`;
|
|
|
49647
49662
|
);
|
|
49648
49663
|
}
|
|
49649
49664
|
await this._persistState();
|
|
49665
|
+
for (const frame of pendingWsSends) {
|
|
49666
|
+
this._ws.send(frame);
|
|
49667
|
+
}
|
|
49650
49668
|
}
|
|
49651
49669
|
/**
|
|
49652
49670
|
* Relay an owner's message to all sibling sessions as encrypted sync messages.
|
|
@@ -49669,13 +49687,14 @@ ${messageText}`;
|
|
|
49669
49687
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
49670
49688
|
topicId
|
|
49671
49689
|
});
|
|
49690
|
+
const pendingWsSends = [];
|
|
49672
49691
|
for (const [siblingConvId, siblingSession] of this._sessions) {
|
|
49673
49692
|
if (siblingConvId === sourceConvId) continue;
|
|
49674
49693
|
if (!siblingSession.activated) continue;
|
|
49675
49694
|
if (roomConvIds.has(siblingConvId)) continue;
|
|
49676
49695
|
const syncEncrypted = siblingSession.ratchet.encrypt(syncPayload);
|
|
49677
49696
|
const syncTransport = encryptedMessageToTransport(syncEncrypted);
|
|
49678
|
-
|
|
49697
|
+
pendingWsSends.push(
|
|
49679
49698
|
JSON.stringify({
|
|
49680
49699
|
event: "message",
|
|
49681
49700
|
data: {
|
|
@@ -49686,6 +49705,10 @@ ${messageText}`;
|
|
|
49686
49705
|
})
|
|
49687
49706
|
);
|
|
49688
49707
|
}
|
|
49708
|
+
await this._persistState();
|
|
49709
|
+
for (const frame of pendingWsSends) {
|
|
49710
|
+
this._ws.send(frame);
|
|
49711
|
+
}
|
|
49689
49712
|
}
|
|
49690
49713
|
/**
|
|
49691
49714
|
* Resolve the agent's workspace directory.
|
|
@@ -49729,6 +49752,7 @@ ${messageText}`;
|
|
|
49729
49752
|
const plaintext = JSON.stringify(payload);
|
|
49730
49753
|
const encrypted = session.ratchet.encrypt(plaintext);
|
|
49731
49754
|
const transport = encryptedMessageToTransport(encrypted);
|
|
49755
|
+
await this._persistState();
|
|
49732
49756
|
this._ws.send(
|
|
49733
49757
|
JSON.stringify({
|
|
49734
49758
|
event: "message",
|
|
@@ -49739,7 +49763,6 @@ ${messageText}`;
|
|
|
49739
49763
|
}
|
|
49740
49764
|
})
|
|
49741
49765
|
);
|
|
49742
|
-
await this._persistState();
|
|
49743
49766
|
}
|
|
49744
49767
|
/**
|
|
49745
49768
|
* Send stored message history to a newly-activated session.
|
|
@@ -49762,6 +49785,7 @@ ${messageText}`;
|
|
|
49762
49785
|
});
|
|
49763
49786
|
const encrypted = session.ratchet.encrypt(replayPayload);
|
|
49764
49787
|
const transport = encryptedMessageToTransport(encrypted);
|
|
49788
|
+
await this._persistState();
|
|
49765
49789
|
this._ws.send(
|
|
49766
49790
|
JSON.stringify({
|
|
49767
49791
|
event: "message",
|
|
@@ -50014,15 +50038,31 @@ ${messageText}`;
|
|
|
50014
50038
|
console.log(
|
|
50015
50039
|
`[SecureChannel] Room ratchet re-initialized for conv ${convId.slice(0, 8)}...`
|
|
50016
50040
|
);
|
|
50017
|
-
|
|
50018
|
-
|
|
50019
|
-
|
|
50020
|
-
|
|
50041
|
+
const incomingMsgNum = encrypted.header.messageNumber;
|
|
50042
|
+
if (incomingMsgNum <= 5) {
|
|
50043
|
+
try {
|
|
50044
|
+
plaintext = session.ratchet.decrypt(encrypted);
|
|
50045
|
+
session.activated = true;
|
|
50046
|
+
if (this._persisted.sessions[convId]) {
|
|
50047
|
+
this._persisted.sessions[convId].activated = true;
|
|
50048
|
+
}
|
|
50049
|
+
await this._persistState();
|
|
50050
|
+
console.log(
|
|
50051
|
+
`[SecureChannel] Room session ${convId.slice(0, 8)}... re-activated after ratchet re-init`
|
|
50052
|
+
);
|
|
50053
|
+
} catch (retryErr) {
|
|
50054
|
+
console.warn(
|
|
50055
|
+
`[SecureChannel] Room re-init retry failed for conv ${convId.slice(0, 8)} (msgNum=${incomingMsgNum}):`,
|
|
50056
|
+
retryErr
|
|
50057
|
+
);
|
|
50058
|
+
return;
|
|
50059
|
+
}
|
|
50060
|
+
} else {
|
|
50061
|
+
console.log(
|
|
50062
|
+
`[SecureChannel] Room re-init: skipping message with msgNum=${incomingMsgNum} for conv ${convId.slice(0, 8)} (too far ahead for fresh ratchet)`
|
|
50063
|
+
);
|
|
50064
|
+
return;
|
|
50021
50065
|
}
|
|
50022
|
-
await this._persistState();
|
|
50023
|
-
console.log(
|
|
50024
|
-
`[SecureChannel] Room session ${convId.slice(0, 8)}... re-activated after ratchet re-init`
|
|
50025
|
-
);
|
|
50026
50066
|
} catch (reinitErr) {
|
|
50027
50067
|
console.error(
|
|
50028
50068
|
`[SecureChannel] Room ratchet re-init failed for conv ${convId.slice(0, 8)}...:`,
|
|
@@ -50201,13 +50241,14 @@ ${messageText}`;
|
|
|
50201
50241
|
const dist = chain.getDistribution(this._deviceId);
|
|
50202
50242
|
const distJson = JSON.stringify(dist);
|
|
50203
50243
|
const alreadyDistributed = new Set(room.distributedTo ?? []);
|
|
50244
|
+
const pendingWsSends = [];
|
|
50204
50245
|
for (const convId of room.conversationIds) {
|
|
50205
50246
|
const session = this._sessions.get(convId);
|
|
50206
50247
|
if (!session || alreadyDistributed.has(session.ownerDeviceId)) continue;
|
|
50207
50248
|
const encrypted = session.ratchet.encrypt(distJson);
|
|
50208
50249
|
const transport = encryptedMessageToTransport(encrypted);
|
|
50209
50250
|
if (this._state === "ready" && this._ws) {
|
|
50210
|
-
|
|
50251
|
+
pendingWsSends.push(
|
|
50211
50252
|
JSON.stringify({
|
|
50212
50253
|
event: "sender_key_distribution",
|
|
50213
50254
|
data: {
|
|
@@ -50223,6 +50264,9 @@ ${messageText}`;
|
|
|
50223
50264
|
}
|
|
50224
50265
|
room.distributedTo = [...alreadyDistributed];
|
|
50225
50266
|
await this._persistState();
|
|
50267
|
+
for (const frame of pendingWsSends) {
|
|
50268
|
+
this._ws.send(frame);
|
|
50269
|
+
}
|
|
50226
50270
|
}
|
|
50227
50271
|
/**
|
|
50228
50272
|
* Handle an incoming sender_key_distribution event.
|
|
@@ -50420,8 +50464,10 @@ ${messageText}`;
|
|
|
50420
50464
|
try {
|
|
50421
50465
|
a2aPlaintext = ratchet.decrypt(encryptedMessage);
|
|
50422
50466
|
} catch (decryptErr) {
|
|
50423
|
-
console.error(`[SecureChannel] A2A decrypt failed \u2014 restoring ratchet
|
|
50467
|
+
console.error(`[SecureChannel] A2A decrypt failed \u2014 restoring ratchet, initiating rekey:`, decryptErr);
|
|
50424
50468
|
channelEntry.session.ratchetState = ratchetSnapshot;
|
|
50469
|
+
await this._persistState();
|
|
50470
|
+
await this._initiateA2ARekey(channelId);
|
|
50425
50471
|
return;
|
|
50426
50472
|
}
|
|
50427
50473
|
channelEntry.session.ratchetState = ratchet.serialize();
|
|
@@ -50463,24 +50509,9 @@ ${messageText}`;
|
|
|
50463
50509
|
}
|
|
50464
50510
|
} else {
|
|
50465
50511
|
console.warn(
|
|
50466
|
-
`[SecureChannel] Received encrypted A2A but no session for ${channelId.slice(0, 8)} \u2014
|
|
50512
|
+
`[SecureChannel] Received encrypted A2A but no session for ${channelId.slice(0, 8)} \u2014 initiating rekey`
|
|
50467
50513
|
);
|
|
50468
|
-
|
|
50469
|
-
if (entry && !entry.pendingEphemeralPrivateKey && !entry.session) {
|
|
50470
|
-
try {
|
|
50471
|
-
const a2aEphemeral = await generateEphemeralKeypair();
|
|
50472
|
-
const ephPubHex = bytesToHex(a2aEphemeral.publicKey);
|
|
50473
|
-
entry.pendingEphemeralPrivateKey = bytesToHex(a2aEphemeral.privateKey);
|
|
50474
|
-
this._ws?.send(JSON.stringify({
|
|
50475
|
-
event: "a2a_key_exchange",
|
|
50476
|
-
data: { channel_id: channelId, ephemeral_key: ephPubHex }
|
|
50477
|
-
}));
|
|
50478
|
-
await this._persistState();
|
|
50479
|
-
console.log(`[SecureChannel] On-demand A2A key exchange for ${channelId.slice(0, 8)}`);
|
|
50480
|
-
} catch (kxErr) {
|
|
50481
|
-
console.warn(`[SecureChannel] On-demand key exchange failed:`, kxErr);
|
|
50482
|
-
}
|
|
50483
|
-
}
|
|
50514
|
+
await this._initiateA2ARekey(channelId);
|
|
50484
50515
|
}
|
|
50485
50516
|
} else {
|
|
50486
50517
|
const a2aMsg = {
|
|
@@ -50497,6 +50528,51 @@ ${messageText}`;
|
|
|
50497
50528
|
}
|
|
50498
50529
|
}
|
|
50499
50530
|
}
|
|
50531
|
+
/**
|
|
50532
|
+
* Initiate A2A channel rekey after decrypt failure.
|
|
50533
|
+
* Calls the backend to reset channel to approved, clears local session,
|
|
50534
|
+
* and submits a fresh ephemeral key for key exchange.
|
|
50535
|
+
*/
|
|
50536
|
+
async _initiateA2ARekey(channelId) {
|
|
50537
|
+
const entry = this._persisted?.a2aChannels?.[channelId];
|
|
50538
|
+
if (!entry || !this._deviceJwt || !this._ws) return;
|
|
50539
|
+
const now = Date.now();
|
|
50540
|
+
const lastRekey = entry._lastRekeyAttempt ?? 0;
|
|
50541
|
+
if (now - lastRekey < 3e4) return;
|
|
50542
|
+
entry._lastRekeyAttempt = now;
|
|
50543
|
+
console.log(`[SecureChannel] Initiating A2A rekey for ${channelId.slice(0, 8)}...`);
|
|
50544
|
+
try {
|
|
50545
|
+
const res = await fetch(
|
|
50546
|
+
`${this.config.apiUrl}/api/v1/a2a/channels/${channelId}/rekey`,
|
|
50547
|
+
{
|
|
50548
|
+
method: "POST",
|
|
50549
|
+
headers: { Authorization: `Bearer ${this._deviceJwt}` }
|
|
50550
|
+
}
|
|
50551
|
+
);
|
|
50552
|
+
if (!res.ok) {
|
|
50553
|
+
const detail = await res.text();
|
|
50554
|
+
console.warn(`[SecureChannel] A2A rekey API failed (${res.status}): ${detail}`);
|
|
50555
|
+
return;
|
|
50556
|
+
}
|
|
50557
|
+
delete entry.session;
|
|
50558
|
+
delete entry.observerSession;
|
|
50559
|
+
delete entry.pendingEphemeralPrivateKey;
|
|
50560
|
+
delete entry.pendingObserverEphemeralPrivateKey;
|
|
50561
|
+
const a2aEphemeral = await generateEphemeralKeypair();
|
|
50562
|
+
entry.pendingEphemeralPrivateKey = bytesToHex(a2aEphemeral.privateKey);
|
|
50563
|
+
this._ws.send(JSON.stringify({
|
|
50564
|
+
event: "a2a_key_exchange",
|
|
50565
|
+
data: {
|
|
50566
|
+
channel_id: channelId,
|
|
50567
|
+
ephemeral_key: bytesToHex(a2aEphemeral.publicKey)
|
|
50568
|
+
}
|
|
50569
|
+
}));
|
|
50570
|
+
await this._persistState();
|
|
50571
|
+
console.log(`[SecureChannel] A2A rekey submitted for ${channelId.slice(0, 8)}`);
|
|
50572
|
+
} catch (err) {
|
|
50573
|
+
console.warn(`[SecureChannel] A2A rekey failed:`, err);
|
|
50574
|
+
}
|
|
50575
|
+
}
|
|
50500
50576
|
/**
|
|
50501
50577
|
* Paginated sync: fetch missed messages in pages of 200, up to 5 pages (1000 messages).
|
|
50502
50578
|
* Tracks message IDs in _syncMessageIds to prevent duplicate processing from concurrent WS messages.
|
|
@@ -50917,6 +50993,8 @@ ${messageText}`;
|
|
|
50917
50993
|
const hasA2AChannels = !!this._persisted.a2aChannels && Object.keys(this._persisted.a2aChannels).length > 0;
|
|
50918
50994
|
if (!hasOwnerSessions && !hasA2AChannels) return;
|
|
50919
50995
|
this._persisted.lastInboundRoomId = this._lastInboundRoomId;
|
|
50996
|
+
this._persisted.seenMessageIds = [...this._seenMessageIds].slice(-_SecureChannel.SEEN_MSG_MAX);
|
|
50997
|
+
this._persisted.seenA2AMessageIds = [...this._a2aSeenMessageIds].slice(-_SecureChannel.A2A_SEEN_MAX);
|
|
50920
50998
|
for (const [convId, session] of this._sessions) {
|
|
50921
50999
|
this._persisted.sessions[convId] = {
|
|
50922
51000
|
ownerDeviceId: session.ownerDeviceId,
|