@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/index.js
CHANGED
|
@@ -44743,7 +44743,7 @@ var init_ratchet = __esm({
|
|
|
44743
44743
|
async "../crypto/dist/ratchet.js"() {
|
|
44744
44744
|
"use strict";
|
|
44745
44745
|
await init_libsodium_wrappers();
|
|
44746
|
-
MAX_SKIP =
|
|
44746
|
+
MAX_SKIP = 1e3;
|
|
44747
44747
|
CHAIN_KEY_SEED = new Uint8Array([1]);
|
|
44748
44748
|
MSG_KEY_SEED = new Uint8Array([2]);
|
|
44749
44749
|
HEADER_KEY_SEED = new Uint8Array([3]);
|
|
@@ -47236,6 +47236,12 @@ var init_channel = __esm({
|
|
|
47236
47236
|
this._primaryConversationId = this._persisted.primaryConversationId;
|
|
47237
47237
|
this._fingerprint = this._persisted.fingerprint;
|
|
47238
47238
|
this._lastInboundRoomId = this._persisted.lastInboundRoomId;
|
|
47239
|
+
if (this._persisted.seenMessageIds) {
|
|
47240
|
+
this._seenMessageIds = new Set(this._persisted.seenMessageIds.slice(-_SecureChannel.SEEN_MSG_MAX));
|
|
47241
|
+
}
|
|
47242
|
+
if (this._persisted.seenA2AMessageIds) {
|
|
47243
|
+
this._a2aSeenMessageIds = new Set(this._persisted.seenA2AMessageIds.slice(-_SecureChannel.A2A_SEEN_MAX));
|
|
47244
|
+
}
|
|
47239
47245
|
for (const [convId, sessionData] of Object.entries(
|
|
47240
47246
|
this._persisted.sessions
|
|
47241
47247
|
)) {
|
|
@@ -47382,6 +47388,7 @@ var init_channel = __esm({
|
|
|
47382
47388
|
}
|
|
47383
47389
|
const messageGroupId = randomUUID2();
|
|
47384
47390
|
let sentCount = 0;
|
|
47391
|
+
const pendingWsSends = [];
|
|
47385
47392
|
for (const [convId, session] of this._sessions) {
|
|
47386
47393
|
if (!session.activated) continue;
|
|
47387
47394
|
if (roomConvIds.has(convId)) continue;
|
|
@@ -47414,7 +47421,7 @@ var init_channel = __esm({
|
|
|
47414
47421
|
if (this._persisted?.hubId) {
|
|
47415
47422
|
payload.sender_hub_id = this._persisted.hubId;
|
|
47416
47423
|
}
|
|
47417
|
-
|
|
47424
|
+
pendingWsSends.push(
|
|
47418
47425
|
JSON.stringify({
|
|
47419
47426
|
event: "message",
|
|
47420
47427
|
data: payload
|
|
@@ -47440,6 +47447,9 @@ var init_channel = __esm({
|
|
|
47440
47447
|
console.warn("[SecureChannel] send() delivered to 0 sessions (all skipped or failed)");
|
|
47441
47448
|
}
|
|
47442
47449
|
await this._persistState();
|
|
47450
|
+
for (const frame of pendingWsSends) {
|
|
47451
|
+
this._ws.send(frame);
|
|
47452
|
+
}
|
|
47443
47453
|
}
|
|
47444
47454
|
/**
|
|
47445
47455
|
* Send a typing indicator to all owner devices.
|
|
@@ -47718,6 +47728,7 @@ var init_channel = __esm({
|
|
|
47718
47728
|
if (recipients.length === 0) {
|
|
47719
47729
|
throw new Error("No active sessions in room");
|
|
47720
47730
|
}
|
|
47731
|
+
await this._persistState();
|
|
47721
47732
|
if (this._state === "ready" && this._ws) {
|
|
47722
47733
|
this._ws.send(
|
|
47723
47734
|
JSON.stringify({
|
|
@@ -47757,7 +47768,6 @@ var init_channel = __esm({
|
|
|
47757
47768
|
throw new Error(`Failed to send room message: ${err}`);
|
|
47758
47769
|
}
|
|
47759
47770
|
}
|
|
47760
|
-
await this._persistState();
|
|
47761
47771
|
}
|
|
47762
47772
|
/**
|
|
47763
47773
|
* Leave a room: remove sessions and persisted room state.
|
|
@@ -47856,11 +47866,12 @@ var init_channel = __esm({
|
|
|
47856
47866
|
attachment: attachMeta
|
|
47857
47867
|
});
|
|
47858
47868
|
const messageGroupId = randomUUID2();
|
|
47869
|
+
const pendingWsSends = [];
|
|
47859
47870
|
for (const [convId, session] of this._sessions) {
|
|
47860
47871
|
if (!session.activated) continue;
|
|
47861
47872
|
const encrypted = session.ratchet.encrypt(envelope);
|
|
47862
47873
|
const transport = encryptedMessageToTransport(encrypted);
|
|
47863
|
-
|
|
47874
|
+
pendingWsSends.push(
|
|
47864
47875
|
JSON.stringify({
|
|
47865
47876
|
event: "message",
|
|
47866
47877
|
data: {
|
|
@@ -47874,6 +47885,9 @@ var init_channel = __esm({
|
|
|
47874
47885
|
);
|
|
47875
47886
|
}
|
|
47876
47887
|
await this._persistState();
|
|
47888
|
+
for (const frame of pendingWsSends) {
|
|
47889
|
+
this._ws.send(frame);
|
|
47890
|
+
}
|
|
47877
47891
|
}
|
|
47878
47892
|
async sendActionConfirmation(confirmation) {
|
|
47879
47893
|
const envelope = {
|
|
@@ -49690,11 +49704,12 @@ ${messageText}`;
|
|
|
49690
49704
|
});
|
|
49691
49705
|
this._appendHistory("agent", plaintext, topicId);
|
|
49692
49706
|
const messageGroupId = randomUUID2();
|
|
49707
|
+
const pendingWsSends = [];
|
|
49693
49708
|
for (const [convId, session] of this._sessions) {
|
|
49694
49709
|
if (!session.activated) continue;
|
|
49695
49710
|
const encrypted = session.ratchet.encrypt(envelope);
|
|
49696
49711
|
const transport = encryptedMessageToTransport(encrypted);
|
|
49697
|
-
|
|
49712
|
+
pendingWsSends.push(
|
|
49698
49713
|
JSON.stringify({
|
|
49699
49714
|
event: "message",
|
|
49700
49715
|
data: {
|
|
@@ -49708,6 +49723,9 @@ ${messageText}`;
|
|
|
49708
49723
|
);
|
|
49709
49724
|
}
|
|
49710
49725
|
await this._persistState();
|
|
49726
|
+
for (const frame of pendingWsSends) {
|
|
49727
|
+
this._ws.send(frame);
|
|
49728
|
+
}
|
|
49711
49729
|
}
|
|
49712
49730
|
/**
|
|
49713
49731
|
* Relay an owner's message to all sibling sessions as encrypted sync messages.
|
|
@@ -49730,13 +49748,14 @@ ${messageText}`;
|
|
|
49730
49748
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
49731
49749
|
topicId
|
|
49732
49750
|
});
|
|
49751
|
+
const pendingWsSends = [];
|
|
49733
49752
|
for (const [siblingConvId, siblingSession] of this._sessions) {
|
|
49734
49753
|
if (siblingConvId === sourceConvId) continue;
|
|
49735
49754
|
if (!siblingSession.activated) continue;
|
|
49736
49755
|
if (roomConvIds.has(siblingConvId)) continue;
|
|
49737
49756
|
const syncEncrypted = siblingSession.ratchet.encrypt(syncPayload);
|
|
49738
49757
|
const syncTransport = encryptedMessageToTransport(syncEncrypted);
|
|
49739
|
-
|
|
49758
|
+
pendingWsSends.push(
|
|
49740
49759
|
JSON.stringify({
|
|
49741
49760
|
event: "message",
|
|
49742
49761
|
data: {
|
|
@@ -49747,6 +49766,10 @@ ${messageText}`;
|
|
|
49747
49766
|
})
|
|
49748
49767
|
);
|
|
49749
49768
|
}
|
|
49769
|
+
await this._persistState();
|
|
49770
|
+
for (const frame of pendingWsSends) {
|
|
49771
|
+
this._ws.send(frame);
|
|
49772
|
+
}
|
|
49750
49773
|
}
|
|
49751
49774
|
/**
|
|
49752
49775
|
* Resolve the agent's workspace directory.
|
|
@@ -49790,6 +49813,7 @@ ${messageText}`;
|
|
|
49790
49813
|
const plaintext = JSON.stringify(payload);
|
|
49791
49814
|
const encrypted = session.ratchet.encrypt(plaintext);
|
|
49792
49815
|
const transport = encryptedMessageToTransport(encrypted);
|
|
49816
|
+
await this._persistState();
|
|
49793
49817
|
this._ws.send(
|
|
49794
49818
|
JSON.stringify({
|
|
49795
49819
|
event: "message",
|
|
@@ -49800,7 +49824,6 @@ ${messageText}`;
|
|
|
49800
49824
|
}
|
|
49801
49825
|
})
|
|
49802
49826
|
);
|
|
49803
|
-
await this._persistState();
|
|
49804
49827
|
}
|
|
49805
49828
|
/**
|
|
49806
49829
|
* Send stored message history to a newly-activated session.
|
|
@@ -49823,6 +49846,7 @@ ${messageText}`;
|
|
|
49823
49846
|
});
|
|
49824
49847
|
const encrypted = session.ratchet.encrypt(replayPayload);
|
|
49825
49848
|
const transport = encryptedMessageToTransport(encrypted);
|
|
49849
|
+
await this._persistState();
|
|
49826
49850
|
this._ws.send(
|
|
49827
49851
|
JSON.stringify({
|
|
49828
49852
|
event: "message",
|
|
@@ -50075,15 +50099,31 @@ ${messageText}`;
|
|
|
50075
50099
|
console.log(
|
|
50076
50100
|
`[SecureChannel] Room ratchet re-initialized for conv ${convId.slice(0, 8)}...`
|
|
50077
50101
|
);
|
|
50078
|
-
|
|
50079
|
-
|
|
50080
|
-
|
|
50081
|
-
|
|
50102
|
+
const incomingMsgNum = encrypted.header.messageNumber;
|
|
50103
|
+
if (incomingMsgNum <= 5) {
|
|
50104
|
+
try {
|
|
50105
|
+
plaintext = session.ratchet.decrypt(encrypted);
|
|
50106
|
+
session.activated = true;
|
|
50107
|
+
if (this._persisted.sessions[convId]) {
|
|
50108
|
+
this._persisted.sessions[convId].activated = true;
|
|
50109
|
+
}
|
|
50110
|
+
await this._persistState();
|
|
50111
|
+
console.log(
|
|
50112
|
+
`[SecureChannel] Room session ${convId.slice(0, 8)}... re-activated after ratchet re-init`
|
|
50113
|
+
);
|
|
50114
|
+
} catch (retryErr) {
|
|
50115
|
+
console.warn(
|
|
50116
|
+
`[SecureChannel] Room re-init retry failed for conv ${convId.slice(0, 8)} (msgNum=${incomingMsgNum}):`,
|
|
50117
|
+
retryErr
|
|
50118
|
+
);
|
|
50119
|
+
return;
|
|
50120
|
+
}
|
|
50121
|
+
} else {
|
|
50122
|
+
console.log(
|
|
50123
|
+
`[SecureChannel] Room re-init: skipping message with msgNum=${incomingMsgNum} for conv ${convId.slice(0, 8)} (too far ahead for fresh ratchet)`
|
|
50124
|
+
);
|
|
50125
|
+
return;
|
|
50082
50126
|
}
|
|
50083
|
-
await this._persistState();
|
|
50084
|
-
console.log(
|
|
50085
|
-
`[SecureChannel] Room session ${convId.slice(0, 8)}... re-activated after ratchet re-init`
|
|
50086
|
-
);
|
|
50087
50127
|
} catch (reinitErr) {
|
|
50088
50128
|
console.error(
|
|
50089
50129
|
`[SecureChannel] Room ratchet re-init failed for conv ${convId.slice(0, 8)}...:`,
|
|
@@ -50262,13 +50302,14 @@ ${messageText}`;
|
|
|
50262
50302
|
const dist = chain.getDistribution(this._deviceId);
|
|
50263
50303
|
const distJson = JSON.stringify(dist);
|
|
50264
50304
|
const alreadyDistributed = new Set(room.distributedTo ?? []);
|
|
50305
|
+
const pendingWsSends = [];
|
|
50265
50306
|
for (const convId of room.conversationIds) {
|
|
50266
50307
|
const session = this._sessions.get(convId);
|
|
50267
50308
|
if (!session || alreadyDistributed.has(session.ownerDeviceId)) continue;
|
|
50268
50309
|
const encrypted = session.ratchet.encrypt(distJson);
|
|
50269
50310
|
const transport = encryptedMessageToTransport(encrypted);
|
|
50270
50311
|
if (this._state === "ready" && this._ws) {
|
|
50271
|
-
|
|
50312
|
+
pendingWsSends.push(
|
|
50272
50313
|
JSON.stringify({
|
|
50273
50314
|
event: "sender_key_distribution",
|
|
50274
50315
|
data: {
|
|
@@ -50284,6 +50325,9 @@ ${messageText}`;
|
|
|
50284
50325
|
}
|
|
50285
50326
|
room.distributedTo = [...alreadyDistributed];
|
|
50286
50327
|
await this._persistState();
|
|
50328
|
+
for (const frame of pendingWsSends) {
|
|
50329
|
+
this._ws.send(frame);
|
|
50330
|
+
}
|
|
50287
50331
|
}
|
|
50288
50332
|
/**
|
|
50289
50333
|
* Handle an incoming sender_key_distribution event.
|
|
@@ -50481,8 +50525,10 @@ ${messageText}`;
|
|
|
50481
50525
|
try {
|
|
50482
50526
|
a2aPlaintext = ratchet.decrypt(encryptedMessage);
|
|
50483
50527
|
} catch (decryptErr) {
|
|
50484
|
-
console.error(`[SecureChannel] A2A decrypt failed \u2014 restoring ratchet
|
|
50528
|
+
console.error(`[SecureChannel] A2A decrypt failed \u2014 restoring ratchet, initiating rekey:`, decryptErr);
|
|
50485
50529
|
channelEntry.session.ratchetState = ratchetSnapshot;
|
|
50530
|
+
await this._persistState();
|
|
50531
|
+
await this._initiateA2ARekey(channelId);
|
|
50486
50532
|
return;
|
|
50487
50533
|
}
|
|
50488
50534
|
channelEntry.session.ratchetState = ratchet.serialize();
|
|
@@ -50524,24 +50570,9 @@ ${messageText}`;
|
|
|
50524
50570
|
}
|
|
50525
50571
|
} else {
|
|
50526
50572
|
console.warn(
|
|
50527
|
-
`[SecureChannel] Received encrypted A2A but no session for ${channelId.slice(0, 8)} \u2014
|
|
50573
|
+
`[SecureChannel] Received encrypted A2A but no session for ${channelId.slice(0, 8)} \u2014 initiating rekey`
|
|
50528
50574
|
);
|
|
50529
|
-
|
|
50530
|
-
if (entry && !entry.pendingEphemeralPrivateKey && !entry.session) {
|
|
50531
|
-
try {
|
|
50532
|
-
const a2aEphemeral = await generateEphemeralKeypair();
|
|
50533
|
-
const ephPubHex = bytesToHex(a2aEphemeral.publicKey);
|
|
50534
|
-
entry.pendingEphemeralPrivateKey = bytesToHex(a2aEphemeral.privateKey);
|
|
50535
|
-
this._ws?.send(JSON.stringify({
|
|
50536
|
-
event: "a2a_key_exchange",
|
|
50537
|
-
data: { channel_id: channelId, ephemeral_key: ephPubHex }
|
|
50538
|
-
}));
|
|
50539
|
-
await this._persistState();
|
|
50540
|
-
console.log(`[SecureChannel] On-demand A2A key exchange for ${channelId.slice(0, 8)}`);
|
|
50541
|
-
} catch (kxErr) {
|
|
50542
|
-
console.warn(`[SecureChannel] On-demand key exchange failed:`, kxErr);
|
|
50543
|
-
}
|
|
50544
|
-
}
|
|
50575
|
+
await this._initiateA2ARekey(channelId);
|
|
50545
50576
|
}
|
|
50546
50577
|
} else {
|
|
50547
50578
|
const a2aMsg = {
|
|
@@ -50558,6 +50589,51 @@ ${messageText}`;
|
|
|
50558
50589
|
}
|
|
50559
50590
|
}
|
|
50560
50591
|
}
|
|
50592
|
+
/**
|
|
50593
|
+
* Initiate A2A channel rekey after decrypt failure.
|
|
50594
|
+
* Calls the backend to reset channel to approved, clears local session,
|
|
50595
|
+
* and submits a fresh ephemeral key for key exchange.
|
|
50596
|
+
*/
|
|
50597
|
+
async _initiateA2ARekey(channelId) {
|
|
50598
|
+
const entry = this._persisted?.a2aChannels?.[channelId];
|
|
50599
|
+
if (!entry || !this._deviceJwt || !this._ws) return;
|
|
50600
|
+
const now = Date.now();
|
|
50601
|
+
const lastRekey = entry._lastRekeyAttempt ?? 0;
|
|
50602
|
+
if (now - lastRekey < 3e4) return;
|
|
50603
|
+
entry._lastRekeyAttempt = now;
|
|
50604
|
+
console.log(`[SecureChannel] Initiating A2A rekey for ${channelId.slice(0, 8)}...`);
|
|
50605
|
+
try {
|
|
50606
|
+
const res = await fetch(
|
|
50607
|
+
`${this.config.apiUrl}/api/v1/a2a/channels/${channelId}/rekey`,
|
|
50608
|
+
{
|
|
50609
|
+
method: "POST",
|
|
50610
|
+
headers: { Authorization: `Bearer ${this._deviceJwt}` }
|
|
50611
|
+
}
|
|
50612
|
+
);
|
|
50613
|
+
if (!res.ok) {
|
|
50614
|
+
const detail = await res.text();
|
|
50615
|
+
console.warn(`[SecureChannel] A2A rekey API failed (${res.status}): ${detail}`);
|
|
50616
|
+
return;
|
|
50617
|
+
}
|
|
50618
|
+
delete entry.session;
|
|
50619
|
+
delete entry.observerSession;
|
|
50620
|
+
delete entry.pendingEphemeralPrivateKey;
|
|
50621
|
+
delete entry.pendingObserverEphemeralPrivateKey;
|
|
50622
|
+
const a2aEphemeral = await generateEphemeralKeypair();
|
|
50623
|
+
entry.pendingEphemeralPrivateKey = bytesToHex(a2aEphemeral.privateKey);
|
|
50624
|
+
this._ws.send(JSON.stringify({
|
|
50625
|
+
event: "a2a_key_exchange",
|
|
50626
|
+
data: {
|
|
50627
|
+
channel_id: channelId,
|
|
50628
|
+
ephemeral_key: bytesToHex(a2aEphemeral.publicKey)
|
|
50629
|
+
}
|
|
50630
|
+
}));
|
|
50631
|
+
await this._persistState();
|
|
50632
|
+
console.log(`[SecureChannel] A2A rekey submitted for ${channelId.slice(0, 8)}`);
|
|
50633
|
+
} catch (err) {
|
|
50634
|
+
console.warn(`[SecureChannel] A2A rekey failed:`, err);
|
|
50635
|
+
}
|
|
50636
|
+
}
|
|
50561
50637
|
/**
|
|
50562
50638
|
* Paginated sync: fetch missed messages in pages of 200, up to 5 pages (1000 messages).
|
|
50563
50639
|
* Tracks message IDs in _syncMessageIds to prevent duplicate processing from concurrent WS messages.
|
|
@@ -50978,6 +51054,8 @@ ${messageText}`;
|
|
|
50978
51054
|
const hasA2AChannels = !!this._persisted.a2aChannels && Object.keys(this._persisted.a2aChannels).length > 0;
|
|
50979
51055
|
if (!hasOwnerSessions && !hasA2AChannels) return;
|
|
50980
51056
|
this._persisted.lastInboundRoomId = this._lastInboundRoomId;
|
|
51057
|
+
this._persisted.seenMessageIds = [...this._seenMessageIds].slice(-_SecureChannel.SEEN_MSG_MAX);
|
|
51058
|
+
this._persisted.seenA2AMessageIds = [...this._a2aSeenMessageIds].slice(-_SecureChannel.A2A_SEEN_MAX);
|
|
50981
51059
|
for (const [convId, session] of this._sessions) {
|
|
50982
51060
|
this._persisted.sessions[convId] = {
|
|
50983
51061
|
ownerDeviceId: session.ownerDeviceId,
|