agentbnb 8.0.1 → 8.2.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 (43) hide show
  1. package/dist/{chunk-TBJ3FZKZ.js → chunk-7Q2XUXSA.js} +1 -1
  2. package/dist/{chunk-LJM7FHPM.js → chunk-BZOJ7HBT.js} +33 -1
  3. package/dist/{chunk-FTZTEHYG.js → chunk-DEWY7OQK.js} +135 -8
  4. package/dist/{chunk-CUONY5TO.js → chunk-EJKW57ZV.js} +19 -1
  5. package/dist/chunk-EZVOG7QS.js +161 -0
  6. package/dist/{chunk-E2OKP5CY.js → chunk-GJETGML6.js} +181 -83
  7. package/dist/{chunk-YHY7OG6S.js → chunk-GWMMYVLL.js} +4 -4
  8. package/dist/{chunk-D6RKW2XG.js → chunk-JLNHMNES.js} +16 -3
  9. package/dist/{chunk-5AAFG2V2.js → chunk-KBQNTUTN.js} +239 -24
  10. package/dist/{chunk-C537SFHV.js → chunk-LOUEJI6X.js} +4 -4
  11. package/dist/{chunk-ALX4WS3A.js → chunk-NP55V7RQ.js} +1 -1
  12. package/dist/{chunk-X32NE6V4.js → chunk-RBXTWWUH.js} +1 -1
  13. package/dist/{chunk-O2OYBAVR.js → chunk-SRBVKO2V.js} +9 -0
  14. package/dist/{chunk-7EF3HYVZ.js → chunk-STJLWMXH.js} +48 -4
  15. package/dist/{chunk-5GME4KJZ.js → chunk-UYCD3JBZ.js} +3 -3
  16. package/dist/chunk-WKWJWKX7.js +1460 -0
  17. package/dist/cli/index.js +36 -48
  18. package/dist/{client-HKV3QWZ3.js → client-66TFS7RS.js} +4 -2
  19. package/dist/{conduct-W6XF6DJW.js → conduct-A6COHLHY.js} +8 -8
  20. package/dist/{conduct-YB64OHI6.js → conduct-IUVAXUAV.js} +8 -8
  21. package/dist/conductor-mode-D5TFQW5L.js +266 -0
  22. package/dist/{conductor-mode-AKREGDIU.js → conductor-mode-L2MB44BW.js} +7 -7
  23. package/dist/{execute-AYQWORVH.js → execute-5AWLARB5.js} +5 -5
  24. package/dist/{execute-EPE6MZLT.js → execute-WOS457HW.js} +2 -2
  25. package/dist/index.js +438 -92
  26. package/dist/{publish-capability-AH2HDW54.js → publish-capability-JJCBBMSX.js} +2 -2
  27. package/dist/{request-HCCXSKAY.js → request-6YQLA7K3.js} +13 -8
  28. package/dist/{serve-skill-SZAQT5T5.js → serve-skill-X7TZSILV.js} +5 -5
  29. package/dist/{server-MHMAYXWZ.js → server-5TSP4DBX.js} +11 -15
  30. package/dist/{service-coordinator-WGH6B2VT.js → service-coordinator-WTUSMPY6.js} +69 -46
  31. package/dist/skills/agentbnb/bootstrap.js +1158 -184
  32. package/openclaw.plugin.json +1 -1
  33. package/package.json +13 -17
  34. package/skills/agentbnb/bootstrap.test.ts +42 -6
  35. package/skills/agentbnb/bootstrap.ts +49 -13
  36. package/skills/agentbnb/install.sh +0 -0
  37. package/skills/agentbnb/openclaw-tools.test.ts +328 -0
  38. package/skills/agentbnb/openclaw-tools.ts +297 -0
  39. package/dist/chunk-64AK4FJM.js +0 -84
  40. package/dist/chunk-B2VJTKO5.js +0 -393
  41. package/dist/chunk-OH7BP5NP.js +0 -96
  42. package/dist/conductor-mode-2GSLHVN6.js +0 -891
  43. package/dist/index.d.ts +0 -5069
@@ -3,16 +3,17 @@ import {
3
3
  } from "./chunk-3MJT4PZG.js";
4
4
  import {
5
5
  scorePeers
6
- } from "./chunk-5GME4KJZ.js";
6
+ } from "./chunk-UYCD3JBZ.js";
7
7
  import {
8
8
  fetchRemoteCards
9
9
  } from "./chunk-KF3TZHA5.js";
10
10
  import {
11
11
  searchCards
12
- } from "./chunk-LJM7FHPM.js";
12
+ } from "./chunk-BZOJ7HBT.js";
13
13
  import {
14
- requestCapability
15
- } from "./chunk-64AK4FJM.js";
14
+ requestCapability,
15
+ requestCapabilityBatch
16
+ } from "./chunk-EZVOG7QS.js";
16
17
 
17
18
  // src/conductor/decomposition-validator.ts
18
19
  function validateAndNormalizeSubtasks(raw, context) {
@@ -410,6 +411,65 @@ function computeWaves(subtasks) {
410
411
  }
411
412
  return waves;
412
413
  }
414
+ async function executeSingleTask(pt, gatewayToken, timeoutMs, requesterOwner, relayClient, resolveAgentUrl) {
415
+ const { taskId, match: m, interpolatedParams, primary, teamId, capabilityType } = pt;
416
+ try {
417
+ let res;
418
+ if (primary.url.startsWith("relay://") && relayClient) {
419
+ const targetOwner = primary.url.replace("relay://", "");
420
+ res = await relayClient.request({
421
+ targetOwner,
422
+ cardId: primary.cardId,
423
+ params: interpolatedParams,
424
+ requester: requesterOwner,
425
+ timeoutMs
426
+ });
427
+ } else {
428
+ res = await requestCapability({
429
+ gatewayUrl: primary.url,
430
+ token: gatewayToken,
431
+ cardId: primary.cardId,
432
+ params: { ...interpolatedParams, requester: requesterOwner },
433
+ timeoutMs
434
+ });
435
+ }
436
+ return { taskId, result: res, credits: m.credits, team_id: teamId, capability_type: capabilityType };
437
+ } catch (primaryErr) {
438
+ if (m.alternatives.length > 0) {
439
+ const alt = m.alternatives[0];
440
+ const altResolved = resolveAgentUrl ? resolveAgentUrl(alt.agent) : { url: `http://${alt.agent}:7700`, cardId: `card-${alt.agent}` };
441
+ try {
442
+ let altRes;
443
+ if (altResolved.url.startsWith("relay://") && relayClient) {
444
+ const targetOwner = altResolved.url.replace("relay://", "");
445
+ altRes = await relayClient.request({
446
+ targetOwner,
447
+ cardId: altResolved.cardId,
448
+ params: interpolatedParams,
449
+ requester: requesterOwner,
450
+ timeoutMs
451
+ });
452
+ } else {
453
+ altRes = await requestCapability({
454
+ gatewayUrl: altResolved.url,
455
+ token: gatewayToken,
456
+ cardId: altResolved.cardId,
457
+ params: { ...interpolatedParams, requester: requesterOwner },
458
+ timeoutMs
459
+ });
460
+ }
461
+ return { taskId, result: altRes, credits: alt.credits, team_id: teamId, capability_type: capabilityType };
462
+ } catch (altErr) {
463
+ throw new Error(
464
+ `Task ${taskId}: primary (${m.selected_agent}) failed: ${primaryErr instanceof Error ? primaryErr.message : String(primaryErr)}; alternative (${alt.agent}) failed: ${altErr instanceof Error ? altErr.message : String(altErr)}`
465
+ );
466
+ }
467
+ }
468
+ throw new Error(
469
+ `Task ${taskId}: ${primaryErr instanceof Error ? primaryErr.message : String(primaryErr)}`
470
+ );
471
+ }
472
+ }
413
473
  async function orchestrate(opts) {
414
474
  const { subtasks, matches, gatewayToken, resolveAgentUrl, timeoutMs = 3e5, maxBudget, relayClient, requesterOwner } = opts;
415
475
  const startTime = Date.now();
@@ -447,89 +507,127 @@ async function orchestrate(opts) {
447
507
  }
448
508
  executableIds.push(taskId);
449
509
  }
450
- const waveResults = await Promise.allSettled(
451
- executableIds.map(async (taskId) => {
452
- const subtask = subtaskMap.get(taskId);
453
- const m = matches.get(taskId);
454
- if (!m) {
455
- throw new Error(`No match found for subtask ${taskId}`);
456
- }
457
- const stepsContext = {};
458
- for (const [id, val] of results) {
459
- stepsContext[id] = val;
460
- }
461
- const interpContext = { steps: stepsContext, prev: void 0 };
462
- if (subtask.depends_on.length > 0) {
463
- const lastDep = subtask.depends_on[subtask.depends_on.length - 1];
464
- interpContext.prev = results.get(lastDep);
465
- }
466
- const interpolatedParams = interpolateObject(
467
- subtask.params,
468
- interpContext
469
- );
470
- const teamMember = teamMemberMap.get(taskId);
471
- const teamId = opts.team?.team_id ?? null;
472
- const taskCapabilityType = teamMember?.capability_type ?? null;
473
- const agentOwner = teamMember?.agent ?? m.selected_agent;
474
- const primary = resolveAgentUrl(agentOwner);
475
- try {
476
- let res;
477
- if (primary.url.startsWith("relay://") && relayClient) {
478
- const targetOwner = primary.url.replace("relay://", "");
479
- res = await relayClient.request({
480
- targetOwner,
481
- cardId: primary.cardId,
482
- params: interpolatedParams,
483
- requester: requesterOwner,
484
- timeoutMs
485
- });
486
- } else {
487
- res = await requestCapability({
488
- gatewayUrl: primary.url,
489
- token: gatewayToken,
490
- cardId: primary.cardId,
491
- params: { ...interpolatedParams, requester: requesterOwner },
492
- timeoutMs
493
- });
494
- }
495
- return { taskId, result: res, credits: m.credits, team_id: teamId, capability_type: taskCapabilityType };
496
- } catch (primaryErr) {
497
- if (m.alternatives.length > 0) {
498
- const alt = m.alternatives[0];
499
- const altAgent = resolveAgentUrl(alt.agent);
510
+ const preparedTasks = [];
511
+ for (const taskId of executableIds) {
512
+ const subtask = subtaskMap.get(taskId);
513
+ const m = matches.get(taskId);
514
+ if (!m) {
515
+ errors.push(`No match found for subtask ${taskId}`);
516
+ continue;
517
+ }
518
+ const stepsContext = {};
519
+ for (const [id, val] of results) stepsContext[id] = val;
520
+ const interpContext = { steps: stepsContext, prev: void 0 };
521
+ if (subtask.depends_on.length > 0) {
522
+ const lastDep = subtask.depends_on[subtask.depends_on.length - 1];
523
+ interpContext.prev = results.get(lastDep);
524
+ }
525
+ const interpolatedParams = interpolateObject(
526
+ subtask.params,
527
+ interpContext
528
+ );
529
+ const teamMember = teamMemberMap.get(taskId);
530
+ const agentOwner = teamMember?.agent ?? m.selected_agent;
531
+ const primary = resolveAgentUrl(agentOwner);
532
+ preparedTasks.push({
533
+ taskId,
534
+ subtask,
535
+ match: m,
536
+ interpolatedParams,
537
+ agentOwner,
538
+ primary,
539
+ teamId: opts.team?.team_id ?? null,
540
+ capabilityType: teamMember?.capability_type ?? null
541
+ });
542
+ }
543
+ const httpGroups = /* @__PURE__ */ new Map();
544
+ const relayTasks = [];
545
+ for (const pt of preparedTasks) {
546
+ if (pt.primary.url.startsWith("relay://") && relayClient) {
547
+ relayTasks.push(pt);
548
+ } else {
549
+ const group = httpGroups.get(pt.primary.url) ?? [];
550
+ group.push(pt);
551
+ httpGroups.set(pt.primary.url, group);
552
+ }
553
+ }
554
+ const batchPromises = [];
555
+ for (const [gatewayUrl, group] of httpGroups) {
556
+ if (group.length >= 2) {
557
+ batchPromises.push(
558
+ (async () => {
559
+ const items = group.map((pt) => ({
560
+ id: pt.taskId,
561
+ cardId: pt.primary.cardId,
562
+ params: { ...pt.interpolatedParams, requester: requesterOwner },
563
+ _pt: pt
564
+ }));
500
565
  try {
501
- let altRes;
502
- if (altAgent.url.startsWith("relay://") && relayClient) {
503
- const targetOwner = altAgent.url.replace("relay://", "");
504
- altRes = await relayClient.request({
505
- targetOwner,
506
- cardId: altAgent.cardId,
507
- params: interpolatedParams,
508
- requester: requesterOwner,
509
- timeoutMs
510
- });
511
- } else {
512
- altRes = await requestCapability({
513
- gatewayUrl: altAgent.url,
514
- token: gatewayToken,
515
- cardId: altAgent.cardId,
516
- params: { ...interpolatedParams, requester: requesterOwner },
517
- timeoutMs
518
- });
519
- }
520
- return { taskId, result: altRes, credits: alt.credits, team_id: teamId, capability_type: taskCapabilityType };
521
- } catch (altErr) {
522
- throw new Error(
523
- `Task ${taskId}: primary (${m.selected_agent}) failed: ${primaryErr instanceof Error ? primaryErr.message : String(primaryErr)}; alternative (${alt.agent}) failed: ${altErr instanceof Error ? altErr.message : String(altErr)}`
566
+ const batchResults = await requestCapabilityBatch(
567
+ gatewayUrl,
568
+ gatewayToken,
569
+ items.map(({ _pt, ...item }) => item),
570
+ { timeoutMs }
524
571
  );
572
+ return items.map((item) => {
573
+ const res = batchResults.get(item.id);
574
+ if (res instanceof Error) {
575
+ return {
576
+ status: "rejected",
577
+ reason: new Error(`Task ${item.id}: ${res.message}`)
578
+ };
579
+ }
580
+ return {
581
+ status: "fulfilled",
582
+ value: {
583
+ taskId: item.id,
584
+ result: res,
585
+ credits: item._pt.match.credits,
586
+ team_id: item._pt.teamId,
587
+ capability_type: item._pt.capabilityType
588
+ }
589
+ };
590
+ });
591
+ } catch (batchErr) {
592
+ return Promise.all(group.map(async (pt) => {
593
+ try {
594
+ const res = await executeSingleTask(pt, gatewayToken, timeoutMs, requesterOwner, relayClient, resolveAgentUrl);
595
+ return { status: "fulfilled", value: res };
596
+ } catch (err) {
597
+ return { status: "rejected", reason: err };
598
+ }
599
+ }));
600
+ }
601
+ })()
602
+ );
603
+ } else {
604
+ const pt = group[0];
605
+ batchPromises.push(
606
+ (async () => {
607
+ try {
608
+ const res = await executeSingleTask(pt, gatewayToken, timeoutMs, requesterOwner, relayClient, resolveAgentUrl);
609
+ return [{ status: "fulfilled", value: res }];
610
+ } catch (err) {
611
+ return [{ status: "rejected", reason: err }];
525
612
  }
613
+ })()
614
+ );
615
+ }
616
+ }
617
+ for (const pt of relayTasks) {
618
+ batchPromises.push(
619
+ (async () => {
620
+ try {
621
+ const res = await executeSingleTask(pt, gatewayToken, timeoutMs, requesterOwner, relayClient, resolveAgentUrl);
622
+ return [{ status: "fulfilled", value: res }];
623
+ } catch (err) {
624
+ return [{ status: "rejected", reason: err }];
526
625
  }
527
- throw new Error(
528
- `Task ${taskId}: ${primaryErr instanceof Error ? primaryErr.message : String(primaryErr)}`
529
- );
530
- }
531
- })
532
- );
626
+ })()
627
+ );
628
+ }
629
+ const allBatchResults = await Promise.all(batchPromises);
630
+ const waveResults = allBatchResults.flat();
533
631
  for (const settlement of waveResults) {
534
632
  if (settlement.status === "fulfilled") {
535
633
  const { taskId, result, credits, team_id, capability_type } = settlement.value;
@@ -7,13 +7,13 @@ import {
7
7
  decompose,
8
8
  matchSubTasks,
9
9
  orchestrate
10
- } from "./chunk-E2OKP5CY.js";
10
+ } from "./chunk-GJETGML6.js";
11
11
  import {
12
12
  BudgetManager
13
- } from "./chunk-5GME4KJZ.js";
13
+ } from "./chunk-UYCD3JBZ.js";
14
14
  import {
15
15
  openCreditDb
16
- } from "./chunk-D6RKW2XG.js";
16
+ } from "./chunk-JLNHMNES.js";
17
17
  import {
18
18
  loadPeers
19
19
  } from "./chunk-5AH3CMOX.js";
@@ -22,7 +22,7 @@ import {
22
22
  } from "./chunk-75OC6E4F.js";
23
23
  import {
24
24
  openDatabase
25
- } from "./chunk-O2OYBAVR.js";
25
+ } from "./chunk-SRBVKO2V.js";
26
26
 
27
27
  // src/cli/conduct.ts
28
28
  async function conductAction(task, opts) {
@@ -149,10 +149,23 @@ function getBalance(db, owner) {
149
149
  const row = db.prepare("SELECT balance FROM credit_balances WHERE owner = ?").get(owner);
150
150
  return row?.balance ?? 0;
151
151
  }
152
- function getTransactions(db, owner, limit = 100) {
152
+ function getTransactions(db, owner, opts = 100) {
153
+ const page = typeof opts === "number" ? { limit: opts } : opts;
154
+ const limit = page.limit ?? 100;
155
+ const conditions = ["owner = ?"];
156
+ const params = [owner];
157
+ if (page.before) {
158
+ conditions.push("created_at < ?");
159
+ params.push(page.before);
160
+ }
161
+ if (page.after) {
162
+ conditions.push("created_at > ?");
163
+ params.push(page.after);
164
+ }
165
+ params.push(limit);
153
166
  return db.prepare(
154
- "SELECT id, owner, amount, reason, reference_id, created_at FROM credit_transactions WHERE owner = ? ORDER BY created_at DESC LIMIT ?"
155
- ).all(owner, limit);
167
+ `SELECT id, owner, amount, reason, reference_id, created_at FROM credit_transactions WHERE ${conditions.join(" AND ")} ORDER BY created_at DESC LIMIT ?`
168
+ ).all(...params);
156
169
  }
157
170
  function registerProvider(db, owner) {
158
171
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -3,19 +3,154 @@ import {
3
3
  getBalance,
4
4
  getTransactions,
5
5
  holdEscrow,
6
+ lookupAgent,
6
7
  migrateOwner,
7
8
  openCreditDb,
8
9
  releaseEscrow,
9
10
  settleEscrow
10
- } from "./chunk-D6RKW2XG.js";
11
+ } from "./chunk-JLNHMNES.js";
11
12
  import {
13
+ generateKeyPair,
14
+ loadKeyPair,
15
+ saveKeyPair,
12
16
  signEscrowReceipt,
13
17
  verifyEscrowReceipt
14
- } from "./chunk-CUONY5TO.js";
18
+ } from "./chunk-EJKW57ZV.js";
15
19
  import {
16
20
  AgentBnBError
17
21
  } from "./chunk-WVY2W7AA.js";
18
22
 
23
+ // src/identity/identity.ts
24
+ import { z } from "zod";
25
+ import { createHash, createPrivateKey, createPublicKey } from "crypto";
26
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
27
+ import { join } from "path";
28
+ var AgentIdentitySchema = z.object({
29
+ /** Deterministic ID derived from public key: sha256(hex).slice(0, 16). */
30
+ agent_id: z.string().min(1),
31
+ /** Human-readable owner name (from config or init). */
32
+ owner: z.string().min(1),
33
+ /** Hex-encoded Ed25519 public key. */
34
+ public_key: z.string().min(1),
35
+ /** ISO 8601 timestamp of identity creation. */
36
+ created_at: z.string().datetime(),
37
+ /** Optional guarantor info if linked to a human. */
38
+ guarantor: z.object({
39
+ github_login: z.string().min(1),
40
+ verified_at: z.string().datetime()
41
+ }).optional()
42
+ });
43
+ var AgentCertificateSchema = z.object({
44
+ identity: AgentIdentitySchema,
45
+ /** ISO 8601 timestamp of certificate issuance. */
46
+ issued_at: z.string().datetime(),
47
+ /** ISO 8601 timestamp of certificate expiry. */
48
+ expires_at: z.string().datetime(),
49
+ /** Hex-encoded public key of the issuer (same as identity for self-signed). */
50
+ issuer_public_key: z.string().min(1),
51
+ /** Base64url Ed25519 signature over { identity, issued_at, expires_at, issuer_public_key }. */
52
+ signature: z.string().min(1)
53
+ });
54
+ var IDENTITY_FILENAME = "identity.json";
55
+ var PRIVATE_KEY_FILENAME = "private.key";
56
+ var PUBLIC_KEY_FILENAME = "public.key";
57
+ function derivePublicKeyFromPrivate(privateKey) {
58
+ const privateKeyObject = createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
59
+ const publicKeyObject = createPublicKey(privateKeyObject);
60
+ const publicKey = publicKeyObject.export({ format: "der", type: "spki" });
61
+ return Buffer.from(publicKey);
62
+ }
63
+ function buildIdentityFromPublicKey(publicKey, owner, createdAt) {
64
+ const publicKeyHex = publicKey.toString("hex");
65
+ return {
66
+ agent_id: deriveAgentId(publicKeyHex),
67
+ owner,
68
+ public_key: publicKeyHex,
69
+ created_at: createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
70
+ };
71
+ }
72
+ function generateFreshIdentity(configDir, owner) {
73
+ const keys = generateKeyPair();
74
+ saveKeyPair(configDir, keys);
75
+ const identity = buildIdentityFromPublicKey(keys.publicKey, owner);
76
+ saveIdentity(configDir, identity);
77
+ return { identity, keys, status: "generated" };
78
+ }
79
+ function deriveAgentId(publicKeyHex) {
80
+ return createHash("sha256").update(publicKeyHex, "hex").digest("hex").slice(0, 16);
81
+ }
82
+ function loadIdentity(configDir) {
83
+ const filePath = join(configDir, IDENTITY_FILENAME);
84
+ if (!existsSync(filePath)) return null;
85
+ try {
86
+ const raw = readFileSync(filePath, "utf-8");
87
+ return AgentIdentitySchema.parse(JSON.parse(raw));
88
+ } catch {
89
+ return null;
90
+ }
91
+ }
92
+ function saveIdentity(configDir, identity) {
93
+ if (!existsSync(configDir)) {
94
+ mkdirSync(configDir, { recursive: true });
95
+ }
96
+ const filePath = join(configDir, IDENTITY_FILENAME);
97
+ writeFileSync(filePath, JSON.stringify(identity, null, 2), "utf-8");
98
+ }
99
+ function loadOrRepairIdentity(configDir, ownerHint) {
100
+ if (!existsSync(configDir)) {
101
+ mkdirSync(configDir, { recursive: true });
102
+ }
103
+ const identityPath = join(configDir, IDENTITY_FILENAME);
104
+ const privateKeyPath = join(configDir, PRIVATE_KEY_FILENAME);
105
+ const publicKeyPath = join(configDir, PUBLIC_KEY_FILENAME);
106
+ const hasIdentity = existsSync(identityPath);
107
+ const hasPrivateKey = existsSync(privateKeyPath);
108
+ const hasPublicKey = existsSync(publicKeyPath);
109
+ if (!hasIdentity || !hasPrivateKey || !hasPublicKey) {
110
+ return generateFreshIdentity(configDir, ownerHint ?? "agent");
111
+ }
112
+ let keys;
113
+ try {
114
+ keys = loadKeyPair(configDir);
115
+ } catch {
116
+ return generateFreshIdentity(configDir, ownerHint ?? "agent");
117
+ }
118
+ let derivedPublicKey;
119
+ try {
120
+ derivedPublicKey = derivePublicKeyFromPrivate(keys.privateKey);
121
+ } catch {
122
+ return generateFreshIdentity(configDir, ownerHint ?? "agent");
123
+ }
124
+ let keypairRepaired = false;
125
+ if (!keys.publicKey.equals(derivedPublicKey)) {
126
+ keypairRepaired = true;
127
+ keys = { privateKey: keys.privateKey, publicKey: derivedPublicKey };
128
+ saveKeyPair(configDir, keys);
129
+ }
130
+ const loadedIdentity = loadIdentity(configDir);
131
+ const expectedAgentId = deriveAgentId(derivedPublicKey.toString("hex"));
132
+ const expectedPublicKeyHex = derivedPublicKey.toString("hex");
133
+ const identityMismatch = !loadedIdentity || loadedIdentity.public_key !== expectedPublicKeyHex || loadedIdentity.agent_id !== expectedAgentId;
134
+ if (identityMismatch) {
135
+ const repairedIdentity = buildIdentityFromPublicKey(
136
+ derivedPublicKey,
137
+ loadedIdentity?.owner ?? ownerHint ?? "agent",
138
+ loadedIdentity?.created_at
139
+ );
140
+ saveIdentity(configDir, repairedIdentity);
141
+ return { identity: repairedIdentity, keys, status: "repaired" };
142
+ }
143
+ if (ownerHint && loadedIdentity.owner !== ownerHint) {
144
+ const updatedIdentity = { ...loadedIdentity, owner: ownerHint };
145
+ saveIdentity(configDir, updatedIdentity);
146
+ return { identity: updatedIdentity, keys, status: "repaired" };
147
+ }
148
+ return { identity: loadedIdentity, keys, status: keypairRepaired ? "repaired" : "existing" };
149
+ }
150
+ function ensureIdentity(configDir, owner) {
151
+ return loadOrRepairIdentity(configDir, owner).identity;
152
+ }
153
+
19
154
  // src/credit/local-credit-ledger.ts
20
155
  var LocalCreditLedger = class {
21
156
  constructor(db) {
@@ -91,11 +226,57 @@ var LocalCreditLedger = class {
91
226
 
92
227
  // src/registry/identity-auth.ts
93
228
  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) {
229
+ function normalizeSignedParams(body) {
230
+ return body === void 0 ? null : body;
231
+ }
232
+ function buildIdentityPayload(method, path, timestamp, publicKeyHex, agentId, params) {
233
+ return {
234
+ method,
235
+ path,
236
+ timestamp,
237
+ publicKey: publicKeyHex,
238
+ agentId,
239
+ params: normalizeSignedParams(params)
240
+ };
241
+ }
242
+ function extractClaimedRequester(request) {
243
+ const extractFromObject = (obj) => {
244
+ const directOwner = typeof obj.owner === "string" ? obj.owner.trim() : "";
245
+ if (directOwner) return directOwner;
246
+ const directRequester = typeof obj.requester === "string" ? obj.requester.trim() : "";
247
+ if (directRequester) return directRequester;
248
+ const oldOwner = typeof obj.oldOwner === "string" ? obj.oldOwner.trim() : "";
249
+ if (oldOwner) return oldOwner;
250
+ const nestedParams = obj.params;
251
+ if (nestedParams && typeof nestedParams === "object" && !Array.isArray(nestedParams)) {
252
+ const nested = nestedParams;
253
+ const nestedOwner = typeof nested.owner === "string" ? nested.owner.trim() : "";
254
+ if (nestedOwner) return nestedOwner;
255
+ const nestedRequester = typeof nested.requester === "string" ? nested.requester.trim() : "";
256
+ if (nestedRequester) return nestedRequester;
257
+ }
258
+ return null;
259
+ };
260
+ if (request.body && typeof request.body === "object" && !Array.isArray(request.body)) {
261
+ const claimed = extractFromObject(request.body);
262
+ if (claimed) return claimed;
263
+ }
264
+ if (request.params && typeof request.params === "object" && !Array.isArray(request.params)) {
265
+ const claimed = extractFromObject(request.params);
266
+ if (claimed) return claimed;
267
+ }
268
+ return null;
269
+ }
270
+ async function verifyIdentity(request, reply, options) {
271
+ const agentIdHeader = request.headers["x-agent-id"];
272
+ const publicKeyHeader = request.headers["x-agent-publickey"];
273
+ const signatureHeader = request.headers["x-agent-signature"];
274
+ const timestampHeader = request.headers["x-agent-timestamp"];
275
+ const agentId = agentIdHeader?.trim();
276
+ const publicKeyHex = publicKeyHeader?.trim();
277
+ const signature = signatureHeader?.trim();
278
+ const timestamp = timestampHeader?.trim();
279
+ if (!agentId || !publicKeyHex || !signature || !timestamp) {
99
280
  await reply.code(401).send({ error: "Missing identity headers" });
100
281
  return false;
101
282
  }
@@ -104,12 +285,21 @@ async function verifyIdentity(request, reply) {
104
285
  await reply.code(401).send({ error: "Request expired" });
105
286
  return false;
106
287
  }
107
- const payload = {
108
- method: request.method,
109
- path: request.url,
110
- timestamp,
111
- publicKey: publicKeyHex
112
- };
288
+ if (!/^[0-9a-fA-F]+$/.test(publicKeyHex) || publicKeyHex.length % 2 !== 0) {
289
+ await reply.code(401).send({ error: "Invalid identity signature" });
290
+ return false;
291
+ }
292
+ let expectedAgentId;
293
+ try {
294
+ expectedAgentId = deriveAgentId(publicKeyHex);
295
+ } catch {
296
+ await reply.code(401).send({ error: "Invalid identity signature" });
297
+ return false;
298
+ }
299
+ if (agentId !== expectedAgentId) {
300
+ await reply.code(401).send({ error: "Invalid identity signature" });
301
+ return false;
302
+ }
113
303
  let publicKeyBuffer;
114
304
  try {
115
305
  publicKeyBuffer = Buffer.from(publicKeyHex, "hex");
@@ -117,30 +307,52 @@ async function verifyIdentity(request, reply) {
117
307
  await reply.code(401).send({ error: "Invalid identity signature" });
118
308
  return false;
119
309
  }
310
+ const knownAgent = options.agentDb ? lookupAgent(options.agentDb, agentId) : null;
311
+ if (knownAgent && knownAgent.public_key.toLowerCase() !== publicKeyHex.toLowerCase()) {
312
+ await reply.code(401).send({ error: "Invalid identity signature" });
313
+ return false;
314
+ }
315
+ const payload = buildIdentityPayload(
316
+ request.method,
317
+ request.url,
318
+ timestamp,
319
+ publicKeyHex,
320
+ agentId,
321
+ request.body
322
+ );
120
323
  const valid = verifyEscrowReceipt(payload, signature, publicKeyBuffer);
121
324
  if (!valid) {
122
325
  await reply.code(401).send({ error: "Invalid identity signature" });
123
326
  return false;
124
327
  }
328
+ const claimedRequester = extractClaimedRequester(request);
329
+ if (claimedRequester) {
330
+ const matchesAgentId = claimedRequester === agentId;
331
+ const matchesLegacyOwner = knownAgent?.legacy_owner === claimedRequester;
332
+ if (!matchesAgentId && !matchesLegacyOwner) {
333
+ await reply.code(401).send({ error: "Identity does not match requester" });
334
+ return false;
335
+ }
336
+ }
125
337
  request.agentPublicKey = publicKeyHex;
338
+ request.agentId = agentId;
126
339
  return true;
127
340
  }
128
- function identityAuthPlugin(fastify) {
129
- fastify.addHook("onRequest", async (request, reply) => {
130
- await verifyIdentity(request, reply);
341
+ function identityAuthPlugin(fastify, options = {}) {
342
+ fastify.addHook("preHandler", async (request, reply) => {
343
+ const ok = await verifyIdentity(request, reply, options);
344
+ if (!ok) {
345
+ return reply;
346
+ }
131
347
  });
132
348
  }
133
- function signRequest(method, path, body, privateKey, publicKeyHex) {
349
+ function signRequest(method, path, body, privateKey, publicKeyHex, agentIdOverride) {
134
350
  const timestamp = (/* @__PURE__ */ new Date()).toISOString();
135
- const payload = {
136
- method,
137
- path,
138
- timestamp,
139
- publicKey: publicKeyHex
140
- };
141
- void body;
351
+ const agentId = agentIdOverride ?? deriveAgentId(publicKeyHex);
352
+ const payload = buildIdentityPayload(method, path, timestamp, publicKeyHex, agentId, body);
142
353
  const signature = signEscrowReceipt(payload, privateKey);
143
354
  return {
355
+ "X-Agent-Id": agentId,
144
356
  "X-Agent-PublicKey": publicKeyHex,
145
357
  "X-Agent-Signature": signature,
146
358
  "X-Agent-Timestamp": timestamp
@@ -368,6 +580,9 @@ function createLedger(opts) {
368
580
  }
369
581
 
370
582
  export {
583
+ deriveAgentId,
584
+ loadOrRepairIdentity,
585
+ ensureIdentity,
371
586
  identityAuthPlugin,
372
587
  createLedger
373
588
  };