agentbnb 8.2.0 → 8.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/{chunk-TBJ3FZKZ.js → chunk-4IPJJRTP.js} +1 -1
  2. package/dist/chunk-CKOOVZOI.js +158 -0
  3. package/dist/chunk-CQFBNTGT.js +145 -0
  4. package/dist/{chunk-P4LOYSLA.js → chunk-DYQOFGGI.js} +331 -416
  5. package/dist/{chunk-ALX4WS3A.js → chunk-EG6RS4JC.js} +70 -46
  6. package/dist/{chunk-CUONY5TO.js → chunk-EJKW57ZV.js} +19 -1
  7. package/dist/{chunk-5AAFG2V2.js → chunk-LKLKYXLV.js} +239 -24
  8. package/dist/{chunk-7EF3HYVZ.js → chunk-MCED4GDW.js} +499 -86
  9. package/dist/{chunk-YHY7OG6S.js → chunk-MWOXW7JQ.js} +7 -7
  10. package/dist/{chunk-E2OKP5CY.js → chunk-QCGIG7WW.js} +182 -86
  11. package/dist/{chunk-5GME4KJZ.js → chunk-QHZGOG3O.js} +148 -46
  12. package/dist/{chunk-D6RKW2XG.js → chunk-RYISHSHB.js} +302 -4
  13. package/dist/{chunk-O2OYBAVR.js → chunk-S3V6R3EN.js} +75 -39
  14. package/dist/{chunk-X32NE6V4.js → chunk-WNXXLCV5.js} +1 -1
  15. package/dist/{chunk-C537SFHV.js → chunk-XBGVQMQJ.js} +72 -48
  16. package/dist/{chunk-FTZTEHYG.js → chunk-Z2GEFFDO.js} +135 -8
  17. package/dist/cli/index.js +42 -67
  18. package/dist/{client-HKV3QWZ3.js → client-XOLP5IUZ.js} +4 -2
  19. package/dist/{conduct-W6XF6DJW.js → conduct-AZFLNUX3.js} +10 -11
  20. package/dist/{conduct-YB64OHI6.js → conduct-VPUYTNEA.js} +10 -11
  21. package/dist/{conductor-mode-AKREGDIU.js → conductor-mode-PLTB6MS3.js} +7 -8
  22. package/dist/{conductor-mode-TFCVCQHU.js → conductor-mode-WKB42PYM.js} +6 -3
  23. package/dist/{execute-EPE6MZLT.js → execute-NNDCXTN4.js} +3 -2
  24. package/dist/{execute-AYQWORVH.js → execute-RIRHTIBU.js} +6 -5
  25. package/dist/index.d.ts +8 -8
  26. package/dist/index.js +637 -693
  27. package/dist/{publish-capability-AH2HDW54.js → publish-capability-QDR2QIZ2.js} +2 -2
  28. package/dist/{request-HCCXSKAY.js → request-NX7GSPIG.js} +31 -36
  29. package/dist/{serve-skill-SZAQT5T5.js → serve-skill-E6EJQYAK.js} +10 -9
  30. package/dist/{server-LMY2A3GT.js → server-VBCT32FC.js} +12 -18
  31. package/dist/{service-coordinator-WGH6B2VT.js → service-coordinator-KMSA6BST.js} +137 -69
  32. package/dist/skills/agentbnb/bootstrap.js +561 -247
  33. package/package.json +13 -17
  34. package/skills/agentbnb/bootstrap.test.ts +8 -6
  35. package/skills/agentbnb/bootstrap.ts +21 -13
  36. package/skills/agentbnb/install.sh +0 -0
  37. package/dist/chunk-64AK4FJM.js +0 -84
  38. package/dist/chunk-KF3TZHA5.js +0 -91
  39. package/dist/chunk-LJM7FHPM.js +0 -138
  40. package/dist/chunk-OH7BP5NP.js +0 -96
@@ -319,7 +319,10 @@ var V2_FTS_TRIGGERS = `
319
319
  new.id,
320
320
  new.owner,
321
321
  COALESCE(
322
- (SELECT group_concat(json_extract(value, '$.name'), ' ')
322
+ (SELECT group_concat(
323
+ COALESCE(json_extract(value, '$.id'), '') || ' ' || COALESCE(json_extract(value, '$.name'), ''),
324
+ ' '
325
+ )
323
326
  FROM json_each(json_extract(new.data, '$.skills'))),
324
327
  json_extract(new.data, '$.name'),
325
328
  ''
@@ -359,7 +362,10 @@ var V2_FTS_TRIGGERS = `
359
362
  old.id,
360
363
  old.owner,
361
364
  COALESCE(
362
- (SELECT group_concat(json_extract(value, '$.name'), ' ')
365
+ (SELECT group_concat(
366
+ COALESCE(json_extract(value, '$.id'), '') || ' ' || COALESCE(json_extract(value, '$.name'), ''),
367
+ ' '
368
+ )
363
369
  FROM json_each(json_extract(old.data, '$.skills'))),
364
370
  json_extract(old.data, '$.name'),
365
371
  ''
@@ -395,7 +401,10 @@ var V2_FTS_TRIGGERS = `
395
401
  new.id,
396
402
  new.owner,
397
403
  COALESCE(
398
- (SELECT group_concat(json_extract(value, '$.name'), ' ')
404
+ (SELECT group_concat(
405
+ COALESCE(json_extract(value, '$.id'), '') || ' ' || COALESCE(json_extract(value, '$.name'), ''),
406
+ ' '
407
+ )
399
408
  FROM json_each(json_extract(new.data, '$.skills'))),
400
409
  json_extract(new.data, '$.name'),
401
410
  ''
@@ -435,7 +444,10 @@ var V2_FTS_TRIGGERS = `
435
444
  old.id,
436
445
  old.owner,
437
446
  COALESCE(
438
- (SELECT group_concat(json_extract(value, '$.name'), ' ')
447
+ (SELECT group_concat(
448
+ COALESCE(json_extract(value, '$.id'), '') || ' ' || COALESCE(json_extract(value, '$.name'), ''),
449
+ ' '
450
+ )
439
451
  FROM json_each(json_extract(old.data, '$.skills'))),
440
452
  json_extract(old.data, '$.name'),
441
453
  ''
@@ -502,6 +514,15 @@ function openDatabase(path = ":memory:") {
502
514
  tags,
503
515
  content=""
504
516
  );
517
+
518
+ -- Expression index for capability_type lookups (used by Conductor routing).
519
+ -- Turns json_extract full-table-scan into O(log n) B-tree lookup.
520
+ CREATE INDEX IF NOT EXISTS idx_cards_capability_type
521
+ ON capability_cards(json_extract(data, '$.capability_type'));
522
+
523
+ -- Owner index for listCards(owner) and other owner-scoped queries.
524
+ CREATE INDEX IF NOT EXISTS idx_cards_owner
525
+ ON capability_cards(owner);
505
526
  `);
506
527
  createRequestLogTable(db);
507
528
  initFeedbackTable(db);
@@ -513,6 +534,10 @@ function runMigrations(db) {
513
534
  const version = db.pragma("user_version")[0]?.user_version ?? 0;
514
535
  if (version < 2) {
515
536
  migrateV1toV2(db);
537
+ return;
538
+ }
539
+ if (version < 3) {
540
+ migrateV2toV3(db);
516
541
  }
517
542
  }
518
543
  function migrateV1toV2(db) {
@@ -554,44 +579,55 @@ function migrateV1toV2(db) {
554
579
  );
555
580
  }
556
581
  db.exec(V2_FTS_TRIGGERS);
557
- db.exec(`INSERT INTO cards_fts(cards_fts) VALUES('delete-all')`);
558
- const allRows = db.prepare("SELECT rowid, id, owner, data FROM capability_cards").all();
559
- const ftsInsert = db.prepare(
560
- "INSERT INTO cards_fts(rowid, id, owner, name, description, tags) VALUES (?, ?, ?, ?, ?, ?)"
561
- );
562
- for (const row of allRows) {
563
- const data = JSON.parse(row.data);
564
- const skills = data["skills"] ?? [];
565
- let name;
566
- let description;
567
- let tags;
568
- if (skills.length > 0) {
569
- name = skills.map((s) => String(s["name"] ?? "")).join(" ");
570
- description = skills.map((s) => String(s["description"] ?? "")).join(" ");
571
- tags = [
572
- // tags from metadata.tags[]
573
- ...skills.flatMap((s) => {
574
- const meta = s["metadata"];
575
- return meta?.["tags"] ?? [];
576
- }),
577
- // capability_type (singular)
578
- ...skills.map((s) => s["capability_type"]).filter((v) => typeof v === "string" && v.length > 0),
579
- // capability_types[] (plural)
580
- ...skills.flatMap((s) => s["capability_types"] ?? [])
581
- ].join(" ");
582
- } else {
583
- name = String(data["name"] ?? "");
584
- description = String(data["description"] ?? "");
585
- const meta = data["metadata"];
586
- const rawTags = meta?.["tags"] ?? [];
587
- tags = rawTags.join(" ");
588
- }
589
- ftsInsert.run(row.rowid, row.id, row.owner, name, description, tags);
590
- }
591
- db.pragma("user_version = 2");
582
+ rebuildCardsFts(db);
583
+ db.pragma("user_version = 3");
592
584
  });
593
585
  migrate();
594
586
  }
587
+ function migrateV2toV3(db) {
588
+ const migrate = db.transaction(() => {
589
+ db.exec(V2_FTS_TRIGGERS);
590
+ rebuildCardsFts(db);
591
+ db.pragma("user_version = 3");
592
+ });
593
+ migrate();
594
+ }
595
+ function rebuildCardsFts(db) {
596
+ db.exec(`INSERT INTO cards_fts(cards_fts) VALUES('delete-all')`);
597
+ const allRows = db.prepare("SELECT rowid, id, owner, data FROM capability_cards").all();
598
+ const ftsInsert = db.prepare(
599
+ "INSERT INTO cards_fts(rowid, id, owner, name, description, tags) VALUES (?, ?, ?, ?, ?, ?)"
600
+ );
601
+ for (const row of allRows) {
602
+ const data = JSON.parse(row.data);
603
+ const skills = data["skills"] ?? [];
604
+ let name;
605
+ let description;
606
+ let tags;
607
+ if (skills.length > 0) {
608
+ name = skills.map((s) => `${String(s["id"] ?? "")} ${String(s["name"] ?? "")}`.trim()).join(" ");
609
+ description = skills.map((s) => String(s["description"] ?? "")).join(" ");
610
+ tags = [
611
+ // tags from metadata.tags[]
612
+ ...skills.flatMap((s) => {
613
+ const meta = s["metadata"];
614
+ return meta?.["tags"] ?? [];
615
+ }),
616
+ // capability_type (singular)
617
+ ...skills.map((s) => s["capability_type"]).filter((v) => typeof v === "string" && v.length > 0),
618
+ // capability_types[] (plural)
619
+ ...skills.flatMap((s) => s["capability_types"] ?? [])
620
+ ].join(" ");
621
+ } else {
622
+ name = String(data["name"] ?? "");
623
+ description = String(data["description"] ?? "");
624
+ const meta = data["metadata"];
625
+ const rawTags = meta?.["tags"] ?? [];
626
+ tags = rawTags.join(" ");
627
+ }
628
+ ftsInsert.run(row.rowid, row.id, row.owner, name, description, tags);
629
+ }
630
+ }
595
631
  function insertCard(db, card) {
596
632
  const now = (/* @__PURE__ */ new Date()).toISOString();
597
633
  const withTimestamps = { ...card, created_at: card.created_at ?? now, updated_at: now };
@@ -759,6 +795,9 @@ var AGENTS_SCHEMA = `
759
795
  function ensureAgentsTable(db) {
760
796
  db.exec(AGENTS_SCHEMA);
761
797
  }
798
+ function lookupAgent(db, agentId) {
799
+ return db.prepare("SELECT * FROM agents WHERE agent_id = ?").get(agentId) ?? null;
800
+ }
762
801
 
763
802
  // src/credit/ledger.ts
764
803
  var CREDIT_SCHEMA = `
@@ -839,10 +878,23 @@ function getBalance(db, owner) {
839
878
  const row = db.prepare("SELECT balance FROM credit_balances WHERE owner = ?").get(owner);
840
879
  return row?.balance ?? 0;
841
880
  }
842
- function getTransactions(db, owner, limit = 100) {
881
+ function getTransactions(db, owner, opts = 100) {
882
+ const page = typeof opts === "number" ? { limit: opts } : opts;
883
+ const limit = page.limit ?? 100;
884
+ const conditions = ["owner = ?"];
885
+ const params = [owner];
886
+ if (page.before) {
887
+ conditions.push("created_at < ?");
888
+ params.push(page.before);
889
+ }
890
+ if (page.after) {
891
+ conditions.push("created_at > ?");
892
+ params.push(page.after);
893
+ }
894
+ params.push(limit);
843
895
  return db.prepare(
844
- "SELECT id, owner, amount, reason, reference_id, created_at FROM credit_transactions WHERE owner = ? ORDER BY created_at DESC LIMIT ?"
845
- ).all(owner, limit);
896
+ `SELECT id, owner, amount, reason, reference_id, created_at FROM credit_transactions WHERE ${conditions.join(" AND ")} ORDER BY created_at DESC LIMIT ?`
897
+ ).all(...params);
846
898
  }
847
899
  function registerProvider(db, owner) {
848
900
  const now = (/* @__PURE__ */ new Date()).toISOString();
@@ -1067,56 +1119,414 @@ function confirmEscrowDebit(db, escrowId) {
1067
1119
  confirm();
1068
1120
  }
1069
1121
 
1070
- // src/credit/signing.ts
1071
- import { generateKeyPairSync, sign, verify, createPublicKey, createPrivateKey } from "crypto";
1072
- import { writeFileSync, readFileSync, existsSync, chmodSync } from "fs";
1073
- import { join } from "path";
1074
- function generateKeyPair() {
1075
- const { publicKey, privateKey } = generateKeyPairSync("ed25519", {
1076
- publicKeyEncoding: { type: "spki", format: "der" },
1077
- privateKeyEncoding: { type: "pkcs8", format: "der" }
1122
+ // src/feedback/reputation.ts
1123
+ var QUALITY_SCORES = {
1124
+ excellent: 1,
1125
+ good: 0.8,
1126
+ acceptable: 0.6,
1127
+ poor: 0.3,
1128
+ failed: 0
1129
+ };
1130
+ var COST_VALUE_SCORES = {
1131
+ great: 1,
1132
+ fair: 0.6,
1133
+ overpriced: 0.2
1134
+ };
1135
+ var DECAY_DAYS = 30;
1136
+ var WEIGHTS = {
1137
+ rating: 0.4,
1138
+ quality: 0.3,
1139
+ would_reuse: 0.2,
1140
+ cost_value: 0.1
1141
+ };
1142
+ function computeReputation(feedbacks) {
1143
+ if (feedbacks.length === 0) return 0.5;
1144
+ const now = Date.now();
1145
+ let weightedSum = 0;
1146
+ let totalWeight = 0;
1147
+ for (const fb of feedbacks) {
1148
+ const feedbackDate = new Date(fb.timestamp).getTime();
1149
+ const ageDays = Math.max(0, (now - feedbackDate) / (1e3 * 60 * 60 * 24));
1150
+ const recencyWeight = Math.exp(-ageDays / DECAY_DAYS);
1151
+ const ratingScore = (fb.rating - 1) / 4;
1152
+ const qualityScore = QUALITY_SCORES[fb.result_quality];
1153
+ const reuseScore = fb.would_reuse ? 1 : 0;
1154
+ const costScore = COST_VALUE_SCORES[fb.cost_value_ratio];
1155
+ const componentScore = WEIGHTS.rating * ratingScore + WEIGHTS.quality * qualityScore + WEIGHTS.would_reuse * reuseScore + WEIGHTS.cost_value * costScore;
1156
+ weightedSum += recencyWeight * componentScore;
1157
+ totalWeight += recencyWeight;
1158
+ }
1159
+ if (totalWeight === 0) return 0.5;
1160
+ const raw = weightedSum / totalWeight;
1161
+ return Math.max(0, Math.min(1, raw));
1162
+ }
1163
+ function getReputationScore(db, agentId) {
1164
+ const feedbacks = getFeedbackForProvider(db, agentId);
1165
+ return computeReputation(feedbacks);
1166
+ }
1167
+
1168
+ // src/registry/matcher.ts
1169
+ var CACHE_MAX_ENTRIES = 100;
1170
+ var CACHE_TTL_MS = 3e4;
1171
+ var dbCaches = /* @__PURE__ */ new WeakMap();
1172
+ function getDbCache(db) {
1173
+ let cache = dbCaches.get(db);
1174
+ if (!cache) {
1175
+ cache = /* @__PURE__ */ new Map();
1176
+ dbCaches.set(db, cache);
1177
+ }
1178
+ return cache;
1179
+ }
1180
+ function cacheKey(query, filters) {
1181
+ return `${query}|${filters.level ?? ""}|${filters.online ?? ""}|${(filters.apis_used ?? []).join(",")}|${filters.min_reputation ?? ""}`;
1182
+ }
1183
+ function evictCache(cache) {
1184
+ const now = Date.now();
1185
+ for (const [key, entry] of cache) {
1186
+ if (entry.expiresAt <= now) cache.delete(key);
1187
+ }
1188
+ while (cache.size > CACHE_MAX_ENTRIES) {
1189
+ const firstKey = cache.keys().next().value;
1190
+ cache.delete(firstKey);
1191
+ }
1192
+ }
1193
+ function searchCards(db, query, filters = {}) {
1194
+ const cache = getDbCache(db);
1195
+ const key = cacheKey(query, filters);
1196
+ const cached = cache.get(key);
1197
+ if (cached && cached.expiresAt > Date.now()) {
1198
+ return cached.results;
1199
+ }
1200
+ const trimmedQuery = query.trim();
1201
+ const exactSkillMatches = findCardsByExactSkillId(db, trimmedQuery, filters);
1202
+ const words = query.trim().split(/\s+/).map((w) => w.replace(/["*^{}():]/g, "")).filter((w) => w.length > 0);
1203
+ if (words.length === 0) {
1204
+ return exactSkillMatches;
1205
+ }
1206
+ const ftsQuery = words.map((w) => `"${w}"`).join(" OR ");
1207
+ const conditions = [];
1208
+ const params = [ftsQuery];
1209
+ if (filters.level !== void 0) {
1210
+ conditions.push(`json_extract(cc.data, '$.level') = ?`);
1211
+ params.push(filters.level);
1212
+ }
1213
+ if (filters.online !== void 0) {
1214
+ conditions.push(`json_extract(cc.data, '$.availability.online') = ?`);
1215
+ params.push(filters.online ? 1 : 0);
1216
+ }
1217
+ const whereClause = conditions.length > 0 ? `AND ${conditions.join(" AND ")}` : "";
1218
+ const sql = `
1219
+ SELECT cc.data
1220
+ FROM capability_cards cc
1221
+ JOIN cards_fts ON cc.rowid = cards_fts.rowid
1222
+ WHERE cards_fts MATCH ?
1223
+ ${whereClause}
1224
+ ORDER BY bm25(cards_fts)
1225
+ LIMIT 50
1226
+ `;
1227
+ const stmt = db.prepare(sql);
1228
+ const rows = stmt.all(...params);
1229
+ const results = rows.map((row) => JSON.parse(row.data));
1230
+ const mergedResults = mergeByCardId(exactSkillMatches, results);
1231
+ let filtered = mergedResults;
1232
+ if (filters.apis_used && filters.apis_used.length > 0) {
1233
+ const requiredApis = filters.apis_used;
1234
+ filtered = filtered.filter((card) => {
1235
+ const cardApis = card.metadata?.apis_used ?? [];
1236
+ return requiredApis.every((api) => cardApis.includes(api));
1237
+ });
1238
+ }
1239
+ if (filters.min_reputation !== void 0 && filters.min_reputation > 0) {
1240
+ filtered = applyReputationFilter(db, filtered, filters.min_reputation);
1241
+ }
1242
+ evictCache(cache);
1243
+ cache.set(key, { results: filtered, expiresAt: Date.now() + CACHE_TTL_MS });
1244
+ return filtered;
1245
+ }
1246
+ function mergeByCardId(primary, secondary) {
1247
+ const seen = /* @__PURE__ */ new Set();
1248
+ const merged = [];
1249
+ for (const card of primary) {
1250
+ if (seen.has(card.id)) continue;
1251
+ seen.add(card.id);
1252
+ merged.push(card);
1253
+ }
1254
+ for (const card of secondary) {
1255
+ if (seen.has(card.id)) continue;
1256
+ seen.add(card.id);
1257
+ merged.push(card);
1258
+ }
1259
+ return merged;
1260
+ }
1261
+ function findCardsByExactSkillId(db, query, filters) {
1262
+ if (query.length === 0) return [];
1263
+ const rows = db.prepare("SELECT data FROM capability_cards").all();
1264
+ const cards = rows.map((row) => JSON.parse(row.data));
1265
+ return cards.filter((card) => {
1266
+ if (filters.level !== void 0 && card.level !== filters.level) return false;
1267
+ if (filters.online !== void 0 && card.availability?.online !== filters.online) return false;
1268
+ const asRecord = card;
1269
+ const skills = asRecord["skills"];
1270
+ if (!Array.isArray(skills)) return false;
1271
+ return skills.some((skill) => String(skill["id"] ?? "") === query);
1078
1272
  });
1079
- return {
1080
- publicKey: Buffer.from(publicKey),
1081
- privateKey: Buffer.from(privateKey)
1082
- };
1083
1273
  }
1084
- function saveKeyPair(configDir, keys) {
1085
- const privatePath = join(configDir, "private.key");
1086
- const publicPath = join(configDir, "public.key");
1087
- writeFileSync(privatePath, keys.privateKey);
1088
- chmodSync(privatePath, 384);
1089
- writeFileSync(publicPath, keys.publicKey);
1090
- }
1091
- function loadKeyPair(configDir) {
1092
- const privatePath = join(configDir, "private.key");
1093
- const publicPath = join(configDir, "public.key");
1094
- if (!existsSync(privatePath) || !existsSync(publicPath)) {
1095
- throw new AgentBnBError("Keypair not found. Run `agentbnb init` to generate one.", "KEYPAIR_NOT_FOUND");
1274
+ function filterCards(db, filters) {
1275
+ const conditions = [];
1276
+ const params = [];
1277
+ if (filters.level !== void 0) {
1278
+ conditions.push(`json_extract(data, '$.level') = ?`);
1279
+ params.push(filters.level);
1280
+ }
1281
+ if (filters.online !== void 0) {
1282
+ conditions.push(`json_extract(data, '$.availability.online') = ?`);
1283
+ params.push(filters.online ? 1 : 0);
1284
+ }
1285
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
1286
+ const sql = `SELECT data FROM capability_cards ${whereClause}`;
1287
+ const stmt = db.prepare(sql);
1288
+ const rows = stmt.all(...params);
1289
+ let cards = rows.map((row) => JSON.parse(row.data));
1290
+ if (filters.min_reputation !== void 0 && filters.min_reputation > 0) {
1291
+ cards = applyReputationFilter(db, cards, filters.min_reputation);
1292
+ }
1293
+ return cards;
1294
+ }
1295
+ function applyReputationFilter(db, cards, minReputation) {
1296
+ const owners = [...new Set(cards.map((c) => c.owner))];
1297
+ const reputationMap = /* @__PURE__ */ new Map();
1298
+ for (const owner of owners) {
1299
+ reputationMap.set(owner, getReputationScore(db, owner));
1300
+ }
1301
+ return cards.filter((card) => {
1302
+ const score = reputationMap.get(card.owner) ?? 0.5;
1303
+ return score >= minReputation;
1304
+ });
1305
+ }
1306
+ function buildReputationMap(db, owners) {
1307
+ const unique = [...new Set(owners)];
1308
+ const map = /* @__PURE__ */ new Map();
1309
+ for (const owner of unique) {
1310
+ map.set(owner, getReputationScore(db, owner));
1311
+ }
1312
+ return map;
1313
+ }
1314
+
1315
+ // src/cli/remote-registry.ts
1316
+ var RegistryTimeoutError = class extends AgentBnBError {
1317
+ constructor(url) {
1318
+ super(
1319
+ `Registry at ${url} did not respond within 5s. Showing local results only.`,
1320
+ "REGISTRY_TIMEOUT"
1321
+ );
1322
+ this.name = "RegistryTimeoutError";
1323
+ }
1324
+ };
1325
+ var RegistryConnectionError = class extends AgentBnBError {
1326
+ constructor(url) {
1327
+ super(
1328
+ `Cannot reach ${url}. Is the registry running? Showing local results only.`,
1329
+ "REGISTRY_CONNECTION"
1330
+ );
1331
+ this.name = "RegistryConnectionError";
1332
+ }
1333
+ };
1334
+ var RegistryAuthError = class extends AgentBnBError {
1335
+ constructor(url) {
1336
+ super(
1337
+ `Authentication failed for ${url}. Run \`agentbnb config set token <your-token>\`.`,
1338
+ "REGISTRY_AUTH"
1339
+ );
1340
+ this.name = "RegistryAuthError";
1341
+ }
1342
+ };
1343
+ async function fetchRemoteCards(registryUrl, params, timeoutMs = 5e3) {
1344
+ let cardsUrl;
1345
+ try {
1346
+ cardsUrl = new URL("/cards", registryUrl);
1347
+ } catch {
1348
+ throw new AgentBnBError(`Invalid registry URL: ${registryUrl}`, "INVALID_REGISTRY_URL");
1349
+ }
1350
+ const searchParams = new URLSearchParams();
1351
+ if (params.q !== void 0) searchParams.set("q", params.q);
1352
+ if (params.level !== void 0) searchParams.set("level", String(params.level));
1353
+ if (params.online !== void 0) searchParams.set("online", String(params.online));
1354
+ if (params.tag !== void 0) searchParams.set("tag", params.tag);
1355
+ searchParams.set("limit", "100");
1356
+ cardsUrl.search = searchParams.toString();
1357
+ const controller = new AbortController();
1358
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
1359
+ let response;
1360
+ try {
1361
+ response = await fetch(cardsUrl.toString(), { signal: controller.signal });
1362
+ } catch (err) {
1363
+ clearTimeout(timer);
1364
+ const isTimeout = err instanceof Error && err.name === "AbortError";
1365
+ if (isTimeout) {
1366
+ throw new RegistryTimeoutError(registryUrl);
1367
+ }
1368
+ throw new RegistryConnectionError(registryUrl);
1369
+ } finally {
1370
+ clearTimeout(timer);
1371
+ }
1372
+ if (response.status === 401 || response.status === 403) {
1373
+ throw new RegistryAuthError(registryUrl);
1374
+ }
1375
+ if (!response.ok) {
1376
+ throw new RegistryConnectionError(registryUrl);
1377
+ }
1378
+ const body = await response.json();
1379
+ return body.items;
1380
+ }
1381
+ function mergeResults(localCards, remoteCards, hasQuery) {
1382
+ const taggedLocal = localCards.map((c) => ({ ...c, source: "local" }));
1383
+ const taggedRemote = remoteCards.map((c) => ({ ...c, source: "remote" }));
1384
+ const localIds = new Set(localCards.map((c) => c.id));
1385
+ const dedupedRemote = taggedRemote.filter((c) => !localIds.has(c.id));
1386
+ if (!hasQuery) {
1387
+ return [...taggedLocal, ...dedupedRemote];
1388
+ }
1389
+ const result = [];
1390
+ const maxLen = Math.max(taggedLocal.length, dedupedRemote.length);
1391
+ for (let i = 0; i < maxLen; i++) {
1392
+ if (i < taggedLocal.length) result.push(taggedLocal[i]);
1393
+ if (i < dedupedRemote.length) result.push(dedupedRemote[i]);
1394
+ }
1395
+ return result;
1396
+ }
1397
+
1398
+ // src/gateway/resolve-target-capability.ts
1399
+ function canQueryLocalDb(db) {
1400
+ return Boolean(db) && typeof db.prepare === "function";
1401
+ }
1402
+ function getGatewayUrl(card) {
1403
+ if (typeof card.gateway_url === "string" && card.gateway_url.length > 0) {
1404
+ return card.gateway_url;
1096
1405
  }
1406
+ const internal = card._internal;
1407
+ const internalGateway = internal?.["gateway_url"];
1408
+ return typeof internalGateway === "string" ? internalGateway : "";
1409
+ }
1410
+ function isOnline(card) {
1411
+ return card.availability?.online !== false;
1412
+ }
1413
+ function scoreSkill(skill, query) {
1414
+ const q = query.toLowerCase();
1415
+ if (skill.id.toLowerCase() === q) return 100;
1416
+ let score = 0;
1417
+ if (skill.id.toLowerCase().includes(q)) score += 40;
1418
+ if (skill.name.toLowerCase().includes(q)) score += 20;
1419
+ if (skill.description.toLowerCase().includes(q)) score += 10;
1420
+ return score;
1421
+ }
1422
+ function pickSkill(card, queryOrId) {
1423
+ const skills = Array.isArray(card.skills) ? card.skills : [];
1424
+ if (skills.length === 0) return void 0;
1425
+ const exact = skills.find((s) => s.id === queryOrId);
1426
+ if (exact) return exact;
1427
+ const scored = skills.map((skill) => ({ skill, score: scoreSkill(skill, queryOrId) })).sort((a, b) => b.score - a.score);
1428
+ if ((scored[0]?.score ?? 0) > 0) return scored[0]?.skill;
1429
+ return skills[0];
1430
+ }
1431
+ function toResolved(card, queryOrId, source) {
1432
+ const skill = pickSkill(card, queryOrId);
1433
+ const gatewayUrl = getGatewayUrl(card);
1434
+ const viaRelay = source === "local" ? false : gatewayUrl.length === 0;
1435
+ const resolvedSource = viaRelay ? "relay" : source;
1097
1436
  return {
1098
- publicKey: readFileSync(publicPath),
1099
- privateKey: readFileSync(privatePath)
1437
+ cardId: card.id,
1438
+ skillId: skill?.id,
1439
+ owner: card.owner,
1440
+ gateway_url: gatewayUrl,
1441
+ via_relay: viaRelay,
1442
+ credits_per_call: skill?.pricing.credits_per_call ?? card.pricing.credits_per_call,
1443
+ source: resolvedSource
1100
1444
  };
1101
1445
  }
1102
- function canonicalJson(data) {
1103
- return JSON.stringify(data, Object.keys(data).sort());
1446
+ function findLocalBySkillId(db, skillId, onlineOnly) {
1447
+ const rows = db.prepare("SELECT data FROM capability_cards").all();
1448
+ for (const row of rows) {
1449
+ const card = JSON.parse(row.data);
1450
+ if (onlineOnly && !isOnline(card)) continue;
1451
+ const skills = Array.isArray(card.skills) ? card.skills : [];
1452
+ if (skills.some((s) => s.id === skillId)) {
1453
+ return card;
1454
+ }
1455
+ }
1456
+ return null;
1457
+ }
1458
+ function findRemoteBySkillId(cards, skillId) {
1459
+ for (const card of cards) {
1460
+ const skills = Array.isArray(card.skills) ? card.skills : [];
1461
+ if (skills.some((s) => s.id === skillId)) return card;
1462
+ }
1463
+ return null;
1104
1464
  }
1105
- function signEscrowReceipt(data, privateKey) {
1106
- const message = Buffer.from(canonicalJson(data), "utf-8");
1107
- const keyObject = createPrivateKey({ key: privateKey, format: "der", type: "pkcs8" });
1108
- const signature = sign(null, message, keyObject);
1109
- return signature.toString("base64url");
1465
+ function looksLikeCardId(value) {
1466
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
1110
1467
  }
1111
- function verifyEscrowReceipt(data, signature, publicKey) {
1468
+ async function resolveTargetCapability(queryOrId, options) {
1469
+ const { registryDb, registryUrl, onlineOnly = true } = options;
1470
+ const needle = queryOrId.trim();
1471
+ if (needle.length === 0) return null;
1472
+ if (canQueryLocalDb(registryDb)) {
1473
+ const byCardId = getCard(registryDb, needle);
1474
+ if (byCardId && (!onlineOnly || isOnline(byCardId))) {
1475
+ return toResolved(byCardId, needle, "local");
1476
+ }
1477
+ const bySkillId = findLocalBySkillId(registryDb, needle, onlineOnly);
1478
+ if (bySkillId) {
1479
+ return toResolved(bySkillId, needle, "local");
1480
+ }
1481
+ const localMatches = searchCards(registryDb, needle, { online: onlineOnly ? true : void 0 });
1482
+ if (localMatches.length > 0) {
1483
+ return toResolved(localMatches[0], needle, "local");
1484
+ }
1485
+ }
1486
+ if (!registryUrl) return null;
1487
+ if (looksLikeCardId(needle)) {
1488
+ try {
1489
+ const cardResp = await fetch(`${registryUrl.replace(/\/$/, "")}/cards/${encodeURIComponent(needle)}`);
1490
+ if (cardResp.ok) {
1491
+ const remoteCard = await cardResp.json();
1492
+ if (!onlineOnly || isOnline(remoteCard)) {
1493
+ return toResolved(remoteCard, needle, "remote");
1494
+ }
1495
+ }
1496
+ } catch {
1497
+ }
1498
+ }
1112
1499
  try {
1113
- const message = Buffer.from(canonicalJson(data), "utf-8");
1114
- const keyObject = createPublicKey({ key: publicKey, format: "der", type: "spki" });
1115
- const sigBuffer = Buffer.from(signature, "base64url");
1116
- return verify(null, message, keyObject, sigBuffer);
1500
+ const remoteMatches = await fetchRemoteCards(registryUrl, {
1501
+ q: needle,
1502
+ ...onlineOnly ? { online: true } : {}
1503
+ });
1504
+ if (remoteMatches.length > 0) {
1505
+ const exactSkill = findRemoteBySkillId(remoteMatches, needle);
1506
+ if (exactSkill) return toResolved(exactSkill, needle, "remote");
1507
+ return toResolved(remoteMatches[0], needle, "remote");
1508
+ }
1509
+ } catch {
1510
+ }
1511
+ try {
1512
+ const onlineCards = await fetchRemoteCards(registryUrl, {
1513
+ ...onlineOnly ? { online: true } : {}
1514
+ });
1515
+ const exactSkill = findRemoteBySkillId(onlineCards, needle);
1516
+ if (exactSkill) return toResolved(exactSkill, needle, "relay");
1517
+ const tokens = needle.toLowerCase().split(/\s+/).filter((t) => t.length > 0);
1518
+ const fuzzy = onlineCards.find((card) => {
1519
+ const text = [
1520
+ card.name,
1521
+ card.description,
1522
+ ...Array.isArray(card.skills) ? card.skills.map((s) => `${s.id} ${s.name} ${s.description}`) : []
1523
+ ].join(" ").toLowerCase();
1524
+ return tokens.some((token) => text.includes(token));
1525
+ });
1526
+ if (fuzzy) return toResolved(fuzzy, needle, "relay");
1117
1527
  } catch {
1118
- return false;
1119
1528
  }
1529
+ return null;
1120
1530
  }
1121
1531
 
1122
1532
  export {
@@ -1140,6 +1550,7 @@ export {
1140
1550
  listCards,
1141
1551
  getCardsByCapabilityType,
1142
1552
  getCardsBySkillCapability,
1553
+ lookupAgent,
1143
1554
  openCreditDb,
1144
1555
  bootstrapAgent,
1145
1556
  getBalance,
@@ -1151,9 +1562,11 @@ export {
1151
1562
  settleEscrow,
1152
1563
  releaseEscrow,
1153
1564
  confirmEscrowDebit,
1154
- generateKeyPair,
1155
- saveKeyPair,
1156
- loadKeyPair,
1157
- signEscrowReceipt,
1158
- verifyEscrowReceipt
1565
+ computeReputation,
1566
+ searchCards,
1567
+ filterCards,
1568
+ buildReputationMap,
1569
+ fetchRemoteCards,
1570
+ mergeResults,
1571
+ resolveTargetCapability
1159
1572
  };