agentbnb 3.1.6 → 4.0.1

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 (37) hide show
  1. package/README.md +117 -86
  2. package/dist/{card-IE5UV5QX.js → card-4XH4AOTE.js} +11 -4
  3. package/dist/chunk-3MJT4PZG.js +50 -0
  4. package/dist/{conduct-IEQ567ET.js → chunk-3UKAVIMC.js} +70 -31
  5. package/dist/chunk-5AH3CMOX.js +62 -0
  6. package/dist/{chunk-IZZ4FP45.js → chunk-6K5WUVF3.js} +33 -166
  7. package/dist/chunk-75OC6E4F.js +33 -0
  8. package/dist/chunk-DVAS2443.js +63 -0
  9. package/dist/{chunk-XA63SD4T.js → chunk-FNKBHBYK.js} +3 -0
  10. package/dist/{websocket-client-5TIQDYQ4.js → chunk-JOY533UH.js} +38 -4
  11. package/dist/chunk-KJG2UJV5.js +83 -0
  12. package/dist/chunk-M3G5NR2Z.js +90 -0
  13. package/dist/{chunk-7OACGAFD.js → chunk-MQKYGY5I.js} +63 -24
  14. package/dist/chunk-ODBGCCEH.js +358 -0
  15. package/dist/{chunk-QSPWE5AE.js → chunk-Q7HRI666.js} +9 -6
  16. package/dist/chunk-QJEOCKVF.js +148 -0
  17. package/dist/{chunk-3Y36WQDV.js → chunk-QT7TEVNV.js} +14 -2
  18. package/dist/{chunk-UOGDK2S2.js → chunk-TLU7ALCZ.js} +1 -1
  19. package/dist/{chunk-QHQPXO67.js → chunk-XQHN6ITI.js} +1 -58
  20. package/dist/cli/index.js +2734 -850
  21. package/dist/client-BTPIFY7E.js +10 -0
  22. package/dist/conduct-CW62HBPT.js +52 -0
  23. package/dist/conduct-FXLVGKD5.js +19 -0
  24. package/dist/{conductor-mode-IO45PWMI.js → conductor-mode-3JS4VWCR.js} +16 -7
  25. package/dist/execute-EXOITLHN.js +10 -0
  26. package/dist/index.d.ts +1005 -916
  27. package/dist/index.js +516 -120
  28. package/dist/{peers-G36URZYB.js → peers-K7FSHPN3.js} +2 -1
  29. package/dist/request-CNZ3XIVX.js +196 -0
  30. package/dist/serve-skill-SUOGUM7N.js +104 -0
  31. package/dist/server-2LWHL24P.js +295 -0
  32. package/dist/types-FGBUZ3QV.js +18 -0
  33. package/dist/websocket-client-6IIDGXKB.js +7 -0
  34. package/package.json +4 -1
  35. package/dist/chunk-BEI5MTNZ.js +0 -91
  36. package/dist/cli/index.d.ts +0 -1
  37. package/dist/execute-SWWEHV2K.js +0 -9
@@ -1,16 +1,22 @@
1
+ import {
2
+ fetchRemoteCards,
3
+ searchCards
4
+ } from "./chunk-QJEOCKVF.js";
5
+ import {
6
+ requestCapability
7
+ } from "./chunk-KJG2UJV5.js";
1
8
  import {
2
9
  findPeer
3
- } from "./chunk-BEI5MTNZ.js";
10
+ } from "./chunk-5AH3CMOX.js";
4
11
  import {
5
12
  getBalance,
6
13
  holdEscrow,
7
14
  releaseEscrow,
8
- settleEscrow,
9
- signEscrowReceipt
10
- } from "./chunk-QHQPXO67.js";
15
+ settleEscrow
16
+ } from "./chunk-XQHN6ITI.js";
11
17
  import {
12
18
  AgentBnBError
13
- } from "./chunk-XA63SD4T.js";
19
+ } from "./chunk-FNKBHBYK.js";
14
20
 
15
21
  // src/autonomy/tiers.ts
16
22
  import { randomUUID } from "crypto";
@@ -93,116 +99,10 @@ var BudgetManager = class {
93
99
  }
94
100
  };
95
101
 
96
- // src/registry/matcher.ts
97
- function searchCards(db, query, filters = {}) {
98
- const words = query.trim().split(/\s+/).map((w) => w.replace(/["*^{}():]/g, "")).filter((w) => w.length > 0);
99
- if (words.length === 0) return [];
100
- const ftsQuery = words.map((w) => `"${w}"`).join(" OR ");
101
- const conditions = [];
102
- const params = [ftsQuery];
103
- if (filters.level !== void 0) {
104
- conditions.push(`json_extract(cc.data, '$.level') = ?`);
105
- params.push(filters.level);
106
- }
107
- if (filters.online !== void 0) {
108
- conditions.push(`json_extract(cc.data, '$.availability.online') = ?`);
109
- params.push(filters.online ? 1 : 0);
110
- }
111
- const whereClause = conditions.length > 0 ? `AND ${conditions.join(" AND ")}` : "";
112
- const sql = `
113
- SELECT cc.data
114
- FROM capability_cards cc
115
- JOIN cards_fts ON cc.rowid = cards_fts.rowid
116
- WHERE cards_fts MATCH ?
117
- ${whereClause}
118
- ORDER BY bm25(cards_fts)
119
- LIMIT 50
120
- `;
121
- const stmt = db.prepare(sql);
122
- const rows = stmt.all(...params);
123
- const results = rows.map((row) => JSON.parse(row.data));
124
- if (filters.apis_used && filters.apis_used.length > 0) {
125
- const requiredApis = filters.apis_used;
126
- return results.filter((card) => {
127
- const cardApis = card.metadata?.apis_used ?? [];
128
- return requiredApis.every((api) => cardApis.includes(api));
129
- });
130
- }
131
- return results;
132
- }
133
- function filterCards(db, filters) {
134
- const conditions = [];
135
- const params = [];
136
- if (filters.level !== void 0) {
137
- conditions.push(`json_extract(data, '$.level') = ?`);
138
- params.push(filters.level);
139
- }
140
- if (filters.online !== void 0) {
141
- conditions.push(`json_extract(data, '$.availability.online') = ?`);
142
- params.push(filters.online ? 1 : 0);
143
- }
144
- const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
145
- const sql = `SELECT data FROM capability_cards ${whereClause}`;
146
- const stmt = db.prepare(sql);
147
- const rows = stmt.all(...params);
148
- return rows.map((row) => JSON.parse(row.data));
149
- }
150
-
151
- // src/gateway/client.ts
152
- import { randomUUID as randomUUID2 } from "crypto";
153
- async function requestCapability(opts) {
154
- const { gatewayUrl, token, cardId, params = {}, timeoutMs = 3e4, escrowReceipt, identity } = opts;
155
- const id = randomUUID2();
156
- const payload = {
157
- jsonrpc: "2.0",
158
- id,
159
- method: "capability.execute",
160
- params: {
161
- card_id: cardId,
162
- ...params,
163
- ...escrowReceipt ? { escrow_receipt: escrowReceipt } : {}
164
- }
165
- };
166
- const headers = { "Content-Type": "application/json" };
167
- if (identity) {
168
- const signature = signEscrowReceipt(payload, identity.privateKey);
169
- headers["X-Agent-Id"] = identity.agentId;
170
- headers["X-Agent-Public-Key"] = identity.publicKey;
171
- headers["X-Agent-Signature"] = signature;
172
- } else if (token) {
173
- headers["Authorization"] = `Bearer ${token}`;
174
- }
175
- const controller = new AbortController();
176
- const timer = setTimeout(() => controller.abort(), timeoutMs);
177
- let response;
178
- try {
179
- response = await fetch(`${gatewayUrl}/rpc`, {
180
- method: "POST",
181
- headers,
182
- body: JSON.stringify(payload),
183
- signal: controller.signal
184
- });
185
- } catch (err) {
186
- clearTimeout(timer);
187
- const isTimeout = err instanceof Error && err.name === "AbortError";
188
- throw new AgentBnBError(
189
- isTimeout ? "Request timed out" : `Network error: ${String(err)}`,
190
- isTimeout ? "TIMEOUT" : "NETWORK_ERROR"
191
- );
192
- } finally {
193
- clearTimeout(timer);
194
- }
195
- const body = await response.json();
196
- if (body.error) {
197
- throw new AgentBnBError(body.error.message, `RPC_ERROR_${body.error.code}`);
198
- }
199
- return body.result;
200
- }
201
-
202
102
  // src/autonomy/pending-requests.ts
203
- import { randomUUID as randomUUID3 } from "crypto";
103
+ import { randomUUID as randomUUID2 } from "crypto";
204
104
  function createPendingRequest(db, opts) {
205
- const id = randomUUID3();
105
+ const id = randomUUID2();
206
106
  const now = (/* @__PURE__ */ new Date()).toISOString();
207
107
  const paramsJson = opts.params !== void 0 ? JSON.stringify(opts.params) : null;
208
108
  db.prepare(`
@@ -277,6 +177,7 @@ var AutoRequestor = class {
277
177
  creditDb;
278
178
  autonomyConfig;
279
179
  budgetManager;
180
+ registryUrl;
280
181
  /**
281
182
  * Creates a new AutoRequestor.
282
183
  *
@@ -288,6 +189,7 @@ var AutoRequestor = class {
288
189
  this.creditDb = opts.creditDb;
289
190
  this.autonomyConfig = opts.autonomyConfig;
290
191
  this.budgetManager = opts.budgetManager;
192
+ this.registryUrl = opts.registryUrl;
291
193
  }
292
194
  /**
293
195
  * Executes an autonomous capability request.
@@ -308,7 +210,23 @@ var AutoRequestor = class {
308
210
  * @returns The result of the auto-request attempt.
309
211
  */
310
212
  async requestWithAutonomy(need) {
311
- const cards = searchCards(this.registryDb, need.query, { online: true });
213
+ let cards = searchCards(this.registryDb, need.query, { online: true });
214
+ if (cards.length === 0 && this.registryUrl) {
215
+ try {
216
+ cards = await fetchRemoteCards(this.registryUrl, { q: need.query, online: true });
217
+ } catch {
218
+ insertAuditEvent(this.registryDb, {
219
+ type: "auto_request_failed",
220
+ card_id: "none",
221
+ skill_id: "none",
222
+ tier_invoked: 3,
223
+ credits: 0,
224
+ peer: "none",
225
+ reason: `Remote registry fallback failed for query "${need.query}"`
226
+ });
227
+ cards = [];
228
+ }
229
+ }
312
230
  const candidates = [];
313
231
  for (const card of cards) {
314
232
  const cardAsV2 = card;
@@ -429,65 +347,14 @@ var AutoRequestor = class {
429
347
  }
430
348
  };
431
349
 
432
- // src/utils/interpolation.ts
433
- function resolvePath(obj, path) {
434
- const segments = path.replace(/\[(\d+)\]/g, ".$1").split(".").filter((s) => s.length > 0);
435
- let current = obj;
436
- for (const segment of segments) {
437
- if (current === null || current === void 0) {
438
- return void 0;
439
- }
440
- if (typeof current !== "object") {
441
- return void 0;
442
- }
443
- current = current[segment];
444
- }
445
- return current;
446
- }
447
- function interpolate(template, context) {
448
- return template.replace(/\$\{([^}]+)\}/g, (_match, expression) => {
449
- const resolved = resolvePath(context, expression.trim());
450
- if (resolved === void 0 || resolved === null) {
451
- return "";
452
- }
453
- if (typeof resolved === "object") {
454
- return JSON.stringify(resolved);
455
- }
456
- return String(resolved);
457
- });
458
- }
459
- function interpolateObject(obj, context) {
460
- const result = {};
461
- for (const [key, value] of Object.entries(obj)) {
462
- result[key] = interpolateValue(value, context);
463
- }
464
- return result;
465
- }
466
- function interpolateValue(value, context) {
467
- if (typeof value === "string") {
468
- return interpolate(value, context);
469
- }
470
- if (Array.isArray(value)) {
471
- return value.map((item) => interpolateValue(item, context));
472
- }
473
- if (value !== null && typeof value === "object") {
474
- return interpolateObject(value, context);
475
- }
476
- return value;
477
- }
478
-
479
350
  export {
480
351
  DEFAULT_AUTONOMY_CONFIG,
481
352
  getAutonomyTier,
482
353
  insertAuditEvent,
483
354
  DEFAULT_BUDGET_CONFIG,
484
355
  BudgetManager,
485
- searchCards,
486
- filterCards,
487
- requestCapability,
488
356
  listPendingRequests,
489
357
  resolvePendingRequest,
490
358
  scorePeers,
491
- AutoRequestor,
492
- interpolateObject
359
+ AutoRequestor
493
360
  };
@@ -0,0 +1,33 @@
1
+ // src/cli/config.ts
2
+ import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
3
+ import { homedir } from "os";
4
+ import { join } from "path";
5
+ function getConfigDir() {
6
+ return process.env["AGENTBNB_DIR"] ?? join(homedir(), ".agentbnb");
7
+ }
8
+ function getConfigPath() {
9
+ return join(getConfigDir(), "config.json");
10
+ }
11
+ function loadConfig() {
12
+ const configPath = getConfigPath();
13
+ if (!existsSync(configPath)) return null;
14
+ try {
15
+ const raw = readFileSync(configPath, "utf-8");
16
+ return JSON.parse(raw);
17
+ } catch {
18
+ return null;
19
+ }
20
+ }
21
+ function saveConfig(config) {
22
+ const dir = getConfigDir();
23
+ if (!existsSync(dir)) {
24
+ mkdirSync(dir, { recursive: true });
25
+ }
26
+ writeFileSync(getConfigPath(), JSON.stringify(config, null, 2), "utf-8");
27
+ }
28
+
29
+ export {
30
+ getConfigDir,
31
+ loadConfig,
32
+ saveConfig
33
+ };
@@ -0,0 +1,63 @@
1
+ import {
2
+ AgentBnBError
3
+ } from "./chunk-FNKBHBYK.js";
4
+
5
+ // src/credit/signing.ts
6
+ import { generateKeyPairSync, sign, verify, createPublicKey, createPrivateKey } from "crypto";
7
+ import { writeFileSync, readFileSync, existsSync, chmodSync } from "fs";
8
+ import { join } from "path";
9
+ function generateKeyPair() {
10
+ const { publicKey, privateKey } = generateKeyPairSync("ed25519", {
11
+ publicKeyEncoding: { type: "spki", format: "der" },
12
+ privateKeyEncoding: { type: "pkcs8", format: "der" }
13
+ });
14
+ return {
15
+ publicKey: Buffer.from(publicKey),
16
+ privateKey: Buffer.from(privateKey)
17
+ };
18
+ }
19
+ function saveKeyPair(configDir, keys) {
20
+ const privatePath = join(configDir, "private.key");
21
+ const publicPath = join(configDir, "public.key");
22
+ writeFileSync(privatePath, keys.privateKey);
23
+ chmodSync(privatePath, 384);
24
+ writeFileSync(publicPath, keys.publicKey);
25
+ }
26
+ function loadKeyPair(configDir) {
27
+ const privatePath = join(configDir, "private.key");
28
+ const publicPath = join(configDir, "public.key");
29
+ if (!existsSync(privatePath) || !existsSync(publicPath)) {
30
+ throw new AgentBnBError("Keypair not found. Run `agentbnb init` to generate one.", "KEYPAIR_NOT_FOUND");
31
+ }
32
+ return {
33
+ publicKey: readFileSync(publicPath),
34
+ privateKey: readFileSync(privatePath)
35
+ };
36
+ }
37
+ function canonicalJson(data) {
38
+ return JSON.stringify(data, Object.keys(data).sort());
39
+ }
40
+ function signEscrowReceipt(data, privateKey) {
41
+ const message = Buffer.from(canonicalJson(data), "utf-8");
42
+ const keyObject = createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
43
+ const signature = sign(null, message, keyObject);
44
+ return signature.toString("base64url");
45
+ }
46
+ function verifyEscrowReceipt(data, signature, publicKey) {
47
+ try {
48
+ const message = Buffer.from(canonicalJson(data), "utf-8");
49
+ const keyObject = createPublicKey({ key: publicKey, format: "der", type: "spki" });
50
+ const sigBuffer = Buffer.from(signature, "base64url");
51
+ return verify(null, message, keyObject, sigBuffer);
52
+ } catch {
53
+ return false;
54
+ }
55
+ }
56
+
57
+ export {
58
+ generateKeyPair,
59
+ saveKeyPair,
60
+ loadKeyPair,
61
+ signEscrowReceipt,
62
+ verifyEscrowReceipt
63
+ };
@@ -123,7 +123,10 @@ var AgentBnBError = class extends Error {
123
123
  };
124
124
 
125
125
  export {
126
+ IOSchemaSchema,
127
+ PoweredBySchema,
126
128
  CapabilityCardSchema,
129
+ SkillSchema,
127
130
  CapabilityCardV2Schema,
128
131
  AnyCardSchema,
129
132
  AgentBnBError
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  RelayMessageSchema
3
- } from "./chunk-3Y36WQDV.js";
3
+ } from "./chunk-QT7TEVNV.js";
4
4
 
5
5
  // src/relay/websocket-client.ts
6
6
  import WebSocket from "ws";
@@ -36,7 +36,8 @@ var RelayClient = class {
36
36
  type: "register",
37
37
  owner: this.opts.owner,
38
38
  token: this.opts.token,
39
- card: this.opts.card
39
+ card: this.opts.card,
40
+ ...this.opts.cards && this.opts.cards.length > 0 ? { cards: this.opts.cards } : {}
40
41
  });
41
42
  });
42
43
  this.ws.on("message", (raw) => {
@@ -101,13 +102,13 @@ var RelayClient = class {
101
102
  throw new Error("Not connected to registry relay");
102
103
  }
103
104
  const id = randomUUID();
104
- const timeoutMs = opts.timeoutMs ?? 3e4;
105
+ const timeoutMs = opts.timeoutMs ?? 3e5;
105
106
  return new Promise((resolve, reject) => {
106
107
  const timeout = setTimeout(() => {
107
108
  this.pendingRequests.delete(id);
108
109
  reject(new Error("Relay request timeout"));
109
110
  }, timeoutMs);
110
- this.pendingRequests.set(id, { resolve, reject, timeout });
111
+ this.pendingRequests.set(id, { resolve, reject, timeout, timeoutMs, onProgress: opts.onProgress });
111
112
  this.send({
112
113
  type: "relay_request",
113
114
  id,
@@ -120,6 +121,22 @@ var RelayClient = class {
120
121
  });
121
122
  });
122
123
  }
124
+ /**
125
+ * Send a relay_progress message to the relay server for a given request.
126
+ * Used by the onRequest handler to forward SkillExecutor progress updates
127
+ * to the requesting agent so it can reset its timeout window.
128
+ *
129
+ * @param requestId - The relay request ID to associate progress with.
130
+ * @param info - Progress details (step, total, message).
131
+ */
132
+ sendProgress(requestId, info) {
133
+ this.send({
134
+ type: "relay_progress",
135
+ id: requestId,
136
+ progress: Math.round(info.step / info.total * 100),
137
+ message: info.message
138
+ });
139
+ }
123
140
  /** Whether the client is connected and registered */
124
141
  get isConnected() {
125
142
  return this.ws !== null && this.ws.readyState === WebSocket.OPEN && this.registered;
@@ -166,6 +183,9 @@ var RelayClient = class {
166
183
  case "error":
167
184
  this.handleError(msg);
168
185
  break;
186
+ case "relay_progress":
187
+ this.handleProgress(msg);
188
+ break;
169
189
  default:
170
190
  break;
171
191
  }
@@ -211,6 +231,19 @@ var RelayClient = class {
211
231
  }
212
232
  }
213
233
  }
234
+ handleProgress(msg) {
235
+ const pending = this.pendingRequests.get(msg.id);
236
+ if (!pending) return;
237
+ clearTimeout(pending.timeout);
238
+ const newTimeout = setTimeout(() => {
239
+ this.pendingRequests.delete(msg.id);
240
+ pending.reject(new Error("Relay request timeout"));
241
+ }, pending.timeoutMs);
242
+ pending.timeout = newTimeout;
243
+ if (pending.onProgress) {
244
+ pending.onProgress({ id: msg.id, progress: msg.progress, message: msg.message });
245
+ }
246
+ }
214
247
  send(msg) {
215
248
  if (this.ws && this.ws.readyState === WebSocket.OPEN) {
216
249
  this.ws.send(JSON.stringify(msg));
@@ -270,6 +303,7 @@ var RelayClient = class {
270
303
  }, delay);
271
304
  }
272
305
  };
306
+
273
307
  export {
274
308
  RelayClient
275
309
  };
@@ -0,0 +1,83 @@
1
+ import {
2
+ signEscrowReceipt
3
+ } from "./chunk-DVAS2443.js";
4
+ import {
5
+ AgentBnBError
6
+ } from "./chunk-FNKBHBYK.js";
7
+
8
+ // src/gateway/client.ts
9
+ import { randomUUID } from "crypto";
10
+ async function requestCapability(opts) {
11
+ const { gatewayUrl, token, cardId, params = {}, timeoutMs = 3e5, escrowReceipt, identity } = opts;
12
+ const id = randomUUID();
13
+ const payload = {
14
+ jsonrpc: "2.0",
15
+ id,
16
+ method: "capability.execute",
17
+ params: {
18
+ card_id: cardId,
19
+ ...params,
20
+ ...escrowReceipt ? { escrow_receipt: escrowReceipt } : {}
21
+ }
22
+ };
23
+ const headers = { "Content-Type": "application/json" };
24
+ if (identity) {
25
+ const signature = signEscrowReceipt(payload, identity.privateKey);
26
+ headers["X-Agent-Id"] = identity.agentId;
27
+ headers["X-Agent-Public-Key"] = identity.publicKey;
28
+ headers["X-Agent-Signature"] = signature;
29
+ } else if (token) {
30
+ headers["Authorization"] = `Bearer ${token}`;
31
+ }
32
+ const controller = new AbortController();
33
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
34
+ let response;
35
+ try {
36
+ response = await fetch(`${gatewayUrl}/rpc`, {
37
+ method: "POST",
38
+ headers,
39
+ body: JSON.stringify(payload),
40
+ signal: controller.signal
41
+ });
42
+ } catch (err) {
43
+ clearTimeout(timer);
44
+ const isTimeout = err instanceof Error && err.name === "AbortError";
45
+ throw new AgentBnBError(
46
+ isTimeout ? "Request timed out" : `Network error: ${String(err)}`,
47
+ isTimeout ? "TIMEOUT" : "NETWORK_ERROR"
48
+ );
49
+ } finally {
50
+ clearTimeout(timer);
51
+ }
52
+ const body = await response.json();
53
+ if (body.error) {
54
+ throw new AgentBnBError(body.error.message, `RPC_ERROR_${body.error.code}`);
55
+ }
56
+ return body.result;
57
+ }
58
+ async function requestViaRelay(relay, opts) {
59
+ try {
60
+ return await relay.request({
61
+ targetOwner: opts.targetOwner,
62
+ cardId: opts.cardId,
63
+ skillId: opts.skillId,
64
+ params: opts.params ?? {},
65
+ escrowReceipt: opts.escrowReceipt,
66
+ timeoutMs: opts.timeoutMs
67
+ });
68
+ } catch (err) {
69
+ const message = err instanceof Error ? err.message : String(err);
70
+ if (message.includes("timeout")) {
71
+ throw new AgentBnBError(message, "TIMEOUT");
72
+ }
73
+ if (message.includes("offline")) {
74
+ throw new AgentBnBError(message, "AGENT_OFFLINE");
75
+ }
76
+ throw new AgentBnBError(message, "RELAY_ERROR");
77
+ }
78
+ }
79
+
80
+ export {
81
+ requestCapability,
82
+ requestViaRelay
83
+ };
@@ -0,0 +1,90 @@
1
+ import {
2
+ generateKeyPair,
3
+ loadKeyPair,
4
+ saveKeyPair
5
+ } from "./chunk-DVAS2443.js";
6
+
7
+ // src/identity/identity.ts
8
+ import { z } from "zod";
9
+ import { createHash } from "crypto";
10
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
11
+ import { join } from "path";
12
+ var AgentIdentitySchema = z.object({
13
+ /** Deterministic ID derived from public key: sha256(hex).slice(0, 16). */
14
+ agent_id: z.string().min(1),
15
+ /** Human-readable owner name (from config or init). */
16
+ owner: z.string().min(1),
17
+ /** Hex-encoded Ed25519 public key. */
18
+ public_key: z.string().min(1),
19
+ /** ISO 8601 timestamp of identity creation. */
20
+ created_at: z.string().datetime(),
21
+ /** Optional guarantor info if linked to a human. */
22
+ guarantor: z.object({
23
+ github_login: z.string().min(1),
24
+ verified_at: z.string().datetime()
25
+ }).optional()
26
+ });
27
+ var AgentCertificateSchema = z.object({
28
+ identity: AgentIdentitySchema,
29
+ /** ISO 8601 timestamp of certificate issuance. */
30
+ issued_at: z.string().datetime(),
31
+ /** ISO 8601 timestamp of certificate expiry. */
32
+ expires_at: z.string().datetime(),
33
+ /** Hex-encoded public key of the issuer (same as identity for self-signed). */
34
+ issuer_public_key: z.string().min(1),
35
+ /** Base64url Ed25519 signature over { identity, issued_at, expires_at, issuer_public_key }. */
36
+ signature: z.string().min(1)
37
+ });
38
+ var IDENTITY_FILENAME = "identity.json";
39
+ function deriveAgentId(publicKeyHex) {
40
+ return createHash("sha256").update(publicKeyHex, "hex").digest("hex").slice(0, 16);
41
+ }
42
+ function createIdentity(configDir, owner) {
43
+ if (!existsSync(configDir)) {
44
+ mkdirSync(configDir, { recursive: true });
45
+ }
46
+ let keys;
47
+ try {
48
+ keys = loadKeyPair(configDir);
49
+ } catch {
50
+ keys = generateKeyPair();
51
+ saveKeyPair(configDir, keys);
52
+ }
53
+ const publicKeyHex = keys.publicKey.toString("hex");
54
+ const agentId = deriveAgentId(publicKeyHex);
55
+ const identity = {
56
+ agent_id: agentId,
57
+ owner,
58
+ public_key: publicKeyHex,
59
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
60
+ };
61
+ saveIdentity(configDir, identity);
62
+ return identity;
63
+ }
64
+ function loadIdentity(configDir) {
65
+ const filePath = join(configDir, IDENTITY_FILENAME);
66
+ if (!existsSync(filePath)) return null;
67
+ try {
68
+ const raw = readFileSync(filePath, "utf-8");
69
+ return AgentIdentitySchema.parse(JSON.parse(raw));
70
+ } catch {
71
+ return null;
72
+ }
73
+ }
74
+ function saveIdentity(configDir, identity) {
75
+ if (!existsSync(configDir)) {
76
+ mkdirSync(configDir, { recursive: true });
77
+ }
78
+ const filePath = join(configDir, IDENTITY_FILENAME);
79
+ writeFileSync(filePath, JSON.stringify(identity, null, 2), "utf-8");
80
+ }
81
+ function ensureIdentity(configDir, owner) {
82
+ const existing = loadIdentity(configDir);
83
+ if (existing) return existing;
84
+ return createIdentity(configDir, owner);
85
+ }
86
+
87
+ export {
88
+ deriveAgentId,
89
+ ensureIdentity
90
+ };