agentbnb 6.0.0 → 7.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +245 -39
- package/dist/{card-REW7BSWW.js → card-EX2EYGCZ.js} +1 -1
- package/dist/{chunk-C6KPAFCC.js → chunk-3LWBH7P3.js} +94 -3
- package/dist/{chunk-YRRVFTDR.js → chunk-5AAFG2V2.js} +3 -3
- package/dist/{chunk-C2T4BMRW.js → chunk-5GME4KJZ.js} +8 -6
- package/dist/{chunk-VPQ44XKE.js → chunk-64AK4FJM.js} +2 -2
- package/dist/{chunk-2TLZ6G2B.js → chunk-7EF3HYVZ.js} +158 -18
- package/dist/{chunk-JR6TJDIF.js → chunk-ALX4WS3A.js} +9 -4
- package/dist/{chunk-7XHDSWRD.js → chunk-B2VJTKO5.js} +2 -2
- package/dist/{chunk-TR6UZDNX.js → chunk-C537SFHV.js} +8 -6
- package/dist/{chunk-F53QQIM2.js → chunk-CUONY5TO.js} +1 -1
- package/dist/chunk-D6RKW2XG.js +395 -0
- package/dist/{chunk-NYV3NE5Z.js → chunk-E2OKP5CY.js} +4 -4
- package/dist/{chunk-TQDV254A.js → chunk-FTZTEHYG.js} +117 -117
- package/dist/{chunk-Y7T6IMM3.js → chunk-GKVTD4EZ.js} +1 -1
- package/dist/{chunk-VMH2YS2I.js → chunk-KF3TZHA5.js} +1 -1
- package/dist/{chunk-574W3HHE.js → chunk-LJM7FHPM.js} +1 -1
- package/dist/chunk-NWIQJ2CL.js +108 -0
- package/dist/{chunk-KA2VIEGM.js → chunk-O2OYBAVR.js} +1 -1
- package/dist/{chunk-NQTE577Q.js → chunk-OCSU2S6W.js} +9 -0
- package/dist/{chunk-PSQHUZ7X.js → chunk-OH7BP5NP.js} +1 -1
- package/dist/chunk-SSK653A6.js +169 -0
- package/dist/{chunk-BP3L2TET.js → chunk-TBJ3FZKZ.js} +2 -2
- package/dist/{chunk-3CIMVISQ.js → chunk-WVY2W7AA.js} +4 -0
- package/dist/{chunk-OZXCRLP3.js → chunk-X32NE6V4.js} +5 -2
- package/dist/{chunk-7YLFLC5C.js → chunk-YHY7OG6S.js} +5 -5
- package/dist/{chunk-JOY533UH.js → chunk-Z4MCGKTL.js} +6 -2
- package/dist/cli/index.js +530 -269
- package/dist/{client-HRYRJKSA.js → client-HKV3QWZ3.js} +3 -3
- package/dist/{conduct-LF6FYPLD.js → conduct-W6XF6DJW.js} +14 -13
- package/dist/conduct-YB64OHI6.js +22 -0
- package/dist/{conductor-mode-NUDQLZFM.js → conductor-mode-2GSLHVN6.js} +7 -4
- package/dist/{conductor-mode-YQ6QSPPT.js → conductor-mode-AKREGDIU.js} +11 -10
- package/dist/execute-AYQWORVH.js +15 -0
- package/dist/{execute-ITHIYYOX.js → execute-EPE6MZLT.js} +4 -3
- package/dist/index.d.ts +502 -12
- package/dist/index.js +706 -53
- package/dist/{process-guard-QCCBGILS.js → process-guard-GH5LRNWO.js} +1 -1
- package/dist/{publish-capability-TS6CNR5G.js → publish-capability-AH2HDW54.js} +3 -3
- package/dist/reliability-metrics-QG7WC5QK.js +18 -0
- package/dist/{request-P6QCTCCG.js → request-HCCXSKAY.js} +15 -14
- package/dist/{serve-skill-EZOL7UYN.js → serve-skill-SZAQT5T5.js} +9 -8
- package/dist/{server-3G6ZTASA.js → server-MHMAYXWZ.js} +12 -11
- package/dist/{service-coordinator-CRSE4GWC.js → service-coordinator-WGH6B2VT.js} +572 -68
- package/dist/{skill-config-4W5W5O6T.js → skill-config-FETXPNVP.js} +1 -1
- package/dist/skills/agentbnb/bootstrap.js +594 -73
- package/dist/{websocket-client-WRN3HO73.js → websocket-client-4Z5P54RU.js} +1 -1
- package/dist/websocket-client-QOVARTRN.js +7 -0
- package/openclaw.plugin.json +2 -2
- package/package.json +18 -11
- package/skills/agentbnb/bootstrap.test.ts +9 -0
- package/skills/agentbnb/bootstrap.ts +51 -26
- package/skills/agentbnb/install.sh +0 -0
- package/dist/chunk-QT7TEVNV.js +0 -82
- package/dist/chunk-RVYQSC6L.js +0 -212
- package/dist/conduct-QAFZIEY6.js +0 -21
- package/dist/execute-PNJFABVJ.js +0 -14
- package/dist/websocket-client-6IIDGXKB.js +0 -7
package/dist/cli/index.js
CHANGED
|
@@ -6,53 +6,57 @@ import {
|
|
|
6
6
|
detectOpenPorts,
|
|
7
7
|
discoverLocalAgents,
|
|
8
8
|
getPricingStats
|
|
9
|
-
} from "../chunk-
|
|
9
|
+
} from "../chunk-FTZTEHYG.js";
|
|
10
10
|
import {
|
|
11
11
|
ensureIdentity
|
|
12
|
-
} from "../chunk-
|
|
13
|
-
import {
|
|
14
|
-
createLedger
|
|
15
|
-
} from "../chunk-YRRVFTDR.js";
|
|
12
|
+
} from "../chunk-OH7BP5NP.js";
|
|
16
13
|
import {
|
|
17
14
|
releaseRequesterEscrow,
|
|
18
15
|
settleRequesterEscrow
|
|
19
|
-
} from "../chunk-
|
|
16
|
+
} from "../chunk-X32NE6V4.js";
|
|
17
|
+
import {
|
|
18
|
+
createLedger
|
|
19
|
+
} from "../chunk-5AAFG2V2.js";
|
|
20
20
|
import {
|
|
21
21
|
parseSoulMd
|
|
22
|
-
} from "../chunk-
|
|
22
|
+
} from "../chunk-TBJ3FZKZ.js";
|
|
23
23
|
import {
|
|
24
24
|
AutoRequestor,
|
|
25
25
|
BudgetManager,
|
|
26
26
|
DEFAULT_BUDGET_CONFIG
|
|
27
|
-
} from "../chunk-
|
|
27
|
+
} from "../chunk-5GME4KJZ.js";
|
|
28
28
|
import {
|
|
29
29
|
fetchRemoteCards,
|
|
30
30
|
mergeResults
|
|
31
|
-
} from "../chunk-
|
|
31
|
+
} from "../chunk-KF3TZHA5.js";
|
|
32
32
|
import {
|
|
33
33
|
DEFAULT_AUTONOMY_CONFIG
|
|
34
|
-
} from "../chunk-
|
|
34
|
+
} from "../chunk-GKVTD4EZ.js";
|
|
35
35
|
import {
|
|
36
36
|
filterCards,
|
|
37
37
|
searchCards
|
|
38
|
-
} from "../chunk-
|
|
38
|
+
} from "../chunk-LJM7FHPM.js";
|
|
39
39
|
import {
|
|
40
40
|
bootstrapAgent,
|
|
41
|
+
createAgentRecord,
|
|
41
42
|
getBalance,
|
|
42
43
|
getTransactions,
|
|
43
44
|
holdEscrow,
|
|
45
|
+
lookupAgent,
|
|
46
|
+
lookupAgentByOwner,
|
|
44
47
|
migrateOwner,
|
|
45
48
|
openCreditDb
|
|
46
|
-
} from "../chunk-
|
|
49
|
+
} from "../chunk-D6RKW2XG.js";
|
|
50
|
+
import "../chunk-NWIQJ2CL.js";
|
|
47
51
|
import {
|
|
48
52
|
requestCapability
|
|
49
|
-
} from "../chunk-
|
|
53
|
+
} from "../chunk-64AK4FJM.js";
|
|
50
54
|
import {
|
|
51
55
|
generateKeyPair,
|
|
52
56
|
loadKeyPair,
|
|
53
57
|
saveKeyPair,
|
|
54
58
|
signEscrowReceipt
|
|
55
|
-
} from "../chunk-
|
|
59
|
+
} from "../chunk-CUONY5TO.js";
|
|
56
60
|
import {
|
|
57
61
|
findPeer,
|
|
58
62
|
loadPeers,
|
|
@@ -70,27 +74,28 @@ import {
|
|
|
70
74
|
insertCard,
|
|
71
75
|
listCards,
|
|
72
76
|
openDatabase
|
|
73
|
-
} from "../chunk-
|
|
77
|
+
} from "../chunk-O2OYBAVR.js";
|
|
74
78
|
import {
|
|
75
79
|
AgentBnBError,
|
|
76
80
|
AnyCardSchema,
|
|
77
81
|
CapabilityCardV2Schema
|
|
78
|
-
} from "../chunk-
|
|
82
|
+
} from "../chunk-WVY2W7AA.js";
|
|
79
83
|
|
|
80
84
|
// src/cli/index.ts
|
|
81
85
|
import { Command } from "commander";
|
|
82
|
-
import { readFileSync as
|
|
86
|
+
import { readFileSync as readFileSync4 } from "fs";
|
|
83
87
|
import { createRequire } from "module";
|
|
84
|
-
import {
|
|
85
|
-
import { join as
|
|
86
|
-
import { networkInterfaces } from "os";
|
|
87
|
-
import { createInterface as
|
|
88
|
+
import { randomUUID as randomUUID4 } from "crypto";
|
|
89
|
+
import { join as join4 } from "path";
|
|
90
|
+
import { networkInterfaces as networkInterfaces2 } from "os";
|
|
91
|
+
import { createInterface as createInterface3 } from "readline";
|
|
88
92
|
|
|
89
93
|
// src/credit/escrow-receipt.ts
|
|
90
94
|
import { z } from "zod";
|
|
91
95
|
import { randomUUID } from "crypto";
|
|
92
96
|
var EscrowReceiptSchema = z.object({
|
|
93
97
|
requester_owner: z.string().min(1),
|
|
98
|
+
requester_agent_id: z.string().optional(),
|
|
94
99
|
requester_public_key: z.string().min(1),
|
|
95
100
|
amount: z.number().positive(),
|
|
96
101
|
card_id: z.string().min(1),
|
|
@@ -103,6 +108,7 @@ function createSignedEscrowReceipt(db, privateKey, publicKey, opts) {
|
|
|
103
108
|
const escrowId = holdEscrow(db, opts.owner, opts.amount, opts.cardId);
|
|
104
109
|
const receiptData = {
|
|
105
110
|
requester_owner: opts.owner,
|
|
111
|
+
...opts.agent_id ? { requester_agent_id: opts.agent_id } : {},
|
|
106
112
|
requester_public_key: publicKey.toString("hex"),
|
|
107
113
|
amount: opts.amount,
|
|
108
114
|
card_id: opts.cardId,
|
|
@@ -118,183 +124,8 @@ function createSignedEscrowReceipt(db, privateKey, publicKey, opts) {
|
|
|
118
124
|
return { escrowId, receipt };
|
|
119
125
|
}
|
|
120
126
|
|
|
121
|
-
// src/onboarding/index.ts
|
|
122
|
-
import { randomUUID as randomUUID2 } from "crypto";
|
|
123
|
-
import { existsSync, readFileSync } from "fs";
|
|
124
|
-
import { join } from "path";
|
|
125
|
-
|
|
126
|
-
// src/onboarding/capability-templates.ts
|
|
127
|
-
var API_PATTERNS = [
|
|
128
|
-
{
|
|
129
|
-
pattern: /openai|gpt-4|gpt-3|chatgpt|dall-e/i,
|
|
130
|
-
capability: { key: "openai", name: "OpenAI Text Generation", category: "Text Gen", credits_per_call: 3, tags: ["llm", "text", "generation"] }
|
|
131
|
-
},
|
|
132
|
-
{
|
|
133
|
-
pattern: /elevenlabs|eleven.?labs/i,
|
|
134
|
-
capability: { key: "elevenlabs", name: "ElevenLabs TTS", category: "TTS", credits_per_call: 5, tags: ["tts", "audio", "voice"] }
|
|
135
|
-
},
|
|
136
|
-
{
|
|
137
|
-
pattern: /anthropic|claude/i,
|
|
138
|
-
capability: { key: "anthropic", name: "Anthropic Claude", category: "Text Gen", credits_per_call: 3, tags: ["llm", "text", "generation"] }
|
|
139
|
-
},
|
|
140
|
-
{
|
|
141
|
-
pattern: /recraft/i,
|
|
142
|
-
capability: { key: "recraft", name: "Recraft V4 Image Gen", category: "Image Gen", credits_per_call: 8, tags: ["image", "generation", "design"] }
|
|
143
|
-
},
|
|
144
|
-
{
|
|
145
|
-
pattern: /kling/i,
|
|
146
|
-
capability: { key: "kling", name: "Kling AI Video Gen", category: "Video Gen", credits_per_call: 10, tags: ["video", "generation"] }
|
|
147
|
-
},
|
|
148
|
-
{
|
|
149
|
-
pattern: /stable.?diffusion|sdxl|comfyui/i,
|
|
150
|
-
capability: { key: "stable-diffusion", name: "Stable Diffusion Image Gen", category: "Image Gen", credits_per_call: 6, tags: ["image", "generation", "diffusion"] }
|
|
151
|
-
},
|
|
152
|
-
{
|
|
153
|
-
pattern: /whisper|speech.?to.?text|stt/i,
|
|
154
|
-
capability: { key: "whisper", name: "Whisper Speech-to-Text", category: "STT", credits_per_call: 3, tags: ["stt", "audio", "transcription"] }
|
|
155
|
-
},
|
|
156
|
-
{
|
|
157
|
-
pattern: /puppeteer|playwright|selenium/i,
|
|
158
|
-
capability: { key: "puppeteer", name: "Web Scraping & Automation", category: "Web Scraping", credits_per_call: 2, tags: ["scraping", "automation", "browser"] }
|
|
159
|
-
},
|
|
160
|
-
{
|
|
161
|
-
pattern: /ffmpeg/i,
|
|
162
|
-
capability: { key: "ffmpeg", name: "FFmpeg Media Processing", category: "Media Processing", credits_per_call: 3, tags: ["media", "audio", "video", "processing"] }
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
pattern: /tesseract|ocr/i,
|
|
166
|
-
capability: { key: "tesseract", name: "OCR Text Extraction", category: "OCR", credits_per_call: 4, tags: ["ocr", "text", "extraction"] }
|
|
167
|
-
}
|
|
168
|
-
];
|
|
169
|
-
var INTERACTIVE_TEMPLATES = [
|
|
170
|
-
{ key: "openai", name: "Text Generation (GPT-4o / Claude / Gemini)", category: "Text Gen", credits_per_call: 3, tags: ["llm", "text", "generation"] },
|
|
171
|
-
{ key: "image-gen", name: "Image Generation (DALL-E / Recraft / Stable Diffusion)", category: "Image Gen", credits_per_call: 8, tags: ["image", "generation"] },
|
|
172
|
-
{ key: "tts", name: "TTS / Voice (ElevenLabs / Google TTS)", category: "TTS", credits_per_call: 5, tags: ["tts", "audio", "voice"] },
|
|
173
|
-
{ key: "video-gen", name: "Video Generation (Kling / Runway)", category: "Video Gen", credits_per_call: 10, tags: ["video", "generation"] },
|
|
174
|
-
{ key: "code-review", name: "Code Review / Analysis", category: "Code", credits_per_call: 3, tags: ["code", "review", "analysis"] },
|
|
175
|
-
{ key: "scraping", name: "Web Scraping / Data Extraction", category: "Web Scraping", credits_per_call: 2, tags: ["scraping", "data", "extraction"] },
|
|
176
|
-
{ key: "translation", name: "Translation", category: "Translation", credits_per_call: 3, tags: ["translation", "language", "text"] },
|
|
177
|
-
{ key: "custom", name: "Custom (describe it)", category: "Custom", credits_per_call: 5, tags: ["custom"] }
|
|
178
|
-
];
|
|
179
|
-
|
|
180
|
-
// src/onboarding/detect-from-docs.ts
|
|
181
|
-
function detectFromDocs(content) {
|
|
182
|
-
if (!content || content.trim().length === 0) {
|
|
183
|
-
return [];
|
|
184
|
-
}
|
|
185
|
-
const seen = /* @__PURE__ */ new Set();
|
|
186
|
-
const results = [];
|
|
187
|
-
for (const entry of API_PATTERNS) {
|
|
188
|
-
if (entry.pattern.test(content) && !seen.has(entry.capability.key)) {
|
|
189
|
-
seen.add(entry.capability.key);
|
|
190
|
-
results.push({ ...entry.capability });
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
return results;
|
|
194
|
-
}
|
|
195
|
-
|
|
196
|
-
// src/onboarding/interactive.ts
|
|
197
|
-
import { createInterface } from "readline";
|
|
198
|
-
async function interactiveTemplateMenu() {
|
|
199
|
-
console.log("\nNo capabilities auto-detected.\n");
|
|
200
|
-
console.log("What can your agent do? Pick from templates:\n");
|
|
201
|
-
for (let i = 0; i < INTERACTIVE_TEMPLATES.length; i++) {
|
|
202
|
-
console.log(` ${i + 1}. ${INTERACTIVE_TEMPLATES[i].name}`);
|
|
203
|
-
}
|
|
204
|
-
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
205
|
-
const answer = await new Promise((resolve) => {
|
|
206
|
-
rl.question("\nSelect [1-8, comma-separated]: ", (ans) => {
|
|
207
|
-
rl.close();
|
|
208
|
-
resolve(ans);
|
|
209
|
-
});
|
|
210
|
-
});
|
|
211
|
-
return parseSelection(answer);
|
|
212
|
-
}
|
|
213
|
-
function parseSelection(input) {
|
|
214
|
-
if (!input || input.trim().length === 0) {
|
|
215
|
-
return [];
|
|
216
|
-
}
|
|
217
|
-
const selected = [];
|
|
218
|
-
const seen = /* @__PURE__ */ new Set();
|
|
219
|
-
const parts = input.split(",").map((s) => s.trim());
|
|
220
|
-
for (const part of parts) {
|
|
221
|
-
const num = parseInt(part, 10);
|
|
222
|
-
if (isNaN(num) || num < 1 || num > INTERACTIVE_TEMPLATES.length) {
|
|
223
|
-
continue;
|
|
224
|
-
}
|
|
225
|
-
const template = INTERACTIVE_TEMPLATES[num - 1];
|
|
226
|
-
if (!seen.has(template.key)) {
|
|
227
|
-
seen.add(template.key);
|
|
228
|
-
selected.push({ ...template });
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
return selected;
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
// src/onboarding/index.ts
|
|
235
|
-
var DOC_FILES = ["SOUL.md", "CLAUDE.md", "AGENTS.md", "README.md"];
|
|
236
|
-
function detectCapabilities(opts = {}) {
|
|
237
|
-
const cwd = opts.cwd ?? process.cwd();
|
|
238
|
-
if (opts.fromFile) {
|
|
239
|
-
const filePath = opts.fromFile.startsWith("/") ? opts.fromFile : join(cwd, opts.fromFile);
|
|
240
|
-
if (existsSync(filePath)) {
|
|
241
|
-
const content = readFileSync(filePath, "utf-8");
|
|
242
|
-
const capabilities = detectFromDocs(content);
|
|
243
|
-
if (capabilities.length > 0) {
|
|
244
|
-
return { source: "docs", capabilities, sourceFile: filePath };
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
return { source: "none", capabilities: [] };
|
|
248
|
-
}
|
|
249
|
-
for (const fileName of DOC_FILES) {
|
|
250
|
-
const filePath = join(cwd, fileName);
|
|
251
|
-
if (!existsSync(filePath)) continue;
|
|
252
|
-
const content = readFileSync(filePath, "utf-8");
|
|
253
|
-
if (fileName === "SOUL.md") {
|
|
254
|
-
return { source: "soul", capabilities: [], soulContent: content, sourceFile: filePath };
|
|
255
|
-
}
|
|
256
|
-
const capabilities = detectFromDocs(content);
|
|
257
|
-
if (capabilities.length > 0) {
|
|
258
|
-
return { source: "docs", capabilities, sourceFile: filePath };
|
|
259
|
-
}
|
|
260
|
-
}
|
|
261
|
-
const envKeys = detectApiKeys(KNOWN_API_KEYS);
|
|
262
|
-
if (envKeys.length > 0) {
|
|
263
|
-
return { source: "env", capabilities: [], envKeys };
|
|
264
|
-
}
|
|
265
|
-
return { source: "none", capabilities: [] };
|
|
266
|
-
}
|
|
267
|
-
function capabilitiesToV2Card(capabilities, owner, agentName) {
|
|
268
|
-
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
269
|
-
const skills = capabilities.map((cap) => ({
|
|
270
|
-
id: cap.key,
|
|
271
|
-
name: cap.name,
|
|
272
|
-
description: `${cap.name} capability \u2014 ${cap.category}`,
|
|
273
|
-
level: 1,
|
|
274
|
-
category: cap.category.toLowerCase().replace(/\s+/g, "_"),
|
|
275
|
-
inputs: [{ name: "input", type: "text", required: true }],
|
|
276
|
-
outputs: [{ name: "output", type: "text", required: true }],
|
|
277
|
-
pricing: { credits_per_call: cap.credits_per_call },
|
|
278
|
-
availability: { online: true },
|
|
279
|
-
metadata: {
|
|
280
|
-
tags: cap.tags
|
|
281
|
-
}
|
|
282
|
-
}));
|
|
283
|
-
const card = {
|
|
284
|
-
spec_version: "2.0",
|
|
285
|
-
id: randomUUID2(),
|
|
286
|
-
owner,
|
|
287
|
-
agent_name: agentName ?? owner,
|
|
288
|
-
skills,
|
|
289
|
-
availability: { online: true },
|
|
290
|
-
created_at: now,
|
|
291
|
-
updated_at: now
|
|
292
|
-
};
|
|
293
|
-
return CapabilityCardV2Schema.parse(card);
|
|
294
|
-
}
|
|
295
|
-
|
|
296
127
|
// src/openclaw/soul-sync.ts
|
|
297
|
-
import { randomUUID as
|
|
128
|
+
import { randomUUID as randomUUID2 } from "crypto";
|
|
298
129
|
var SKILL_META_GLOBAL_RE = /(?:^|\s)-\s*(capability_types|requires(?:_capabilities)?|visibility)\s*:\s*([^-][^]*?)(?=\s+-\s+(?:capability_types|requires(?:_capabilities)?|visibility)\s*:|$)/gi;
|
|
299
130
|
function extractSkillMeta(raw) {
|
|
300
131
|
let capability_types;
|
|
@@ -329,7 +160,7 @@ function parseSoulMdV2(content) {
|
|
|
329
160
|
const parsed = parseSoulMd(content);
|
|
330
161
|
const skills = parsed.capabilities.map((cap) => {
|
|
331
162
|
const sanitizedId = cap.name.toLowerCase().replace(/\s+/g, "-").replace(/[^a-z0-9-]/g, "");
|
|
332
|
-
const id = sanitizedId.length > 0 ? sanitizedId :
|
|
163
|
+
const id = sanitizedId.length > 0 ? sanitizedId : randomUUID2();
|
|
333
164
|
const { description: cleanDesc, capability_types, requires_capabilities, visibility } = extractSkillMeta(cap.description);
|
|
334
165
|
const finalDescription = (cleanDesc || cap.name).slice(0, 500);
|
|
335
166
|
const skill = {
|
|
@@ -383,7 +214,7 @@ function publishFromSoulV2(db, soulContent, owner, sharedSkills) {
|
|
|
383
214
|
(c) => c.spec_version === "2.0"
|
|
384
215
|
);
|
|
385
216
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
386
|
-
const cardId = existingV2?.id ??
|
|
217
|
+
const cardId = existingV2?.id ?? randomUUID2();
|
|
387
218
|
const card = {
|
|
388
219
|
spec_version: "2.0",
|
|
389
220
|
id: cardId,
|
|
@@ -408,7 +239,7 @@ function publishFromSoulV2(db, soulContent, owner, sharedSkills) {
|
|
|
408
239
|
}
|
|
409
240
|
|
|
410
241
|
// src/openclaw/heartbeat-writer.ts
|
|
411
|
-
import { readFileSync
|
|
242
|
+
import { readFileSync, writeFileSync, existsSync } from "fs";
|
|
412
243
|
var HEARTBEAT_MARKER_START = "<!-- agentbnb:start -->";
|
|
413
244
|
var HEARTBEAT_MARKER_END = "<!-- agentbnb:end -->";
|
|
414
245
|
function generateHeartbeatSection(autonomy, budget) {
|
|
@@ -444,11 +275,11 @@ function generateHeartbeatSection(autonomy, budget) {
|
|
|
444
275
|
].join("\n");
|
|
445
276
|
}
|
|
446
277
|
function injectHeartbeatSection(heartbeatPath, section) {
|
|
447
|
-
if (!
|
|
278
|
+
if (!existsSync(heartbeatPath)) {
|
|
448
279
|
writeFileSync(heartbeatPath, section + "\n", "utf-8");
|
|
449
280
|
return;
|
|
450
281
|
}
|
|
451
|
-
let content =
|
|
282
|
+
let content = readFileSync(heartbeatPath, "utf-8");
|
|
452
283
|
const startIdx = content.indexOf(HEARTBEAT_MARKER_START);
|
|
453
284
|
const endIdx = content.indexOf(HEARTBEAT_MARKER_END);
|
|
454
285
|
if (startIdx !== -1 && endIdx !== -1) {
|
|
@@ -493,9 +324,188 @@ function getOpenClawStatus(config, db, creditDb) {
|
|
|
493
324
|
};
|
|
494
325
|
}
|
|
495
326
|
|
|
496
|
-
// src/cli/
|
|
497
|
-
|
|
498
|
-
|
|
327
|
+
// src/cli/init-action.ts
|
|
328
|
+
import { randomBytes } from "crypto";
|
|
329
|
+
import { join as join2 } from "path";
|
|
330
|
+
import { networkInterfaces } from "os";
|
|
331
|
+
|
|
332
|
+
// src/onboarding/index.ts
|
|
333
|
+
import { randomUUID as randomUUID3 } from "crypto";
|
|
334
|
+
import { existsSync as existsSync2, readFileSync as readFileSync2 } from "fs";
|
|
335
|
+
import { join } from "path";
|
|
336
|
+
|
|
337
|
+
// src/onboarding/capability-templates.ts
|
|
338
|
+
var API_PATTERNS = [
|
|
339
|
+
{
|
|
340
|
+
pattern: /openai|gpt-4|gpt-3|chatgpt|dall-e/i,
|
|
341
|
+
capability: { key: "openai", name: "OpenAI Text Generation", category: "Text Gen", credits_per_call: 3, tags: ["llm", "text", "generation"] }
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
pattern: /elevenlabs|eleven.?labs/i,
|
|
345
|
+
capability: { key: "elevenlabs", name: "ElevenLabs TTS", category: "TTS", credits_per_call: 5, tags: ["tts", "audio", "voice"] }
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
pattern: /anthropic|claude/i,
|
|
349
|
+
capability: { key: "anthropic", name: "Anthropic Claude", category: "Text Gen", credits_per_call: 3, tags: ["llm", "text", "generation"] }
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
pattern: /recraft/i,
|
|
353
|
+
capability: { key: "recraft", name: "Recraft V4 Image Gen", category: "Image Gen", credits_per_call: 8, tags: ["image", "generation", "design"] }
|
|
354
|
+
},
|
|
355
|
+
{
|
|
356
|
+
pattern: /kling/i,
|
|
357
|
+
capability: { key: "kling", name: "Kling AI Video Gen", category: "Video Gen", credits_per_call: 10, tags: ["video", "generation"] }
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
pattern: /stable.?diffusion|sdxl|comfyui/i,
|
|
361
|
+
capability: { key: "stable-diffusion", name: "Stable Diffusion Image Gen", category: "Image Gen", credits_per_call: 6, tags: ["image", "generation", "diffusion"] }
|
|
362
|
+
},
|
|
363
|
+
{
|
|
364
|
+
pattern: /whisper|speech.?to.?text|stt/i,
|
|
365
|
+
capability: { key: "whisper", name: "Whisper Speech-to-Text", category: "STT", credits_per_call: 3, tags: ["stt", "audio", "transcription"] }
|
|
366
|
+
},
|
|
367
|
+
{
|
|
368
|
+
pattern: /puppeteer|playwright|selenium/i,
|
|
369
|
+
capability: { key: "puppeteer", name: "Web Scraping & Automation", category: "Web Scraping", credits_per_call: 2, tags: ["scraping", "automation", "browser"] }
|
|
370
|
+
},
|
|
371
|
+
{
|
|
372
|
+
pattern: /ffmpeg/i,
|
|
373
|
+
capability: { key: "ffmpeg", name: "FFmpeg Media Processing", category: "Media Processing", credits_per_call: 3, tags: ["media", "audio", "video", "processing"] }
|
|
374
|
+
},
|
|
375
|
+
{
|
|
376
|
+
pattern: /tesseract|ocr/i,
|
|
377
|
+
capability: { key: "tesseract", name: "OCR Text Extraction", category: "OCR", credits_per_call: 4, tags: ["ocr", "text", "extraction"] }
|
|
378
|
+
}
|
|
379
|
+
];
|
|
380
|
+
var INTERACTIVE_TEMPLATES = [
|
|
381
|
+
{ key: "openai", name: "Text Generation (GPT-4o / Claude / Gemini)", category: "Text Gen", credits_per_call: 3, tags: ["llm", "text", "generation"] },
|
|
382
|
+
{ key: "image-gen", name: "Image Generation (DALL-E / Recraft / Stable Diffusion)", category: "Image Gen", credits_per_call: 8, tags: ["image", "generation"] },
|
|
383
|
+
{ key: "tts", name: "TTS / Voice (ElevenLabs / Google TTS)", category: "TTS", credits_per_call: 5, tags: ["tts", "audio", "voice"] },
|
|
384
|
+
{ key: "video-gen", name: "Video Generation (Kling / Runway)", category: "Video Gen", credits_per_call: 10, tags: ["video", "generation"] },
|
|
385
|
+
{ key: "code-review", name: "Code Review / Analysis", category: "Code", credits_per_call: 3, tags: ["code", "review", "analysis"] },
|
|
386
|
+
{ key: "scraping", name: "Web Scraping / Data Extraction", category: "Web Scraping", credits_per_call: 2, tags: ["scraping", "data", "extraction"] },
|
|
387
|
+
{ key: "translation", name: "Translation", category: "Translation", credits_per_call: 3, tags: ["translation", "language", "text"] },
|
|
388
|
+
{ key: "custom", name: "Custom (describe it)", category: "Custom", credits_per_call: 5, tags: ["custom"] }
|
|
389
|
+
];
|
|
390
|
+
|
|
391
|
+
// src/onboarding/detect-from-docs.ts
|
|
392
|
+
function detectFromDocs(content) {
|
|
393
|
+
if (!content || content.trim().length === 0) {
|
|
394
|
+
return [];
|
|
395
|
+
}
|
|
396
|
+
const seen = /* @__PURE__ */ new Set();
|
|
397
|
+
const results = [];
|
|
398
|
+
for (const entry of API_PATTERNS) {
|
|
399
|
+
if (entry.pattern.test(content) && !seen.has(entry.capability.key)) {
|
|
400
|
+
seen.add(entry.capability.key);
|
|
401
|
+
results.push({ ...entry.capability });
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
return results;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
// src/onboarding/interactive.ts
|
|
408
|
+
import { createInterface } from "readline";
|
|
409
|
+
async function interactiveTemplateMenu() {
|
|
410
|
+
console.log("\nNo capabilities auto-detected.\n");
|
|
411
|
+
console.log("What can your agent do? Pick from templates:\n");
|
|
412
|
+
for (let i = 0; i < INTERACTIVE_TEMPLATES.length; i++) {
|
|
413
|
+
console.log(` ${i + 1}. ${INTERACTIVE_TEMPLATES[i].name}`);
|
|
414
|
+
}
|
|
415
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
416
|
+
const answer = await new Promise((resolve) => {
|
|
417
|
+
rl.question("\nSelect [1-8, comma-separated]: ", (ans) => {
|
|
418
|
+
rl.close();
|
|
419
|
+
resolve(ans);
|
|
420
|
+
});
|
|
421
|
+
});
|
|
422
|
+
return parseSelection(answer);
|
|
423
|
+
}
|
|
424
|
+
function parseSelection(input) {
|
|
425
|
+
if (!input || input.trim().length === 0) {
|
|
426
|
+
return [];
|
|
427
|
+
}
|
|
428
|
+
const selected = [];
|
|
429
|
+
const seen = /* @__PURE__ */ new Set();
|
|
430
|
+
const parts = input.split(",").map((s) => s.trim());
|
|
431
|
+
for (const part of parts) {
|
|
432
|
+
const num = parseInt(part, 10);
|
|
433
|
+
if (isNaN(num) || num < 1 || num > INTERACTIVE_TEMPLATES.length) {
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
const template = INTERACTIVE_TEMPLATES[num - 1];
|
|
437
|
+
if (!seen.has(template.key)) {
|
|
438
|
+
seen.add(template.key);
|
|
439
|
+
selected.push({ ...template });
|
|
440
|
+
}
|
|
441
|
+
}
|
|
442
|
+
return selected;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// src/onboarding/index.ts
|
|
446
|
+
var DOC_FILES = ["SOUL.md", "CLAUDE.md", "AGENTS.md", "README.md"];
|
|
447
|
+
function detectCapabilities(opts = {}) {
|
|
448
|
+
const cwd = opts.cwd ?? process.cwd();
|
|
449
|
+
if (opts.fromFile) {
|
|
450
|
+
const filePath = opts.fromFile.startsWith("/") ? opts.fromFile : join(cwd, opts.fromFile);
|
|
451
|
+
if (existsSync2(filePath)) {
|
|
452
|
+
const content = readFileSync2(filePath, "utf-8");
|
|
453
|
+
const capabilities = detectFromDocs(content);
|
|
454
|
+
if (capabilities.length > 0) {
|
|
455
|
+
return { source: "docs", capabilities, sourceFile: filePath };
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
return { source: "none", capabilities: [] };
|
|
459
|
+
}
|
|
460
|
+
for (const fileName of DOC_FILES) {
|
|
461
|
+
const filePath = join(cwd, fileName);
|
|
462
|
+
if (!existsSync2(filePath)) continue;
|
|
463
|
+
const content = readFileSync2(filePath, "utf-8");
|
|
464
|
+
if (fileName === "SOUL.md") {
|
|
465
|
+
return { source: "soul", capabilities: [], soulContent: content, sourceFile: filePath };
|
|
466
|
+
}
|
|
467
|
+
const capabilities = detectFromDocs(content);
|
|
468
|
+
if (capabilities.length > 0) {
|
|
469
|
+
return { source: "docs", capabilities, sourceFile: filePath };
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
const envKeys = detectApiKeys(KNOWN_API_KEYS);
|
|
473
|
+
if (envKeys.length > 0) {
|
|
474
|
+
return { source: "env", capabilities: [], envKeys };
|
|
475
|
+
}
|
|
476
|
+
return { source: "none", capabilities: [] };
|
|
477
|
+
}
|
|
478
|
+
function capabilitiesToV2Card(capabilities, owner, agentName) {
|
|
479
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
480
|
+
const skills = capabilities.map((cap) => ({
|
|
481
|
+
id: cap.key,
|
|
482
|
+
name: cap.name,
|
|
483
|
+
description: `${cap.name} capability \u2014 ${cap.category}`,
|
|
484
|
+
level: 1,
|
|
485
|
+
category: cap.category.toLowerCase().replace(/\s+/g, "_"),
|
|
486
|
+
inputs: [{ name: "input", type: "text", required: true }],
|
|
487
|
+
outputs: [{ name: "output", type: "text", required: true }],
|
|
488
|
+
pricing: { credits_per_call: cap.credits_per_call },
|
|
489
|
+
availability: { online: true },
|
|
490
|
+
metadata: {
|
|
491
|
+
tags: cap.tags
|
|
492
|
+
}
|
|
493
|
+
}));
|
|
494
|
+
const card = {
|
|
495
|
+
spec_version: "2.0",
|
|
496
|
+
id: randomUUID3(),
|
|
497
|
+
owner,
|
|
498
|
+
agent_name: agentName ?? owner,
|
|
499
|
+
skills,
|
|
500
|
+
availability: { online: true },
|
|
501
|
+
created_at: now,
|
|
502
|
+
updated_at: now
|
|
503
|
+
};
|
|
504
|
+
return CapabilityCardV2Schema.parse(card);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// src/cli/init-action.ts
|
|
508
|
+
import { createInterface as createInterface2 } from "readline";
|
|
499
509
|
async function confirm(question) {
|
|
500
510
|
const rl = createInterface2({ input: process.stdin, output: process.stdout });
|
|
501
511
|
try {
|
|
@@ -508,6 +518,15 @@ async function confirm(question) {
|
|
|
508
518
|
rl.close();
|
|
509
519
|
}
|
|
510
520
|
}
|
|
521
|
+
function getLanIp() {
|
|
522
|
+
const nets = networkInterfaces();
|
|
523
|
+
for (const ifaces of Object.values(nets)) {
|
|
524
|
+
for (const iface of ifaces ?? []) {
|
|
525
|
+
if (iface.family === "IPv4" && !iface.internal) return iface.address;
|
|
526
|
+
}
|
|
527
|
+
}
|
|
528
|
+
return "localhost";
|
|
529
|
+
}
|
|
511
530
|
function loadIdentityAuth(owner) {
|
|
512
531
|
const configDir = getConfigDir();
|
|
513
532
|
let keys;
|
|
@@ -524,41 +543,25 @@ function loadIdentityAuth(owner) {
|
|
|
524
543
|
privateKey: keys.privateKey
|
|
525
544
|
};
|
|
526
545
|
}
|
|
527
|
-
function
|
|
528
|
-
const nets = networkInterfaces();
|
|
529
|
-
for (const ifaces of Object.values(nets)) {
|
|
530
|
-
for (const iface of ifaces ?? []) {
|
|
531
|
-
if (iface.family === "IPv4" && !iface.internal) return iface.address;
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
return "localhost";
|
|
535
|
-
}
|
|
536
|
-
var program = new Command();
|
|
537
|
-
program.name("agentbnb").description("P2P Agent Capability Sharing Protocol \u2014 Airbnb for AI agent pipelines").version(pkg.version);
|
|
538
|
-
program.command("init").description("Initialize AgentBnB config and create agent identity").option("--owner <name>", "Agent owner name").option("--agent-id <id>", "Agent identity (alias for --owner, for genesis-template compat)").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("--non-interactive", "Non-interactive mode (alias for --yes)").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) => {
|
|
546
|
+
async function performInit(opts) {
|
|
539
547
|
const configDir = getConfigDir();
|
|
540
548
|
const dbPath = join2(configDir, "registry.db");
|
|
541
549
|
const creditDbPath = join2(configDir, "credit.db");
|
|
542
550
|
const port = parseInt(opts.port, 10);
|
|
543
551
|
const ip = opts.host ?? getLanIp();
|
|
544
552
|
const yesMode = opts.yes ?? opts.nonInteractive ?? false;
|
|
545
|
-
opts.yes = yesMode;
|
|
546
553
|
const existingConfig = loadConfig();
|
|
547
554
|
const owner = opts.agentId ?? opts.owner ?? existingConfig?.owner ?? `agent-${randomBytes(4).toString("hex")}`;
|
|
548
555
|
const config = {
|
|
549
556
|
...existingConfig,
|
|
550
|
-
// Preserve all existing keys (registry, autonomy, budget, etc.)
|
|
551
557
|
owner,
|
|
552
558
|
gateway_url: `http://${ip}:${port}`,
|
|
553
559
|
gateway_port: port,
|
|
554
560
|
db_path: dbPath,
|
|
555
561
|
credit_db_path: creditDbPath,
|
|
556
562
|
token: existingConfig?.token ?? randomBytes(32).toString("hex"),
|
|
557
|
-
// Preserve existing token
|
|
558
563
|
api_key: existingConfig?.api_key ?? randomBytes(32).toString("hex"),
|
|
559
|
-
|
|
560
|
-
// Interactive init leaves registry unset so users can configure it explicitly.
|
|
561
|
-
...existingConfig?.registry ? { registry: existingConfig.registry } : opts.yes ? { registry: "https://agentbnb.fly.dev" } : {}
|
|
564
|
+
...existingConfig?.registry ? { registry: existingConfig.registry } : yesMode ? { registry: "https://agentbnb.fly.dev" } : {}
|
|
562
565
|
};
|
|
563
566
|
saveConfig(config);
|
|
564
567
|
let keypairStatus = "existing";
|
|
@@ -616,6 +619,22 @@ program.command("init").description("Initialize AgentBnB config and create agent
|
|
|
616
619
|
console.log(`Migrated local credits: ${existingConfig.owner} \u2192 ${owner}`);
|
|
617
620
|
}
|
|
618
621
|
}
|
|
622
|
+
const existingAgent = lookupAgent(creditDb, identity.agent_id) ?? lookupAgentByOwner(creditDb, owner);
|
|
623
|
+
if (!existingAgent) {
|
|
624
|
+
try {
|
|
625
|
+
createAgentRecord(creditDb, {
|
|
626
|
+
agent_id: identity.agent_id,
|
|
627
|
+
display_name: config.display_name ?? owner,
|
|
628
|
+
public_key: identity.public_key,
|
|
629
|
+
legacy_owner: owner
|
|
630
|
+
});
|
|
631
|
+
} catch {
|
|
632
|
+
}
|
|
633
|
+
}
|
|
634
|
+
if (!config.agent_id || config.agent_id !== identity.agent_id) {
|
|
635
|
+
config.agent_id = identity.agent_id;
|
|
636
|
+
saveConfig(config);
|
|
637
|
+
}
|
|
619
638
|
bootstrapAgent(creditDb, owner, 100);
|
|
620
639
|
creditDb.close();
|
|
621
640
|
let registryBalance;
|
|
@@ -664,12 +683,12 @@ program.command("init").description("Initialize AgentBnB config and create agent
|
|
|
664
683
|
}
|
|
665
684
|
}
|
|
666
685
|
const card = capabilitiesToV2Card(result.capabilities, owner);
|
|
667
|
-
if (
|
|
686
|
+
if (yesMode) {
|
|
668
687
|
const db = openDatabase(dbPath);
|
|
669
688
|
try {
|
|
670
689
|
db.prepare(
|
|
671
690
|
`INSERT OR REPLACE INTO capability_cards (id, owner, data, created_at, updated_at)
|
|
672
|
-
|
|
691
|
+
VALUES (?, ?, ?, ?, ?)`
|
|
673
692
|
).run(card.id, card.owner, JSON.stringify(card), card.created_at, card.updated_at);
|
|
674
693
|
publishedCards.push({ id: card.id, name: card.agent_name });
|
|
675
694
|
if (!opts.json) {
|
|
@@ -686,7 +705,7 @@ Publish these ${card.skills.length} capabilities? [y/N] `);
|
|
|
686
705
|
try {
|
|
687
706
|
db.prepare(
|
|
688
707
|
`INSERT OR REPLACE INTO capability_cards (id, owner, data, created_at, updated_at)
|
|
689
|
-
|
|
708
|
+
VALUES (?, ?, ?, ?, ?)`
|
|
690
709
|
).run(card.id, card.owner, JSON.stringify(card), card.created_at, card.updated_at);
|
|
691
710
|
publishedCards.push({ id: card.id, name: card.agent_name });
|
|
692
711
|
console.log(` Published v2.0 card: ${card.agent_name} (${card.skills.length} skills)`);
|
|
@@ -711,7 +730,7 @@ Publish these ${card.skills.length} capabilities? [y/N] `);
|
|
|
711
730
|
console.log(` Found services on ports: ${detectedPorts.join(", ")}`);
|
|
712
731
|
}
|
|
713
732
|
const drafts = detectedKeys.map((key) => buildDraftCard(key, owner)).filter((card) => card !== null);
|
|
714
|
-
if (
|
|
733
|
+
if (yesMode) {
|
|
715
734
|
const db = openDatabase(dbPath);
|
|
716
735
|
try {
|
|
717
736
|
for (const card of drafts) {
|
|
@@ -746,7 +765,7 @@ Publish these ${card.skills.length} capabilities? [y/N] `);
|
|
|
746
765
|
}
|
|
747
766
|
}
|
|
748
767
|
} else {
|
|
749
|
-
if (process.stdout.isTTY && !
|
|
768
|
+
if (process.stdout.isTTY && !yesMode && !opts.json) {
|
|
750
769
|
const selected = await interactiveTemplateMenu();
|
|
751
770
|
if (selected.length > 0) {
|
|
752
771
|
const card = capabilitiesToV2Card(selected, owner);
|
|
@@ -754,7 +773,7 @@ Publish these ${card.skills.length} capabilities? [y/N] `);
|
|
|
754
773
|
try {
|
|
755
774
|
db.prepare(
|
|
756
775
|
`INSERT OR REPLACE INTO capability_cards (id, owner, data, created_at, updated_at)
|
|
757
|
-
|
|
776
|
+
VALUES (?, ?, ?, ?, ?)`
|
|
758
777
|
).run(card.id, card.owner, JSON.stringify(card), card.created_at, card.updated_at);
|
|
759
778
|
publishedCards.push({ id: card.id, name: card.agent_name });
|
|
760
779
|
console.log(`
|
|
@@ -768,36 +787,277 @@ Publish these ${card.skills.length} capabilities? [y/N] `);
|
|
|
768
787
|
}
|
|
769
788
|
}
|
|
770
789
|
}
|
|
790
|
+
return {
|
|
791
|
+
config,
|
|
792
|
+
owner,
|
|
793
|
+
configDir,
|
|
794
|
+
publishedCards,
|
|
795
|
+
registryBalance,
|
|
796
|
+
identity: { agent_id: identity.agent_id },
|
|
797
|
+
keypairStatus,
|
|
798
|
+
detectedSource
|
|
799
|
+
};
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// src/cli/quickstart.ts
|
|
803
|
+
import { existsSync as existsSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "fs";
|
|
804
|
+
import { join as join3 } from "path";
|
|
805
|
+
import { homedir } from "os";
|
|
806
|
+
import { execSync } from "child_process";
|
|
807
|
+
var SKILLS_YAML_TEMPLATE = `skills:
|
|
808
|
+
# General-purpose AI task execution via Claude Code CLI
|
|
809
|
+
- id: claude-code-run
|
|
810
|
+
type: command
|
|
811
|
+
name: Claude Code Task Runner
|
|
812
|
+
description: "Execute any text-based AI task via Claude Code"
|
|
813
|
+
command: claude -p "\${params.prompt}"
|
|
814
|
+
output_type: text
|
|
815
|
+
allowed_commands:
|
|
816
|
+
- claude
|
|
817
|
+
timeout_ms: 180000
|
|
818
|
+
pricing:
|
|
819
|
+
credits_per_call: 5
|
|
820
|
+
|
|
821
|
+
# Code review skill
|
|
822
|
+
- id: claude-code-review
|
|
823
|
+
type: command
|
|
824
|
+
name: Code Review
|
|
825
|
+
description: "Review code for bugs, style, and improvements"
|
|
826
|
+
command: claude -p "Review this code for bugs, style issues, and improvements:\\n\\n\${params.code}"
|
|
827
|
+
output_type: text
|
|
828
|
+
allowed_commands:
|
|
829
|
+
- claude
|
|
830
|
+
timeout_ms: 120000
|
|
831
|
+
pricing:
|
|
832
|
+
credits_per_call: 3
|
|
833
|
+
|
|
834
|
+
# Text summarization skill
|
|
835
|
+
- id: claude-code-summarize
|
|
836
|
+
type: command
|
|
837
|
+
name: Text Summarizer
|
|
838
|
+
description: "Summarize long text into concise key points"
|
|
839
|
+
command: claude -p "Summarize the following text into concise key points:\\n\\n\${params.text}"
|
|
840
|
+
output_type: text
|
|
841
|
+
allowed_commands:
|
|
842
|
+
- claude
|
|
843
|
+
timeout_ms: 120000
|
|
844
|
+
pricing:
|
|
845
|
+
credits_per_call: 2
|
|
846
|
+
`;
|
|
847
|
+
function generateSkillsYaml(configDir) {
|
|
848
|
+
const skillsPath = join3(configDir, "skills.yaml");
|
|
849
|
+
if (existsSync3(skillsPath)) {
|
|
850
|
+
const content = readFileSync3(skillsPath, "utf-8");
|
|
851
|
+
const matches = content.match(/^\s+-\s+id:/gm);
|
|
852
|
+
return { generated: false, path: skillsPath, skillCount: matches?.length ?? 0 };
|
|
853
|
+
}
|
|
854
|
+
writeFileSync2(skillsPath, SKILLS_YAML_TEMPLATE, "utf-8");
|
|
855
|
+
return { generated: true, path: skillsPath, skillCount: 3 };
|
|
856
|
+
}
|
|
857
|
+
function registerMcpWithClaudeCode() {
|
|
858
|
+
const claudeDir = join3(homedir(), ".claude");
|
|
859
|
+
if (!existsSync3(claudeDir)) {
|
|
860
|
+
return {
|
|
861
|
+
registered: false,
|
|
862
|
+
reason: "Claude Code not detected. Add MCP manually: claude mcp add agentbnb -- agentbnb mcp-server"
|
|
863
|
+
};
|
|
864
|
+
}
|
|
865
|
+
const settingsPath = join3(claudeDir, "settings.json");
|
|
866
|
+
let agentbnbCommand = "agentbnb";
|
|
867
|
+
try {
|
|
868
|
+
const resolved = execSync("which agentbnb", { encoding: "utf-8" }).trim();
|
|
869
|
+
if (resolved) agentbnbCommand = resolved;
|
|
870
|
+
} catch {
|
|
871
|
+
}
|
|
872
|
+
let settings = {};
|
|
873
|
+
if (existsSync3(settingsPath)) {
|
|
874
|
+
try {
|
|
875
|
+
settings = JSON.parse(readFileSync3(settingsPath, "utf-8"));
|
|
876
|
+
} catch {
|
|
877
|
+
try {
|
|
878
|
+
writeFileSync2(`${settingsPath}.bak`, readFileSync3(settingsPath, "utf-8"), "utf-8");
|
|
879
|
+
} catch {
|
|
880
|
+
}
|
|
881
|
+
settings = {};
|
|
882
|
+
}
|
|
883
|
+
}
|
|
884
|
+
const mcpServers = settings.mcpServers ?? {};
|
|
885
|
+
if (mcpServers.agentbnb) {
|
|
886
|
+
return { registered: false, path: settingsPath, reason: "already registered" };
|
|
887
|
+
}
|
|
888
|
+
mcpServers.agentbnb = {
|
|
889
|
+
command: agentbnbCommand,
|
|
890
|
+
args: ["mcp-server"]
|
|
891
|
+
};
|
|
892
|
+
settings.mcpServers = mcpServers;
|
|
893
|
+
writeFileSync2(settingsPath, JSON.stringify(settings, null, 2) + "\n", "utf-8");
|
|
894
|
+
return { registered: true, path: settingsPath };
|
|
895
|
+
}
|
|
896
|
+
async function runQuickstart(opts) {
|
|
897
|
+
const jsonMode = opts.json ?? false;
|
|
898
|
+
const skipServe = opts.serve === false;
|
|
899
|
+
const skipMcp = opts.mcp === false;
|
|
900
|
+
if (!jsonMode) console.log("Initializing AgentBnB...");
|
|
901
|
+
const initResult = await performInit({
|
|
902
|
+
owner: opts.owner,
|
|
903
|
+
port: opts.port,
|
|
904
|
+
yes: true,
|
|
905
|
+
detect: true,
|
|
906
|
+
json: false
|
|
907
|
+
// We handle output ourselves
|
|
908
|
+
});
|
|
909
|
+
const skills = generateSkillsYaml(initResult.configDir);
|
|
910
|
+
if (!jsonMode) {
|
|
911
|
+
if (skills.generated) {
|
|
912
|
+
console.log(`
|
|
913
|
+
Generated skills.yaml with ${skills.skillCount} Claude Code skills`);
|
|
914
|
+
} else {
|
|
915
|
+
console.log(`
|
|
916
|
+
Skills: ${skills.skillCount} skill(s) in ${skills.path}`);
|
|
917
|
+
}
|
|
918
|
+
}
|
|
919
|
+
let mcpResult = { registered: false, reason: "skipped" };
|
|
920
|
+
if (!skipMcp) {
|
|
921
|
+
mcpResult = registerMcpWithClaudeCode();
|
|
922
|
+
if (!jsonMode) {
|
|
923
|
+
if (mcpResult.registered) {
|
|
924
|
+
console.log(`MCP: registered in ${mcpResult.path}`);
|
|
925
|
+
} else if (mcpResult.reason === "already registered") {
|
|
926
|
+
console.log(`MCP: already registered in ${mcpResult.path}`);
|
|
927
|
+
} else {
|
|
928
|
+
console.log(`MCP: ${mcpResult.reason}`);
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
}
|
|
932
|
+
let daemonStatus = { running: false, reason: "skipped" };
|
|
933
|
+
if (!skipServe) {
|
|
934
|
+
try {
|
|
935
|
+
const { ProcessGuard } = await import("../process-guard-GH5LRNWO.js");
|
|
936
|
+
const { ServiceCoordinator } = await import("../service-coordinator-WGH6B2VT.js");
|
|
937
|
+
const guard = new ProcessGuard(join3(initResult.configDir, ".pid"));
|
|
938
|
+
const coordinator = new ServiceCoordinator(initResult.config, guard);
|
|
939
|
+
const result = await coordinator.ensureRunning({
|
|
940
|
+
port: initResult.config.gateway_port,
|
|
941
|
+
skillsYamlPath: join3(initResult.configDir, "skills.yaml"),
|
|
942
|
+
registryUrl: initResult.config.registry,
|
|
943
|
+
relay: true
|
|
944
|
+
});
|
|
945
|
+
if (result === "already_running") {
|
|
946
|
+
daemonStatus = { running: true, reason: "already running" };
|
|
947
|
+
} else {
|
|
948
|
+
const meta = guard.getRunningMeta();
|
|
949
|
+
daemonStatus = { running: true, pid: meta?.pid };
|
|
950
|
+
}
|
|
951
|
+
if (!jsonMode) {
|
|
952
|
+
if (result === "already_running") {
|
|
953
|
+
console.log(`Daemon: already running`);
|
|
954
|
+
} else {
|
|
955
|
+
console.log(`Daemon: started (pid ${daemonStatus.pid ?? "unknown"})`);
|
|
956
|
+
}
|
|
957
|
+
}
|
|
958
|
+
} catch (err) {
|
|
959
|
+
daemonStatus = { running: false, reason: err.message };
|
|
960
|
+
if (!jsonMode) {
|
|
961
|
+
console.warn(`Daemon: failed to start \u2014 ${err.message}`);
|
|
962
|
+
console.warn(` Start manually with: agentbnb serve`);
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
}
|
|
966
|
+
if (jsonMode) {
|
|
967
|
+
console.log(JSON.stringify({
|
|
968
|
+
success: true,
|
|
969
|
+
owner: initResult.owner,
|
|
970
|
+
config_dir: initResult.configDir,
|
|
971
|
+
gateway_url: initResult.config.gateway_url,
|
|
972
|
+
registry: initResult.config.registry,
|
|
973
|
+
credits: initResult.registryBalance ?? 100,
|
|
974
|
+
skills: { count: skills.skillCount, generated: skills.generated, path: skills.path },
|
|
975
|
+
mcp: mcpResult,
|
|
976
|
+
daemon: daemonStatus,
|
|
977
|
+
published_cards: initResult.publishedCards
|
|
978
|
+
}, null, 2));
|
|
979
|
+
} else {
|
|
980
|
+
console.log("\n--- AgentBnB quickstart complete! ---\n");
|
|
981
|
+
console.log(` Owner: ${initResult.owner}`);
|
|
982
|
+
console.log(` Gateway: ${initResult.config.gateway_url}`);
|
|
983
|
+
console.log(` Credits: ${initResult.registryBalance ?? 100}`);
|
|
984
|
+
console.log(` Registry: ${initResult.config.registry ?? "not configured"}`);
|
|
985
|
+
console.log(` Skills: ${skills.skillCount} loaded`);
|
|
986
|
+
console.log(` MCP: ${mcpResult.registered ? "registered" : mcpResult.reason}`);
|
|
987
|
+
console.log(` Daemon: ${daemonStatus.running ? `running${daemonStatus.pid ? ` (pid ${daemonStatus.pid})` : ""}` : `not running \u2014 ${daemonStatus.reason}`}`);
|
|
988
|
+
console.log("");
|
|
989
|
+
console.log(" You are now both a consumer and provider on AgentBnB.");
|
|
990
|
+
console.log("");
|
|
991
|
+
console.log(" Consumer: In Claude Code, use agentbnb_discover and agentbnb_request");
|
|
992
|
+
console.log(" Provider: Your claude -p skills are live and accepting requests");
|
|
993
|
+
console.log(` Dashboard: http://localhost:7701/hub/#/myagent`);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
// src/cli/index.ts
|
|
998
|
+
var require2 = createRequire(import.meta.url);
|
|
999
|
+
var pkg = require2("../../package.json");
|
|
1000
|
+
function loadIdentityAuth2(owner) {
|
|
1001
|
+
const configDir = getConfigDir();
|
|
1002
|
+
let keys;
|
|
1003
|
+
try {
|
|
1004
|
+
keys = loadKeyPair(configDir);
|
|
1005
|
+
} catch {
|
|
1006
|
+
keys = generateKeyPair();
|
|
1007
|
+
saveKeyPair(configDir, keys);
|
|
1008
|
+
}
|
|
1009
|
+
const identity = ensureIdentity(configDir, owner);
|
|
1010
|
+
return {
|
|
1011
|
+
agentId: identity.agent_id,
|
|
1012
|
+
publicKey: identity.public_key,
|
|
1013
|
+
privateKey: keys.privateKey
|
|
1014
|
+
};
|
|
1015
|
+
}
|
|
1016
|
+
function getLanIp2() {
|
|
1017
|
+
const nets = networkInterfaces2();
|
|
1018
|
+
for (const ifaces of Object.values(nets)) {
|
|
1019
|
+
for (const iface of ifaces ?? []) {
|
|
1020
|
+
if (iface.family === "IPv4" && !iface.internal) return iface.address;
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
return "localhost";
|
|
1024
|
+
}
|
|
1025
|
+
var program = new Command();
|
|
1026
|
+
program.name("agentbnb").description("P2P Agent Capability Sharing Protocol \u2014 Airbnb for AI agent pipelines").version(pkg.version);
|
|
1027
|
+
program.command("init").description("Initialize AgentBnB config and create agent identity").option("--owner <name>", "Agent owner name").option("--agent-id <id>", "Agent identity (alias for --owner, for genesis-template compat)").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("--non-interactive", "Non-interactive mode (alias for --yes)").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) => {
|
|
1028
|
+
const result = await performInit(opts);
|
|
771
1029
|
if (opts.json) {
|
|
772
1030
|
const jsonOutput = {
|
|
773
1031
|
success: true,
|
|
774
|
-
owner,
|
|
775
|
-
config_dir: configDir,
|
|
776
|
-
token: config.token,
|
|
777
|
-
gateway_url: config.gateway_url,
|
|
778
|
-
keypair: keypairStatus,
|
|
779
|
-
agent_id: identity.agent_id
|
|
1032
|
+
owner: result.owner,
|
|
1033
|
+
config_dir: result.configDir,
|
|
1034
|
+
token: result.config.token,
|
|
1035
|
+
gateway_url: result.config.gateway_url,
|
|
1036
|
+
keypair: result.keypairStatus,
|
|
1037
|
+
agent_id: result.identity.agent_id
|
|
780
1038
|
};
|
|
781
|
-
if (registryBalance !== void 0) {
|
|
782
|
-
jsonOutput.registry_balance = registryBalance;
|
|
1039
|
+
if (result.registryBalance !== void 0) {
|
|
1040
|
+
jsonOutput.registry_balance = result.registryBalance;
|
|
783
1041
|
}
|
|
784
|
-
if (
|
|
785
|
-
jsonOutput.detected_source = detectedSource;
|
|
786
|
-
jsonOutput.published_cards = publishedCards;
|
|
1042
|
+
if (opts.detect !== false) {
|
|
1043
|
+
jsonOutput.detected_source = result.detectedSource;
|
|
1044
|
+
jsonOutput.published_cards = result.publishedCards;
|
|
787
1045
|
}
|
|
788
1046
|
console.log(JSON.stringify(jsonOutput, null, 2));
|
|
789
1047
|
} else {
|
|
1048
|
+
const ip = opts.host ?? getLanIp2();
|
|
1049
|
+
const port = parseInt(opts.port, 10);
|
|
790
1050
|
console.log(`AgentBnB initialized.`);
|
|
791
|
-
console.log(` Owner: ${owner}`);
|
|
792
|
-
console.log(` Token: ${config.token}`);
|
|
793
|
-
console.log(` Config: ${configDir}/config.json`);
|
|
794
|
-
if (registryBalance !== void 0) {
|
|
795
|
-
console.log(` Registry balance: ${registryBalance} credits`);
|
|
1051
|
+
console.log(` Owner: ${result.owner}`);
|
|
1052
|
+
console.log(` Token: ${result.config.token}`);
|
|
1053
|
+
console.log(` Config: ${result.configDir}/config.json`);
|
|
1054
|
+
if (result.registryBalance !== void 0) {
|
|
1055
|
+
console.log(` Registry balance: ${result.registryBalance} credits`);
|
|
796
1056
|
} else {
|
|
797
1057
|
console.log(` Credits: 100 (starter grant)`);
|
|
798
1058
|
}
|
|
799
|
-
console.log(` Keypair: ${keypairStatus === "generated" ? "generated (Ed25519)" : "preserved (existing)"}`);
|
|
800
|
-
console.log(` Agent ID: ${identity.agent_id}`);
|
|
1059
|
+
console.log(` Keypair: ${result.keypairStatus === "generated" ? "generated (Ed25519)" : "preserved (existing)"}`);
|
|
1060
|
+
console.log(` Agent ID: ${result.identity.agent_id}`);
|
|
801
1061
|
console.log(` Gateway: http://${ip}:${port}`);
|
|
802
1062
|
}
|
|
803
1063
|
});
|
|
@@ -809,7 +1069,7 @@ program.command("publish <card.json>").description("Publish a Capability Card to
|
|
|
809
1069
|
}
|
|
810
1070
|
let raw;
|
|
811
1071
|
try {
|
|
812
|
-
raw =
|
|
1072
|
+
raw = readFileSync4(cardPath, "utf-8");
|
|
813
1073
|
} catch {
|
|
814
1074
|
console.error(`Error: cannot read file: ${cardPath}`);
|
|
815
1075
|
process.exit(1);
|
|
@@ -916,12 +1176,12 @@ program.command("publish-skills").description("Publish capabilities from skills.
|
|
|
916
1176
|
console.error("Error: not initialized. Run `agentbnb init` first.");
|
|
917
1177
|
process.exit(1);
|
|
918
1178
|
}
|
|
919
|
-
const { parseSkillsFile } = await import("../skill-config-
|
|
920
|
-
const { skillConfigToSkill } = await import("../publish-capability-
|
|
1179
|
+
const { parseSkillsFile } = await import("../skill-config-FETXPNVP.js");
|
|
1180
|
+
const { skillConfigToSkill } = await import("../publish-capability-AH2HDW54.js");
|
|
921
1181
|
const skillsPath = typeof opts.fromSkills === "string" ? opts.fromSkills : "./skills.yaml";
|
|
922
1182
|
let yamlContent;
|
|
923
1183
|
try {
|
|
924
|
-
yamlContent =
|
|
1184
|
+
yamlContent = readFileSync4(skillsPath, "utf-8");
|
|
925
1185
|
} catch {
|
|
926
1186
|
console.error(`Error: cannot read skills.yaml at ${skillsPath}`);
|
|
927
1187
|
process.exit(1);
|
|
@@ -1168,7 +1428,7 @@ program.command("request [card-id]").description("Request a capability from anot
|
|
|
1168
1428
|
}
|
|
1169
1429
|
let batchPayload;
|
|
1170
1430
|
try {
|
|
1171
|
-
const raw =
|
|
1431
|
+
const raw = readFileSync4(opts.batch, "utf-8");
|
|
1172
1432
|
batchPayload = JSON.parse(raw);
|
|
1173
1433
|
} catch (err) {
|
|
1174
1434
|
console.error(`Error: could not read batch file: ${err.message}`);
|
|
@@ -1229,8 +1489,8 @@ Batch Results (${res.results.length} items):`);
|
|
|
1229
1489
|
process.exit(1);
|
|
1230
1490
|
}
|
|
1231
1491
|
}
|
|
1232
|
-
const registryDb = openDatabase(
|
|
1233
|
-
const creditDb = openCreditDb(
|
|
1492
|
+
const registryDb = openDatabase(join4(getConfigDir(), "registry.db"));
|
|
1493
|
+
const creditDb = openCreditDb(join4(getConfigDir(), "credit.db"));
|
|
1234
1494
|
registryDb.pragma("busy_timeout = 5000");
|
|
1235
1495
|
creditDb.pragma("busy_timeout = 5000");
|
|
1236
1496
|
try {
|
|
@@ -1270,7 +1530,7 @@ Batch Results (${res.results.length} items):`);
|
|
|
1270
1530
|
let token;
|
|
1271
1531
|
let isRemoteRequest = false;
|
|
1272
1532
|
let targetOwner;
|
|
1273
|
-
const identityAuth =
|
|
1533
|
+
const identityAuth = loadIdentityAuth2(config.owner);
|
|
1274
1534
|
if (opts.peer) {
|
|
1275
1535
|
const peer = findPeer(opts.peer);
|
|
1276
1536
|
if (!peer) {
|
|
@@ -1350,7 +1610,7 @@ Batch Results (${res.results.length} items):`);
|
|
|
1350
1610
|
process.exit(1);
|
|
1351
1611
|
}
|
|
1352
1612
|
if (useRegistryLedger) {
|
|
1353
|
-
const reqIdentityAuth =
|
|
1613
|
+
const reqIdentityAuth = loadIdentityAuth2(config.owner);
|
|
1354
1614
|
requestLedger = createLedger({
|
|
1355
1615
|
registryUrl: config.registry,
|
|
1356
1616
|
ownerPublicKey: reqIdentityAuth.publicKey,
|
|
@@ -1373,7 +1633,7 @@ Batch Results (${res.results.length} items):`);
|
|
|
1373
1633
|
}
|
|
1374
1634
|
} else if (gatewayUrl) {
|
|
1375
1635
|
const configDir = getConfigDir();
|
|
1376
|
-
const creditDb = openCreditDb(
|
|
1636
|
+
const creditDb = openCreditDb(join4(configDir, "credit.db"));
|
|
1377
1637
|
creditDb.pragma("busy_timeout = 5000");
|
|
1378
1638
|
try {
|
|
1379
1639
|
const keys = loadKeyPair(configDir);
|
|
@@ -1408,7 +1668,7 @@ Batch Results (${res.results.length} items):`);
|
|
|
1408
1668
|
if (!opts.json) console.log(`Escrow settled: ${opts.cost} credits deducted.`);
|
|
1409
1669
|
} else if (escrowReceipt) {
|
|
1410
1670
|
const configDir = getConfigDir();
|
|
1411
|
-
const creditDb = openCreditDb(
|
|
1671
|
+
const creditDb = openCreditDb(join4(configDir, "credit.db"));
|
|
1412
1672
|
creditDb.pragma("busy_timeout = 5000");
|
|
1413
1673
|
try {
|
|
1414
1674
|
settleRequesterEscrow(creditDb, escrowId);
|
|
@@ -1426,7 +1686,7 @@ Batch Results (${res.results.length} items):`);
|
|
|
1426
1686
|
if (!opts.json) console.log("Escrow released: credits refunded.");
|
|
1427
1687
|
} else if (escrowReceipt) {
|
|
1428
1688
|
const configDir = getConfigDir();
|
|
1429
|
-
const creditDb = openCreditDb(
|
|
1689
|
+
const creditDb = openCreditDb(join4(configDir, "credit.db"));
|
|
1430
1690
|
creditDb.pragma("busy_timeout = 5000");
|
|
1431
1691
|
try {
|
|
1432
1692
|
releaseRequesterEscrow(creditDb, escrowId);
|
|
@@ -1450,8 +1710,8 @@ Batch Results (${res.results.length} items):`);
|
|
|
1450
1710
|
return msg.includes("NETWORK_ERROR") || msg.includes("ECONNREFUSED") || msg.includes("fetch failed") || msg.includes("Network error");
|
|
1451
1711
|
};
|
|
1452
1712
|
const tryViaRelay = async () => {
|
|
1453
|
-
const { RelayClient } = await import("../websocket-client-
|
|
1454
|
-
const { requestViaRelay } = await import("../client-
|
|
1713
|
+
const { RelayClient } = await import("../websocket-client-QOVARTRN.js");
|
|
1714
|
+
const { requestViaRelay } = await import("../client-HKV3QWZ3.js");
|
|
1455
1715
|
const requesterId = `${config.owner}:req:${randomUUID4()}`;
|
|
1456
1716
|
const tempRelay = new RelayClient({
|
|
1457
1717
|
registryUrl: config.registry,
|
|
@@ -1529,7 +1789,7 @@ program.command("status").description("Show credit balance and recent transactio
|
|
|
1529
1789
|
let transactions;
|
|
1530
1790
|
let heldEscrows;
|
|
1531
1791
|
if (config.registry) {
|
|
1532
|
-
const statusIdentityAuth =
|
|
1792
|
+
const statusIdentityAuth = loadIdentityAuth2(config.owner);
|
|
1533
1793
|
const statusLedger = createLedger({
|
|
1534
1794
|
registryUrl: config.registry,
|
|
1535
1795
|
ownerPublicKey: statusIdentityAuth.publicKey,
|
|
@@ -1580,15 +1840,15 @@ program.command("serve").description("Start the AgentBnB gateway server").option
|
|
|
1580
1840
|
console.error("Error: not initialized. Run `agentbnb init` first.");
|
|
1581
1841
|
process.exit(1);
|
|
1582
1842
|
}
|
|
1583
|
-
const { ProcessGuard } = await import("../process-guard-
|
|
1584
|
-
const { ServiceCoordinator } = await import("../service-coordinator-
|
|
1843
|
+
const { ProcessGuard } = await import("../process-guard-GH5LRNWO.js");
|
|
1844
|
+
const { ServiceCoordinator } = await import("../service-coordinator-WGH6B2VT.js");
|
|
1585
1845
|
const port = opts.port ? parseInt(opts.port, 10) : config.gateway_port;
|
|
1586
1846
|
const registryPort = parseInt(opts.registryPort, 10);
|
|
1587
1847
|
if (!Number.isFinite(port) || !Number.isFinite(registryPort)) {
|
|
1588
1848
|
console.error("Error: --port and --registry-port must be valid numbers.");
|
|
1589
1849
|
process.exit(1);
|
|
1590
1850
|
}
|
|
1591
|
-
const guard = new ProcessGuard(
|
|
1851
|
+
const guard = new ProcessGuard(join4(getConfigDir(), ".pid"));
|
|
1592
1852
|
const coordinator = new ServiceCoordinator(config, guard);
|
|
1593
1853
|
try {
|
|
1594
1854
|
await coordinator.ensureRunning({
|
|
@@ -1856,7 +2116,7 @@ cardsCmd.command("delete <card-id>").description("Delete a published capability
|
|
|
1856
2116
|
console.log(` Skills: ${skillCount}`);
|
|
1857
2117
|
console.log(` ID: ${card.id}`);
|
|
1858
2118
|
if (!opts.force && process.stdin.isTTY) {
|
|
1859
|
-
const rl =
|
|
2119
|
+
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
1860
2120
|
const answer = await new Promise((resolve) => {
|
|
1861
2121
|
rl.question("Confirm deletion? [y/N] ", resolve);
|
|
1862
2122
|
});
|
|
@@ -1885,7 +2145,7 @@ openclaw.command("sync").description("Read SOUL.md and publish/update a v2.0 cap
|
|
|
1885
2145
|
}
|
|
1886
2146
|
let content;
|
|
1887
2147
|
try {
|
|
1888
|
-
content =
|
|
2148
|
+
content = readFileSync4(opts.soulPath, "utf-8");
|
|
1889
2149
|
} catch {
|
|
1890
2150
|
console.error(`Error: cannot read SOUL.md at ${opts.soulPath}`);
|
|
1891
2151
|
process.exit(1);
|
|
@@ -1955,7 +2215,7 @@ openclaw.command("rules").description("Print HEARTBEAT.md rules block (or inject
|
|
|
1955
2215
|
}
|
|
1956
2216
|
});
|
|
1957
2217
|
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) => {
|
|
1958
|
-
const { conductAction } = await import("../conduct-
|
|
2218
|
+
const { conductAction } = await import("../conduct-YB64OHI6.js");
|
|
1959
2219
|
const result = await conductAction(task, opts);
|
|
1960
2220
|
if (opts.json) {
|
|
1961
2221
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -2065,8 +2325,9 @@ Feedback for skill: ${opts.skill} (${feedbacks.length} entries)
|
|
|
2065
2325
|
}
|
|
2066
2326
|
}
|
|
2067
2327
|
});
|
|
2328
|
+
program.command("quickstart").alias("qs").description("One-command setup: init + skills.yaml + MCP registration + serve daemon").option("--owner <name>", "Agent owner name").option("--port <port>", "Gateway port", "7700").option("--no-serve", "Skip starting background daemon").option("--no-mcp", "Skip MCP registration with Claude Code").option("--json", "Output as JSON").action(runQuickstart);
|
|
2068
2329
|
program.command("mcp-server").description("Start an MCP (Model Context Protocol) server for IDE integration").action(async () => {
|
|
2069
|
-
const { startMcpServer } = await import("../server-
|
|
2330
|
+
const { startMcpServer } = await import("../server-MHMAYXWZ.js");
|
|
2070
2331
|
await startMcpServer();
|
|
2071
2332
|
});
|
|
2072
2333
|
await program.parseAsync(process.argv);
|