@agentvault/agentvault 0.17.4 → 0.18.0

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.
Files changed (64) hide show
  1. package/dist/cli.js +250 -22
  2. package/dist/cli.js.map +4 -4
  3. package/dist/index.js +298 -64
  4. package/dist/index.js.map +4 -4
  5. package/dist/openclaw-entry.js +45494 -16312
  6. package/dist/openclaw-entry.js.map +4 -4
  7. package/openclaw.plugin.json +1 -1
  8. package/package.json +1 -1
  9. package/dist/_cp.d.ts +0 -10
  10. package/dist/_cp.d.ts.map +0 -1
  11. package/dist/account-config.d.ts +0 -20
  12. package/dist/account-config.d.ts.map +0 -1
  13. package/dist/channel.d.ts +0 -358
  14. package/dist/channel.d.ts.map +0 -1
  15. package/dist/cli.d.ts +0 -2
  16. package/dist/cli.d.ts.map +0 -1
  17. package/dist/create-agent.d.ts +0 -28
  18. package/dist/create-agent.d.ts.map +0 -1
  19. package/dist/crypto-helpers.d.ts +0 -2
  20. package/dist/crypto-helpers.d.ts.map +0 -1
  21. package/dist/doctor.d.ts +0 -41
  22. package/dist/doctor.d.ts.map +0 -1
  23. package/dist/fetch-interceptor.d.ts +0 -32
  24. package/dist/fetch-interceptor.d.ts.map +0 -1
  25. package/dist/gateway-send.d.ts +0 -98
  26. package/dist/gateway-send.d.ts.map +0 -1
  27. package/dist/http-handlers.d.ts +0 -49
  28. package/dist/http-handlers.d.ts.map +0 -1
  29. package/dist/index.d.ts +0 -25
  30. package/dist/index.d.ts.map +0 -1
  31. package/dist/mcp-handlers.d.ts +0 -26
  32. package/dist/mcp-handlers.d.ts.map +0 -1
  33. package/dist/mcp-proxy-helpers.d.ts +0 -9
  34. package/dist/mcp-proxy-helpers.d.ts.map +0 -1
  35. package/dist/mcp-server.d.ts +0 -90
  36. package/dist/mcp-server.d.ts.map +0 -1
  37. package/dist/openclaw-compat.d.ts +0 -33
  38. package/dist/openclaw-compat.d.ts.map +0 -1
  39. package/dist/openclaw-entry.d.ts +0 -27
  40. package/dist/openclaw-entry.d.ts.map +0 -1
  41. package/dist/openclaw-plugin.d.ts +0 -102
  42. package/dist/openclaw-plugin.d.ts.map +0 -1
  43. package/dist/openclaw-types.d.ts +0 -155
  44. package/dist/openclaw-types.d.ts.map +0 -1
  45. package/dist/policy-enforcer.d.ts +0 -78
  46. package/dist/policy-enforcer.d.ts.map +0 -1
  47. package/dist/setup.d.ts +0 -27
  48. package/dist/setup.d.ts.map +0 -1
  49. package/dist/skill-invoker.d.ts +0 -30
  50. package/dist/skill-invoker.d.ts.map +0 -1
  51. package/dist/skill-manifest.d.ts +0 -25
  52. package/dist/skill-manifest.d.ts.map +0 -1
  53. package/dist/skill-telemetry.d.ts +0 -36
  54. package/dist/skill-telemetry.d.ts.map +0 -1
  55. package/dist/skills-publish.d.ts +0 -8
  56. package/dist/skills-publish.d.ts.map +0 -1
  57. package/dist/state.d.ts +0 -32
  58. package/dist/state.d.ts.map +0 -1
  59. package/dist/transport.d.ts +0 -24
  60. package/dist/transport.d.ts.map +0 -1
  61. package/dist/types.d.ts +0 -379
  62. package/dist/types.d.ts.map +0 -1
  63. package/dist/workspace-handlers.d.ts +0 -62
  64. package/dist/workspace-handlers.d.ts.map +0 -1
package/dist/index.js CHANGED
@@ -46265,6 +46265,123 @@ var init_dist = __esm({
46265
46265
  }
46266
46266
  });
46267
46267
 
46268
+ // src/credential-store.ts
46269
+ var CredentialStore;
46270
+ var init_credential_store = __esm({
46271
+ "src/credential-store.ts"() {
46272
+ "use strict";
46273
+ CredentialStore = class _CredentialStore {
46274
+ /** Map<roomId, Map<credentialKey, RenterCredential>> */
46275
+ _store = /* @__PURE__ */ new Map();
46276
+ /** Seen nonces for replay prevention — bounded per room */
46277
+ _seenNonces = /* @__PURE__ */ new Map();
46278
+ static MAX_NONCES_PER_ROOM = 1e3;
46279
+ constructor() {
46280
+ const purge = () => this.purgeAll();
46281
+ process.on("exit", purge);
46282
+ process.on("SIGINT", () => {
46283
+ purge();
46284
+ process.exit(0);
46285
+ });
46286
+ process.on("SIGTERM", () => {
46287
+ purge();
46288
+ process.exit(0);
46289
+ });
46290
+ }
46291
+ /**
46292
+ * Check if a nonce has been seen (replay prevention).
46293
+ * Returns true if the nonce is new (not a replay), false if seen before.
46294
+ */
46295
+ checkNonce(roomId, nonce) {
46296
+ if (!nonce) return true;
46297
+ let nonces = this._seenNonces.get(roomId);
46298
+ if (!nonces) {
46299
+ nonces = /* @__PURE__ */ new Set();
46300
+ this._seenNonces.set(roomId, nonces);
46301
+ }
46302
+ if (nonces.has(nonce)) return false;
46303
+ nonces.add(nonce);
46304
+ if (nonces.size > _CredentialStore.MAX_NONCES_PER_ROOM) {
46305
+ const iter = nonces.values();
46306
+ for (let i2 = 0; i2 < 100; i2++) {
46307
+ const val = iter.next().value;
46308
+ if (val !== void 0) nonces.delete(val);
46309
+ }
46310
+ }
46311
+ return true;
46312
+ }
46313
+ /** Store a credential for a room. */
46314
+ grant(roomId, credential) {
46315
+ let room = this._store.get(roomId);
46316
+ if (!room) {
46317
+ room = /* @__PURE__ */ new Map();
46318
+ this._store.set(roomId, room);
46319
+ }
46320
+ room.set(credential.key, credential);
46321
+ }
46322
+ /** Revoke a specific credential. */
46323
+ revoke(roomId, key) {
46324
+ const room = this._store.get(roomId);
46325
+ if (!room) return false;
46326
+ return room.delete(key);
46327
+ }
46328
+ /** Revoke all credentials for a room. */
46329
+ revokeAll(roomId) {
46330
+ this._store.delete(roomId);
46331
+ }
46332
+ /** Get a credential value. */
46333
+ get(roomId, key) {
46334
+ return this._store.get(roomId)?.get(key);
46335
+ }
46336
+ /** Get all credentials for a room (values included — only for agent context injection). */
46337
+ getAll(roomId) {
46338
+ const room = this._store.get(roomId);
46339
+ if (!room) return [];
46340
+ return Array.from(room.values());
46341
+ }
46342
+ /** Get credential info without values (safe for logging). */
46343
+ getInfo(roomId) {
46344
+ const room = this._store.get(roomId);
46345
+ if (!room) return [];
46346
+ return Array.from(room.values()).map((c2) => ({
46347
+ key: c2.key,
46348
+ type: c2.type,
46349
+ scope: c2.scope,
46350
+ grantedAt: c2.grantedAt
46351
+ }));
46352
+ }
46353
+ /** Check if a specific credential exists. */
46354
+ has(roomId, key) {
46355
+ return this._store.get(roomId)?.has(key) ?? false;
46356
+ }
46357
+ /** Get credential count for a room. */
46358
+ count(roomId) {
46359
+ return this._store.get(roomId)?.size ?? 0;
46360
+ }
46361
+ /** Purge all credentials for a room (rental end). */
46362
+ purgeForRoom(roomId) {
46363
+ this._store.delete(roomId);
46364
+ this._seenNonces.delete(roomId);
46365
+ }
46366
+ /** Purge everything (process exit). */
46367
+ purgeAll() {
46368
+ this._store.clear();
46369
+ this._seenNonces.clear();
46370
+ }
46371
+ /** Get a map of credential key → value for context injection. */
46372
+ getCredentialMap(roomId) {
46373
+ const room = this._store.get(roomId);
46374
+ if (!room) return {};
46375
+ const result = {};
46376
+ for (const [key, cred] of room) {
46377
+ result[key] = cred.value;
46378
+ }
46379
+ return result;
46380
+ }
46381
+ };
46382
+ }
46383
+ });
46384
+
46268
46385
  // src/crypto-helpers.ts
46269
46386
  var init_crypto_helpers = __esm({
46270
46387
  async "src/crypto-helpers.ts"() {
@@ -46934,12 +47051,13 @@ function migratePersistedState(raw) {
46934
47051
  messageHistory: []
46935
47052
  };
46936
47053
  }
46937
- var ROOM_AGENT_TYPES, POLL_INTERVAL_MS, RECONNECT_BASE_MS, RECONNECT_MAX_MS, PENDING_POLL_INTERVAL_MS, SecureChannel;
47054
+ var ROOM_AGENT_TYPES, CREDENTIAL_MESSAGE_TYPES, POLL_INTERVAL_MS, RECONNECT_BASE_MS, RECONNECT_MAX_MS, PENDING_POLL_INTERVAL_MS, SecureChannel;
46938
47055
  var init_channel = __esm({
46939
47056
  async "src/channel.ts"() {
46940
47057
  "use strict";
46941
47058
  await init_libsodium_wrappers();
46942
47059
  await init_dist();
47060
+ init_credential_store();
46943
47061
  await init_crypto_helpers();
46944
47062
  await init_state();
46945
47063
  init_transport2();
@@ -46950,6 +47068,11 @@ var init_channel = __esm({
46950
47068
  "decision_response",
46951
47069
  "artifact_share"
46952
47070
  ]);
47071
+ CREDENTIAL_MESSAGE_TYPES = /* @__PURE__ */ new Set([
47072
+ "credential_grant",
47073
+ "credential_revoke",
47074
+ "credential_request"
47075
+ ]);
46953
47076
  POLL_INTERVAL_MS = 6e3;
46954
47077
  RECONNECT_BASE_MS = 1e3;
46955
47078
  RECONNECT_MAX_MS = 3e4;
@@ -46992,6 +47115,8 @@ var init_channel = __esm({
46992
47115
  _senderKeyChains = /* @__PURE__ */ new Map();
46993
47116
  /** Sender Key peer state — peer chains per room for decryption */
46994
47117
  _senderKeyStates = /* @__PURE__ */ new Map();
47118
+ /** In-memory credential store for renter-provided credentials (never persisted). */
47119
+ _credentialStore = new CredentialStore();
46995
47120
  /** Queued A2A messages for responder channels not yet activated (no first initiator message received). */
46996
47121
  _a2aPendingQueue = {};
46997
47122
  /** Dedup buffer for A2A message IDs (prevents double-delivery via direct + Redis) */
@@ -49778,6 +49903,14 @@ ${messageText}`;
49778
49903
  messageType = "message";
49779
49904
  messageText = plaintext;
49780
49905
  }
49906
+ if (CREDENTIAL_MESSAGE_TYPES.has(messageType)) {
49907
+ this._handleCredentialMessage(msgData.room_id, messageType, messageText, msgData.message_id);
49908
+ if (msgData.created_at && this._persisted) {
49909
+ this._persisted.lastMessageTimestamp = msgData.created_at;
49910
+ }
49911
+ await this._persistState();
49912
+ return;
49913
+ }
49781
49914
  if (!ROOM_AGENT_TYPES.has(messageType)) {
49782
49915
  return;
49783
49916
  }
@@ -49814,6 +49947,94 @@ ${messageText}`;
49814
49947
  console.error("[SecureChannel] onMessage callback error:", err);
49815
49948
  });
49816
49949
  }
49950
+ /**
49951
+ * Handle credential protocol messages (grant, revoke, request).
49952
+ * These are intercepted before reaching the agent's onMessage callback.
49953
+ */
49954
+ _handleCredentialMessage(roomId, messageType, plaintext, messageId) {
49955
+ try {
49956
+ const payload = JSON.parse(plaintext);
49957
+ if (messageType === "credential_grant") {
49958
+ const grant = payload;
49959
+ if (grant.nonce && !this._credentialStore.checkNonce(roomId, grant.nonce)) {
49960
+ console.warn(`[SecureChannel] Credential grant replay detected for room ${roomId.slice(0, 8)}..., ignoring`);
49961
+ return;
49962
+ }
49963
+ const keys = [];
49964
+ for (const cred of grant.credentials || []) {
49965
+ this._credentialStore.grant(roomId, {
49966
+ key: cred.key,
49967
+ value: cred.value,
49968
+ type: cred.type,
49969
+ scope: cred.scope,
49970
+ grantedAt: grant.timestamp || (/* @__PURE__ */ new Date()).toISOString(),
49971
+ agreementId: grant.agreement_id,
49972
+ roomId
49973
+ });
49974
+ keys.push(cred.key);
49975
+ }
49976
+ console.log(
49977
+ `[SecureChannel] Credentials granted for room ${roomId.slice(0, 8)}...: ${keys.join(", ")} (${keys.length} keys)`
49978
+ );
49979
+ this._sendCredentialAck(roomId, grant.agreement_id, keys, "stored");
49980
+ this.emit("credentials_granted", { roomId, keys, agreementId: grant.agreement_id });
49981
+ } else if (messageType === "credential_revoke") {
49982
+ const revoke = payload;
49983
+ const revoked = [];
49984
+ for (const key of revoke.credential_keys || []) {
49985
+ if (this._credentialStore.revoke(roomId, key)) {
49986
+ revoked.push(key);
49987
+ }
49988
+ }
49989
+ console.log(
49990
+ `[SecureChannel] Credentials revoked for room ${roomId.slice(0, 8)}...: ${revoked.join(", ")} (reason: ${revoke.reason || "none"})`
49991
+ );
49992
+ this._sendCredentialAck(roomId, revoke.agreement_id, revoked, "revoked");
49993
+ this.emit("credentials_revoked", { roomId, keys: revoked, agreementId: revoke.agreement_id });
49994
+ }
49995
+ } catch (err) {
49996
+ console.error("[SecureChannel] Error handling credential message:", err);
49997
+ }
49998
+ if (messageId) {
49999
+ this._sendAck(messageId);
50000
+ }
50001
+ }
50002
+ /**
50003
+ * Send a credential_ack back to a room.
50004
+ */
50005
+ _sendCredentialAck(roomId, agreementId, keys, ackStatus) {
50006
+ const ack = JSON.stringify({
50007
+ type: "credential_ack",
50008
+ agreement_id: agreementId,
50009
+ acknowledged_keys: keys,
50010
+ status: ackStatus,
50011
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
50012
+ });
50013
+ this.sendToRoom(roomId, ack, { messageType: "credential_ack" }).catch((err) => {
50014
+ console.warn("[SecureChannel] Failed to send credential ACK:", err);
50015
+ });
50016
+ }
50017
+ // --- Public credential accessors ---
50018
+ /** Get a specific renter credential for a room. */
50019
+ getCredential(roomId, key) {
50020
+ return this._credentialStore.get(roomId, key);
50021
+ }
50022
+ /** Get all renter credentials for a room (includes values — for agent context). */
50023
+ getCredentials(roomId) {
50024
+ return this._credentialStore.getAll(roomId);
50025
+ }
50026
+ /** Get credential key→value map for a room (for context injection). */
50027
+ getCredentialMap(roomId) {
50028
+ return this._credentialStore.getCredentialMap(roomId);
50029
+ }
50030
+ /** Check if a specific credential exists for a room. */
50031
+ hasCredential(roomId, key) {
50032
+ return this._credentialStore.has(roomId, key);
50033
+ }
50034
+ /** Purge all credentials for a room (call on rental end). */
50035
+ purgeRoomCredentials(roomId) {
50036
+ this._credentialStore.purgeForRoom(roomId);
50037
+ }
49817
50038
  /**
49818
50039
  * Find the pairwise conversation ID for a given sender in a room.
49819
50040
  */
@@ -49976,6 +50197,14 @@ ${messageText}`;
49976
50197
  messageType = "message";
49977
50198
  messageText = plaintext;
49978
50199
  }
50200
+ if (CREDENTIAL_MESSAGE_TYPES.has(messageType)) {
50201
+ this._handleCredentialMessage(msgData.room_id, messageType, messageText, msgData.message_id);
50202
+ if (msgData.created_at && this._persisted) {
50203
+ this._persisted.lastMessageTimestamp = msgData.created_at;
50204
+ }
50205
+ await this._persistState();
50206
+ return;
50207
+ }
49979
50208
  if (!ROOM_AGENT_TYPES.has(messageType)) {
49980
50209
  return;
49981
50210
  }
@@ -51007,6 +51236,20 @@ var init_fetch_interceptor = __esm({
51007
51236
  }
51008
51237
  });
51009
51238
 
51239
+ // src/openclaw-entry.ts
51240
+ var isUsingManagedRoutes;
51241
+ var init_openclaw_entry = __esm({
51242
+ "src/openclaw-entry.ts"() {
51243
+ "use strict";
51244
+ init_account_config();
51245
+ init_fetch_interceptor();
51246
+ init_http_handlers();
51247
+ init_openclaw_compat();
51248
+ init_types();
51249
+ isUsingManagedRoutes = false;
51250
+ }
51251
+ });
51252
+
51010
51253
  // ../../node_modules/zod/v3/helpers/util.js
51011
51254
  var util, objectUtil, ZodParsedType, getParsedType;
51012
51255
  var init_util = __esm({
@@ -76507,6 +76750,44 @@ var init_mcp_server2 = __esm({
76507
76750
  }
76508
76751
  });
76509
76752
 
76753
+ // src/mcp-handlers.ts
76754
+ function createMcpHandler(mcpServer, basePath = "/mcp") {
76755
+ return (req, res, next) => {
76756
+ const url2 = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
76757
+ const pathname = url2.pathname;
76758
+ if (!pathname.startsWith(basePath)) {
76759
+ if (next) next();
76760
+ return;
76761
+ }
76762
+ if (!mcpServer) {
76763
+ res.writeHead(503, { "Content-Type": "application/json" });
76764
+ res.end(JSON.stringify({ error: "MCP server not initialized" }));
76765
+ return;
76766
+ }
76767
+ mcpServer.handleRequest(req, res).catch((err) => {
76768
+ console.error("[MCP] Request handling error:", err);
76769
+ if (!res.headersSent) {
76770
+ res.writeHead(500, { "Content-Type": "application/json" });
76771
+ res.end(JSON.stringify({ error: "Internal MCP error" }));
76772
+ }
76773
+ });
76774
+ };
76775
+ }
76776
+ function getMcpStatus(mcpServer) {
76777
+ if (!mcpServer) {
76778
+ return { mcp_enabled: false, mcp_skills_count: 0 };
76779
+ }
76780
+ return {
76781
+ mcp_enabled: true,
76782
+ mcp_skills_count: mcpServer.skillCount
76783
+ };
76784
+ }
76785
+ var init_mcp_handlers = __esm({
76786
+ "src/mcp-handlers.ts"() {
76787
+ "use strict";
76788
+ }
76789
+ });
76790
+
76510
76791
  // src/skill-manifest.ts
76511
76792
  import { readFileSync, existsSync, readdirSync } from "node:fs";
76512
76793
  import { resolve as resolve2, join as join4 } from "node:path";
@@ -76612,21 +76893,26 @@ function loadSkillsFromDirectory(dir) {
76612
76893
  const skills = [];
76613
76894
  const absDir = resolve2(dir);
76614
76895
  if (!existsSync(absDir)) return skills;
76615
- const rootSkill = join4(absDir, "SKILL.md");
76616
- if (existsSync(rootSkill)) {
76617
- const content = readFileSync(rootSkill, "utf-8");
76618
- const skill = parseSkillMd(content);
76619
- if (skill) skills.push(skill);
76896
+ const seen = /* @__PURE__ */ new Set();
76897
+ function tryLoad(filePath) {
76898
+ if (seen.has(filePath)) return;
76899
+ seen.add(filePath);
76900
+ try {
76901
+ const content = readFileSync(filePath, "utf-8");
76902
+ const skill = parseSkillMd(content);
76903
+ if (skill) skills.push(skill);
76904
+ } catch {
76905
+ }
76620
76906
  }
76621
76907
  try {
76622
76908
  const entries = readdirSync(absDir, { withFileTypes: true });
76623
76909
  for (const entry of entries) {
76624
- if (entry.isDirectory()) {
76910
+ if (entry.isFile() && entry.name.endsWith("SKILL.md")) {
76911
+ tryLoad(join4(absDir, entry.name));
76912
+ } else if (entry.isDirectory()) {
76625
76913
  const subSkill = join4(absDir, entry.name, "SKILL.md");
76626
76914
  if (existsSync(subSkill)) {
76627
- const content = readFileSync(subSkill, "utf-8");
76628
- const skill = parseSkillMd(content);
76629
- if (skill) skills.push(skill);
76915
+ tryLoad(subSkill);
76630
76916
  }
76631
76917
  }
76632
76918
  }
@@ -76674,60 +76960,6 @@ var init_skill_manifest = __esm({
76674
76960
  }
76675
76961
  });
76676
76962
 
76677
- // src/openclaw-entry.ts
76678
- var isUsingManagedRoutes;
76679
- var init_openclaw_entry = __esm({
76680
- "src/openclaw-entry.ts"() {
76681
- "use strict";
76682
- init_account_config();
76683
- init_fetch_interceptor();
76684
- init_http_handlers();
76685
- init_openclaw_compat();
76686
- init_types();
76687
- init_mcp_server2();
76688
- init_skill_manifest();
76689
- isUsingManagedRoutes = false;
76690
- }
76691
- });
76692
-
76693
- // src/mcp-handlers.ts
76694
- function createMcpHandler(mcpServer, basePath = "/mcp") {
76695
- return (req, res, next) => {
76696
- const url2 = new URL(req.url ?? "/", `http://${req.headers.host ?? "localhost"}`);
76697
- const pathname = url2.pathname;
76698
- if (!pathname.startsWith(basePath)) {
76699
- if (next) next();
76700
- return;
76701
- }
76702
- if (!mcpServer) {
76703
- res.writeHead(503, { "Content-Type": "application/json" });
76704
- res.end(JSON.stringify({ error: "MCP server not initialized" }));
76705
- return;
76706
- }
76707
- mcpServer.handleRequest(req, res).catch((err) => {
76708
- console.error("[MCP] Request handling error:", err);
76709
- if (!res.headersSent) {
76710
- res.writeHead(500, { "Content-Type": "application/json" });
76711
- res.end(JSON.stringify({ error: "Internal MCP error" }));
76712
- }
76713
- });
76714
- };
76715
- }
76716
- function getMcpStatus(mcpServer) {
76717
- if (!mcpServer) {
76718
- return { mcp_enabled: false, mcp_skills_count: 0 };
76719
- }
76720
- return {
76721
- mcp_enabled: true,
76722
- mcp_skills_count: mcpServer.skillCount
76723
- };
76724
- }
76725
- var init_mcp_handlers = __esm({
76726
- "src/mcp-handlers.ts"() {
76727
- "use strict";
76728
- }
76729
- });
76730
-
76731
76963
  // src/skill-invoker.ts
76732
76964
  async function invokeSkill(opts, handler) {
76733
76965
  const start = Date.now();
@@ -77081,6 +77313,7 @@ var init_index = __esm({
77081
77313
  async "src/index.ts"() {
77082
77314
  await init_channel();
77083
77315
  init_types();
77316
+ init_credential_store();
77084
77317
  init_account_config();
77085
77318
  await init_openclaw_plugin();
77086
77319
  init_gateway_send();
@@ -77099,6 +77332,7 @@ var init_index = __esm({
77099
77332
  await init_index();
77100
77333
  export {
77101
77334
  AgentVaultMcpServer,
77335
+ CredentialStore,
77102
77336
  PolicyEnforcer,
77103
77337
  SecureChannel,
77104
77338
  VERSION,