agentbnb 9.0.2 → 9.0.3
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
|
@@ -299,7 +299,7 @@ Skills: ${skills2.skillCount} skill(s) in ${skills2.path}`);
|
|
|
299
299
|
}
|
|
300
300
|
|
|
301
301
|
// src/cli/index.ts
|
|
302
|
-
var VERSION = true ? "9.0.
|
|
302
|
+
var VERSION = true ? "9.0.3" : "0.0.0-dev";
|
|
303
303
|
function loadIdentityAuth(owner) {
|
|
304
304
|
const configDir = getConfigDir();
|
|
305
305
|
let keys;
|
|
@@ -560,8 +560,8 @@ program.command("publish-skills").description("Publish capabilities from skills.
|
|
|
560
560
|
db.close();
|
|
561
561
|
}
|
|
562
562
|
console.log(`Published ${skills2.length} skill(s) to local registry`);
|
|
563
|
-
for (const
|
|
564
|
-
console.log(` - ${
|
|
563
|
+
for (const skill2 of skills2) {
|
|
564
|
+
console.log(` - ${skill2.id}: ${skill2.name} (${skill2.pricing.credits_per_call} cr/call)`);
|
|
565
565
|
}
|
|
566
566
|
});
|
|
567
567
|
program.command("sync").description("Push all local capability cards to the configured remote registry").option("--registry <url>", "Remote registry URL (overrides config.registry)").option("--json", "Output as JSON").action(async (opts) => {
|
|
@@ -735,10 +735,10 @@ ${displayName} (${shortId}) [${tags}]`);
|
|
|
735
735
|
const skills2 = Array.isArray(raw["skills"]) ? raw["skills"] : [];
|
|
736
736
|
if (skills2.length > 0) {
|
|
737
737
|
console.log(" Skills:");
|
|
738
|
-
for (const
|
|
739
|
-
const price = String(
|
|
740
|
-
const desc = (
|
|
741
|
-
console.log(` ${col(
|
|
738
|
+
for (const skill2 of skills2) {
|
|
739
|
+
const price = String(skill2.pricing?.credits_per_call ?? "?");
|
|
740
|
+
const desc = (skill2.description ?? "").slice(0, 50);
|
|
741
|
+
console.log(` ${col(skill2.id, 24)} ${col(price + " cr", 8)} ${desc}`);
|
|
742
742
|
}
|
|
743
743
|
totalSkills += skills2.length;
|
|
744
744
|
} else if (card.pricing?.credits_per_call != null) {
|
|
@@ -1496,12 +1496,12 @@ openclaw.command("sync").description("Read SOUL.md and publish/update a v2.0 cap
|
|
|
1496
1496
|
try {
|
|
1497
1497
|
const card = publishFromSoulV2(db, content, config.owner, sharedSkills);
|
|
1498
1498
|
console.log(`Published card ${card.id} with ${card.skills.length} skill(s) (from ${resolvedSoulPath})`);
|
|
1499
|
-
for (const
|
|
1500
|
-
const stats = getPricingStats(db,
|
|
1499
|
+
for (const skill2 of card.skills) {
|
|
1500
|
+
const stats = getPricingStats(db, skill2.name);
|
|
1501
1501
|
if (stats.count > 0) {
|
|
1502
|
-
console.log(` ${
|
|
1502
|
+
console.log(` ${skill2.name}: ${skill2.pricing.credits_per_call} cr (market: ${stats.min}-${stats.max} cr, median ${stats.median}, ${stats.count} providers)`);
|
|
1503
1503
|
} else {
|
|
1504
|
-
console.log(` ${
|
|
1504
|
+
console.log(` ${skill2.name}: ${skill2.pricing.credits_per_call} cr (no market data yet)`);
|
|
1505
1505
|
}
|
|
1506
1506
|
}
|
|
1507
1507
|
} catch (err) {
|
|
@@ -1531,8 +1531,8 @@ openclaw.command("status").description("Show OpenClaw integration status, tier c
|
|
|
1531
1531
|
console.log(`Balance: ${status.balance} credits`);
|
|
1532
1532
|
console.log(`Reserve: ${status.reserve} credits`);
|
|
1533
1533
|
console.log(`Skills: ${status.skills.length}`);
|
|
1534
|
-
for (const
|
|
1535
|
-
console.log(` - ${
|
|
1534
|
+
for (const skill2 of status.skills) {
|
|
1535
|
+
console.log(` - ${skill2.id}: ${skill2.name} (idle: ${skill2.idle_rate ?? "N/A"}, online: ${skill2.online})`);
|
|
1536
1536
|
}
|
|
1537
1537
|
} finally {
|
|
1538
1538
|
db.close();
|
|
@@ -1694,6 +1694,11 @@ Feedback for skill: ${opts.skill} (${feedbacks.length} entries)
|
|
|
1694
1694
|
}
|
|
1695
1695
|
});
|
|
1696
1696
|
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);
|
|
1697
|
+
var skill = program.command("skill").description("Skill management commands");
|
|
1698
|
+
skill.command("wrap").description("Wrap a CLI command as a rentable AgentBnB skill").option("--name <name>", "Skill name").option("--command <cmd>", "Command template with ${params.x} placeholders").option("--description <desc>", "Short description").option("--price <credits>", 'Price per call (number or "auto")').option("--category <cat>", "Category for pricing hints").option("--inputs <json>", "Input schema JSON override").option("--outputs <json>", "Output schema JSON override").option("--tags <tags>", "Comma-separated tags").option("--auto <binary>", "Auto-detect subcommands from CLI binary").option("--from-help <binary>", "Parse --help to generate skill definition").option("--scan", "Scan PATH for all cli-anything-* binaries").option("--dry-run", "Preview without writing").option("-y, --yes", "Skip confirmation prompts").action(async (opts) => {
|
|
1699
|
+
const { runSkillWrap } = await import("../skill-wrap-YLCJMFEJ.js");
|
|
1700
|
+
await runSkillWrap(opts);
|
|
1701
|
+
});
|
|
1697
1702
|
var did = program.command("did").description("Decentralized Identity commands");
|
|
1698
1703
|
did.command("show").description("Display local agent DID identifiers").option("--json", "Output as JSON").action(async (opts) => {
|
|
1699
1704
|
const { didShow, didShowJson } = await import("../did-action-MQLDT4RF.js");
|
|
@@ -1722,7 +1727,7 @@ credits.command("grant <agent_id> <amount>").description("Admin: grant credits t
|
|
|
1722
1727
|
await creditsGrant(agentId, amount);
|
|
1723
1728
|
});
|
|
1724
1729
|
program.command("mcp-server").description("Start an MCP (Model Context Protocol) server for IDE integration").action(async () => {
|
|
1725
|
-
const { startMcpServer } = await import("../server-
|
|
1730
|
+
const { startMcpServer } = await import("../server-OCCAVVDF.js");
|
|
1726
1731
|
await startMcpServer();
|
|
1727
1732
|
});
|
|
1728
1733
|
await program.parseAsync(process.argv);
|
|
@@ -258,7 +258,7 @@ function registerPublishTool(server, ctx) {
|
|
|
258
258
|
}
|
|
259
259
|
|
|
260
260
|
// src/mcp/server.ts
|
|
261
|
-
var VERSION = true ? "9.0.
|
|
261
|
+
var VERSION = true ? "9.0.3" : "0.0.0-dev";
|
|
262
262
|
async function startMcpServer() {
|
|
263
263
|
const config = loadConfig();
|
|
264
264
|
if (!config) {
|
|
@@ -0,0 +1,364 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getConfigDir
|
|
3
|
+
} from "./chunk-3XPBFF6H.js";
|
|
4
|
+
|
|
5
|
+
// src/cli/skill-wrap.ts
|
|
6
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
7
|
+
import { join } from "path";
|
|
8
|
+
import { execSync } from "child_process";
|
|
9
|
+
import { createInterface } from "readline";
|
|
10
|
+
import yaml from "js-yaml";
|
|
11
|
+
var CATEGORY_PRICES = {
|
|
12
|
+
"3d-rendering": 15,
|
|
13
|
+
"image-processing": 8,
|
|
14
|
+
"video-editing": 12,
|
|
15
|
+
"audio-processing": 8,
|
|
16
|
+
"document-generation": 5,
|
|
17
|
+
"code-execution": 5,
|
|
18
|
+
"web-crawling": 3,
|
|
19
|
+
"data-analysis": 10,
|
|
20
|
+
"custom": 5
|
|
21
|
+
};
|
|
22
|
+
var BINARY_CATEGORY_HINTS = [
|
|
23
|
+
[["blender", "3d", "render"], "3d-rendering"],
|
|
24
|
+
[["gimp", "imagemagick", "magick", "sharp", "image"], "image-processing"],
|
|
25
|
+
[["ffmpeg", "video", "premiere", "davinci"], "video-editing"],
|
|
26
|
+
[["sox", "audio", "elevenlabs", "tts", "whisper"], "audio-processing"],
|
|
27
|
+
[["libreoffice", "pandoc", "latex", "pdf", "doc"], "document-generation"],
|
|
28
|
+
[["node", "python", "ruby", "code", "claude"], "code-execution"],
|
|
29
|
+
[["curl", "wget", "crawl", "scrape", "fetch"], "web-crawling"],
|
|
30
|
+
[["pandas", "data", "csv", "sql", "analyze"], "data-analysis"]
|
|
31
|
+
];
|
|
32
|
+
function extractParamsFromTemplate(command) {
|
|
33
|
+
const regex = /\$\{params\.(\w+)\}/g;
|
|
34
|
+
const params = [];
|
|
35
|
+
let match;
|
|
36
|
+
while ((match = regex.exec(command)) !== null) {
|
|
37
|
+
if (!params.includes(match[1])) {
|
|
38
|
+
params.push(match[1]);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
return params;
|
|
42
|
+
}
|
|
43
|
+
function parseHelpOutput(text) {
|
|
44
|
+
const lines = text.split("\n");
|
|
45
|
+
const subcommands = [];
|
|
46
|
+
let description = "";
|
|
47
|
+
for (const line of lines) {
|
|
48
|
+
const trimmed = line.trim();
|
|
49
|
+
if (!trimmed) continue;
|
|
50
|
+
if (/^(usage|options|commands|flags):/i.test(trimmed)) continue;
|
|
51
|
+
if (trimmed.startsWith("-")) continue;
|
|
52
|
+
if (trimmed.startsWith("$")) continue;
|
|
53
|
+
description = trimmed;
|
|
54
|
+
break;
|
|
55
|
+
}
|
|
56
|
+
let inCommandSection = false;
|
|
57
|
+
for (const line of lines) {
|
|
58
|
+
const trimmed = line.trim();
|
|
59
|
+
if (/^(commands|available commands|subcommands|positional arguments):/i.test(trimmed)) {
|
|
60
|
+
inCommandSection = true;
|
|
61
|
+
continue;
|
|
62
|
+
}
|
|
63
|
+
if (inCommandSection && /^(options|flags|global|examples):/i.test(trimmed)) {
|
|
64
|
+
inCommandSection = false;
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (inCommandSection && trimmed) {
|
|
68
|
+
const match = trimmed.match(/^(\S+)\s{2,}(.+)$/);
|
|
69
|
+
if (match) {
|
|
70
|
+
subcommands.push({ name: match[1], description: match[2].trim() });
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return { description, subcommands };
|
|
75
|
+
}
|
|
76
|
+
async function detectCliInfo(binary) {
|
|
77
|
+
try {
|
|
78
|
+
execSync(`which ${binary}`, { stdio: "pipe", timeout: 5e3 });
|
|
79
|
+
} catch {
|
|
80
|
+
throw new Error(`CLI not found: ${binary}. Is it installed and on PATH?`);
|
|
81
|
+
}
|
|
82
|
+
let helpText = "";
|
|
83
|
+
try {
|
|
84
|
+
helpText = execSync(`${binary} --help 2>&1`, { encoding: "utf-8", timeout: 1e4 });
|
|
85
|
+
} catch (err) {
|
|
86
|
+
const stderr = err.stdout ?? "";
|
|
87
|
+
helpText = stderr || `CLI tool: ${binary}`;
|
|
88
|
+
}
|
|
89
|
+
const parsed = parseHelpOutput(helpText);
|
|
90
|
+
const baseName = binary.replace(/^cli-anything-/, "");
|
|
91
|
+
return {
|
|
92
|
+
name: baseName,
|
|
93
|
+
description: parsed.description || `CLI tool: ${binary}`,
|
|
94
|
+
subcommands: parsed.subcommands
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
function suggestPrice(binary, category) {
|
|
98
|
+
if (category && CATEGORY_PRICES[category] !== void 0) {
|
|
99
|
+
return CATEGORY_PRICES[category];
|
|
100
|
+
}
|
|
101
|
+
const lower = binary.toLowerCase();
|
|
102
|
+
for (const [keywords, cat] of BINARY_CATEGORY_HINTS) {
|
|
103
|
+
if (keywords.some((kw) => lower.includes(kw))) {
|
|
104
|
+
return CATEGORY_PRICES[cat] ?? 5;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return 5;
|
|
108
|
+
}
|
|
109
|
+
function getSkillsYamlPath(configDir) {
|
|
110
|
+
return join(configDir ?? getConfigDir(), "skills.yaml");
|
|
111
|
+
}
|
|
112
|
+
function appendToSkillsYaml(skillDef, configDir) {
|
|
113
|
+
const dir = configDir ?? getConfigDir();
|
|
114
|
+
const yamlPath = getSkillsYamlPath(dir);
|
|
115
|
+
if (!existsSync(dir)) mkdirSync(dir, { recursive: true });
|
|
116
|
+
let skills = [];
|
|
117
|
+
if (existsSync(yamlPath)) {
|
|
118
|
+
const content = readFileSync(yamlPath, "utf-8");
|
|
119
|
+
const parsed = yaml.load(content);
|
|
120
|
+
if (Array.isArray(parsed)) {
|
|
121
|
+
skills = parsed;
|
|
122
|
+
} else if (parsed && typeof parsed === "object" && "skills" in parsed) {
|
|
123
|
+
skills = parsed.skills ?? [];
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const newId = skillDef["id"];
|
|
127
|
+
const existing = skills.find((s) => s["id"] === newId);
|
|
128
|
+
if (existing) {
|
|
129
|
+
throw new Error(`Skill "${newId}" already exists in skills.yaml. Remove it first or use a different name.`);
|
|
130
|
+
}
|
|
131
|
+
skills.push(skillDef);
|
|
132
|
+
const header = "# AgentBnB skills configuration \u2014 managed by agentbnb skill wrap\n";
|
|
133
|
+
writeFileSync(yamlPath, header + yaml.dump(skills, { lineWidth: 120 }), "utf-8");
|
|
134
|
+
}
|
|
135
|
+
function scanCliAnythingBinaries() {
|
|
136
|
+
try {
|
|
137
|
+
const result = execSync(`bash -c 'compgen -c | grep "^cli-anything-" | sort -u'`, {
|
|
138
|
+
encoding: "utf-8",
|
|
139
|
+
timeout: 1e4
|
|
140
|
+
});
|
|
141
|
+
return result.trim().split("\n").filter(Boolean);
|
|
142
|
+
} catch {
|
|
143
|
+
const pathDirs = (process.env["PATH"] ?? "").split(":");
|
|
144
|
+
const found = /* @__PURE__ */ new Set();
|
|
145
|
+
for (const dir of pathDirs) {
|
|
146
|
+
try {
|
|
147
|
+
const entries = execSync(`ls "${dir}" 2>/dev/null | grep "^cli-anything-"`, {
|
|
148
|
+
encoding: "utf-8",
|
|
149
|
+
timeout: 5e3
|
|
150
|
+
});
|
|
151
|
+
for (const entry of entries.trim().split("\n").filter(Boolean)) {
|
|
152
|
+
found.add(entry);
|
|
153
|
+
}
|
|
154
|
+
} catch {
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return [...found].sort();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
async function prompt(question, defaultVal) {
|
|
161
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
162
|
+
const suffix = defaultVal ? ` (${defaultVal})` : "";
|
|
163
|
+
return new Promise((resolve) => {
|
|
164
|
+
rl.question(`${question}${suffix}: `, (answer) => {
|
|
165
|
+
rl.close();
|
|
166
|
+
resolve(answer.trim() || defaultVal || "");
|
|
167
|
+
});
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
async function runSkillWrap(opts) {
|
|
171
|
+
if (opts.scan) {
|
|
172
|
+
const binaries = scanCliAnythingBinaries();
|
|
173
|
+
if (binaries.length === 0) {
|
|
174
|
+
console.log("No cli-anything-* binaries found on PATH.");
|
|
175
|
+
return;
|
|
176
|
+
}
|
|
177
|
+
console.log(`Found ${binaries.length} CLI-Anything tool(s):`);
|
|
178
|
+
binaries.forEach((b) => console.log(` ${b}`));
|
|
179
|
+
if (!opts.yes && !opts.dryRun) {
|
|
180
|
+
const confirm = await prompt("\nWrap all as skills? (Y/n)", "Y");
|
|
181
|
+
if (confirm.toLowerCase() === "n") return;
|
|
182
|
+
}
|
|
183
|
+
let totalSkills = 0;
|
|
184
|
+
for (const binary of binaries) {
|
|
185
|
+
try {
|
|
186
|
+
const info = await detectCliInfo(binary);
|
|
187
|
+
const created = await wrapDetectedCli(binary, info, opts);
|
|
188
|
+
totalSkills += created;
|
|
189
|
+
} catch (err) {
|
|
190
|
+
console.error(` Skipping ${binary}: ${err.message}`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
console.log(`
|
|
194
|
+
Created ${totalSkills} skill(s) from ${binaries.length} CLI(s).`);
|
|
195
|
+
if (!opts.dryRun) {
|
|
196
|
+
console.log(`Run 'agentbnb serve' to start accepting requests.`);
|
|
197
|
+
}
|
|
198
|
+
return;
|
|
199
|
+
}
|
|
200
|
+
if (opts.auto) {
|
|
201
|
+
const info = await detectCliInfo(opts.auto);
|
|
202
|
+
await wrapDetectedCli(opts.auto, info, opts);
|
|
203
|
+
return;
|
|
204
|
+
}
|
|
205
|
+
if (opts.fromHelp) {
|
|
206
|
+
const info = await detectCliInfo(opts.fromHelp);
|
|
207
|
+
if (info.subcommands.length === 0) {
|
|
208
|
+
const name = opts.name ?? info.name;
|
|
209
|
+
const price2 = resolvePrice(opts.price, opts.fromHelp, opts.category);
|
|
210
|
+
await wrapSingleSkill({
|
|
211
|
+
name,
|
|
212
|
+
command: `${opts.fromHelp} \${params.input}`,
|
|
213
|
+
description: opts.description ?? info.description,
|
|
214
|
+
price: price2,
|
|
215
|
+
category: opts.category,
|
|
216
|
+
tags: opts.tags,
|
|
217
|
+
dryRun: opts.dryRun
|
|
218
|
+
});
|
|
219
|
+
} else {
|
|
220
|
+
await wrapDetectedCli(opts.fromHelp, info, opts);
|
|
221
|
+
}
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
if (!opts.name && !opts.command) {
|
|
225
|
+
const command = await prompt("CLI command to wrap");
|
|
226
|
+
if (!command) {
|
|
227
|
+
console.error("Command is required.");
|
|
228
|
+
process.exit(1);
|
|
229
|
+
}
|
|
230
|
+
const baseName = command.split(/\s+/)[0].replace(/^.*\//, "").replace(/^cli-anything-/, "");
|
|
231
|
+
const name = await prompt("Skill name", baseName);
|
|
232
|
+
const description = await prompt("Short description");
|
|
233
|
+
const priceStr = await prompt("Price (credits per call)", "5");
|
|
234
|
+
const category = await prompt("Category (optional)");
|
|
235
|
+
opts = { ...opts, name, command, description, price: priceStr, category: category || void 0 };
|
|
236
|
+
}
|
|
237
|
+
if (!opts.name || !opts.command) {
|
|
238
|
+
console.error("Error: --name and --command are required (or use --auto/--from-help/--scan).");
|
|
239
|
+
process.exit(1);
|
|
240
|
+
}
|
|
241
|
+
const price = resolvePrice(opts.price, opts.command, opts.category);
|
|
242
|
+
await wrapSingleSkill({
|
|
243
|
+
name: opts.name,
|
|
244
|
+
command: opts.command,
|
|
245
|
+
description: opts.description,
|
|
246
|
+
price,
|
|
247
|
+
category: opts.category,
|
|
248
|
+
tags: opts.tags,
|
|
249
|
+
inputs: opts.inputs,
|
|
250
|
+
outputs: opts.outputs,
|
|
251
|
+
dryRun: opts.dryRun
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
function resolvePrice(priceStr, binary, category) {
|
|
255
|
+
if (!priceStr || priceStr === "auto") {
|
|
256
|
+
return suggestPrice(binary, category);
|
|
257
|
+
}
|
|
258
|
+
const n = parseInt(priceStr, 10);
|
|
259
|
+
if (!Number.isFinite(n) || n < 1) {
|
|
260
|
+
console.error('Error: --price must be a positive integer or "auto".');
|
|
261
|
+
process.exit(1);
|
|
262
|
+
}
|
|
263
|
+
return n;
|
|
264
|
+
}
|
|
265
|
+
async function wrapSingleSkill(opts) {
|
|
266
|
+
const params = extractParamsFromTemplate(opts.command);
|
|
267
|
+
const baseCommand = opts.command.split(/\s+/)[0] ?? "";
|
|
268
|
+
const skillDef = {
|
|
269
|
+
id: opts.name,
|
|
270
|
+
type: "command",
|
|
271
|
+
name: opts.name,
|
|
272
|
+
description: opts.description || `Wrapped CLI: ${baseCommand}`,
|
|
273
|
+
command: opts.command,
|
|
274
|
+
output_type: "text",
|
|
275
|
+
pricing: { credits_per_call: opts.price }
|
|
276
|
+
};
|
|
277
|
+
if (opts.category) {
|
|
278
|
+
skillDef["category"] = opts.category;
|
|
279
|
+
}
|
|
280
|
+
const tags = opts.tags ? opts.tags.split(",").map((t) => t.trim()).filter(Boolean) : [];
|
|
281
|
+
if (tags.length > 0) {
|
|
282
|
+
skillDef["metadata"] = { tags };
|
|
283
|
+
}
|
|
284
|
+
if (opts.inputs) {
|
|
285
|
+
try {
|
|
286
|
+
skillDef["_input_hint"] = JSON.parse(opts.inputs);
|
|
287
|
+
} catch {
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
if (opts.dryRun) {
|
|
291
|
+
console.log("--- Dry Run Preview ---");
|
|
292
|
+
console.log(yaml.dump([skillDef], { lineWidth: 120 }));
|
|
293
|
+
console.log(`Parameters detected: ${params.length > 0 ? params.join(", ") : "(none)"}`);
|
|
294
|
+
console.log(`Price: ${opts.price} cr/call`);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
try {
|
|
298
|
+
appendToSkillsYaml(skillDef);
|
|
299
|
+
} catch (err) {
|
|
300
|
+
console.error(`Error: ${err.message}`);
|
|
301
|
+
process.exit(1);
|
|
302
|
+
}
|
|
303
|
+
console.log(`Created skill: ${opts.name} (${opts.price} cr/call)`);
|
|
304
|
+
console.log(` Command: ${opts.command}`);
|
|
305
|
+
if (params.length > 0) console.log(` Params: ${params.join(", ")}`);
|
|
306
|
+
console.log(` Added to ${getSkillsYamlPath()}`);
|
|
307
|
+
console.log(` Run 'agentbnb serve' to start accepting requests.`);
|
|
308
|
+
}
|
|
309
|
+
async function wrapDetectedCli(binary, info, opts) {
|
|
310
|
+
const baseName = binary.replace(/^cli-anything-/, "");
|
|
311
|
+
if (info.subcommands.length === 0) {
|
|
312
|
+
const price = resolvePrice(opts.price, binary, opts.category);
|
|
313
|
+
await wrapSingleSkill({
|
|
314
|
+
name: opts.name ?? baseName,
|
|
315
|
+
command: `${binary} \${params.input}`,
|
|
316
|
+
description: opts.description ?? info.description,
|
|
317
|
+
price,
|
|
318
|
+
category: opts.category,
|
|
319
|
+
tags: opts.tags,
|
|
320
|
+
dryRun: opts.dryRun
|
|
321
|
+
});
|
|
322
|
+
return 1;
|
|
323
|
+
}
|
|
324
|
+
console.log(`
|
|
325
|
+
${binary} \u2014 ${info.description}`);
|
|
326
|
+
console.log(`Found ${info.subcommands.length} subcommand(s):`);
|
|
327
|
+
for (const sub of info.subcommands) {
|
|
328
|
+
const price = suggestPrice(`${baseName}-${sub.name}`, opts.category);
|
|
329
|
+
console.log(` ${sub.name.padEnd(20)} ${String(price).padEnd(4)} cr ${sub.description}`);
|
|
330
|
+
}
|
|
331
|
+
if (!opts.yes && !opts.dryRun) {
|
|
332
|
+
const confirm = await prompt("\nCreate skills for all subcommands? (Y/n)", "Y");
|
|
333
|
+
if (confirm.toLowerCase() === "n") return 0;
|
|
334
|
+
}
|
|
335
|
+
let created = 0;
|
|
336
|
+
for (const sub of info.subcommands) {
|
|
337
|
+
const skillName = `${baseName}-${sub.name}`;
|
|
338
|
+
const price = resolvePrice(opts.price, `${baseName}-${sub.name}`, opts.category);
|
|
339
|
+
try {
|
|
340
|
+
await wrapSingleSkill({
|
|
341
|
+
name: skillName,
|
|
342
|
+
command: `${binary} ${sub.name} \${params.input}`,
|
|
343
|
+
description: sub.description,
|
|
344
|
+
price,
|
|
345
|
+
category: opts.category,
|
|
346
|
+
tags: opts.tags,
|
|
347
|
+
dryRun: opts.dryRun
|
|
348
|
+
});
|
|
349
|
+
created++;
|
|
350
|
+
} catch (err) {
|
|
351
|
+
console.error(` Skipping ${skillName}: ${err.message}`);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return created;
|
|
355
|
+
}
|
|
356
|
+
export {
|
|
357
|
+
appendToSkillsYaml,
|
|
358
|
+
detectCliInfo,
|
|
359
|
+
extractParamsFromTemplate,
|
|
360
|
+
parseHelpOutput,
|
|
361
|
+
runSkillWrap,
|
|
362
|
+
scanCliAnythingBinaries,
|
|
363
|
+
suggestPrice
|
|
364
|
+
};
|