@agentvault/agentvault 0.13.6 → 0.13.7

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.
@@ -0,0 +1,32 @@
1
+ export interface HttpCallReport {
2
+ method: string;
3
+ url: string;
4
+ statusCode: number;
5
+ latencyMs: number;
6
+ traceId?: string;
7
+ parentSpanId?: string;
8
+ }
9
+ export interface TraceContext {
10
+ traceId: string;
11
+ parentSpanId: string;
12
+ }
13
+ export interface FetchInterceptorOptions {
14
+ onHttpCall: (report: HttpCallReport) => void;
15
+ skipPatterns?: RegExp[];
16
+ }
17
+ /**
18
+ * Install HTTP interceptor using both undici diagnostics channels and
19
+ * globalThis.fetch monkey-patching. Idempotent.
20
+ */
21
+ export declare function installFetchInterceptor(opts: FetchInterceptorOptions): void;
22
+ /**
23
+ * Uninstall all interceptors. Safe to call even if not installed.
24
+ */
25
+ export declare function uninstallFetchInterceptor(): void;
26
+ /**
27
+ * Run an async function with trace context attached via AsyncLocalStorage.
28
+ * Any HTTP calls made within `fn` (via undici or fetch) will include
29
+ * traceId/parentSpanId in their HttpCallReport.
30
+ */
31
+ export declare function runWithTraceContext<T>(ctx: TraceContext, fn: () => T | Promise<T>): Promise<T>;
32
+ //# sourceMappingURL=fetch-interceptor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-interceptor.d.ts","sourceRoot":"","sources":["../src/fetch-interceptor.ts"],"names":[],"mappings":"AAoBA,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED,MAAM,WAAW,YAAY;IAC3B,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,uBAAuB;IACtC,UAAU,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CACzB;AA0CD;;;GAGG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,uBAAuB,GAAG,IAAI,CAmK3E;AAED;;GAEG;AACH,wBAAgB,yBAAyB,IAAI,IAAI,CAkBhD;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,EACnC,GAAG,EAAE,YAAY,EACjB,EAAE,EAAE,MAAM,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,GACvB,OAAO,CAAC,CAAC,CAAC,CAEZ"}
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.11.0";
8
+ export declare const VERSION = "0.13.7";
9
9
  //# sourceMappingURL=index.d.ts.map
package/dist/index.js CHANGED
@@ -45443,7 +45443,7 @@ var TelemetryReporter = class {
45443
45443
  };
45444
45444
 
45445
45445
  // src/state.ts
45446
- import { mkdir, readFile, rm, writeFile } from "node:fs/promises";
45446
+ import { mkdir, readFile, rename, rm, writeFile } from "node:fs/promises";
45447
45447
  import { join } from "node:path";
45448
45448
  var STATE_FILE = "agentvault.json";
45449
45449
  var LEGACY_STATE_FILE = "secure-channel.json";
@@ -45475,6 +45475,44 @@ async function loadState(dataDir) {
45475
45475
  return null;
45476
45476
  }
45477
45477
  }
45478
+ async function isStateValid(dataDir) {
45479
+ try {
45480
+ const filePath = join(dataDir, STATE_FILE);
45481
+ const raw = await readFile(filePath, "utf-8");
45482
+ const parsed = JSON.parse(raw);
45483
+ return !!(parsed && parsed.deviceId && parsed.deviceJwt && parsed.sessions && Object.keys(parsed.sessions).length > 0);
45484
+ } catch {
45485
+ return false;
45486
+ }
45487
+ }
45488
+ async function backupState(dataDir) {
45489
+ const src = join(dataDir, STATE_FILE);
45490
+ const bak = join(dataDir, `${STATE_FILE}.bak`);
45491
+ const tmp = join(dataDir, `${STATE_FILE}.bak.tmp`);
45492
+ try {
45493
+ const data = await readFile(src, "utf-8");
45494
+ await writeFile(tmp, data, "utf-8");
45495
+ await rename(tmp, bak);
45496
+ } catch {
45497
+ }
45498
+ }
45499
+ async function restoreState(dataDir) {
45500
+ const primaryValid = await isStateValid(dataDir);
45501
+ if (primaryValid) return false;
45502
+ const bak = join(dataDir, `${STATE_FILE}.bak`);
45503
+ try {
45504
+ const data = await readFile(bak, "utf-8");
45505
+ const parsed = JSON.parse(data);
45506
+ if (!parsed || !parsed.deviceId || !parsed.deviceJwt || !parsed.sessions || Object.keys(parsed.sessions).length === 0) {
45507
+ return false;
45508
+ }
45509
+ await mkdir(dataDir, { recursive: true });
45510
+ await writeFile(join(dataDir, STATE_FILE), data, "utf-8");
45511
+ return true;
45512
+ } catch {
45513
+ return false;
45514
+ }
45515
+ }
45478
45516
  async function clearState(dataDir) {
45479
45517
  for (const filename of [STATE_FILE, LEGACY_STATE_FILE]) {
45480
45518
  try {
@@ -45629,6 +45667,7 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
45629
45667
  await libsodium_wrappers_default.ready;
45630
45668
  const raw = await loadState(this.config.dataDir);
45631
45669
  if (raw) {
45670
+ await backupState(this.config.dataDir);
45632
45671
  this._persisted = migratePersistedState(raw);
45633
45672
  if (!this._persisted.messageHistory) {
45634
45673
  this._persisted.messageHistory = [];
@@ -45652,6 +45691,30 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
45652
45691
  this._connect();
45653
45692
  return;
45654
45693
  }
45694
+ const restored = await restoreState(this.config.dataDir);
45695
+ if (restored) {
45696
+ console.log("[SecureChannel] Restored state from backup");
45697
+ const restoredRaw = await loadState(this.config.dataDir);
45698
+ if (restoredRaw) {
45699
+ this._persisted = migratePersistedState(restoredRaw);
45700
+ if (!this._persisted.messageHistory) this._persisted.messageHistory = [];
45701
+ this._deviceId = this._persisted.deviceId;
45702
+ this._deviceJwt = this._persisted.deviceJwt;
45703
+ this._primaryConversationId = this._persisted.primaryConversationId;
45704
+ this._fingerprint = this._persisted.fingerprint;
45705
+ for (const [convId, sd] of Object.entries(this._persisted.sessions)) {
45706
+ if (sd.ratchetState) {
45707
+ this._sessions.set(convId, {
45708
+ ownerDeviceId: sd.ownerDeviceId,
45709
+ ratchet: DoubleRatchet.deserialize(sd.ratchetState),
45710
+ activated: sd.activated ?? false
45711
+ });
45712
+ }
45713
+ }
45714
+ this._connect();
45715
+ return;
45716
+ }
45717
+ }
45655
45718
  await this._enroll();
45656
45719
  }
45657
45720
  /**
@@ -45998,7 +46061,9 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
45998
46061
  data: {
45999
46062
  room_id: roomId,
46000
46063
  recipients,
46001
- message_type: messageType
46064
+ message_type: messageType,
46065
+ priority: opts?.priority ?? "normal",
46066
+ metadata: opts?.metadata
46002
46067
  }
46003
46068
  })
46004
46069
  );
@@ -46012,7 +46077,12 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
46012
46077
  "Content-Type": "application/json",
46013
46078
  Authorization: `Bearer ${this._deviceJwt}`
46014
46079
  },
46015
- body: JSON.stringify({ recipients, message_type: messageType })
46080
+ body: JSON.stringify({
46081
+ recipients,
46082
+ message_type: messageType,
46083
+ priority: opts?.priority ?? "normal",
46084
+ metadata: opts?.metadata
46085
+ })
46016
46086
  }
46017
46087
  );
46018
46088
  if (!res.ok) {
@@ -46157,6 +46227,27 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
46157
46227
  }
46158
46228
  );
46159
46229
  }
46230
+ async sendActionConfirmationToRoom(roomId, confirmation) {
46231
+ const envelope = {
46232
+ type: "action_confirmation",
46233
+ action: confirmation.action,
46234
+ status: confirmation.status
46235
+ };
46236
+ if (confirmation.decisionId !== void 0) envelope.decision_id = confirmation.decisionId;
46237
+ if (confirmation.detail !== void 0) envelope.detail = confirmation.detail;
46238
+ const metadata = {
46239
+ action: confirmation.action,
46240
+ status: confirmation.status
46241
+ };
46242
+ if (confirmation.estimated_cost !== void 0) {
46243
+ metadata.estimated_cost = confirmation.estimated_cost;
46244
+ }
46245
+ await this.sendToRoom(roomId, JSON.stringify(envelope), {
46246
+ messageType: "action_confirmation",
46247
+ priority: "high",
46248
+ metadata
46249
+ });
46250
+ }
46160
46251
  _sendHeartbeat() {
46161
46252
  if (this._state !== "ready" || !this._heartbeatCallback) return;
46162
46253
  const status = this._heartbeatCallback();
@@ -46231,10 +46322,52 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
46231
46322
  res.end(JSON.stringify({ ok: false, error: "Missing 'text' field" }));
46232
46323
  return;
46233
46324
  }
46234
- if (parsed.file_path && typeof parsed.file_path === "string") {
46325
+ if (parsed.room_id && typeof parsed.room_id === "string") {
46326
+ await this.sendToRoom(parsed.room_id, text, {
46327
+ messageType: parsed.message_type,
46328
+ priority: parsed.priority,
46329
+ metadata: parsed.metadata
46330
+ });
46331
+ } else if (parsed.file_path && typeof parsed.file_path === "string") {
46235
46332
  await this.sendWithAttachment(text, parsed.file_path, { topicId: parsed.topicId });
46236
46333
  } else {
46237
- await this.send(text, { topicId: parsed.topicId });
46334
+ await this.send(text, {
46335
+ topicId: parsed.topicId,
46336
+ messageType: parsed.message_type,
46337
+ metadata: parsed.metadata
46338
+ });
46339
+ }
46340
+ res.writeHead(200, { "Content-Type": "application/json" });
46341
+ res.end(JSON.stringify({ ok: true }));
46342
+ } catch (err) {
46343
+ res.writeHead(500, { "Content-Type": "application/json" });
46344
+ res.end(JSON.stringify({ ok: false, error: String(err) }));
46345
+ }
46346
+ });
46347
+ } else if (req.method === "POST" && req.url === "/action") {
46348
+ let body = "";
46349
+ req.on("data", (chunk) => {
46350
+ body += chunk.toString();
46351
+ });
46352
+ req.on("end", async () => {
46353
+ try {
46354
+ const parsed = JSON.parse(body);
46355
+ if (!parsed.action || typeof parsed.action !== "string") {
46356
+ res.writeHead(400, { "Content-Type": "application/json" });
46357
+ res.end(JSON.stringify({ ok: false, error: "Missing 'action' field" }));
46358
+ return;
46359
+ }
46360
+ const confirmation = {
46361
+ action: parsed.action,
46362
+ status: parsed.status ?? "completed",
46363
+ decisionId: parsed.decision_id,
46364
+ detail: parsed.detail,
46365
+ estimated_cost: parsed.estimated_cost
46366
+ };
46367
+ if (parsed.room_id && typeof parsed.room_id === "string") {
46368
+ await this.sendActionConfirmationToRoom(parsed.room_id, confirmation);
46369
+ } else {
46370
+ await this.sendActionConfirmation(confirmation);
46238
46371
  }
46239
46372
  res.writeHead(200, { "Content-Type": "application/json" });
46240
46373
  res.end(JSON.stringify({ ok: true }));
@@ -46253,7 +46386,7 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
46253
46386
  }));
46254
46387
  } else {
46255
46388
  res.writeHead(404, { "Content-Type": "application/json" });
46256
- res.end(JSON.stringify({ ok: false, error: "Not found. Use POST /send or GET /status" }));
46389
+ res.end(JSON.stringify({ ok: false, error: "Not found. Use POST /send, POST /action, or GET /status" }));
46257
46390
  }
46258
46391
  });
46259
46392
  this._httpServer.listen(port, "127.0.0.1", () => {
@@ -47047,7 +47180,15 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
47047
47180
  nonce: hexToBytes(msgData.nonce)
47048
47181
  };
47049
47182
  const ratchet = DoubleRatchet.deserialize(channelEntry.session.ratchetState);
47050
- const plaintext = ratchet.decrypt(encryptedMessage);
47183
+ const ratchetSnapshot = channelEntry.session.ratchetState;
47184
+ let a2aPlaintext;
47185
+ try {
47186
+ a2aPlaintext = ratchet.decrypt(encryptedMessage);
47187
+ } catch (decryptErr) {
47188
+ console.error(`[SecureChannel] A2A decrypt failed \u2014 restoring ratchet state:`, decryptErr);
47189
+ channelEntry.session.ratchetState = ratchetSnapshot;
47190
+ return;
47191
+ }
47051
47192
  channelEntry.session.ratchetState = ratchet.serialize();
47052
47193
  if (channelEntry.role === "responder" && !channelEntry.session.activated) {
47053
47194
  channelEntry.session.activated = true;
@@ -47070,7 +47211,7 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
47070
47211
  }
47071
47212
  await this._persistState();
47072
47213
  const a2aMsg = {
47073
- text: plaintext,
47214
+ text: a2aPlaintext,
47074
47215
  fromHubAddress: msgData.from_hub_address || msgData.hub_address || "",
47075
47216
  channelId,
47076
47217
  conversationId: msgData.conversation_id || "",
@@ -47141,7 +47282,19 @@ var SecureChannel = class _SecureChannel extends EventEmitter {
47141
47282
  header_blob: msgData.header_blob,
47142
47283
  ciphertext: msgData.ciphertext
47143
47284
  });
47144
- const plaintext = session.ratchet.decrypt(encrypted);
47285
+ const ratchetSnapshot = session.ratchet.serialize();
47286
+ let plaintext;
47287
+ try {
47288
+ plaintext = session.ratchet.decrypt(encrypted);
47289
+ } catch (decryptErr) {
47290
+ console.error(`[SecureChannel] Decrypt failed for conv ${convId.slice(0, 8)}... \u2014 restoring ratchet:`, decryptErr);
47291
+ try {
47292
+ session.ratchet = DoubleRatchet.deserialize(ratchetSnapshot);
47293
+ } catch (restoreErr) {
47294
+ console.error("[SecureChannel] Ratchet restore failed:", restoreErr);
47295
+ }
47296
+ return;
47297
+ }
47145
47298
  this._sendAck(msgData.message_id);
47146
47299
  if (!session.activated) {
47147
47300
  session.activated = true;
@@ -47529,9 +47682,14 @@ ${messageText}`;
47529
47682
  ciphertext: msgData.ciphertext
47530
47683
  });
47531
47684
  let plaintext;
47685
+ const ratchetSnapshot = session.ratchet.serialize();
47532
47686
  try {
47533
47687
  plaintext = session.ratchet.decrypt(encrypted);
47534
47688
  } catch (decryptErr) {
47689
+ try {
47690
+ session.ratchet = DoubleRatchet.deserialize(ratchetSnapshot);
47691
+ } catch {
47692
+ }
47535
47693
  console.warn(
47536
47694
  `[SecureChannel] Room decrypt failed for conv ${convId.slice(0, 8)}...: ${String(decryptErr)}, re-initializing ratchet`
47537
47695
  );
@@ -47677,7 +47835,20 @@ ${messageText}`;
47677
47835
  header_blob: msg.header_blob,
47678
47836
  ciphertext: msg.ciphertext
47679
47837
  });
47680
- const plaintext = session.ratchet.decrypt(encrypted);
47838
+ const ratchetSnapshot = session.ratchet.serialize();
47839
+ let plaintext;
47840
+ try {
47841
+ plaintext = session.ratchet.decrypt(encrypted);
47842
+ } catch (decryptErr) {
47843
+ console.error(`[SecureChannel] Sync decrypt failed for ${msg.conversation_id.slice(0, 8)}... \u2014 restoring ratchet:`, decryptErr);
47844
+ try {
47845
+ session.ratchet = DoubleRatchet.deserialize(ratchetSnapshot);
47846
+ } catch {
47847
+ }
47848
+ this._persisted.lastMessageTimestamp = msg.created_at;
47849
+ since = msg.created_at;
47850
+ continue;
47851
+ }
47681
47852
  this._sendAck(msg.id);
47682
47853
  if (!session.activated) {
47683
47854
  session.activated = true;
@@ -47712,7 +47883,7 @@ ${messageText}`;
47712
47883
  totalProcessed++;
47713
47884
  } catch (err) {
47714
47885
  console.warn(
47715
- `[SecureChannel] Sync decrypt failed for msg ${msg.id.slice(0, 8)}... in conv ${msg.conversation_id.slice(0, 8)}...: ${String(err)}`
47886
+ `[SecureChannel] Sync failed for msg ${msg.id.slice(0, 8)}... in conv ${msg.conversation_id.slice(0, 8)}...: ${String(err)}`
47716
47887
  );
47717
47888
  this._persisted.lastMessageTimestamp = msg.created_at;
47718
47889
  since = msg.created_at;
@@ -47908,7 +48079,18 @@ ${messageText}`;
47908
48079
  header_blob: msg.header_blob,
47909
48080
  ciphertext: msg.ciphertext
47910
48081
  });
47911
- const plaintext = session.ratchet.decrypt(encrypted);
48082
+ const ratchetSnapshot = session.ratchet.serialize();
48083
+ let plaintext;
48084
+ try {
48085
+ plaintext = session.ratchet.decrypt(encrypted);
48086
+ } catch (decryptErr) {
48087
+ console.error(`[SecureChannel] Room sync decrypt failed for ${msg.conversation_id.slice(0, 8)}... \u2014 restoring ratchet:`, decryptErr);
48088
+ try {
48089
+ session.ratchet = DoubleRatchet.deserialize(ratchetSnapshot);
48090
+ } catch {
48091
+ }
48092
+ continue;
48093
+ }
47912
48094
  if (!session.activated) {
47913
48095
  session.activated = true;
47914
48096
  }
@@ -47988,6 +48170,7 @@ ${messageText}`;
47988
48170
  };
47989
48171
  }
47990
48172
  await saveState(this.config.dataDir, this._persisted);
48173
+ await backupState(this.config.dataDir);
47991
48174
  }
47992
48175
  };
47993
48176
 
@@ -48014,8 +48197,7 @@ function resolveAccount(cfg, accountId) {
48014
48197
  apiUrl: av.apiUrl ?? DEFAULT_API_URL,
48015
48198
  agentName: id,
48016
48199
  httpPort: DEFAULT_HTTP_PORT,
48017
- configured: false,
48018
- inviteToken: ""
48200
+ configured: false
48019
48201
  };
48020
48202
  }
48021
48203
  let httpPort = acct.httpPort;
@@ -48030,8 +48212,7 @@ function resolveAccount(cfg, accountId) {
48030
48212
  apiUrl: acct.apiUrl ?? av.apiUrl ?? DEFAULT_API_URL,
48031
48213
  agentName: acct.agentName ?? id,
48032
48214
  httpPort,
48033
- configured: Boolean(acct.dataDir),
48034
- inviteToken: acct.inviteToken ?? ""
48215
+ configured: Boolean(acct.dataDir)
48035
48216
  };
48036
48217
  }
48037
48218
  return {
@@ -48040,8 +48221,7 @@ function resolveAccount(cfg, accountId) {
48040
48221
  apiUrl: av.apiUrl ?? DEFAULT_API_URL,
48041
48222
  agentName: av.agentName ?? "OpenClaw Agent",
48042
48223
  httpPort: av.httpPort ?? DEFAULT_HTTP_PORT,
48043
- configured: Boolean(av.dataDir),
48044
- inviteToken: av.inviteToken ?? ""
48224
+ configured: Boolean(av.dataDir)
48045
48225
  };
48046
48226
  }
48047
48227
 
@@ -48283,7 +48463,7 @@ async function checkGateway(options) {
48283
48463
  }
48284
48464
 
48285
48465
  // src/index.ts
48286
- var VERSION = "0.11.0";
48466
+ var VERSION = "0.13.7";
48287
48467
  export {
48288
48468
  SecureChannel,
48289
48469
  VERSION,