agentbnb 3.1.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/cli/index.js CHANGED
@@ -7,7 +7,7 @@ import {
7
7
  saveKeyPair,
8
8
  settleRequesterEscrow,
9
9
  signEscrowReceipt
10
- } from "../chunk-4Q7D24DP.js";
10
+ } from "../chunk-MGHI67GR.js";
11
11
  import {
12
12
  RelayMessageSchema
13
13
  } from "../chunk-3Y36WQDV.js";
@@ -24,7 +24,7 @@ import {
24
24
  requestCapability,
25
25
  resolvePendingRequest,
26
26
  searchCards
27
- } from "../chunk-QVIGMCHA.js";
27
+ } from "../chunk-2ETVQXP7.js";
28
28
  import {
29
29
  findPeer,
30
30
  getConfigDir,
@@ -46,7 +46,7 @@ import {
46
46
  updateCard,
47
47
  updateSkillAvailability,
48
48
  updateSkillIdleRate
49
- } from "../chunk-2LLXUKMY.js";
49
+ } from "../chunk-QAY6XTT7.js";
50
50
  import {
51
51
  bootstrapAgent,
52
52
  getBalance,
@@ -54,35 +54,115 @@ import {
54
54
  holdEscrow,
55
55
  openCreditDb,
56
56
  releaseEscrow
57
- } from "../chunk-ZJCIBK6O.js";
57
+ } from "../chunk-MZCNJ5PY.js";
58
58
  import {
59
59
  AgentBnBError,
60
- CapabilityCardSchema,
60
+ AnyCardSchema,
61
61
  CapabilityCardV2Schema
62
- } from "../chunk-TQMI73LL.js";
62
+ } from "../chunk-7RU5INZI.js";
63
63
 
64
64
  // src/cli/index.ts
65
65
  import { Command } from "commander";
66
- import { readFileSync as readFileSync3 } from "fs";
66
+ import { readFileSync as readFileSync5 } from "fs";
67
67
  import { createRequire } from "module";
68
68
  import { randomBytes } from "crypto";
69
- import { join as join2 } from "path";
69
+ import { join as join4 } from "path";
70
70
  import { networkInterfaces, homedir } from "os";
71
- import { createInterface } from "readline";
71
+ import { createInterface as createInterface2 } from "readline";
72
72
 
73
- // src/credit/escrow-receipt.ts
73
+ // src/identity/identity.ts
74
74
  import { z } from "zod";
75
- import { randomUUID } from "crypto";
76
- var EscrowReceiptSchema = z.object({
77
- requester_owner: z.string().min(1),
78
- requester_public_key: z.string().min(1),
79
- amount: z.number().positive(),
80
- card_id: z.string().min(1),
81
- skill_id: z.string().optional(),
82
- timestamp: z.string(),
83
- nonce: z.string().uuid(),
75
+ import { createHash } from "crypto";
76
+ import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
77
+ import { join } from "path";
78
+ var AgentIdentitySchema = z.object({
79
+ /** Deterministic ID derived from public key: sha256(hex).slice(0, 16). */
80
+ agent_id: z.string().min(1),
81
+ /** Human-readable owner name (from config or init). */
82
+ owner: z.string().min(1),
83
+ /** Hex-encoded Ed25519 public key. */
84
+ public_key: z.string().min(1),
85
+ /** ISO 8601 timestamp of identity creation. */
86
+ created_at: z.string().datetime(),
87
+ /** Optional guarantor info if linked to a human. */
88
+ guarantor: z.object({
89
+ github_login: z.string().min(1),
90
+ verified_at: z.string().datetime()
91
+ }).optional()
92
+ });
93
+ var AgentCertificateSchema = z.object({
94
+ identity: AgentIdentitySchema,
95
+ /** ISO 8601 timestamp of certificate issuance. */
96
+ issued_at: z.string().datetime(),
97
+ /** ISO 8601 timestamp of certificate expiry. */
98
+ expires_at: z.string().datetime(),
99
+ /** Hex-encoded public key of the issuer (same as identity for self-signed). */
100
+ issuer_public_key: z.string().min(1),
101
+ /** Base64url Ed25519 signature over { identity, issued_at, expires_at, issuer_public_key }. */
84
102
  signature: z.string().min(1)
85
103
  });
104
+ var IDENTITY_FILENAME = "identity.json";
105
+ function deriveAgentId(publicKeyHex) {
106
+ return createHash("sha256").update(publicKeyHex, "hex").digest("hex").slice(0, 16);
107
+ }
108
+ function createIdentity(configDir, owner) {
109
+ if (!existsSync(configDir)) {
110
+ mkdirSync(configDir, { recursive: true });
111
+ }
112
+ let keys;
113
+ try {
114
+ keys = loadKeyPair(configDir);
115
+ } catch {
116
+ keys = generateKeyPair();
117
+ saveKeyPair(configDir, keys);
118
+ }
119
+ const publicKeyHex = keys.publicKey.toString("hex");
120
+ const agentId = deriveAgentId(publicKeyHex);
121
+ const identity = {
122
+ agent_id: agentId,
123
+ owner,
124
+ public_key: publicKeyHex,
125
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
126
+ };
127
+ saveIdentity(configDir, identity);
128
+ return identity;
129
+ }
130
+ function loadIdentity(configDir) {
131
+ const filePath = join(configDir, IDENTITY_FILENAME);
132
+ if (!existsSync(filePath)) return null;
133
+ try {
134
+ const raw = readFileSync(filePath, "utf-8");
135
+ return AgentIdentitySchema.parse(JSON.parse(raw));
136
+ } catch {
137
+ return null;
138
+ }
139
+ }
140
+ function saveIdentity(configDir, identity) {
141
+ if (!existsSync(configDir)) {
142
+ mkdirSync(configDir, { recursive: true });
143
+ }
144
+ const filePath = join(configDir, IDENTITY_FILENAME);
145
+ writeFileSync(filePath, JSON.stringify(identity, null, 2), "utf-8");
146
+ }
147
+ function ensureIdentity(configDir, owner) {
148
+ const existing = loadIdentity(configDir);
149
+ if (existing) return existing;
150
+ return createIdentity(configDir, owner);
151
+ }
152
+
153
+ // src/credit/escrow-receipt.ts
154
+ import { z as z2 } from "zod";
155
+ import { randomUUID } from "crypto";
156
+ var EscrowReceiptSchema = z2.object({
157
+ requester_owner: z2.string().min(1),
158
+ requester_public_key: z2.string().min(1),
159
+ amount: z2.number().positive(),
160
+ card_id: z2.string().min(1),
161
+ skill_id: z2.string().optional(),
162
+ timestamp: z2.string(),
163
+ nonce: z2.string().uuid(),
164
+ signature: z2.string().min(1)
165
+ });
86
166
  function createSignedEscrowReceipt(db, privateKey, publicKey, opts) {
87
167
  const escrowId = holdEscrow(db, opts.owner, opts.amount, opts.cardId);
88
168
  const receiptData = {
@@ -447,8 +527,183 @@ function buildDraftCard(apiKey, owner) {
447
527
  };
448
528
  }
449
529
 
530
+ // src/onboarding/index.ts
531
+ import { randomUUID as randomUUID3 } from "crypto";
532
+ import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
533
+ import { join as join2 } from "path";
534
+
535
+ // src/onboarding/capability-templates.ts
536
+ var API_PATTERNS = [
537
+ {
538
+ pattern: /openai|gpt-4|gpt-3|chatgpt|dall-e/i,
539
+ capability: { key: "openai", name: "OpenAI Text Generation", category: "Text Gen", credits_per_call: 3, tags: ["llm", "text", "generation"] }
540
+ },
541
+ {
542
+ pattern: /elevenlabs|eleven.?labs/i,
543
+ capability: { key: "elevenlabs", name: "ElevenLabs TTS", category: "TTS", credits_per_call: 5, tags: ["tts", "audio", "voice"] }
544
+ },
545
+ {
546
+ pattern: /anthropic|claude/i,
547
+ capability: { key: "anthropic", name: "Anthropic Claude", category: "Text Gen", credits_per_call: 3, tags: ["llm", "text", "generation"] }
548
+ },
549
+ {
550
+ pattern: /recraft/i,
551
+ capability: { key: "recraft", name: "Recraft V4 Image Gen", category: "Image Gen", credits_per_call: 8, tags: ["image", "generation", "design"] }
552
+ },
553
+ {
554
+ pattern: /kling/i,
555
+ capability: { key: "kling", name: "Kling AI Video Gen", category: "Video Gen", credits_per_call: 10, tags: ["video", "generation"] }
556
+ },
557
+ {
558
+ pattern: /stable.?diffusion|sdxl|comfyui/i,
559
+ capability: { key: "stable-diffusion", name: "Stable Diffusion Image Gen", category: "Image Gen", credits_per_call: 6, tags: ["image", "generation", "diffusion"] }
560
+ },
561
+ {
562
+ pattern: /whisper|speech.?to.?text|stt/i,
563
+ capability: { key: "whisper", name: "Whisper Speech-to-Text", category: "STT", credits_per_call: 3, tags: ["stt", "audio", "transcription"] }
564
+ },
565
+ {
566
+ pattern: /puppeteer|playwright|selenium/i,
567
+ capability: { key: "puppeteer", name: "Web Scraping & Automation", category: "Web Scraping", credits_per_call: 2, tags: ["scraping", "automation", "browser"] }
568
+ },
569
+ {
570
+ pattern: /ffmpeg/i,
571
+ capability: { key: "ffmpeg", name: "FFmpeg Media Processing", category: "Media Processing", credits_per_call: 3, tags: ["media", "audio", "video", "processing"] }
572
+ },
573
+ {
574
+ pattern: /tesseract|ocr/i,
575
+ capability: { key: "tesseract", name: "OCR Text Extraction", category: "OCR", credits_per_call: 4, tags: ["ocr", "text", "extraction"] }
576
+ }
577
+ ];
578
+ var INTERACTIVE_TEMPLATES = [
579
+ { key: "openai", name: "Text Generation (GPT-4o / Claude / Gemini)", category: "Text Gen", credits_per_call: 3, tags: ["llm", "text", "generation"] },
580
+ { key: "image-gen", name: "Image Generation (DALL-E / Recraft / Stable Diffusion)", category: "Image Gen", credits_per_call: 8, tags: ["image", "generation"] },
581
+ { key: "tts", name: "TTS / Voice (ElevenLabs / Google TTS)", category: "TTS", credits_per_call: 5, tags: ["tts", "audio", "voice"] },
582
+ { key: "video-gen", name: "Video Generation (Kling / Runway)", category: "Video Gen", credits_per_call: 10, tags: ["video", "generation"] },
583
+ { key: "code-review", name: "Code Review / Analysis", category: "Code", credits_per_call: 3, tags: ["code", "review", "analysis"] },
584
+ { key: "scraping", name: "Web Scraping / Data Extraction", category: "Web Scraping", credits_per_call: 2, tags: ["scraping", "data", "extraction"] },
585
+ { key: "translation", name: "Translation", category: "Translation", credits_per_call: 3, tags: ["translation", "language", "text"] },
586
+ { key: "custom", name: "Custom (describe it)", category: "Custom", credits_per_call: 5, tags: ["custom"] }
587
+ ];
588
+
589
+ // src/onboarding/detect-from-docs.ts
590
+ function detectFromDocs(content) {
591
+ if (!content || content.trim().length === 0) {
592
+ return [];
593
+ }
594
+ const seen = /* @__PURE__ */ new Set();
595
+ const results = [];
596
+ for (const entry of API_PATTERNS) {
597
+ if (entry.pattern.test(content) && !seen.has(entry.capability.key)) {
598
+ seen.add(entry.capability.key);
599
+ results.push({ ...entry.capability });
600
+ }
601
+ }
602
+ return results;
603
+ }
604
+
605
+ // src/onboarding/interactive.ts
606
+ import { createInterface } from "readline";
607
+ async function interactiveTemplateMenu() {
608
+ console.log("\nNo capabilities auto-detected.\n");
609
+ console.log("What can your agent do? Pick from templates:\n");
610
+ for (let i = 0; i < INTERACTIVE_TEMPLATES.length; i++) {
611
+ console.log(` ${i + 1}. ${INTERACTIVE_TEMPLATES[i].name}`);
612
+ }
613
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
614
+ const answer = await new Promise((resolve) => {
615
+ rl.question("\nSelect [1-8, comma-separated]: ", (ans) => {
616
+ rl.close();
617
+ resolve(ans);
618
+ });
619
+ });
620
+ return parseSelection(answer);
621
+ }
622
+ function parseSelection(input) {
623
+ if (!input || input.trim().length === 0) {
624
+ return [];
625
+ }
626
+ const selected = [];
627
+ const seen = /* @__PURE__ */ new Set();
628
+ const parts = input.split(",").map((s) => s.trim());
629
+ for (const part of parts) {
630
+ const num = parseInt(part, 10);
631
+ if (isNaN(num) || num < 1 || num > INTERACTIVE_TEMPLATES.length) {
632
+ continue;
633
+ }
634
+ const template = INTERACTIVE_TEMPLATES[num - 1];
635
+ if (!seen.has(template.key)) {
636
+ seen.add(template.key);
637
+ selected.push({ ...template });
638
+ }
639
+ }
640
+ return selected;
641
+ }
642
+
643
+ // src/onboarding/index.ts
644
+ var DOC_FILES = ["SOUL.md", "CLAUDE.md", "AGENTS.md", "README.md"];
645
+ function detectCapabilities(opts = {}) {
646
+ const cwd = opts.cwd ?? process.cwd();
647
+ if (opts.fromFile) {
648
+ const filePath = opts.fromFile.startsWith("/") ? opts.fromFile : join2(cwd, opts.fromFile);
649
+ if (existsSync2(filePath)) {
650
+ const content = readFileSync2(filePath, "utf-8");
651
+ const capabilities = detectFromDocs(content);
652
+ if (capabilities.length > 0) {
653
+ return { source: "docs", capabilities, sourceFile: filePath };
654
+ }
655
+ }
656
+ return { source: "none", capabilities: [] };
657
+ }
658
+ for (const fileName of DOC_FILES) {
659
+ const filePath = join2(cwd, fileName);
660
+ if (!existsSync2(filePath)) continue;
661
+ const content = readFileSync2(filePath, "utf-8");
662
+ if (fileName === "SOUL.md") {
663
+ return { source: "soul", capabilities: [], soulContent: content, sourceFile: filePath };
664
+ }
665
+ const capabilities = detectFromDocs(content);
666
+ if (capabilities.length > 0) {
667
+ return { source: "docs", capabilities, sourceFile: filePath };
668
+ }
669
+ }
670
+ const envKeys = detectApiKeys(KNOWN_API_KEYS);
671
+ if (envKeys.length > 0) {
672
+ return { source: "env", capabilities: [], envKeys };
673
+ }
674
+ return { source: "none", capabilities: [] };
675
+ }
676
+ function capabilitiesToV2Card(capabilities, owner, agentName) {
677
+ const now = (/* @__PURE__ */ new Date()).toISOString();
678
+ const skills = capabilities.map((cap) => ({
679
+ id: cap.key,
680
+ name: cap.name,
681
+ description: `${cap.name} capability \u2014 ${cap.category}`,
682
+ level: 1,
683
+ category: cap.category.toLowerCase().replace(/\s+/g, "_"),
684
+ inputs: [{ name: "input", type: "text", required: true }],
685
+ outputs: [{ name: "output", type: "text", required: true }],
686
+ pricing: { credits_per_call: cap.credits_per_call },
687
+ availability: { online: true },
688
+ metadata: {
689
+ tags: cap.tags
690
+ }
691
+ }));
692
+ const card = {
693
+ spec_version: "2.0",
694
+ id: randomUUID3(),
695
+ owner,
696
+ agent_name: agentName ?? owner,
697
+ skills,
698
+ availability: { online: true },
699
+ created_at: now,
700
+ updated_at: now
701
+ };
702
+ return CapabilityCardV2Schema.parse(card);
703
+ }
704
+
450
705
  // src/runtime/agent-runtime.ts
451
- import { readFileSync, existsSync } from "fs";
706
+ import { readFileSync as readFileSync3, existsSync as existsSync3 } from "fs";
452
707
 
453
708
  // src/skills/executor.ts
454
709
  var SkillExecutor = class {
@@ -531,98 +786,98 @@ function createSkillExecutor(configs, modes) {
531
786
  }
532
787
 
533
788
  // src/skills/skill-config.ts
534
- import { z as z2 } from "zod";
789
+ import { z as z3 } from "zod";
535
790
  import yaml from "js-yaml";
536
- var PricingSchema = z2.object({
537
- credits_per_call: z2.number().nonnegative(),
538
- credits_per_minute: z2.number().nonnegative().optional(),
539
- free_tier: z2.number().nonnegative().optional()
791
+ var PricingSchema = z3.object({
792
+ credits_per_call: z3.number().nonnegative(),
793
+ credits_per_minute: z3.number().nonnegative().optional(),
794
+ free_tier: z3.number().nonnegative().optional()
540
795
  });
541
- var ApiAuthSchema = z2.discriminatedUnion("type", [
542
- z2.object({
543
- type: z2.literal("bearer"),
544
- token: z2.string()
796
+ var ApiAuthSchema = z3.discriminatedUnion("type", [
797
+ z3.object({
798
+ type: z3.literal("bearer"),
799
+ token: z3.string()
545
800
  }),
546
- z2.object({
547
- type: z2.literal("apikey"),
548
- header: z2.string().default("X-API-Key"),
549
- key: z2.string()
801
+ z3.object({
802
+ type: z3.literal("apikey"),
803
+ header: z3.string().default("X-API-Key"),
804
+ key: z3.string()
550
805
  }),
551
- z2.object({
552
- type: z2.literal("basic"),
553
- username: z2.string(),
554
- password: z2.string()
806
+ z3.object({
807
+ type: z3.literal("basic"),
808
+ username: z3.string(),
809
+ password: z3.string()
555
810
  })
556
811
  ]);
557
- var ApiSkillConfigSchema = z2.object({
558
- id: z2.string().min(1),
559
- type: z2.literal("api"),
560
- name: z2.string().min(1),
561
- endpoint: z2.string().min(1),
562
- method: z2.enum(["GET", "POST", "PUT", "DELETE"]),
812
+ var ApiSkillConfigSchema = z3.object({
813
+ id: z3.string().min(1),
814
+ type: z3.literal("api"),
815
+ name: z3.string().min(1),
816
+ endpoint: z3.string().min(1),
817
+ method: z3.enum(["GET", "POST", "PUT", "DELETE"]),
563
818
  auth: ApiAuthSchema.optional(),
564
- input_mapping: z2.record(z2.string()).default({}),
565
- output_mapping: z2.record(z2.string()).default({}),
819
+ input_mapping: z3.record(z3.string()).default({}),
820
+ output_mapping: z3.record(z3.string()).default({}),
566
821
  pricing: PricingSchema,
567
- timeout_ms: z2.number().positive().default(3e4),
568
- retries: z2.number().nonnegative().int().default(0),
569
- provider: z2.string().optional()
822
+ timeout_ms: z3.number().positive().default(3e4),
823
+ retries: z3.number().nonnegative().int().default(0),
824
+ provider: z3.string().optional()
570
825
  });
571
- var PipelineStepSchema = z2.union([
572
- z2.object({
573
- skill_id: z2.string().min(1),
574
- input_mapping: z2.record(z2.string()).default({})
826
+ var PipelineStepSchema = z3.union([
827
+ z3.object({
828
+ skill_id: z3.string().min(1),
829
+ input_mapping: z3.record(z3.string()).default({})
575
830
  }),
576
- z2.object({
577
- command: z2.string().min(1),
578
- input_mapping: z2.record(z2.string()).default({})
831
+ z3.object({
832
+ command: z3.string().min(1),
833
+ input_mapping: z3.record(z3.string()).default({})
579
834
  })
580
835
  ]);
581
- var PipelineSkillConfigSchema = z2.object({
582
- id: z2.string().min(1),
583
- type: z2.literal("pipeline"),
584
- name: z2.string().min(1),
585
- steps: z2.array(PipelineStepSchema).min(1),
836
+ var PipelineSkillConfigSchema = z3.object({
837
+ id: z3.string().min(1),
838
+ type: z3.literal("pipeline"),
839
+ name: z3.string().min(1),
840
+ steps: z3.array(PipelineStepSchema).min(1),
586
841
  pricing: PricingSchema,
587
- timeout_ms: z2.number().positive().optional()
842
+ timeout_ms: z3.number().positive().optional()
588
843
  });
589
- var OpenClawSkillConfigSchema = z2.object({
590
- id: z2.string().min(1),
591
- type: z2.literal("openclaw"),
592
- name: z2.string().min(1),
593
- agent_name: z2.string().min(1),
594
- channel: z2.enum(["telegram", "webhook", "process"]),
844
+ var OpenClawSkillConfigSchema = z3.object({
845
+ id: z3.string().min(1),
846
+ type: z3.literal("openclaw"),
847
+ name: z3.string().min(1),
848
+ agent_name: z3.string().min(1),
849
+ channel: z3.enum(["telegram", "webhook", "process"]),
595
850
  pricing: PricingSchema,
596
- timeout_ms: z2.number().positive().optional()
851
+ timeout_ms: z3.number().positive().optional()
597
852
  });
598
- var CommandSkillConfigSchema = z2.object({
599
- id: z2.string().min(1),
600
- type: z2.literal("command"),
601
- name: z2.string().min(1),
602
- command: z2.string().min(1),
603
- output_type: z2.enum(["json", "text", "file"]),
604
- allowed_commands: z2.array(z2.string()).optional(),
605
- working_dir: z2.string().optional(),
606
- timeout_ms: z2.number().positive().default(3e4),
853
+ var CommandSkillConfigSchema = z3.object({
854
+ id: z3.string().min(1),
855
+ type: z3.literal("command"),
856
+ name: z3.string().min(1),
857
+ command: z3.string().min(1),
858
+ output_type: z3.enum(["json", "text", "file"]),
859
+ allowed_commands: z3.array(z3.string()).optional(),
860
+ working_dir: z3.string().optional(),
861
+ timeout_ms: z3.number().positive().default(3e4),
607
862
  pricing: PricingSchema
608
863
  });
609
- var ConductorSkillConfigSchema = z2.object({
610
- id: z2.string().min(1),
611
- type: z2.literal("conductor"),
612
- name: z2.string().min(1),
613
- conductor_skill: z2.enum(["orchestrate", "plan"]),
864
+ var ConductorSkillConfigSchema = z3.object({
865
+ id: z3.string().min(1),
866
+ type: z3.literal("conductor"),
867
+ name: z3.string().min(1),
868
+ conductor_skill: z3.enum(["orchestrate", "plan"]),
614
869
  pricing: PricingSchema,
615
- timeout_ms: z2.number().positive().optional()
870
+ timeout_ms: z3.number().positive().optional()
616
871
  });
617
- var SkillConfigSchema = z2.discriminatedUnion("type", [
872
+ var SkillConfigSchema = z3.discriminatedUnion("type", [
618
873
  ApiSkillConfigSchema,
619
874
  PipelineSkillConfigSchema,
620
875
  OpenClawSkillConfigSchema,
621
876
  CommandSkillConfigSchema,
622
877
  ConductorSkillConfigSchema
623
878
  ]);
624
- var SkillsFileSchema = z2.object({
625
- skills: z2.array(SkillConfigSchema)
879
+ var SkillsFileSchema = z3.object({
880
+ skills: z3.array(SkillConfigSchema)
626
881
  });
627
882
  function expandEnvVars(value) {
628
883
  return value.replace(/\$\{([^}]+)\}/g, (_match, varName) => {
@@ -1259,19 +1514,19 @@ var AgentRuntime = class {
1259
1514
  * 3. Populate the Map with all 4 modes — SkillExecutor sees them via reference.
1260
1515
  */
1261
1516
  async initSkillExecutor() {
1262
- const hasSkillsYaml = this.skillsYamlPath && existsSync(this.skillsYamlPath);
1517
+ const hasSkillsYaml = this.skillsYamlPath && existsSync3(this.skillsYamlPath);
1263
1518
  if (!hasSkillsYaml && !this.conductorEnabled) {
1264
1519
  return;
1265
1520
  }
1266
1521
  let configs = [];
1267
1522
  if (hasSkillsYaml) {
1268
- const yamlContent = readFileSync(this.skillsYamlPath, "utf8");
1523
+ const yamlContent = readFileSync3(this.skillsYamlPath, "utf8");
1269
1524
  configs = parseSkillsFile(yamlContent);
1270
1525
  }
1271
1526
  const modes = /* @__PURE__ */ new Map();
1272
1527
  if (this.conductorEnabled) {
1273
- const { ConductorMode } = await import("../conductor-mode-CF6PSRRA.js");
1274
- const { registerConductorCard, CONDUCTOR_OWNER } = await import("../card-P5C36VBD.js");
1528
+ const { ConductorMode } = await import("../conductor-mode-GPLAM2XO.js");
1529
+ const { registerConductorCard, CONDUCTOR_OWNER } = await import("../card-EWIXC377.js");
1275
1530
  const { loadPeers: loadPeers2 } = await import("../peers-G36URZYB.js");
1276
1531
  registerConductorCard(this.registryDb);
1277
1532
  const resolveAgentUrl = (owner) => {
@@ -1468,12 +1723,12 @@ import Fastify2 from "fastify";
1468
1723
  import cors from "@fastify/cors";
1469
1724
  import fastifyStatic from "@fastify/static";
1470
1725
  import fastifyWebsocket from "@fastify/websocket";
1471
- import { join, dirname } from "path";
1726
+ import { join as join3, dirname } from "path";
1472
1727
  import { fileURLToPath } from "url";
1473
- import { existsSync as existsSync2 } from "fs";
1728
+ import { existsSync as existsSync4 } from "fs";
1474
1729
 
1475
1730
  // src/relay/websocket-relay.ts
1476
- import { randomUUID as randomUUID3 } from "crypto";
1731
+ import { randomUUID as randomUUID4 } from "crypto";
1477
1732
  var RATE_LIMIT_MAX = 60;
1478
1733
  var RATE_LIMIT_WINDOW_MS = 6e4;
1479
1734
  var RELAY_TIMEOUT_MS = 3e4;
@@ -1545,7 +1800,7 @@ function registerWebSocketRelay(server, db) {
1545
1800
  function logAgentJoined(owner, cardName, cardId) {
1546
1801
  try {
1547
1802
  insertRequestLog(db, {
1548
- id: randomUUID3(),
1803
+ id: randomUUID4(),
1549
1804
  card_id: cardId,
1550
1805
  card_name: cardName,
1551
1806
  requester: owner,
@@ -1645,7 +1900,8 @@ function registerWebSocketRelay(server, db) {
1645
1900
  }
1646
1901
  }
1647
1902
  }
1648
- server.get("/ws", { websocket: true }, (socket) => {
1903
+ server.get("/ws", { websocket: true }, (rawSocket, _request) => {
1904
+ const socket = rawSocket;
1649
1905
  let registeredOwner;
1650
1906
  socket.on("message", (raw) => {
1651
1907
  let data;
@@ -1715,6 +1971,125 @@ function registerWebSocketRelay(server, db) {
1715
1971
  };
1716
1972
  }
1717
1973
 
1974
+ // src/identity/guarantor.ts
1975
+ import { z as z4 } from "zod";
1976
+ import { randomUUID as randomUUID5 } from "crypto";
1977
+ var MAX_AGENTS_PER_GUARANTOR = 10;
1978
+ var GUARANTOR_CREDIT_POOL = 50;
1979
+ var GuarantorRecordSchema = z4.object({
1980
+ id: z4.string().uuid(),
1981
+ github_login: z4.string().min(1),
1982
+ agent_count: z4.number().int().nonnegative(),
1983
+ credit_pool: z4.number().int().nonnegative(),
1984
+ created_at: z4.string().datetime()
1985
+ });
1986
+ var GUARANTOR_SCHEMA = `
1987
+ CREATE TABLE IF NOT EXISTS guarantors (
1988
+ id TEXT PRIMARY KEY,
1989
+ github_login TEXT UNIQUE NOT NULL,
1990
+ agent_count INTEGER NOT NULL DEFAULT 0,
1991
+ credit_pool INTEGER NOT NULL DEFAULT ${GUARANTOR_CREDIT_POOL},
1992
+ created_at TEXT NOT NULL
1993
+ );
1994
+
1995
+ CREATE TABLE IF NOT EXISTS agent_guarantors (
1996
+ agent_id TEXT PRIMARY KEY,
1997
+ guarantor_id TEXT NOT NULL,
1998
+ linked_at TEXT NOT NULL,
1999
+ FOREIGN KEY (guarantor_id) REFERENCES guarantors(id)
2000
+ );
2001
+ `;
2002
+ function ensureGuarantorTables(db) {
2003
+ db.exec(GUARANTOR_SCHEMA);
2004
+ }
2005
+ function registerGuarantor(db, githubLogin) {
2006
+ ensureGuarantorTables(db);
2007
+ const existing = db.prepare("SELECT * FROM guarantors WHERE github_login = ?").get(githubLogin);
2008
+ if (existing) {
2009
+ throw new AgentBnBError(
2010
+ `Guarantor already registered: ${githubLogin}`,
2011
+ "GUARANTOR_EXISTS"
2012
+ );
2013
+ }
2014
+ const record = {
2015
+ id: randomUUID5(),
2016
+ github_login: githubLogin,
2017
+ agent_count: 0,
2018
+ credit_pool: GUARANTOR_CREDIT_POOL,
2019
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
2020
+ };
2021
+ db.prepare(
2022
+ "INSERT INTO guarantors (id, github_login, agent_count, credit_pool, created_at) VALUES (?, ?, ?, ?, ?)"
2023
+ ).run(record.id, record.github_login, record.agent_count, record.credit_pool, record.created_at);
2024
+ return record;
2025
+ }
2026
+ function linkAgentToGuarantor(db, agentId, githubLogin) {
2027
+ ensureGuarantorTables(db);
2028
+ const guarantor = db.prepare("SELECT * FROM guarantors WHERE github_login = ?").get(githubLogin);
2029
+ if (!guarantor) {
2030
+ throw new AgentBnBError(
2031
+ `Guarantor not found: ${githubLogin}`,
2032
+ "GUARANTOR_NOT_FOUND"
2033
+ );
2034
+ }
2035
+ if (guarantor["agent_count"] >= MAX_AGENTS_PER_GUARANTOR) {
2036
+ throw new AgentBnBError(
2037
+ `Maximum agents per guarantor reached (${MAX_AGENTS_PER_GUARANTOR})`,
2038
+ "MAX_AGENTS_EXCEEDED"
2039
+ );
2040
+ }
2041
+ const existingLink = db.prepare("SELECT * FROM agent_guarantors WHERE agent_id = ?").get(agentId);
2042
+ if (existingLink) {
2043
+ throw new AgentBnBError(
2044
+ `Agent ${agentId} is already linked to a guarantor`,
2045
+ "AGENT_ALREADY_LINKED"
2046
+ );
2047
+ }
2048
+ db.transaction(() => {
2049
+ db.prepare("INSERT INTO agent_guarantors (agent_id, guarantor_id, linked_at) VALUES (?, ?, ?)").run(
2050
+ agentId,
2051
+ guarantor["id"],
2052
+ (/* @__PURE__ */ new Date()).toISOString()
2053
+ );
2054
+ db.prepare("UPDATE guarantors SET agent_count = agent_count + 1 WHERE id = ?").run(guarantor["id"]);
2055
+ })();
2056
+ return getGuarantor(db, githubLogin);
2057
+ }
2058
+ function getGuarantor(db, githubLogin) {
2059
+ ensureGuarantorTables(db);
2060
+ const row = db.prepare("SELECT * FROM guarantors WHERE github_login = ?").get(githubLogin);
2061
+ if (!row) return null;
2062
+ return {
2063
+ id: row["id"],
2064
+ github_login: row["github_login"],
2065
+ agent_count: row["agent_count"],
2066
+ credit_pool: row["credit_pool"],
2067
+ created_at: row["created_at"]
2068
+ };
2069
+ }
2070
+ function getAgentGuarantor(db, agentId) {
2071
+ ensureGuarantorTables(db);
2072
+ const link = db.prepare(
2073
+ `SELECT g.* FROM guarantors g
2074
+ JOIN agent_guarantors ag ON ag.guarantor_id = g.id
2075
+ WHERE ag.agent_id = ?`
2076
+ ).get(agentId);
2077
+ if (!link) return null;
2078
+ return {
2079
+ id: link["id"],
2080
+ github_login: link["github_login"],
2081
+ agent_count: link["agent_count"],
2082
+ credit_pool: link["credit_pool"],
2083
+ created_at: link["created_at"]
2084
+ };
2085
+ }
2086
+ function initiateGithubAuth() {
2087
+ return {
2088
+ auth_url: "https://github.com/login/oauth/authorize?client_id=PLACEHOLDER&scope=read:user",
2089
+ state: randomUUID5()
2090
+ };
2091
+ }
2092
+
1718
2093
  // src/registry/server.ts
1719
2094
  function stripInternal(card) {
1720
2095
  const { _internal: _, ...publicCard } = card;
@@ -1736,17 +2111,20 @@ function createRegistryServer(opts) {
1736
2111
  const __filename = fileURLToPath(import.meta.url);
1737
2112
  const __dirname = dirname(__filename);
1738
2113
  const hubDistCandidates = [
1739
- join(__dirname, "../../hub/dist"),
2114
+ join3(__dirname, "../../hub/dist"),
1740
2115
  // When running from dist/registry/server.js
1741
- join(__dirname, "../../../hub/dist")
2116
+ join3(__dirname, "../../../hub/dist")
1742
2117
  // Fallback for alternative layouts
1743
2118
  ];
1744
- const hubDistDir = hubDistCandidates.find((p) => existsSync2(p));
2119
+ const hubDistDir = hubDistCandidates.find((p) => existsSync4(p));
1745
2120
  if (hubDistDir) {
1746
2121
  void server.register(fastifyStatic, {
1747
2122
  root: hubDistDir,
1748
2123
  prefix: "/hub/"
1749
2124
  });
2125
+ server.get("/", async (_request, reply) => {
2126
+ return reply.redirect("/hub/");
2127
+ });
1750
2128
  server.get("/hub", async (_request, reply) => {
1751
2129
  return reply.redirect("/hub/");
1752
2130
  });
@@ -1794,12 +2172,47 @@ function createRegistryServer(opts) {
1794
2172
  (c) => (c.metadata?.avg_latency_ms ?? Infinity) <= maxLatencyMs
1795
2173
  );
1796
2174
  }
1797
- if (sort === "success_rate") {
2175
+ const usesStmt = db.prepare(`
2176
+ SELECT card_id, skill_id, COUNT(*) as cnt
2177
+ FROM request_log
2178
+ WHERE status = 'success'
2179
+ AND created_at > datetime('now', '-7 days')
2180
+ AND (action_type IS NULL OR action_type = 'auto_share')
2181
+ GROUP BY card_id, skill_id
2182
+ `);
2183
+ const usesRows = usesStmt.all();
2184
+ const usesMap = /* @__PURE__ */ new Map();
2185
+ for (const row of usesRows) {
2186
+ usesMap.set(row.card_id, (usesMap.get(row.card_id) ?? 0) + row.cnt);
2187
+ if (row.skill_id) {
2188
+ usesMap.set(row.skill_id, (usesMap.get(row.skill_id) ?? 0) + row.cnt);
2189
+ }
2190
+ }
2191
+ if (sort === "popular") {
2192
+ cards = [...cards].sort((a, b) => {
2193
+ const aUses = usesMap.get(a.id) ?? 0;
2194
+ const bUses = usesMap.get(b.id) ?? 0;
2195
+ return bUses - aUses;
2196
+ });
2197
+ } else if (sort === "rated" || sort === "success_rate") {
1798
2198
  cards = [...cards].sort((a, b) => {
1799
2199
  const aRate = a.metadata?.success_rate ?? -1;
1800
2200
  const bRate = b.metadata?.success_rate ?? -1;
1801
2201
  return bRate - aRate;
1802
2202
  });
2203
+ } else if (sort === "cheapest") {
2204
+ cards = [...cards].sort((a, b) => {
2205
+ return a.pricing.credits_per_call - b.pricing.credits_per_call;
2206
+ });
2207
+ } else if (sort === "newest") {
2208
+ const createdStmt = db.prepare("SELECT id, created_at FROM capability_cards");
2209
+ const createdRows = createdStmt.all();
2210
+ const createdMap = new Map(createdRows.map((r) => [r.id, r.created_at]));
2211
+ cards = [...cards].sort((a, b) => {
2212
+ const aDate = createdMap.get(a.id) ?? "";
2213
+ const bDate = createdMap.get(b.id) ?? "";
2214
+ return bDate.localeCompare(aDate);
2215
+ });
1803
2216
  } else if (sort === "latency") {
1804
2217
  cards = [...cards].sort((a, b) => {
1805
2218
  const aLatency = a.metadata?.avg_latency_ms ?? Infinity;
@@ -1809,9 +2222,32 @@ function createRegistryServer(opts) {
1809
2222
  }
1810
2223
  const total = cards.length;
1811
2224
  const items = cards.slice(offset, offset + limit).map(stripInternal);
1812
- const result = { total, limit, offset, items };
2225
+ const usesThisWeek = {};
2226
+ for (const [key, count] of usesMap) {
2227
+ if (count > 0) usesThisWeek[key] = count;
2228
+ }
2229
+ const result = { total, limit, offset, items, uses_this_week: usesThisWeek };
1813
2230
  return reply.send(result);
1814
2231
  });
2232
+ server.get("/api/cards/trending", async (_request, reply) => {
2233
+ const trendingStmt = db.prepare(`
2234
+ SELECT rl.card_id, COUNT(*) as recent_requests
2235
+ FROM request_log rl
2236
+ WHERE rl.status = 'success'
2237
+ AND rl.created_at > datetime('now', '-7 days')
2238
+ AND (rl.action_type IS NULL OR rl.action_type = 'auto_share')
2239
+ GROUP BY rl.card_id
2240
+ ORDER BY recent_requests DESC
2241
+ LIMIT 10
2242
+ `);
2243
+ const trendingRows = trendingStmt.all();
2244
+ const items = trendingRows.map((row) => {
2245
+ const card = getCard(db, row.card_id);
2246
+ if (!card) return null;
2247
+ return { ...stripInternal(card), uses_this_week: row.recent_requests };
2248
+ }).filter((item) => item !== null);
2249
+ return reply.send({ items });
2250
+ });
1815
2251
  server.get("/cards/:id", async (request, reply) => {
1816
2252
  const { id } = request.params;
1817
2253
  const card = getCard(db, id);
@@ -1820,6 +2256,57 @@ function createRegistryServer(opts) {
1820
2256
  }
1821
2257
  return reply.send(stripInternal(card));
1822
2258
  });
2259
+ server.post("/cards", async (request, reply) => {
2260
+ const body = request.body;
2261
+ if (!body.spec_version) {
2262
+ body.spec_version = "1.0";
2263
+ }
2264
+ const result = AnyCardSchema.safeParse(body);
2265
+ if (!result.success) {
2266
+ return reply.code(400).send({
2267
+ error: "Card validation failed",
2268
+ issues: result.error.issues
2269
+ });
2270
+ }
2271
+ const card = result.data;
2272
+ const now = (/* @__PURE__ */ new Date()).toISOString();
2273
+ if (card.spec_version === "2.0") {
2274
+ const cardWithTimestamps = {
2275
+ ...card,
2276
+ created_at: card.created_at ?? now,
2277
+ updated_at: now
2278
+ };
2279
+ db.prepare(
2280
+ `INSERT OR REPLACE INTO capability_cards (id, owner, data, created_at, updated_at)
2281
+ VALUES (?, ?, ?, ?, ?)`
2282
+ ).run(
2283
+ cardWithTimestamps.id,
2284
+ cardWithTimestamps.owner,
2285
+ JSON.stringify(cardWithTimestamps),
2286
+ cardWithTimestamps.created_at,
2287
+ cardWithTimestamps.updated_at
2288
+ );
2289
+ } else {
2290
+ try {
2291
+ insertCard(db, card);
2292
+ } catch (err) {
2293
+ if (err instanceof AgentBnBError && err.code === "VALIDATION_ERROR") {
2294
+ return reply.code(400).send({ error: err.message });
2295
+ }
2296
+ throw err;
2297
+ }
2298
+ }
2299
+ return reply.code(201).send({ ok: true, id: card.id });
2300
+ });
2301
+ server.delete("/cards/:id", async (request, reply) => {
2302
+ const { id } = request.params;
2303
+ const card = getCard(db, id);
2304
+ if (!card) {
2305
+ return reply.code(404).send({ error: "Not found" });
2306
+ }
2307
+ db.prepare("DELETE FROM capability_cards WHERE id = ?").run(id);
2308
+ return reply.send({ ok: true, id });
2309
+ });
1823
2310
  server.get("/api/agents", async (_request, reply) => {
1824
2311
  const allCards = listCards(db);
1825
2312
  const ownerMap = /* @__PURE__ */ new Map();
@@ -1930,10 +2417,67 @@ function createRegistryServer(opts) {
1930
2417
  const exchangeRow = exchangeStmt.get();
1931
2418
  return reply.send({
1932
2419
  agents_online: onlineOwners.size,
1933
- total_capabilities: allCards.length,
2420
+ total_capabilities: allCards.reduce((sum, card) => {
2421
+ const v2 = card;
2422
+ return sum + (v2.skills?.length ?? 1);
2423
+ }, 0),
1934
2424
  total_exchanges: exchangeRow.count
1935
2425
  });
1936
2426
  });
2427
+ server.post("/api/identity/register", async (request, reply) => {
2428
+ if (!opts.creditDb) {
2429
+ return reply.code(503).send({ error: "Credit database not configured" });
2430
+ }
2431
+ const body = request.body;
2432
+ const githubLogin = typeof body.github_login === "string" ? body.github_login.trim() : "";
2433
+ if (!githubLogin) {
2434
+ return reply.code(400).send({ error: "github_login is required" });
2435
+ }
2436
+ try {
2437
+ const record = registerGuarantor(opts.creditDb, githubLogin);
2438
+ const auth = initiateGithubAuth();
2439
+ return reply.code(201).send({ guarantor: record, oauth: auth });
2440
+ } catch (err) {
2441
+ if (err instanceof AgentBnBError && err.code === "GUARANTOR_EXISTS") {
2442
+ return reply.code(409).send({ error: err.message });
2443
+ }
2444
+ throw err;
2445
+ }
2446
+ });
2447
+ server.post("/api/identity/link", async (request, reply) => {
2448
+ if (!opts.creditDb) {
2449
+ return reply.code(503).send({ error: "Credit database not configured" });
2450
+ }
2451
+ const body = request.body;
2452
+ const agentId = typeof body.agent_id === "string" ? body.agent_id.trim() : "";
2453
+ const githubLogin = typeof body.github_login === "string" ? body.github_login.trim() : "";
2454
+ if (!agentId || !githubLogin) {
2455
+ return reply.code(400).send({ error: "agent_id and github_login are required" });
2456
+ }
2457
+ try {
2458
+ const record = linkAgentToGuarantor(opts.creditDb, agentId, githubLogin);
2459
+ return reply.send({ guarantor: record });
2460
+ } catch (err) {
2461
+ if (err instanceof AgentBnBError) {
2462
+ const statusMap = {
2463
+ GUARANTOR_NOT_FOUND: 404,
2464
+ MAX_AGENTS_EXCEEDED: 409,
2465
+ AGENT_ALREADY_LINKED: 409
2466
+ };
2467
+ const status = statusMap[err.code] ?? 400;
2468
+ return reply.code(status).send({ error: err.message });
2469
+ }
2470
+ throw err;
2471
+ }
2472
+ });
2473
+ server.get("/api/identity/:agent_id", async (request, reply) => {
2474
+ if (!opts.creditDb) {
2475
+ return reply.code(503).send({ error: "Credit database not configured" });
2476
+ }
2477
+ const { agent_id } = request.params;
2478
+ const guarantor = getAgentGuarantor(opts.creditDb, agent_id);
2479
+ return reply.send({ agent_id, guarantor });
2480
+ });
1937
2481
  if (opts.ownerApiKey && opts.ownerName) {
1938
2482
  const ownerApiKey = opts.ownerApiKey;
1939
2483
  const ownerName = opts.ownerName;
@@ -2114,10 +2658,10 @@ async function stopAnnouncement() {
2114
2658
  }
2115
2659
 
2116
2660
  // src/openclaw/soul-sync.ts
2117
- import { randomUUID as randomUUID5 } from "crypto";
2661
+ import { randomUUID as randomUUID7 } from "crypto";
2118
2662
 
2119
2663
  // src/skills/publish-capability.ts
2120
- import { randomUUID as randomUUID4 } from "crypto";
2664
+ import { randomUUID as randomUUID6 } from "crypto";
2121
2665
  function parseSoulMd(content) {
2122
2666
  const lines = content.split("\n");
2123
2667
  let name = "";
@@ -2188,7 +2732,7 @@ function parseSoulMdV2(content) {
2188
2732
  const parsed = parseSoulMd(content);
2189
2733
  const skills = parsed.capabilities.map((cap) => {
2190
2734
  const sanitizedId = cap.name.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
2191
- const id = sanitizedId.length > 0 ? sanitizedId : randomUUID5();
2735
+ const id = sanitizedId.length > 0 ? sanitizedId : randomUUID7();
2192
2736
  return {
2193
2737
  id,
2194
2738
  name: cap.name,
@@ -2230,7 +2774,7 @@ function publishFromSoulV2(db, soulContent, owner) {
2230
2774
  (c) => c.spec_version === "2.0"
2231
2775
  );
2232
2776
  const now = (/* @__PURE__ */ new Date()).toISOString();
2233
- const cardId = existingV2?.id ?? randomUUID5();
2777
+ const cardId = existingV2?.id ?? randomUUID7();
2234
2778
  const card = {
2235
2779
  spec_version: "2.0",
2236
2780
  id: cardId,
@@ -2255,7 +2799,7 @@ function publishFromSoulV2(db, soulContent, owner) {
2255
2799
  }
2256
2800
 
2257
2801
  // src/openclaw/heartbeat-writer.ts
2258
- import { readFileSync as readFileSync2, writeFileSync, existsSync as existsSync3 } from "fs";
2802
+ import { readFileSync as readFileSync4, writeFileSync as writeFileSync2, existsSync as existsSync5 } from "fs";
2259
2803
  var HEARTBEAT_MARKER_START = "<!-- agentbnb:start -->";
2260
2804
  var HEARTBEAT_MARKER_END = "<!-- agentbnb:end -->";
2261
2805
  function generateHeartbeatSection(autonomy, budget) {
@@ -2291,11 +2835,11 @@ function generateHeartbeatSection(autonomy, budget) {
2291
2835
  ].join("\n");
2292
2836
  }
2293
2837
  function injectHeartbeatSection(heartbeatPath, section) {
2294
- if (!existsSync3(heartbeatPath)) {
2295
- writeFileSync(heartbeatPath, section + "\n", "utf-8");
2838
+ if (!existsSync5(heartbeatPath)) {
2839
+ writeFileSync2(heartbeatPath, section + "\n", "utf-8");
2296
2840
  return;
2297
2841
  }
2298
- let content = readFileSync2(heartbeatPath, "utf-8");
2842
+ let content = readFileSync4(heartbeatPath, "utf-8");
2299
2843
  const startIdx = content.indexOf(HEARTBEAT_MARKER_START);
2300
2844
  const endIdx = content.indexOf(HEARTBEAT_MARKER_END);
2301
2845
  if (startIdx !== -1 && endIdx !== -1) {
@@ -2303,7 +2847,7 @@ function injectHeartbeatSection(heartbeatPath, section) {
2303
2847
  } else {
2304
2848
  content = content + "\n" + section + "\n";
2305
2849
  }
2306
- writeFileSync(heartbeatPath, content, "utf-8");
2850
+ writeFileSync2(heartbeatPath, content, "utf-8");
2307
2851
  }
2308
2852
 
2309
2853
  // src/openclaw/skill.ts
@@ -2344,7 +2888,7 @@ function getOpenClawStatus(config, db, creditDb) {
2344
2888
  var require2 = createRequire(import.meta.url);
2345
2889
  var pkg = require2("../../package.json");
2346
2890
  async function confirm(question) {
2347
- const rl = createInterface({ input: process.stdin, output: process.stdout });
2891
+ const rl = createInterface2({ input: process.stdin, output: process.stdout });
2348
2892
  try {
2349
2893
  return await new Promise((resolve) => {
2350
2894
  rl.question(question, (answer) => {
@@ -2366,12 +2910,12 @@ function getLanIp() {
2366
2910
  }
2367
2911
  var program = new Command();
2368
2912
  program.name("agentbnb").description("P2P Agent Capability Sharing Protocol \u2014 Airbnb for AI agent pipelines").version(pkg.version);
2369
- program.command("init").description("Initialize AgentBnB config and create agent identity").option("--owner <name>", "Agent owner name").option("--port <port>", "Gateway port", "7700").option("--host <ip>", "Override gateway host IP (default: auto-detected LAN IP)").option("--yes", "Auto-confirm all draft cards (non-interactive)").option("--no-detect", "Skip API key detection").option("--json", "Output as JSON").action(async (opts) => {
2913
+ program.command("init").description("Initialize AgentBnB config and create agent identity").option("--owner <name>", "Agent owner name").option("--port <port>", "Gateway port", "7700").option("--host <ip>", "Override gateway host IP (default: auto-detected LAN IP)").option("--yes", "Auto-confirm all draft cards (non-interactive)").option("--no-detect", "Skip API key detection").option("--from <file>", "Parse a specific file for capability detection").option("--json", "Output as JSON").action(async (opts) => {
2370
2914
  const owner = opts.owner ?? `agent-${randomBytes(4).toString("hex")}`;
2371
2915
  const token = randomBytes(32).toString("hex");
2372
2916
  const configDir = getConfigDir();
2373
- const dbPath = join2(configDir, "registry.db");
2374
- const creditDbPath = join2(configDir, "credit.db");
2917
+ const dbPath = join4(configDir, "registry.db");
2918
+ const creditDbPath = join4(configDir, "credit.db");
2375
2919
  const port = parseInt(opts.port, 10);
2376
2920
  const ip = opts.host ?? getLanIp();
2377
2921
  const existingConfig = loadConfig();
@@ -2394,23 +2938,86 @@ program.command("init").description("Initialize AgentBnB config and create agent
2394
2938
  saveKeyPair(configDir, keys);
2395
2939
  keypairStatus = "generated";
2396
2940
  }
2941
+ const identity = ensureIdentity(configDir, owner);
2397
2942
  const creditDb = openCreditDb(creditDbPath);
2398
2943
  bootstrapAgent(creditDb, owner, 100);
2399
2944
  creditDb.close();
2400
2945
  const skipDetect = opts.detect === false;
2401
- let detectedKeys = [];
2402
- let detectedPorts = [];
2403
2946
  const publishedCards = [];
2947
+ let detectedSource = "none";
2404
2948
  if (!skipDetect) {
2405
- detectedKeys = detectApiKeys(KNOWN_API_KEYS);
2406
- detectedPorts = await detectOpenPorts([7700, 7701, 8080, 3e3, 8e3, 11434]);
2407
- if (detectedKeys.length > 0) {
2949
+ if (!opts.json) {
2950
+ console.log("\nDetecting capabilities...");
2951
+ }
2952
+ const result = detectCapabilities({ fromFile: opts.from, cwd: process.cwd() });
2953
+ detectedSource = result.source;
2954
+ if (result.source === "soul") {
2955
+ if (!opts.json) {
2956
+ console.log(` Found SOUL.md \u2014 extracting capabilities...`);
2957
+ }
2958
+ const db = openDatabase(dbPath);
2959
+ try {
2960
+ const card = publishFromSoulV2(db, result.soulContent, owner);
2961
+ publishedCards.push({ id: card.id, name: card.agent_name });
2962
+ if (!opts.json) {
2963
+ console.log(` Published v2.0 card: ${card.agent_name} (${card.skills.length} skills)`);
2964
+ }
2965
+ } finally {
2966
+ db.close();
2967
+ }
2968
+ } else if (result.source === "docs") {
2969
+ if (!opts.json) {
2970
+ console.log(` Found ${result.sourceFile ?? "docs"} \u2014 detected ${result.capabilities.length} capabilities:`);
2971
+ for (const cap of result.capabilities) {
2972
+ console.log(` ${cap.name} (${cap.category}, cr ${cap.credits_per_call}/call)`);
2973
+ }
2974
+ }
2975
+ const card = capabilitiesToV2Card(result.capabilities, owner);
2976
+ if (opts.yes) {
2977
+ const db = openDatabase(dbPath);
2978
+ try {
2979
+ db.prepare(
2980
+ `INSERT OR REPLACE INTO capability_cards (id, owner, data, created_at, updated_at)
2981
+ VALUES (?, ?, ?, ?, ?)`
2982
+ ).run(card.id, card.owner, JSON.stringify(card), card.created_at, card.updated_at);
2983
+ publishedCards.push({ id: card.id, name: card.agent_name });
2984
+ if (!opts.json) {
2985
+ console.log(` Published v2.0 card: ${card.agent_name} (${card.skills.length} skills)`);
2986
+ }
2987
+ } finally {
2988
+ db.close();
2989
+ }
2990
+ } else if (process.stdout.isTTY) {
2991
+ const yes = await confirm(`
2992
+ Publish these ${card.skills.length} capabilities? [y/N] `);
2993
+ if (yes) {
2994
+ const db = openDatabase(dbPath);
2995
+ try {
2996
+ db.prepare(
2997
+ `INSERT OR REPLACE INTO capability_cards (id, owner, data, created_at, updated_at)
2998
+ VALUES (?, ?, ?, ?, ?)`
2999
+ ).run(card.id, card.owner, JSON.stringify(card), card.created_at, card.updated_at);
3000
+ publishedCards.push({ id: card.id, name: card.agent_name });
3001
+ console.log(` Published v2.0 card: ${card.agent_name} (${card.skills.length} skills)`);
3002
+ } finally {
3003
+ db.close();
3004
+ }
3005
+ } else {
3006
+ console.log(" Skipped publishing.");
3007
+ }
3008
+ } else {
3009
+ if (!opts.json) {
3010
+ console.log(" Non-interactive environment. Re-run with --yes to auto-publish.");
3011
+ }
3012
+ }
3013
+ } else if (result.source === "env") {
3014
+ const detectedKeys = result.envKeys ?? [];
2408
3015
  if (!opts.json) {
2409
- console.log(`
2410
- Detected ${detectedKeys.length} API key${detectedKeys.length > 1 ? "s" : ""}: ${detectedKeys.join(", ")}`);
3016
+ console.log(` Detected ${detectedKeys.length} API key${detectedKeys.length > 1 ? "s" : ""}: ${detectedKeys.join(", ")}`);
2411
3017
  }
3018
+ const detectedPorts = await detectOpenPorts([7700, 7701, 8080, 3e3, 8e3, 11434]);
2412
3019
  if (detectedPorts.length > 0 && !opts.json) {
2413
- console.log(`Found services on ports: ${detectedPorts.join(", ")}`);
3020
+ console.log(` Found services on ports: ${detectedPorts.join(", ")}`);
2414
3021
  }
2415
3022
  const drafts = detectedKeys.map((key) => buildDraftCard(key, owner)).filter((card) => card !== null);
2416
3023
  if (opts.yes) {
@@ -2420,7 +3027,7 @@ Detected ${detectedKeys.length} API key${detectedKeys.length > 1 ? "s" : ""}: ${
2420
3027
  insertCard(db, card);
2421
3028
  publishedCards.push({ id: card.id, name: card.name });
2422
3029
  if (!opts.json) {
2423
- console.log(`Published: ${card.name} (${card.id})`);
3030
+ console.log(` Published: ${card.name} (${card.id})`);
2424
3031
  }
2425
3032
  }
2426
3033
  } finally {
@@ -2434,9 +3041,9 @@ Detected ${detectedKeys.length} API key${detectedKeys.length > 1 ? "s" : ""}: ${
2434
3041
  if (yes) {
2435
3042
  insertCard(db, card);
2436
3043
  publishedCards.push({ id: card.id, name: card.name });
2437
- console.log(`Published: ${card.name} (${card.id})`);
3044
+ console.log(` Published: ${card.name} (${card.id})`);
2438
3045
  } else {
2439
- console.log(`Skipped: ${card.name}`);
3046
+ console.log(` Skipped: ${card.name}`);
2440
3047
  }
2441
3048
  }
2442
3049
  } finally {
@@ -2444,12 +3051,29 @@ Detected ${detectedKeys.length} API key${detectedKeys.length > 1 ? "s" : ""}: ${
2444
3051
  }
2445
3052
  } else {
2446
3053
  if (!opts.json) {
2447
- console.log("Non-interactive environment detected. Re-run with --yes to auto-publish draft cards.");
3054
+ console.log(" Non-interactive environment. Re-run with --yes to auto-publish.");
2448
3055
  }
2449
3056
  }
2450
3057
  } else {
2451
- if (!opts.json) {
2452
- console.log("\nNo API keys detected. You can manually publish cards with `agentbnb publish`.");
3058
+ if (process.stdout.isTTY && !opts.yes && !opts.json) {
3059
+ const selected = await interactiveTemplateMenu();
3060
+ if (selected.length > 0) {
3061
+ const card = capabilitiesToV2Card(selected, owner);
3062
+ const db = openDatabase(dbPath);
3063
+ try {
3064
+ db.prepare(
3065
+ `INSERT OR REPLACE INTO capability_cards (id, owner, data, created_at, updated_at)
3066
+ VALUES (?, ?, ?, ?, ?)`
3067
+ ).run(card.id, card.owner, JSON.stringify(card), card.created_at, card.updated_at);
3068
+ publishedCards.push({ id: card.id, name: card.agent_name });
3069
+ console.log(`
3070
+ Published v2.0 card: ${card.agent_name} (${card.skills.length} skills)`);
3071
+ } finally {
3072
+ db.close();
3073
+ }
3074
+ }
3075
+ } else if (!opts.json) {
3076
+ console.log(" No capabilities detected. You can manually publish with `agentbnb publish`.");
2453
3077
  }
2454
3078
  }
2455
3079
  }
@@ -2460,10 +3084,11 @@ Detected ${detectedKeys.length} API key${detectedKeys.length > 1 ? "s" : ""}: ${
2460
3084
  config_dir: configDir,
2461
3085
  token,
2462
3086
  gateway_url: config.gateway_url,
2463
- keypair: keypairStatus
3087
+ keypair: keypairStatus,
3088
+ agent_id: identity.agent_id
2464
3089
  };
2465
3090
  if (!skipDetect) {
2466
- jsonOutput.detected_keys = detectedKeys;
3091
+ jsonOutput.detected_source = detectedSource;
2467
3092
  jsonOutput.published_cards = publishedCards;
2468
3093
  }
2469
3094
  console.log(JSON.stringify(jsonOutput, null, 2));
@@ -2474,10 +3099,11 @@ Detected ${detectedKeys.length} API key${detectedKeys.length > 1 ? "s" : ""}: ${
2474
3099
  console.log(` Config: ${configDir}/config.json`);
2475
3100
  console.log(` Credits: 100 (starter grant)`);
2476
3101
  console.log(` Keypair: ${keypairStatus === "generated" ? "generated (Ed25519)" : "preserved (existing)"}`);
3102
+ console.log(` Agent ID: ${identity.agent_id}`);
2477
3103
  console.log(` Gateway: http://${ip}:${port}`);
2478
3104
  }
2479
3105
  });
2480
- program.command("publish <card.json>").description("Publish a Capability Card to the registry").option("--json", "Output as JSON").action(async (cardPath, opts) => {
3106
+ program.command("publish <card.json>").description("Publish a Capability Card to the registry (v1.0 or v2.0)").option("--json", "Output as JSON").option("--registry <url>", "POST card to a remote registry URL instead of local DB").action(async (cardPath, opts) => {
2481
3107
  const config = loadConfig();
2482
3108
  if (!config) {
2483
3109
  console.error("Error: not initialized. Run `agentbnb init` first.");
@@ -2485,7 +3111,7 @@ program.command("publish <card.json>").description("Publish a Capability Card to
2485
3111
  }
2486
3112
  let raw;
2487
3113
  try {
2488
- raw = readFileSync3(cardPath, "utf-8");
3114
+ raw = readFileSync5(cardPath, "utf-8");
2489
3115
  } catch {
2490
3116
  console.error(`Error: cannot read file: ${cardPath}`);
2491
3117
  process.exit(1);
@@ -2497,7 +3123,10 @@ program.command("publish <card.json>").description("Publish a Capability Card to
2497
3123
  console.error("Error: invalid JSON in card file.");
2498
3124
  process.exit(1);
2499
3125
  }
2500
- const result = CapabilityCardSchema.safeParse(parsed);
3126
+ if (typeof parsed === "object" && parsed !== null && !("spec_version" in parsed)) {
3127
+ parsed.spec_version = "1.0";
3128
+ }
3129
+ const result = AnyCardSchema.safeParse(parsed);
2501
3130
  if (!result.success) {
2502
3131
  if (opts.json) {
2503
3132
  console.log(JSON.stringify({ success: false, errors: result.error.issues }, null, 2));
@@ -2509,16 +3138,56 @@ program.command("publish <card.json>").description("Publish a Capability Card to
2509
3138
  }
2510
3139
  process.exit(1);
2511
3140
  }
3141
+ const card = result.data;
3142
+ const cardName = card.spec_version === "2.0" ? card.agent_name : card.name;
2512
3143
  const db = openDatabase(config.db_path);
2513
3144
  try {
2514
- insertCard(db, result.data);
3145
+ if (card.spec_version === "2.0") {
3146
+ const now = (/* @__PURE__ */ new Date()).toISOString();
3147
+ const cardWithTimestamps = { ...card, created_at: card.created_at ?? now, updated_at: now };
3148
+ db.prepare(
3149
+ "INSERT OR REPLACE INTO capability_cards (id, owner, data, created_at, updated_at) VALUES (?, ?, ?, ?, ?)"
3150
+ ).run(cardWithTimestamps.id, cardWithTimestamps.owner, JSON.stringify(cardWithTimestamps), cardWithTimestamps.created_at, cardWithTimestamps.updated_at);
3151
+ } else {
3152
+ insertCard(db, card);
3153
+ }
2515
3154
  } finally {
2516
3155
  db.close();
2517
3156
  }
3157
+ if (!opts.json) {
3158
+ console.log(`Published locally: ${cardName} (${card.id})`);
3159
+ }
3160
+ const registryUrl = opts.registry ?? config.registry;
3161
+ let remoteSuccess = false;
3162
+ if (registryUrl) {
3163
+ const url = `${registryUrl.replace(/\/$/, "")}/cards`;
3164
+ try {
3165
+ const response = await fetch(url, {
3166
+ method: "POST",
3167
+ headers: { "Content-Type": "application/json" },
3168
+ body: JSON.stringify(card)
3169
+ });
3170
+ if (!response.ok) {
3171
+ const body = await response.text();
3172
+ console.error(`Warning: remote registry returned ${response.status}: ${body}`);
3173
+ } else {
3174
+ remoteSuccess = true;
3175
+ if (!opts.json) {
3176
+ console.log(`Published to registry: ${url}`);
3177
+ }
3178
+ }
3179
+ } catch (err) {
3180
+ console.error(`Warning: cannot reach registry at ${url}: ${err.message}`);
3181
+ }
3182
+ }
2518
3183
  if (opts.json) {
2519
- console.log(JSON.stringify({ success: true, id: result.data.id, name: result.data.name }, null, 2));
2520
- } else {
2521
- console.log(`Published: ${result.data.name} (${result.data.id})`);
3184
+ console.log(JSON.stringify({
3185
+ success: true,
3186
+ id: card.id,
3187
+ name: cardName,
3188
+ ...registryUrl ? { registry: registryUrl, remote_published: remoteSuccess } : {}
3189
+ }, null, 2));
3190
+ } else if (!registryUrl) {
2522
3191
  }
2523
3192
  });
2524
3193
  program.command("discover [query]").description("Search available capabilities in the registry").option("--level <level>", "Filter by level (1, 2, or 3)").option("--online", "Only show online capabilities").option("--local", "Browse for agents on the local network via mDNS").option("--registry <url>", "Remote registry URL to query (e.g., http://host:7701)").option("--tag <tag>", "Filter by metadata tag").option("--json", "Output as JSON").action(async (query, opts) => {
@@ -2537,7 +3206,7 @@ program.command("discover [query]").description("Search available capabilities i
2537
3206
  console.log("No agents found on local network.");
2538
3207
  return;
2539
3208
  }
2540
- const col2 = (s, w) => s.slice(0, w).padEnd(w);
3209
+ const col2 = (s, w) => (s ?? "").slice(0, w).padEnd(w);
2541
3210
  console.log(col2("Name", 24) + " " + col2("URL", 32) + " " + col2("Owner", 20));
2542
3211
  console.log("-".repeat(80));
2543
3212
  for (const agent of discovered) {
@@ -2607,7 +3276,7 @@ ${discovered.length} agent(s) found on local network`);
2607
3276
  console.log("No capabilities found.");
2608
3277
  return;
2609
3278
  }
2610
- const col = (s, w) => s.slice(0, w).padEnd(w);
3279
+ const col = (s, w) => (s ?? "").slice(0, w).padEnd(w);
2611
3280
  if (hasRemote) {
2612
3281
  console.log(
2613
3282
  col("ID", 16) + " " + col("Name", 28) + " " + col("Lvl", 3) + " " + col("Credits", 7) + " " + col("Online", 6) + " " + col("Source", 8)
@@ -2615,10 +3284,11 @@ ${discovered.length} agent(s) found on local network`);
2615
3284
  console.log("-".repeat(80));
2616
3285
  for (const card of outputCards) {
2617
3286
  const shortId = card.id.slice(0, 8) + "...";
3287
+ const displayName = card.name ?? card.agent_name ?? "";
2618
3288
  const source = "source" in card ? card.source : "local";
2619
3289
  const sourceTag = source === "remote" ? "[remote]" : "[local]";
2620
3290
  console.log(
2621
- col(shortId, 16) + " " + col(card.name, 28) + " " + col(String(card.level), 3) + " " + col(String(card.pricing.credits_per_call), 7) + " " + col(card.availability.online ? "yes" : "no", 6) + " " + col(sourceTag, 8)
3291
+ col(shortId, 16) + " " + col(displayName, 28) + " " + col(String(card.level ?? ""), 3) + " " + col(String(card.pricing?.credits_per_call ?? ""), 7) + " " + col(card.availability?.online ? "yes" : "no", 6) + " " + col(sourceTag, 8)
2622
3292
  );
2623
3293
  }
2624
3294
  } else {
@@ -2628,8 +3298,9 @@ ${discovered.length} agent(s) found on local network`);
2628
3298
  console.log("-".repeat(72));
2629
3299
  for (const card of outputCards) {
2630
3300
  const shortId = card.id.slice(0, 8) + "...";
3301
+ const displayName = card.name ?? card.agent_name ?? "";
2631
3302
  console.log(
2632
- col(shortId, 16) + " " + col(card.name, 32) + " " + col(String(card.level), 3) + " " + col(String(card.pricing.credits_per_call), 7) + " " + col(card.availability.online ? "yes" : "no", 6)
3303
+ col(shortId, 16) + " " + col(displayName, 32) + " " + col(String(card.level ?? ""), 3) + " " + col(String(card.pricing?.credits_per_call ?? ""), 7) + " " + col(card.availability?.online ? "yes" : "no", 6)
2633
3304
  );
2634
3305
  }
2635
3306
  }
@@ -2652,8 +3323,8 @@ program.command("request [card-id]").description("Request a capability from anot
2652
3323
  process.exit(1);
2653
3324
  }
2654
3325
  }
2655
- const registryDb = openDatabase(join2(getConfigDir(), "registry.db"));
2656
- const creditDb = openCreditDb(join2(getConfigDir(), "credit.db"));
3326
+ const registryDb = openDatabase(join4(getConfigDir(), "registry.db"));
3327
+ const creditDb = openCreditDb(join4(getConfigDir(), "credit.db"));
2657
3328
  registryDb.pragma("busy_timeout = 5000");
2658
3329
  creditDb.pragma("busy_timeout = 5000");
2659
3330
  try {
@@ -2712,7 +3383,7 @@ program.command("request [card-id]").description("Request a capability from anot
2712
3383
  let escrowReceipt;
2713
3384
  if (useReceipt) {
2714
3385
  const configDir = getConfigDir();
2715
- const creditDb = openCreditDb(join2(configDir, "credit.db"));
3386
+ const creditDb = openCreditDb(join4(configDir, "credit.db"));
2716
3387
  creditDb.pragma("busy_timeout = 5000");
2717
3388
  try {
2718
3389
  const keys = loadKeyPair(configDir);
@@ -2753,7 +3424,7 @@ program.command("request [card-id]").description("Request a capability from anot
2753
3424
  });
2754
3425
  if (useReceipt && escrowId) {
2755
3426
  const configDir = getConfigDir();
2756
- const creditDb = openCreditDb(join2(configDir, "credit.db"));
3427
+ const creditDb = openCreditDb(join4(configDir, "credit.db"));
2757
3428
  creditDb.pragma("busy_timeout = 5000");
2758
3429
  try {
2759
3430
  settleRequesterEscrow(creditDb, escrowId);
@@ -2773,7 +3444,7 @@ program.command("request [card-id]").description("Request a capability from anot
2773
3444
  } catch (err) {
2774
3445
  if (useReceipt && escrowId) {
2775
3446
  const configDir = getConfigDir();
2776
- const creditDb = openCreditDb(join2(configDir, "credit.db"));
3447
+ const creditDb = openCreditDb(join4(configDir, "credit.db"));
2777
3448
  creditDb.pragma("busy_timeout = 5000");
2778
3449
  try {
2779
3450
  releaseRequesterEscrow(creditDb, escrowId);
@@ -2841,7 +3512,7 @@ program.command("serve").description("Start the AgentBnB gateway server").option
2841
3512
  }
2842
3513
  const port = opts.port ? parseInt(opts.port, 10) : config.gateway_port;
2843
3514
  const registryPort = parseInt(opts.registryPort, 10);
2844
- const skillsYamlPath = opts.skillsYaml ?? join2(homedir(), ".agentbnb", "skills.yaml");
3515
+ const skillsYamlPath = opts.skillsYaml ?? join4(homedir(), ".agentbnb", "skills.yaml");
2845
3516
  const runtime = new AgentRuntime({
2846
3517
  registryDbPath: config.db_path,
2847
3518
  creditDbPath: config.credit_db_path,
@@ -2920,7 +3591,7 @@ program.command("serve").description("Start the AgentBnB gateway server").option
2920
3591
  }
2921
3592
  if (opts.registry) {
2922
3593
  const { RelayClient } = await import("../websocket-client-5TIQDYQ4.js");
2923
- const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../execute-3T5RF3DP.js");
3594
+ const { executeCapabilityRequest: executeCapabilityRequest2 } = await import("../execute-NZXTSSVV.js");
2924
3595
  const cards = listCards(runtime.registryDb, config.owner);
2925
3596
  const card = cards[0] ?? {
2926
3597
  id: config.owner,
@@ -3004,7 +3675,7 @@ peersCommand.option("--json", "Output as JSON").action(async (opts) => {
3004
3675
  console.log("No peers registered. Use `agentbnb connect` to add one.");
3005
3676
  return;
3006
3677
  }
3007
- const col = (s, w) => s.slice(0, w).padEnd(w);
3678
+ const col = (s, w) => (s ?? "").slice(0, w).padEnd(w);
3008
3679
  console.log(col("Name", 20) + " " + col("URL", 36) + " " + col("Added", 20));
3009
3680
  console.log("-".repeat(80));
3010
3681
  for (const peer of peers) {
@@ -3128,7 +3799,7 @@ openclaw.command("sync").description("Read SOUL.md and publish/update a v2.0 cap
3128
3799
  }
3129
3800
  let content;
3130
3801
  try {
3131
- content = readFileSync3(opts.soulPath, "utf-8");
3802
+ content = readFileSync5(opts.soulPath, "utf-8");
3132
3803
  } catch {
3133
3804
  console.error(`Error: cannot read SOUL.md at ${opts.soulPath}`);
3134
3805
  process.exit(1);
@@ -3189,7 +3860,7 @@ openclaw.command("rules").description("Print HEARTBEAT.md rules block (or inject
3189
3860
  }
3190
3861
  });
3191
3862
  program.command("conduct <task>").description("Orchestrate a complex task across the AgentBnB network").option("--plan-only", "Show execution plan without executing").option("--max-budget <credits>", "Maximum credits to spend", "100").option("--json", "Output as JSON").action(async (task, opts) => {
3192
- const { conductAction } = await import("../conduct-M57F72RK.js");
3863
+ const { conductAction } = await import("../conduct-5T3LGXMF.js");
3193
3864
  const result = await conductAction(task, opts);
3194
3865
  if (opts.json) {
3195
3866
  console.log(JSON.stringify(result, null, 2));