agentbnb 9.0.2 → 9.1.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 (72) hide show
  1. package/dist/{card-NKQFB3HD.js → card-NQHAGTQQ.js} +3 -1
  2. package/dist/{card-6KL6L4GF.js → card-VVT3XBOI.js} +3 -1
  3. package/dist/chunk-3RG5ZIWI.js +10 -0
  4. package/dist/{chunk-76YORWFJ.js → chunk-3Y76PHEY.js} +62 -5
  5. package/dist/{chunk-QEDVPJKP.js → chunk-4DBSSFHG.js} +20 -16
  6. package/dist/chunk-4HLGFR72.js +155 -0
  7. package/dist/{chunk-ERT77HKY.js → chunk-4M6IAIVK.js} +2 -2
  8. package/dist/{chunk-FUGWPKXN.js → chunk-4UIUIHST.js} +1 -1
  9. package/dist/chunk-4XTYT4JW.js +147 -0
  10. package/dist/{chunk-2SOHHB2O.js → chunk-AR7Z3EQB.js} +34 -11
  11. package/dist/{chunk-Z4IDXMSP.js → chunk-D7NH6YLM.js} +6 -1
  12. package/dist/{chunk-SLZBE2I5.js → chunk-DBO2335D.js} +17 -12
  13. package/dist/{chunk-N3TXLBGK.js → chunk-GAZCZCAZ.js} +1 -1
  14. package/dist/{chunk-UQCQ2JCG.js → chunk-JJHQAZWE.js} +4 -4
  15. package/dist/{chunk-NLQCHO7N.js → chunk-JKD6QRUD.js} +3 -134
  16. package/dist/{chunk-74OZGLIT.js → chunk-LENX5NUW.js} +1 -1
  17. package/dist/{chunk-I3RRMAAD.js → chunk-PIO2FMX4.js} +5 -5
  18. package/dist/{chunk-77HAL2ZL.js → chunk-PYZGF5QH.js} +60 -3
  19. package/dist/chunk-Q5OFZ2JR.js +292 -0
  20. package/dist/{chunk-YJ3RGKPU.js → chunk-QG2LLVXP.js} +6 -2
  21. package/dist/chunk-QXRNW4OJ.js +35 -0
  22. package/dist/{chunk-UR3MISL2.js → chunk-UPNREF4L.js} +1 -1
  23. package/dist/{chunk-SMQDT7CT.js → chunk-UXL7DV7P.js} +7 -3
  24. package/dist/{chunk-PG3CLSAH.js → chunk-VJ2Q33AP.js} +3 -134
  25. package/dist/{chunk-DYJ7YGBM.js → chunk-WOVESOQ7.js} +237 -124
  26. package/dist/{chunk-BNS76U6K.js → chunk-XL5XD3IG.js} +23 -17
  27. package/dist/{chunk-FMKBCO2Q.js → chunk-ZYOMPJGG.js} +2 -2
  28. package/dist/cli/index.js +133 -59
  29. package/dist/{client-YB3IYO3S.js → client-XOSXFC7Q.js} +1 -0
  30. package/dist/{conduct-URYWMA5T.js → conduct-6C6JWZKZ.js} +13 -10
  31. package/dist/conduct-VSSHJHVH.js +29 -0
  32. package/dist/{conductor-mode-NRSVP2AU.js → conductor-mode-KKPSNN7V.js} +9 -6
  33. package/dist/{conductor-mode-2UFN6BUL.js → conductor-mode-NKHIZG4N.js} +17 -14
  34. package/dist/{config-IRWLG6IW.js → config-ZFWBAGDU.js} +1 -0
  35. package/dist/{credits-action-24EPLUHG.js → credits-action-N3WB4WSI.js} +5 -3
  36. package/dist/{daemon-A7DXZIQW.js → daemon-OM2K3U7J.js} +1 -0
  37. package/dist/{did-action-MQLDT4RF.js → did-action-3PNFYLX2.js} +1 -0
  38. package/dist/{execute-DNRNU3HM.js → execute-IEQ3RV7I.js} +6 -3
  39. package/dist/{execute-2Z3XIUHR.js → execute-QHP4KUV2.js} +10 -7
  40. package/dist/index.d.ts +412 -275
  41. package/dist/index.js +886 -282
  42. package/dist/{openclaw-setup-WA625DZA.js → openclaw-setup-PKGFB4IH.js} +19 -16
  43. package/dist/{openclaw-skills-76ZWXHFM.js → openclaw-skills-5VJDA6SX.js} +7 -6
  44. package/dist/{peers-F2EWUMVQ.js → peers-7BMU2775.js} +1 -0
  45. package/dist/{peers-CJ7T4RJO.js → peers-IOVCBWAI.js} +1 -0
  46. package/dist/{process-guard-QDBIOLY4.js → process-guard-6324CZDC.js} +1 -0
  47. package/dist/{publish-capability-FOCHYNYE.js → publish-capability-CHMPZ6W3.js} +4 -2
  48. package/dist/{reliability-metrics-JSOY3PNW.js → reliability-metrics-22JTZGB4.js} +1 -0
  49. package/dist/{reliability-metrics-KKUFFVB6.js → reliability-metrics-MIJ3TJWL.js} +1 -0
  50. package/dist/{request-KPKWBL5W.js → request-6TBVP3GR.js} +12 -9
  51. package/dist/request-log-2D253WML.js +17 -0
  52. package/dist/request-log-SIGTGOFA.js +16 -0
  53. package/dist/{scanner-GP4AOCW6.js → scanner-EFU6NBEJ.js} +1 -0
  54. package/dist/{schema-7BSSLZ4S.js → schema-FABVZKSI.js} +1 -0
  55. package/dist/{serve-skill-QSUIK3ZF.js → serve-skill-BRUHUDRA.js} +12 -9
  56. package/dist/{server-TGV2OPUM.js → server-N4BJW4TS.js} +15 -8
  57. package/dist/{service-coordinator-4JAUUNUL.js → service-coordinator-M2CBDEUQ.js} +539 -50
  58. package/dist/session-5AIRM7YF.js +144 -0
  59. package/dist/session-action-67J57636.js +131 -0
  60. package/dist/{skill-config-5O2VR546.js → skill-config-VYNF7BCY.js} +1 -0
  61. package/dist/skill-wrap-IAZHOYM4.js +365 -0
  62. package/dist/skills/agentbnb/bootstrap.js +564 -75
  63. package/dist/{store-S22F3I7G.js → store-A4YPEHDV.js} +3 -1
  64. package/dist/{vc-action-SUD7TMN2.js → vc-action-TSAIABUM.js} +1 -0
  65. package/dist/websocket-client-FCPZOE4S.js +9 -0
  66. package/dist/websocket-client-RT4KLJL4.js +8 -0
  67. package/dist/{writer-4QJ3U3WE.js → writer-V7JBWKKZ.js} +1 -0
  68. package/package.json +1 -1
  69. package/dist/chunk-3466S65P.js +0 -179
  70. package/dist/conduct-UAEEMVFD.js +0 -26
  71. package/dist/websocket-client-5CRE36Z5.js +0 -7
  72. package/dist/websocket-client-WHEHIYIZ.js +0 -6
package/dist/index.js CHANGED
@@ -1,3 +1,9 @@
1
+ import {
2
+ __require,
3
+ createRequestLogTable,
4
+ insertRequestLog
5
+ } from "./chunk-4HLGFR72.js";
6
+
1
7
  // src/types/index.ts
2
8
  import { z } from "zod";
3
9
  var IOSchemaSchema = z.object({
@@ -213,76 +219,6 @@ var AgentBnBError = class extends Error {
213
219
  // src/registry/store.ts
214
220
  import Database from "better-sqlite3";
215
221
 
216
- // src/registry/request-log.ts
217
- function createRequestLogTable(db) {
218
- db.exec(`
219
- CREATE TABLE IF NOT EXISTS request_log (
220
- id TEXT PRIMARY KEY,
221
- card_id TEXT NOT NULL,
222
- card_name TEXT NOT NULL,
223
- requester TEXT NOT NULL,
224
- status TEXT NOT NULL CHECK(status IN ('success', 'failure', 'timeout')),
225
- latency_ms INTEGER NOT NULL,
226
- credits_charged INTEGER NOT NULL,
227
- created_at TEXT NOT NULL
228
- );
229
-
230
- CREATE INDEX IF NOT EXISTS request_log_created_at_idx
231
- ON request_log (created_at DESC);
232
- `);
233
- try {
234
- db.exec("ALTER TABLE request_log ADD COLUMN skill_id TEXT");
235
- } catch {
236
- }
237
- try {
238
- db.exec("ALTER TABLE request_log ADD COLUMN action_type TEXT");
239
- } catch {
240
- }
241
- try {
242
- db.exec("ALTER TABLE request_log ADD COLUMN tier_invoked INTEGER");
243
- } catch {
244
- }
245
- try {
246
- db.exec("ALTER TABLE request_log ADD COLUMN failure_reason TEXT");
247
- } catch {
248
- }
249
- try {
250
- db.exec("ALTER TABLE request_log ADD COLUMN team_id TEXT");
251
- } catch {
252
- }
253
- try {
254
- db.exec("ALTER TABLE request_log ADD COLUMN role TEXT");
255
- } catch {
256
- }
257
- try {
258
- db.exec("ALTER TABLE request_log ADD COLUMN capability_type TEXT");
259
- } catch {
260
- }
261
- }
262
- function insertRequestLog(db, entry) {
263
- const stmt = db.prepare(`
264
- INSERT INTO request_log (id, card_id, card_name, requester, status, latency_ms, credits_charged, created_at, skill_id, action_type, tier_invoked, failure_reason, team_id, role, capability_type)
265
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
266
- `);
267
- stmt.run(
268
- entry.id,
269
- entry.card_id,
270
- entry.card_name,
271
- entry.requester,
272
- entry.status,
273
- entry.latency_ms,
274
- entry.credits_charged,
275
- entry.created_at,
276
- entry.skill_id ?? null,
277
- entry.action_type ?? null,
278
- entry.tier_invoked ?? null,
279
- entry.failure_reason ?? null,
280
- entry.team_id ?? null,
281
- entry.role ?? null,
282
- entry.capability_type ?? null
283
- );
284
- }
285
-
286
222
  // src/feedback/store.ts
287
223
  import { randomUUID } from "crypto";
288
224
  function initFeedbackTable(db) {
@@ -858,28 +794,57 @@ function getCardsBySkillCapability(db, capabilityType) {
858
794
  });
859
795
  }
860
796
 
797
+ // src/core-config.ts
798
+ import { readFileSync } from "fs";
799
+ import { join } from "path";
800
+ var coreBasePath = null;
801
+ var coreResolved = false;
802
+ function resolveCoreBase() {
803
+ if (coreResolved) return coreBasePath;
804
+ coreResolved = true;
805
+ try {
806
+ const pkgPath = __require.resolve("@agentbnb/core/package.json");
807
+ coreBasePath = join(pkgPath, "..");
808
+ return coreBasePath;
809
+ } catch {
810
+ return null;
811
+ }
812
+ }
813
+ function loadCoreConfig(configName) {
814
+ const base = resolveCoreBase();
815
+ if (!base) return null;
816
+ try {
817
+ const filePath = join(base, "config", `${configName}.json`);
818
+ const raw = readFileSync(filePath, "utf8");
819
+ return JSON.parse(raw);
820
+ } catch {
821
+ return null;
822
+ }
823
+ }
824
+
861
825
  // src/feedback/reputation.ts
826
+ var coreReputation = loadCoreConfig("reputation");
862
827
  var QUALITY_SCORES = {
863
- excellent: 1,
864
- good: 0.8,
865
- acceptable: 0.6,
866
- poor: 0.3,
867
- failed: 0
828
+ excellent: coreReputation?.quality_scores?.["excellent"] ?? 1,
829
+ good: coreReputation?.quality_scores?.["good"] ?? 0.8,
830
+ acceptable: coreReputation?.quality_scores?.["acceptable"] ?? 0.6,
831
+ poor: coreReputation?.quality_scores?.["poor"] ?? 0.3,
832
+ failed: coreReputation?.quality_scores?.["failed"] ?? 0
868
833
  };
869
834
  var COST_VALUE_SCORES = {
870
- great: 1,
871
- fair: 0.6,
872
- overpriced: 0.2
835
+ great: coreReputation?.cost_value_scores?.["great"] ?? 1,
836
+ fair: coreReputation?.cost_value_scores?.["fair"] ?? 0.6,
837
+ overpriced: coreReputation?.cost_value_scores?.["overpriced"] ?? 0.2
873
838
  };
874
- var DECAY_DAYS = 30;
839
+ var DECAY_DAYS = coreReputation?.decay_days ?? 30;
875
840
  var WEIGHTS = {
876
- rating: 0.4,
877
- quality: 0.3,
878
- would_reuse: 0.2,
879
- cost_value: 0.1
841
+ rating: coreReputation?.weights?.["rating"] ?? 0.4,
842
+ quality: coreReputation?.weights?.["quality"] ?? 0.3,
843
+ would_reuse: coreReputation?.weights?.["would_reuse"] ?? 0.2,
844
+ cost_value: coreReputation?.weights?.["cost_value"] ?? 0.1
880
845
  };
881
846
  function computeReputation(feedbacks) {
882
- if (feedbacks.length === 0) return 0.5;
847
+ if (feedbacks.length === 0) return coreReputation?.cold_start_score ?? 0.5;
883
848
  const now = Date.now();
884
849
  let weightedSum = 0;
885
850
  let totalWeight = 0;
@@ -895,7 +860,7 @@ function computeReputation(feedbacks) {
895
860
  weightedSum += recencyWeight * componentScore;
896
861
  totalWeight += recencyWeight;
897
862
  }
898
- if (totalWeight === 0) return 0.5;
863
+ if (totalWeight === 0) return coreReputation?.cold_start_score ?? 0.5;
899
864
  const raw = weightedSum / totalWeight;
900
865
  return Math.max(0, Math.min(1, raw));
901
866
  }
@@ -1372,7 +1337,8 @@ import { randomUUID as randomUUID5 } from "crypto";
1372
1337
 
1373
1338
  // src/credit/escrow.ts
1374
1339
  import { randomUUID as randomUUID4 } from "crypto";
1375
- var NETWORK_FEE_RATE = 0.05;
1340
+ var coreEconomics = loadCoreConfig("economics");
1341
+ var NETWORK_FEE_RATE = coreEconomics?.network_fee_rate ?? 0.05;
1376
1342
  var FINALIZABLE_ESCROW_STATUSES = /* @__PURE__ */ new Set([
1377
1343
  "held",
1378
1344
  "started",
@@ -1559,20 +1525,20 @@ function confirmEscrowDebit(db, escrowId) {
1559
1525
  }
1560
1526
 
1561
1527
  // src/cli/config.ts
1562
- import { readFileSync, writeFileSync, mkdirSync, existsSync } from "fs";
1528
+ import { readFileSync as readFileSync2, writeFileSync, mkdirSync, existsSync } from "fs";
1563
1529
  import { homedir } from "os";
1564
- import { join } from "path";
1530
+ import { join as join2 } from "path";
1565
1531
  function getConfigDir() {
1566
- return process.env["AGENTBNB_DIR"] ?? join(homedir(), ".agentbnb");
1532
+ return process.env["AGENTBNB_DIR"] ?? join2(homedir(), ".agentbnb");
1567
1533
  }
1568
1534
  function getConfigPath() {
1569
- return join(getConfigDir(), "config.json");
1535
+ return join2(getConfigDir(), "config.json");
1570
1536
  }
1571
1537
  function loadConfig() {
1572
1538
  const configPath = getConfigPath();
1573
1539
  if (!existsSync(configPath)) return null;
1574
1540
  try {
1575
- const raw = readFileSync(configPath, "utf-8");
1541
+ const raw = readFileSync2(configPath, "utf-8");
1576
1542
  return JSON.parse(raw);
1577
1543
  } catch {
1578
1544
  return null;
@@ -1582,13 +1548,13 @@ function loadConfig() {
1582
1548
  // src/identity/identity.ts
1583
1549
  import { z as z2 } from "zod";
1584
1550
  import { createHash, createPrivateKey as createPrivateKey2, createPublicKey as createPublicKey2 } from "crypto";
1585
- import { readFileSync as readFileSync3, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
1586
- import { join as join3 } from "path";
1551
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync3, existsSync as existsSync3, mkdirSync as mkdirSync2 } from "fs";
1552
+ import { join as join4 } from "path";
1587
1553
 
1588
1554
  // src/credit/signing.ts
1589
1555
  import { generateKeyPairSync, sign, verify, createPublicKey, createPrivateKey } from "crypto";
1590
- import { writeFileSync as writeFileSync2, readFileSync as readFileSync2, existsSync as existsSync2, chmodSync } from "fs";
1591
- import { join as join2 } from "path";
1556
+ import { writeFileSync as writeFileSync2, readFileSync as readFileSync3, existsSync as existsSync2, chmodSync } from "fs";
1557
+ import { join as join3 } from "path";
1592
1558
  function generateKeyPair() {
1593
1559
  const { publicKey, privateKey } = generateKeyPairSync("ed25519", {
1594
1560
  publicKeyEncoding: { type: "spki", format: "der" },
@@ -1600,21 +1566,21 @@ function generateKeyPair() {
1600
1566
  };
1601
1567
  }
1602
1568
  function saveKeyPair(configDir, keys) {
1603
- const privatePath = join2(configDir, "private.key");
1604
- const publicPath = join2(configDir, "public.key");
1569
+ const privatePath = join3(configDir, "private.key");
1570
+ const publicPath = join3(configDir, "public.key");
1605
1571
  writeFileSync2(privatePath, keys.privateKey);
1606
1572
  chmodSync(privatePath, 384);
1607
1573
  writeFileSync2(publicPath, keys.publicKey);
1608
1574
  }
1609
1575
  function loadKeyPair(configDir) {
1610
- const privatePath = join2(configDir, "private.key");
1611
- const publicPath = join2(configDir, "public.key");
1576
+ const privatePath = join3(configDir, "private.key");
1577
+ const publicPath = join3(configDir, "public.key");
1612
1578
  if (!existsSync2(privatePath) || !existsSync2(publicPath)) {
1613
1579
  throw new AgentBnBError("Keypair not found. Run `agentbnb init` to generate one.", "KEYPAIR_NOT_FOUND");
1614
1580
  }
1615
1581
  return {
1616
- publicKey: readFileSync2(publicPath),
1617
- privateKey: readFileSync2(privatePath)
1582
+ publicKey: readFileSync3(publicPath),
1583
+ privateKey: readFileSync3(privatePath)
1618
1584
  };
1619
1585
  }
1620
1586
  function canonicalJson(data) {
@@ -1738,10 +1704,10 @@ function createIdentity(configDir, owner) {
1738
1704
  return identity;
1739
1705
  }
1740
1706
  function loadIdentity(configDir) {
1741
- const filePath = join3(configDir, IDENTITY_FILENAME);
1707
+ const filePath = join4(configDir, IDENTITY_FILENAME);
1742
1708
  if (!existsSync3(filePath)) return null;
1743
1709
  try {
1744
- const raw = readFileSync3(filePath, "utf-8");
1710
+ const raw = readFileSync4(filePath, "utf-8");
1745
1711
  return AgentIdentitySchema.parse(JSON.parse(raw));
1746
1712
  } catch {
1747
1713
  return null;
@@ -1751,16 +1717,16 @@ function saveIdentity(configDir, identity) {
1751
1717
  if (!existsSync3(configDir)) {
1752
1718
  mkdirSync2(configDir, { recursive: true });
1753
1719
  }
1754
- const filePath = join3(configDir, IDENTITY_FILENAME);
1720
+ const filePath = join4(configDir, IDENTITY_FILENAME);
1755
1721
  writeFileSync3(filePath, JSON.stringify(identity, null, 2), "utf-8");
1756
1722
  }
1757
1723
  function loadOrRepairIdentity(configDir, ownerHint) {
1758
1724
  if (!existsSync3(configDir)) {
1759
1725
  mkdirSync2(configDir, { recursive: true });
1760
1726
  }
1761
- const identityPath = join3(configDir, IDENTITY_FILENAME);
1762
- const privateKeyPath = join3(configDir, PRIVATE_KEY_FILENAME);
1763
- const publicKeyPath = join3(configDir, PUBLIC_KEY_FILENAME);
1727
+ const identityPath = join4(configDir, IDENTITY_FILENAME);
1728
+ const privateKeyPath = join4(configDir, PRIVATE_KEY_FILENAME);
1729
+ const publicKeyPath = join4(configDir, PUBLIC_KEY_FILENAME);
1764
1730
  const hasIdentity = existsSync3(identityPath);
1765
1731
  const hasPrivateKey = existsSync3(privateKeyPath);
1766
1732
  const hasPublicKey = existsSync3(publicKeyPath);
@@ -2325,6 +2291,26 @@ async function notifyTelegramSkillFailed(opts) {
2325
2291
  body: JSON.stringify({ chat_id: chatId, text })
2326
2292
  });
2327
2293
  }
2294
+ async function notifyTelegramSkillReceived(opts) {
2295
+ const cfg = loadConfig();
2296
+ if (cfg?.provider_gate !== "notify") return;
2297
+ const token = cfg.telegram_bot_token ?? process.env["TELEGRAM_BOT_TOKEN"];
2298
+ const chatId = cfg.telegram_chat_id ?? process.env["TELEGRAM_CHAT_ID"];
2299
+ if (!token || !chatId) return;
2300
+ const skillLabel = opts.skillId ? `${opts.skillName} (${opts.skillId})` : opts.skillName;
2301
+ const text = [
2302
+ "\u{1F4E5} [AgentBnB] Incoming rental request",
2303
+ `Skill: ${skillLabel}`,
2304
+ `Requester: ${opts.requester}`,
2305
+ `Cost: ${opts.cost} credits`,
2306
+ `Status: Executing...`
2307
+ ].join("\n");
2308
+ await fetch(`https://api.telegram.org/bot${token}/sendMessage`, {
2309
+ method: "POST",
2310
+ headers: { "Content-Type": "application/json" },
2311
+ body: JSON.stringify({ chat_id: chatId, text })
2312
+ });
2313
+ }
2328
2314
  async function executeCapabilityRequest(opts) {
2329
2315
  const {
2330
2316
  registryDb,
@@ -2416,6 +2402,41 @@ async function executeCapabilityRequest(opts) {
2416
2402
  return { success: false, error: { code: -32603, message: msg } };
2417
2403
  }
2418
2404
  }
2405
+ const providerCfg = loadConfig();
2406
+ const providerWhitelist = providerCfg?.provider_whitelist ?? [];
2407
+ const isWhitelisted = providerWhitelist.includes(requester);
2408
+ if (providerCfg?.provider_accepting === false && !isWhitelisted) {
2409
+ if (escrowId) releaseEscrow(creditDb, escrowId);
2410
+ return { success: false, error: { code: -32098, message: "Provider is not accepting requests" } };
2411
+ }
2412
+ if (!isWhitelisted) {
2413
+ const blacklist = providerCfg?.provider_blacklist ?? [];
2414
+ if (blacklist.includes(requester)) {
2415
+ if (escrowId) releaseEscrow(creditDb, escrowId);
2416
+ return { success: false, error: { code: -32097, message: "Requester is blocked by provider" } };
2417
+ }
2418
+ }
2419
+ if (!isWhitelisted) {
2420
+ const dailyLimit = providerCfg?.provider_daily_limit ?? 0;
2421
+ if (dailyLimit > 0) {
2422
+ const { countTodayExecutions } = await import("./request-log-SIGTGOFA.js");
2423
+ const todayCount = countTodayExecutions(registryDb);
2424
+ if (todayCount >= dailyLimit) {
2425
+ if (escrowId) releaseEscrow(creditDb, escrowId);
2426
+ return {
2427
+ success: false,
2428
+ error: { code: -32099, message: `Provider daily execution limit reached (${dailyLimit}/day)` }
2429
+ };
2430
+ }
2431
+ }
2432
+ }
2433
+ notifyTelegramSkillReceived({
2434
+ skillName: cardName,
2435
+ skillId: resolvedSkillId ?? null,
2436
+ requester,
2437
+ cost: creditsNeeded
2438
+ }).catch(() => {
2439
+ });
2419
2440
  const startMs = Date.now();
2420
2441
  const handleFailure = (status, latencyMs, message, failureReason = "bad_execution") => {
2421
2442
  if (escrowId) releaseEscrow(creditDb, escrowId);
@@ -3590,9 +3611,42 @@ var PipelineExecutor = class {
3590
3611
  };
3591
3612
 
3592
3613
  // src/skills/openclaw-bridge.ts
3593
- import { execFileSync } from "child_process";
3614
+ import { spawnSync } from "child_process";
3594
3615
  var DEFAULT_BASE_URL = "http://localhost:3000";
3595
3616
  var DEFAULT_TIMEOUT_MS = 6e4;
3617
+ function isOpenClawJsonResponse(value) {
3618
+ return typeof value === "object" && value !== null && "payloads" in value && Array.isArray(value.payloads) && "meta" in value;
3619
+ }
3620
+ function parseOpenClawResponse(raw) {
3621
+ if (!isOpenClawJsonResponse(raw)) {
3622
+ return raw;
3623
+ }
3624
+ const { payloads, meta } = raw;
3625
+ const texts = payloads.map((p) => p.text).filter((t) => typeof t === "string" && t.length > 0);
3626
+ const mediaUrls = payloads.map((p) => p.mediaUrl).filter((u) => typeof u === "string" && u.length > 0);
3627
+ const openclawMeta = {
3628
+ duration_ms: meta.durationMs,
3629
+ model: meta.agentMeta?.model,
3630
+ provider: meta.agentMeta?.provider
3631
+ };
3632
+ if (texts.length === 0) {
3633
+ return { text: "", media_urls: mediaUrls, _openclaw_meta: openclawMeta };
3634
+ }
3635
+ const lastText = texts[texts.length - 1];
3636
+ try {
3637
+ const structured = JSON.parse(lastText);
3638
+ if (typeof structured === "object" && structured !== null) {
3639
+ return { ...structured, _openclaw_meta: openclawMeta };
3640
+ }
3641
+ return { result: structured, _openclaw_meta: openclawMeta };
3642
+ } catch {
3643
+ return {
3644
+ text: texts.join("\n\n"),
3645
+ media_urls: mediaUrls.length > 0 ? mediaUrls : void 0,
3646
+ _openclaw_meta: openclawMeta
3647
+ };
3648
+ }
3649
+ }
3596
3650
  function buildPayload(config, params) {
3597
3651
  return {
3598
3652
  task: config.name,
@@ -3659,7 +3713,7 @@ Do NOT include explanations, markdown formatting, or code blocks.
3659
3713
  The JSON should contain the output fields specified in your SKILL.md.
3660
3714
  If you cannot complete the task, return: {"error": "reason"}`;
3661
3715
  try {
3662
- const stdout = execFileSync("openclaw", [
3716
+ const proc = spawnSync("openclaw", [
3663
3717
  "agent",
3664
3718
  "--agent",
3665
3719
  config.agent_name,
@@ -3668,21 +3722,37 @@ If you cannot complete the task, return: {"error": "reason"}`;
3668
3722
  "--json",
3669
3723
  "--local"
3670
3724
  ], {
3671
- timeout: timeoutMs
3725
+ timeout: timeoutMs,
3726
+ maxBuffer: 10 * 1024 * 1024
3727
+ // 10 MB
3672
3728
  });
3673
- const text = stdout.toString().trim();
3729
+ if (proc.error) {
3730
+ return { success: false, error: proc.error.message };
3731
+ }
3732
+ const stderrText = proc.stderr?.toString() ?? "";
3733
+ const stdoutText = proc.stdout?.toString() ?? "";
3734
+ const text = (stderrText || stdoutText).trim();
3735
+ if (!text) {
3736
+ return {
3737
+ success: false,
3738
+ error: `OpenClaw process channel returned empty output (exit code ${proc.status})`
3739
+ };
3740
+ }
3741
+ const jsonStart = text.lastIndexOf("\n{");
3742
+ const jsonText = jsonStart >= 0 ? text.slice(jsonStart + 1) : text;
3674
3743
  try {
3675
- const parsed = JSON.parse(text);
3676
- return { success: true, result: parsed };
3744
+ const parsed = JSON.parse(jsonText);
3745
+ const result = parseOpenClawResponse(parsed);
3746
+ return { success: true, result };
3677
3747
  } catch {
3678
3748
  return {
3679
3749
  success: false,
3680
- error: `OpenClaw process channel returned invalid JSON: ${text}`
3750
+ error: `OpenClaw process channel returned invalid JSON: ${jsonText.slice(0, 500)}`
3681
3751
  };
3682
3752
  }
3683
3753
  } catch (err) {
3684
- const message2 = err instanceof Error ? err.message : String(err);
3685
- return { success: false, error: message2 };
3754
+ const errMsg = err instanceof Error ? err.message : String(err);
3755
+ return { success: false, error: errMsg };
3686
3756
  }
3687
3757
  }
3688
3758
  async function executeTelegram(config, payload) {
@@ -4446,163 +4516,261 @@ import WebSocket from "ws";
4446
4516
  import { randomUUID as randomUUID10 } from "crypto";
4447
4517
 
4448
4518
  // src/relay/types.ts
4519
+ import { z as z5 } from "zod";
4520
+
4521
+ // src/session/session-types.ts
4449
4522
  import { z as z4 } from "zod";
4450
- var RegisterMessageSchema = z4.object({
4451
- type: z4.literal("register"),
4452
- owner: z4.string().min(1),
4523
+ var DEFAULT_SESSION_CONFIG = {
4524
+ pricing: {
4525
+ default_model: "per_message",
4526
+ per_message_base_rate: 2,
4527
+ per_minute_base_rate: 1,
4528
+ per_session_flat_rate: 10,
4529
+ max_messages_per_session: 50,
4530
+ max_minutes_per_session: 30
4531
+ },
4532
+ timeouts: {
4533
+ idle_timeout_ms: 12e4,
4534
+ max_session_duration_ms: 18e5,
4535
+ message_timeout_ms: 9e4
4536
+ },
4537
+ abuse: {
4538
+ max_concurrent_sessions_per_agent: 5,
4539
+ max_sessions_per_hour: 20,
4540
+ min_message_interval_ms: 1e3
4541
+ },
4542
+ quality: {
4543
+ min_provider_reputation_for_session: 0.5,
4544
+ auto_refund_on_timeout: true,
4545
+ partial_refund_ratio: 0.5
4546
+ }
4547
+ };
4548
+ function loadSessionConfig() {
4549
+ const core = loadCoreConfig("session");
4550
+ if (!core) return DEFAULT_SESSION_CONFIG;
4551
+ return {
4552
+ pricing: { ...DEFAULT_SESSION_CONFIG.pricing, ...core.pricing },
4553
+ timeouts: { ...DEFAULT_SESSION_CONFIG.timeouts, ...core.timeouts },
4554
+ abuse: { ...DEFAULT_SESSION_CONFIG.abuse, ...core.abuse },
4555
+ quality: { ...DEFAULT_SESSION_CONFIG.quality, ...core.quality }
4556
+ };
4557
+ }
4558
+ var SessionPricingModelSchema = z4.enum(["per_message", "per_minute", "per_session"]);
4559
+ var SessionOpenMessageSchema = z4.object({
4560
+ type: z4.literal("session_open"),
4561
+ session_id: z4.string().uuid(),
4562
+ requester_id: z4.string().min(1),
4563
+ provider_id: z4.string().min(1),
4564
+ card_id: z4.string().min(1),
4565
+ skill_id: z4.string().min(1),
4566
+ budget: z4.number().positive(),
4567
+ pricing_model: SessionPricingModelSchema.default("per_message"),
4568
+ initial_message: z4.string().min(1),
4569
+ ucan_token: z4.string().optional()
4570
+ });
4571
+ var SessionAckMessageSchema = z4.object({
4572
+ type: z4.literal("session_ack"),
4573
+ session_id: z4.string(),
4574
+ escrow_id: z4.string(),
4575
+ status: z4.literal("open")
4576
+ });
4577
+ var SessionMessageMessageSchema = z4.object({
4578
+ type: z4.literal("session_message"),
4579
+ session_id: z4.string().uuid(),
4580
+ sender: z4.enum(["requester", "provider"]),
4581
+ content: z4.string().min(1),
4582
+ metadata: z4.object({
4583
+ model: z4.string().optional(),
4584
+ latency_ms: z4.number().optional(),
4585
+ tokens_used: z4.number().optional()
4586
+ }).optional()
4587
+ });
4588
+ var SessionEndMessageSchema = z4.object({
4589
+ type: z4.literal("session_end"),
4590
+ session_id: z4.string().uuid(),
4591
+ reason: z4.enum(["completed", "timeout", "budget_exhausted", "error", "cancelled"]).default("completed"),
4592
+ summary: z4.string().optional()
4593
+ });
4594
+ var SessionSettledMessageSchema = z4.object({
4595
+ type: z4.literal("session_settled"),
4596
+ session_id: z4.string(),
4597
+ total_cost: z4.number(),
4598
+ messages_count: z4.number(),
4599
+ duration_seconds: z4.number(),
4600
+ refunded: z4.number()
4601
+ });
4602
+ var SessionErrorMessageSchema = z4.object({
4603
+ type: z4.literal("session_error"),
4604
+ session_id: z4.string(),
4605
+ code: z4.string(),
4606
+ message: z4.string()
4607
+ });
4608
+ var SESSION_MESSAGE_TYPES = /* @__PURE__ */ new Set([
4609
+ "session_open",
4610
+ "session_ack",
4611
+ "session_message",
4612
+ "session_end",
4613
+ "session_settled",
4614
+ "session_error"
4615
+ ]);
4616
+
4617
+ // src/relay/types.ts
4618
+ var RegisterMessageSchema = z5.object({
4619
+ type: z5.literal("register"),
4620
+ owner: z5.string().min(1),
4453
4621
  /** V8: Cryptographic agent identity. When present, used as the canonical key. */
4454
- agent_id: z4.string().optional(),
4622
+ agent_id: z5.string().optional(),
4455
4623
  /** V8 Phase 3: Server identifier for multi-agent delegation. */
4456
- server_id: z4.string().optional(),
4457
- token: z4.string().min(1),
4458
- card: z4.record(z4.unknown()),
4624
+ server_id: z5.string().optional(),
4625
+ token: z5.string().min(1),
4626
+ card: z5.record(z5.unknown()),
4459
4627
  // CapabilityCard (validated separately)
4460
- cards: z4.array(z4.record(z4.unknown())).optional(),
4628
+ cards: z5.array(z5.record(z5.unknown())).optional(),
4461
4629
  // Additional cards (e.g., conductor card)
4462
4630
  /** V8 Phase 3: Additional agents served by this server (multi-agent registration). */
4463
- agents: z4.array(z4.object({
4464
- agent_id: z4.string().min(1),
4465
- display_name: z4.string().min(1),
4466
- cards: z4.array(z4.record(z4.unknown())),
4467
- delegation_token: z4.record(z4.unknown()).optional()
4631
+ agents: z5.array(z5.object({
4632
+ agent_id: z5.string().min(1),
4633
+ display_name: z5.string().min(1),
4634
+ cards: z5.array(z5.record(z5.unknown())),
4635
+ delegation_token: z5.record(z5.unknown()).optional()
4468
4636
  })).optional()
4469
4637
  });
4470
- var RegisteredMessageSchema = z4.object({
4471
- type: z4.literal("registered"),
4472
- agent_id: z4.string()
4638
+ var RegisteredMessageSchema = z5.object({
4639
+ type: z5.literal("registered"),
4640
+ agent_id: z5.string()
4473
4641
  });
4474
- var RelayRequestMessageSchema = z4.object({
4475
- type: z4.literal("relay_request"),
4476
- id: z4.string().uuid(),
4477
- target_owner: z4.string().min(1),
4642
+ var RelayRequestMessageSchema = z5.object({
4643
+ type: z5.literal("relay_request"),
4644
+ id: z5.string().uuid(),
4645
+ target_owner: z5.string().min(1),
4478
4646
  /** V8: Target agent's cryptographic identity. Preferred over target_owner. */
4479
- target_agent_id: z4.string().optional(),
4480
- card_id: z4.string(),
4481
- skill_id: z4.string().optional(),
4482
- params: z4.record(z4.unknown()).default({}),
4483
- requester: z4.string().optional(),
4484
- escrow_receipt: z4.record(z4.unknown()).optional(),
4647
+ target_agent_id: z5.string().optional(),
4648
+ card_id: z5.string(),
4649
+ skill_id: z5.string().optional(),
4650
+ params: z5.record(z5.unknown()).default({}),
4651
+ requester: z5.string().optional(),
4652
+ escrow_receipt: z5.record(z5.unknown()).optional(),
4485
4653
  /** Optional UCAN token for capability delegation. */
4486
- ucan_token: z4.string().optional()
4654
+ ucan_token: z5.string().optional()
4487
4655
  });
4488
- var IncomingRequestMessageSchema = z4.object({
4489
- type: z4.literal("incoming_request"),
4490
- id: z4.string().uuid(),
4491
- from_owner: z4.string().min(1),
4492
- card_id: z4.string(),
4493
- skill_id: z4.string().optional(),
4494
- params: z4.record(z4.unknown()).default({}),
4495
- requester: z4.string().optional(),
4496
- escrow_receipt: z4.record(z4.unknown()).optional(),
4656
+ var IncomingRequestMessageSchema = z5.object({
4657
+ type: z5.literal("incoming_request"),
4658
+ id: z5.string().uuid(),
4659
+ from_owner: z5.string().min(1),
4660
+ card_id: z5.string(),
4661
+ skill_id: z5.string().optional(),
4662
+ params: z5.record(z5.unknown()).default({}),
4663
+ requester: z5.string().optional(),
4664
+ escrow_receipt: z5.record(z5.unknown()).optional(),
4497
4665
  /** Optional UCAN token for capability delegation. */
4498
- ucan_token: z4.string().optional()
4666
+ ucan_token: z5.string().optional()
4499
4667
  });
4500
- var RelayResponseMessageSchema = z4.object({
4501
- type: z4.literal("relay_response"),
4502
- id: z4.string().uuid(),
4503
- result: z4.unknown().optional(),
4504
- error: z4.object({
4505
- code: z4.number(),
4506
- message: z4.string()
4668
+ var RelayResponseMessageSchema = z5.object({
4669
+ type: z5.literal("relay_response"),
4670
+ id: z5.string().uuid(),
4671
+ result: z5.unknown().optional(),
4672
+ error: z5.object({
4673
+ code: z5.number(),
4674
+ message: z5.string()
4507
4675
  }).optional()
4508
4676
  });
4509
- var ResponseMessageSchema = z4.object({
4510
- type: z4.literal("response"),
4511
- id: z4.string().uuid(),
4512
- result: z4.unknown().optional(),
4513
- error: z4.object({
4514
- code: z4.number(),
4515
- message: z4.string()
4677
+ var ResponseMessageSchema = z5.object({
4678
+ type: z5.literal("response"),
4679
+ id: z5.string().uuid(),
4680
+ result: z5.unknown().optional(),
4681
+ error: z5.object({
4682
+ code: z5.number(),
4683
+ message: z5.string()
4516
4684
  }).optional()
4517
4685
  });
4518
- var ErrorMessageSchema = z4.object({
4519
- type: z4.literal("error"),
4520
- code: z4.string(),
4521
- message: z4.string(),
4522
- request_id: z4.string().optional()
4686
+ var ErrorMessageSchema = z5.object({
4687
+ type: z5.literal("error"),
4688
+ code: z5.string(),
4689
+ message: z5.string(),
4690
+ request_id: z5.string().optional()
4523
4691
  });
4524
- var RelayProgressMessageSchema = z4.object({
4525
- type: z4.literal("relay_progress"),
4526
- id: z4.string().uuid(),
4692
+ var RelayProgressMessageSchema = z5.object({
4693
+ type: z5.literal("relay_progress"),
4694
+ id: z5.string().uuid(),
4527
4695
  // request ID this progress relates to
4528
- progress: z4.number().min(0).max(100).optional(),
4696
+ progress: z5.number().min(0).max(100).optional(),
4529
4697
  // optional percentage
4530
- message: z4.string().optional()
4698
+ message: z5.string().optional()
4531
4699
  // optional status message
4532
4700
  });
4533
- var RelayStartedMessageSchema = z4.object({
4534
- type: z4.literal("relay_started"),
4535
- id: z4.string().uuid(),
4536
- message: z4.string().optional()
4701
+ var RelayStartedMessageSchema = z5.object({
4702
+ type: z5.literal("relay_started"),
4703
+ id: z5.string().uuid(),
4704
+ message: z5.string().optional()
4537
4705
  });
4538
- var HeartbeatMessageSchema = z4.object({
4539
- type: z4.literal("heartbeat"),
4540
- owner: z4.string().min(1),
4541
- capacity: z4.object({
4542
- current_load: z4.number(),
4543
- max_concurrent: z4.number(),
4544
- queue_depth: z4.number()
4706
+ var HeartbeatMessageSchema = z5.object({
4707
+ type: z5.literal("heartbeat"),
4708
+ owner: z5.string().min(1),
4709
+ capacity: z5.object({
4710
+ current_load: z5.number(),
4711
+ max_concurrent: z5.number(),
4712
+ queue_depth: z5.number()
4545
4713
  }),
4546
- self_summary: z4.object({
4547
- capabilities: z4.array(z4.string()),
4548
- success_rate: z4.number(),
4549
- credit_balance: z4.number(),
4550
- total_completed: z4.number(),
4551
- provider_number: z4.number(),
4552
- reliability: z4.object({
4553
- current_streak: z4.number(),
4554
- repeat_hire_rate: z4.number(),
4555
- avg_feedback: z4.number()
4714
+ self_summary: z5.object({
4715
+ capabilities: z5.array(z5.string()),
4716
+ success_rate: z5.number(),
4717
+ credit_balance: z5.number(),
4718
+ total_completed: z5.number(),
4719
+ provider_number: z5.number(),
4720
+ reliability: z5.object({
4721
+ current_streak: z5.number(),
4722
+ repeat_hire_rate: z5.number(),
4723
+ avg_feedback: z5.number()
4556
4724
  })
4557
4725
  })
4558
4726
  });
4559
- var EscrowHoldMessageSchema = z4.object({
4560
- type: z4.literal("escrow_hold"),
4561
- consumer_agent_id: z4.string().min(1),
4562
- provider_agent_id: z4.string().min(1),
4563
- skill_id: z4.string().min(1),
4564
- amount: z4.number().positive(),
4565
- request_id: z4.string().uuid(),
4566
- signature: z4.string().optional(),
4567
- public_key: z4.string().optional()
4727
+ var EscrowHoldMessageSchema = z5.object({
4728
+ type: z5.literal("escrow_hold"),
4729
+ consumer_agent_id: z5.string().min(1),
4730
+ provider_agent_id: z5.string().min(1),
4731
+ skill_id: z5.string().min(1),
4732
+ amount: z5.number().positive(),
4733
+ request_id: z5.string().uuid(),
4734
+ signature: z5.string().optional(),
4735
+ public_key: z5.string().optional()
4568
4736
  });
4569
- var EscrowHoldConfirmedMessageSchema = z4.object({
4570
- type: z4.literal("escrow_hold_confirmed"),
4571
- request_id: z4.string(),
4572
- escrow_id: z4.string(),
4573
- hold_amount: z4.number(),
4574
- consumer_remaining: z4.number()
4737
+ var EscrowHoldConfirmedMessageSchema = z5.object({
4738
+ type: z5.literal("escrow_hold_confirmed"),
4739
+ request_id: z5.string(),
4740
+ escrow_id: z5.string(),
4741
+ hold_amount: z5.number(),
4742
+ consumer_remaining: z5.number()
4575
4743
  });
4576
- var EscrowSettleMessageSchema = z4.object({
4577
- type: z4.literal("escrow_settle"),
4578
- escrow_id: z4.string().min(1),
4579
- request_id: z4.string().uuid(),
4580
- success: z4.boolean(),
4581
- failure_reason: z4.enum(["bad_execution", "overload", "timeout", "auth_error", "not_found"]).optional(),
4582
- result_hash: z4.string().optional(),
4583
- signature: z4.string().optional(),
4584
- public_key: z4.string().optional(),
4585
- consumer_agent_id: z4.string().optional()
4744
+ var EscrowSettleMessageSchema = z5.object({
4745
+ type: z5.literal("escrow_settle"),
4746
+ escrow_id: z5.string().min(1),
4747
+ request_id: z5.string().uuid(),
4748
+ success: z5.boolean(),
4749
+ failure_reason: z5.enum(["bad_execution", "overload", "timeout", "auth_error", "not_found"]).optional(),
4750
+ result_hash: z5.string().optional(),
4751
+ signature: z5.string().optional(),
4752
+ public_key: z5.string().optional(),
4753
+ consumer_agent_id: z5.string().optional()
4586
4754
  });
4587
- var EscrowSettledMessageSchema = z4.object({
4588
- type: z4.literal("escrow_settled"),
4589
- escrow_id: z4.string(),
4590
- request_id: z4.string(),
4591
- provider_earned: z4.number(),
4592
- network_fee: z4.number(),
4593
- consumer_remaining: z4.number(),
4594
- provider_balance: z4.number()
4755
+ var EscrowSettledMessageSchema = z5.object({
4756
+ type: z5.literal("escrow_settled"),
4757
+ escrow_id: z5.string(),
4758
+ request_id: z5.string(),
4759
+ provider_earned: z5.number(),
4760
+ network_fee: z5.number(),
4761
+ consumer_remaining: z5.number(),
4762
+ provider_balance: z5.number()
4595
4763
  });
4596
- var BalanceSyncMessageSchema = z4.object({
4597
- type: z4.literal("balance_sync"),
4598
- agent_id: z4.string().min(1)
4764
+ var BalanceSyncMessageSchema = z5.object({
4765
+ type: z5.literal("balance_sync"),
4766
+ agent_id: z5.string().min(1)
4599
4767
  });
4600
- var BalanceSyncResponseMessageSchema = z4.object({
4601
- type: z4.literal("balance_sync_response"),
4602
- agent_id: z4.string(),
4603
- balance: z4.number()
4768
+ var BalanceSyncResponseMessageSchema = z5.object({
4769
+ type: z5.literal("balance_sync_response"),
4770
+ agent_id: z5.string(),
4771
+ balance: z5.number()
4604
4772
  });
4605
- var RelayMessageSchema = z4.discriminatedUnion("type", [
4773
+ var RelayMessageSchema = z5.discriminatedUnion("type", [
4606
4774
  RegisterMessageSchema,
4607
4775
  RegisteredMessageSchema,
4608
4776
  RelayRequestMessageSchema,
@@ -4618,7 +4786,13 @@ var RelayMessageSchema = z4.discriminatedUnion("type", [
4618
4786
  EscrowSettleMessageSchema,
4619
4787
  EscrowSettledMessageSchema,
4620
4788
  BalanceSyncMessageSchema,
4621
- BalanceSyncResponseMessageSchema
4789
+ BalanceSyncResponseMessageSchema,
4790
+ SessionOpenMessageSchema,
4791
+ SessionAckMessageSchema,
4792
+ SessionMessageMessageSchema,
4793
+ SessionEndMessageSchema,
4794
+ SessionSettledMessageSchema,
4795
+ SessionErrorMessageSchema
4622
4796
  ]);
4623
4797
 
4624
4798
  // src/relay/websocket-client.ts
@@ -5005,8 +5179,8 @@ import { randomUUID as randomUUID12 } from "crypto";
5005
5179
  import { randomUUID as randomUUID13 } from "crypto";
5006
5180
 
5007
5181
  // src/cli/peers.ts
5008
- import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
5009
- import { join as join4 } from "path";
5182
+ import { readFileSync as readFileSync5, writeFileSync as writeFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
5183
+ import { join as join5 } from "path";
5010
5184
 
5011
5185
  // src/autonomy/auto-request.ts
5012
5186
  function minMaxNormalize(values) {
@@ -5123,7 +5297,8 @@ async function matchSubTasks(opts) {
5123
5297
  }
5124
5298
 
5125
5299
  // src/conductor/budget-controller.ts
5126
- var ORCHESTRATION_FEE = 5;
5300
+ var coreConductor = loadCoreConfig("economics");
5301
+ var ORCHESTRATION_FEE = coreConductor?.conductor?.orchestration_fee ?? 5;
5127
5302
  var BudgetController = class {
5128
5303
  /**
5129
5304
  * Creates a new BudgetController.
@@ -5539,8 +5714,9 @@ async function orchestrate(opts) {
5539
5714
  }
5540
5715
 
5541
5716
  // src/credit/budget.ts
5717
+ var coreBudget = loadCoreConfig("economics");
5542
5718
  var DEFAULT_BUDGET_CONFIG = {
5543
- reserve_credits: 20
5719
+ reserve_credits: coreBudget?.budget_reserve_credits ?? 20
5544
5720
  };
5545
5721
  var BudgetManager = class {
5546
5722
  /**
@@ -5978,18 +6154,18 @@ var ConductorMode = class {
5978
6154
  };
5979
6155
 
5980
6156
  // src/credit/escrow-receipt.ts
5981
- import { z as z5 } from "zod";
6157
+ import { z as z6 } from "zod";
5982
6158
  import { randomUUID as randomUUID15 } from "crypto";
5983
- var EscrowReceiptSchema = z5.object({
5984
- requester_owner: z5.string().min(1),
5985
- requester_agent_id: z5.string().optional(),
5986
- requester_public_key: z5.string().min(1),
5987
- amount: z5.number().positive(),
5988
- card_id: z5.string().min(1),
5989
- skill_id: z5.string().optional(),
5990
- timestamp: z5.string(),
5991
- nonce: z5.string().uuid(),
5992
- signature: z5.string().min(1)
6159
+ var EscrowReceiptSchema = z6.object({
6160
+ requester_owner: z6.string().min(1),
6161
+ requester_agent_id: z6.string().optional(),
6162
+ requester_public_key: z6.string().min(1),
6163
+ amount: z6.number().positive(),
6164
+ card_id: z6.string().min(1),
6165
+ skill_id: z6.string().optional(),
6166
+ timestamp: z6.string(),
6167
+ nonce: z6.string().uuid(),
6168
+ signature: z6.string().min(1)
5993
6169
  });
5994
6170
  function createSignedEscrowReceipt(db, privateKey, publicKey, opts) {
5995
6171
  const escrowId = holdEscrow(db, opts.owner, opts.amount, opts.cardId);
@@ -6310,16 +6486,16 @@ var AgentBnBProvider = class {
6310
6486
  };
6311
6487
 
6312
6488
  // src/identity/guarantor.ts
6313
- import { z as z6 } from "zod";
6489
+ import { z as z7 } from "zod";
6314
6490
  import { randomUUID as randomUUID16 } from "crypto";
6315
6491
  var MAX_AGENTS_PER_GUARANTOR = 10;
6316
6492
  var GUARANTOR_CREDIT_POOL = 50;
6317
- var GuarantorRecordSchema = z6.object({
6318
- id: z6.string().uuid(),
6319
- github_login: z6.string().min(1),
6320
- agent_count: z6.number().int().nonnegative(),
6321
- credit_pool: z6.number().int().nonnegative(),
6322
- created_at: z6.string().datetime()
6493
+ var GuarantorRecordSchema = z7.object({
6494
+ id: z7.string().uuid(),
6495
+ github_login: z7.string().min(1),
6496
+ agent_count: z7.number().int().nonnegative(),
6497
+ credit_pool: z7.number().int().nonnegative(),
6498
+ created_at: z7.string().datetime()
6323
6499
  });
6324
6500
  var GUARANTOR_SCHEMA = `
6325
6501
  CREATE TABLE IF NOT EXISTS guarantors (
@@ -6429,9 +6605,10 @@ function initiateGithubAuth() {
6429
6605
  }
6430
6606
 
6431
6607
  // src/relay/websocket-relay.ts
6432
- import { randomUUID as randomUUID19 } from "crypto";
6608
+ import { randomUUID as randomUUID20 } from "crypto";
6433
6609
 
6434
6610
  // src/relay/relay-credit.ts
6611
+ var coreConductorFee = loadCoreConfig("economics");
6435
6612
  function lookupCardPrice(registryDb, cardId, skillId) {
6436
6613
  const row = registryDb.prepare("SELECT data FROM capability_cards WHERE id = ?").get(cardId);
6437
6614
  if (!row) return null;
@@ -6478,8 +6655,11 @@ function settleForRelay(creditDb, escrowId, recipientOwner) {
6478
6655
  }
6479
6656
  function calculateConductorFee(totalSubTaskCost) {
6480
6657
  if (totalSubTaskCost <= 0) return 0;
6481
- const fee = Math.ceil(totalSubTaskCost * 0.1);
6482
- return Math.max(1, Math.min(20, fee));
6658
+ const rate = coreConductorFee?.conductor?.sub_task_fee_rate ?? 0.1;
6659
+ const min = coreConductorFee?.conductor?.sub_task_fee_min ?? 1;
6660
+ const max = coreConductorFee?.conductor?.sub_task_fee_max ?? 20;
6661
+ const fee = Math.ceil(totalSubTaskCost * rate);
6662
+ return Math.max(min, Math.min(max, fee));
6483
6663
  }
6484
6664
  function releaseForRelay(creditDb, escrowId) {
6485
6665
  if (escrowId === void 0) return;
@@ -6533,10 +6713,9 @@ function processEscrowSettle(creditDb, escrowId, success, providerAgentId, signa
6533
6713
  if (!escrowRow) {
6534
6714
  throw new Error(`Escrow not found or already settled: ${escrowId}`);
6535
6715
  }
6536
- const NETWORK_FEE_RATE2 = 0.05;
6537
6716
  if (success) {
6538
6717
  settleEscrow(creditDb, escrowId, providerAgentId);
6539
- const networkFee = Math.floor(escrowRow.amount * NETWORK_FEE_RATE2);
6718
+ const networkFee = Math.floor(escrowRow.amount * NETWORK_FEE_RATE);
6540
6719
  const providerAmount = escrowRow.amount - networkFee;
6541
6720
  return {
6542
6721
  escrow_id: escrowId,
@@ -6601,12 +6780,413 @@ function handleJobRelayResponse(opts) {
6601
6780
  }
6602
6781
  }
6603
6782
 
6783
+ // src/session/session-manager.ts
6784
+ import { randomUUID as randomUUID19 } from "crypto";
6785
+
6786
+ // src/session/session-escrow.ts
6787
+ var SessionEscrow = class {
6788
+ constructor(creditDb) {
6789
+ this.creditDb = creditDb;
6790
+ }
6791
+ /** escrowId → { budget, spent } */
6792
+ tracking = /* @__PURE__ */ new Map();
6793
+ /**
6794
+ * Hold the full session budget in escrow.
6795
+ * @returns The escrow ID for tracking.
6796
+ */
6797
+ holdBudget(owner, budget, cardId) {
6798
+ const escrowId = holdEscrow(this.creditDb, owner, budget, cardId);
6799
+ this.tracking.set(escrowId, { budget, spent: 0 });
6800
+ return escrowId;
6801
+ }
6802
+ /**
6803
+ * Record a per-message deduction against the session budget.
6804
+ * Does not touch the DB — tracking is in-memory until settle.
6805
+ */
6806
+ deductMessage(escrowId, rate) {
6807
+ return this.deduct(escrowId, rate);
6808
+ }
6809
+ /**
6810
+ * Record a per-minute deduction against the session budget.
6811
+ */
6812
+ deductMinute(escrowId, rate) {
6813
+ return this.deduct(escrowId, rate);
6814
+ }
6815
+ /**
6816
+ * Settle the session escrow. Pays the provider the actual cost and
6817
+ * refunds the remainder to the requester.
6818
+ */
6819
+ settle(escrowId, providerOwner) {
6820
+ const t = this.tracking.get(escrowId);
6821
+ if (!t) {
6822
+ settleEscrow(this.creditDb, escrowId, providerOwner);
6823
+ return;
6824
+ }
6825
+ if (t.spent <= 0) {
6826
+ releaseEscrow(this.creditDb, escrowId);
6827
+ } else {
6828
+ settleEscrow(this.creditDb, escrowId, providerOwner);
6829
+ }
6830
+ this.tracking.delete(escrowId);
6831
+ }
6832
+ /**
6833
+ * Release the escrow entirely — full refund to requester.
6834
+ */
6835
+ refund(escrowId) {
6836
+ releaseEscrow(this.creditDb, escrowId);
6837
+ this.tracking.delete(escrowId);
6838
+ }
6839
+ /**
6840
+ * Get remaining budget for a session escrow.
6841
+ */
6842
+ getRemainingBudget(escrowId) {
6843
+ const t = this.tracking.get(escrowId);
6844
+ if (!t) return 0;
6845
+ return t.budget - t.spent;
6846
+ }
6847
+ /**
6848
+ * Get total spent for a session escrow.
6849
+ */
6850
+ getSpent(escrowId) {
6851
+ return this.tracking.get(escrowId)?.spent ?? 0;
6852
+ }
6853
+ /**
6854
+ * Check if the budget is exhausted.
6855
+ */
6856
+ isBudgetExhausted(escrowId) {
6857
+ return this.getRemainingBudget(escrowId) <= 0;
6858
+ }
6859
+ /**
6860
+ * Calculate the cost for a single interaction based on pricing model.
6861
+ */
6862
+ calculateCost(pricingModel, rate, durationMinutes) {
6863
+ switch (pricingModel) {
6864
+ case "per_message":
6865
+ return rate;
6866
+ case "per_minute":
6867
+ return Math.ceil(durationMinutes ?? 1) * rate;
6868
+ case "per_session":
6869
+ return rate;
6870
+ }
6871
+ }
6872
+ deduct(escrowId, amount) {
6873
+ const t = this.tracking.get(escrowId);
6874
+ if (!t) {
6875
+ throw new Error(`No session escrow tracking for ${escrowId}`);
6876
+ }
6877
+ t.spent += amount;
6878
+ return { spent: t.spent, remaining: t.budget - t.spent };
6879
+ }
6880
+ };
6881
+
6882
+ // src/session/session-manager.ts
6883
+ var SessionManager = class {
6884
+ sessions = /* @__PURE__ */ new Map();
6885
+ idleTimers = /* @__PURE__ */ new Map();
6886
+ durationTimers = /* @__PURE__ */ new Map();
6887
+ escrow;
6888
+ config;
6889
+ sendToAgent;
6890
+ /** Maps agent connection key → set of session IDs they participate in. */
6891
+ agentSessions = /* @__PURE__ */ new Map();
6892
+ constructor(opts) {
6893
+ this.escrow = new SessionEscrow(opts.creditDb);
6894
+ this.config = opts.config ?? loadSessionConfig();
6895
+ this.sendToAgent = opts.sendToAgent;
6896
+ }
6897
+ /**
6898
+ * Open a new session between requester and provider.
6899
+ */
6900
+ openSession(msg, requesterKey) {
6901
+ const requesterSessions = this.agentSessions.get(requesterKey);
6902
+ if (requesterSessions && requesterSessions.size >= this.config.abuse.max_concurrent_sessions_per_agent) {
6903
+ this.sendToAgent(requesterKey, {
6904
+ type: "session_error",
6905
+ session_id: msg.session_id,
6906
+ code: "MAX_CONCURRENT_SESSIONS",
6907
+ message: `Maximum concurrent sessions (${this.config.abuse.max_concurrent_sessions_per_agent}) reached`
6908
+ });
6909
+ throw new Error("Max concurrent sessions reached");
6910
+ }
6911
+ const escrowId = this.escrow.holdBudget(msg.requester_id, msg.budget, msg.card_id);
6912
+ const now = (/* @__PURE__ */ new Date()).toISOString();
6913
+ const session = {
6914
+ id: msg.session_id,
6915
+ requester_id: msg.requester_id,
6916
+ provider_id: msg.provider_id,
6917
+ skill_id: msg.skill_id,
6918
+ card_id: msg.card_id,
6919
+ status: "open",
6920
+ escrow_id: escrowId,
6921
+ budget: msg.budget,
6922
+ spent: 0,
6923
+ pricing_model: msg.pricing_model,
6924
+ messages: [],
6925
+ created_at: now,
6926
+ updated_at: now
6927
+ };
6928
+ this.sessions.set(session.id, session);
6929
+ this.trackAgentSession(requesterKey, session.id);
6930
+ this.trackAgentSession(msg.provider_id, session.id);
6931
+ this.sendToAgent(requesterKey, {
6932
+ type: "session_ack",
6933
+ session_id: session.id,
6934
+ escrow_id: escrowId,
6935
+ status: "open"
6936
+ });
6937
+ const initialMsg = this.createMessage(session.id, "requester", msg.initial_message);
6938
+ session.messages.push(initialMsg);
6939
+ session.status = "active";
6940
+ session.updated_at = (/* @__PURE__ */ new Date()).toISOString();
6941
+ this.sendToAgent(msg.provider_id, {
6942
+ type: "session_message",
6943
+ session_id: session.id,
6944
+ sender: "requester",
6945
+ content: msg.initial_message
6946
+ });
6947
+ if (session.pricing_model === "per_session") {
6948
+ const cost = this.config.pricing.per_session_flat_rate;
6949
+ this.escrow.deductMessage(escrowId, cost);
6950
+ session.spent = cost;
6951
+ }
6952
+ this.resetIdleTimer(session.id);
6953
+ this.startDurationTimer(session.id);
6954
+ return session;
6955
+ }
6956
+ /**
6957
+ * Route a message within an active session.
6958
+ */
6959
+ routeMessage(msg, senderKey) {
6960
+ const session = this.sessions.get(msg.session_id);
6961
+ if (!session) {
6962
+ this.sendToAgent(senderKey, {
6963
+ type: "session_error",
6964
+ session_id: msg.session_id,
6965
+ code: "SESSION_NOT_FOUND",
6966
+ message: "Session not found"
6967
+ });
6968
+ return;
6969
+ }
6970
+ if (session.status !== "active") {
6971
+ this.sendToAgent(senderKey, {
6972
+ type: "session_error",
6973
+ session_id: msg.session_id,
6974
+ code: "SESSION_NOT_ACTIVE",
6975
+ message: `Session is ${session.status}, not active`
6976
+ });
6977
+ return;
6978
+ }
6979
+ if (session.messages.length >= this.config.pricing.max_messages_per_session) {
6980
+ this.endSessionInternal(session, "budget_exhausted");
6981
+ return;
6982
+ }
6983
+ if (session.pricing_model === "per_message" && msg.sender === "provider") {
6984
+ const rate = this.config.pricing.per_message_base_rate;
6985
+ const { remaining } = this.escrow.deductMessage(session.escrow_id, rate);
6986
+ session.spent += rate;
6987
+ if (remaining <= 0) {
6988
+ const record2 = this.createMessage(session.id, msg.sender, msg.content, msg.metadata);
6989
+ session.messages.push(record2);
6990
+ session.updated_at = (/* @__PURE__ */ new Date()).toISOString();
6991
+ const targetKey2 = this.getCounterpartyKey(session, msg.sender);
6992
+ this.sendToAgent(targetKey2, {
6993
+ type: "session_message",
6994
+ session_id: session.id,
6995
+ sender: msg.sender,
6996
+ content: msg.content,
6997
+ metadata: msg.metadata
6998
+ });
6999
+ this.endSessionInternal(session, "budget_exhausted");
7000
+ return;
7001
+ }
7002
+ }
7003
+ const record = this.createMessage(session.id, msg.sender, msg.content, msg.metadata);
7004
+ session.messages.push(record);
7005
+ session.updated_at = (/* @__PURE__ */ new Date()).toISOString();
7006
+ const targetKey = this.getCounterpartyKey(session, msg.sender);
7007
+ this.sendToAgent(targetKey, {
7008
+ type: "session_message",
7009
+ session_id: session.id,
7010
+ sender: msg.sender,
7011
+ content: msg.content,
7012
+ metadata: msg.metadata
7013
+ });
7014
+ this.resetIdleTimer(session.id);
7015
+ }
7016
+ /**
7017
+ * End a session at the request of either party.
7018
+ */
7019
+ endSession(msg, _senderKey) {
7020
+ const session = this.sessions.get(msg.session_id);
7021
+ if (!session) return;
7022
+ if (session.status === "settled" || session.status === "closed") return;
7023
+ this.endSessionInternal(session, msg.reason);
7024
+ }
7025
+ /**
7026
+ * Handle agent disconnection — end all their active sessions.
7027
+ */
7028
+ handleDisconnect(agentKey) {
7029
+ const sessionIds = this.agentSessions.get(agentKey);
7030
+ if (!sessionIds) return;
7031
+ for (const sessionId of sessionIds) {
7032
+ const session = this.sessions.get(sessionId);
7033
+ if (session && session.status !== "settled" && session.status !== "closed") {
7034
+ this.endSessionInternal(session, "error");
7035
+ }
7036
+ }
7037
+ }
7038
+ /** Get a session by ID. */
7039
+ getSession(sessionId) {
7040
+ return this.sessions.get(sessionId);
7041
+ }
7042
+ /** List sessions, optionally filtered by agent. */
7043
+ listSessions(agentId) {
7044
+ if (!agentId) return Array.from(this.sessions.values());
7045
+ return Array.from(this.sessions.values()).filter(
7046
+ (s) => s.requester_id === agentId || s.provider_id === agentId
7047
+ );
7048
+ }
7049
+ /** Clean up all timers (for graceful shutdown). */
7050
+ shutdown() {
7051
+ for (const timer of this.idleTimers.values()) clearTimeout(timer);
7052
+ for (const timer of this.durationTimers.values()) clearTimeout(timer);
7053
+ this.idleTimers.clear();
7054
+ this.durationTimers.clear();
7055
+ }
7056
+ // -------------------------------------------------------------------------
7057
+ // Internal helpers
7058
+ // -------------------------------------------------------------------------
7059
+ endSessionInternal(session, reason) {
7060
+ session.status = "closing";
7061
+ session.end_reason = reason;
7062
+ session.ended_at = (/* @__PURE__ */ new Date()).toISOString();
7063
+ this.clearTimers(session.id);
7064
+ if (session.spent > 0) {
7065
+ this.escrow.settle(session.escrow_id, session.provider_id);
7066
+ } else {
7067
+ this.escrow.refund(session.escrow_id);
7068
+ }
7069
+ const durationMs = Date.now() - new Date(session.created_at).getTime();
7070
+ const settledMsg = {
7071
+ type: "session_settled",
7072
+ session_id: session.id,
7073
+ total_cost: session.spent,
7074
+ messages_count: session.messages.length,
7075
+ duration_seconds: Math.round(durationMs / 1e3),
7076
+ refunded: session.budget - session.spent
7077
+ };
7078
+ session.status = "settled";
7079
+ session.updated_at = (/* @__PURE__ */ new Date()).toISOString();
7080
+ this.sendToAgent(session.requester_id, settledMsg);
7081
+ this.sendToAgent(session.provider_id, settledMsg);
7082
+ session.status = "closed";
7083
+ this.untrackAgentSession(session.requester_id, session.id);
7084
+ this.untrackAgentSession(session.provider_id, session.id);
7085
+ }
7086
+ resetIdleTimer(sessionId) {
7087
+ const existing = this.idleTimers.get(sessionId);
7088
+ if (existing) clearTimeout(existing);
7089
+ const timer = setTimeout(() => {
7090
+ const session = this.sessions.get(sessionId);
7091
+ if (session && session.status === "active") {
7092
+ this.endSessionInternal(session, "timeout");
7093
+ }
7094
+ }, this.config.timeouts.idle_timeout_ms);
7095
+ this.idleTimers.set(sessionId, timer);
7096
+ }
7097
+ startDurationTimer(sessionId) {
7098
+ const timer = setTimeout(() => {
7099
+ const session = this.sessions.get(sessionId);
7100
+ if (session && session.status !== "settled" && session.status !== "closed") {
7101
+ this.endSessionInternal(session, "timeout");
7102
+ }
7103
+ }, this.config.timeouts.max_session_duration_ms);
7104
+ this.durationTimers.set(sessionId, timer);
7105
+ }
7106
+ clearTimers(sessionId) {
7107
+ const idle = this.idleTimers.get(sessionId);
7108
+ if (idle) {
7109
+ clearTimeout(idle);
7110
+ this.idleTimers.delete(sessionId);
7111
+ }
7112
+ const dur = this.durationTimers.get(sessionId);
7113
+ if (dur) {
7114
+ clearTimeout(dur);
7115
+ this.durationTimers.delete(sessionId);
7116
+ }
7117
+ }
7118
+ createMessage(sessionId, sender, content, metadata) {
7119
+ return {
7120
+ id: randomUUID19(),
7121
+ session_id: sessionId,
7122
+ sender,
7123
+ content,
7124
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
7125
+ metadata
7126
+ };
7127
+ }
7128
+ getCounterpartyKey(session, sender) {
7129
+ return sender === "requester" ? session.provider_id : session.requester_id;
7130
+ }
7131
+ trackAgentSession(agentKey, sessionId) {
7132
+ let set = this.agentSessions.get(agentKey);
7133
+ if (!set) {
7134
+ set = /* @__PURE__ */ new Set();
7135
+ this.agentSessions.set(agentKey, set);
7136
+ }
7137
+ set.add(sessionId);
7138
+ }
7139
+ untrackAgentSession(agentKey, sessionId) {
7140
+ const set = this.agentSessions.get(agentKey);
7141
+ if (set) {
7142
+ set.delete(sessionId);
7143
+ if (set.size === 0) this.agentSessions.delete(agentKey);
7144
+ }
7145
+ }
7146
+ };
7147
+
7148
+ // src/session/session-relay.ts
7149
+ function attachSessionHandler(opts) {
7150
+ const { sessionManager } = opts;
7151
+ return {
7152
+ handleSessionMessage(msg, senderKey) {
7153
+ if (!SESSION_MESSAGE_TYPES.has(msg.type)) return false;
7154
+ switch (msg.type) {
7155
+ case "session_open": {
7156
+ const parsed = SessionOpenMessageSchema.parse(msg);
7157
+ sessionManager.openSession(parsed, senderKey);
7158
+ return true;
7159
+ }
7160
+ case "session_message": {
7161
+ const parsed = SessionMessageMessageSchema.parse(msg);
7162
+ sessionManager.routeMessage(parsed, senderKey);
7163
+ return true;
7164
+ }
7165
+ case "session_end": {
7166
+ const parsed = SessionEndMessageSchema.parse(msg);
7167
+ sessionManager.endSession(parsed, senderKey);
7168
+ return true;
7169
+ }
7170
+ // session_ack, session_settled, session_error are relay→agent only
7171
+ // They should not arrive from agents, but we silently absorb them
7172
+ case "session_ack":
7173
+ case "session_settled":
7174
+ case "session_error":
7175
+ return true;
7176
+ default:
7177
+ return false;
7178
+ }
7179
+ }
7180
+ };
7181
+ }
7182
+
6604
7183
  // src/relay/websocket-relay.ts
6605
- var RATE_LIMIT_MAX = 60;
6606
- var RATE_LIMIT_WINDOW_MS = 6e4;
6607
- var RELAY_IDLE_TIMEOUT_MS = 3e4;
6608
- var RELAY_HARD_TIMEOUT_MS = 3e5;
6609
- var RELAY_DISCONNECT_GRACE_MS = RELAY_HARD_TIMEOUT_MS + 3e4;
7184
+ var coreRelay = loadCoreConfig("relay");
7185
+ var RATE_LIMIT_MAX = coreRelay?.rate_limit_max ?? 60;
7186
+ var RATE_LIMIT_WINDOW_MS = coreRelay?.rate_limit_window_ms ?? 6e4;
7187
+ var RELAY_IDLE_TIMEOUT_MS = coreRelay?.relay_idle_timeout_ms ?? 3e4;
7188
+ var RELAY_HARD_TIMEOUT_MS = coreRelay?.relay_hard_timeout_ms ?? 3e5;
7189
+ var RELAY_DISCONNECT_GRACE_MS = coreRelay?.relay_disconnect_grace_ms ?? RELAY_HARD_TIMEOUT_MS + 3e4;
6610
7190
  function readTimeoutOverride(envKey, fallbackMs) {
6611
7191
  const raw = process.env[envKey];
6612
7192
  if (!raw) return fallbackMs;
@@ -6837,7 +7417,7 @@ function registerWebSocketRelay(server, db, creditDb) {
6837
7417
  function logAgentJoined(owner, cardName, cardId) {
6838
7418
  try {
6839
7419
  insertRequestLog(db, {
6840
- id: randomUUID19(),
7420
+ id: randomUUID20(),
6841
7421
  card_id: cardId,
6842
7422
  card_name: cardName,
6843
7423
  requester: owner,
@@ -6855,6 +7435,19 @@ function registerWebSocketRelay(server, db, creditDb) {
6855
7435
  ws.send(JSON.stringify(msg));
6856
7436
  }
6857
7437
  }
7438
+ function sendToAgentByKey(agentKey, msg) {
7439
+ const connKey = resolveConnectionKey(agentKey);
7440
+ const ws = connKey ? connections.get(connKey) : void 0;
7441
+ if (ws && ws.readyState === 1) {
7442
+ ws.send(JSON.stringify(msg));
7443
+ }
7444
+ }
7445
+ const sessionManager = creditDb ? new SessionManager({
7446
+ creditDb,
7447
+ sendToAgent: sendToAgentByKey,
7448
+ isAgentOnline: (key) => !!resolveConnectionKey(key)
7449
+ }) : void 0;
7450
+ const sessionHandler = sessionManager ? attachSessionHandler({ sessionManager }) : void 0;
6858
7451
  function handleRegister(ws, msg) {
6859
7452
  const { owner, card } = msg;
6860
7453
  const existing = connections.get(owner);
@@ -7074,6 +7667,9 @@ function registerWebSocketRelay(server, db, creditDb) {
7074
7667
  }
7075
7668
  }
7076
7669
  markOwnerOffline(owner);
7670
+ if (sessionManager) {
7671
+ sessionManager.handleDisconnect(owner);
7672
+ }
7077
7673
  for (const [reqId, pending] of pendingRequests) {
7078
7674
  if (pending.targetOwner === owner) {
7079
7675
  clearPendingTimers(pending);
@@ -7268,6 +7864,13 @@ function registerWebSocketRelay(server, db, creditDb) {
7268
7864
  handleBalanceSync(socket, msg);
7269
7865
  break;
7270
7866
  default:
7867
+ if (sessionHandler && registeredOwner) {
7868
+ const handled = sessionHandler.handleSessionMessage(
7869
+ msg,
7870
+ registeredOwner
7871
+ );
7872
+ if (handled) break;
7873
+ }
7271
7874
  break;
7272
7875
  }
7273
7876
  })();
@@ -7302,6 +7905,7 @@ function registerWebSocketRelay(server, db, creditDb) {
7302
7905
  pendingRequests.clear();
7303
7906
  rateLimits.clear();
7304
7907
  agentCapacities.clear();
7908
+ if (sessionManager) sessionManager.shutdown();
7305
7909
  },
7306
7910
  setOnAgentOnline: (cb) => {
7307
7911
  onAgentOnlineCallback = cb;
@@ -7317,12 +7921,12 @@ function registerWebSocketRelay(server, db, creditDb) {
7317
7921
  }
7318
7922
 
7319
7923
  // src/onboarding/index.ts
7320
- import { randomUUID as randomUUID21 } from "crypto";
7321
- import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
7322
- import { join as join5 } from "path";
7924
+ import { randomUUID as randomUUID22 } from "crypto";
7925
+ import { existsSync as existsSync5, readFileSync as readFileSync6 } from "fs";
7926
+ import { join as join6 } from "path";
7323
7927
 
7324
7928
  // src/cli/onboarding.ts
7325
- import { randomUUID as randomUUID20 } from "crypto";
7929
+ import { randomUUID as randomUUID21 } from "crypto";
7326
7930
  import { createConnection } from "net";
7327
7931
  var KNOWN_API_KEYS = [
7328
7932
  "OPENAI_API_KEY",
@@ -7418,9 +8022,9 @@ var DOC_FILES = ["SOUL.md", "CLAUDE.md", "AGENTS.md", "README.md"];
7418
8022
  function detectCapabilities(opts = {}) {
7419
8023
  const cwd = opts.cwd ?? process.cwd();
7420
8024
  if (opts.fromFile) {
7421
- const filePath = opts.fromFile.startsWith("/") ? opts.fromFile : join5(cwd, opts.fromFile);
8025
+ const filePath = opts.fromFile.startsWith("/") ? opts.fromFile : join6(cwd, opts.fromFile);
7422
8026
  if (existsSync5(filePath)) {
7423
- const content = readFileSync5(filePath, "utf-8");
8027
+ const content = readFileSync6(filePath, "utf-8");
7424
8028
  const capabilities = detectFromDocs(content);
7425
8029
  if (capabilities.length > 0) {
7426
8030
  return { source: "docs", capabilities, sourceFile: filePath };
@@ -7429,9 +8033,9 @@ function detectCapabilities(opts = {}) {
7429
8033
  return { source: "none", capabilities: [] };
7430
8034
  }
7431
8035
  for (const fileName of DOC_FILES) {
7432
- const filePath = join5(cwd, fileName);
8036
+ const filePath = join6(cwd, fileName);
7433
8037
  if (!existsSync5(filePath)) continue;
7434
- const content = readFileSync5(filePath, "utf-8");
8038
+ const content = readFileSync6(filePath, "utf-8");
7435
8039
  if (fileName === "SOUL.md") {
7436
8040
  return { source: "soul", capabilities: [], soulContent: content, sourceFile: filePath };
7437
8041
  }
@@ -7464,7 +8068,7 @@ function capabilitiesToV2Card(capabilities, owner, agentName) {
7464
8068
  }));
7465
8069
  const card = {
7466
8070
  spec_version: "2.0",
7467
- id: randomUUID21(),
8071
+ id: randomUUID22(),
7468
8072
  owner,
7469
8073
  agent_name: agentName ?? owner,
7470
8074
  skills,