@agentvault/agentvault 0.17.5 → 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.
- package/dist/cli.js +231 -1
- package/dist/cli.js.map +4 -4
- package/dist/index.js +246 -10
- package/dist/index.js.map +4 -4
- package/dist/openclaw-entry.js +45057 -87
- package/dist/openclaw-entry.js.map +4 -4
- package/openclaw.plugin.json +1 -1
- package/package.json +1 -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
|
}
|
|
@@ -76664,21 +76893,26 @@ function loadSkillsFromDirectory(dir) {
|
|
|
76664
76893
|
const skills = [];
|
|
76665
76894
|
const absDir = resolve2(dir);
|
|
76666
76895
|
if (!existsSync(absDir)) return skills;
|
|
76667
|
-
const
|
|
76668
|
-
|
|
76669
|
-
|
|
76670
|
-
|
|
76671
|
-
|
|
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
|
+
}
|
|
76672
76906
|
}
|
|
76673
76907
|
try {
|
|
76674
76908
|
const entries = readdirSync(absDir, { withFileTypes: true });
|
|
76675
76909
|
for (const entry of entries) {
|
|
76676
|
-
if (entry.
|
|
76910
|
+
if (entry.isFile() && entry.name.endsWith("SKILL.md")) {
|
|
76911
|
+
tryLoad(join4(absDir, entry.name));
|
|
76912
|
+
} else if (entry.isDirectory()) {
|
|
76677
76913
|
const subSkill = join4(absDir, entry.name, "SKILL.md");
|
|
76678
76914
|
if (existsSync(subSkill)) {
|
|
76679
|
-
|
|
76680
|
-
const skill = parseSkillMd(content);
|
|
76681
|
-
if (skill) skills.push(skill);
|
|
76915
|
+
tryLoad(subSkill);
|
|
76682
76916
|
}
|
|
76683
76917
|
}
|
|
76684
76918
|
}
|
|
@@ -77079,6 +77313,7 @@ var init_index = __esm({
|
|
|
77079
77313
|
async "src/index.ts"() {
|
|
77080
77314
|
await init_channel();
|
|
77081
77315
|
init_types();
|
|
77316
|
+
init_credential_store();
|
|
77082
77317
|
init_account_config();
|
|
77083
77318
|
await init_openclaw_plugin();
|
|
77084
77319
|
init_gateway_send();
|
|
@@ -77097,6 +77332,7 @@ var init_index = __esm({
|
|
|
77097
77332
|
await init_index();
|
|
77098
77333
|
export {
|
|
77099
77334
|
AgentVaultMcpServer,
|
|
77335
|
+
CredentialStore,
|
|
77100
77336
|
PolicyEnforcer,
|
|
77101
77337
|
SecureChannel,
|
|
77102
77338
|
VERSION,
|