agentbnb 9.1.0 → 9.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/README.md +29 -4
  2. package/dist/{card-VVT3XBOI.js → card-U2HQRPYN.js} +2 -1
  3. package/dist/{card-NQHAGTQQ.js → card-VVXNKHDX.js} +2 -1
  4. package/dist/{chunk-3Y76PHEY.js → chunk-53Q2HHHH.js} +154 -88
  5. package/dist/{chunk-5CC6O6SO.js → chunk-AA25Z6FW.js} +1 -1
  6. package/dist/{chunk-PIO2FMX4.js → chunk-B6AKTLXB.js} +5 -5
  7. package/dist/{chunk-VJ2Q33AP.js → chunk-BPPFY72X.js} +4 -0
  8. package/dist/{chunk-JKD6QRUD.js → chunk-C56X7EFJ.js} +4 -0
  9. package/dist/{chunk-PYZGF5QH.js → chunk-CMGJ52SX.js} +215 -98
  10. package/dist/{chunk-4DBSSFHG.js → chunk-EC6DIVE5.js} +3 -3
  11. package/dist/{chunk-4M6IAIVK.js → chunk-FK54LVDR.js} +2 -2
  12. package/dist/{chunk-JJHQAZWE.js → chunk-GGRH5PCD.js} +10 -10
  13. package/dist/chunk-GZUTU6IZ.js +153 -0
  14. package/dist/{chunk-W6LOCBWQ.js → chunk-IWAK4WHK.js} +1 -1
  15. package/dist/{chunk-ZYOMPJGG.js → chunk-KKFP5Y2Z.js} +2 -2
  16. package/dist/{chunk-XL5XD3IG.js → chunk-MPS4RE7T.js} +7 -7
  17. package/dist/{chunk-DBO2335D.js → chunk-MQIT2F5V.js} +8 -8
  18. package/dist/{chunk-GAZCZCAZ.js → chunk-RNALIVRR.js} +1 -1
  19. package/dist/{chunk-4UIUIHST.js → chunk-UPWAXWY2.js} +1 -1
  20. package/dist/{chunk-UXL7DV7P.js → chunk-V5TJXK3F.js} +3 -3
  21. package/dist/{chunk-AR7Z3EQB.js → chunk-WEZ7PSOE.js} +14 -14
  22. package/dist/{chunk-LENX5NUW.js → chunk-Z7XWQ63B.js} +55 -2
  23. package/dist/cli/index.js +76 -61
  24. package/dist/{client-XOSXFC7Q.js → client-KL67WZVJ.js} +2 -2
  25. package/dist/{conduct-VSSHJHVH.js → conduct-JRLLA4PB.js} +12 -11
  26. package/dist/{conduct-6C6JWZKZ.js → conduct-QLWXU2ZU.js} +12 -11
  27. package/dist/{conductor-mode-KKPSNN7V.js → conductor-mode-66IITI4I.js} +13 -12
  28. package/dist/{conductor-mode-NKHIZG4N.js → conductor-mode-PFO2VLH6.js} +14 -13
  29. package/dist/{credits-action-N3WB4WSI.js → credits-action-XERUEDF3.js} +6 -6
  30. package/dist/{did-action-3PNFYLX2.js → did-action-ODWTBVXL.js} +3 -3
  31. package/dist/{execute-QHP4KUV2.js → execute-NOQVN7ZG.js} +10 -9
  32. package/dist/{execute-IEQ3RV7I.js → execute-YBNCDAOX.js} +8 -7
  33. package/dist/index.js +350 -147
  34. package/dist/{openclaw-setup-PKGFB4IH.js → openclaw-setup-4RIZRMXA.js} +12 -11
  35. package/dist/{openclaw-skills-5VJDA6SX.js → openclaw-skills-TQ2JVBRM.js} +2 -2
  36. package/dist/provider-events-GTTJPYHS.js +13 -0
  37. package/dist/{publish-capability-CHMPZ6W3.js → publish-capability-2FMD3K6Z.js} +3 -2
  38. package/dist/{request-6TBVP3GR.js → request-EYN4CVXC.js} +12 -11
  39. package/dist/{serve-skill-BRUHUDRA.js → serve-skill-NWERGVH5.js} +13 -12
  40. package/dist/{server-N4BJW4TS.js → server-UPOPLZ24.js} +17 -16
  41. package/dist/{service-coordinator-M2CBDEUQ.js → service-coordinator-ZOZTW2U6.js} +419 -58
  42. package/dist/{session-action-67J57636.js → session-action-OSBZB4TX.js} +3 -3
  43. package/dist/signing-AQTKYJDB.js +16 -0
  44. package/dist/skills/agentbnb/bootstrap.js +426 -65
  45. package/dist/{store-A4YPEHDV.js → store-74EWU77V.js} +2 -1
  46. package/dist/{vc-action-TSAIABUM.js → vc-action-A6VBKERF.js} +3 -3
  47. package/package.json +3 -1
  48. package/dist/{chunk-YNBZLXYS.js → chunk-65GNX2KC.js} +0 -0
  49. package/dist/{daemon-OM2K3U7J.js → daemon-ETXXE4IS.js} +1 -1
@@ -1,13 +1,3 @@
1
- import {
2
- createLedger,
3
- deriveAgentId,
4
- ensureIdentity,
5
- executeCapabilityBatch,
6
- executeCapabilityRequest,
7
- identityAuthPlugin,
8
- loadOrRepairIdentity,
9
- syncCreditsFromRegistry
10
- } from "../../chunk-PYZGF5QH.js";
11
1
  import {
12
2
  AutoRequestor,
13
3
  BudgetController,
@@ -26,7 +16,19 @@ import {
26
16
  requestViaTemporaryRelay,
27
17
  resolvePendingRequest,
28
18
  verifyUCAN
29
- } from "../../chunk-DBO2335D.js";
19
+ } from "../../chunk-MQIT2F5V.js";
20
+ import {
21
+ createLedger,
22
+ deriveAgentId,
23
+ ensureIdentity,
24
+ executeCapabilityBatch,
25
+ executeCapabilityRequest,
26
+ identityAuthPlugin,
27
+ loadOrRepairIdentity,
28
+ notifyProviderEvent,
29
+ syncCreditsFromRegistry,
30
+ tryVerifyIdentity
31
+ } from "../../chunk-CMGJ52SX.js";
30
32
  import {
31
33
  NETWORK_FEE_RATE,
32
34
  bootstrapAgent,
@@ -47,18 +49,49 @@ import {
47
49
  releaseEscrow,
48
50
  searchCards,
49
51
  settleEscrow
50
- } from "../../chunk-XL5XD3IG.js";
52
+ } from "../../chunk-MPS4RE7T.js";
53
+ import {
54
+ attachCanonicalAgentId,
55
+ getCard,
56
+ getCardsBySkillCapability,
57
+ getEvolutionHistory,
58
+ getFeedbackForProvider,
59
+ getFeedbackForSkill,
60
+ getLatestEvolution,
61
+ insertCard,
62
+ insertEvolution,
63
+ insertFeedback,
64
+ listCards,
65
+ openDatabase,
66
+ updateCard,
67
+ updateSkillAvailability,
68
+ updateSkillIdleRate
69
+ } from "../../chunk-BPPFY72X.js";
70
+ import {
71
+ getActivityFeed,
72
+ getRequestLog,
73
+ getSkillRequestCount,
74
+ insertRequestLog
75
+ } from "../../chunk-4XTYT4JW.js";
76
+ import {
77
+ emitProviderEvent
78
+ } from "../../chunk-GZUTU6IZ.js";
51
79
  import "../../chunk-6QMDJVMS.js";
80
+ import "../../chunk-EE3V3DXK.js";
52
81
  import {
53
82
  requestCapability,
54
83
  requestViaRelay
55
- } from "../../chunk-W6LOCBWQ.js";
84
+ } from "../../chunk-IWAK4WHK.js";
56
85
  import {
57
86
  generateKeyPair,
58
87
  loadKeyPair,
59
88
  signEscrowReceipt,
60
89
  verifyEscrowReceipt
61
- } from "../../chunk-YNBZLXYS.js";
90
+ } from "../../chunk-65GNX2KC.js";
91
+ import {
92
+ AgentBnBError,
93
+ AnyCardSchema
94
+ } from "../../chunk-UVCNMRPS.js";
62
95
  import {
63
96
  RelayClient,
64
97
  RelayMessageSchema,
@@ -78,38 +111,10 @@ import {
78
111
  getConfigDir,
79
112
  loadConfig
80
113
  } from "../../chunk-IVOYM3WG.js";
81
- import {
82
- attachCanonicalAgentId,
83
- getCard,
84
- getCardsBySkillCapability,
85
- getEvolutionHistory,
86
- getFeedbackForProvider,
87
- getFeedbackForSkill,
88
- getLatestEvolution,
89
- insertCard,
90
- insertEvolution,
91
- insertFeedback,
92
- listCards,
93
- openDatabase,
94
- updateCard,
95
- updateSkillAvailability,
96
- updateSkillIdleRate
97
- } from "../../chunk-VJ2Q33AP.js";
98
- import {
99
- getActivityFeed,
100
- getRequestLog,
101
- getSkillRequestCount,
102
- insertRequestLog
103
- } from "../../chunk-4XTYT4JW.js";
104
- import "../../chunk-EE3V3DXK.js";
105
- import {
106
- AgentBnBError,
107
- AnyCardSchema
108
- } from "../../chunk-UVCNMRPS.js";
109
114
  import "../../chunk-3RG5ZIWI.js";
110
115
 
111
116
  // skills/agentbnb/bootstrap.ts
112
- import { join as join6, basename as basename2, dirname as dirname4 } from "path";
117
+ import { join as join6, basename as basename3, dirname as dirname4 } from "path";
113
118
  import { existsSync as existsSync7, writeFileSync as writeFileSync2 } from "fs";
114
119
  import { homedir as homedir4 } from "os";
115
120
  import { exec } from "child_process";
@@ -287,7 +292,7 @@ function isPidFileContent(value) {
287
292
  }
288
293
 
289
294
  // src/runtime/agent-runtime.ts
290
- import { readFileSync as readFileSync2, existsSync as existsSync2 } from "fs";
295
+ import { readFileSync as readFileSync3, existsSync as existsSync2 } from "fs";
291
296
 
292
297
  // src/skills/executor.ts
293
298
  function buildTimeoutError(skillId, timeoutMs) {
@@ -1100,7 +1105,30 @@ var OpenClawBridge = class {
1100
1105
 
1101
1106
  // src/skills/command-executor.ts
1102
1107
  import { spawn } from "child_process";
1108
+ import { readFileSync as readFileSync2, statSync } from "fs";
1109
+ import { basename, extname } from "path";
1103
1110
  var KILL_GRACE_MS = 5e3;
1111
+ var MAX_INLINE_FILE_BYTES = 5 * 1024 * 1024;
1112
+ var MIME_TYPES = {
1113
+ ".mp3": "audio/mpeg",
1114
+ ".wav": "audio/wav",
1115
+ ".ogg": "audio/ogg",
1116
+ ".m4a": "audio/mp4",
1117
+ ".pdf": "application/pdf",
1118
+ ".png": "image/png",
1119
+ ".jpg": "image/jpeg",
1120
+ ".jpeg": "image/jpeg",
1121
+ ".gif": "image/gif",
1122
+ ".webp": "image/webp",
1123
+ ".svg": "image/svg+xml",
1124
+ ".json": "application/json",
1125
+ ".txt": "text/plain",
1126
+ ".md": "text/markdown",
1127
+ ".csv": "text/csv"
1128
+ };
1129
+ function guessMimeType(filePath) {
1130
+ return MIME_TYPES[extname(filePath).toLowerCase()] ?? "application/octet-stream";
1131
+ }
1104
1132
  function shellEscape2(value) {
1105
1133
  return "'" + value.replace(/'/g, "'\\''") + "'";
1106
1134
  }
@@ -1316,8 +1344,34 @@ var CommandExecutor = class {
1316
1344
  };
1317
1345
  }
1318
1346
  }
1319
- case "file":
1320
- return { success: true, result: { file_path: rawOutput } };
1347
+ case "file": {
1348
+ try {
1349
+ const stats = statSync(rawOutput);
1350
+ if (stats.size > MAX_INLINE_FILE_BYTES) {
1351
+ return {
1352
+ success: false,
1353
+ error: `File too large for inline return: ${stats.size} bytes (max ${MAX_INLINE_FILE_BYTES})`
1354
+ };
1355
+ }
1356
+ const buffer = readFileSync2(rawOutput);
1357
+ return {
1358
+ success: true,
1359
+ result: {
1360
+ file: {
1361
+ name: basename(rawOutput),
1362
+ mime_type: guessMimeType(rawOutput),
1363
+ size_bytes: stats.size,
1364
+ data_base64: buffer.toString("base64")
1365
+ },
1366
+ // Keep file_path for backward compat (local workflows)
1367
+ file_path: rawOutput
1368
+ }
1369
+ };
1370
+ } catch (err) {
1371
+ const msg = err instanceof Error ? err.message : String(err);
1372
+ return { success: false, error: `Failed to read file "${rawOutput}": ${msg}` };
1373
+ }
1374
+ }
1321
1375
  default:
1322
1376
  return {
1323
1377
  success: false,
@@ -1446,13 +1500,13 @@ var AgentRuntime = class {
1446
1500
  }
1447
1501
  let configs = [];
1448
1502
  if (hasSkillsYaml) {
1449
- const yamlContent = readFileSync2(this.skillsYamlPath, "utf8");
1503
+ const yamlContent = readFileSync3(this.skillsYamlPath, "utf8");
1450
1504
  configs = parseSkillsFile(yamlContent);
1451
1505
  }
1452
1506
  const modes = /* @__PURE__ */ new Map();
1453
1507
  if (this.conductorEnabled) {
1454
- const { ConductorMode } = await import("../../conductor-mode-KKPSNN7V.js");
1455
- const { registerConductorCard, CONDUCTOR_OWNER } = await import("../../card-VVT3XBOI.js");
1508
+ const { ConductorMode } = await import("../../conductor-mode-66IITI4I.js");
1509
+ const { registerConductorCard, CONDUCTOR_OWNER } = await import("../../card-U2HQRPYN.js");
1456
1510
  const { loadPeers: loadPeers2 } = await import("../../peers-IOVCBWAI.js");
1457
1511
  registerConductorCard(this.registryDb);
1458
1512
  const resolveAgentUrl = (owner) => {
@@ -2517,12 +2571,14 @@ var SessionManager = class {
2517
2571
  escrow;
2518
2572
  config;
2519
2573
  sendToAgent;
2574
+ registryDb;
2520
2575
  /** Maps agent connection key → set of session IDs they participate in. */
2521
2576
  agentSessions = /* @__PURE__ */ new Map();
2522
2577
  constructor(opts) {
2523
2578
  this.escrow = new SessionEscrow(opts.creditDb);
2524
2579
  this.config = opts.config ?? loadSessionConfig();
2525
2580
  this.sendToAgent = opts.sendToAgent;
2581
+ this.registryDb = opts.registryDb ?? null;
2526
2582
  }
2527
2583
  /**
2528
2584
  * Open a new session between requester and provider.
@@ -2581,6 +2637,15 @@ var SessionManager = class {
2581
2637
  }
2582
2638
  this.resetIdleTimer(session.id);
2583
2639
  this.startDurationTimer(session.id);
2640
+ this.emitEvent({
2641
+ event_type: "session.opened",
2642
+ skill_id: session.skill_id,
2643
+ session_id: session.id,
2644
+ requester: session.requester_id,
2645
+ credits: session.budget,
2646
+ duration_ms: 0,
2647
+ metadata: { engine: "session", pricing_model: session.pricing_model }
2648
+ });
2584
2649
  return session;
2585
2650
  }
2586
2651
  /**
@@ -2641,6 +2706,15 @@ var SessionManager = class {
2641
2706
  content: msg.content,
2642
2707
  metadata: msg.metadata
2643
2708
  });
2709
+ this.emitEvent({
2710
+ event_type: "session.message",
2711
+ skill_id: session.skill_id,
2712
+ session_id: session.id,
2713
+ requester: session.requester_id,
2714
+ credits: session.spent,
2715
+ duration_ms: Date.now() - new Date(session.created_at).getTime(),
2716
+ metadata: { message_count: session.messages.length, running_cost: session.spent, sender: msg.sender }
2717
+ });
2644
2718
  this.resetIdleTimer(session.id);
2645
2719
  }
2646
2720
  /**
@@ -2684,6 +2758,19 @@ var SessionManager = class {
2684
2758
  this.durationTimers.clear();
2685
2759
  }
2686
2760
  // -------------------------------------------------------------------------
2761
+ // Event emission
2762
+ // -------------------------------------------------------------------------
2763
+ /** Emit a provider event + Telegram notification. Silently no-ops on failure. */
2764
+ emitEvent(event) {
2765
+ if (!this.registryDb) return;
2766
+ try {
2767
+ const emitted = emitProviderEvent(this.registryDb, event);
2768
+ notifyProviderEvent(emitted).catch(() => {
2769
+ });
2770
+ } catch {
2771
+ }
2772
+ }
2773
+ // -------------------------------------------------------------------------
2687
2774
  // Internal helpers
2688
2775
  // -------------------------------------------------------------------------
2689
2776
  endSessionInternal(session, reason) {
@@ -2707,6 +2794,27 @@ var SessionManager = class {
2707
2794
  };
2708
2795
  session.status = "settled";
2709
2796
  session.updated_at = (/* @__PURE__ */ new Date()).toISOString();
2797
+ const isFailed = reason === "error";
2798
+ const eventMetadata = {
2799
+ total_messages: session.messages.length,
2800
+ reason,
2801
+ refunded: session.budget - session.spent
2802
+ };
2803
+ if (isFailed) {
2804
+ eventMetadata["last_messages"] = session.messages.slice(-3).map((m) => ({
2805
+ sender: m.sender,
2806
+ content: m.content.slice(0, 200)
2807
+ }));
2808
+ }
2809
+ this.emitEvent({
2810
+ event_type: isFailed ? "session.failed" : "session.ended",
2811
+ skill_id: session.skill_id,
2812
+ session_id: session.id,
2813
+ requester: session.requester_id,
2814
+ credits: session.spent,
2815
+ duration_ms: durationMs,
2816
+ metadata: eventMetadata
2817
+ });
2710
2818
  this.sendToAgent(session.requester_id, settledMsg);
2711
2819
  this.sendToAgent(session.provider_id, settledMsg);
2712
2820
  session.status = "closed";
@@ -3669,6 +3777,75 @@ function initiateGithubAuth() {
3669
3777
  };
3670
3778
  }
3671
3779
 
3780
+ // src/registry/hub-identities.ts
3781
+ import { randomBytes as randomBytes2, createHash } from "crypto";
3782
+ var HUB_IDENTITIES_SCHEMA = `
3783
+ CREATE TABLE IF NOT EXISTS hub_identities (
3784
+ email TEXT PRIMARY KEY,
3785
+ agent_id TEXT NOT NULL UNIQUE,
3786
+ public_key TEXT NOT NULL,
3787
+ encrypted_private_key TEXT NOT NULL,
3788
+ kdf_salt TEXT NOT NULL,
3789
+ display_name TEXT NOT NULL,
3790
+ created_at TEXT NOT NULL
3791
+ );
3792
+
3793
+ CREATE INDEX IF NOT EXISTS idx_hub_identities_agent_id
3794
+ ON hub_identities(agent_id);
3795
+ `;
3796
+ var CHALLENGES_SCHEMA = `
3797
+ CREATE TABLE IF NOT EXISTS hub_challenges (
3798
+ challenge TEXT PRIMARY KEY,
3799
+ expires_at TEXT NOT NULL,
3800
+ consumed_at TEXT
3801
+ );
3802
+ `;
3803
+ function ensureHubIdentitiesTables(db) {
3804
+ db.exec(HUB_IDENTITIES_SCHEMA);
3805
+ db.exec(CHALLENGES_SCHEMA);
3806
+ }
3807
+ function deriveAgentId2(publicKeyHex) {
3808
+ const hash = createHash("sha256").update(publicKeyHex, "hex").digest("hex");
3809
+ return `agent-${hash.slice(0, 16)}`;
3810
+ }
3811
+ var CHALLENGE_TTL_MS = 10 * 60 * 1e3;
3812
+ function createChallenge(db) {
3813
+ const challenge = randomBytes2(32).toString("hex");
3814
+ const expires_at = new Date(Date.now() + CHALLENGE_TTL_MS).toISOString();
3815
+ db.prepare("INSERT INTO hub_challenges (challenge, expires_at) VALUES (?, ?)").run(challenge, expires_at);
3816
+ return { challenge, expires_at };
3817
+ }
3818
+ function consumeChallenge(db, challenge) {
3819
+ const row = db.prepare("SELECT expires_at, consumed_at FROM hub_challenges WHERE challenge = ?").get(challenge);
3820
+ if (!row) return false;
3821
+ if (row.consumed_at) return false;
3822
+ if (new Date(row.expires_at).getTime() < Date.now()) return false;
3823
+ const consumed_at = (/* @__PURE__ */ new Date()).toISOString();
3824
+ db.prepare("UPDATE hub_challenges SET consumed_at = ? WHERE challenge = ?").run(consumed_at, challenge);
3825
+ return true;
3826
+ }
3827
+ function pruneChallenges(db) {
3828
+ const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1e3).toISOString();
3829
+ db.prepare("DELETE FROM hub_challenges WHERE expires_at < ? OR consumed_at IS NOT NULL").run(cutoff);
3830
+ }
3831
+ function registerHubIdentity(db, input) {
3832
+ const agent_id = deriveAgentId2(input.public_key);
3833
+ const created_at = (/* @__PURE__ */ new Date()).toISOString();
3834
+ db.prepare(`
3835
+ INSERT INTO hub_identities (email, agent_id, public_key, encrypted_private_key, kdf_salt, display_name, created_at)
3836
+ VALUES (?, ?, ?, ?, ?, ?, ?)
3837
+ `).run(input.email, agent_id, input.public_key, input.encrypted_private_key, input.kdf_salt, input.display_name, created_at);
3838
+ return { ...input, agent_id, created_at };
3839
+ }
3840
+ function getHubIdentityByEmail(db, email) {
3841
+ const row = db.prepare("SELECT * FROM hub_identities WHERE email = ?").get(email);
3842
+ return row ?? null;
3843
+ }
3844
+ function getHubIdentityByAgentId(db, agent_id) {
3845
+ const row = db.prepare("SELECT * FROM hub_identities WHERE agent_id = ?").get(agent_id);
3846
+ return row ?? null;
3847
+ }
3848
+
3672
3849
  // src/registry/free-tier.ts
3673
3850
  function initFreeTierTable(db) {
3674
3851
  db.exec(`
@@ -5698,6 +5875,121 @@ function createRegistryServer(opts) {
5698
5875
  throw err;
5699
5876
  }
5700
5877
  });
5878
+ ensureHubIdentitiesTables(db);
5879
+ try {
5880
+ pruneChallenges(db);
5881
+ } catch {
5882
+ }
5883
+ api.get("/api/agents/challenge", {
5884
+ schema: {
5885
+ tags: ["hub-auth"],
5886
+ summary: "Get a registration challenge",
5887
+ response: {
5888
+ 200: {
5889
+ type: "object",
5890
+ properties: {
5891
+ challenge: { type: "string" },
5892
+ expires_at: { type: "string" }
5893
+ }
5894
+ }
5895
+ }
5896
+ }
5897
+ }, async (_request, reply) => {
5898
+ const { challenge, expires_at } = createChallenge(db);
5899
+ return reply.send({ challenge, expires_at });
5900
+ });
5901
+ api.post("/api/agents/register", {
5902
+ schema: {
5903
+ tags: ["hub-auth"],
5904
+ summary: "Register a new Hub-managed agent identity",
5905
+ body: {
5906
+ type: "object",
5907
+ required: ["email", "public_key", "encrypted_private_key", "kdf_salt", "display_name", "challenge", "signature"],
5908
+ properties: {
5909
+ email: { type: "string", format: "email" },
5910
+ public_key: { type: "string" },
5911
+ encrypted_private_key: { type: "string" },
5912
+ kdf_salt: { type: "string" },
5913
+ display_name: { type: "string" },
5914
+ challenge: { type: "string" },
5915
+ signature: { type: "string" }
5916
+ }
5917
+ },
5918
+ response: {
5919
+ 201: { type: "object", additionalProperties: true },
5920
+ 400: { type: "object", properties: { error: { type: "string" } } },
5921
+ 409: { type: "object", properties: { error: { type: "string" } } }
5922
+ }
5923
+ }
5924
+ }, async (request, reply) => {
5925
+ const body = request.body;
5926
+ if (!consumeChallenge(db, body.challenge)) {
5927
+ return reply.code(400).send({ error: "Invalid or expired challenge" });
5928
+ }
5929
+ if (!/^[0-9a-fA-F]+$/.test(body.public_key) || body.public_key.length % 2 !== 0) {
5930
+ return reply.code(400).send({ error: "Invalid public_key format" });
5931
+ }
5932
+ try {
5933
+ const { verifyEscrowReceipt: verifyEscrowReceipt2 } = await import("../../signing-AQTKYJDB.js");
5934
+ const publicKeyBuffer = Buffer.from(body.public_key, "hex");
5935
+ const valid = verifyEscrowReceipt2({ challenge: body.challenge }, body.signature, publicKeyBuffer);
5936
+ if (!valid) {
5937
+ return reply.code(400).send({ error: "Invalid signature" });
5938
+ }
5939
+ } catch (err) {
5940
+ const msg = err instanceof Error ? err.message : String(err);
5941
+ return reply.code(400).send({ error: `Signature verification failed: ${msg}` });
5942
+ }
5943
+ const existing = getHubIdentityByEmail(db, body.email.toLowerCase());
5944
+ if (existing) {
5945
+ return reply.code(409).send({ error: "Email already registered" });
5946
+ }
5947
+ const agent_id = deriveAgentId2(body.public_key);
5948
+ const existingByAgentId = getHubIdentityByAgentId(db, agent_id);
5949
+ if (existingByAgentId) {
5950
+ return reply.code(409).send({ error: "Agent already registered" });
5951
+ }
5952
+ const identity = registerHubIdentity(db, {
5953
+ email: body.email.toLowerCase(),
5954
+ public_key: body.public_key,
5955
+ encrypted_private_key: body.encrypted_private_key,
5956
+ kdf_salt: body.kdf_salt,
5957
+ display_name: body.display_name
5958
+ });
5959
+ return reply.code(201).send({
5960
+ agent_id: identity.agent_id,
5961
+ did: `did:agentbnb:${identity.agent_id}`,
5962
+ created_at: identity.created_at
5963
+ });
5964
+ });
5965
+ api.post("/api/agents/login", {
5966
+ schema: {
5967
+ tags: ["hub-auth"],
5968
+ summary: "Fetch encrypted identity blob for login",
5969
+ body: {
5970
+ type: "object",
5971
+ required: ["email"],
5972
+ properties: { email: { type: "string", format: "email" } }
5973
+ },
5974
+ response: {
5975
+ 200: { type: "object", additionalProperties: true },
5976
+ 404: { type: "object", properties: { error: { type: "string" } } }
5977
+ }
5978
+ }
5979
+ }, async (request, reply) => {
5980
+ const body = request.body;
5981
+ const identity = getHubIdentityByEmail(db, body.email.toLowerCase());
5982
+ if (!identity) {
5983
+ return reply.code(404).send({ error: "Identity not found" });
5984
+ }
5985
+ return reply.send({
5986
+ agent_id: identity.agent_id,
5987
+ public_key: identity.public_key,
5988
+ encrypted_private_key: identity.encrypted_private_key,
5989
+ kdf_salt: identity.kdf_salt,
5990
+ display_name: identity.display_name
5991
+ });
5992
+ });
5701
5993
  api.post("/api/identity/link", {
5702
5994
  schema: {
5703
5995
  tags: ["identity"],
@@ -5997,7 +6289,7 @@ function createRegistryServer(opts) {
5997
6289
  });
5998
6290
  await relayClient.connect();
5999
6291
  }
6000
- const { requestViaRelay: requestViaRelay2 } = await import("../../client-XOSXFC7Q.js");
6292
+ const { requestViaRelay: requestViaRelay2 } = await import("../../client-KL67WZVJ.js");
6001
6293
  return requestViaRelay2(relayClient, {
6002
6294
  targetOwner: target.owner,
6003
6295
  cardId: target.cardId,
@@ -6016,12 +6308,24 @@ function createRegistryServer(opts) {
6016
6308
  const ownerApiKey = opts.ownerApiKey;
6017
6309
  const ownerName = opts.ownerName;
6018
6310
  void api.register(async (ownerRoutes) => {
6019
- ownerRoutes.addHook("onRequest", async (request, reply) => {
6311
+ ownerRoutes.addHook("preHandler", async (request, reply) => {
6020
6312
  const auth = request.headers.authorization;
6021
6313
  const token = auth?.startsWith("Bearer ") ? auth.slice(7).trim() : null;
6022
- if (!token || token !== ownerApiKey) {
6023
- return reply.status(401).send({ error: "Unauthorized" });
6314
+ if (token === ownerApiKey) {
6315
+ request.agentId = ownerName;
6316
+ return;
6317
+ }
6318
+ const didResult = await tryVerifyIdentity(request, {});
6319
+ if (didResult.valid) {
6320
+ const hubIdentity = getHubIdentityByAgentId(db, didResult.agentId);
6321
+ if (!hubIdentity) {
6322
+ return reply.status(401).send({ error: "Agent not registered on this Hub" });
6323
+ }
6324
+ request.agentId = didResult.agentId;
6325
+ request.agentPublicKey = didResult.publicKey;
6326
+ return;
6024
6327
  }
6328
+ return reply.status(401).send({ error: "Unauthorized" });
6025
6329
  });
6026
6330
  ownerRoutes.get("/me", {
6027
6331
  schema: {
@@ -6032,13 +6336,14 @@ function createRegistryServer(opts) {
6032
6336
  200: { type: "object", properties: { owner: { type: "string" }, balance: { type: "number" } } }
6033
6337
  }
6034
6338
  }
6035
- }, async (_request, reply) => {
6339
+ }, async (request, reply) => {
6340
+ const identity = request.agentId ?? ownerName;
6036
6341
  let balance = 0;
6037
6342
  if (opts.creditDb) {
6038
6343
  const ledger = createLedger({ db: opts.creditDb });
6039
- balance = await ledger.getBalance(ownerName);
6344
+ balance = await ledger.getBalance(identity);
6040
6345
  }
6041
- return reply.send({ owner: ownerName, balance });
6346
+ return reply.send({ owner: identity, balance });
6042
6347
  });
6043
6348
  ownerRoutes.get("/requests", {
6044
6349
  schema: {
@@ -6225,6 +6530,62 @@ function createRegistryServer(opts) {
6225
6530
  const items = await ledger.getHistory(ownerName, limit);
6226
6531
  return reply.send({ items, limit });
6227
6532
  });
6533
+ ownerRoutes.get("/me/events", {
6534
+ schema: {
6535
+ tags: ["owner"],
6536
+ summary: "Provider event stream",
6537
+ security: [{ bearerAuth: [] }],
6538
+ querystring: {
6539
+ type: "object",
6540
+ properties: {
6541
+ limit: { type: "integer", description: "Max entries (default 50)" },
6542
+ since: { type: "string", description: "ISO timestamp for cursor-based polling" },
6543
+ event_type: { type: "string", description: "Filter by event type" }
6544
+ }
6545
+ }
6546
+ }
6547
+ }, async (request, reply) => {
6548
+ const { getProviderEvents: getEvents } = await import("../../provider-events-GTTJPYHS.js");
6549
+ const query = request.query;
6550
+ const limit = query.limit ? parseInt(query.limit, 10) : void 0;
6551
+ const events = getEvents(db, {
6552
+ limit,
6553
+ since: query.since,
6554
+ event_type: query.event_type
6555
+ });
6556
+ return reply.send({ events });
6557
+ });
6558
+ ownerRoutes.get("/me/stats", {
6559
+ schema: {
6560
+ tags: ["owner"],
6561
+ summary: "Aggregated provider stats",
6562
+ security: [{ bearerAuth: [] }],
6563
+ querystring: {
6564
+ type: "object",
6565
+ properties: { period: { type: "string", enum: ["24h", "7d", "30d"] } }
6566
+ }
6567
+ }
6568
+ }, async (request, reply) => {
6569
+ const { getProviderStats: getStats } = await import("../../provider-events-GTTJPYHS.js");
6570
+ const query = request.query;
6571
+ const period = query.period ?? "7d";
6572
+ const stats = getStats(db, period);
6573
+ if (opts.creditDb) {
6574
+ const periodMs = { "24h": 864e5, "7d": 6048e5, "30d": 2592e6 }[period];
6575
+ const cutoff = new Date(Date.now() - periodMs).toISOString();
6576
+ try {
6577
+ const row = opts.creditDb.prepare(`
6578
+ SELECT COALESCE(SUM(CASE WHEN amount < 0 AND reason IN ('escrow_hold', 'voucher_hold', 'network_fee') THEN -amount ELSE 0 END), 0) as spent
6579
+ FROM credit_transactions
6580
+ WHERE owner = ? AND created_at >= ?
6581
+ `).get(ownerName, cutoff);
6582
+ stats.total_spending = row?.spent ?? 0;
6583
+ stats.net_pnl = stats.total_earnings - stats.total_spending;
6584
+ } catch {
6585
+ }
6586
+ }
6587
+ return reply.send(stats);
6588
+ });
6228
6589
  });
6229
6590
  }
6230
6591
  api.get("/api/providers/:owner/reliability", {
@@ -6469,7 +6830,7 @@ import { execFileSync } from "child_process";
6469
6830
  import { existsSync as existsSync4, realpathSync } from "fs";
6470
6831
  import { createRequire } from "module";
6471
6832
  import { homedir as homedir2 } from "os";
6472
- import { basename, dirname as dirname3, isAbsolute, join as join3, resolve } from "path";
6833
+ import { basename as basename2, dirname as dirname3, isAbsolute, join as join3, resolve } from "path";
6473
6834
  function resolveSelfCli() {
6474
6835
  const require2 = createRequire(import.meta.url);
6475
6836
  return resolveSelfCliWithDeps({
@@ -6587,7 +6948,7 @@ function getPnpmGlobalCandidates(platform, homeDir) {
6587
6948
  }
6588
6949
  function looksLikeAgentbnbCli(path) {
6589
6950
  const normalized = path.replace(/\\/g, "/").toLowerCase();
6590
- const fileName = basename(normalized);
6951
+ const fileName = basename2(normalized);
6591
6952
  if (fileName === "agentbnb" || fileName === "agentbnb.cmd" || fileName === "agentbnb.exe") {
6592
6953
  return true;
6593
6954
  }
@@ -6600,7 +6961,7 @@ function extractErrorMessage(err) {
6600
6961
 
6601
6962
  // src/runtime/service-coordinator.ts
6602
6963
  import { spawn as spawn2 } from "child_process";
6603
- import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
6964
+ import { existsSync as existsSync5, readFileSync as readFileSync4 } from "fs";
6604
6965
  import { join as join4 } from "path";
6605
6966
  import { randomUUID as randomUUID9 } from "crypto";
6606
6967
  import { Cron as Cron2 } from "croner";
@@ -6775,7 +7136,7 @@ var ServiceCoordinator = class {
6775
7136
  console.log("Conductor mode enabled \u2014 orchestrate/plan skills available via gateway");
6776
7137
  }
6777
7138
  if (opts.conductorEnabled && this.config.conductor?.public) {
6778
- const { buildConductorCard } = await import("../../card-VVT3XBOI.js");
7139
+ const { buildConductorCard } = await import("../../card-U2HQRPYN.js");
6779
7140
  const conductorCard = attachCanonicalAgentId(
6780
7141
  this.runtime.registryDb,
6781
7142
  buildConductorCard(this.config.owner)
@@ -6852,7 +7213,7 @@ var ServiceCoordinator = class {
6852
7213
  }
6853
7214
  if (opts.registryUrl && opts.relay) {
6854
7215
  const { RelayClient: RelayClient2 } = await import("../../websocket-client-RT4KLJL4.js");
6855
- const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../../execute-IEQ3RV7I.js");
7216
+ const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../../execute-YBNCDAOX.js");
6856
7217
  const localCards = listCards(this.runtime.registryDb, this.config.owner);
6857
7218
  const { primaryCard, additionalCards } = buildRelayRegistrationCards(this.config.owner, localCards);
6858
7219
  if (this.config.conductor?.public) {
@@ -7113,7 +7474,7 @@ function loadPersistedRuntime(configDir) {
7113
7474
  const runtimePath = join4(configDir, "runtime.json");
7114
7475
  if (!existsSync5(runtimePath)) return null;
7115
7476
  try {
7116
- const raw = readFileSync3(runtimePath, "utf8");
7477
+ const raw = readFileSync4(runtimePath, "utf8");
7117
7478
  const parsed = JSON.parse(raw);
7118
7479
  const nodeExec = parsed["node_exec"];
7119
7480
  if (typeof nodeExec !== "string" || nodeExec.trim().length === 0) {
@@ -7530,7 +7891,7 @@ function isNetworkError(err) {
7530
7891
  }
7531
7892
 
7532
7893
  // skills/agentbnb/openclaw-tools.ts
7533
- import { readFileSync as readFileSync4, existsSync as existsSync6 } from "fs";
7894
+ import { readFileSync as readFileSync5, existsSync as existsSync6 } from "fs";
7534
7895
  import { join as join5 } from "path";
7535
7896
  import { homedir as homedir3 } from "os";
7536
7897
 
@@ -8119,7 +8480,7 @@ function buildMcpContext(toolCtx) {
8119
8480
  `AgentBnB not initialized at ${configDir}. Run \`agentbnb init\` or activate the plugin first.`
8120
8481
  );
8121
8482
  }
8122
- const config = JSON.parse(readFileSync4(configPath, "utf-8"));
8483
+ const config = JSON.parse(readFileSync5(configPath, "utf-8"));
8123
8484
  const identity = ensureIdentity(configDir, config.owner);
8124
8485
  const ctx = { configDir, config, identity };
8125
8486
  contextCache.set(configDir, ctx);
@@ -8358,7 +8719,7 @@ async function runCommand(cmd, env) {
8358
8719
  return execAsync(cmd, { env });
8359
8720
  }
8360
8721
  function deriveAgentName(configDir) {
8361
- const parent = basename2(dirname4(configDir));
8722
+ const parent = basename3(dirname4(configDir));
8362
8723
  if (parent && parent !== "." && parent !== ".agentbnb" && parent !== homedir4().split("/").pop()) {
8363
8724
  return parent;
8364
8725
  }