agentbnb 4.0.0 → 4.0.2

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 (44) hide show
  1. package/README.md +2 -0
  2. package/dist/{card-IE5UV5QX.js → card-RSGDCHCV.js} +11 -4
  3. package/dist/chunk-3MJT4PZG.js +50 -0
  4. package/dist/{chunk-HEVXCYCY.js → chunk-4P3EMGL4.js} +61 -24
  5. package/dist/chunk-5AH3CMOX.js +62 -0
  6. package/dist/{chunk-QO67IGCW.js → chunk-5KFI5X7B.js} +1 -1
  7. package/dist/chunk-75OC6E4F.js +33 -0
  8. package/dist/{chunk-CUVIWPQO.js → chunk-7NA43XCG.js} +7 -6
  9. package/dist/{conduct-IQYAT6ZU.js → chunk-BH6WGYFB.js} +70 -33
  10. package/dist/{chunk-QVV2P3FN.js → chunk-DNWT5FZQ.js} +22 -2
  11. package/dist/chunk-FF226TIV.js +148 -0
  12. package/dist/{chunk-UJWYE7VL.js → chunk-GGYC5U2Z.js} +28 -111
  13. package/dist/chunk-HH24WMFN.js +373 -0
  14. package/dist/{websocket-client-5TIQDYQ4.js → chunk-JOY533UH.js} +38 -4
  15. package/dist/chunk-QITOPASZ.js +96 -0
  16. package/dist/{chunk-3Y36WQDV.js → chunk-QT7TEVNV.js} +14 -2
  17. package/dist/{chunk-UOGDK2S2.js → chunk-T7NS2J2B.js} +1 -1
  18. package/dist/{chunk-XA63SD4T.js → chunk-WGZ5AGOX.js} +37 -0
  19. package/dist/{chunk-RSX4SCPN.js → chunk-XND2DWTZ.js} +4 -3
  20. package/dist/cli/index.js +2924 -835
  21. package/dist/{client-IOTK6GOS.js → client-T5MTY3CS.js} +3 -3
  22. package/dist/conduct-GZQNFTRP.js +19 -0
  23. package/dist/conduct-N52JX7RT.js +52 -0
  24. package/dist/{conductor-mode-XU7ONJWC.js → conductor-mode-XUWGR4ZE.js} +16 -9
  25. package/dist/execute-PNGQOMYO.js +10 -0
  26. package/dist/index.d.ts +1148 -915
  27. package/dist/index.js +589 -127
  28. package/dist/{peers-G36URZYB.js → peers-K7FSHPN3.js} +2 -1
  29. package/dist/request-4GQSSM4B.js +196 -0
  30. package/dist/serve-skill-TPHZH6BS.js +104 -0
  31. package/dist/server-365V3GYD.js +295 -0
  32. package/dist/websocket-client-6IIDGXKB.js +7 -0
  33. package/package.json +3 -6
  34. package/skills/agentbnb/HEARTBEAT.rules.md +47 -0
  35. package/skills/agentbnb/SKILL.md +166 -0
  36. package/skills/agentbnb/auto-request.ts +14 -0
  37. package/skills/agentbnb/auto-share.ts +10 -0
  38. package/skills/agentbnb/bootstrap.test.ts +323 -0
  39. package/skills/agentbnb/bootstrap.ts +126 -0
  40. package/skills/agentbnb/credit-mgr.ts +11 -0
  41. package/skills/agentbnb/gateway.ts +12 -0
  42. package/skills/agentbnb/install.sh +210 -0
  43. package/dist/chunk-BEI5MTNZ.js +0 -91
  44. package/dist/execute-GDGBU6DJ.js +0 -10
@@ -0,0 +1,373 @@
1
+ import {
2
+ bootstrapAgent,
3
+ getBalance,
4
+ getTransactions,
5
+ holdEscrow,
6
+ migrateOwner,
7
+ openCreditDb,
8
+ releaseEscrow,
9
+ settleEscrow
10
+ } from "./chunk-DNWT5FZQ.js";
11
+ import {
12
+ signEscrowReceipt,
13
+ verifyEscrowReceipt
14
+ } from "./chunk-5KFI5X7B.js";
15
+ import {
16
+ AgentBnBError
17
+ } from "./chunk-WGZ5AGOX.js";
18
+
19
+ // src/credit/local-credit-ledger.ts
20
+ var LocalCreditLedger = class {
21
+ constructor(db) {
22
+ this.db = db;
23
+ }
24
+ /**
25
+ * Holds credits in escrow during capability execution.
26
+ *
27
+ * @param owner - Agent identifier (requester).
28
+ * @param amount - Number of credits to hold.
29
+ * @param cardId - Capability Card ID being requested.
30
+ * @returns EscrowResult with the new escrowId.
31
+ * @throws {AgentBnBError} with code 'INSUFFICIENT_CREDITS' if balance < amount.
32
+ */
33
+ async hold(owner, amount, cardId) {
34
+ const escrowId = holdEscrow(this.db, owner, amount, cardId);
35
+ return { escrowId };
36
+ }
37
+ /**
38
+ * Settles an escrow — transfers held credits to the capability provider.
39
+ *
40
+ * @param escrowId - The escrow ID to settle.
41
+ * @param recipientOwner - Agent identifier who will receive the credits.
42
+ * @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
43
+ * @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
44
+ */
45
+ async settle(escrowId, recipientOwner) {
46
+ settleEscrow(this.db, escrowId, recipientOwner);
47
+ }
48
+ /**
49
+ * Releases an escrow — refunds credits back to the requester.
50
+ *
51
+ * @param escrowId - The escrow ID to release.
52
+ * @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
53
+ * @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
54
+ */
55
+ async release(escrowId) {
56
+ releaseEscrow(this.db, escrowId);
57
+ }
58
+ /**
59
+ * Returns the current credit balance for an agent.
60
+ *
61
+ * @param owner - Agent identifier.
62
+ * @returns Current balance in credits (0 if agent is unknown).
63
+ */
64
+ async getBalance(owner) {
65
+ return getBalance(this.db, owner);
66
+ }
67
+ /**
68
+ * Returns the transaction history for an agent, newest first.
69
+ *
70
+ * @param owner - Agent identifier.
71
+ * @param limit - Maximum number of transactions to return. Defaults to 100.
72
+ * @returns Array of credit transactions ordered newest first.
73
+ */
74
+ async getHistory(owner, limit) {
75
+ return getTransactions(this.db, owner, limit);
76
+ }
77
+ /**
78
+ * Grants initial credits to an agent (bootstrap grant).
79
+ * Idempotent — calling multiple times has no additional effect on balance.
80
+ *
81
+ * @param owner - Agent identifier.
82
+ * @param amount - Number of credits to grant. Defaults to 100.
83
+ */
84
+ async grant(owner, amount) {
85
+ bootstrapAgent(this.db, owner, amount);
86
+ }
87
+ async rename(oldOwner, newOwner) {
88
+ migrateOwner(this.db, oldOwner, newOwner);
89
+ }
90
+ };
91
+
92
+ // src/registry/identity-auth.ts
93
+ var MAX_REQUEST_AGE_MS = 5 * 60 * 1e3;
94
+ async function verifyIdentity(request, reply) {
95
+ const publicKeyHex = request.headers["x-agent-publickey"];
96
+ const signature = request.headers["x-agent-signature"];
97
+ const timestamp = request.headers["x-agent-timestamp"];
98
+ if (!publicKeyHex || !signature || !timestamp) {
99
+ await reply.code(401).send({ error: "Missing identity headers" });
100
+ return false;
101
+ }
102
+ const requestTime = new Date(timestamp).getTime();
103
+ if (isNaN(requestTime) || Math.abs(Date.now() - requestTime) > MAX_REQUEST_AGE_MS) {
104
+ await reply.code(401).send({ error: "Request expired" });
105
+ return false;
106
+ }
107
+ const payload = {
108
+ method: request.method,
109
+ path: request.url,
110
+ timestamp,
111
+ publicKey: publicKeyHex
112
+ };
113
+ let publicKeyBuffer;
114
+ try {
115
+ publicKeyBuffer = Buffer.from(publicKeyHex, "hex");
116
+ } catch {
117
+ await reply.code(401).send({ error: "Invalid identity signature" });
118
+ return false;
119
+ }
120
+ const valid = verifyEscrowReceipt(payload, signature, publicKeyBuffer);
121
+ if (!valid) {
122
+ await reply.code(401).send({ error: "Invalid identity signature" });
123
+ return false;
124
+ }
125
+ request.agentPublicKey = publicKeyHex;
126
+ return true;
127
+ }
128
+ function identityAuthPlugin(fastify) {
129
+ fastify.addHook("onRequest", async (request, reply) => {
130
+ await verifyIdentity(request, reply);
131
+ });
132
+ }
133
+ function signRequest(method, path, body, privateKey, publicKeyHex) {
134
+ const timestamp = (/* @__PURE__ */ new Date()).toISOString();
135
+ const payload = {
136
+ method,
137
+ path,
138
+ timestamp,
139
+ publicKey: publicKeyHex
140
+ };
141
+ void body;
142
+ const signature = signEscrowReceipt(payload, privateKey);
143
+ return {
144
+ "X-Agent-PublicKey": publicKeyHex,
145
+ "X-Agent-Signature": signature,
146
+ "X-Agent-Timestamp": timestamp
147
+ };
148
+ }
149
+
150
+ // src/credit/registry-credit-ledger.ts
151
+ var HTTP_TIMEOUT_MS = 1e4;
152
+ var RegistryCreditLedger = class {
153
+ config;
154
+ constructor(config) {
155
+ this.config = config;
156
+ }
157
+ /**
158
+ * Holds credits in escrow during capability execution.
159
+ *
160
+ * @param owner - Agent identifier (requester).
161
+ * @param amount - Number of credits to hold.
162
+ * @param cardId - Capability Card ID being requested.
163
+ * @returns EscrowResult with the new escrowId.
164
+ * @throws {AgentBnBError} with code 'INSUFFICIENT_CREDITS' if balance < amount.
165
+ */
166
+ async hold(owner, amount, cardId) {
167
+ if (this.config.mode === "direct") {
168
+ const escrowId = holdEscrow(this.config.db, owner, amount, cardId);
169
+ return { escrowId };
170
+ }
171
+ const data = await this.post("/api/credits/hold", owner, {
172
+ owner,
173
+ amount,
174
+ cardId
175
+ });
176
+ return { escrowId: data.escrowId };
177
+ }
178
+ /**
179
+ * Settles an escrow — transfers held credits to the capability provider.
180
+ *
181
+ * @param escrowId - The escrow ID to settle.
182
+ * @param recipientOwner - Agent identifier who will receive the credits.
183
+ * @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
184
+ * @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
185
+ */
186
+ async settle(escrowId, recipientOwner) {
187
+ if (this.config.mode === "direct") {
188
+ settleEscrow(this.config.db, escrowId, recipientOwner);
189
+ return;
190
+ }
191
+ await this.post("/api/credits/settle", null, { escrowId, recipientOwner });
192
+ }
193
+ /**
194
+ * Releases an escrow — refunds credits back to the requester.
195
+ *
196
+ * @param escrowId - The escrow ID to release.
197
+ * @throws {AgentBnBError} with code 'ESCROW_NOT_FOUND' if escrow does not exist.
198
+ * @throws {AgentBnBError} with code 'ESCROW_ALREADY_SETTLED' if escrow is not in 'held' status.
199
+ */
200
+ async release(escrowId) {
201
+ if (this.config.mode === "direct") {
202
+ releaseEscrow(this.config.db, escrowId);
203
+ return;
204
+ }
205
+ await this.post("/api/credits/release", null, { escrowId });
206
+ }
207
+ /**
208
+ * Returns the current credit balance for an agent.
209
+ *
210
+ * @param owner - Agent identifier.
211
+ * @returns Current balance in credits (0 if agent is unknown).
212
+ */
213
+ async getBalance(owner) {
214
+ if (this.config.mode === "direct") {
215
+ return getBalance(this.config.db, owner);
216
+ }
217
+ const data = await this.get(`/api/credits/${owner}`, owner);
218
+ return data.balance;
219
+ }
220
+ /**
221
+ * Returns the transaction history for an agent, newest first.
222
+ *
223
+ * @param owner - Agent identifier.
224
+ * @param limit - Maximum number of transactions to return. Defaults to 100.
225
+ * @returns Array of credit transactions ordered newest first.
226
+ */
227
+ async getHistory(owner, limit = 100) {
228
+ if (this.config.mode === "direct") {
229
+ return getTransactions(this.config.db, owner, limit);
230
+ }
231
+ const data = await this.get(
232
+ `/api/credits/${owner}/history?limit=${limit}`,
233
+ owner
234
+ );
235
+ return data.transactions;
236
+ }
237
+ /**
238
+ * Grants initial credits to an agent (bootstrap grant).
239
+ * Idempotent — calling multiple times has no additional effect on balance.
240
+ *
241
+ * @param owner - Agent identifier.
242
+ * @param amount - Number of credits to grant. Defaults to 100.
243
+ */
244
+ async grant(owner, amount = 100) {
245
+ if (this.config.mode === "direct") {
246
+ bootstrapAgent(this.config.db, owner, amount);
247
+ return;
248
+ }
249
+ await this.post("/api/credits/grant", owner, { owner, amount });
250
+ }
251
+ /**
252
+ * Renames an owner — migrates balance, transactions, and escrows.
253
+ */
254
+ async rename(oldOwner, newOwner) {
255
+ if (oldOwner === newOwner) return;
256
+ if (this.config.mode === "direct") {
257
+ migrateOwner(this.config.db, oldOwner, newOwner);
258
+ return;
259
+ }
260
+ await this.post("/api/credits/rename", null, { oldOwner, newOwner });
261
+ }
262
+ // ─── Private HTTP helpers ─────────────────────────────────────────────────
263
+ /**
264
+ * Makes an authenticated POST request to the Registry HTTP API.
265
+ * Includes a 10s timeout via AbortController.
266
+ *
267
+ * @param path - API path (e.g., '/api/credits/hold').
268
+ * @param ownerForHeader - Agent owner identifier for X-Agent-Owner header, or null to omit.
269
+ * @param body - JSON body to send.
270
+ * @returns Parsed JSON response body.
271
+ * @throws {AgentBnBError} on non-2xx responses or network errors.
272
+ */
273
+ async post(path, ownerForHeader, body) {
274
+ const cfg = this.config;
275
+ const controller = new AbortController();
276
+ const timeoutId = setTimeout(() => controller.abort(), HTTP_TIMEOUT_MS);
277
+ try {
278
+ const authHeaders = signRequest("POST", path, body, cfg.privateKey, cfg.ownerPublicKey);
279
+ const headers = {
280
+ "Content-Type": "application/json",
281
+ ...authHeaders
282
+ };
283
+ void ownerForHeader;
284
+ const res = await fetch(`${cfg.registryUrl}${path}`, {
285
+ method: "POST",
286
+ headers,
287
+ body: JSON.stringify(body),
288
+ signal: controller.signal
289
+ });
290
+ return await this.handleResponse(res);
291
+ } catch (err) {
292
+ if (err instanceof AgentBnBError) throw err;
293
+ throw new AgentBnBError(
294
+ `Registry unreachable: ${err.message}`,
295
+ "REGISTRY_UNREACHABLE"
296
+ );
297
+ } finally {
298
+ clearTimeout(timeoutId);
299
+ }
300
+ }
301
+ /**
302
+ * Makes an authenticated GET request to the Registry HTTP API.
303
+ * Includes a 10s timeout via AbortController.
304
+ *
305
+ * @param path - API path (e.g., '/api/credits/owner-id').
306
+ * @param owner - Agent owner identifier for X-Agent-Owner header.
307
+ * @returns Parsed JSON response body.
308
+ * @throws {AgentBnBError} on non-2xx responses or network errors.
309
+ */
310
+ async get(path, owner) {
311
+ const cfg = this.config;
312
+ const controller = new AbortController();
313
+ const timeoutId = setTimeout(() => controller.abort(), HTTP_TIMEOUT_MS);
314
+ try {
315
+ const authHeaders = signRequest("GET", path, null, cfg.privateKey, cfg.ownerPublicKey);
316
+ void owner;
317
+ const res = await fetch(`${cfg.registryUrl}${path}`, {
318
+ method: "GET",
319
+ headers: {
320
+ "Content-Type": "application/json",
321
+ ...authHeaders
322
+ },
323
+ signal: controller.signal
324
+ });
325
+ return await this.handleResponse(res);
326
+ } catch (err) {
327
+ if (err instanceof AgentBnBError) throw err;
328
+ throw new AgentBnBError(
329
+ `Registry unreachable: ${err.message}`,
330
+ "REGISTRY_UNREACHABLE"
331
+ );
332
+ } finally {
333
+ clearTimeout(timeoutId);
334
+ }
335
+ }
336
+ /**
337
+ * Handles an HTTP response — returns parsed JSON on 2xx, throws AgentBnBError on error.
338
+ */
339
+ async handleResponse(res) {
340
+ const json = await res.json();
341
+ if (!res.ok) {
342
+ const code = typeof json["code"] === "string" ? json["code"] : "REGISTRY_ERROR";
343
+ const message = typeof json["error"] === "string" ? json["error"] : `HTTP ${res.status}`;
344
+ throw new AgentBnBError(message, code);
345
+ }
346
+ return json;
347
+ }
348
+ };
349
+
350
+ // src/credit/create-ledger.ts
351
+ function createLedger(opts) {
352
+ if ("registryUrl" in opts && opts.registryUrl !== void 0) {
353
+ return new RegistryCreditLedger({
354
+ mode: "http",
355
+ registryUrl: opts.registryUrl,
356
+ ownerPublicKey: opts.ownerPublicKey,
357
+ privateKey: opts.privateKey
358
+ });
359
+ }
360
+ if ("db" in opts && opts.db !== void 0) {
361
+ return new RegistryCreditLedger({
362
+ mode: "direct",
363
+ db: opts.db
364
+ });
365
+ }
366
+ const db = openCreditDb(opts.creditDbPath);
367
+ return new LocalCreditLedger(db);
368
+ }
369
+
370
+ export {
371
+ identityAuthPlugin,
372
+ createLedger
373
+ };
@@ -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,96 @@
1
+ import {
2
+ generateKeyPair,
3
+ loadKeyPair,
4
+ saveKeyPair
5
+ } from "./chunk-5KFI5X7B.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) {
84
+ if (existing.owner !== owner) {
85
+ existing.owner = owner;
86
+ saveIdentity(configDir, existing);
87
+ }
88
+ return existing;
89
+ }
90
+ return createIdentity(configDir, owner);
91
+ }
92
+
93
+ export {
94
+ deriveAgentId,
95
+ ensureIdentity
96
+ };
@@ -4,8 +4,10 @@ var RegisterMessageSchema = z.object({
4
4
  type: z.literal("register"),
5
5
  owner: z.string().min(1),
6
6
  token: z.string().min(1),
7
- card: z.record(z.unknown())
7
+ card: z.record(z.unknown()),
8
8
  // CapabilityCard (validated separately)
9
+ cards: z.array(z.record(z.unknown())).optional()
10
+ // Additional cards (e.g., conductor card)
9
11
  });
10
12
  var RegisteredMessageSchema = z.object({
11
13
  type: z.literal("registered"),
@@ -55,6 +57,15 @@ var ErrorMessageSchema = z.object({
55
57
  message: z.string(),
56
58
  request_id: z.string().optional()
57
59
  });
60
+ var RelayProgressMessageSchema = z.object({
61
+ type: z.literal("relay_progress"),
62
+ id: z.string().uuid(),
63
+ // request ID this progress relates to
64
+ progress: z.number().min(0).max(100).optional(),
65
+ // optional percentage
66
+ message: z.string().optional()
67
+ // optional status message
68
+ });
58
69
  var RelayMessageSchema = z.discriminatedUnion("type", [
59
70
  RegisterMessageSchema,
60
71
  RegisteredMessageSchema,
@@ -62,7 +73,8 @@ var RelayMessageSchema = z.discriminatedUnion("type", [
62
73
  IncomingRequestMessageSchema,
63
74
  RelayResponseMessageSchema,
64
75
  ResponseMessageSchema,
65
- ErrorMessageSchema
76
+ ErrorMessageSchema,
77
+ RelayProgressMessageSchema
66
78
  ]);
67
79
 
68
80
  export {
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  AgentBnBError,
3
3
  CapabilityCardSchema
4
- } from "./chunk-XA63SD4T.js";
4
+ } from "./chunk-WGZ5AGOX.js";
5
5
 
6
6
  // src/registry/request-log.ts
7
7
  var SINCE_MS = {
@@ -83,12 +83,45 @@ var SkillSchema = z.object({
83
83
  */
84
84
  _internal: z.record(z.unknown()).optional()
85
85
  });
86
+ var SuitabilitySchema = z.object({
87
+ /** Use cases this agent/skill is optimised for. */
88
+ ideal_for: z.array(z.string()).optional(),
89
+ /** Scenarios this agent/skill cannot reliably handle. */
90
+ not_suitable_for: z.array(z.string()).optional(),
91
+ /** Domains explicitly excluded (used for routing exclusions in later phases). */
92
+ excluded_domains: z.array(z.string()).optional(),
93
+ /** Conditions that increase failure risk, shown as warnings in the Hub. */
94
+ risk_conditions: z.array(z.string()).optional(),
95
+ /** Recommended alternative when this agent is unsuitable. */
96
+ fallback_recommendation: z.string().optional()
97
+ });
98
+ var LearningSchema = z.object({
99
+ /** Known limitations that may affect reliability (self-declared). */
100
+ known_limitations: z.array(z.string()).optional(),
101
+ /** Common failure patterns observed by the provider. */
102
+ common_failure_patterns: z.array(z.string()).optional(),
103
+ /** Version-tagged improvements the provider has shipped. */
104
+ recent_improvements: z.array(z.object({
105
+ version: z.string(),
106
+ summary: z.string(),
107
+ timestamp: z.string()
108
+ })).optional(),
109
+ /** Structured critiques from external sources (phase 2+). */
110
+ critiques: z.array(z.object({
111
+ type: z.literal("structured"),
112
+ summary: z.string(),
113
+ source_tier: z.string(),
114
+ timestamp: z.string()
115
+ })).optional()
116
+ });
86
117
  var CapabilityCardV2Schema = z.object({
87
118
  spec_version: z.literal("2.0"),
88
119
  id: z.string().uuid(),
89
120
  owner: z.string().min(1),
90
121
  /** Agent display name — was 'name' in v1.0. */
91
122
  agent_name: z.string().min(1).max(100),
123
+ /** Short one-liner shown in Hub v2 Identity Header. */
124
+ short_description: z.string().max(200).optional(),
92
125
  /** At least one skill is required. */
93
126
  skills: z.array(SkillSchema).min(1),
94
127
  availability: z.object({
@@ -100,6 +133,10 @@ var CapabilityCardV2Schema = z.object({
100
133
  runtime: z.string(),
101
134
  region: z.string().optional()
102
135
  }).optional(),
136
+ /** Suitability metadata for Hub v2 profile and future routing warnings. */
137
+ suitability: SuitabilitySchema.optional(),
138
+ /** Learning signals — self-declared limitations, improvements, critiques. */
139
+ learning: LearningSchema.optional(),
103
140
  /**
104
141
  * Private per-card metadata. Stripped from all API and CLI responses —
105
142
  * never transmitted beyond the local store.
@@ -1,14 +1,14 @@
1
1
  import {
2
2
  signEscrowReceipt
3
- } from "./chunk-QO67IGCW.js";
3
+ } from "./chunk-5KFI5X7B.js";
4
4
  import {
5
5
  AgentBnBError
6
- } from "./chunk-XA63SD4T.js";
6
+ } from "./chunk-WGZ5AGOX.js";
7
7
 
8
8
  // src/gateway/client.ts
9
9
  import { randomUUID } from "crypto";
10
10
  async function requestCapability(opts) {
11
- const { gatewayUrl, token, cardId, params = {}, timeoutMs = 3e4, escrowReceipt, identity } = opts;
11
+ const { gatewayUrl, token, cardId, params = {}, timeoutMs = 3e5, escrowReceipt, identity } = opts;
12
12
  const id = randomUUID();
13
13
  const payload = {
14
14
  jsonrpc: "2.0",
@@ -62,6 +62,7 @@ async function requestViaRelay(relay, opts) {
62
62
  cardId: opts.cardId,
63
63
  skillId: opts.skillId,
64
64
  params: opts.params ?? {},
65
+ requester: opts.requester,
65
66
  escrowReceipt: opts.escrowReceipt,
66
67
  timeoutMs: opts.timeoutMs
67
68
  });