agentbnb 3.0.0 → 3.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -432,6 +432,30 @@ function getCard(db, id) {
432
432
  if (!row) return null;
433
433
  return JSON.parse(row.data);
434
434
  }
435
+ function updateCard(db, id, owner, updates) {
436
+ const existing = getCard(db, id);
437
+ if (!existing) {
438
+ throw new AgentBnBError(`Card not found: ${id}`, "NOT_FOUND");
439
+ }
440
+ if (existing.owner !== owner) {
441
+ throw new AgentBnBError("Forbidden: you do not own this card", "FORBIDDEN");
442
+ }
443
+ const now = (/* @__PURE__ */ new Date()).toISOString();
444
+ const merged = { ...existing, ...updates, updated_at: now };
445
+ const parsed = CapabilityCardSchema.safeParse(merged);
446
+ if (!parsed.success) {
447
+ throw new AgentBnBError(
448
+ `Card validation failed: ${parsed.error.message}`,
449
+ "VALIDATION_ERROR"
450
+ );
451
+ }
452
+ const stmt = db.prepare(`
453
+ UPDATE capability_cards
454
+ SET data = ?, updated_at = ?
455
+ WHERE id = ?
456
+ `);
457
+ stmt.run(JSON.stringify(parsed.data), now, id);
458
+ }
435
459
  function updateReputation(db, cardId, success, latencyMs) {
436
460
  const existing = getCard(db, cardId);
437
461
  if (!existing) return;
@@ -455,6 +479,18 @@ function updateReputation(db, cardId, success, latencyMs) {
455
479
  `);
456
480
  stmt.run(JSON.stringify(updatedCard), now, cardId);
457
481
  }
482
+ function listCards(db, owner) {
483
+ let stmt;
484
+ let rows;
485
+ if (owner !== void 0) {
486
+ stmt = db.prepare("SELECT data FROM capability_cards WHERE owner = ?");
487
+ rows = stmt.all(owner);
488
+ } else {
489
+ stmt = db.prepare("SELECT data FROM capability_cards");
490
+ rows = stmt.all();
491
+ }
492
+ return rows.map((row) => JSON.parse(row.data));
493
+ }
458
494
 
459
495
  // src/registry/matcher.ts
460
496
  function searchCards(db, query, filters = {}) {
@@ -558,6 +594,8 @@ function recordEarning(db, owner, amount, _cardId, receiptNonce) {
558
594
 
559
595
  // src/gateway/server.ts
560
596
  import Fastify from "fastify";
597
+
598
+ // src/gateway/execute.ts
561
599
  import { randomUUID as randomUUID3 } from "crypto";
562
600
 
563
601
  // src/credit/escrow.ts
@@ -729,6 +767,164 @@ function releaseRequesterEscrow(requesterDb, escrowId) {
729
767
  releaseEscrow(requesterDb, escrowId);
730
768
  }
731
769
 
770
+ // src/gateway/execute.ts
771
+ async function executeCapabilityRequest(opts) {
772
+ const {
773
+ registryDb,
774
+ creditDb,
775
+ cardId,
776
+ skillId,
777
+ params,
778
+ requester,
779
+ escrowReceipt: receipt,
780
+ skillExecutor,
781
+ handlerUrl,
782
+ timeoutMs = 3e4
783
+ } = opts;
784
+ const card = getCard(registryDb, cardId);
785
+ if (!card) {
786
+ return { success: false, error: { code: -32602, message: `Card not found: ${cardId}` } };
787
+ }
788
+ let creditsNeeded;
789
+ let cardName;
790
+ let resolvedSkillId;
791
+ const rawCard = card;
792
+ if (Array.isArray(rawCard["skills"])) {
793
+ const v2card = card;
794
+ const skill = skillId ? v2card.skills.find((s) => s.id === skillId) : v2card.skills[0];
795
+ if (!skill) {
796
+ return { success: false, error: { code: -32602, message: `Skill not found: ${skillId}` } };
797
+ }
798
+ creditsNeeded = skill.pricing.credits_per_call;
799
+ cardName = skill.name;
800
+ resolvedSkillId = skill.id;
801
+ } else {
802
+ creditsNeeded = card.pricing.credits_per_call;
803
+ cardName = card.name;
804
+ }
805
+ let escrowId = null;
806
+ let isRemoteEscrow = false;
807
+ if (receipt) {
808
+ const { signature, ...receiptData2 } = receipt;
809
+ const publicKeyBuf = Buffer.from(receipt.requester_public_key, "hex");
810
+ const valid = verifyEscrowReceipt(receiptData2, signature, publicKeyBuf);
811
+ if (!valid) {
812
+ return { success: false, error: { code: -32603, message: "Invalid escrow receipt signature" } };
813
+ }
814
+ if (receipt.amount < creditsNeeded) {
815
+ return { success: false, error: { code: -32603, message: "Insufficient escrow amount" } };
816
+ }
817
+ const receiptAge = Date.now() - new Date(receipt.timestamp).getTime();
818
+ if (receiptAge > 5 * 60 * 1e3) {
819
+ return { success: false, error: { code: -32603, message: "Escrow receipt expired" } };
820
+ }
821
+ isRemoteEscrow = true;
822
+ } else {
823
+ try {
824
+ const balance = getBalance(creditDb, requester);
825
+ if (balance < creditsNeeded) {
826
+ return { success: false, error: { code: -32603, message: "Insufficient credits" } };
827
+ }
828
+ escrowId = holdEscrow(creditDb, requester, creditsNeeded, cardId);
829
+ } catch (err) {
830
+ const msg = err instanceof AgentBnBError ? err.message : "Failed to hold escrow";
831
+ return { success: false, error: { code: -32603, message: msg } };
832
+ }
833
+ }
834
+ const startMs = Date.now();
835
+ const receiptData = isRemoteEscrow ? { receipt_released: true } : void 0;
836
+ const handleFailure = (status, latencyMs, message) => {
837
+ if (!isRemoteEscrow && escrowId) releaseEscrow(creditDb, escrowId);
838
+ updateReputation(registryDb, cardId, false, latencyMs);
839
+ try {
840
+ insertRequestLog(registryDb, {
841
+ id: randomUUID3(),
842
+ card_id: cardId,
843
+ card_name: cardName,
844
+ skill_id: resolvedSkillId,
845
+ requester,
846
+ status,
847
+ latency_ms: latencyMs,
848
+ credits_charged: 0,
849
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
850
+ });
851
+ } catch {
852
+ }
853
+ return {
854
+ success: false,
855
+ error: { code: -32603, message, ...receiptData ? { data: receiptData } : {} }
856
+ };
857
+ };
858
+ const handleSuccess = (result, latencyMs) => {
859
+ if (isRemoteEscrow && receipt) {
860
+ settleProviderEarning(creditDb, card.owner, receipt);
861
+ } else if (escrowId) {
862
+ settleEscrow(creditDb, escrowId, card.owner);
863
+ }
864
+ updateReputation(registryDb, cardId, true, latencyMs);
865
+ try {
866
+ insertRequestLog(registryDb, {
867
+ id: randomUUID3(),
868
+ card_id: cardId,
869
+ card_name: cardName,
870
+ skill_id: resolvedSkillId,
871
+ requester,
872
+ status: "success",
873
+ latency_ms: latencyMs,
874
+ credits_charged: creditsNeeded,
875
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
876
+ });
877
+ } catch {
878
+ }
879
+ const successResult = isRemoteEscrow ? {
880
+ ...typeof result === "object" && result !== null ? result : { data: result },
881
+ receipt_settled: true,
882
+ receipt_nonce: receipt.nonce
883
+ } : result;
884
+ return { success: true, result: successResult };
885
+ };
886
+ if (skillExecutor) {
887
+ const targetSkillId = resolvedSkillId ?? skillId ?? cardId;
888
+ try {
889
+ const execResult = await skillExecutor.execute(targetSkillId, params);
890
+ if (!execResult.success) {
891
+ return handleFailure("failure", execResult.latency_ms, execResult.error ?? "Execution failed");
892
+ }
893
+ return handleSuccess(execResult.result, execResult.latency_ms);
894
+ } catch (err) {
895
+ const message = err instanceof Error ? err.message : "Execution error";
896
+ return handleFailure("failure", Date.now() - startMs, message);
897
+ }
898
+ }
899
+ if (!handlerUrl) {
900
+ return handleFailure("failure", Date.now() - startMs, "No skill executor or handler URL configured");
901
+ }
902
+ const controller = new AbortController();
903
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
904
+ try {
905
+ const response = await fetch(handlerUrl, {
906
+ method: "POST",
907
+ headers: { "Content-Type": "application/json" },
908
+ body: JSON.stringify({ card_id: cardId, skill_id: resolvedSkillId, params }),
909
+ signal: controller.signal
910
+ });
911
+ clearTimeout(timer);
912
+ if (!response.ok) {
913
+ return handleFailure("failure", Date.now() - startMs, `Handler returned ${response.status}`);
914
+ }
915
+ const result = await response.json();
916
+ return handleSuccess(result, Date.now() - startMs);
917
+ } catch (err) {
918
+ clearTimeout(timer);
919
+ const isTimeout = err instanceof Error && err.name === "AbortError";
920
+ return handleFailure(
921
+ isTimeout ? "timeout" : "failure",
922
+ Date.now() - startMs,
923
+ isTimeout ? "Execution timeout" : "Handler error"
924
+ );
925
+ }
926
+ }
927
+
732
928
  // src/gateway/server.ts
733
929
  var VERSION = "0.0.1";
734
930
  function createGatewayServer(opts) {
@@ -793,258 +989,24 @@ function createGatewayServer(opts) {
793
989
  error: { code: -32602, message: "Invalid params: card_id required" }
794
990
  });
795
991
  }
796
- const card = getCard(registryDb, cardId);
797
- if (!card) {
798
- return reply.send({
799
- jsonrpc: "2.0",
800
- id,
801
- error: { code: -32602, message: `Card not found: ${cardId}` }
802
- });
803
- }
804
992
  const requester = params.requester ?? "unknown";
805
- let creditsNeeded;
806
- let cardName;
807
- let resolvedSkillId;
808
- const rawCard = card;
809
- if (Array.isArray(rawCard["skills"])) {
810
- const v2card = card;
811
- const skill = skillId ? v2card.skills.find((s) => s.id === skillId) : v2card.skills[0];
812
- if (!skill) {
813
- return reply.send({
814
- jsonrpc: "2.0",
815
- id,
816
- error: { code: -32602, message: `Skill not found: ${skillId}` }
817
- });
818
- }
819
- creditsNeeded = skill.pricing.credits_per_call;
820
- cardName = skill.name;
821
- resolvedSkillId = skill.id;
822
- } else {
823
- creditsNeeded = card.pricing.credits_per_call;
824
- cardName = card.name;
825
- }
826
993
  const receipt = params.escrow_receipt;
827
- let escrowId = null;
828
- let isRemoteEscrow = false;
829
- if (receipt) {
830
- const { signature, ...receiptData } = receipt;
831
- const publicKeyBuf = Buffer.from(receipt.requester_public_key, "hex");
832
- const valid = verifyEscrowReceipt(receiptData, signature, publicKeyBuf);
833
- if (!valid) {
834
- return reply.send({
835
- jsonrpc: "2.0",
836
- id,
837
- error: { code: -32603, message: "Invalid escrow receipt signature" }
838
- });
839
- }
840
- if (receipt.amount < creditsNeeded) {
841
- return reply.send({
842
- jsonrpc: "2.0",
843
- id,
844
- error: { code: -32603, message: "Insufficient escrow amount" }
845
- });
846
- }
847
- const receiptAge = Date.now() - new Date(receipt.timestamp).getTime();
848
- if (receiptAge > 5 * 60 * 1e3) {
849
- return reply.send({
850
- jsonrpc: "2.0",
851
- id,
852
- error: { code: -32603, message: "Escrow receipt expired" }
853
- });
854
- }
855
- isRemoteEscrow = true;
994
+ const result = await executeCapabilityRequest({
995
+ registryDb,
996
+ creditDb,
997
+ cardId,
998
+ skillId,
999
+ params,
1000
+ requester,
1001
+ escrowReceipt: receipt,
1002
+ skillExecutor,
1003
+ handlerUrl,
1004
+ timeoutMs
1005
+ });
1006
+ if (result.success) {
1007
+ return reply.send({ jsonrpc: "2.0", id, result: result.result });
856
1008
  } else {
857
- try {
858
- const balance = getBalance(creditDb, requester);
859
- if (balance < creditsNeeded) {
860
- return reply.send({
861
- jsonrpc: "2.0",
862
- id,
863
- error: { code: -32603, message: "Insufficient credits" }
864
- });
865
- }
866
- escrowId = holdEscrow(creditDb, requester, creditsNeeded, cardId);
867
- } catch (err) {
868
- const msg = err instanceof AgentBnBError ? err.message : "Failed to hold escrow";
869
- return reply.send({
870
- jsonrpc: "2.0",
871
- id,
872
- error: { code: -32603, message: msg }
873
- });
874
- }
875
- }
876
- const startMs = Date.now();
877
- if (skillExecutor) {
878
- const targetSkillId = resolvedSkillId ?? skillId ?? cardId;
879
- let execResult;
880
- try {
881
- execResult = await skillExecutor.execute(targetSkillId, params);
882
- } catch (err) {
883
- if (!isRemoteEscrow && escrowId) releaseEscrow(creditDb, escrowId);
884
- updateReputation(registryDb, cardId, false, Date.now() - startMs);
885
- try {
886
- insertRequestLog(registryDb, {
887
- id: randomUUID3(),
888
- card_id: cardId,
889
- card_name: cardName,
890
- skill_id: resolvedSkillId,
891
- requester,
892
- status: "failure",
893
- latency_ms: Date.now() - startMs,
894
- credits_charged: 0,
895
- created_at: (/* @__PURE__ */ new Date()).toISOString()
896
- });
897
- } catch {
898
- }
899
- const message = err instanceof Error ? err.message : "Execution error";
900
- return reply.send({
901
- jsonrpc: "2.0",
902
- id,
903
- error: {
904
- code: -32603,
905
- message,
906
- ...isRemoteEscrow ? { data: { receipt_released: true } } : {}
907
- }
908
- });
909
- }
910
- if (!execResult.success) {
911
- if (!isRemoteEscrow && escrowId) releaseEscrow(creditDb, escrowId);
912
- updateReputation(registryDb, cardId, false, execResult.latency_ms);
913
- try {
914
- insertRequestLog(registryDb, {
915
- id: randomUUID3(),
916
- card_id: cardId,
917
- card_name: cardName,
918
- skill_id: resolvedSkillId,
919
- requester,
920
- status: "failure",
921
- latency_ms: execResult.latency_ms,
922
- credits_charged: 0,
923
- created_at: (/* @__PURE__ */ new Date()).toISOString()
924
- });
925
- } catch {
926
- }
927
- return reply.send({
928
- jsonrpc: "2.0",
929
- id,
930
- error: {
931
- code: -32603,
932
- message: execResult.error ?? "Execution failed",
933
- ...isRemoteEscrow ? { data: { receipt_released: true } } : {}
934
- }
935
- });
936
- }
937
- if (isRemoteEscrow && receipt) {
938
- settleProviderEarning(creditDb, card.owner, receipt);
939
- } else if (escrowId) {
940
- settleEscrow(creditDb, escrowId, card.owner);
941
- }
942
- updateReputation(registryDb, cardId, true, execResult.latency_ms);
943
- try {
944
- insertRequestLog(registryDb, {
945
- id: randomUUID3(),
946
- card_id: cardId,
947
- card_name: cardName,
948
- skill_id: resolvedSkillId,
949
- requester,
950
- status: "success",
951
- latency_ms: execResult.latency_ms,
952
- credits_charged: creditsNeeded,
953
- created_at: (/* @__PURE__ */ new Date()).toISOString()
954
- });
955
- } catch {
956
- }
957
- const successResult = isRemoteEscrow ? { ...typeof execResult.result === "object" && execResult.result !== null ? execResult.result : { data: execResult.result }, receipt_settled: true, receipt_nonce: receipt.nonce } : execResult.result;
958
- return reply.send({ jsonrpc: "2.0", id, result: successResult });
959
- }
960
- const controller = new AbortController();
961
- const timer = setTimeout(() => controller.abort(), timeoutMs);
962
- try {
963
- const response = await fetch(handlerUrl, {
964
- method: "POST",
965
- headers: { "Content-Type": "application/json" },
966
- body: JSON.stringify({ card_id: cardId, skill_id: resolvedSkillId, params }),
967
- signal: controller.signal
968
- });
969
- clearTimeout(timer);
970
- if (!response.ok) {
971
- if (!isRemoteEscrow && escrowId) releaseEscrow(creditDb, escrowId);
972
- updateReputation(registryDb, cardId, false, Date.now() - startMs);
973
- try {
974
- insertRequestLog(registryDb, {
975
- id: randomUUID3(),
976
- card_id: cardId,
977
- card_name: cardName,
978
- skill_id: resolvedSkillId,
979
- requester,
980
- status: "failure",
981
- latency_ms: Date.now() - startMs,
982
- credits_charged: 0,
983
- created_at: (/* @__PURE__ */ new Date()).toISOString()
984
- });
985
- } catch {
986
- }
987
- return reply.send({
988
- jsonrpc: "2.0",
989
- id,
990
- error: {
991
- code: -32603,
992
- message: `Handler returned ${response.status}`,
993
- ...isRemoteEscrow ? { data: { receipt_released: true } } : {}
994
- }
995
- });
996
- }
997
- const result = await response.json();
998
- if (isRemoteEscrow && receipt) {
999
- settleProviderEarning(creditDb, card.owner, receipt);
1000
- } else if (escrowId) {
1001
- settleEscrow(creditDb, escrowId, card.owner);
1002
- }
1003
- updateReputation(registryDb, cardId, true, Date.now() - startMs);
1004
- try {
1005
- insertRequestLog(registryDb, {
1006
- id: randomUUID3(),
1007
- card_id: cardId,
1008
- card_name: cardName,
1009
- skill_id: resolvedSkillId,
1010
- requester,
1011
- status: "success",
1012
- latency_ms: Date.now() - startMs,
1013
- credits_charged: creditsNeeded,
1014
- created_at: (/* @__PURE__ */ new Date()).toISOString()
1015
- });
1016
- } catch {
1017
- }
1018
- const successResult = isRemoteEscrow ? { ...typeof result === "object" && result !== null ? result : { data: result }, receipt_settled: true, receipt_nonce: receipt.nonce } : result;
1019
- return reply.send({ jsonrpc: "2.0", id, result: successResult });
1020
- } catch (err) {
1021
- clearTimeout(timer);
1022
- if (!isRemoteEscrow && escrowId) releaseEscrow(creditDb, escrowId);
1023
- updateReputation(registryDb, cardId, false, Date.now() - startMs);
1024
- const isTimeout = err instanceof Error && err.name === "AbortError";
1025
- try {
1026
- insertRequestLog(registryDb, {
1027
- id: randomUUID3(),
1028
- card_id: cardId,
1029
- card_name: cardName,
1030
- skill_id: resolvedSkillId,
1031
- requester,
1032
- status: isTimeout ? "timeout" : "failure",
1033
- latency_ms: Date.now() - startMs,
1034
- credits_charged: 0,
1035
- created_at: (/* @__PURE__ */ new Date()).toISOString()
1036
- });
1037
- } catch {
1038
- }
1039
- return reply.send({
1040
- jsonrpc: "2.0",
1041
- id,
1042
- error: {
1043
- code: -32603,
1044
- message: isTimeout ? "Execution timeout" : "Handler error",
1045
- ...isRemoteEscrow ? { data: { receipt_released: true } } : {}
1046
- }
1047
- });
1009
+ return reply.send({ jsonrpc: "2.0", id, error: result.error });
1048
1010
  }
1049
1011
  });
1050
1012
  return fastify;
@@ -1992,6 +1954,27 @@ async function requestCapability(opts) {
1992
1954
  }
1993
1955
  return body.result;
1994
1956
  }
1957
+ async function requestViaRelay(relay, opts) {
1958
+ try {
1959
+ return await relay.request({
1960
+ targetOwner: opts.targetOwner,
1961
+ cardId: opts.cardId,
1962
+ skillId: opts.skillId,
1963
+ params: opts.params ?? {},
1964
+ escrowReceipt: opts.escrowReceipt,
1965
+ timeoutMs: opts.timeoutMs
1966
+ });
1967
+ } catch (err) {
1968
+ const message = err instanceof Error ? err.message : String(err);
1969
+ if (message.includes("timeout")) {
1970
+ throw new AgentBnBError(message, "TIMEOUT");
1971
+ }
1972
+ if (message.includes("offline")) {
1973
+ throw new AgentBnBError(message, "AGENT_OFFLINE");
1974
+ }
1975
+ throw new AgentBnBError(message, "RELAY_ERROR");
1976
+ }
1977
+ }
1995
1978
 
1996
1979
  // src/autonomy/tiers.ts
1997
1980
  import { randomUUID as randomUUID6 } from "crypto";
@@ -2007,6 +1990,22 @@ import { join as join3 } from "path";
2007
1990
  import { readFileSync as readFileSync2, writeFileSync as writeFileSync2, mkdirSync, existsSync as existsSync2 } from "fs";
2008
1991
  import { homedir } from "os";
2009
1992
  import { join as join2 } from "path";
1993
+ function getConfigDir() {
1994
+ return process.env["AGENTBNB_DIR"] ?? join2(homedir(), ".agentbnb");
1995
+ }
1996
+ function getConfigPath() {
1997
+ return join2(getConfigDir(), "config.json");
1998
+ }
1999
+ function loadConfig() {
2000
+ const configPath = getConfigPath();
2001
+ if (!existsSync2(configPath)) return null;
2002
+ try {
2003
+ const raw = readFileSync2(configPath, "utf-8");
2004
+ return JSON.parse(raw);
2005
+ } catch {
2006
+ return null;
2007
+ }
2008
+ }
2010
2009
 
2011
2010
  // src/autonomy/auto-request.ts
2012
2011
  function minMaxNormalize(values) {
@@ -2535,7 +2534,1223 @@ function createSignedEscrowReceipt(db, privateKey, publicKey, opts) {
2535
2534
  };
2536
2535
  return { escrowId, receipt };
2537
2536
  }
2537
+
2538
+ // src/identity/identity.ts
2539
+ import { z as z4 } from "zod";
2540
+ import { createHash } from "crypto";
2541
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync4, existsSync as existsSync4, mkdirSync as mkdirSync3 } from "fs";
2542
+ import { join as join4 } from "path";
2543
+ var AgentIdentitySchema = z4.object({
2544
+ /** Deterministic ID derived from public key: sha256(hex).slice(0, 16). */
2545
+ agent_id: z4.string().min(1),
2546
+ /** Human-readable owner name (from config or init). */
2547
+ owner: z4.string().min(1),
2548
+ /** Hex-encoded Ed25519 public key. */
2549
+ public_key: z4.string().min(1),
2550
+ /** ISO 8601 timestamp of identity creation. */
2551
+ created_at: z4.string().datetime(),
2552
+ /** Optional guarantor info if linked to a human. */
2553
+ guarantor: z4.object({
2554
+ github_login: z4.string().min(1),
2555
+ verified_at: z4.string().datetime()
2556
+ }).optional()
2557
+ });
2558
+ var AgentCertificateSchema = z4.object({
2559
+ identity: AgentIdentitySchema,
2560
+ /** ISO 8601 timestamp of certificate issuance. */
2561
+ issued_at: z4.string().datetime(),
2562
+ /** ISO 8601 timestamp of certificate expiry. */
2563
+ expires_at: z4.string().datetime(),
2564
+ /** Hex-encoded public key of the issuer (same as identity for self-signed). */
2565
+ issuer_public_key: z4.string().min(1),
2566
+ /** Base64url Ed25519 signature over { identity, issued_at, expires_at, issuer_public_key }. */
2567
+ signature: z4.string().min(1)
2568
+ });
2569
+ var IDENTITY_FILENAME = "identity.json";
2570
+ function deriveAgentId(publicKeyHex) {
2571
+ return createHash("sha256").update(publicKeyHex, "hex").digest("hex").slice(0, 16);
2572
+ }
2573
+ function createIdentity(configDir, owner) {
2574
+ if (!existsSync4(configDir)) {
2575
+ mkdirSync3(configDir, { recursive: true });
2576
+ }
2577
+ let keys;
2578
+ try {
2579
+ keys = loadKeyPair(configDir);
2580
+ } catch {
2581
+ keys = generateKeyPair();
2582
+ saveKeyPair(configDir, keys);
2583
+ }
2584
+ const publicKeyHex = keys.publicKey.toString("hex");
2585
+ const agentId = deriveAgentId(publicKeyHex);
2586
+ const identity = {
2587
+ agent_id: agentId,
2588
+ owner,
2589
+ public_key: publicKeyHex,
2590
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
2591
+ };
2592
+ saveIdentity(configDir, identity);
2593
+ return identity;
2594
+ }
2595
+ function loadIdentity(configDir) {
2596
+ const filePath = join4(configDir, IDENTITY_FILENAME);
2597
+ if (!existsSync4(filePath)) return null;
2598
+ try {
2599
+ const raw = readFileSync4(filePath, "utf-8");
2600
+ return AgentIdentitySchema.parse(JSON.parse(raw));
2601
+ } catch {
2602
+ return null;
2603
+ }
2604
+ }
2605
+ function saveIdentity(configDir, identity) {
2606
+ if (!existsSync4(configDir)) {
2607
+ mkdirSync3(configDir, { recursive: true });
2608
+ }
2609
+ const filePath = join4(configDir, IDENTITY_FILENAME);
2610
+ writeFileSync4(filePath, JSON.stringify(identity, null, 2), "utf-8");
2611
+ }
2612
+ function issueAgentCertificate(identity, privateKey) {
2613
+ const issuedAt = (/* @__PURE__ */ new Date()).toISOString();
2614
+ const expiresAt = new Date(Date.now() + 365 * 24 * 60 * 60 * 1e3).toISOString();
2615
+ const payload = {
2616
+ identity,
2617
+ issued_at: issuedAt,
2618
+ expires_at: expiresAt,
2619
+ issuer_public_key: identity.public_key
2620
+ };
2621
+ const signature = signEscrowReceipt(payload, privateKey);
2622
+ return {
2623
+ identity,
2624
+ issued_at: issuedAt,
2625
+ expires_at: expiresAt,
2626
+ issuer_public_key: identity.public_key,
2627
+ signature
2628
+ };
2629
+ }
2630
+ function verifyAgentCertificate(cert) {
2631
+ if (new Date(cert.expires_at) < /* @__PURE__ */ new Date()) {
2632
+ return false;
2633
+ }
2634
+ const publicKeyHex = cert.issuer_public_key;
2635
+ const publicKeyBuf = Buffer.from(publicKeyHex, "hex");
2636
+ const payload = {
2637
+ identity: cert.identity,
2638
+ issued_at: cert.issued_at,
2639
+ expires_at: cert.expires_at,
2640
+ issuer_public_key: cert.issuer_public_key
2641
+ };
2642
+ return verifyEscrowReceipt(payload, cert.signature, publicKeyBuf);
2643
+ }
2644
+ function ensureIdentity(configDir, owner) {
2645
+ const existing = loadIdentity(configDir);
2646
+ if (existing) return existing;
2647
+ return createIdentity(configDir, owner);
2648
+ }
2649
+
2650
+ // src/sdk/consumer.ts
2651
+ var AgentBnBConsumer = class {
2652
+ configDir;
2653
+ identity = null;
2654
+ keys = null;
2655
+ creditDb = null;
2656
+ constructor(opts) {
2657
+ this.configDir = opts?.configDir ?? getConfigDir();
2658
+ }
2659
+ /**
2660
+ * Loads agent identity and keypair from disk.
2661
+ * Creates identity if none exists (uses owner from config.json or generates one).
2662
+ *
2663
+ * @returns The loaded AgentIdentity.
2664
+ * @throws {AgentBnBError} if keypair is missing and cannot be created.
2665
+ */
2666
+ authenticate() {
2667
+ const config = loadConfig();
2668
+ const owner = config?.owner ?? `agent-${Date.now().toString(36)}`;
2669
+ this.identity = ensureIdentity(this.configDir, owner);
2670
+ this.keys = loadKeyPair(this.configDir);
2671
+ return this.identity;
2672
+ }
2673
+ /**
2674
+ * Returns the cached identity. Throws if not yet authenticated.
2675
+ */
2676
+ getIdentity() {
2677
+ if (!this.identity) {
2678
+ throw new AgentBnBError("Not authenticated. Call authenticate() first.", "NOT_AUTHENTICATED");
2679
+ }
2680
+ return this.identity;
2681
+ }
2682
+ /**
2683
+ * Requests a capability from a remote agent with full escrow lifecycle.
2684
+ *
2685
+ * 1. Creates a signed escrow receipt (holds credits locally)
2686
+ * 2. Sends the request to the target gateway
2687
+ * 3. Settles escrow on success, releases on failure
2688
+ *
2689
+ * @param opts - Request options including target, card, credits, and params.
2690
+ * @returns The result from the capability execution.
2691
+ * @throws {AgentBnBError} on insufficient credits, network error, or RPC error.
2692
+ */
2693
+ async request(opts) {
2694
+ const identity = this.getIdentity();
2695
+ if (!this.keys) {
2696
+ throw new AgentBnBError("Keypair not loaded. Call authenticate() first.", "NOT_AUTHENTICATED");
2697
+ }
2698
+ const db = this.getCreditDb();
2699
+ const { escrowId, receipt } = createSignedEscrowReceipt(
2700
+ db,
2701
+ this.keys.privateKey,
2702
+ this.keys.publicKey,
2703
+ {
2704
+ owner: identity.owner,
2705
+ amount: opts.credits,
2706
+ cardId: opts.cardId,
2707
+ skillId: opts.skillId
2708
+ }
2709
+ );
2710
+ try {
2711
+ const result = await requestCapability({
2712
+ gatewayUrl: opts.gatewayUrl,
2713
+ token: opts.token,
2714
+ cardId: opts.cardId,
2715
+ params: opts.params,
2716
+ timeoutMs: opts.timeoutMs,
2717
+ escrowReceipt: receipt
2718
+ });
2719
+ settleRequesterEscrow(db, escrowId);
2720
+ return result;
2721
+ } catch (err) {
2722
+ releaseRequesterEscrow(db, escrowId);
2723
+ throw err;
2724
+ }
2725
+ }
2726
+ /**
2727
+ * Returns the current credit balance for this agent.
2728
+ */
2729
+ getBalance() {
2730
+ const identity = this.getIdentity();
2731
+ const db = this.getCreditDb();
2732
+ return getBalance(db, identity.owner);
2733
+ }
2734
+ /**
2735
+ * Returns basic reputation data from the local credit database.
2736
+ * Note: success_rate is computed from local request history only.
2737
+ */
2738
+ getReputation() {
2739
+ const identity = this.getIdentity();
2740
+ const db = this.getCreditDb();
2741
+ const stmt = db.prepare(`
2742
+ SELECT
2743
+ COUNT(*) as total,
2744
+ SUM(CASE WHEN status = 'settled' THEN 1 ELSE 0 END) as settled
2745
+ FROM credit_escrow
2746
+ WHERE owner = ?
2747
+ `);
2748
+ const row = stmt.get(identity.owner);
2749
+ const total = row?.total ?? 0;
2750
+ const settled = row?.settled ?? 0;
2751
+ return {
2752
+ success_rate: total > 0 ? settled / total : 1,
2753
+ total_requests: total
2754
+ };
2755
+ }
2756
+ /**
2757
+ * Closes the credit database connection. Call when done.
2758
+ */
2759
+ close() {
2760
+ if (this.creditDb) {
2761
+ this.creditDb.close();
2762
+ this.creditDb = null;
2763
+ }
2764
+ }
2765
+ /** Lazily opens and caches the credit database. */
2766
+ getCreditDb() {
2767
+ if (!this.creditDb) {
2768
+ const config = loadConfig();
2769
+ const creditDbPath = config?.credit_db_path ?? `${this.configDir}/credit.db`;
2770
+ this.creditDb = openCreditDb(creditDbPath);
2771
+ }
2772
+ return this.creditDb;
2773
+ }
2774
+ };
2775
+
2776
+ // src/sdk/provider.ts
2777
+ var AgentBnBProvider = class {
2778
+ configDir;
2779
+ identity = null;
2780
+ registryDb = null;
2781
+ creditDb = null;
2782
+ gateway = null;
2783
+ constructor(opts) {
2784
+ this.configDir = opts?.configDir ?? getConfigDir();
2785
+ }
2786
+ /**
2787
+ * Loads agent identity from disk.
2788
+ * Creates identity if none exists.
2789
+ *
2790
+ * @returns The loaded AgentIdentity.
2791
+ */
2792
+ authenticate() {
2793
+ const config = loadConfig();
2794
+ const owner = config?.owner ?? `agent-${Date.now().toString(36)}`;
2795
+ this.identity = ensureIdentity(this.configDir, owner);
2796
+ return this.identity;
2797
+ }
2798
+ /**
2799
+ * Returns the cached identity. Throws if not yet authenticated.
2800
+ */
2801
+ getIdentity() {
2802
+ if (!this.identity) {
2803
+ throw new AgentBnBError("Not authenticated. Call authenticate() first.", "NOT_AUTHENTICATED");
2804
+ }
2805
+ return this.identity;
2806
+ }
2807
+ /**
2808
+ * Starts the gateway server to share capabilities.
2809
+ *
2810
+ * @param opts - Optional port and host configuration.
2811
+ * @returns Context with the gateway server and port.
2812
+ */
2813
+ async startSharing(opts) {
2814
+ this.getIdentity();
2815
+ const config = loadConfig();
2816
+ const port = opts?.port ?? config?.gateway_port ?? 7700;
2817
+ const host = opts?.host ?? "0.0.0.0";
2818
+ const registryDb = this.getRegistryDb();
2819
+ const creditDb = this.getCreditDb();
2820
+ const token = config?.token ?? "";
2821
+ const gateway = createGatewayServer({
2822
+ registryDb,
2823
+ creditDb,
2824
+ tokens: [token],
2825
+ handlerUrl: `http://localhost:${port}`,
2826
+ silent: true
2827
+ });
2828
+ await gateway.listen({ port, host });
2829
+ this.gateway = gateway;
2830
+ return { gateway, port };
2831
+ }
2832
+ /**
2833
+ * Stops the gateway server.
2834
+ */
2835
+ async stopSharing() {
2836
+ if (this.gateway) {
2837
+ await this.gateway.close();
2838
+ this.gateway = null;
2839
+ }
2840
+ }
2841
+ /**
2842
+ * Returns all capability cards owned by this agent.
2843
+ */
2844
+ listCapabilities() {
2845
+ const identity = this.getIdentity();
2846
+ const db = this.getRegistryDb();
2847
+ return listCards(db, identity.owner);
2848
+ }
2849
+ /**
2850
+ * Returns the current credit balance for this agent.
2851
+ */
2852
+ getBalance() {
2853
+ const identity = this.getIdentity();
2854
+ const db = this.getCreditDb();
2855
+ return getBalance(db, identity.owner);
2856
+ }
2857
+ /**
2858
+ * Closes all database connections and stops the gateway. Call when done.
2859
+ */
2860
+ async close() {
2861
+ await this.stopSharing();
2862
+ if (this.registryDb) {
2863
+ this.registryDb.close();
2864
+ this.registryDb = null;
2865
+ }
2866
+ if (this.creditDb) {
2867
+ this.creditDb.close();
2868
+ this.creditDb = null;
2869
+ }
2870
+ }
2871
+ /** Lazily opens and caches the registry database. */
2872
+ getRegistryDb() {
2873
+ if (!this.registryDb) {
2874
+ const config = loadConfig();
2875
+ const dbPath = config?.db_path ?? `${this.configDir}/registry.db`;
2876
+ this.registryDb = openDatabase(dbPath);
2877
+ }
2878
+ return this.registryDb;
2879
+ }
2880
+ /** Lazily opens and caches the credit database. */
2881
+ getCreditDb() {
2882
+ if (!this.creditDb) {
2883
+ const config = loadConfig();
2884
+ const creditDbPath = config?.credit_db_path ?? `${this.configDir}/credit.db`;
2885
+ this.creditDb = openCreditDb(creditDbPath);
2886
+ }
2887
+ return this.creditDb;
2888
+ }
2889
+ };
2890
+
2891
+ // src/identity/guarantor.ts
2892
+ import { z as z5 } from "zod";
2893
+ import { randomUUID as randomUUID9 } from "crypto";
2894
+ var MAX_AGENTS_PER_GUARANTOR = 10;
2895
+ var GUARANTOR_CREDIT_POOL = 50;
2896
+ var GuarantorRecordSchema = z5.object({
2897
+ id: z5.string().uuid(),
2898
+ github_login: z5.string().min(1),
2899
+ agent_count: z5.number().int().nonnegative(),
2900
+ credit_pool: z5.number().int().nonnegative(),
2901
+ created_at: z5.string().datetime()
2902
+ });
2903
+ var GUARANTOR_SCHEMA = `
2904
+ CREATE TABLE IF NOT EXISTS guarantors (
2905
+ id TEXT PRIMARY KEY,
2906
+ github_login TEXT UNIQUE NOT NULL,
2907
+ agent_count INTEGER NOT NULL DEFAULT 0,
2908
+ credit_pool INTEGER NOT NULL DEFAULT ${GUARANTOR_CREDIT_POOL},
2909
+ created_at TEXT NOT NULL
2910
+ );
2911
+
2912
+ CREATE TABLE IF NOT EXISTS agent_guarantors (
2913
+ agent_id TEXT PRIMARY KEY,
2914
+ guarantor_id TEXT NOT NULL,
2915
+ linked_at TEXT NOT NULL,
2916
+ FOREIGN KEY (guarantor_id) REFERENCES guarantors(id)
2917
+ );
2918
+ `;
2919
+ function ensureGuarantorTables(db) {
2920
+ db.exec(GUARANTOR_SCHEMA);
2921
+ }
2922
+ function registerGuarantor(db, githubLogin) {
2923
+ ensureGuarantorTables(db);
2924
+ const existing = db.prepare("SELECT * FROM guarantors WHERE github_login = ?").get(githubLogin);
2925
+ if (existing) {
2926
+ throw new AgentBnBError(
2927
+ `Guarantor already registered: ${githubLogin}`,
2928
+ "GUARANTOR_EXISTS"
2929
+ );
2930
+ }
2931
+ const record = {
2932
+ id: randomUUID9(),
2933
+ github_login: githubLogin,
2934
+ agent_count: 0,
2935
+ credit_pool: GUARANTOR_CREDIT_POOL,
2936
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
2937
+ };
2938
+ db.prepare(
2939
+ "INSERT INTO guarantors (id, github_login, agent_count, credit_pool, created_at) VALUES (?, ?, ?, ?, ?)"
2940
+ ).run(record.id, record.github_login, record.agent_count, record.credit_pool, record.created_at);
2941
+ return record;
2942
+ }
2943
+ function linkAgentToGuarantor(db, agentId, githubLogin) {
2944
+ ensureGuarantorTables(db);
2945
+ const guarantor = db.prepare("SELECT * FROM guarantors WHERE github_login = ?").get(githubLogin);
2946
+ if (!guarantor) {
2947
+ throw new AgentBnBError(
2948
+ `Guarantor not found: ${githubLogin}`,
2949
+ "GUARANTOR_NOT_FOUND"
2950
+ );
2951
+ }
2952
+ if (guarantor["agent_count"] >= MAX_AGENTS_PER_GUARANTOR) {
2953
+ throw new AgentBnBError(
2954
+ `Maximum agents per guarantor reached (${MAX_AGENTS_PER_GUARANTOR})`,
2955
+ "MAX_AGENTS_EXCEEDED"
2956
+ );
2957
+ }
2958
+ const existingLink = db.prepare("SELECT * FROM agent_guarantors WHERE agent_id = ?").get(agentId);
2959
+ if (existingLink) {
2960
+ throw new AgentBnBError(
2961
+ `Agent ${agentId} is already linked to a guarantor`,
2962
+ "AGENT_ALREADY_LINKED"
2963
+ );
2964
+ }
2965
+ db.transaction(() => {
2966
+ db.prepare("INSERT INTO agent_guarantors (agent_id, guarantor_id, linked_at) VALUES (?, ?, ?)").run(
2967
+ agentId,
2968
+ guarantor["id"],
2969
+ (/* @__PURE__ */ new Date()).toISOString()
2970
+ );
2971
+ db.prepare("UPDATE guarantors SET agent_count = agent_count + 1 WHERE id = ?").run(guarantor["id"]);
2972
+ })();
2973
+ return getGuarantor(db, githubLogin);
2974
+ }
2975
+ function getGuarantor(db, githubLogin) {
2976
+ ensureGuarantorTables(db);
2977
+ const row = db.prepare("SELECT * FROM guarantors WHERE github_login = ?").get(githubLogin);
2978
+ if (!row) return null;
2979
+ return {
2980
+ id: row["id"],
2981
+ github_login: row["github_login"],
2982
+ agent_count: row["agent_count"],
2983
+ credit_pool: row["credit_pool"],
2984
+ created_at: row["created_at"]
2985
+ };
2986
+ }
2987
+ function getAgentGuarantor(db, agentId) {
2988
+ ensureGuarantorTables(db);
2989
+ const link = db.prepare(
2990
+ `SELECT g.* FROM guarantors g
2991
+ JOIN agent_guarantors ag ON ag.guarantor_id = g.id
2992
+ WHERE ag.agent_id = ?`
2993
+ ).get(agentId);
2994
+ if (!link) return null;
2995
+ return {
2996
+ id: link["id"],
2997
+ github_login: link["github_login"],
2998
+ agent_count: link["agent_count"],
2999
+ credit_pool: link["credit_pool"],
3000
+ created_at: link["created_at"]
3001
+ };
3002
+ }
3003
+ function initiateGithubAuth() {
3004
+ return {
3005
+ auth_url: "https://github.com/login/oauth/authorize?client_id=PLACEHOLDER&scope=read:user",
3006
+ state: randomUUID9()
3007
+ };
3008
+ }
3009
+
3010
+ // src/relay/types.ts
3011
+ import { z as z6 } from "zod";
3012
+ var RegisterMessageSchema = z6.object({
3013
+ type: z6.literal("register"),
3014
+ owner: z6.string().min(1),
3015
+ token: z6.string().min(1),
3016
+ card: z6.record(z6.unknown())
3017
+ // CapabilityCard (validated separately)
3018
+ });
3019
+ var RegisteredMessageSchema = z6.object({
3020
+ type: z6.literal("registered"),
3021
+ agent_id: z6.string()
3022
+ });
3023
+ var RelayRequestMessageSchema = z6.object({
3024
+ type: z6.literal("relay_request"),
3025
+ id: z6.string().uuid(),
3026
+ target_owner: z6.string().min(1),
3027
+ card_id: z6.string(),
3028
+ skill_id: z6.string().optional(),
3029
+ params: z6.record(z6.unknown()).default({}),
3030
+ requester: z6.string().optional(),
3031
+ escrow_receipt: z6.record(z6.unknown()).optional()
3032
+ });
3033
+ var IncomingRequestMessageSchema = z6.object({
3034
+ type: z6.literal("incoming_request"),
3035
+ id: z6.string().uuid(),
3036
+ from_owner: z6.string().min(1),
3037
+ card_id: z6.string(),
3038
+ skill_id: z6.string().optional(),
3039
+ params: z6.record(z6.unknown()).default({}),
3040
+ requester: z6.string().optional(),
3041
+ escrow_receipt: z6.record(z6.unknown()).optional()
3042
+ });
3043
+ var RelayResponseMessageSchema = z6.object({
3044
+ type: z6.literal("relay_response"),
3045
+ id: z6.string().uuid(),
3046
+ result: z6.unknown().optional(),
3047
+ error: z6.object({
3048
+ code: z6.number(),
3049
+ message: z6.string()
3050
+ }).optional()
3051
+ });
3052
+ var ResponseMessageSchema = z6.object({
3053
+ type: z6.literal("response"),
3054
+ id: z6.string().uuid(),
3055
+ result: z6.unknown().optional(),
3056
+ error: z6.object({
3057
+ code: z6.number(),
3058
+ message: z6.string()
3059
+ }).optional()
3060
+ });
3061
+ var ErrorMessageSchema = z6.object({
3062
+ type: z6.literal("error"),
3063
+ code: z6.string(),
3064
+ message: z6.string(),
3065
+ request_id: z6.string().optional()
3066
+ });
3067
+ var RelayMessageSchema = z6.discriminatedUnion("type", [
3068
+ RegisterMessageSchema,
3069
+ RegisteredMessageSchema,
3070
+ RelayRequestMessageSchema,
3071
+ IncomingRequestMessageSchema,
3072
+ RelayResponseMessageSchema,
3073
+ ResponseMessageSchema,
3074
+ ErrorMessageSchema
3075
+ ]);
3076
+
3077
+ // src/relay/websocket-relay.ts
3078
+ import { randomUUID as randomUUID10 } from "crypto";
3079
+ var RATE_LIMIT_MAX = 60;
3080
+ var RATE_LIMIT_WINDOW_MS = 6e4;
3081
+ var RELAY_TIMEOUT_MS = 3e4;
3082
+ function registerWebSocketRelay(server, db) {
3083
+ const connections = /* @__PURE__ */ new Map();
3084
+ const pendingRequests = /* @__PURE__ */ new Map();
3085
+ const rateLimits = /* @__PURE__ */ new Map();
3086
+ function checkRateLimit(owner) {
3087
+ const now = Date.now();
3088
+ const entry = rateLimits.get(owner);
3089
+ if (!entry || now >= entry.resetTime) {
3090
+ rateLimits.set(owner, { count: 1, resetTime: now + RATE_LIMIT_WINDOW_MS });
3091
+ return true;
3092
+ }
3093
+ if (entry.count >= RATE_LIMIT_MAX) {
3094
+ return false;
3095
+ }
3096
+ entry.count++;
3097
+ return true;
3098
+ }
3099
+ function markOwnerOffline(owner) {
3100
+ try {
3101
+ const stmt = db.prepare("SELECT id, data FROM capability_cards WHERE owner = ?");
3102
+ const rows = stmt.all(owner);
3103
+ for (const row of rows) {
3104
+ try {
3105
+ const card = JSON.parse(row.data);
3106
+ if (card.availability?.online) {
3107
+ card.availability.online = false;
3108
+ card.updated_at = (/* @__PURE__ */ new Date()).toISOString();
3109
+ const updateStmt = db.prepare("UPDATE capability_cards SET data = ?, updated_at = ? WHERE id = ?");
3110
+ updateStmt.run(JSON.stringify(card), card.updated_at, row.id);
3111
+ }
3112
+ } catch {
3113
+ }
3114
+ }
3115
+ } catch {
3116
+ }
3117
+ }
3118
+ function markOwnerOnline(owner) {
3119
+ try {
3120
+ const stmt = db.prepare("SELECT id, data FROM capability_cards WHERE owner = ?");
3121
+ const rows = stmt.all(owner);
3122
+ for (const row of rows) {
3123
+ try {
3124
+ const card = JSON.parse(row.data);
3125
+ card.availability = { ...card.availability, online: true };
3126
+ card.updated_at = (/* @__PURE__ */ new Date()).toISOString();
3127
+ const updateStmt = db.prepare("UPDATE capability_cards SET data = ?, updated_at = ? WHERE id = ?");
3128
+ updateStmt.run(JSON.stringify(card), card.updated_at, row.id);
3129
+ } catch {
3130
+ }
3131
+ }
3132
+ } catch {
3133
+ }
3134
+ }
3135
+ function upsertCard(cardData, owner) {
3136
+ const cardId = cardData.id;
3137
+ const existing = getCard(db, cardId);
3138
+ if (existing) {
3139
+ const updates = { ...cardData, availability: { ...cardData.availability ?? {}, online: true } };
3140
+ updateCard(db, cardId, owner, updates);
3141
+ } else {
3142
+ const card = { ...cardData, availability: { ...cardData.availability ?? {}, online: true } };
3143
+ insertCard(db, card);
3144
+ }
3145
+ return cardId;
3146
+ }
3147
+ function logAgentJoined(owner, cardName, cardId) {
3148
+ try {
3149
+ insertRequestLog(db, {
3150
+ id: randomUUID10(),
3151
+ card_id: cardId,
3152
+ card_name: cardName,
3153
+ requester: owner,
3154
+ status: "success",
3155
+ latency_ms: 0,
3156
+ credits_charged: 0,
3157
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
3158
+ action_type: "agent_joined"
3159
+ });
3160
+ } catch {
3161
+ }
3162
+ }
3163
+ function sendMessage(ws, msg) {
3164
+ if (ws.readyState === 1) {
3165
+ ws.send(JSON.stringify(msg));
3166
+ }
3167
+ }
3168
+ function handleRegister(ws, msg) {
3169
+ const { owner, card } = msg;
3170
+ const existing = connections.get(owner);
3171
+ if (existing && existing !== ws) {
3172
+ try {
3173
+ existing.close(1e3, "Replaced by new connection");
3174
+ } catch {
3175
+ }
3176
+ }
3177
+ connections.set(owner, ws);
3178
+ const cardId = upsertCard(card, owner);
3179
+ const cardName = card.name ?? card.agent_name ?? owner;
3180
+ logAgentJoined(owner, cardName, cardId);
3181
+ markOwnerOnline(owner);
3182
+ sendMessage(ws, { type: "registered", agent_id: cardId });
3183
+ }
3184
+ function handleRelayRequest(ws, msg, fromOwner) {
3185
+ if (!checkRateLimit(fromOwner)) {
3186
+ sendMessage(ws, {
3187
+ type: "error",
3188
+ code: "rate_limited",
3189
+ message: `Rate limit exceeded: max ${RATE_LIMIT_MAX} requests per minute`,
3190
+ request_id: msg.id
3191
+ });
3192
+ return;
3193
+ }
3194
+ const targetWs = connections.get(msg.target_owner);
3195
+ if (!targetWs || targetWs.readyState !== 1) {
3196
+ sendMessage(ws, {
3197
+ type: "response",
3198
+ id: msg.id,
3199
+ error: { code: -32603, message: `Agent offline: ${msg.target_owner}` }
3200
+ });
3201
+ return;
3202
+ }
3203
+ const timeout = setTimeout(() => {
3204
+ pendingRequests.delete(msg.id);
3205
+ sendMessage(ws, {
3206
+ type: "response",
3207
+ id: msg.id,
3208
+ error: { code: -32603, message: "Relay request timeout" }
3209
+ });
3210
+ }, RELAY_TIMEOUT_MS);
3211
+ pendingRequests.set(msg.id, { originOwner: fromOwner, timeout });
3212
+ sendMessage(targetWs, {
3213
+ type: "incoming_request",
3214
+ id: msg.id,
3215
+ from_owner: fromOwner,
3216
+ card_id: msg.card_id,
3217
+ skill_id: msg.skill_id,
3218
+ params: msg.params,
3219
+ requester: msg.requester ?? fromOwner,
3220
+ escrow_receipt: msg.escrow_receipt
3221
+ });
3222
+ }
3223
+ function handleRelayResponse(msg) {
3224
+ const pending = pendingRequests.get(msg.id);
3225
+ if (!pending) return;
3226
+ clearTimeout(pending.timeout);
3227
+ pendingRequests.delete(msg.id);
3228
+ const originWs = connections.get(pending.originOwner);
3229
+ if (originWs && originWs.readyState === 1) {
3230
+ sendMessage(originWs, {
3231
+ type: "response",
3232
+ id: msg.id,
3233
+ result: msg.result,
3234
+ error: msg.error
3235
+ });
3236
+ }
3237
+ }
3238
+ function handleDisconnect(owner) {
3239
+ if (!owner) return;
3240
+ connections.delete(owner);
3241
+ rateLimits.delete(owner);
3242
+ markOwnerOffline(owner);
3243
+ for (const [reqId, pending] of pendingRequests) {
3244
+ if (pending.originOwner === owner) {
3245
+ clearTimeout(pending.timeout);
3246
+ pendingRequests.delete(reqId);
3247
+ }
3248
+ }
3249
+ }
3250
+ server.get("/ws", { websocket: true }, (rawSocket, _request) => {
3251
+ const socket = rawSocket;
3252
+ let registeredOwner;
3253
+ socket.on("message", (raw) => {
3254
+ let data;
3255
+ try {
3256
+ data = JSON.parse(typeof raw === "string" ? raw : raw.toString("utf-8"));
3257
+ } catch {
3258
+ sendMessage(socket, { type: "error", code: "invalid_json", message: "Invalid JSON" });
3259
+ return;
3260
+ }
3261
+ const parsed = RelayMessageSchema.safeParse(data);
3262
+ if (!parsed.success) {
3263
+ sendMessage(socket, {
3264
+ type: "error",
3265
+ code: "invalid_message",
3266
+ message: `Invalid message: ${parsed.error.issues[0]?.message ?? "unknown error"}`
3267
+ });
3268
+ return;
3269
+ }
3270
+ const msg = parsed.data;
3271
+ switch (msg.type) {
3272
+ case "register":
3273
+ registeredOwner = msg.owner;
3274
+ handleRegister(socket, msg);
3275
+ break;
3276
+ case "relay_request":
3277
+ if (!registeredOwner) {
3278
+ sendMessage(socket, {
3279
+ type: "error",
3280
+ code: "not_registered",
3281
+ message: "Must send register message before relay requests"
3282
+ });
3283
+ return;
3284
+ }
3285
+ handleRelayRequest(socket, msg, registeredOwner);
3286
+ break;
3287
+ case "relay_response":
3288
+ handleRelayResponse(msg);
3289
+ break;
3290
+ default:
3291
+ break;
3292
+ }
3293
+ });
3294
+ socket.on("close", () => {
3295
+ handleDisconnect(registeredOwner);
3296
+ });
3297
+ socket.on("error", () => {
3298
+ handleDisconnect(registeredOwner);
3299
+ });
3300
+ });
3301
+ return {
3302
+ getOnlineCount: () => connections.size,
3303
+ getOnlineOwners: () => Array.from(connections.keys()),
3304
+ shutdown: () => {
3305
+ for (const [, ws] of connections) {
3306
+ try {
3307
+ ws.close(1001, "Server shutting down");
3308
+ } catch {
3309
+ }
3310
+ }
3311
+ connections.clear();
3312
+ for (const [, pending] of pendingRequests) {
3313
+ clearTimeout(pending.timeout);
3314
+ }
3315
+ pendingRequests.clear();
3316
+ rateLimits.clear();
3317
+ }
3318
+ };
3319
+ }
3320
+
3321
+ // src/relay/websocket-client.ts
3322
+ import WebSocket from "ws";
3323
+ import { randomUUID as randomUUID11 } from "crypto";
3324
+ var RelayClient = class {
3325
+ ws = null;
3326
+ opts;
3327
+ pendingRequests = /* @__PURE__ */ new Map();
3328
+ reconnectAttempts = 0;
3329
+ reconnectTimer = null;
3330
+ intentionalClose = false;
3331
+ registered = false;
3332
+ pongTimeout = null;
3333
+ pingInterval = null;
3334
+ constructor(opts) {
3335
+ this.opts = opts;
3336
+ }
3337
+ /**
3338
+ * Connect to the registry relay and register.
3339
+ * Resolves when registration is acknowledged.
3340
+ */
3341
+ async connect() {
3342
+ return new Promise((resolve, reject) => {
3343
+ this.intentionalClose = false;
3344
+ this.registered = false;
3345
+ const wsUrl = this.buildWsUrl();
3346
+ this.ws = new WebSocket(wsUrl);
3347
+ let resolved = false;
3348
+ this.ws.on("open", () => {
3349
+ this.reconnectAttempts = 0;
3350
+ this.startPingInterval();
3351
+ this.send({
3352
+ type: "register",
3353
+ owner: this.opts.owner,
3354
+ token: this.opts.token,
3355
+ card: this.opts.card
3356
+ });
3357
+ });
3358
+ this.ws.on("message", (raw) => {
3359
+ this.handleMessage(raw, (err) => {
3360
+ if (!resolved) {
3361
+ resolved = true;
3362
+ if (err) reject(err);
3363
+ else resolve();
3364
+ }
3365
+ });
3366
+ });
3367
+ this.ws.on("close", () => {
3368
+ this.cleanup();
3369
+ if (!this.intentionalClose) {
3370
+ if (!resolved) {
3371
+ resolved = true;
3372
+ reject(new Error("WebSocket closed before registration"));
3373
+ }
3374
+ this.scheduleReconnect();
3375
+ }
3376
+ });
3377
+ this.ws.on("error", (err) => {
3378
+ if (!resolved) {
3379
+ resolved = true;
3380
+ reject(err);
3381
+ }
3382
+ });
3383
+ setTimeout(() => {
3384
+ if (!resolved) {
3385
+ resolved = true;
3386
+ reject(new Error("Connection timeout"));
3387
+ this.ws?.close();
3388
+ }
3389
+ }, 1e4);
3390
+ });
3391
+ }
3392
+ /**
3393
+ * Disconnect from the registry relay.
3394
+ */
3395
+ disconnect() {
3396
+ this.intentionalClose = true;
3397
+ this.cleanup();
3398
+ if (this.ws) {
3399
+ try {
3400
+ this.ws.close(1e3, "Client disconnect");
3401
+ } catch {
3402
+ }
3403
+ this.ws = null;
3404
+ }
3405
+ for (const [id, pending] of this.pendingRequests) {
3406
+ clearTimeout(pending.timeout);
3407
+ pending.reject(new Error("Client disconnected"));
3408
+ this.pendingRequests.delete(id);
3409
+ }
3410
+ }
3411
+ /**
3412
+ * Send a relay request to another agent via the registry.
3413
+ * @returns The result from the target agent.
3414
+ */
3415
+ async request(opts) {
3416
+ if (!this.ws || this.ws.readyState !== WebSocket.OPEN || !this.registered) {
3417
+ throw new Error("Not connected to registry relay");
3418
+ }
3419
+ const id = randomUUID11();
3420
+ const timeoutMs = opts.timeoutMs ?? 3e4;
3421
+ return new Promise((resolve, reject) => {
3422
+ const timeout = setTimeout(() => {
3423
+ this.pendingRequests.delete(id);
3424
+ reject(new Error("Relay request timeout"));
3425
+ }, timeoutMs);
3426
+ this.pendingRequests.set(id, { resolve, reject, timeout });
3427
+ this.send({
3428
+ type: "relay_request",
3429
+ id,
3430
+ target_owner: opts.targetOwner,
3431
+ card_id: opts.cardId,
3432
+ skill_id: opts.skillId,
3433
+ params: opts.params,
3434
+ requester: opts.requester ?? this.opts.owner,
3435
+ escrow_receipt: opts.escrowReceipt
3436
+ });
3437
+ });
3438
+ }
3439
+ /** Whether the client is connected and registered */
3440
+ get isConnected() {
3441
+ return this.ws !== null && this.ws.readyState === WebSocket.OPEN && this.registered;
3442
+ }
3443
+ // ── Private methods ─────────────────────────────────────────────────────────
3444
+ buildWsUrl() {
3445
+ let url = this.opts.registryUrl;
3446
+ if (url.startsWith("http://")) {
3447
+ url = "ws://" + url.slice(7);
3448
+ } else if (url.startsWith("https://")) {
3449
+ url = "wss://" + url.slice(8);
3450
+ } else if (!url.startsWith("ws://") && !url.startsWith("wss://")) {
3451
+ url = "wss://" + url;
3452
+ }
3453
+ if (!url.endsWith("/ws")) {
3454
+ url = url.replace(/\/$/, "") + "/ws";
3455
+ }
3456
+ return url;
3457
+ }
3458
+ handleMessage(raw, onRegistered) {
3459
+ let data;
3460
+ try {
3461
+ data = JSON.parse(typeof raw === "string" ? raw : raw.toString("utf-8"));
3462
+ } catch {
3463
+ return;
3464
+ }
3465
+ const parsed = RelayMessageSchema.safeParse(data);
3466
+ if (!parsed.success) return;
3467
+ const msg = parsed.data;
3468
+ switch (msg.type) {
3469
+ case "registered":
3470
+ this.registered = true;
3471
+ if (!this.opts.silent) {
3472
+ console.log(` \u2713 Registered with registry (agent_id: ${msg.agent_id})`);
3473
+ }
3474
+ onRegistered?.();
3475
+ break;
3476
+ case "incoming_request":
3477
+ this.handleIncomingRequest(msg);
3478
+ break;
3479
+ case "response":
3480
+ this.handleResponse(msg);
3481
+ break;
3482
+ case "error":
3483
+ this.handleError(msg);
3484
+ break;
3485
+ default:
3486
+ break;
3487
+ }
3488
+ }
3489
+ async handleIncomingRequest(msg) {
3490
+ try {
3491
+ const result = await this.opts.onRequest(msg);
3492
+ this.send({
3493
+ type: "relay_response",
3494
+ id: msg.id,
3495
+ result: result.result,
3496
+ error: result.error
3497
+ });
3498
+ } catch (err) {
3499
+ this.send({
3500
+ type: "relay_response",
3501
+ id: msg.id,
3502
+ error: {
3503
+ code: -32603,
3504
+ message: err instanceof Error ? err.message : "Internal error"
3505
+ }
3506
+ });
3507
+ }
3508
+ }
3509
+ handleResponse(msg) {
3510
+ const pending = this.pendingRequests.get(msg.id);
3511
+ if (!pending) return;
3512
+ clearTimeout(pending.timeout);
3513
+ this.pendingRequests.delete(msg.id);
3514
+ if (msg.error) {
3515
+ pending.reject(new Error(msg.error.message));
3516
+ } else {
3517
+ pending.resolve(msg.result);
3518
+ }
3519
+ }
3520
+ handleError(msg) {
3521
+ if (msg.request_id) {
3522
+ const pending = this.pendingRequests.get(msg.request_id);
3523
+ if (pending) {
3524
+ clearTimeout(pending.timeout);
3525
+ this.pendingRequests.delete(msg.request_id);
3526
+ pending.reject(new Error(`${msg.code}: ${msg.message}`));
3527
+ }
3528
+ }
3529
+ }
3530
+ send(msg) {
3531
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
3532
+ this.ws.send(JSON.stringify(msg));
3533
+ }
3534
+ }
3535
+ startPingInterval() {
3536
+ this.stopPingInterval();
3537
+ this.pingInterval = setInterval(() => {
3538
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) {
3539
+ this.ws.ping();
3540
+ this.pongTimeout = setTimeout(() => {
3541
+ if (!this.opts.silent) {
3542
+ console.log(" \u26A0 Registry pong timeout, reconnecting...");
3543
+ }
3544
+ this.ws?.terminate();
3545
+ }, 15e3);
3546
+ }
3547
+ }, 3e4);
3548
+ this.ws?.on("pong", () => {
3549
+ if (this.pongTimeout) {
3550
+ clearTimeout(this.pongTimeout);
3551
+ this.pongTimeout = null;
3552
+ }
3553
+ });
3554
+ }
3555
+ stopPingInterval() {
3556
+ if (this.pingInterval) {
3557
+ clearInterval(this.pingInterval);
3558
+ this.pingInterval = null;
3559
+ }
3560
+ if (this.pongTimeout) {
3561
+ clearTimeout(this.pongTimeout);
3562
+ this.pongTimeout = null;
3563
+ }
3564
+ }
3565
+ cleanup() {
3566
+ this.stopPingInterval();
3567
+ this.registered = false;
3568
+ }
3569
+ scheduleReconnect() {
3570
+ if (this.intentionalClose) return;
3571
+ if (this.reconnectTimer) return;
3572
+ const delay = Math.min(1e3 * Math.pow(2, this.reconnectAttempts), 3e4);
3573
+ this.reconnectAttempts++;
3574
+ if (!this.opts.silent) {
3575
+ console.log(` \u21BB Reconnecting to registry in ${delay / 1e3}s...`);
3576
+ }
3577
+ this.reconnectTimer = setTimeout(async () => {
3578
+ this.reconnectTimer = null;
3579
+ try {
3580
+ await this.connect();
3581
+ if (!this.opts.silent) {
3582
+ console.log(" \u2713 Reconnected to registry");
3583
+ }
3584
+ } catch {
3585
+ }
3586
+ }, delay);
3587
+ }
3588
+ };
3589
+
3590
+ // src/onboarding/index.ts
3591
+ import { randomUUID as randomUUID13 } from "crypto";
3592
+ import { existsSync as existsSync5, readFileSync as readFileSync5 } from "fs";
3593
+ import { join as join5 } from "path";
3594
+
3595
+ // src/cli/onboarding.ts
3596
+ import { randomUUID as randomUUID12 } from "crypto";
3597
+ import { createConnection } from "net";
3598
+ var KNOWN_API_KEYS = [
3599
+ "OPENAI_API_KEY",
3600
+ "ANTHROPIC_API_KEY",
3601
+ "ELEVENLABS_API_KEY",
3602
+ "KLING_API_KEY",
3603
+ "STABILITY_API_KEY",
3604
+ "REPLICATE_API_TOKEN",
3605
+ "GOOGLE_API_KEY",
3606
+ "AZURE_OPENAI_API_KEY",
3607
+ "COHERE_API_KEY",
3608
+ "MISTRAL_API_KEY"
3609
+ ];
3610
+ function detectApiKeys(knownKeys) {
3611
+ return knownKeys.filter((key) => key in process.env);
3612
+ }
3613
+
3614
+ // src/onboarding/capability-templates.ts
3615
+ var API_PATTERNS = [
3616
+ {
3617
+ pattern: /openai|gpt-4|gpt-3|chatgpt|dall-e/i,
3618
+ capability: { key: "openai", name: "OpenAI Text Generation", category: "Text Gen", credits_per_call: 3, tags: ["llm", "text", "generation"] }
3619
+ },
3620
+ {
3621
+ pattern: /elevenlabs|eleven.?labs/i,
3622
+ capability: { key: "elevenlabs", name: "ElevenLabs TTS", category: "TTS", credits_per_call: 5, tags: ["tts", "audio", "voice"] }
3623
+ },
3624
+ {
3625
+ pattern: /anthropic|claude/i,
3626
+ capability: { key: "anthropic", name: "Anthropic Claude", category: "Text Gen", credits_per_call: 3, tags: ["llm", "text", "generation"] }
3627
+ },
3628
+ {
3629
+ pattern: /recraft/i,
3630
+ capability: { key: "recraft", name: "Recraft V4 Image Gen", category: "Image Gen", credits_per_call: 8, tags: ["image", "generation", "design"] }
3631
+ },
3632
+ {
3633
+ pattern: /kling/i,
3634
+ capability: { key: "kling", name: "Kling AI Video Gen", category: "Video Gen", credits_per_call: 10, tags: ["video", "generation"] }
3635
+ },
3636
+ {
3637
+ pattern: /stable.?diffusion|sdxl|comfyui/i,
3638
+ capability: { key: "stable-diffusion", name: "Stable Diffusion Image Gen", category: "Image Gen", credits_per_call: 6, tags: ["image", "generation", "diffusion"] }
3639
+ },
3640
+ {
3641
+ pattern: /whisper|speech.?to.?text|stt/i,
3642
+ capability: { key: "whisper", name: "Whisper Speech-to-Text", category: "STT", credits_per_call: 3, tags: ["stt", "audio", "transcription"] }
3643
+ },
3644
+ {
3645
+ pattern: /puppeteer|playwright|selenium/i,
3646
+ capability: { key: "puppeteer", name: "Web Scraping & Automation", category: "Web Scraping", credits_per_call: 2, tags: ["scraping", "automation", "browser"] }
3647
+ },
3648
+ {
3649
+ pattern: /ffmpeg/i,
3650
+ capability: { key: "ffmpeg", name: "FFmpeg Media Processing", category: "Media Processing", credits_per_call: 3, tags: ["media", "audio", "video", "processing"] }
3651
+ },
3652
+ {
3653
+ pattern: /tesseract|ocr/i,
3654
+ capability: { key: "tesseract", name: "OCR Text Extraction", category: "OCR", credits_per_call: 4, tags: ["ocr", "text", "extraction"] }
3655
+ }
3656
+ ];
3657
+ var INTERACTIVE_TEMPLATES = [
3658
+ { key: "openai", name: "Text Generation (GPT-4o / Claude / Gemini)", category: "Text Gen", credits_per_call: 3, tags: ["llm", "text", "generation"] },
3659
+ { key: "image-gen", name: "Image Generation (DALL-E / Recraft / Stable Diffusion)", category: "Image Gen", credits_per_call: 8, tags: ["image", "generation"] },
3660
+ { key: "tts", name: "TTS / Voice (ElevenLabs / Google TTS)", category: "TTS", credits_per_call: 5, tags: ["tts", "audio", "voice"] },
3661
+ { key: "video-gen", name: "Video Generation (Kling / Runway)", category: "Video Gen", credits_per_call: 10, tags: ["video", "generation"] },
3662
+ { key: "code-review", name: "Code Review / Analysis", category: "Code", credits_per_call: 3, tags: ["code", "review", "analysis"] },
3663
+ { key: "scraping", name: "Web Scraping / Data Extraction", category: "Web Scraping", credits_per_call: 2, tags: ["scraping", "data", "extraction"] },
3664
+ { key: "translation", name: "Translation", category: "Translation", credits_per_call: 3, tags: ["translation", "language", "text"] },
3665
+ { key: "custom", name: "Custom (describe it)", category: "Custom", credits_per_call: 5, tags: ["custom"] }
3666
+ ];
3667
+
3668
+ // src/onboarding/detect-from-docs.ts
3669
+ function detectFromDocs(content) {
3670
+ if (!content || content.trim().length === 0) {
3671
+ return [];
3672
+ }
3673
+ const seen = /* @__PURE__ */ new Set();
3674
+ const results = [];
3675
+ for (const entry of API_PATTERNS) {
3676
+ if (entry.pattern.test(content) && !seen.has(entry.capability.key)) {
3677
+ seen.add(entry.capability.key);
3678
+ results.push({ ...entry.capability });
3679
+ }
3680
+ }
3681
+ return results;
3682
+ }
3683
+
3684
+ // src/onboarding/interactive.ts
3685
+ import { createInterface } from "readline";
3686
+
3687
+ // src/onboarding/index.ts
3688
+ var DOC_FILES = ["SOUL.md", "CLAUDE.md", "AGENTS.md", "README.md"];
3689
+ function detectCapabilities(opts = {}) {
3690
+ const cwd = opts.cwd ?? process.cwd();
3691
+ if (opts.fromFile) {
3692
+ const filePath = opts.fromFile.startsWith("/") ? opts.fromFile : join5(cwd, opts.fromFile);
3693
+ if (existsSync5(filePath)) {
3694
+ const content = readFileSync5(filePath, "utf-8");
3695
+ const capabilities = detectFromDocs(content);
3696
+ if (capabilities.length > 0) {
3697
+ return { source: "docs", capabilities, sourceFile: filePath };
3698
+ }
3699
+ }
3700
+ return { source: "none", capabilities: [] };
3701
+ }
3702
+ for (const fileName of DOC_FILES) {
3703
+ const filePath = join5(cwd, fileName);
3704
+ if (!existsSync5(filePath)) continue;
3705
+ const content = readFileSync5(filePath, "utf-8");
3706
+ if (fileName === "SOUL.md") {
3707
+ return { source: "soul", capabilities: [], soulContent: content, sourceFile: filePath };
3708
+ }
3709
+ const capabilities = detectFromDocs(content);
3710
+ if (capabilities.length > 0) {
3711
+ return { source: "docs", capabilities, sourceFile: filePath };
3712
+ }
3713
+ }
3714
+ const envKeys = detectApiKeys(KNOWN_API_KEYS);
3715
+ if (envKeys.length > 0) {
3716
+ return { source: "env", capabilities: [], envKeys };
3717
+ }
3718
+ return { source: "none", capabilities: [] };
3719
+ }
3720
+ function capabilitiesToV2Card(capabilities, owner, agentName) {
3721
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3722
+ const skills = capabilities.map((cap) => ({
3723
+ id: cap.key,
3724
+ name: cap.name,
3725
+ description: `${cap.name} capability \u2014 ${cap.category}`,
3726
+ level: 1,
3727
+ category: cap.category.toLowerCase().replace(/\s+/g, "_"),
3728
+ inputs: [{ name: "input", type: "text", required: true }],
3729
+ outputs: [{ name: "output", type: "text", required: true }],
3730
+ pricing: { credits_per_call: cap.credits_per_call },
3731
+ availability: { online: true },
3732
+ metadata: {
3733
+ tags: cap.tags
3734
+ }
3735
+ }));
3736
+ const card = {
3737
+ spec_version: "2.0",
3738
+ id: randomUUID13(),
3739
+ owner,
3740
+ agent_name: agentName ?? owner,
3741
+ skills,
3742
+ availability: { online: true },
3743
+ created_at: now,
3744
+ updated_at: now
3745
+ };
3746
+ return CapabilityCardV2Schema.parse(card);
3747
+ }
2538
3748
  export {
3749
+ API_PATTERNS,
3750
+ AgentBnBConsumer,
3751
+ AgentBnBProvider,
3752
+ AgentCertificateSchema,
3753
+ AgentIdentitySchema,
2539
3754
  ApiExecutor,
2540
3755
  ApiSkillConfigSchema,
2541
3756
  BudgetController,
@@ -2546,11 +3761,17 @@ export {
2546
3761
  ConductorMode,
2547
3762
  ConductorSkillConfigSchema,
2548
3763
  EscrowReceiptSchema,
3764
+ GUARANTOR_CREDIT_POOL,
3765
+ GuarantorRecordSchema,
3766
+ INTERACTIVE_TEMPLATES,
3767
+ MAX_AGENTS_PER_GUARANTOR,
2549
3768
  ORCHESTRATION_FEE,
2550
3769
  OpenClawBridge,
2551
3770
  OpenClawSkillConfigSchema,
2552
3771
  PipelineExecutor,
2553
3772
  PipelineSkillConfigSchema,
3773
+ RelayClient,
3774
+ RelayMessageSchema,
2554
3775
  SkillConfigSchema,
2555
3776
  SkillExecutor,
2556
3777
  SkillsFileSchema,
@@ -2558,18 +3779,31 @@ export {
2558
3779
  applyInputMapping,
2559
3780
  buildAuthHeaders,
2560
3781
  buildConductorCard,
3782
+ capabilitiesToV2Card,
2561
3783
  createGatewayServer,
3784
+ createIdentity,
2562
3785
  createSignedEscrowReceipt,
2563
3786
  createSkillExecutor,
2564
3787
  decompose,
3788
+ deriveAgentId,
3789
+ detectCapabilities,
3790
+ detectFromDocs,
3791
+ ensureIdentity,
3792
+ executeCapabilityRequest,
2565
3793
  expandEnvVars,
2566
3794
  extractByPath,
2567
3795
  generateKeyPair,
3796
+ getAgentGuarantor,
2568
3797
  getBalance,
2569
3798
  getCard,
3799
+ getGuarantor,
3800
+ initiateGithubAuth,
2570
3801
  insertCard,
2571
3802
  interpolate,
2572
3803
  interpolateObject,
3804
+ issueAgentCertificate,
3805
+ linkAgentToGuarantor,
3806
+ loadIdentity,
2573
3807
  loadKeyPair,
2574
3808
  matchSubTasks,
2575
3809
  openCreditDb,
@@ -2577,12 +3811,17 @@ export {
2577
3811
  orchestrate,
2578
3812
  parseSkillsFile,
2579
3813
  registerConductorCard,
3814
+ registerGuarantor,
3815
+ registerWebSocketRelay,
2580
3816
  releaseRequesterEscrow,
3817
+ requestViaRelay,
2581
3818
  resolvePath,
3819
+ saveIdentity,
2582
3820
  saveKeyPair,
2583
3821
  searchCards,
2584
3822
  settleProviderEarning,
2585
3823
  settleRequesterEscrow,
2586
3824
  signEscrowReceipt,
3825
+ verifyAgentCertificate,
2587
3826
  verifyEscrowReceipt
2588
3827
  };