@agentvault/agentvault 0.13.8 → 0.13.10
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/channel.d.ts +8 -0
- package/dist/channel.d.ts.map +1 -1
- package/dist/cli.js +148 -28
- package/dist/cli.js.map +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.js +194 -29
- package/dist/index.js.map +2 -2
- package/dist/openclaw-entry.d.ts.map +1 -1
- package/dist/openclaw-entry.js +80 -1
- package/dist/openclaw-entry.js.map +2 -2
- package/dist/openclaw-plugin.d.ts +37 -0
- package/dist/openclaw-plugin.d.ts.map +1 -1
- package/openclaw.plugin.json +2 -1
- package/package.json +9 -1
package/dist/index.d.ts
CHANGED
|
@@ -5,5 +5,5 @@ export type { ResolvedAccount } from "./account-config.js";
|
|
|
5
5
|
export { agentVaultPlugin, setOcRuntime, getActiveChannel } from "./openclaw-plugin.js";
|
|
6
6
|
export { sendToOwner, checkGateway } from "./gateway-send.js";
|
|
7
7
|
export type { GatewaySendOptions, GatewaySendResult, GatewayStatusResult, } from "./gateway-send.js";
|
|
8
|
-
export declare const VERSION = "0.13.
|
|
8
|
+
export declare const VERSION = "0.13.9";
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -44880,6 +44880,7 @@ var DoubleRatchet = class _DoubleRatchet {
|
|
|
44880
44880
|
serialize() {
|
|
44881
44881
|
const s2 = this.state;
|
|
44882
44882
|
return JSON.stringify({
|
|
44883
|
+
version: 1,
|
|
44883
44884
|
rootKey: libsodium_wrappers_default.to_hex(s2.rootKey),
|
|
44884
44885
|
sendingChain: s2.sendingChain ? {
|
|
44885
44886
|
chainKey: libsodium_wrappers_default.to_hex(s2.sendingChain.chainKey),
|
|
@@ -44907,33 +44908,59 @@ var DoubleRatchet = class _DoubleRatchet {
|
|
|
44907
44908
|
});
|
|
44908
44909
|
}
|
|
44909
44910
|
static deserialize(json) {
|
|
44910
|
-
|
|
44911
|
-
|
|
44912
|
-
|
|
44913
|
-
|
|
44914
|
-
|
|
44915
|
-
|
|
44916
|
-
|
|
44917
|
-
|
|
44918
|
-
|
|
44919
|
-
|
|
44920
|
-
|
|
44921
|
-
|
|
44922
|
-
|
|
44923
|
-
|
|
44924
|
-
|
|
44925
|
-
|
|
44926
|
-
|
|
44927
|
-
|
|
44928
|
-
|
|
44929
|
-
|
|
44930
|
-
|
|
44931
|
-
|
|
44932
|
-
|
|
44933
|
-
|
|
44934
|
-
|
|
44935
|
-
|
|
44936
|
-
|
|
44911
|
+
let d2;
|
|
44912
|
+
try {
|
|
44913
|
+
d2 = JSON.parse(json);
|
|
44914
|
+
} catch {
|
|
44915
|
+
throw new Error("Ratchet state: corrupt JSON");
|
|
44916
|
+
}
|
|
44917
|
+
if (d2.version !== void 0 && d2.version !== 1) {
|
|
44918
|
+
throw new Error(`Ratchet state version ${d2.version} not supported`);
|
|
44919
|
+
}
|
|
44920
|
+
if (typeof d2.rootKey !== "string") {
|
|
44921
|
+
throw new Error("Ratchet state: missing required field rootKey");
|
|
44922
|
+
}
|
|
44923
|
+
const dhSend = d2.dhSendingKeypair;
|
|
44924
|
+
if (!dhSend || typeof dhSend.publicKey !== "string" || typeof dhSend.privateKey !== "string") {
|
|
44925
|
+
throw new Error("Ratchet state: missing required field dhSendingKeypair");
|
|
44926
|
+
}
|
|
44927
|
+
const idKp = d2.identityKeypair;
|
|
44928
|
+
if (!idKp || typeof idKp.publicKey !== "string" || typeof idKp.privateKey !== "string") {
|
|
44929
|
+
throw new Error("Ratchet state: missing required field identityKeypair");
|
|
44930
|
+
}
|
|
44931
|
+
try {
|
|
44932
|
+
return new _DoubleRatchet({
|
|
44933
|
+
rootKey: libsodium_wrappers_default.from_hex(d2.rootKey),
|
|
44934
|
+
sendingChain: d2.sendingChain ? {
|
|
44935
|
+
chainKey: libsodium_wrappers_default.from_hex(d2.sendingChain.chainKey),
|
|
44936
|
+
messageNumber: d2.sendingChain.messageNumber
|
|
44937
|
+
} : null,
|
|
44938
|
+
receivingChain: d2.receivingChain ? {
|
|
44939
|
+
chainKey: libsodium_wrappers_default.from_hex(d2.receivingChain.chainKey),
|
|
44940
|
+
messageNumber: d2.receivingChain.messageNumber
|
|
44941
|
+
} : null,
|
|
44942
|
+
dhSendingKeypair: {
|
|
44943
|
+
publicKey: libsodium_wrappers_default.from_hex(dhSend.publicKey),
|
|
44944
|
+
privateKey: libsodium_wrappers_default.from_hex(dhSend.privateKey)
|
|
44945
|
+
},
|
|
44946
|
+
dhReceivingPublicKey: d2.dhReceivingPublicKey ? libsodium_wrappers_default.from_hex(d2.dhReceivingPublicKey) : null,
|
|
44947
|
+
identityKeypair: {
|
|
44948
|
+
publicKey: libsodium_wrappers_default.from_hex(idKp.publicKey),
|
|
44949
|
+
privateKey: libsodium_wrappers_default.from_hex(idKp.privateKey)
|
|
44950
|
+
},
|
|
44951
|
+
previousSendingChainLength: d2.previousSendingChainLength,
|
|
44952
|
+
skippedKeys: d2.skippedKeys.map((sk) => ({
|
|
44953
|
+
dhPub: sk.dhPub,
|
|
44954
|
+
n: sk.n,
|
|
44955
|
+
messageKey: libsodium_wrappers_default.from_hex(sk.messageKey)
|
|
44956
|
+
}))
|
|
44957
|
+
});
|
|
44958
|
+
} catch (err) {
|
|
44959
|
+
if (err instanceof Error && err.message.startsWith("Ratchet state")) {
|
|
44960
|
+
throw err;
|
|
44961
|
+
}
|
|
44962
|
+
throw new Error(`Ratchet state: corrupt hex data \u2014 ${err instanceof Error ? err.message : String(err)}`);
|
|
44963
|
+
}
|
|
44937
44964
|
}
|
|
44938
44965
|
};
|
|
44939
44966
|
|
|
@@ -45632,6 +45659,8 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
|
|
|
45632
45659
|
_telemetryReporter = null;
|
|
45633
45660
|
/** Topic ID from the most recent inbound message — used as fallback for replies. */
|
|
45634
45661
|
_lastIncomingTopicId;
|
|
45662
|
+
/** Rate-limit: last resync_request timestamp per conversation (5-min cooldown). */
|
|
45663
|
+
_lastResyncRequest = /* @__PURE__ */ new Map();
|
|
45635
45664
|
// Liveness detection: server sends app-level {"event":"ping"} every 30s.
|
|
45636
45665
|
// We check every 30s; if no data received in 90s (3 missed pings), connection is dead.
|
|
45637
45666
|
static PING_INTERVAL_MS = 3e4;
|
|
@@ -46890,6 +46919,13 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
|
|
|
46890
46919
|
await this._handleDeviceLinked(data.data);
|
|
46891
46920
|
return;
|
|
46892
46921
|
}
|
|
46922
|
+
if (data.event === "resync_request") {
|
|
46923
|
+
await this._handleResyncRequest(data.data);
|
|
46924
|
+
return;
|
|
46925
|
+
}
|
|
46926
|
+
if (data.event === "resync_ack") {
|
|
46927
|
+
return;
|
|
46928
|
+
}
|
|
46893
46929
|
if (data.event === "message") {
|
|
46894
46930
|
try {
|
|
46895
46931
|
await this._handleIncomingMessage(data.data);
|
|
@@ -47295,6 +47331,26 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
|
|
|
47295
47331
|
} catch (restoreErr) {
|
|
47296
47332
|
console.error("[SecureChannel] Ratchet restore failed:", restoreErr);
|
|
47297
47333
|
}
|
|
47334
|
+
const RESYNC_COOLDOWN_MS = 5 * 60 * 1e3;
|
|
47335
|
+
const lastResync = this._lastResyncRequest.get(convId) ?? 0;
|
|
47336
|
+
if (Date.now() - lastResync > RESYNC_COOLDOWN_MS && this._ws && this._persisted) {
|
|
47337
|
+
this._lastResyncRequest.set(convId, Date.now());
|
|
47338
|
+
const idPubHex = this._persisted.identityKeypair.publicKey;
|
|
47339
|
+
const ephPubHex = this._persisted.ephemeralKeypair.publicKey;
|
|
47340
|
+
this._ws.send(
|
|
47341
|
+
JSON.stringify({
|
|
47342
|
+
event: "resync_request",
|
|
47343
|
+
data: {
|
|
47344
|
+
conversation_id: convId,
|
|
47345
|
+
reason: "decrypt_failure",
|
|
47346
|
+
identity_public_key: idPubHex,
|
|
47347
|
+
ephemeral_public_key: ephPubHex
|
|
47348
|
+
}
|
|
47349
|
+
})
|
|
47350
|
+
);
|
|
47351
|
+
console.log(`[SecureChannel] Sent resync_request for conv ${convId.slice(0, 8)}...`);
|
|
47352
|
+
this.emit("resync_requested", { conversationId: convId, reason: "decrypt_failure" });
|
|
47353
|
+
}
|
|
47298
47354
|
return;
|
|
47299
47355
|
}
|
|
47300
47356
|
this._sendAck(msgData.message_id);
|
|
@@ -47619,6 +47675,70 @@ ${messageText}`;
|
|
|
47619
47675
|
this.emit("error", err);
|
|
47620
47676
|
}
|
|
47621
47677
|
}
|
|
47678
|
+
/**
|
|
47679
|
+
* Handle a resync_request from the owner (owner-initiated ratchet re-establishment).
|
|
47680
|
+
* Re-derives shared secret via X3DH as responder, initializes fresh receiver ratchet,
|
|
47681
|
+
* and sends resync_ack back with agent's public keys.
|
|
47682
|
+
*/
|
|
47683
|
+
async _handleResyncRequest(data) {
|
|
47684
|
+
const convId = data.conversation_id;
|
|
47685
|
+
console.log(
|
|
47686
|
+
`[SecureChannel] Received resync_request for conv ${convId.slice(0, 8)}... (reason: ${data.reason ?? "unknown"})`
|
|
47687
|
+
);
|
|
47688
|
+
try {
|
|
47689
|
+
if (!this._persisted) {
|
|
47690
|
+
console.error("[SecureChannel] Cannot handle resync \u2014 no persisted state");
|
|
47691
|
+
return;
|
|
47692
|
+
}
|
|
47693
|
+
const identity = this._persisted.identityKeypair;
|
|
47694
|
+
const ephemeral = this._persisted.ephemeralKeypair;
|
|
47695
|
+
const sharedSecret = performX3DH({
|
|
47696
|
+
myIdentityPrivate: hexToBytes(identity.privateKey),
|
|
47697
|
+
myEphemeralPrivate: hexToBytes(ephemeral.privateKey),
|
|
47698
|
+
theirIdentityPublic: hexToBytes(data.identity_public_key),
|
|
47699
|
+
theirEphemeralPublic: hexToBytes(data.ephemeral_public_key),
|
|
47700
|
+
isInitiator: false
|
|
47701
|
+
});
|
|
47702
|
+
const ratchet = DoubleRatchet.initReceiver(sharedSecret, {
|
|
47703
|
+
publicKey: hexToBytes(identity.publicKey),
|
|
47704
|
+
privateKey: hexToBytes(identity.privateKey),
|
|
47705
|
+
keyType: "ed25519"
|
|
47706
|
+
});
|
|
47707
|
+
const existingSession = this._sessions.get(convId);
|
|
47708
|
+
const ownerDeviceId = data.sender_device_id ?? existingSession?.ownerDeviceId ?? "";
|
|
47709
|
+
this._sessions.set(convId, {
|
|
47710
|
+
ownerDeviceId,
|
|
47711
|
+
ratchet,
|
|
47712
|
+
activated: false
|
|
47713
|
+
// Wait for owner's encrypted session_init
|
|
47714
|
+
});
|
|
47715
|
+
this._persisted.sessions[convId] = {
|
|
47716
|
+
ownerDeviceId,
|
|
47717
|
+
ratchetState: ratchet.serialize(),
|
|
47718
|
+
activated: false
|
|
47719
|
+
};
|
|
47720
|
+
await this._persistState();
|
|
47721
|
+
if (this._ws) {
|
|
47722
|
+
this._ws.send(
|
|
47723
|
+
JSON.stringify({
|
|
47724
|
+
event: "resync_ack",
|
|
47725
|
+
data: {
|
|
47726
|
+
conversation_id: convId,
|
|
47727
|
+
identity_public_key: identity.publicKey,
|
|
47728
|
+
ephemeral_public_key: ephemeral.publicKey
|
|
47729
|
+
}
|
|
47730
|
+
})
|
|
47731
|
+
);
|
|
47732
|
+
}
|
|
47733
|
+
console.log(
|
|
47734
|
+
`[SecureChannel] Resync complete for conv ${convId.slice(0, 8)}... \u2014 waiting for owner session_init`
|
|
47735
|
+
);
|
|
47736
|
+
this.emit("resync_completed", { conversationId: convId });
|
|
47737
|
+
} catch (err) {
|
|
47738
|
+
console.error(`[SecureChannel] Resync failed for conv ${convId.slice(0, 8)}...:`, err);
|
|
47739
|
+
this.emit("error", err);
|
|
47740
|
+
}
|
|
47741
|
+
}
|
|
47622
47742
|
/**
|
|
47623
47743
|
* Handle an incoming room message. Finds the pairwise conversation
|
|
47624
47744
|
* for the sender, decrypts, and emits a room_message event.
|
|
@@ -48248,13 +48368,39 @@ var agentVaultPlugin = {
|
|
|
48248
48368
|
aliases: ["av", "agent-vault"]
|
|
48249
48369
|
},
|
|
48250
48370
|
capabilities: {
|
|
48251
|
-
chatTypes: ["direct"]
|
|
48371
|
+
chatTypes: ["direct", "room"]
|
|
48252
48372
|
},
|
|
48253
48373
|
config: {
|
|
48254
48374
|
listAccountIds,
|
|
48255
48375
|
resolveAccount
|
|
48256
48376
|
},
|
|
48257
48377
|
gateway: {
|
|
48378
|
+
/** Health probe for `openclaw channels status --probe` */
|
|
48379
|
+
probe: async (ctx) => {
|
|
48380
|
+
const accountId = ctx?.accountId ?? "default";
|
|
48381
|
+
const ch = _channels.get(accountId);
|
|
48382
|
+
if (!ch) return { ok: false, status: "disconnected", error: "Channel not started" };
|
|
48383
|
+
const state = ch.state;
|
|
48384
|
+
return {
|
|
48385
|
+
ok: state === "ready",
|
|
48386
|
+
status: state,
|
|
48387
|
+
deviceId: ch.deviceId ?? void 0,
|
|
48388
|
+
sessions: ch.sessionCount
|
|
48389
|
+
};
|
|
48390
|
+
},
|
|
48391
|
+
/** Status for `openclaw health --json` per-channel summary */
|
|
48392
|
+
status: (ctx) => {
|
|
48393
|
+
const accountId = ctx?.accountId ?? "default";
|
|
48394
|
+
const ch = _channels.get(accountId);
|
|
48395
|
+
if (!ch) return { connected: false, status: "not_started" };
|
|
48396
|
+
return {
|
|
48397
|
+
connected: ch.state === "ready",
|
|
48398
|
+
status: ch.state,
|
|
48399
|
+
deviceId: ch.deviceId ?? void 0,
|
|
48400
|
+
sessions: ch.sessionCount,
|
|
48401
|
+
encrypted: true
|
|
48402
|
+
};
|
|
48403
|
+
},
|
|
48258
48404
|
startAccount: async (ctx) => {
|
|
48259
48405
|
const { account, cfg, log, abortSignal } = ctx;
|
|
48260
48406
|
if (!account.configured) {
|
|
@@ -48336,6 +48482,25 @@ var agentVaultPlugin = {
|
|
|
48336
48482
|
} catch (err) {
|
|
48337
48483
|
return { ok: false, error: String(err) };
|
|
48338
48484
|
}
|
|
48485
|
+
},
|
|
48486
|
+
sendMedia: async ({
|
|
48487
|
+
text,
|
|
48488
|
+
mediaUrl,
|
|
48489
|
+
accountId
|
|
48490
|
+
}) => {
|
|
48491
|
+
const resolvedId = accountId ?? "default";
|
|
48492
|
+
const channel = _channels.get(resolvedId);
|
|
48493
|
+
if (!channel) {
|
|
48494
|
+
return { ok: false, error: "AgentVault channel is not connected" };
|
|
48495
|
+
}
|
|
48496
|
+
try {
|
|
48497
|
+
const message = text ? `${text}
|
|
48498
|
+
${mediaUrl}` : mediaUrl;
|
|
48499
|
+
await channel.send(message);
|
|
48500
|
+
return { ok: true };
|
|
48501
|
+
} catch (err) {
|
|
48502
|
+
return { ok: false, error: String(err) };
|
|
48503
|
+
}
|
|
48339
48504
|
}
|
|
48340
48505
|
}
|
|
48341
48506
|
};
|
|
@@ -48468,7 +48633,7 @@ async function checkGateway(options) {
|
|
|
48468
48633
|
}
|
|
48469
48634
|
|
|
48470
48635
|
// src/index.ts
|
|
48471
|
-
var VERSION = "0.13.
|
|
48636
|
+
var VERSION = "0.13.9";
|
|
48472
48637
|
export {
|
|
48473
48638
|
SecureChannel,
|
|
48474
48639
|
VERSION,
|