@agentvault/agentvault 0.23.1 → 0.23.3
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 +29 -12
- package/dist/channel.d.ts.map +1 -1
- package/dist/cli.js +176 -129
- package/dist/cli.js.map +2 -2
- package/dist/index.js +177 -130
- package/dist/index.js.map +2 -2
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -64267,145 +64267,140 @@ var init_channel = __esm({
|
|
|
64267
64267
|
}
|
|
64268
64268
|
const raw = await loadState(this.config.dataDir);
|
|
64269
64269
|
if (raw) {
|
|
64270
|
-
await
|
|
64271
|
-
this.
|
|
64272
|
-
|
|
64273
|
-
|
|
64274
|
-
|
|
64275
|
-
|
|
64276
|
-
|
|
64277
|
-
|
|
64278
|
-
|
|
64279
|
-
|
|
64280
|
-
|
|
64281
|
-
|
|
64282
|
-
}
|
|
64283
|
-
|
|
64284
|
-
|
|
64285
|
-
|
|
64286
|
-
|
|
64287
|
-
|
|
64288
|
-
|
|
64289
|
-
|
|
64290
|
-
|
|
64291
|
-
|
|
64292
|
-
|
|
64293
|
-
|
|
64294
|
-
|
|
64295
|
-
|
|
64296
|
-
|
|
64297
|
-
|
|
64298
|
-
|
|
64299
|
-
|
|
64300
|
-
|
|
64301
|
-
|
|
64270
|
+
await this._hydrateFromPersisted(raw);
|
|
64271
|
+
this._connect();
|
|
64272
|
+
return;
|
|
64273
|
+
}
|
|
64274
|
+
const restored = await restoreState(this.config.dataDir);
|
|
64275
|
+
if (restored) {
|
|
64276
|
+
console.log("[SecureChannel] Restored state from backup");
|
|
64277
|
+
const restoredRaw = await loadState(this.config.dataDir);
|
|
64278
|
+
if (restoredRaw) {
|
|
64279
|
+
await this._hydrateFromPersisted(restoredRaw);
|
|
64280
|
+
this._connect();
|
|
64281
|
+
return;
|
|
64282
|
+
}
|
|
64283
|
+
}
|
|
64284
|
+
await this._enroll();
|
|
64285
|
+
}
|
|
64286
|
+
/**
|
|
64287
|
+
* Hydrate all in-memory state from persisted creds. The single source of
|
|
64288
|
+
* truth for both the primary boot and the .bak-restore boot, so the two can
|
|
64289
|
+
* never drift (the drift is what caused #416: the backup branch used to skip
|
|
64290
|
+
* MLS group loading and dropped owner MLS DMs). Callers invoke _connect()
|
|
64291
|
+
* after this resolves.
|
|
64292
|
+
*/
|
|
64293
|
+
async _hydrateFromPersisted(raw) {
|
|
64294
|
+
await backupState(this.config.dataDir);
|
|
64295
|
+
this._persisted = migratePersistedState(raw);
|
|
64296
|
+
if (!this._persisted.messageHistory) {
|
|
64297
|
+
this._persisted.messageHistory = [];
|
|
64298
|
+
}
|
|
64299
|
+
this._deviceId = this._persisted.deviceId;
|
|
64300
|
+
this._deviceJwt = this._persisted.deviceJwt;
|
|
64301
|
+
this._primaryConversationId = this._persisted.primaryConversationId;
|
|
64302
|
+
this._fingerprint = this._persisted.fingerprint;
|
|
64303
|
+
this._lastInboundRoomId = this._persisted.lastInboundRoomId;
|
|
64304
|
+
if (this._persisted.seenMessageIds) {
|
|
64305
|
+
this._seenMessageIds = new Set(this._persisted.seenMessageIds.slice(-_SecureChannel.SEEN_MSG_MAX));
|
|
64306
|
+
}
|
|
64307
|
+
if (this._persisted.seenA2AMessageIds) {
|
|
64308
|
+
this._a2aSeenMessageIds = new Set(this._persisted.seenA2AMessageIds.slice(-_SecureChannel.A2A_SEEN_MAX));
|
|
64309
|
+
}
|
|
64310
|
+
if (this._persisted?.rooms) {
|
|
64311
|
+
const roomConvIds = /* @__PURE__ */ new Set();
|
|
64312
|
+
for (const room of Object.values(this._persisted.rooms)) {
|
|
64313
|
+
for (const cid of room.conversationIds || []) {
|
|
64314
|
+
roomConvIds.add(cid);
|
|
64302
64315
|
}
|
|
64303
64316
|
}
|
|
64304
|
-
|
|
64305
|
-
|
|
64306
|
-
|
|
64307
|
-
|
|
64308
|
-
|
|
64309
|
-
this._sessions.set(convId, {
|
|
64310
|
-
ownerDeviceId: sessionData.ownerDeviceId,
|
|
64311
|
-
ratchet,
|
|
64312
|
-
activated: sessionData.activated ?? false,
|
|
64313
|
-
epoch: sessionData.epoch
|
|
64314
|
-
});
|
|
64317
|
+
let cleanedCount = 0;
|
|
64318
|
+
for (const cid of roomConvIds) {
|
|
64319
|
+
if (this._persisted.sessions[cid]) {
|
|
64320
|
+
delete this._persisted.sessions[cid];
|
|
64321
|
+
cleanedCount++;
|
|
64315
64322
|
}
|
|
64316
64323
|
}
|
|
64317
|
-
if (
|
|
64318
|
-
|
|
64319
|
-
console.log(`[SecureChannel] Restored ${this._sessionGroupIds.size} conversation\u2192group mappings`);
|
|
64324
|
+
if (cleanedCount > 0) {
|
|
64325
|
+
console.log(`[SecureChannel] Cleaned ${cleanedCount} stale DR room sessions`);
|
|
64320
64326
|
}
|
|
64321
|
-
|
|
64322
|
-
|
|
64323
|
-
|
|
64324
|
-
|
|
64325
|
-
|
|
64326
|
-
|
|
64327
|
-
|
|
64328
|
-
|
|
64329
|
-
|
|
64330
|
-
|
|
64331
|
-
|
|
64332
|
-
|
|
64333
|
-
console.warn(`[SecureChannel] Failed to restore MLS state for room ${roomId.slice(0, 8)}:`, mlsErr);
|
|
64334
|
-
}
|
|
64335
|
-
}
|
|
64336
|
-
}
|
|
64327
|
+
}
|
|
64328
|
+
for (const [convId, sessionData] of Object.entries(
|
|
64329
|
+
this._persisted.sessions
|
|
64330
|
+
)) {
|
|
64331
|
+
if (sessionData.ratchetState) {
|
|
64332
|
+
const ratchet = DoubleRatchet.deserialize(sessionData.ratchetState);
|
|
64333
|
+
this._sessions.set(convId, {
|
|
64334
|
+
ownerDeviceId: sessionData.ownerDeviceId,
|
|
64335
|
+
ratchet,
|
|
64336
|
+
activated: sessionData.activated ?? false,
|
|
64337
|
+
epoch: sessionData.epoch
|
|
64338
|
+
});
|
|
64337
64339
|
}
|
|
64338
|
-
|
|
64339
|
-
|
|
64340
|
+
}
|
|
64341
|
+
if (this._persisted.conversationGroupIds) {
|
|
64342
|
+
this._sessionGroupIds = new Map(Object.entries(this._persisted.conversationGroupIds));
|
|
64343
|
+
console.log(`[SecureChannel] Restored ${this._sessionGroupIds.size} conversation\u2192group mappings`);
|
|
64344
|
+
}
|
|
64345
|
+
if (this._persisted.rooms) {
|
|
64346
|
+
for (const [roomId, room] of Object.entries(this._persisted.rooms)) {
|
|
64347
|
+
const mlsGroupId = room.mlsGroupId;
|
|
64348
|
+
if (mlsGroupId) {
|
|
64340
64349
|
try {
|
|
64341
|
-
const mlsState = await loadMlsState(this.config.dataDir,
|
|
64350
|
+
const mlsState = await loadMlsState(this.config.dataDir, mlsGroupId);
|
|
64342
64351
|
if (mlsState) {
|
|
64343
64352
|
const mgr = new MLSGroupManager();
|
|
64344
64353
|
mgr.importState(JSON.parse(mlsState));
|
|
64345
|
-
this._mlsGroups.set(
|
|
64354
|
+
this._mlsGroups.set(roomId, mgr);
|
|
64346
64355
|
}
|
|
64347
64356
|
} catch (mlsErr) {
|
|
64348
|
-
console.warn(`[SecureChannel] Failed to restore MLS state for
|
|
64357
|
+
console.warn(`[SecureChannel] Failed to restore MLS state for room ${roomId.slice(0, 8)}:`, mlsErr);
|
|
64349
64358
|
}
|
|
64350
64359
|
}
|
|
64351
64360
|
}
|
|
64352
|
-
|
|
64353
|
-
|
|
64361
|
+
}
|
|
64362
|
+
for (const [convId, entry] of Object.entries(this._persisted.mlsConversations ?? {})) {
|
|
64363
|
+
if (entry.mlsGroupId) {
|
|
64354
64364
|
try {
|
|
64355
|
-
const
|
|
64356
|
-
if (
|
|
64365
|
+
const mlsState = await loadMlsState(this.config.dataDir, entry.mlsGroupId);
|
|
64366
|
+
if (mlsState) {
|
|
64357
64367
|
const mgr = new MLSGroupManager();
|
|
64358
|
-
mgr.importState(JSON.parse(
|
|
64359
|
-
this._mlsGroups.set(`
|
|
64360
|
-
console.log(`[SecureChannel] Loaded shared MLS group for ${gid.slice(0, 8)} (epoch=${mgr.epoch})`);
|
|
64368
|
+
mgr.importState(JSON.parse(mlsState));
|
|
64369
|
+
this._mlsGroups.set(`conv:${convId}`, mgr);
|
|
64361
64370
|
}
|
|
64362
|
-
} catch (
|
|
64363
|
-
console.warn(`[SecureChannel] Failed to
|
|
64371
|
+
} catch (mlsErr) {
|
|
64372
|
+
console.warn(`[SecureChannel] Failed to restore MLS state for conv ${convId.slice(0, 8)}:`, mlsErr);
|
|
64364
64373
|
}
|
|
64365
64374
|
}
|
|
64366
|
-
|
|
64367
|
-
|
|
64368
|
-
|
|
64369
|
-
|
|
64370
|
-
|
|
64371
|
-
|
|
64372
|
-
|
|
64373
|
-
|
|
64374
|
-
|
|
64375
|
-
|
|
64376
|
-
console.warn(`[SecureChannel] Failed to restore MLS state for A2A ${channelId.slice(0, 8)}:`, mlsErr);
|
|
64377
|
-
}
|
|
64375
|
+
}
|
|
64376
|
+
for (const [gid, entry] of Object.entries(this._persisted.mlsGroups ?? {})) {
|
|
64377
|
+
if (!entry.mlsGroupId) continue;
|
|
64378
|
+
try {
|
|
64379
|
+
const stateJson = await loadMlsState(this.config.dataDir, entry.mlsGroupId);
|
|
64380
|
+
if (stateJson) {
|
|
64381
|
+
const mgr = new MLSGroupManager();
|
|
64382
|
+
mgr.importState(JSON.parse(stateJson));
|
|
64383
|
+
this._mlsGroups.set(`1to1-group:${gid}`, mgr);
|
|
64384
|
+
console.log(`[SecureChannel] Loaded shared MLS group for ${gid.slice(0, 8)} (epoch=${mgr.epoch})`);
|
|
64378
64385
|
}
|
|
64386
|
+
} catch (loadErr) {
|
|
64387
|
+
console.warn(`[SecureChannel] Failed to load shared MLS group ${gid.slice(0, 8)}:`, loadErr);
|
|
64379
64388
|
}
|
|
64380
|
-
this._connect();
|
|
64381
|
-
return;
|
|
64382
64389
|
}
|
|
64383
|
-
const
|
|
64384
|
-
|
|
64385
|
-
|
|
64386
|
-
|
|
64387
|
-
|
|
64388
|
-
|
|
64389
|
-
|
|
64390
|
-
|
|
64391
|
-
this._deviceJwt = this._persisted.deviceJwt;
|
|
64392
|
-
this._primaryConversationId = this._persisted.primaryConversationId;
|
|
64393
|
-
this._fingerprint = this._persisted.fingerprint;
|
|
64394
|
-
for (const [convId, sd] of Object.entries(this._persisted.sessions)) {
|
|
64395
|
-
if (sd.ratchetState) {
|
|
64396
|
-
this._sessions.set(convId, {
|
|
64397
|
-
ownerDeviceId: sd.ownerDeviceId,
|
|
64398
|
-
ratchet: DoubleRatchet.deserialize(sd.ratchetState),
|
|
64399
|
-
activated: sd.activated ?? false,
|
|
64400
|
-
epoch: sd.epoch
|
|
64401
|
-
});
|
|
64390
|
+
for (const [channelId, entry] of Object.entries(this._persisted.a2aChannels ?? {})) {
|
|
64391
|
+
if (entry.mlsGroupId) {
|
|
64392
|
+
try {
|
|
64393
|
+
const mlsState = await loadMlsState(this.config.dataDir, entry.mlsGroupId);
|
|
64394
|
+
if (mlsState) {
|
|
64395
|
+
const mgr = new MLSGroupManager();
|
|
64396
|
+
mgr.importState(JSON.parse(mlsState));
|
|
64397
|
+
this._mlsGroups.set(`a2a:${channelId}`, mgr);
|
|
64402
64398
|
}
|
|
64399
|
+
} catch (mlsErr) {
|
|
64400
|
+
console.warn(`[SecureChannel] Failed to restore MLS state for A2A ${channelId.slice(0, 8)}:`, mlsErr);
|
|
64403
64401
|
}
|
|
64404
|
-
this._connect();
|
|
64405
|
-
return;
|
|
64406
64402
|
}
|
|
64407
64403
|
}
|
|
64408
|
-
await this._enroll();
|
|
64409
64404
|
}
|
|
64410
64405
|
/**
|
|
64411
64406
|
* Fetch scan rules from the server and load them into the ScanEngine.
|
|
@@ -64745,7 +64740,7 @@ var init_channel = __esm({
|
|
|
64745
64740
|
*/
|
|
64746
64741
|
sendActivitySpan(spanData) {
|
|
64747
64742
|
if (!this._ws || this._ws.readyState !== WebSocket.OPEN) return;
|
|
64748
|
-
const pluginVersion = true ? "0.23.
|
|
64743
|
+
const pluginVersion = true ? "0.23.3" : "0.0.0-dev";
|
|
64749
64744
|
const agentName = this.config.agentName ?? "Agent";
|
|
64750
64745
|
const resource = {
|
|
64751
64746
|
"service.name": "agentvault-agent",
|
|
@@ -66362,7 +66357,7 @@ var init_channel = __esm({
|
|
|
66362
66357
|
agentVersion: this.config.agentVersion ?? "0.0.0",
|
|
66363
66358
|
// __AV_VERSION__ is injected by esbuild from package.json at build time.
|
|
66364
66359
|
// Falls back to "0.0.0-dev" in non-bundled contexts (tests).
|
|
66365
|
-
pluginVersion: true ? "0.23.
|
|
66360
|
+
pluginVersion: true ? "0.23.3" : "0.0.0-dev"
|
|
66366
66361
|
});
|
|
66367
66362
|
this._telemetryReporter.startAutoFlush(3e4);
|
|
66368
66363
|
}
|
|
@@ -66438,7 +66433,7 @@ var init_channel = __esm({
|
|
|
66438
66433
|
return;
|
|
66439
66434
|
}
|
|
66440
66435
|
if (data.event === "device_revoked") {
|
|
66441
|
-
this._handleDeviceRevoked();
|
|
66436
|
+
await this._handleDeviceRevoked();
|
|
66442
66437
|
return;
|
|
66443
66438
|
}
|
|
66444
66439
|
if (data.event === "device_linked") {
|
|
@@ -66672,7 +66667,7 @@ var init_channel = __esm({
|
|
|
66672
66667
|
agentVersion: this.config.agentVersion ?? "0.0.0",
|
|
66673
66668
|
// __AV_VERSION__ is injected by esbuild from package.json at build time.
|
|
66674
66669
|
// Falls back to "0.0.0-dev" in non-bundled contexts (tests).
|
|
66675
|
-
pluginVersion: true ? "0.23.
|
|
66670
|
+
pluginVersion: true ? "0.23.3" : "0.0.0-dev"
|
|
66676
66671
|
});
|
|
66677
66672
|
this._telemetryReporter.startAutoFlush(3e4);
|
|
66678
66673
|
}
|
|
@@ -69837,22 +69832,74 @@ ${messageText}`;
|
|
|
69837
69832
|
this._setState("error");
|
|
69838
69833
|
this.emit("error", err);
|
|
69839
69834
|
}
|
|
69835
|
+
// Phase 2 — rolling-window timestamps of device_revoked self-heal reconnects,
|
|
69836
|
+
// used as a war cap so a takeover war or a server status/WS inconsistency can't
|
|
69837
|
+
// thrash forever.
|
|
69838
|
+
_revokeRecoveries = [];
|
|
69839
|
+
static REVOKE_RECOVERY_MAX = 3;
|
|
69840
|
+
static REVOKE_RECOVERY_WINDOW_MS = 12e4;
|
|
69840
69841
|
/**
|
|
69841
|
-
* Handle a WS `device_revoked` event.
|
|
69842
|
-
* attachLifecycle stops the channel — but does NOT delete credentials.
|
|
69842
|
+
* Handle a WS `device_revoked` event.
|
|
69843
69843
|
*
|
|
69844
|
-
*
|
|
69845
|
-
* session-takeover of a device that is still ACTIVE
|
|
69846
|
-
* text even reads "or another session has taken over"
|
|
69847
|
-
*
|
|
69848
|
-
*
|
|
69849
|
-
*
|
|
69850
|
-
*
|
|
69851
|
-
*
|
|
69852
|
-
*
|
|
69853
|
-
*
|
|
69844
|
+
* The signal is ambiguous: the server sends it both for a genuine owner revoke
|
|
69845
|
+
* AND for a transient/racy session-takeover of a device that is still ACTIVE
|
|
69846
|
+
* (the error text even reads "or another session has taken over" — loopita's
|
|
69847
|
+
* case, where the device stayed ACTIVE on the server). So we do NOT terminate
|
|
69848
|
+
* blindly. We ask the PUBLIC /devices/{id}/status endpoint (no JWT needed, so
|
|
69849
|
+
* it answers even when our device JWT is being rejected):
|
|
69850
|
+
* - ACTIVE -> reconnect in place (transient); stay online.
|
|
69851
|
+
* - non-ACTIVE -> terminal (genuinely revoked; operator must re-enroll).
|
|
69852
|
+
* - unreachable/429 -> reconnect (inconclusive; a network blip shouldn't
|
|
69853
|
+
* permanently kill a healthy agent — the WS is down too,
|
|
69854
|
+
* so normal backoff handles it, and the war cap bounds
|
|
69855
|
+
* thrash if the device really is dead).
|
|
69856
|
+
*
|
|
69857
|
+
* A rolling-window cap (REVOKE_RECOVERY_MAX self-heals per WINDOW_MS) gives up
|
|
69858
|
+
* (terminal) on a repeating loop. Never clears credentials in any branch —
|
|
69859
|
+
* re-enrollment, which SHOULD wipe creds, goes through setup --force /
|
|
69860
|
+
* _forceReEnroll in start().
|
|
69854
69861
|
*/
|
|
69855
|
-
_handleDeviceRevoked() {
|
|
69862
|
+
async _handleDeviceRevoked() {
|
|
69863
|
+
const now = Date.now();
|
|
69864
|
+
this._revokeRecoveries = this._revokeRecoveries.filter(
|
|
69865
|
+
(t2) => now - t2 < _SecureChannel.REVOKE_RECOVERY_WINDOW_MS
|
|
69866
|
+
);
|
|
69867
|
+
if (this._revokeRecoveries.length >= _SecureChannel.REVOKE_RECOVERY_MAX) {
|
|
69868
|
+
console.warn(
|
|
69869
|
+
"[SecureChannel] device_revoked self-healed too many times in a short window \u2014 giving up (terminal)"
|
|
69870
|
+
);
|
|
69871
|
+
this._handleError(new Error("Device was revoked"));
|
|
69872
|
+
return;
|
|
69873
|
+
}
|
|
69874
|
+
const deviceId = this._deviceId ?? this._persisted?.deviceId;
|
|
69875
|
+
if (!deviceId) {
|
|
69876
|
+
this._handleError(new Error("Device was revoked"));
|
|
69877
|
+
return;
|
|
69878
|
+
}
|
|
69879
|
+
let reconnect;
|
|
69880
|
+
try {
|
|
69881
|
+
const status = await pollDeviceStatus(this.config.apiUrl, deviceId);
|
|
69882
|
+
reconnect = status.rateLimited === true || status.status === "ACTIVE";
|
|
69883
|
+
if (!reconnect) {
|
|
69884
|
+
console.warn(
|
|
69885
|
+
`[SecureChannel] device_revoked confirmed by server (status=${status.status}) \u2014 terminal`
|
|
69886
|
+
);
|
|
69887
|
+
}
|
|
69888
|
+
} catch (err) {
|
|
69889
|
+
console.warn(
|
|
69890
|
+
"[SecureChannel] device_revoked status check failed; reconnecting (inconclusive):",
|
|
69891
|
+
err
|
|
69892
|
+
);
|
|
69893
|
+
reconnect = true;
|
|
69894
|
+
}
|
|
69895
|
+
if (reconnect) {
|
|
69896
|
+
this._revokeRecoveries.push(now);
|
|
69897
|
+
console.log(
|
|
69898
|
+
"[SecureChannel] device_revoked but device not confirmed dead \u2014 reconnecting (self-heal)"
|
|
69899
|
+
);
|
|
69900
|
+
this._scheduleReconnect();
|
|
69901
|
+
return;
|
|
69902
|
+
}
|
|
69856
69903
|
this._handleError(new Error("Device was revoked"));
|
|
69857
69904
|
}
|
|
69858
69905
|
/**
|
|
@@ -96803,7 +96850,7 @@ var init_index = __esm({
|
|
|
96803
96850
|
init_skill_invoker();
|
|
96804
96851
|
await init_skill_telemetry();
|
|
96805
96852
|
await init_policy_enforcer();
|
|
96806
|
-
VERSION = true ? "0.23.
|
|
96853
|
+
VERSION = true ? "0.23.3" : "0.0.0-dev";
|
|
96807
96854
|
}
|
|
96808
96855
|
});
|
|
96809
96856
|
await init_index();
|