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,3 +1,11 @@
1
+ import {
2
+ executeCapabilityBatch,
3
+ executeCapabilityRequest,
4
+ notifyProviderEvent
5
+ } from "./chunk-53Q2HHHH.js";
6
+ import {
7
+ StructuredFeedbackSchema
8
+ } from "./chunk-AUBHR7HH.js";
1
9
  import {
2
10
  ApiSkillConfigSchema,
3
11
  parseSkillsFile
@@ -9,17 +17,13 @@ import {
9
17
  import {
10
18
  interpolateObject
11
19
  } from "./chunk-3MJT4PZG.js";
12
- import {
13
- executeCapabilityBatch,
14
- executeCapabilityRequest
15
- } from "./chunk-3Y76PHEY.js";
16
- import {
17
- StructuredFeedbackSchema
18
- } from "./chunk-AUBHR7HH.js";
19
20
  import {
20
21
  announceGateway,
21
22
  stopAnnouncement
22
23
  } from "./chunk-TA73FIZU.js";
24
+ import {
25
+ syncCreditsFromRegistry
26
+ } from "./chunk-KKFP5Y2Z.js";
23
27
  import {
24
28
  resolveSelfCli
25
29
  } from "./chunk-7S4ZLFVI.js";
@@ -28,34 +32,32 @@ import {
28
32
  buildDraftCard,
29
33
  detectApiKeys,
30
34
  getPricingStats
31
- } from "./chunk-4UIUIHST.js";
35
+ } from "./chunk-UPWAXWY2.js";
36
+ import {
37
+ createLedger,
38
+ identityAuthPlugin,
39
+ tryVerifyIdentity
40
+ } from "./chunk-Z7XWQ63B.js";
41
+ import {
42
+ deriveAgentId
43
+ } from "./chunk-AA25Z6FW.js";
32
44
  import {
33
45
  listPendingRequests,
34
46
  resolvePendingRequest
35
47
  } from "./chunk-5PV5YCSN.js";
48
+ import "./chunk-FK54LVDR.js";
49
+ import "./chunk-ELFGYC22.js";
36
50
  import {
37
51
  DEFAULT_AUTONOMY_CONFIG,
38
52
  getAutonomyTier,
39
53
  insertAuditEvent
40
54
  } from "./chunk-G5WKW3ED.js";
41
- import {
42
- syncCreditsFromRegistry
43
- } from "./chunk-ZYOMPJGG.js";
44
- import {
45
- createLedger,
46
- identityAuthPlugin
47
- } from "./chunk-LENX5NUW.js";
48
- import {
49
- deriveAgentId
50
- } from "./chunk-5CC6O6SO.js";
51
- import "./chunk-4M6IAIVK.js";
52
- import "./chunk-ELFGYC22.js";
53
55
  import {
54
56
  buildReputationMap,
55
57
  computeReputation,
56
58
  filterCards,
57
59
  searchCards
58
- } from "./chunk-4DBSSFHG.js";
60
+ } from "./chunk-EC6DIVE5.js";
59
61
  import {
60
62
  NETWORK_FEE_RATE,
61
63
  bootstrapAgent,
@@ -70,25 +72,6 @@ import {
70
72
  releaseEscrow,
71
73
  settleEscrow
72
74
  } from "./chunk-D7NH6YLM.js";
73
- import {
74
- RelayMessageSchema,
75
- SESSION_MESSAGE_TYPES,
76
- SessionEndMessageSchema,
77
- SessionMessageMessageSchema,
78
- SessionOpenMessageSchema,
79
- loadSessionConfig
80
- } from "./chunk-Q5OFZ2JR.js";
81
- import {
82
- loadCoreConfig
83
- } from "./chunk-QXRNW4OJ.js";
84
- import {
85
- generateKeyPair,
86
- verifyEscrowReceipt
87
- } from "./chunk-YNBZLXYS.js";
88
- import "./chunk-YDGXKH2T.js";
89
- import {
90
- getConfigDir
91
- } from "./chunk-3XPBFF6H.js";
92
75
  import {
93
76
  attachCanonicalAgentId,
94
77
  getCard,
@@ -105,12 +88,34 @@ import {
105
88
  updateCard,
106
89
  updateSkillAvailability,
107
90
  updateSkillIdleRate
108
- } from "./chunk-JKD6QRUD.js";
91
+ } from "./chunk-C56X7EFJ.js";
92
+ import {
93
+ emitProviderEvent
94
+ } from "./chunk-GZUTU6IZ.js";
95
+ import {
96
+ RelayMessageSchema,
97
+ SESSION_MESSAGE_TYPES,
98
+ SessionEndMessageSchema,
99
+ SessionMessageMessageSchema,
100
+ SessionOpenMessageSchema,
101
+ loadSessionConfig
102
+ } from "./chunk-Q5OFZ2JR.js";
103
+ import {
104
+ loadCoreConfig
105
+ } from "./chunk-QXRNW4OJ.js";
106
+ import {
107
+ generateKeyPair,
108
+ verifyEscrowReceipt
109
+ } from "./chunk-65GNX2KC.js";
110
+ import "./chunk-YDGXKH2T.js";
109
111
  import "./chunk-J4RFJVXI.js";
110
112
  import {
111
113
  AgentBnBError,
112
114
  AnyCardSchema
113
115
  } from "./chunk-UVCNMRPS.js";
116
+ import {
117
+ getConfigDir
118
+ } from "./chunk-3XPBFF6H.js";
114
119
  import {
115
120
  getActivityFeed,
116
121
  getRequestLog,
@@ -120,7 +125,7 @@ import {
120
125
  import "./chunk-3RG5ZIWI.js";
121
126
 
122
127
  // src/runtime/agent-runtime.ts
123
- import { readFileSync, existsSync } from "fs";
128
+ import { readFileSync as readFileSync2, existsSync } from "fs";
124
129
 
125
130
  // src/skills/executor.ts
126
131
  function buildTimeoutError(skillId, timeoutMs) {
@@ -775,7 +780,30 @@ var OpenClawBridge = class {
775
780
 
776
781
  // src/skills/command-executor.ts
777
782
  import { spawn } from "child_process";
783
+ import { readFileSync, statSync } from "fs";
784
+ import { basename, extname } from "path";
778
785
  var KILL_GRACE_MS = 5e3;
786
+ var MAX_INLINE_FILE_BYTES = 5 * 1024 * 1024;
787
+ var MIME_TYPES = {
788
+ ".mp3": "audio/mpeg",
789
+ ".wav": "audio/wav",
790
+ ".ogg": "audio/ogg",
791
+ ".m4a": "audio/mp4",
792
+ ".pdf": "application/pdf",
793
+ ".png": "image/png",
794
+ ".jpg": "image/jpeg",
795
+ ".jpeg": "image/jpeg",
796
+ ".gif": "image/gif",
797
+ ".webp": "image/webp",
798
+ ".svg": "image/svg+xml",
799
+ ".json": "application/json",
800
+ ".txt": "text/plain",
801
+ ".md": "text/markdown",
802
+ ".csv": "text/csv"
803
+ };
804
+ function guessMimeType(filePath) {
805
+ return MIME_TYPES[extname(filePath).toLowerCase()] ?? "application/octet-stream";
806
+ }
779
807
  function shellEscape2(value) {
780
808
  return "'" + value.replace(/'/g, "'\\''") + "'";
781
809
  }
@@ -991,8 +1019,34 @@ var CommandExecutor = class {
991
1019
  };
992
1020
  }
993
1021
  }
994
- case "file":
995
- return { success: true, result: { file_path: rawOutput } };
1022
+ case "file": {
1023
+ try {
1024
+ const stats = statSync(rawOutput);
1025
+ if (stats.size > MAX_INLINE_FILE_BYTES) {
1026
+ return {
1027
+ success: false,
1028
+ error: `File too large for inline return: ${stats.size} bytes (max ${MAX_INLINE_FILE_BYTES})`
1029
+ };
1030
+ }
1031
+ const buffer = readFileSync(rawOutput);
1032
+ return {
1033
+ success: true,
1034
+ result: {
1035
+ file: {
1036
+ name: basename(rawOutput),
1037
+ mime_type: guessMimeType(rawOutput),
1038
+ size_bytes: stats.size,
1039
+ data_base64: buffer.toString("base64")
1040
+ },
1041
+ // Keep file_path for backward compat (local workflows)
1042
+ file_path: rawOutput
1043
+ }
1044
+ };
1045
+ } catch (err) {
1046
+ const msg = err instanceof Error ? err.message : String(err);
1047
+ return { success: false, error: `Failed to read file "${rawOutput}": ${msg}` };
1048
+ }
1049
+ }
996
1050
  default:
997
1051
  return {
998
1052
  success: false,
@@ -1121,13 +1175,13 @@ var AgentRuntime = class {
1121
1175
  }
1122
1176
  let configs = [];
1123
1177
  if (hasSkillsYaml) {
1124
- const yamlContent = readFileSync(this.skillsYamlPath, "utf8");
1178
+ const yamlContent = readFileSync2(this.skillsYamlPath, "utf8");
1125
1179
  configs = parseSkillsFile(yamlContent);
1126
1180
  }
1127
1181
  const modes = /* @__PURE__ */ new Map();
1128
1182
  if (this.conductorEnabled) {
1129
- const { ConductorMode } = await import("./conductor-mode-NKHIZG4N.js");
1130
- const { registerConductorCard, CONDUCTOR_OWNER } = await import("./card-NQHAGTQQ.js");
1183
+ const { ConductorMode } = await import("./conductor-mode-PFO2VLH6.js");
1184
+ const { registerConductorCard, CONDUCTOR_OWNER } = await import("./card-VVXNKHDX.js");
1131
1185
  const { loadPeers } = await import("./peers-7BMU2775.js");
1132
1186
  registerConductorCard(this.registryDb);
1133
1187
  const resolveAgentUrl = (owner) => {
@@ -2006,12 +2060,14 @@ var SessionManager = class {
2006
2060
  escrow;
2007
2061
  config;
2008
2062
  sendToAgent;
2063
+ registryDb;
2009
2064
  /** Maps agent connection key → set of session IDs they participate in. */
2010
2065
  agentSessions = /* @__PURE__ */ new Map();
2011
2066
  constructor(opts) {
2012
2067
  this.escrow = new SessionEscrow(opts.creditDb);
2013
2068
  this.config = opts.config ?? loadSessionConfig();
2014
2069
  this.sendToAgent = opts.sendToAgent;
2070
+ this.registryDb = opts.registryDb ?? null;
2015
2071
  }
2016
2072
  /**
2017
2073
  * Open a new session between requester and provider.
@@ -2070,6 +2126,15 @@ var SessionManager = class {
2070
2126
  }
2071
2127
  this.resetIdleTimer(session.id);
2072
2128
  this.startDurationTimer(session.id);
2129
+ this.emitEvent({
2130
+ event_type: "session.opened",
2131
+ skill_id: session.skill_id,
2132
+ session_id: session.id,
2133
+ requester: session.requester_id,
2134
+ credits: session.budget,
2135
+ duration_ms: 0,
2136
+ metadata: { engine: "session", pricing_model: session.pricing_model }
2137
+ });
2073
2138
  return session;
2074
2139
  }
2075
2140
  /**
@@ -2130,6 +2195,15 @@ var SessionManager = class {
2130
2195
  content: msg.content,
2131
2196
  metadata: msg.metadata
2132
2197
  });
2198
+ this.emitEvent({
2199
+ event_type: "session.message",
2200
+ skill_id: session.skill_id,
2201
+ session_id: session.id,
2202
+ requester: session.requester_id,
2203
+ credits: session.spent,
2204
+ duration_ms: Date.now() - new Date(session.created_at).getTime(),
2205
+ metadata: { message_count: session.messages.length, running_cost: session.spent, sender: msg.sender }
2206
+ });
2133
2207
  this.resetIdleTimer(session.id);
2134
2208
  }
2135
2209
  /**
@@ -2173,6 +2247,19 @@ var SessionManager = class {
2173
2247
  this.durationTimers.clear();
2174
2248
  }
2175
2249
  // -------------------------------------------------------------------------
2250
+ // Event emission
2251
+ // -------------------------------------------------------------------------
2252
+ /** Emit a provider event + Telegram notification. Silently no-ops on failure. */
2253
+ emitEvent(event) {
2254
+ if (!this.registryDb) return;
2255
+ try {
2256
+ const emitted = emitProviderEvent(this.registryDb, event);
2257
+ notifyProviderEvent(emitted).catch(() => {
2258
+ });
2259
+ } catch {
2260
+ }
2261
+ }
2262
+ // -------------------------------------------------------------------------
2176
2263
  // Internal helpers
2177
2264
  // -------------------------------------------------------------------------
2178
2265
  endSessionInternal(session, reason) {
@@ -2196,6 +2283,27 @@ var SessionManager = class {
2196
2283
  };
2197
2284
  session.status = "settled";
2198
2285
  session.updated_at = (/* @__PURE__ */ new Date()).toISOString();
2286
+ const isFailed = reason === "error";
2287
+ const eventMetadata = {
2288
+ total_messages: session.messages.length,
2289
+ reason,
2290
+ refunded: session.budget - session.spent
2291
+ };
2292
+ if (isFailed) {
2293
+ eventMetadata["last_messages"] = session.messages.slice(-3).map((m) => ({
2294
+ sender: m.sender,
2295
+ content: m.content.slice(0, 200)
2296
+ }));
2297
+ }
2298
+ this.emitEvent({
2299
+ event_type: isFailed ? "session.failed" : "session.ended",
2300
+ skill_id: session.skill_id,
2301
+ session_id: session.id,
2302
+ requester: session.requester_id,
2303
+ credits: session.spent,
2304
+ duration_ms: durationMs,
2305
+ metadata: eventMetadata
2306
+ });
2199
2307
  this.sendToAgent(session.requester_id, settledMsg);
2200
2308
  this.sendToAgent(session.provider_id, settledMsg);
2201
2309
  session.status = "closed";
@@ -3158,6 +3266,75 @@ function initiateGithubAuth() {
3158
3266
  };
3159
3267
  }
3160
3268
 
3269
+ // src/registry/hub-identities.ts
3270
+ import { randomBytes as randomBytes2, createHash } from "crypto";
3271
+ var HUB_IDENTITIES_SCHEMA = `
3272
+ CREATE TABLE IF NOT EXISTS hub_identities (
3273
+ email TEXT PRIMARY KEY,
3274
+ agent_id TEXT NOT NULL UNIQUE,
3275
+ public_key TEXT NOT NULL,
3276
+ encrypted_private_key TEXT NOT NULL,
3277
+ kdf_salt TEXT NOT NULL,
3278
+ display_name TEXT NOT NULL,
3279
+ created_at TEXT NOT NULL
3280
+ );
3281
+
3282
+ CREATE INDEX IF NOT EXISTS idx_hub_identities_agent_id
3283
+ ON hub_identities(agent_id);
3284
+ `;
3285
+ var CHALLENGES_SCHEMA = `
3286
+ CREATE TABLE IF NOT EXISTS hub_challenges (
3287
+ challenge TEXT PRIMARY KEY,
3288
+ expires_at TEXT NOT NULL,
3289
+ consumed_at TEXT
3290
+ );
3291
+ `;
3292
+ function ensureHubIdentitiesTables(db) {
3293
+ db.exec(HUB_IDENTITIES_SCHEMA);
3294
+ db.exec(CHALLENGES_SCHEMA);
3295
+ }
3296
+ function deriveAgentId2(publicKeyHex) {
3297
+ const hash = createHash("sha256").update(publicKeyHex, "hex").digest("hex");
3298
+ return `agent-${hash.slice(0, 16)}`;
3299
+ }
3300
+ var CHALLENGE_TTL_MS = 10 * 60 * 1e3;
3301
+ function createChallenge(db) {
3302
+ const challenge = randomBytes2(32).toString("hex");
3303
+ const expires_at = new Date(Date.now() + CHALLENGE_TTL_MS).toISOString();
3304
+ db.prepare("INSERT INTO hub_challenges (challenge, expires_at) VALUES (?, ?)").run(challenge, expires_at);
3305
+ return { challenge, expires_at };
3306
+ }
3307
+ function consumeChallenge(db, challenge) {
3308
+ const row = db.prepare("SELECT expires_at, consumed_at FROM hub_challenges WHERE challenge = ?").get(challenge);
3309
+ if (!row) return false;
3310
+ if (row.consumed_at) return false;
3311
+ if (new Date(row.expires_at).getTime() < Date.now()) return false;
3312
+ const consumed_at = (/* @__PURE__ */ new Date()).toISOString();
3313
+ db.prepare("UPDATE hub_challenges SET consumed_at = ? WHERE challenge = ?").run(consumed_at, challenge);
3314
+ return true;
3315
+ }
3316
+ function pruneChallenges(db) {
3317
+ const cutoff = new Date(Date.now() - 24 * 60 * 60 * 1e3).toISOString();
3318
+ db.prepare("DELETE FROM hub_challenges WHERE expires_at < ? OR consumed_at IS NOT NULL").run(cutoff);
3319
+ }
3320
+ function registerHubIdentity(db, input) {
3321
+ const agent_id = deriveAgentId2(input.public_key);
3322
+ const created_at = (/* @__PURE__ */ new Date()).toISOString();
3323
+ db.prepare(`
3324
+ INSERT INTO hub_identities (email, agent_id, public_key, encrypted_private_key, kdf_salt, display_name, created_at)
3325
+ VALUES (?, ?, ?, ?, ?, ?, ?)
3326
+ `).run(input.email, agent_id, input.public_key, input.encrypted_private_key, input.kdf_salt, input.display_name, created_at);
3327
+ return { ...input, agent_id, created_at };
3328
+ }
3329
+ function getHubIdentityByEmail(db, email) {
3330
+ const row = db.prepare("SELECT * FROM hub_identities WHERE email = ?").get(email);
3331
+ return row ?? null;
3332
+ }
3333
+ function getHubIdentityByAgentId(db, agent_id) {
3334
+ const row = db.prepare("SELECT * FROM hub_identities WHERE agent_id = ?").get(agent_id);
3335
+ return row ?? null;
3336
+ }
3337
+
3161
3338
  // src/registry/free-tier.ts
3162
3339
  function initFreeTierTable(db) {
3163
3340
  db.exec(`
@@ -5166,6 +5343,121 @@ function createRegistryServer(opts) {
5166
5343
  throw err;
5167
5344
  }
5168
5345
  });
5346
+ ensureHubIdentitiesTables(db);
5347
+ try {
5348
+ pruneChallenges(db);
5349
+ } catch {
5350
+ }
5351
+ api.get("/api/agents/challenge", {
5352
+ schema: {
5353
+ tags: ["hub-auth"],
5354
+ summary: "Get a registration challenge",
5355
+ response: {
5356
+ 200: {
5357
+ type: "object",
5358
+ properties: {
5359
+ challenge: { type: "string" },
5360
+ expires_at: { type: "string" }
5361
+ }
5362
+ }
5363
+ }
5364
+ }
5365
+ }, async (_request, reply) => {
5366
+ const { challenge, expires_at } = createChallenge(db);
5367
+ return reply.send({ challenge, expires_at });
5368
+ });
5369
+ api.post("/api/agents/register", {
5370
+ schema: {
5371
+ tags: ["hub-auth"],
5372
+ summary: "Register a new Hub-managed agent identity",
5373
+ body: {
5374
+ type: "object",
5375
+ required: ["email", "public_key", "encrypted_private_key", "kdf_salt", "display_name", "challenge", "signature"],
5376
+ properties: {
5377
+ email: { type: "string", format: "email" },
5378
+ public_key: { type: "string" },
5379
+ encrypted_private_key: { type: "string" },
5380
+ kdf_salt: { type: "string" },
5381
+ display_name: { type: "string" },
5382
+ challenge: { type: "string" },
5383
+ signature: { type: "string" }
5384
+ }
5385
+ },
5386
+ response: {
5387
+ 201: { type: "object", additionalProperties: true },
5388
+ 400: { type: "object", properties: { error: { type: "string" } } },
5389
+ 409: { type: "object", properties: { error: { type: "string" } } }
5390
+ }
5391
+ }
5392
+ }, async (request, reply) => {
5393
+ const body = request.body;
5394
+ if (!consumeChallenge(db, body.challenge)) {
5395
+ return reply.code(400).send({ error: "Invalid or expired challenge" });
5396
+ }
5397
+ if (!/^[0-9a-fA-F]+$/.test(body.public_key) || body.public_key.length % 2 !== 0) {
5398
+ return reply.code(400).send({ error: "Invalid public_key format" });
5399
+ }
5400
+ try {
5401
+ const { verifyEscrowReceipt: verifyEscrowReceipt2 } = await import("./signing-AQTKYJDB.js");
5402
+ const publicKeyBuffer = Buffer.from(body.public_key, "hex");
5403
+ const valid = verifyEscrowReceipt2({ challenge: body.challenge }, body.signature, publicKeyBuffer);
5404
+ if (!valid) {
5405
+ return reply.code(400).send({ error: "Invalid signature" });
5406
+ }
5407
+ } catch (err) {
5408
+ const msg = err instanceof Error ? err.message : String(err);
5409
+ return reply.code(400).send({ error: `Signature verification failed: ${msg}` });
5410
+ }
5411
+ const existing = getHubIdentityByEmail(db, body.email.toLowerCase());
5412
+ if (existing) {
5413
+ return reply.code(409).send({ error: "Email already registered" });
5414
+ }
5415
+ const agent_id = deriveAgentId2(body.public_key);
5416
+ const existingByAgentId = getHubIdentityByAgentId(db, agent_id);
5417
+ if (existingByAgentId) {
5418
+ return reply.code(409).send({ error: "Agent already registered" });
5419
+ }
5420
+ const identity = registerHubIdentity(db, {
5421
+ email: body.email.toLowerCase(),
5422
+ public_key: body.public_key,
5423
+ encrypted_private_key: body.encrypted_private_key,
5424
+ kdf_salt: body.kdf_salt,
5425
+ display_name: body.display_name
5426
+ });
5427
+ return reply.code(201).send({
5428
+ agent_id: identity.agent_id,
5429
+ did: `did:agentbnb:${identity.agent_id}`,
5430
+ created_at: identity.created_at
5431
+ });
5432
+ });
5433
+ api.post("/api/agents/login", {
5434
+ schema: {
5435
+ tags: ["hub-auth"],
5436
+ summary: "Fetch encrypted identity blob for login",
5437
+ body: {
5438
+ type: "object",
5439
+ required: ["email"],
5440
+ properties: { email: { type: "string", format: "email" } }
5441
+ },
5442
+ response: {
5443
+ 200: { type: "object", additionalProperties: true },
5444
+ 404: { type: "object", properties: { error: { type: "string" } } }
5445
+ }
5446
+ }
5447
+ }, async (request, reply) => {
5448
+ const body = request.body;
5449
+ const identity = getHubIdentityByEmail(db, body.email.toLowerCase());
5450
+ if (!identity) {
5451
+ return reply.code(404).send({ error: "Identity not found" });
5452
+ }
5453
+ return reply.send({
5454
+ agent_id: identity.agent_id,
5455
+ public_key: identity.public_key,
5456
+ encrypted_private_key: identity.encrypted_private_key,
5457
+ kdf_salt: identity.kdf_salt,
5458
+ display_name: identity.display_name
5459
+ });
5460
+ });
5169
5461
  api.post("/api/identity/link", {
5170
5462
  schema: {
5171
5463
  tags: ["identity"],
@@ -5465,7 +5757,7 @@ function createRegistryServer(opts) {
5465
5757
  });
5466
5758
  await relayClient.connect();
5467
5759
  }
5468
- const { requestViaRelay } = await import("./client-XOSXFC7Q.js");
5760
+ const { requestViaRelay } = await import("./client-KL67WZVJ.js");
5469
5761
  return requestViaRelay(relayClient, {
5470
5762
  targetOwner: target.owner,
5471
5763
  cardId: target.cardId,
@@ -5484,12 +5776,24 @@ function createRegistryServer(opts) {
5484
5776
  const ownerApiKey = opts.ownerApiKey;
5485
5777
  const ownerName = opts.ownerName;
5486
5778
  void api.register(async (ownerRoutes) => {
5487
- ownerRoutes.addHook("onRequest", async (request, reply) => {
5779
+ ownerRoutes.addHook("preHandler", async (request, reply) => {
5488
5780
  const auth = request.headers.authorization;
5489
5781
  const token = auth?.startsWith("Bearer ") ? auth.slice(7).trim() : null;
5490
- if (!token || token !== ownerApiKey) {
5491
- return reply.status(401).send({ error: "Unauthorized" });
5782
+ if (token === ownerApiKey) {
5783
+ request.agentId = ownerName;
5784
+ return;
5785
+ }
5786
+ const didResult = await tryVerifyIdentity(request, {});
5787
+ if (didResult.valid) {
5788
+ const hubIdentity = getHubIdentityByAgentId(db, didResult.agentId);
5789
+ if (!hubIdentity) {
5790
+ return reply.status(401).send({ error: "Agent not registered on this Hub" });
5791
+ }
5792
+ request.agentId = didResult.agentId;
5793
+ request.agentPublicKey = didResult.publicKey;
5794
+ return;
5492
5795
  }
5796
+ return reply.status(401).send({ error: "Unauthorized" });
5493
5797
  });
5494
5798
  ownerRoutes.get("/me", {
5495
5799
  schema: {
@@ -5500,13 +5804,14 @@ function createRegistryServer(opts) {
5500
5804
  200: { type: "object", properties: { owner: { type: "string" }, balance: { type: "number" } } }
5501
5805
  }
5502
5806
  }
5503
- }, async (_request, reply) => {
5807
+ }, async (request, reply) => {
5808
+ const identity = request.agentId ?? ownerName;
5504
5809
  let balance = 0;
5505
5810
  if (opts.creditDb) {
5506
5811
  const ledger = createLedger({ db: opts.creditDb });
5507
- balance = await ledger.getBalance(ownerName);
5812
+ balance = await ledger.getBalance(identity);
5508
5813
  }
5509
- return reply.send({ owner: ownerName, balance });
5814
+ return reply.send({ owner: identity, balance });
5510
5815
  });
5511
5816
  ownerRoutes.get("/requests", {
5512
5817
  schema: {
@@ -5693,6 +5998,62 @@ function createRegistryServer(opts) {
5693
5998
  const items = await ledger.getHistory(ownerName, limit);
5694
5999
  return reply.send({ items, limit });
5695
6000
  });
6001
+ ownerRoutes.get("/me/events", {
6002
+ schema: {
6003
+ tags: ["owner"],
6004
+ summary: "Provider event stream",
6005
+ security: [{ bearerAuth: [] }],
6006
+ querystring: {
6007
+ type: "object",
6008
+ properties: {
6009
+ limit: { type: "integer", description: "Max entries (default 50)" },
6010
+ since: { type: "string", description: "ISO timestamp for cursor-based polling" },
6011
+ event_type: { type: "string", description: "Filter by event type" }
6012
+ }
6013
+ }
6014
+ }
6015
+ }, async (request, reply) => {
6016
+ const { getProviderEvents: getEvents } = await import("./provider-events-GTTJPYHS.js");
6017
+ const query = request.query;
6018
+ const limit = query.limit ? parseInt(query.limit, 10) : void 0;
6019
+ const events = getEvents(db, {
6020
+ limit,
6021
+ since: query.since,
6022
+ event_type: query.event_type
6023
+ });
6024
+ return reply.send({ events });
6025
+ });
6026
+ ownerRoutes.get("/me/stats", {
6027
+ schema: {
6028
+ tags: ["owner"],
6029
+ summary: "Aggregated provider stats",
6030
+ security: [{ bearerAuth: [] }],
6031
+ querystring: {
6032
+ type: "object",
6033
+ properties: { period: { type: "string", enum: ["24h", "7d", "30d"] } }
6034
+ }
6035
+ }
6036
+ }, async (request, reply) => {
6037
+ const { getProviderStats: getStats } = await import("./provider-events-GTTJPYHS.js");
6038
+ const query = request.query;
6039
+ const period = query.period ?? "7d";
6040
+ const stats = getStats(db, period);
6041
+ if (opts.creditDb) {
6042
+ const periodMs = { "24h": 864e5, "7d": 6048e5, "30d": 2592e6 }[period];
6043
+ const cutoff = new Date(Date.now() - periodMs).toISOString();
6044
+ try {
6045
+ const row = opts.creditDb.prepare(`
6046
+ SELECT COALESCE(SUM(CASE WHEN amount < 0 AND reason IN ('escrow_hold', 'voucher_hold', 'network_fee') THEN -amount ELSE 0 END), 0) as spent
6047
+ FROM credit_transactions
6048
+ WHERE owner = ? AND created_at >= ?
6049
+ `).get(ownerName, cutoff);
6050
+ stats.total_spending = row?.spent ?? 0;
6051
+ stats.net_pnl = stats.total_earnings - stats.total_spending;
6052
+ } catch {
6053
+ }
6054
+ }
6055
+ return reply.send(stats);
6056
+ });
5696
6057
  });
5697
6058
  }
5698
6059
  api.get("/api/providers/:owner/reliability", {
@@ -5897,7 +6258,7 @@ var IdleMonitor = class {
5897
6258
 
5898
6259
  // src/runtime/service-coordinator.ts
5899
6260
  import { spawn as spawn2 } from "child_process";
5900
- import { existsSync as existsSync3, readFileSync as readFileSync2 } from "fs";
6261
+ import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
5901
6262
  import { join as join2 } from "path";
5902
6263
  import { randomUUID as randomUUID8 } from "crypto";
5903
6264
  import { Cron as Cron2 } from "croner";
@@ -6072,7 +6433,7 @@ var ServiceCoordinator = class {
6072
6433
  console.log("Conductor mode enabled \u2014 orchestrate/plan skills available via gateway");
6073
6434
  }
6074
6435
  if (opts.conductorEnabled && this.config.conductor?.public) {
6075
- const { buildConductorCard } = await import("./card-NQHAGTQQ.js");
6436
+ const { buildConductorCard } = await import("./card-VVXNKHDX.js");
6076
6437
  const conductorCard = attachCanonicalAgentId(
6077
6438
  this.runtime.registryDb,
6078
6439
  buildConductorCard(this.config.owner)
@@ -6149,7 +6510,7 @@ var ServiceCoordinator = class {
6149
6510
  }
6150
6511
  if (opts.registryUrl && opts.relay) {
6151
6512
  const { RelayClient } = await import("./websocket-client-FCPZOE4S.js");
6152
- const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("./execute-QHP4KUV2.js");
6513
+ const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("./execute-NOQVN7ZG.js");
6153
6514
  const localCards = listCards(this.runtime.registryDb, this.config.owner);
6154
6515
  const { primaryCard, additionalCards } = buildRelayRegistrationCards(this.config.owner, localCards);
6155
6516
  if (this.config.conductor?.public) {
@@ -6410,7 +6771,7 @@ function loadPersistedRuntime(configDir) {
6410
6771
  const runtimePath = join2(configDir, "runtime.json");
6411
6772
  if (!existsSync3(runtimePath)) return null;
6412
6773
  try {
6413
- const raw = readFileSync2(runtimePath, "utf8");
6774
+ const raw = readFileSync3(runtimePath, "utf8");
6414
6775
  const parsed = JSON.parse(raw);
6415
6776
  const nodeExec = parsed["node_exec"];
6416
6777
  if (typeof nodeExec !== "string" || nodeExec.trim().length === 0) {
@@ -1,12 +1,12 @@
1
1
  import {
2
2
  ensureIdentity
3
- } from "./chunk-5CC6O6SO.js";
4
- import "./chunk-YNBZLXYS.js";
3
+ } from "./chunk-AA25Z6FW.js";
4
+ import "./chunk-65GNX2KC.js";
5
+ import "./chunk-UVCNMRPS.js";
5
6
  import {
6
7
  getConfigDir,
7
8
  loadConfig
8
9
  } from "./chunk-3XPBFF6H.js";
9
- import "./chunk-UVCNMRPS.js";
10
10
  import "./chunk-3RG5ZIWI.js";
11
11
 
12
12
  // src/cli/session-action.ts