danube-cli 0.2.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/dist/danube.mjs +1792 -0
- package/package.json +33 -0
package/dist/danube.mjs
ADDED
|
@@ -0,0 +1,1792 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { createRequire } from "node:module";
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
7
|
+
function __accessProp(key) {
|
|
8
|
+
return this[key];
|
|
9
|
+
}
|
|
10
|
+
var __toCommonJS = (from) => {
|
|
11
|
+
var entry = (__moduleCache ??= new WeakMap).get(from), desc;
|
|
12
|
+
if (entry)
|
|
13
|
+
return entry;
|
|
14
|
+
entry = __defProp({}, "__esModule", { value: true });
|
|
15
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
16
|
+
for (var key of __getOwnPropNames(from))
|
|
17
|
+
if (!__hasOwnProp.call(entry, key))
|
|
18
|
+
__defProp(entry, key, {
|
|
19
|
+
get: __accessProp.bind(from, key),
|
|
20
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
__moduleCache.set(from, entry);
|
|
24
|
+
return entry;
|
|
25
|
+
};
|
|
26
|
+
var __moduleCache;
|
|
27
|
+
var __returnValue = (v) => v;
|
|
28
|
+
function __exportSetter(name, newValue) {
|
|
29
|
+
this[name] = __returnValue.bind(null, newValue);
|
|
30
|
+
}
|
|
31
|
+
var __export = (target, all) => {
|
|
32
|
+
for (var name in all)
|
|
33
|
+
__defProp(target, name, {
|
|
34
|
+
get: all[name],
|
|
35
|
+
enumerable: true,
|
|
36
|
+
configurable: true,
|
|
37
|
+
set: __exportSetter.bind(all, name)
|
|
38
|
+
});
|
|
39
|
+
};
|
|
40
|
+
var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
41
|
+
var __require = /* @__PURE__ */ createRequire(import.meta.url);
|
|
42
|
+
|
|
43
|
+
// src/lib/output.ts
|
|
44
|
+
import chalk from "chalk";
|
|
45
|
+
function setHumanMode(enabled) {
|
|
46
|
+
humanMode = enabled;
|
|
47
|
+
}
|
|
48
|
+
function setQuietMode(enabled) {
|
|
49
|
+
quietMode = enabled;
|
|
50
|
+
}
|
|
51
|
+
function output(data) {
|
|
52
|
+
if (quietMode)
|
|
53
|
+
return;
|
|
54
|
+
console.log(JSON.stringify(data, null, 2));
|
|
55
|
+
}
|
|
56
|
+
function outputTable(items, columns, title) {
|
|
57
|
+
if (!humanMode) {
|
|
58
|
+
output(items);
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
if (title) {
|
|
62
|
+
console.log(`
|
|
63
|
+
${chalk.bold(title)}`);
|
|
64
|
+
}
|
|
65
|
+
if (items.length === 0) {
|
|
66
|
+
console.log(chalk.dim(" No results found."));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
const rows = items;
|
|
70
|
+
const widths = columns.map((col) => {
|
|
71
|
+
const headerLen = col.header.length;
|
|
72
|
+
const maxDataLen = rows.reduce((max, item) => {
|
|
73
|
+
const val = String(item[col.key] ?? "");
|
|
74
|
+
return Math.max(max, val.length);
|
|
75
|
+
}, 0);
|
|
76
|
+
return Math.min(Math.max(headerLen, maxDataLen), 60);
|
|
77
|
+
});
|
|
78
|
+
const header = columns.map((col, i) => chalk.cyan.bold(col.header.padEnd(widths[i]))).join(" ");
|
|
79
|
+
console.log(` ${header}`);
|
|
80
|
+
console.log(` ${widths.map((w) => "─".repeat(w)).join(" ")}`);
|
|
81
|
+
for (const item of rows) {
|
|
82
|
+
const row = columns.map((col, i) => {
|
|
83
|
+
let val = String(item[col.key] ?? "");
|
|
84
|
+
if (val.length > widths[i]) {
|
|
85
|
+
val = val.slice(0, widths[i] - 1) + "…";
|
|
86
|
+
}
|
|
87
|
+
val = val.padEnd(widths[i]);
|
|
88
|
+
if (col.style === "dim")
|
|
89
|
+
return chalk.dim(val);
|
|
90
|
+
if (col.style === "bold")
|
|
91
|
+
return chalk.bold(val);
|
|
92
|
+
return val;
|
|
93
|
+
}).join(" ");
|
|
94
|
+
console.log(` ${row}`);
|
|
95
|
+
}
|
|
96
|
+
console.log();
|
|
97
|
+
}
|
|
98
|
+
function outputDetail(data, title) {
|
|
99
|
+
if (!humanMode) {
|
|
100
|
+
output(data);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (title) {
|
|
104
|
+
console.log(`
|
|
105
|
+
${chalk.bold(title)}`);
|
|
106
|
+
}
|
|
107
|
+
const record = data;
|
|
108
|
+
for (const [key, value] of Object.entries(record)) {
|
|
109
|
+
if (value === undefined || value === null)
|
|
110
|
+
continue;
|
|
111
|
+
if (typeof value === "object") {
|
|
112
|
+
console.log(` ${chalk.cyan(key + ":")}`);
|
|
113
|
+
console.log(` ${JSON.stringify(value, null, 2).split(`
|
|
114
|
+
`).join(`
|
|
115
|
+
`)}`);
|
|
116
|
+
} else {
|
|
117
|
+
console.log(` ${chalk.cyan(key + ":")} ${value}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
console.log();
|
|
121
|
+
}
|
|
122
|
+
function outputError(error, message, extra) {
|
|
123
|
+
if (humanMode) {
|
|
124
|
+
console.error(`${chalk.red("✗")} ${message}`);
|
|
125
|
+
if (extra) {
|
|
126
|
+
for (const [key, value] of Object.entries(extra)) {
|
|
127
|
+
if (value !== undefined && value !== null) {
|
|
128
|
+
console.error(` ${chalk.dim(key + ":")} ${value}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
} else {
|
|
133
|
+
const err = { error, message };
|
|
134
|
+
if (extra)
|
|
135
|
+
Object.assign(err, extra);
|
|
136
|
+
console.error(JSON.stringify(err));
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
function outputSuccess(message, data) {
|
|
140
|
+
if (humanMode) {
|
|
141
|
+
console.log(`${chalk.green("✓")} ${message}`);
|
|
142
|
+
if (data) {
|
|
143
|
+
for (const [key, value] of Object.entries(data)) {
|
|
144
|
+
console.log(` ${chalk.cyan(key + ":")} ${value}`);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
const result = { success: true, message };
|
|
149
|
+
if (data)
|
|
150
|
+
Object.assign(result, data);
|
|
151
|
+
output(result);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
var humanMode = false, quietMode = false;
|
|
155
|
+
var init_output = () => {};
|
|
156
|
+
|
|
157
|
+
// package.json
|
|
158
|
+
var package_default;
|
|
159
|
+
var init_package = __esm(() => {
|
|
160
|
+
package_default = {
|
|
161
|
+
name: "danube-cli",
|
|
162
|
+
version: "0.2.0",
|
|
163
|
+
description: "Danube CLI — agent-first tool infrastructure for AI agents",
|
|
164
|
+
type: "module",
|
|
165
|
+
license: "MIT",
|
|
166
|
+
repository: {
|
|
167
|
+
type: "git",
|
|
168
|
+
url: "https://github.com/danubeai/danube-cli"
|
|
169
|
+
},
|
|
170
|
+
keywords: ["danube", "cli", "ai", "tools", "mcp", "agent"],
|
|
171
|
+
bin: {
|
|
172
|
+
danube: "./dist/danube.mjs"
|
|
173
|
+
},
|
|
174
|
+
files: [
|
|
175
|
+
"dist",
|
|
176
|
+
"README.md"
|
|
177
|
+
],
|
|
178
|
+
scripts: {
|
|
179
|
+
dev: "bun run bin/danube.ts",
|
|
180
|
+
build: "bash scripts/build.sh",
|
|
181
|
+
prepublishOnly: "npm run build",
|
|
182
|
+
test: "bun test"
|
|
183
|
+
},
|
|
184
|
+
dependencies: {
|
|
185
|
+
chalk: "^5.4.1",
|
|
186
|
+
commander: "^13.1.0"
|
|
187
|
+
},
|
|
188
|
+
devDependencies: {
|
|
189
|
+
"@types/bun": "latest",
|
|
190
|
+
typescript: "^5.8.0"
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
});
|
|
194
|
+
|
|
195
|
+
// src/lib/version.ts
|
|
196
|
+
var VERSION;
|
|
197
|
+
var init_version = __esm(() => {
|
|
198
|
+
init_package();
|
|
199
|
+
VERSION = package_default.version;
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
// src/index.ts
|
|
203
|
+
import { Command } from "commander";
|
|
204
|
+
var ctx;
|
|
205
|
+
var init_src = __esm(() => {
|
|
206
|
+
init_output();
|
|
207
|
+
init_version();
|
|
208
|
+
ctx = {
|
|
209
|
+
human: false,
|
|
210
|
+
apiKey: undefined,
|
|
211
|
+
profile: "default",
|
|
212
|
+
verbose: false,
|
|
213
|
+
quiet: false,
|
|
214
|
+
noColor: false
|
|
215
|
+
};
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
// src/lib/errors.ts
|
|
219
|
+
function handleErrors(fn) {
|
|
220
|
+
return async (...args) => {
|
|
221
|
+
try {
|
|
222
|
+
await fn(...args);
|
|
223
|
+
} catch (e) {
|
|
224
|
+
if (e instanceof ConfigurationRequiredError) {
|
|
225
|
+
outputError("auth_required", e.message, {
|
|
226
|
+
fix: e.serviceName ? `danube connect ${e.serviceName.toLowerCase().replace(/ /g, "-")}` : undefined,
|
|
227
|
+
service_id: e.serviceId,
|
|
228
|
+
configuration_url: e.configurationUrl
|
|
229
|
+
});
|
|
230
|
+
process.exit(EXIT_AUTH);
|
|
231
|
+
} else if (e instanceof AuthenticationError) {
|
|
232
|
+
outputError("not_authenticated", e.message, { fix: "danube login" });
|
|
233
|
+
process.exit(EXIT_AUTH);
|
|
234
|
+
} else if (e instanceof AuthorizationError) {
|
|
235
|
+
outputError("forbidden", e.message);
|
|
236
|
+
process.exit(EXIT_AUTH);
|
|
237
|
+
} else if (e instanceof RateLimitError) {
|
|
238
|
+
outputError("rate_limited", e.message, { retry_after: e.retryAfter });
|
|
239
|
+
process.exit(EXIT_RATE_LIMIT);
|
|
240
|
+
} else if (e instanceof NotFoundError) {
|
|
241
|
+
outputError("not_found", e.message, { resource: e.resource, identifier: e.identifier });
|
|
242
|
+
process.exit(EXIT_ERROR);
|
|
243
|
+
} else if (e instanceof ValidationError) {
|
|
244
|
+
outputError("validation_error", e.message);
|
|
245
|
+
process.exit(EXIT_ERROR);
|
|
246
|
+
} else if (e instanceof TimeoutError) {
|
|
247
|
+
outputError("timeout", e.message);
|
|
248
|
+
process.exit(EXIT_ERROR);
|
|
249
|
+
} else if (e instanceof ConnectionError) {
|
|
250
|
+
outputError("connection_error", e.message);
|
|
251
|
+
process.exit(EXIT_ERROR);
|
|
252
|
+
} else if (e instanceof DanubeError) {
|
|
253
|
+
outputError("error", e.message);
|
|
254
|
+
process.exit(EXIT_ERROR);
|
|
255
|
+
} else {
|
|
256
|
+
throw e;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
var EXIT_ERROR = 1, EXIT_AUTH = 2, EXIT_RATE_LIMIT = 3, DanubeError, AuthenticationError, AuthorizationError, NotFoundError, ValidationError, RateLimitError, ConfigurationRequiredError, ConnectionError, TimeoutError;
|
|
262
|
+
var init_errors = __esm(() => {
|
|
263
|
+
init_output();
|
|
264
|
+
DanubeError = class DanubeError extends Error {
|
|
265
|
+
statusCode;
|
|
266
|
+
constructor(message, statusCode) {
|
|
267
|
+
super(message);
|
|
268
|
+
this.statusCode = statusCode;
|
|
269
|
+
this.name = "DanubeError";
|
|
270
|
+
}
|
|
271
|
+
};
|
|
272
|
+
AuthenticationError = class AuthenticationError extends DanubeError {
|
|
273
|
+
constructor(message = "Not authenticated. Run 'danube login' to authenticate.") {
|
|
274
|
+
super(message, 401);
|
|
275
|
+
this.name = "AuthenticationError";
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
AuthorizationError = class AuthorizationError extends DanubeError {
|
|
279
|
+
constructor(message = "Forbidden.") {
|
|
280
|
+
super(message, 403);
|
|
281
|
+
this.name = "AuthorizationError";
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
NotFoundError = class NotFoundError extends DanubeError {
|
|
285
|
+
resource;
|
|
286
|
+
identifier;
|
|
287
|
+
constructor(message, resource, identifier) {
|
|
288
|
+
super(message, 404);
|
|
289
|
+
this.resource = resource;
|
|
290
|
+
this.identifier = identifier;
|
|
291
|
+
this.name = "NotFoundError";
|
|
292
|
+
}
|
|
293
|
+
};
|
|
294
|
+
ValidationError = class ValidationError extends DanubeError {
|
|
295
|
+
constructor(message) {
|
|
296
|
+
super(message, 422);
|
|
297
|
+
this.name = "ValidationError";
|
|
298
|
+
}
|
|
299
|
+
};
|
|
300
|
+
RateLimitError = class RateLimitError extends DanubeError {
|
|
301
|
+
retryAfter;
|
|
302
|
+
constructor(message = "Rate limited.", retryAfter) {
|
|
303
|
+
super(message, 429);
|
|
304
|
+
this.retryAfter = retryAfter;
|
|
305
|
+
this.name = "RateLimitError";
|
|
306
|
+
}
|
|
307
|
+
};
|
|
308
|
+
ConfigurationRequiredError = class ConfigurationRequiredError extends DanubeError {
|
|
309
|
+
serviceName;
|
|
310
|
+
serviceId;
|
|
311
|
+
configurationUrl;
|
|
312
|
+
constructor(message, serviceName, serviceId, configurationUrl) {
|
|
313
|
+
super(message, 412);
|
|
314
|
+
this.serviceName = serviceName;
|
|
315
|
+
this.serviceId = serviceId;
|
|
316
|
+
this.configurationUrl = configurationUrl;
|
|
317
|
+
this.name = "ConfigurationRequiredError";
|
|
318
|
+
}
|
|
319
|
+
};
|
|
320
|
+
ConnectionError = class ConnectionError extends DanubeError {
|
|
321
|
+
constructor(message = "Failed to connect to the Danube API.") {
|
|
322
|
+
super(message);
|
|
323
|
+
this.name = "ConnectionError";
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
TimeoutError = class TimeoutError extends DanubeError {
|
|
327
|
+
constructor(message = "Request timed out.") {
|
|
328
|
+
super(message);
|
|
329
|
+
this.name = "TimeoutError";
|
|
330
|
+
}
|
|
331
|
+
};
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// src/lib/config.ts
|
|
335
|
+
import { chmodSync } from "node:fs";
|
|
336
|
+
import { homedir } from "node:os";
|
|
337
|
+
import { join } from "node:path";
|
|
338
|
+
function ensureConfigDir() {
|
|
339
|
+
const { mkdirSync } = __require("node:fs");
|
|
340
|
+
try {
|
|
341
|
+
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
342
|
+
} catch {}
|
|
343
|
+
}
|
|
344
|
+
function readConfig() {
|
|
345
|
+
try {
|
|
346
|
+
const text = __require("node:fs").readFileSync(CONFIG_FILE, "utf-8");
|
|
347
|
+
return JSON.parse(text);
|
|
348
|
+
} catch {
|
|
349
|
+
return {};
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
function writeConfig(config) {
|
|
353
|
+
ensureConfigDir();
|
|
354
|
+
const { writeFileSync } = __require("node:fs");
|
|
355
|
+
writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + `
|
|
356
|
+
`, "utf-8");
|
|
357
|
+
chmodSync(CONFIG_FILE, 384);
|
|
358
|
+
}
|
|
359
|
+
function getProfile(profile = "default") {
|
|
360
|
+
const config = readConfig();
|
|
361
|
+
return config.profiles?.[profile] ?? {};
|
|
362
|
+
}
|
|
363
|
+
function saveApiKey(apiKey, profile = "default") {
|
|
364
|
+
const config = readConfig();
|
|
365
|
+
if (!config.profiles)
|
|
366
|
+
config.profiles = {};
|
|
367
|
+
if (!config.profiles[profile])
|
|
368
|
+
config.profiles[profile] = {};
|
|
369
|
+
config.profiles[profile].api_key = apiKey;
|
|
370
|
+
writeConfig(config);
|
|
371
|
+
}
|
|
372
|
+
function removeApiKey(profile = "default") {
|
|
373
|
+
const config = readConfig();
|
|
374
|
+
if (config.profiles?.[profile]) {
|
|
375
|
+
delete config.profiles[profile].api_key;
|
|
376
|
+
writeConfig(config);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
function getApiKey(flagApiKey, profile = "default") {
|
|
380
|
+
if (flagApiKey)
|
|
381
|
+
return flagApiKey;
|
|
382
|
+
const envKey = process.env.DANUBE_API_KEY;
|
|
383
|
+
if (envKey)
|
|
384
|
+
return envKey;
|
|
385
|
+
return getProfile(profile).api_key;
|
|
386
|
+
}
|
|
387
|
+
function getBaseUrl(profile = "default") {
|
|
388
|
+
const envUrl = process.env.DANUBE_API_URL;
|
|
389
|
+
if (envUrl)
|
|
390
|
+
return envUrl;
|
|
391
|
+
return getProfile(profile).base_url ?? DEFAULT_BASE_URL;
|
|
392
|
+
}
|
|
393
|
+
function configSet(key, value, profile = "default") {
|
|
394
|
+
const config = readConfig();
|
|
395
|
+
if (!config.profiles)
|
|
396
|
+
config.profiles = {};
|
|
397
|
+
if (!config.profiles[profile])
|
|
398
|
+
config.profiles[profile] = {};
|
|
399
|
+
config.profiles[profile][key] = value;
|
|
400
|
+
writeConfig(config);
|
|
401
|
+
}
|
|
402
|
+
function configGet(key, profile = "default") {
|
|
403
|
+
return getProfile(profile)[key];
|
|
404
|
+
}
|
|
405
|
+
function listProfiles() {
|
|
406
|
+
const config = readConfig();
|
|
407
|
+
return Object.keys(config.profiles ?? {});
|
|
408
|
+
}
|
|
409
|
+
var CONFIG_DIR, CONFIG_FILE, DEFAULT_BASE_URL = "https://api.danubeai.com";
|
|
410
|
+
var init_config = __esm(() => {
|
|
411
|
+
CONFIG_DIR = join(homedir(), ".danube");
|
|
412
|
+
CONFIG_FILE = join(CONFIG_DIR, "config.json");
|
|
413
|
+
});
|
|
414
|
+
|
|
415
|
+
// src/lib/api.ts
|
|
416
|
+
class ApiClient {
|
|
417
|
+
baseUrl;
|
|
418
|
+
apiKey;
|
|
419
|
+
constructor(baseUrl, apiKey) {
|
|
420
|
+
this.baseUrl = baseUrl;
|
|
421
|
+
this.apiKey = apiKey;
|
|
422
|
+
}
|
|
423
|
+
async request(method, path, opts) {
|
|
424
|
+
const url = new URL(path, this.baseUrl);
|
|
425
|
+
if (opts?.params) {
|
|
426
|
+
for (const [k, v] of Object.entries(opts.params)) {
|
|
427
|
+
if (v !== undefined)
|
|
428
|
+
url.searchParams.set(k, v);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
const headers = {
|
|
432
|
+
"User-Agent": `danube-cli/${VERSION}`,
|
|
433
|
+
"Content-Type": "application/json"
|
|
434
|
+
};
|
|
435
|
+
if (!opts?.noAuth && this.apiKey) {
|
|
436
|
+
headers["danube-api-key"] = this.apiKey;
|
|
437
|
+
}
|
|
438
|
+
let response;
|
|
439
|
+
try {
|
|
440
|
+
response = await fetch(url.toString(), {
|
|
441
|
+
method,
|
|
442
|
+
headers,
|
|
443
|
+
body: opts?.body ? JSON.stringify(opts.body) : undefined,
|
|
444
|
+
signal: AbortSignal.timeout(60000)
|
|
445
|
+
});
|
|
446
|
+
} catch (e) {
|
|
447
|
+
if (e instanceof DOMException && e.name === "AbortError") {
|
|
448
|
+
throw new TimeoutError(`Request timed out: ${method} ${path}`);
|
|
449
|
+
}
|
|
450
|
+
throw new ConnectionError(`Failed to connect to ${this.baseUrl}: ${e instanceof Error ? e.message : String(e)}`);
|
|
451
|
+
}
|
|
452
|
+
if (response.ok) {
|
|
453
|
+
const text = await response.text();
|
|
454
|
+
if (!text)
|
|
455
|
+
return;
|
|
456
|
+
return JSON.parse(text);
|
|
457
|
+
}
|
|
458
|
+
let errorBody = {};
|
|
459
|
+
try {
|
|
460
|
+
errorBody = await response.json();
|
|
461
|
+
} catch {}
|
|
462
|
+
const detail = errorBody.detail ?? errorBody.message ?? response.statusText;
|
|
463
|
+
switch (response.status) {
|
|
464
|
+
case 401:
|
|
465
|
+
throw new AuthenticationError(detail);
|
|
466
|
+
case 403:
|
|
467
|
+
throw new AuthorizationError(detail);
|
|
468
|
+
case 404:
|
|
469
|
+
throw new NotFoundError(detail);
|
|
470
|
+
case 412:
|
|
471
|
+
throw new ConfigurationRequiredError(detail, errorBody.service_name, errorBody.service_id, errorBody.configuration_url);
|
|
472
|
+
case 422:
|
|
473
|
+
throw new ValidationError(detail);
|
|
474
|
+
case 429: {
|
|
475
|
+
const retryAfter = response.headers.get("retry-after");
|
|
476
|
+
throw new RateLimitError(detail, retryAfter ? parseInt(retryAfter) : undefined);
|
|
477
|
+
}
|
|
478
|
+
default:
|
|
479
|
+
throw new DanubeError(`${response.status}: ${detail}`, response.status);
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
async get(path, params) {
|
|
483
|
+
return this.request("GET", path, { params });
|
|
484
|
+
}
|
|
485
|
+
async post(path, body) {
|
|
486
|
+
return this.request("POST", path, { body });
|
|
487
|
+
}
|
|
488
|
+
async delete(path) {
|
|
489
|
+
return this.request("DELETE", path);
|
|
490
|
+
}
|
|
491
|
+
async put(path, body) {
|
|
492
|
+
return this.request("PUT", path, { body });
|
|
493
|
+
}
|
|
494
|
+
async patch(path, body) {
|
|
495
|
+
return this.request("PATCH", path, { body });
|
|
496
|
+
}
|
|
497
|
+
async publicPost(path, body) {
|
|
498
|
+
return this.request("POST", path, { body, noAuth: true });
|
|
499
|
+
}
|
|
500
|
+
async publicGet(path, params) {
|
|
501
|
+
return this.request("GET", path, { params, noAuth: true });
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
function getClient(flagApiKey, profile = "default") {
|
|
505
|
+
const apiKey = getApiKey(flagApiKey, profile);
|
|
506
|
+
if (!apiKey) {
|
|
507
|
+
outputError("not_authenticated", "No API key found. Run 'danube login' to authenticate.", {
|
|
508
|
+
fix: "danube login"
|
|
509
|
+
});
|
|
510
|
+
process.exit(2);
|
|
511
|
+
}
|
|
512
|
+
return new ApiClient(getBaseUrl(profile), apiKey);
|
|
513
|
+
}
|
|
514
|
+
function getPublicClient(profile = "default") {
|
|
515
|
+
return new ApiClient(getBaseUrl(profile));
|
|
516
|
+
}
|
|
517
|
+
var init_api = __esm(() => {
|
|
518
|
+
init_errors();
|
|
519
|
+
init_config();
|
|
520
|
+
init_output();
|
|
521
|
+
init_version();
|
|
522
|
+
});
|
|
523
|
+
|
|
524
|
+
// src/commands/auth.ts
|
|
525
|
+
var exports_auth = {};
|
|
526
|
+
__export(exports_auth, {
|
|
527
|
+
register: () => register
|
|
528
|
+
});
|
|
529
|
+
import chalk2 from "chalk";
|
|
530
|
+
function register(program) {
|
|
531
|
+
program.command("login").description("Log in to Danube via device code (opens browser)").action(handleErrors(async () => {
|
|
532
|
+
const baseUrl = getBaseUrl(ctx.profile);
|
|
533
|
+
const client = new ApiClient(baseUrl);
|
|
534
|
+
const data = await client.publicPost("/v1/auth/device/code", {
|
|
535
|
+
client_name: "danube-cli"
|
|
536
|
+
});
|
|
537
|
+
if (humanMode) {
|
|
538
|
+
console.log();
|
|
539
|
+
console.log(chalk2.bold(" Enter this code:"));
|
|
540
|
+
console.log();
|
|
541
|
+
console.log(` ${chalk2.bold.white.bgCyan(` ${data.user_code} `)}`);
|
|
542
|
+
console.log();
|
|
543
|
+
console.log(chalk2.dim(` ${data.verification_url}`));
|
|
544
|
+
console.log();
|
|
545
|
+
} else {
|
|
546
|
+
output({
|
|
547
|
+
user_code: data.user_code,
|
|
548
|
+
verification_url: data.verification_url,
|
|
549
|
+
expires_in: data.expires_in
|
|
550
|
+
});
|
|
551
|
+
}
|
|
552
|
+
try {
|
|
553
|
+
const url = `${data.verification_url}?code=${data.user_code}`;
|
|
554
|
+
if (process.platform === "darwin") {
|
|
555
|
+
Bun.spawn(["open", url]);
|
|
556
|
+
} else if (process.platform === "linux") {
|
|
557
|
+
Bun.spawn(["xdg-open", url]);
|
|
558
|
+
} else {
|
|
559
|
+
Bun.spawn(["start", url]);
|
|
560
|
+
}
|
|
561
|
+
if (humanMode) {
|
|
562
|
+
console.log(chalk2.dim(" Browser opened. Waiting for authorization..."));
|
|
563
|
+
}
|
|
564
|
+
} catch {
|
|
565
|
+
if (humanMode) {
|
|
566
|
+
console.log(chalk2.dim(` Open ${data.verification_url} in your browser`));
|
|
567
|
+
}
|
|
568
|
+
}
|
|
569
|
+
const start = Date.now();
|
|
570
|
+
const expiresMs = data.expires_in * 1000;
|
|
571
|
+
const intervalMs = data.interval * 1000;
|
|
572
|
+
while (Date.now() - start < expiresMs) {
|
|
573
|
+
await Bun.sleep(intervalMs);
|
|
574
|
+
try {
|
|
575
|
+
const tokenData = await client.publicPost("/v1/auth/device/token", { device_code: data.device_code });
|
|
576
|
+
saveApiKey(tokenData.api_key, ctx.profile);
|
|
577
|
+
if (humanMode) {
|
|
578
|
+
console.log(`
|
|
579
|
+
${chalk2.green("✓")} Authenticated successfully!`);
|
|
580
|
+
console.log(` API key saved to profile ${chalk2.cyan(ctx.profile)}`);
|
|
581
|
+
console.log();
|
|
582
|
+
console.log(chalk2.bold(" Next steps:"));
|
|
583
|
+
console.log(` ${chalk2.dim("$")} danube search "send email" ${chalk2.dim("# Find tools")}`);
|
|
584
|
+
console.log(` ${chalk2.dim("$")} danube execute <tool> -d '{}' ${chalk2.dim("# Run a tool")}`);
|
|
585
|
+
console.log(` ${chalk2.dim("$")} danube services list ${chalk2.dim("# Browse services")}`);
|
|
586
|
+
console.log();
|
|
587
|
+
} else {
|
|
588
|
+
output({
|
|
589
|
+
success: true,
|
|
590
|
+
key_prefix: tokenData.key_prefix ?? tokenData.api_key.slice(0, 8)
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
return;
|
|
594
|
+
} catch (e) {
|
|
595
|
+
const err = e;
|
|
596
|
+
if (err.statusCode === 428) {
|
|
597
|
+
if (humanMode) {
|
|
598
|
+
process.stdout.write(chalk2.dim("."));
|
|
599
|
+
}
|
|
600
|
+
continue;
|
|
601
|
+
}
|
|
602
|
+
if (err.statusCode === 410) {
|
|
603
|
+
outputError("expired", "Device code expired. Please try again.", { fix: "danube login" });
|
|
604
|
+
process.exit(1);
|
|
605
|
+
}
|
|
606
|
+
throw e;
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
outputError("timeout", "Login timed out. Please try again.", { fix: "danube login" });
|
|
610
|
+
process.exit(1);
|
|
611
|
+
}));
|
|
612
|
+
program.command("logout").description("Remove stored credentials").action(handleErrors(async () => {
|
|
613
|
+
removeApiKey(ctx.profile);
|
|
614
|
+
outputSuccess(`Logged out from profile '${ctx.profile}'`);
|
|
615
|
+
}));
|
|
616
|
+
program.command("whoami").description("Show current identity").action(handleErrors(async () => {
|
|
617
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
618
|
+
const identity = await client.get("/v1/identity/api");
|
|
619
|
+
if (humanMode) {
|
|
620
|
+
console.log();
|
|
621
|
+
const aboutMe = identity.about_me;
|
|
622
|
+
if (aboutMe?.name)
|
|
623
|
+
console.log(` ${chalk2.cyan("Name:")} ${aboutMe.name}`);
|
|
624
|
+
if (aboutMe?.role)
|
|
625
|
+
console.log(` ${chalk2.cyan("Role:")} ${aboutMe.role}`);
|
|
626
|
+
console.log(` ${chalk2.cyan("Profile:")} ${ctx.profile}`);
|
|
627
|
+
if (Object.keys(identity).length === 0) {
|
|
628
|
+
console.log(chalk2.dim(" No identity attributes set yet."));
|
|
629
|
+
}
|
|
630
|
+
console.log();
|
|
631
|
+
} else {
|
|
632
|
+
output({
|
|
633
|
+
identity,
|
|
634
|
+
profile: ctx.profile
|
|
635
|
+
});
|
|
636
|
+
}
|
|
637
|
+
}));
|
|
638
|
+
}
|
|
639
|
+
var init_auth = __esm(() => {
|
|
640
|
+
init_src();
|
|
641
|
+
init_api();
|
|
642
|
+
init_config();
|
|
643
|
+
init_errors();
|
|
644
|
+
init_output();
|
|
645
|
+
init_api();
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
// src/commands/search.ts
|
|
649
|
+
var exports_search = {};
|
|
650
|
+
__export(exports_search, {
|
|
651
|
+
register: () => register2
|
|
652
|
+
});
|
|
653
|
+
function register2(program) {
|
|
654
|
+
program.command("search <query>").description("Find tools via semantic search. Use this first.").option("--service <id>", "Filter by service slug or ID").option("--limit <n>", "Maximum results", "10").addHelpText("after", `
|
|
655
|
+
Examples:
|
|
656
|
+
$ danube search "send email"
|
|
657
|
+
$ danube search "weather" --limit 5`).action(handleErrors(async (query, opts) => {
|
|
658
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
659
|
+
const tools = await client.get("/v1/tools/search", {
|
|
660
|
+
query,
|
|
661
|
+
service_id: opts.service,
|
|
662
|
+
limit: opts.limit
|
|
663
|
+
});
|
|
664
|
+
outputTable(tools, [
|
|
665
|
+
{ header: "ID", key: "id", style: "dim" },
|
|
666
|
+
{ header: "Name", key: "name", style: "bold" },
|
|
667
|
+
{ header: "Description", key: "description" },
|
|
668
|
+
{ header: "Service", key: "service_name" }
|
|
669
|
+
], `Tools matching '${query}'`);
|
|
670
|
+
}));
|
|
671
|
+
}
|
|
672
|
+
var init_search = __esm(() => {
|
|
673
|
+
init_src();
|
|
674
|
+
init_api();
|
|
675
|
+
init_errors();
|
|
676
|
+
init_output();
|
|
677
|
+
});
|
|
678
|
+
|
|
679
|
+
// src/lib/data-input.ts
|
|
680
|
+
async function parseData(data) {
|
|
681
|
+
if (!data)
|
|
682
|
+
return {};
|
|
683
|
+
data = data.trim();
|
|
684
|
+
if (data === "-") {
|
|
685
|
+
const raw = await Bun.stdin.text();
|
|
686
|
+
if (!raw.trim())
|
|
687
|
+
return {};
|
|
688
|
+
try {
|
|
689
|
+
return JSON.parse(raw);
|
|
690
|
+
} catch (e) {
|
|
691
|
+
outputError("invalid_input", `Invalid JSON from stdin: ${e instanceof Error ? e.message : String(e)}`);
|
|
692
|
+
process.exit(1);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
if (data.startsWith("@")) {
|
|
696
|
+
const filepath = data.slice(1);
|
|
697
|
+
const file = Bun.file(filepath);
|
|
698
|
+
if (!await file.exists()) {
|
|
699
|
+
outputError("file_not_found", `File not found: ${filepath}`);
|
|
700
|
+
process.exit(1);
|
|
701
|
+
}
|
|
702
|
+
try {
|
|
703
|
+
return JSON.parse(await file.text());
|
|
704
|
+
} catch (e) {
|
|
705
|
+
outputError("invalid_input", `Invalid JSON in ${filepath}: ${e instanceof Error ? e.message : String(e)}`);
|
|
706
|
+
process.exit(1);
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
try {
|
|
710
|
+
return JSON.parse(data);
|
|
711
|
+
} catch (e) {
|
|
712
|
+
outputError("invalid_input", `Invalid JSON: ${e instanceof Error ? e.message : String(e)}`);
|
|
713
|
+
process.exit(1);
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
var init_data_input = __esm(() => {
|
|
717
|
+
init_output();
|
|
718
|
+
});
|
|
719
|
+
|
|
720
|
+
// src/lib/resolve.ts
|
|
721
|
+
function isUUID(value) {
|
|
722
|
+
return UUID_RE.test(value);
|
|
723
|
+
}
|
|
724
|
+
async function resolveTool(client, tool) {
|
|
725
|
+
if (isUUID(tool)) {
|
|
726
|
+
return client.publicGet(`/v1/tools/public/${tool}`);
|
|
727
|
+
}
|
|
728
|
+
const results = await client.get("/v1/tools/search", { query: tool, limit: "1" });
|
|
729
|
+
if (!results.length) {
|
|
730
|
+
outputError("not_found", `No tool found matching '${tool}'`);
|
|
731
|
+
process.exit(1);
|
|
732
|
+
}
|
|
733
|
+
return client.publicGet(`/v1/tools/public/${results[0].id}`);
|
|
734
|
+
}
|
|
735
|
+
var UUID_RE;
|
|
736
|
+
var init_resolve = __esm(() => {
|
|
737
|
+
init_output();
|
|
738
|
+
UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
739
|
+
});
|
|
740
|
+
|
|
741
|
+
// src/commands/execute.ts
|
|
742
|
+
var exports_execute = {};
|
|
743
|
+
__export(exports_execute, {
|
|
744
|
+
register: () => register3
|
|
745
|
+
});
|
|
746
|
+
function register3(program) {
|
|
747
|
+
program.command("execute <tool>").description("Run a tool. Handles validation and auth checks automatically.").option("-d, --data <json>", "JSON args: '{...}', @file, or - for stdin").option("--dry-run", "Validate without executing", false).option("--get-schema", "Print the tool's parameter schema", false).addHelpText("after", `
|
|
748
|
+
Examples:
|
|
749
|
+
$ danube execute gmail-send-email -d '{"to":"a@b.com","subject":"Hi"}'
|
|
750
|
+
$ danube execute <tool-id> -d @params.json
|
|
751
|
+
$ danube execute <tool-name> --get-schema
|
|
752
|
+
$ danube execute <tool-name> --dry-run`).action(handleErrors(async (tool, opts) => {
|
|
753
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
754
|
+
if (opts.getSchema) {
|
|
755
|
+
const toolInfo = await resolveTool(client, tool);
|
|
756
|
+
output({
|
|
757
|
+
id: toolInfo.id,
|
|
758
|
+
name: toolInfo.name,
|
|
759
|
+
description: toolInfo.description,
|
|
760
|
+
parameters: toolInfo.parameters
|
|
761
|
+
});
|
|
762
|
+
return;
|
|
763
|
+
}
|
|
764
|
+
const params = await parseData(opts.data);
|
|
765
|
+
if (opts.dryRun) {
|
|
766
|
+
const toolInfo = await resolveTool(client, tool);
|
|
767
|
+
output({
|
|
768
|
+
dry_run: true,
|
|
769
|
+
tool_id: toolInfo.id,
|
|
770
|
+
tool_name: toolInfo.name,
|
|
771
|
+
parameters: params,
|
|
772
|
+
cost_cents: toolInfo.price_per_call_cents
|
|
773
|
+
});
|
|
774
|
+
return;
|
|
775
|
+
}
|
|
776
|
+
let toolId = tool;
|
|
777
|
+
if (!isUUID(tool)) {
|
|
778
|
+
const toolInfo = await resolveTool(client, tool);
|
|
779
|
+
toolId = toolInfo.id;
|
|
780
|
+
}
|
|
781
|
+
const result = await client.post(`/v1/tools/call/${toolId}`, {
|
|
782
|
+
parameters: params
|
|
783
|
+
});
|
|
784
|
+
output({
|
|
785
|
+
success: result.success,
|
|
786
|
+
result: result.result,
|
|
787
|
+
error: result.error,
|
|
788
|
+
tool_id: result.tool_id,
|
|
789
|
+
tool_name: result.tool_name,
|
|
790
|
+
duration_ms: result.duration_ms
|
|
791
|
+
});
|
|
792
|
+
}));
|
|
793
|
+
}
|
|
794
|
+
var init_execute = __esm(() => {
|
|
795
|
+
init_src();
|
|
796
|
+
init_api();
|
|
797
|
+
init_data_input();
|
|
798
|
+
init_errors();
|
|
799
|
+
init_output();
|
|
800
|
+
init_resolve();
|
|
801
|
+
});
|
|
802
|
+
|
|
803
|
+
// src/commands/connect.ts
|
|
804
|
+
var exports_connect = {};
|
|
805
|
+
__export(exports_connect, {
|
|
806
|
+
register: () => register4
|
|
807
|
+
});
|
|
808
|
+
import chalk3 from "chalk";
|
|
809
|
+
import { createInterface } from "node:readline";
|
|
810
|
+
async function promptSecret(prompt) {
|
|
811
|
+
const rl = createInterface({ input: process.stdin, output: process.stderr });
|
|
812
|
+
return new Promise((resolve) => {
|
|
813
|
+
process.stderr.write(prompt);
|
|
814
|
+
rl.question("", (answer) => {
|
|
815
|
+
rl.close();
|
|
816
|
+
resolve(answer.trim());
|
|
817
|
+
});
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
function register4(program) {
|
|
821
|
+
program.command("connect <service>").description("Authenticate to a service (interactive). See also: credentials store").addHelpText("after", `
|
|
822
|
+
Examples:
|
|
823
|
+
$ danube connect gmail
|
|
824
|
+
$ danube connect openai`).action(handleErrors(async (service) => {
|
|
825
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
826
|
+
const allServices = await client.publicGet("/v1/services/public");
|
|
827
|
+
const query = service.toLowerCase();
|
|
828
|
+
let target = allServices.find((s) => s.name.toLowerCase() === query || s.id === service);
|
|
829
|
+
if (!target) {
|
|
830
|
+
const matches = allServices.filter((s) => s.name.toLowerCase().includes(query) || (s.description ?? "").toLowerCase().includes(query));
|
|
831
|
+
if (matches.length) {
|
|
832
|
+
target = matches[0];
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
if (!target) {
|
|
836
|
+
outputError("not_found", `No service found matching '${service}'`);
|
|
837
|
+
process.exit(1);
|
|
838
|
+
}
|
|
839
|
+
if (humanMode) {
|
|
840
|
+
console.log(`
|
|
841
|
+
Connecting to ${chalk3.bold(target.name)}...`);
|
|
842
|
+
console.log(` Service ID: ${chalk3.dim(target.id)}`);
|
|
843
|
+
console.log();
|
|
844
|
+
}
|
|
845
|
+
let apiKeyValue;
|
|
846
|
+
if (humanMode) {
|
|
847
|
+
apiKeyValue = await promptSecret(" Enter API key: ");
|
|
848
|
+
} else {
|
|
849
|
+
apiKeyValue = (await Bun.stdin.text()).trim();
|
|
850
|
+
if (!apiKeyValue) {
|
|
851
|
+
outputError("invalid_input", "No credential provided on stdin");
|
|
852
|
+
process.exit(1);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
const result = await client.post("/v1/credentials/store", {
|
|
856
|
+
service_id: target.id,
|
|
857
|
+
credential_type: "api_key",
|
|
858
|
+
credential_value: apiKeyValue
|
|
859
|
+
});
|
|
860
|
+
outputSuccess(`Connected to ${target.name}`, {
|
|
861
|
+
service_id: target.id,
|
|
862
|
+
credential_type: "api_key"
|
|
863
|
+
});
|
|
864
|
+
}));
|
|
865
|
+
}
|
|
866
|
+
var init_connect = __esm(() => {
|
|
867
|
+
init_src();
|
|
868
|
+
init_api();
|
|
869
|
+
init_errors();
|
|
870
|
+
init_output();
|
|
871
|
+
});
|
|
872
|
+
|
|
873
|
+
// src/commands/completion.ts
|
|
874
|
+
var exports_completion = {};
|
|
875
|
+
__export(exports_completion, {
|
|
876
|
+
register: () => register5
|
|
877
|
+
});
|
|
878
|
+
function register5(program) {
|
|
879
|
+
program.command("completion <shell>").description("Generate shell completion script (bash, zsh, fish)").addHelpText("after", `
|
|
880
|
+
Examples:
|
|
881
|
+
$ danube completion bash >> ~/.bashrc
|
|
882
|
+
$ danube completion zsh >> ~/.zshrc
|
|
883
|
+
$ danube completion fish > ~/.config/fish/completions/danube.fish`).action(handleErrors(async (shell) => {
|
|
884
|
+
switch (shell) {
|
|
885
|
+
case "bash":
|
|
886
|
+
console.log(BASH_COMPLETION);
|
|
887
|
+
break;
|
|
888
|
+
case "zsh":
|
|
889
|
+
console.log(ZSH_COMPLETION);
|
|
890
|
+
break;
|
|
891
|
+
case "fish":
|
|
892
|
+
console.log(FISH_COMPLETION);
|
|
893
|
+
break;
|
|
894
|
+
default:
|
|
895
|
+
outputError("invalid_input", `Unsupported shell: ${shell}. Use bash, zsh, or fish.`);
|
|
896
|
+
process.exit(1);
|
|
897
|
+
}
|
|
898
|
+
}));
|
|
899
|
+
}
|
|
900
|
+
var BASH_COMPLETION = `#!/usr/bin/env bash
|
|
901
|
+
_danube_completions() {
|
|
902
|
+
local cur prev commands
|
|
903
|
+
cur="\${COMP_WORDS[COMP_CWORD]}"
|
|
904
|
+
prev="\${COMP_WORDS[COMP_CWORD-1]}"
|
|
905
|
+
commands="search execute connect login logout whoami tools services workflows skills wallet credentials keys sites agent config completion"
|
|
906
|
+
|
|
907
|
+
case "\${prev}" in
|
|
908
|
+
danube)
|
|
909
|
+
COMPREPLY=($(compgen -W "\${commands}" -- "\${cur}"))
|
|
910
|
+
return 0
|
|
911
|
+
;;
|
|
912
|
+
tools)
|
|
913
|
+
COMPREPLY=($(compgen -W "info list batch search rate ratings report recommend" -- "\${cur}"))
|
|
914
|
+
return 0
|
|
915
|
+
;;
|
|
916
|
+
services)
|
|
917
|
+
COMPREPLY=($(compgen -W "list info tools" -- "\${cur}"))
|
|
918
|
+
return 0
|
|
919
|
+
;;
|
|
920
|
+
workflows)
|
|
921
|
+
COMPREPLY=($(compgen -W "list info run status create update delete" -- "\${cur}"))
|
|
922
|
+
return 0
|
|
923
|
+
;;
|
|
924
|
+
skills)
|
|
925
|
+
COMPREPLY=($(compgen -W "search get create update delete" -- "\${cur}"))
|
|
926
|
+
return 0
|
|
927
|
+
;;
|
|
928
|
+
wallet)
|
|
929
|
+
COMPREPLY=($(compgen -W "balance transactions limits set-limits" -- "\${cur}"))
|
|
930
|
+
return 0
|
|
931
|
+
;;
|
|
932
|
+
credentials)
|
|
933
|
+
COMPREPLY=($(compgen -W "store" -- "\${cur}"))
|
|
934
|
+
return 0
|
|
935
|
+
;;
|
|
936
|
+
keys)
|
|
937
|
+
COMPREPLY=($(compgen -W "list create rotate revoke" -- "\${cur}"))
|
|
938
|
+
return 0
|
|
939
|
+
;;
|
|
940
|
+
sites)
|
|
941
|
+
COMPREPLY=($(compgen -W "search get" -- "\${cur}"))
|
|
942
|
+
return 0
|
|
943
|
+
;;
|
|
944
|
+
agent)
|
|
945
|
+
COMPREPLY=($(compgen -W "register info fund" -- "\${cur}"))
|
|
946
|
+
return 0
|
|
947
|
+
;;
|
|
948
|
+
config)
|
|
949
|
+
COMPREPLY=($(compgen -W "set get profiles" -- "\${cur}"))
|
|
950
|
+
return 0
|
|
951
|
+
;;
|
|
952
|
+
esac
|
|
953
|
+
}
|
|
954
|
+
complete -F _danube_completions danube
|
|
955
|
+
`, ZSH_COMPLETION = `#compdef danube
|
|
956
|
+
|
|
957
|
+
_danube() {
|
|
958
|
+
local -a commands subcommands
|
|
959
|
+
commands=(
|
|
960
|
+
'search:Find tools via semantic search'
|
|
961
|
+
'execute:Run a tool'
|
|
962
|
+
'connect:Authenticate to a service'
|
|
963
|
+
'login:Log in to Danube'
|
|
964
|
+
'logout:Remove stored credentials'
|
|
965
|
+
'whoami:Show current identity'
|
|
966
|
+
'tools:Inspect tools, ratings, and batch executions'
|
|
967
|
+
'services:Browse and inspect available services'
|
|
968
|
+
'workflows:List, run, and manage workflows'
|
|
969
|
+
'skills:Search, view, and manage skills'
|
|
970
|
+
'wallet:View wallet balance, transactions, and limits'
|
|
971
|
+
'credentials:Store service credentials'
|
|
972
|
+
'keys:Manage API keys'
|
|
973
|
+
'sites:Search the agent web directory'
|
|
974
|
+
'agent:Register and manage autonomous agents'
|
|
975
|
+
'config:Manage CLI configuration'
|
|
976
|
+
'completion:Generate shell completion script'
|
|
977
|
+
)
|
|
978
|
+
|
|
979
|
+
_arguments -C \\
|
|
980
|
+
'--human[Human-readable output]' \\
|
|
981
|
+
'--json[Machine-readable JSON output]' \\
|
|
982
|
+
'--api-key[Override API key]:key' \\
|
|
983
|
+
'--profile[Use named profile]:profile' \\
|
|
984
|
+
'-v[Verbose output]' \\
|
|
985
|
+
'-q[Suppress non-essential output]' \\
|
|
986
|
+
'--no-color[Disable colored output]' \\
|
|
987
|
+
'--version[Show version]' \\
|
|
988
|
+
'1:command:->command' \\
|
|
989
|
+
'*::arg:->args'
|
|
990
|
+
|
|
991
|
+
case $state in
|
|
992
|
+
command)
|
|
993
|
+
_describe 'command' commands
|
|
994
|
+
;;
|
|
995
|
+
esac
|
|
996
|
+
}
|
|
997
|
+
|
|
998
|
+
_danube
|
|
999
|
+
`, FISH_COMPLETION = `# Fish completions for danube
|
|
1000
|
+
complete -c danube -f
|
|
1001
|
+
|
|
1002
|
+
# Top-level commands
|
|
1003
|
+
complete -c danube -n '__fish_use_subcommand' -a search -d 'Find tools via semantic search'
|
|
1004
|
+
complete -c danube -n '__fish_use_subcommand' -a execute -d 'Run a tool'
|
|
1005
|
+
complete -c danube -n '__fish_use_subcommand' -a connect -d 'Authenticate to a service'
|
|
1006
|
+
complete -c danube -n '__fish_use_subcommand' -a login -d 'Log in to Danube'
|
|
1007
|
+
complete -c danube -n '__fish_use_subcommand' -a logout -d 'Remove stored credentials'
|
|
1008
|
+
complete -c danube -n '__fish_use_subcommand' -a whoami -d 'Show current identity'
|
|
1009
|
+
complete -c danube -n '__fish_use_subcommand' -a tools -d 'Inspect tools'
|
|
1010
|
+
complete -c danube -n '__fish_use_subcommand' -a services -d 'Browse services'
|
|
1011
|
+
complete -c danube -n '__fish_use_subcommand' -a workflows -d 'Manage workflows'
|
|
1012
|
+
complete -c danube -n '__fish_use_subcommand' -a skills -d 'Search and manage skills'
|
|
1013
|
+
complete -c danube -n '__fish_use_subcommand' -a wallet -d 'View wallet'
|
|
1014
|
+
complete -c danube -n '__fish_use_subcommand' -a credentials -d 'Store credentials'
|
|
1015
|
+
complete -c danube -n '__fish_use_subcommand' -a keys -d 'Manage API keys'
|
|
1016
|
+
complete -c danube -n '__fish_use_subcommand' -a sites -d 'Agent web directory'
|
|
1017
|
+
complete -c danube -n '__fish_use_subcommand' -a agent -d 'Register and manage agents'
|
|
1018
|
+
complete -c danube -n '__fish_use_subcommand' -a config -d 'CLI configuration'
|
|
1019
|
+
complete -c danube -n '__fish_use_subcommand' -a completion -d 'Shell completions'
|
|
1020
|
+
|
|
1021
|
+
# Subcommands
|
|
1022
|
+
complete -c danube -n '__fish_seen_subcommand_from tools' -a 'info list batch search rate ratings report recommend'
|
|
1023
|
+
complete -c danube -n '__fish_seen_subcommand_from services' -a 'list info tools'
|
|
1024
|
+
complete -c danube -n '__fish_seen_subcommand_from workflows' -a 'list info run status create update delete'
|
|
1025
|
+
complete -c danube -n '__fish_seen_subcommand_from skills' -a 'search get create update delete'
|
|
1026
|
+
complete -c danube -n '__fish_seen_subcommand_from wallet' -a 'balance transactions limits set-limits'
|
|
1027
|
+
complete -c danube -n '__fish_seen_subcommand_from credentials' -a 'store'
|
|
1028
|
+
complete -c danube -n '__fish_seen_subcommand_from keys' -a 'list create rotate revoke'
|
|
1029
|
+
complete -c danube -n '__fish_seen_subcommand_from sites' -a 'search get'
|
|
1030
|
+
complete -c danube -n '__fish_seen_subcommand_from agent' -a 'register info fund'
|
|
1031
|
+
complete -c danube -n '__fish_seen_subcommand_from config' -a 'set get profiles'
|
|
1032
|
+
|
|
1033
|
+
# Global options
|
|
1034
|
+
complete -c danube -l human -d 'Human-readable output'
|
|
1035
|
+
complete -c danube -l json -d 'Machine-readable JSON output'
|
|
1036
|
+
complete -c danube -l api-key -x -d 'Override API key'
|
|
1037
|
+
complete -c danube -l profile -x -d 'Use named profile'
|
|
1038
|
+
complete -c danube -s v -l verbose -d 'Verbose output'
|
|
1039
|
+
complete -c danube -s q -l quiet -d 'Suppress non-essential output'
|
|
1040
|
+
complete -c danube -l no-color -d 'Disable colored output'
|
|
1041
|
+
complete -c danube -l version -d 'Show version'
|
|
1042
|
+
`;
|
|
1043
|
+
var init_completion = __esm(() => {
|
|
1044
|
+
init_errors();
|
|
1045
|
+
init_output();
|
|
1046
|
+
});
|
|
1047
|
+
|
|
1048
|
+
// src/commands/tools.ts
|
|
1049
|
+
var exports_tools = {};
|
|
1050
|
+
__export(exports_tools, {
|
|
1051
|
+
register: () => register6
|
|
1052
|
+
});
|
|
1053
|
+
function register6(program) {
|
|
1054
|
+
const tools = program.command("tools").description("Inspect tools and run batch executions.");
|
|
1055
|
+
tools.command("info <tool>").description("Print tool summary and parameter schema").action(handleErrors(async (tool) => {
|
|
1056
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1057
|
+
const toolInfo = await resolveTool(client, tool);
|
|
1058
|
+
outputDetail(toolInfo, toolInfo.name);
|
|
1059
|
+
}));
|
|
1060
|
+
tools.command("list [service]").description("List tools, optionally filtered by service").option("--limit <n>", "Maximum results", "50").action(handleErrors(async (service, opts) => {
|
|
1061
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1062
|
+
let toolList;
|
|
1063
|
+
if (service) {
|
|
1064
|
+
toolList = await client.get("/v1/tools/search", {
|
|
1065
|
+
service_id: service,
|
|
1066
|
+
limit: opts.limit
|
|
1067
|
+
});
|
|
1068
|
+
} else {
|
|
1069
|
+
toolList = await client.get("/v1/tools/search", { limit: opts.limit });
|
|
1070
|
+
}
|
|
1071
|
+
outputTable(toolList, [
|
|
1072
|
+
{ header: "ID", key: "id", style: "dim" },
|
|
1073
|
+
{ header: "Name", key: "name", style: "bold" },
|
|
1074
|
+
{ header: "Description", key: "description" }
|
|
1075
|
+
]);
|
|
1076
|
+
}));
|
|
1077
|
+
tools.command("batch <file>").description("Batch execute up to 10 tools from a JSON file").action(handleErrors(async (file) => {
|
|
1078
|
+
const f = Bun.file(file);
|
|
1079
|
+
if (!await f.exists()) {
|
|
1080
|
+
outputError("file_not_found", `File not found: ${file}`);
|
|
1081
|
+
process.exit(1);
|
|
1082
|
+
}
|
|
1083
|
+
let calls;
|
|
1084
|
+
try {
|
|
1085
|
+
const parsed = JSON.parse(await f.text());
|
|
1086
|
+
if (!Array.isArray(parsed)) {
|
|
1087
|
+
outputError("invalid_input", "Batch file must contain a JSON array");
|
|
1088
|
+
process.exit(1);
|
|
1089
|
+
}
|
|
1090
|
+
calls = parsed;
|
|
1091
|
+
} catch (e) {
|
|
1092
|
+
outputError("invalid_input", `Invalid JSON in ${file}: ${e instanceof Error ? e.message : String(e)}`);
|
|
1093
|
+
process.exit(1);
|
|
1094
|
+
}
|
|
1095
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1096
|
+
const results = await client.post("/v1/tools/call/batch", calls);
|
|
1097
|
+
output(results);
|
|
1098
|
+
}));
|
|
1099
|
+
tools.command("search <query>").description("Search for tools by name or description").option("--service <id>", "Filter by service ID").option("--limit <n>", "Maximum results", "10").action(handleErrors(async (query, opts) => {
|
|
1100
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1101
|
+
const result = await client.get("/v1/tools/search", {
|
|
1102
|
+
query,
|
|
1103
|
+
service_id: opts.service,
|
|
1104
|
+
limit: opts.limit
|
|
1105
|
+
});
|
|
1106
|
+
outputTable(result, [
|
|
1107
|
+
{ header: "ID", key: "id", style: "dim" },
|
|
1108
|
+
{ header: "Name", key: "name", style: "bold" },
|
|
1109
|
+
{ header: "Description", key: "description" },
|
|
1110
|
+
{ header: "Service", key: "service_name" }
|
|
1111
|
+
], `Tools matching '${query}'`);
|
|
1112
|
+
}));
|
|
1113
|
+
tools.command("rate <tool> <rating>").description("Rate a tool (1-5 stars)").option("--comment <text>", "Optional comment").action(handleErrors(async (tool, rating, opts) => {
|
|
1114
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1115
|
+
const toolInfo = await resolveTool(client, tool);
|
|
1116
|
+
const ratingNum = parseInt(rating, 10);
|
|
1117
|
+
if (isNaN(ratingNum) || ratingNum < 1 || ratingNum > 5) {
|
|
1118
|
+
outputError("invalid_input", "Rating must be between 1 and 5");
|
|
1119
|
+
process.exit(1);
|
|
1120
|
+
}
|
|
1121
|
+
const result = await client.post("/v1/ratings", {
|
|
1122
|
+
tool_id: toolInfo.id,
|
|
1123
|
+
rating: ratingNum,
|
|
1124
|
+
comment: opts.comment
|
|
1125
|
+
});
|
|
1126
|
+
outputSuccess(`Rated ${toolInfo.name}: ${"★".repeat(ratingNum)}${"☆".repeat(5 - ratingNum)}`);
|
|
1127
|
+
}));
|
|
1128
|
+
tools.command("ratings <tool>").description("View ratings for a tool").action(handleErrors(async (tool) => {
|
|
1129
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1130
|
+
const toolInfo = await resolveTool(client, tool);
|
|
1131
|
+
const ratings = await client.publicGet(`/v1/ratings/tool/${toolInfo.id}`);
|
|
1132
|
+
outputDetail(ratings, `Ratings for ${toolInfo.name}`);
|
|
1133
|
+
}));
|
|
1134
|
+
tools.command("report <tool>").description("Report a broken or degraded tool").option("--reason <reason>", "Reason: broken, degraded, incorrect_output, timeout, other", "broken").option("--description <text>", "Additional details").action(handleErrors(async (tool, opts) => {
|
|
1135
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1136
|
+
const toolInfo = await resolveTool(client, tool);
|
|
1137
|
+
const validReasons = ["broken", "degraded", "incorrect_output", "timeout", "other"];
|
|
1138
|
+
if (!validReasons.includes(opts.reason)) {
|
|
1139
|
+
outputError("invalid_input", `Invalid reason. Must be one of: ${validReasons.join(", ")}`);
|
|
1140
|
+
process.exit(1);
|
|
1141
|
+
}
|
|
1142
|
+
await client.post(`/v1/tools/${toolInfo.id}/report`, {
|
|
1143
|
+
reason: opts.reason,
|
|
1144
|
+
description: opts.description
|
|
1145
|
+
});
|
|
1146
|
+
outputSuccess(`Reported ${toolInfo.name} as ${opts.reason}`);
|
|
1147
|
+
}));
|
|
1148
|
+
tools.command("recommend <tool>").description("Get tool recommendations based on co-usage").option("--limit <n>", "Maximum recommendations", "5").action(handleErrors(async (tool, opts) => {
|
|
1149
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1150
|
+
const toolInfo = await resolveTool(client, tool);
|
|
1151
|
+
const result = await client.get("/v1/tools/recommended", {
|
|
1152
|
+
tool_id: toolInfo.id,
|
|
1153
|
+
limit: opts.limit
|
|
1154
|
+
});
|
|
1155
|
+
outputTable(result, [
|
|
1156
|
+
{ header: "ID", key: "id", style: "dim" },
|
|
1157
|
+
{ header: "Name", key: "name", style: "bold" },
|
|
1158
|
+
{ header: "Description", key: "description" }
|
|
1159
|
+
], `Recommended tools based on ${toolInfo.name}`);
|
|
1160
|
+
}));
|
|
1161
|
+
}
|
|
1162
|
+
var init_tools = __esm(() => {
|
|
1163
|
+
init_src();
|
|
1164
|
+
init_api();
|
|
1165
|
+
init_errors();
|
|
1166
|
+
init_output();
|
|
1167
|
+
init_resolve();
|
|
1168
|
+
});
|
|
1169
|
+
|
|
1170
|
+
// src/commands/services.ts
|
|
1171
|
+
var exports_services = {};
|
|
1172
|
+
__export(exports_services, {
|
|
1173
|
+
register: () => register7
|
|
1174
|
+
});
|
|
1175
|
+
function register7(program) {
|
|
1176
|
+
const services = program.command("services").description("Browse and inspect available services.");
|
|
1177
|
+
services.command("list [query]").description("List or search available services").option("--limit <n>", "Maximum results", "10").action(handleErrors(async (query, opts) => {
|
|
1178
|
+
const client = getPublicClient(ctx.profile);
|
|
1179
|
+
let result = await client.publicGet("/v1/services/public", {
|
|
1180
|
+
limit: opts.limit
|
|
1181
|
+
});
|
|
1182
|
+
if (query) {
|
|
1183
|
+
const q = query.toLowerCase();
|
|
1184
|
+
result = result.filter((s) => s.name.toLowerCase().includes(q) || (s.description ?? "").toLowerCase().includes(q));
|
|
1185
|
+
}
|
|
1186
|
+
outputTable(result, [
|
|
1187
|
+
{ header: "ID", key: "id", style: "dim" },
|
|
1188
|
+
{ header: "Name", key: "name", style: "bold" },
|
|
1189
|
+
{ header: "Type", key: "service_type" },
|
|
1190
|
+
{ header: "Description", key: "description" },
|
|
1191
|
+
{ header: "Tools", key: "tool_count" }
|
|
1192
|
+
], "Services");
|
|
1193
|
+
}));
|
|
1194
|
+
services.command("info <serviceId>").description("Get service details").action(handleErrors(async (serviceId) => {
|
|
1195
|
+
const client = getPublicClient(ctx.profile);
|
|
1196
|
+
const service = await client.publicGet(`/v1/services/public/${serviceId}`);
|
|
1197
|
+
outputDetail(service, service.name);
|
|
1198
|
+
}));
|
|
1199
|
+
services.command("tools <serviceId>").description("List tools for a specific service").action(handleErrors(async (serviceId) => {
|
|
1200
|
+
const client = getPublicClient(ctx.profile);
|
|
1201
|
+
const result = await client.publicGet(`/v1/services/public/${serviceId}/tools`);
|
|
1202
|
+
outputTable(result, [
|
|
1203
|
+
{ header: "ID", key: "id", style: "dim" },
|
|
1204
|
+
{ header: "Name", key: "name", style: "bold" },
|
|
1205
|
+
{ header: "Description", key: "description" }
|
|
1206
|
+
], "Service Tools");
|
|
1207
|
+
}));
|
|
1208
|
+
}
|
|
1209
|
+
var init_services = __esm(() => {
|
|
1210
|
+
init_src();
|
|
1211
|
+
init_api();
|
|
1212
|
+
init_errors();
|
|
1213
|
+
init_output();
|
|
1214
|
+
});
|
|
1215
|
+
|
|
1216
|
+
// src/commands/workflows.ts
|
|
1217
|
+
var exports_workflows = {};
|
|
1218
|
+
__export(exports_workflows, {
|
|
1219
|
+
register: () => register8
|
|
1220
|
+
});
|
|
1221
|
+
function register8(program) {
|
|
1222
|
+
const workflows = program.command("workflows").description("List, run, and manage workflows.");
|
|
1223
|
+
workflows.command("list [query]").description("List public workflows").option("--limit <n>", "Maximum results", "10").action(handleErrors(async (query, opts) => {
|
|
1224
|
+
const client = getPublicClient(ctx.profile);
|
|
1225
|
+
const result = await client.publicGet("/v1/workflows/public", {
|
|
1226
|
+
search: query ?? "",
|
|
1227
|
+
limit: opts.limit
|
|
1228
|
+
});
|
|
1229
|
+
outputTable(result, [
|
|
1230
|
+
{ header: "ID", key: "id", style: "dim" },
|
|
1231
|
+
{ header: "Name", key: "name", style: "bold" },
|
|
1232
|
+
{ header: "Description", key: "description" },
|
|
1233
|
+
{ header: "Steps", key: "step_count" }
|
|
1234
|
+
], "Workflows");
|
|
1235
|
+
}));
|
|
1236
|
+
workflows.command("info <workflowId>").description("Get workflow details").action(handleErrors(async (workflowId) => {
|
|
1237
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1238
|
+
const workflow = await client.get(`/v1/workflows/${workflowId}`);
|
|
1239
|
+
outputDetail(workflow, workflow.name);
|
|
1240
|
+
}));
|
|
1241
|
+
workflows.command("run <workflowId>").description("Execute a workflow with inputs").option("-d, --data <json>", "Inputs as JSON, @file, or - for stdin").action(handleErrors(async (workflowId, opts) => {
|
|
1242
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1243
|
+
const inputs = await parseData(opts.data);
|
|
1244
|
+
const execution = await client.post(`/v1/workflows/${workflowId}/execute`, { inputs });
|
|
1245
|
+
outputDetail(execution, `Workflow Execution ${execution.id}`);
|
|
1246
|
+
}));
|
|
1247
|
+
workflows.command("status <executionId>").description("Check workflow execution status").action(handleErrors(async (executionId) => {
|
|
1248
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1249
|
+
const execution = await client.get(`/v1/workflows/executions/${executionId}`);
|
|
1250
|
+
outputDetail(execution, `Execution ${execution.id}`);
|
|
1251
|
+
}));
|
|
1252
|
+
workflows.command("create <file>").description("Create a workflow from a JSON spec file").action(handleErrors(async (file) => {
|
|
1253
|
+
const f = Bun.file(file);
|
|
1254
|
+
if (!await f.exists()) {
|
|
1255
|
+
outputError("file_not_found", `File not found: ${file}`);
|
|
1256
|
+
process.exit(1);
|
|
1257
|
+
}
|
|
1258
|
+
let spec;
|
|
1259
|
+
try {
|
|
1260
|
+
spec = JSON.parse(await f.text());
|
|
1261
|
+
} catch (e) {
|
|
1262
|
+
outputError("invalid_input", `Invalid JSON: ${e instanceof Error ? e.message : String(e)}`);
|
|
1263
|
+
process.exit(1);
|
|
1264
|
+
}
|
|
1265
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1266
|
+
const workflow = await client.post("/v1/workflows", {
|
|
1267
|
+
name: spec.name,
|
|
1268
|
+
steps: spec.steps ?? [],
|
|
1269
|
+
description: spec.description ?? "",
|
|
1270
|
+
visibility: spec.visibility ?? "private",
|
|
1271
|
+
tags: spec.tags
|
|
1272
|
+
});
|
|
1273
|
+
outputDetail(workflow, `Created: ${workflow.name}`);
|
|
1274
|
+
}));
|
|
1275
|
+
workflows.command("update <workflowId> <file>").description("Update a workflow from a JSON spec file").action(handleErrors(async (workflowId, file) => {
|
|
1276
|
+
const f = Bun.file(file);
|
|
1277
|
+
if (!await f.exists()) {
|
|
1278
|
+
outputError("file_not_found", `File not found: ${file}`);
|
|
1279
|
+
process.exit(1);
|
|
1280
|
+
}
|
|
1281
|
+
let spec;
|
|
1282
|
+
try {
|
|
1283
|
+
spec = JSON.parse(await f.text());
|
|
1284
|
+
} catch (e) {
|
|
1285
|
+
outputError("invalid_input", `Invalid JSON: ${e instanceof Error ? e.message : String(e)}`);
|
|
1286
|
+
process.exit(1);
|
|
1287
|
+
}
|
|
1288
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1289
|
+
const workflow = await client.patch(`/v1/workflows/${workflowId}`, spec);
|
|
1290
|
+
outputDetail(workflow, `Updated: ${workflow.name}`);
|
|
1291
|
+
}));
|
|
1292
|
+
workflows.command("delete <workflowId>").description("Delete a workflow you own").action(handleErrors(async (workflowId) => {
|
|
1293
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1294
|
+
await client.delete(`/v1/workflows/${workflowId}`);
|
|
1295
|
+
outputSuccess(`Deleted workflow ${workflowId}`);
|
|
1296
|
+
}));
|
|
1297
|
+
}
|
|
1298
|
+
var init_workflows = __esm(() => {
|
|
1299
|
+
init_src();
|
|
1300
|
+
init_api();
|
|
1301
|
+
init_data_input();
|
|
1302
|
+
init_errors();
|
|
1303
|
+
init_output();
|
|
1304
|
+
});
|
|
1305
|
+
|
|
1306
|
+
// src/commands/skills.ts
|
|
1307
|
+
var exports_skills = {};
|
|
1308
|
+
__export(exports_skills, {
|
|
1309
|
+
register: () => register9
|
|
1310
|
+
});
|
|
1311
|
+
import chalk4 from "chalk";
|
|
1312
|
+
function register9(program) {
|
|
1313
|
+
const skills = program.command("skills").description("Search, view, and manage skills.");
|
|
1314
|
+
skills.command("search <query>").description("Find skills by query").option("--limit <n>", "Maximum results", "10").action(handleErrors(async (query, opts) => {
|
|
1315
|
+
const client = getPublicClient(ctx.profile);
|
|
1316
|
+
const result = await client.publicGet("/v1/skills/search", {
|
|
1317
|
+
query,
|
|
1318
|
+
limit: opts.limit
|
|
1319
|
+
});
|
|
1320
|
+
outputTable(result, [
|
|
1321
|
+
{ header: "ID", key: "id", style: "dim" },
|
|
1322
|
+
{ header: "Name", key: "name", style: "bold" },
|
|
1323
|
+
{ header: "Description", key: "description" }
|
|
1324
|
+
], `Skills matching '${query}'`);
|
|
1325
|
+
}));
|
|
1326
|
+
skills.command("get <identifier>").description("Get skill content (prints SKILL.md)").action(handleErrors(async (identifier) => {
|
|
1327
|
+
const client = getPublicClient(ctx.profile);
|
|
1328
|
+
const skill = await client.publicGet(`/v1/skills/${identifier}`);
|
|
1329
|
+
if (humanMode) {
|
|
1330
|
+
console.log(`
|
|
1331
|
+
${chalk4.bold(skill.name)}`);
|
|
1332
|
+
if (skill.description) {
|
|
1333
|
+
console.log(chalk4.dim(skill.description));
|
|
1334
|
+
}
|
|
1335
|
+
console.log();
|
|
1336
|
+
if (skill.skill_md) {
|
|
1337
|
+
console.log(skill.skill_md);
|
|
1338
|
+
}
|
|
1339
|
+
} else {
|
|
1340
|
+
output({
|
|
1341
|
+
id: skill.id,
|
|
1342
|
+
name: skill.name,
|
|
1343
|
+
description: skill.description,
|
|
1344
|
+
skill_md: skill.skill_md
|
|
1345
|
+
});
|
|
1346
|
+
}
|
|
1347
|
+
}));
|
|
1348
|
+
skills.command("create <file>").description("Create a skill from a JSON spec file").option("--visibility <vis>", "Visibility: private or public", "private").action(handleErrors(async (file, opts) => {
|
|
1349
|
+
const f = Bun.file(file);
|
|
1350
|
+
if (!await f.exists()) {
|
|
1351
|
+
outputError("file_not_found", `File not found: ${file}`);
|
|
1352
|
+
process.exit(1);
|
|
1353
|
+
}
|
|
1354
|
+
let spec;
|
|
1355
|
+
try {
|
|
1356
|
+
spec = JSON.parse(await f.text());
|
|
1357
|
+
} catch (e) {
|
|
1358
|
+
outputError("invalid_input", `Invalid JSON: ${e instanceof Error ? e.message : String(e)}`);
|
|
1359
|
+
process.exit(1);
|
|
1360
|
+
}
|
|
1361
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1362
|
+
const skill = await client.post("/v1/skills", {
|
|
1363
|
+
name: spec.name,
|
|
1364
|
+
skill_md_content: spec.skill_md_content ?? spec.skill_md ?? "",
|
|
1365
|
+
description: spec.description,
|
|
1366
|
+
scripts: spec.scripts,
|
|
1367
|
+
reference_files: spec.reference_files,
|
|
1368
|
+
assets: spec.assets,
|
|
1369
|
+
visibility: opts.visibility,
|
|
1370
|
+
service_id: spec.service_id
|
|
1371
|
+
});
|
|
1372
|
+
outputDetail(skill, `Created: ${skill.name}`);
|
|
1373
|
+
}));
|
|
1374
|
+
skills.command("update <skillId> <file>").description("Update a skill from a JSON spec file").action(handleErrors(async (skillId, file) => {
|
|
1375
|
+
const f = Bun.file(file);
|
|
1376
|
+
if (!await f.exists()) {
|
|
1377
|
+
outputError("file_not_found", `File not found: ${file}`);
|
|
1378
|
+
process.exit(1);
|
|
1379
|
+
}
|
|
1380
|
+
let spec;
|
|
1381
|
+
try {
|
|
1382
|
+
spec = JSON.parse(await f.text());
|
|
1383
|
+
} catch (e) {
|
|
1384
|
+
outputError("invalid_input", `Invalid JSON: ${e instanceof Error ? e.message : String(e)}`);
|
|
1385
|
+
process.exit(1);
|
|
1386
|
+
}
|
|
1387
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1388
|
+
const skill = await client.patch(`/v1/skills/${skillId}`, spec);
|
|
1389
|
+
outputDetail(skill, `Updated: ${skill.name}`);
|
|
1390
|
+
}));
|
|
1391
|
+
skills.command("delete <skillId>").description("Delete a skill you own").action(handleErrors(async (skillId) => {
|
|
1392
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1393
|
+
await client.delete(`/v1/skills/${skillId}`);
|
|
1394
|
+
outputSuccess(`Deleted skill ${skillId}`);
|
|
1395
|
+
}));
|
|
1396
|
+
}
|
|
1397
|
+
var init_skills = __esm(() => {
|
|
1398
|
+
init_src();
|
|
1399
|
+
init_api();
|
|
1400
|
+
init_errors();
|
|
1401
|
+
init_output();
|
|
1402
|
+
});
|
|
1403
|
+
|
|
1404
|
+
// src/commands/wallet.ts
|
|
1405
|
+
var exports_wallet = {};
|
|
1406
|
+
__export(exports_wallet, {
|
|
1407
|
+
register: () => register10
|
|
1408
|
+
});
|
|
1409
|
+
import chalk5 from "chalk";
|
|
1410
|
+
function register10(program) {
|
|
1411
|
+
const wallet = program.command("wallet").description("View wallet balance, transactions, and spending limits.");
|
|
1412
|
+
wallet.command("balance").description("Show USDC wallet balance").action(handleErrors(async () => {
|
|
1413
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1414
|
+
const bal = await client.get("/v1/wallet/balance");
|
|
1415
|
+
if (humanMode) {
|
|
1416
|
+
console.log(`
|
|
1417
|
+
${chalk5.bold("Balance:")} $${bal.balance_dollars.toFixed(2)} USDC`);
|
|
1418
|
+
console.log(chalk5.dim(` Lifetime spent: $${(bal.lifetime_spent_cents / 100).toFixed(2)}`));
|
|
1419
|
+
console.log(chalk5.dim(` Lifetime deposited: $${(bal.lifetime_deposited_cents / 100).toFixed(2)}`));
|
|
1420
|
+
console.log();
|
|
1421
|
+
} else {
|
|
1422
|
+
output({
|
|
1423
|
+
balance_cents: bal.balance_cents,
|
|
1424
|
+
balance_dollars: bal.balance_dollars,
|
|
1425
|
+
lifetime_spent_cents: bal.lifetime_spent_cents,
|
|
1426
|
+
lifetime_deposited_cents: bal.lifetime_deposited_cents
|
|
1427
|
+
});
|
|
1428
|
+
}
|
|
1429
|
+
}));
|
|
1430
|
+
wallet.command("transactions").description("View transaction history").option("--limit <n>", "Number of transactions", "20").option("--offset <n>", "Offset for pagination", "0").action(handleErrors(async (opts) => {
|
|
1431
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1432
|
+
const result = await client.get("/v1/wallet/transactions", {
|
|
1433
|
+
limit: opts.limit,
|
|
1434
|
+
offset: opts.offset
|
|
1435
|
+
});
|
|
1436
|
+
outputTable(result.transactions ?? result, [
|
|
1437
|
+
{ header: "ID", key: "id", style: "dim" },
|
|
1438
|
+
{ header: "Type", key: "type" },
|
|
1439
|
+
{ header: "Amount", key: "amount_cents" },
|
|
1440
|
+
{ header: "Balance After", key: "balance_after_cents" },
|
|
1441
|
+
{ header: "Date", key: "created_at" }
|
|
1442
|
+
], "Transactions");
|
|
1443
|
+
}));
|
|
1444
|
+
wallet.command("limits").description("View spending limits").action(handleErrors(async () => {
|
|
1445
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1446
|
+
const limits = await client.get("/v1/x402/settings");
|
|
1447
|
+
outputDetail(limits, "Spending Limits");
|
|
1448
|
+
}));
|
|
1449
|
+
wallet.command("set-limits").description("Update spending limits (amounts in USDC atomic units, 1 USDC = 1,000,000)").option("--max-per-call <atomic>", "Max per call in atomic units (0-5,000,000)").option("--daily-limit <atomic>", "Daily limit in atomic units (0 to remove limit)").action(handleErrors(async (opts) => {
|
|
1450
|
+
if (!opts.maxPerCall && !opts.dailyLimit) {
|
|
1451
|
+
outputError("invalid_input", "Provide at least one of --max-per-call or --daily-limit");
|
|
1452
|
+
process.exit(1);
|
|
1453
|
+
}
|
|
1454
|
+
const body = {};
|
|
1455
|
+
if (opts.maxPerCall)
|
|
1456
|
+
body.max_per_call_atomic = parseInt(opts.maxPerCall, 10);
|
|
1457
|
+
if (opts.dailyLimit)
|
|
1458
|
+
body.daily_limit_atomic = parseInt(opts.dailyLimit, 10);
|
|
1459
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1460
|
+
const limits = await client.put("/v1/x402/settings", body);
|
|
1461
|
+
outputDetail(limits, "Updated Spending Limits");
|
|
1462
|
+
}));
|
|
1463
|
+
}
|
|
1464
|
+
var init_wallet = __esm(() => {
|
|
1465
|
+
init_src();
|
|
1466
|
+
init_api();
|
|
1467
|
+
init_errors();
|
|
1468
|
+
init_output();
|
|
1469
|
+
});
|
|
1470
|
+
|
|
1471
|
+
// src/commands/credentials.ts
|
|
1472
|
+
var exports_credentials = {};
|
|
1473
|
+
__export(exports_credentials, {
|
|
1474
|
+
register: () => register11
|
|
1475
|
+
});
|
|
1476
|
+
import { createInterface as createInterface2 } from "node:readline";
|
|
1477
|
+
function register11(program) {
|
|
1478
|
+
const credentials = program.command("credentials").description("Store service credentials.");
|
|
1479
|
+
credentials.command("store <serviceId>").description("Store a credential for a service").option("--type <type>", "Credential type: api_key, bearer, oauth", "api_key").action(handleErrors(async (serviceId, opts) => {
|
|
1480
|
+
let credentialValue;
|
|
1481
|
+
if (humanMode) {
|
|
1482
|
+
const rl = createInterface2({ input: process.stdin, output: process.stderr });
|
|
1483
|
+
credentialValue = await new Promise((resolve) => {
|
|
1484
|
+
process.stderr.write(" Enter credential value: ");
|
|
1485
|
+
rl.question("", (answer) => {
|
|
1486
|
+
rl.close();
|
|
1487
|
+
resolve(answer.trim());
|
|
1488
|
+
});
|
|
1489
|
+
});
|
|
1490
|
+
} else {
|
|
1491
|
+
credentialValue = (await Bun.stdin.text()).trim();
|
|
1492
|
+
if (!credentialValue) {
|
|
1493
|
+
outputError("invalid_input", "No credential provided on stdin");
|
|
1494
|
+
process.exit(1);
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1498
|
+
const result = await client.post("/v1/credentials/store", {
|
|
1499
|
+
service_id: serviceId,
|
|
1500
|
+
credential_type: opts.type,
|
|
1501
|
+
credential_value: credentialValue
|
|
1502
|
+
});
|
|
1503
|
+
outputSuccess(`Credential stored for ${result.service_name ?? serviceId}`, {
|
|
1504
|
+
service_id: result.service_id,
|
|
1505
|
+
credential_type: result.credential_type
|
|
1506
|
+
});
|
|
1507
|
+
}));
|
|
1508
|
+
}
|
|
1509
|
+
var init_credentials = __esm(() => {
|
|
1510
|
+
init_src();
|
|
1511
|
+
init_api();
|
|
1512
|
+
init_errors();
|
|
1513
|
+
init_output();
|
|
1514
|
+
});
|
|
1515
|
+
|
|
1516
|
+
// src/commands/keys.ts
|
|
1517
|
+
var exports_keys = {};
|
|
1518
|
+
__export(exports_keys, {
|
|
1519
|
+
register: () => register12
|
|
1520
|
+
});
|
|
1521
|
+
function register12(program) {
|
|
1522
|
+
const keys = program.command("keys").description("Manage API keys.");
|
|
1523
|
+
keys.command("list").description("List all API keys").action(handleErrors(async () => {
|
|
1524
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1525
|
+
const result = await client.get("/v1/api-keys");
|
|
1526
|
+
outputTable(result, [
|
|
1527
|
+
{ header: "ID", key: "id", style: "dim" },
|
|
1528
|
+
{ header: "Name", key: "name", style: "bold" },
|
|
1529
|
+
{ header: "Prefix", key: "key_prefix" },
|
|
1530
|
+
{ header: "Created", key: "created_at" },
|
|
1531
|
+
{ header: "Last Used", key: "last_used" }
|
|
1532
|
+
], "API Keys");
|
|
1533
|
+
}));
|
|
1534
|
+
keys.command("create <name>").description("Create a new API key").action(handleErrors(async (name) => {
|
|
1535
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1536
|
+
const key = await client.post("/v1/api-keys", { name });
|
|
1537
|
+
outputDetail({
|
|
1538
|
+
id: key.id,
|
|
1539
|
+
name: key.name,
|
|
1540
|
+
key: key.key,
|
|
1541
|
+
key_prefix: key.key_prefix
|
|
1542
|
+
}, `Created API Key: ${key.name}`);
|
|
1543
|
+
}));
|
|
1544
|
+
keys.command("rotate <keyId>").description("Rotate an API key (generates new key material)").action(handleErrors(async (keyId) => {
|
|
1545
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1546
|
+
const key = await client.post(`/v1/api-keys/${keyId}/rotate`);
|
|
1547
|
+
outputDetail({
|
|
1548
|
+
id: key.id,
|
|
1549
|
+
name: key.name,
|
|
1550
|
+
key: key.key,
|
|
1551
|
+
key_prefix: key.key_prefix
|
|
1552
|
+
}, "Rotated API Key");
|
|
1553
|
+
}));
|
|
1554
|
+
keys.command("revoke <keyId>").description("Revoke an API key").action(handleErrors(async (keyId) => {
|
|
1555
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1556
|
+
await client.delete(`/v1/api-keys/${keyId}`);
|
|
1557
|
+
outputSuccess(`Revoked API key ${keyId}`);
|
|
1558
|
+
}));
|
|
1559
|
+
}
|
|
1560
|
+
var init_keys = __esm(() => {
|
|
1561
|
+
init_src();
|
|
1562
|
+
init_api();
|
|
1563
|
+
init_errors();
|
|
1564
|
+
init_output();
|
|
1565
|
+
});
|
|
1566
|
+
|
|
1567
|
+
// src/commands/sites.ts
|
|
1568
|
+
var exports_sites = {};
|
|
1569
|
+
__export(exports_sites, {
|
|
1570
|
+
register: () => register13
|
|
1571
|
+
});
|
|
1572
|
+
function register13(program) {
|
|
1573
|
+
const sites = program.command("sites").description("Search and inspect the agent web directory.");
|
|
1574
|
+
sites.command("search <query>").description("Search the agent web directory").option("--category <cat>", "Filter by category").option("--limit <n>", "Maximum results", "10").action(handleErrors(async (query, opts) => {
|
|
1575
|
+
const client = getPublicClient(ctx.profile);
|
|
1576
|
+
const result = await client.publicGet("/v1/agent-sites/search", {
|
|
1577
|
+
query,
|
|
1578
|
+
category: opts.category,
|
|
1579
|
+
limit: opts.limit
|
|
1580
|
+
});
|
|
1581
|
+
outputTable(result, [
|
|
1582
|
+
{ header: "ID", key: "id", style: "dim" },
|
|
1583
|
+
{ header: "Domain", key: "domain", style: "bold" },
|
|
1584
|
+
{ header: "Title", key: "page_title" },
|
|
1585
|
+
{ header: "Category", key: "category" }
|
|
1586
|
+
], `Sites matching '${query}'`);
|
|
1587
|
+
}));
|
|
1588
|
+
sites.command("get <identifier>").description("Get site details by ID or domain").action(handleErrors(async (identifier) => {
|
|
1589
|
+
const client = getPublicClient(ctx.profile);
|
|
1590
|
+
let site;
|
|
1591
|
+
if (identifier.includes(".") && identifier.length < 100) {
|
|
1592
|
+
try {
|
|
1593
|
+
site = await client.publicGet(`/v1/agent-sites/domain/${encodeURIComponent(identifier)}`);
|
|
1594
|
+
outputDetail(site, site.domain);
|
|
1595
|
+
return;
|
|
1596
|
+
} catch {}
|
|
1597
|
+
}
|
|
1598
|
+
site = await client.publicGet(`/v1/agent-sites/${identifier}`);
|
|
1599
|
+
outputDetail(site, site.domain);
|
|
1600
|
+
}));
|
|
1601
|
+
}
|
|
1602
|
+
var init_sites = __esm(() => {
|
|
1603
|
+
init_src();
|
|
1604
|
+
init_api();
|
|
1605
|
+
init_errors();
|
|
1606
|
+
init_output();
|
|
1607
|
+
});
|
|
1608
|
+
|
|
1609
|
+
// src/commands/agent.ts
|
|
1610
|
+
var exports_agent = {};
|
|
1611
|
+
__export(exports_agent, {
|
|
1612
|
+
register: () => register14
|
|
1613
|
+
});
|
|
1614
|
+
import chalk6 from "chalk";
|
|
1615
|
+
function register14(program) {
|
|
1616
|
+
const agent = program.command("agent").description("Register and manage autonomous agents.");
|
|
1617
|
+
agent.command("register <name> <email>").description("Register a new autonomous agent (no auth required)").action(handleErrors(async (name, email) => {
|
|
1618
|
+
const client = new ApiClient(getBaseUrl(ctx.profile));
|
|
1619
|
+
const result = await client.publicPost("/v1/agents", {
|
|
1620
|
+
name,
|
|
1621
|
+
operator_email: email
|
|
1622
|
+
});
|
|
1623
|
+
if (humanMode) {
|
|
1624
|
+
console.log(`
|
|
1625
|
+
${chalk6.green("✓")} Agent registered!`);
|
|
1626
|
+
console.log(` ${chalk6.cyan("Agent ID:")} ${result.agent_id}`);
|
|
1627
|
+
console.log(` ${chalk6.cyan("API Key:")} ${chalk6.bold(result.api_key)}`);
|
|
1628
|
+
console.log(chalk6.dim(" Save this API key — it won't be shown again."));
|
|
1629
|
+
if (result.deposit_address) {
|
|
1630
|
+
console.log(` ${chalk6.cyan("Deposit Address:")} ${result.deposit_address}`);
|
|
1631
|
+
}
|
|
1632
|
+
console.log();
|
|
1633
|
+
} else {
|
|
1634
|
+
outputDetail(result, "Agent Registration");
|
|
1635
|
+
}
|
|
1636
|
+
}));
|
|
1637
|
+
agent.command("info").description("Show current agent info and wallet balance").action(handleErrors(async () => {
|
|
1638
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1639
|
+
const info = await client.get("/v1/agents/me");
|
|
1640
|
+
outputDetail(info, info.name);
|
|
1641
|
+
}));
|
|
1642
|
+
agent.command("fund").description("Fund agent wallet via card or crypto").option("--method <method>", "Funding method: card_checkout or crypto", "card_checkout").option("--amount <cents>", "Amount in cents (required for card_checkout, min 100)").action(handleErrors(async (opts) => {
|
|
1643
|
+
const client = getClient(ctx.apiKey, ctx.profile);
|
|
1644
|
+
if (opts.method === "card_checkout" && !opts.amount) {
|
|
1645
|
+
outputError("invalid_input", "Amount is required for card_checkout (e.g. --amount 500 for $5.00)");
|
|
1646
|
+
process.exit(1);
|
|
1647
|
+
}
|
|
1648
|
+
const result = await client.post("/v1/agents/wallets/fund", {
|
|
1649
|
+
method: opts.method,
|
|
1650
|
+
amount_cents: opts.amount ? parseInt(opts.amount, 10) : undefined
|
|
1651
|
+
});
|
|
1652
|
+
if (humanMode && result.checkout_url) {
|
|
1653
|
+
console.log(`
|
|
1654
|
+
${chalk6.green("✓")} Checkout created`);
|
|
1655
|
+
console.log(` ${chalk6.cyan("Open:")} ${result.checkout_url}`);
|
|
1656
|
+
try {
|
|
1657
|
+
if (process.platform === "darwin") {
|
|
1658
|
+
Bun.spawn(["open", result.checkout_url]);
|
|
1659
|
+
} else if (process.platform === "linux") {
|
|
1660
|
+
Bun.spawn(["xdg-open", result.checkout_url]);
|
|
1661
|
+
}
|
|
1662
|
+
} catch {}
|
|
1663
|
+
console.log();
|
|
1664
|
+
} else if (humanMode && result.deposit_address) {
|
|
1665
|
+
console.log(`
|
|
1666
|
+
${chalk6.green("✓")} Send USDC to:`);
|
|
1667
|
+
console.log(` ${chalk6.cyan("Address:")} ${result.deposit_address}`);
|
|
1668
|
+
if (result.network)
|
|
1669
|
+
console.log(` ${chalk6.cyan("Network:")} ${result.network}`);
|
|
1670
|
+
console.log();
|
|
1671
|
+
} else {
|
|
1672
|
+
outputDetail(result, "Fund Wallet");
|
|
1673
|
+
}
|
|
1674
|
+
}));
|
|
1675
|
+
}
|
|
1676
|
+
var init_agent = __esm(() => {
|
|
1677
|
+
init_src();
|
|
1678
|
+
init_api();
|
|
1679
|
+
init_config();
|
|
1680
|
+
init_errors();
|
|
1681
|
+
init_output();
|
|
1682
|
+
});
|
|
1683
|
+
|
|
1684
|
+
// src/commands/config.ts
|
|
1685
|
+
var exports_config = {};
|
|
1686
|
+
__export(exports_config, {
|
|
1687
|
+
register: () => register15
|
|
1688
|
+
});
|
|
1689
|
+
import chalk7 from "chalk";
|
|
1690
|
+
function register15(program) {
|
|
1691
|
+
const config = program.command("config").description("Manage CLI configuration.");
|
|
1692
|
+
config.command("set <key> <value>").description("Set a config value").action(handleErrors(async (key, value) => {
|
|
1693
|
+
configSet(key, value, ctx.profile);
|
|
1694
|
+
if (humanMode) {
|
|
1695
|
+
console.log(`${chalk7.green("✓")} Set ${key} = ${value} (profile: ${ctx.profile})`);
|
|
1696
|
+
} else {
|
|
1697
|
+
output({ key, value, profile: ctx.profile });
|
|
1698
|
+
}
|
|
1699
|
+
}));
|
|
1700
|
+
config.command("get <key>").description("Get a config value").action(handleErrors(async (key) => {
|
|
1701
|
+
const value = configGet(key, ctx.profile);
|
|
1702
|
+
if (humanMode) {
|
|
1703
|
+
if (value !== undefined) {
|
|
1704
|
+
console.log(` ${chalk7.cyan(key + ":")} ${value}`);
|
|
1705
|
+
} else {
|
|
1706
|
+
console.log(` ${chalk7.cyan(key + ":")} ${chalk7.dim("(not set)")}`);
|
|
1707
|
+
}
|
|
1708
|
+
} else {
|
|
1709
|
+
output({ key, value: value ?? null });
|
|
1710
|
+
}
|
|
1711
|
+
}));
|
|
1712
|
+
config.command("profiles").description("List available profiles").action(handleErrors(async () => {
|
|
1713
|
+
const names = listProfiles();
|
|
1714
|
+
if (humanMode) {
|
|
1715
|
+
if (!names.length) {
|
|
1716
|
+
console.log(chalk7.dim(" No profiles configured. Run 'danube login' to create one."));
|
|
1717
|
+
} else {
|
|
1718
|
+
for (const name of names) {
|
|
1719
|
+
const marker = name === ctx.profile ? ` ${chalk7.green("●")}` : "";
|
|
1720
|
+
console.log(` ${name}${marker}`);
|
|
1721
|
+
}
|
|
1722
|
+
}
|
|
1723
|
+
} else {
|
|
1724
|
+
output({ profiles: names, active: ctx.profile });
|
|
1725
|
+
}
|
|
1726
|
+
}));
|
|
1727
|
+
}
|
|
1728
|
+
var init_config2 = __esm(() => {
|
|
1729
|
+
init_src();
|
|
1730
|
+
init_config();
|
|
1731
|
+
init_errors();
|
|
1732
|
+
init_output();
|
|
1733
|
+
});
|
|
1734
|
+
|
|
1735
|
+
// src/index.ts
|
|
1736
|
+
init_output();
|
|
1737
|
+
init_version();
|
|
1738
|
+
import { Command as Command2 } from "commander";
|
|
1739
|
+
var ctx2 = {
|
|
1740
|
+
human: false,
|
|
1741
|
+
apiKey: undefined,
|
|
1742
|
+
profile: "default",
|
|
1743
|
+
verbose: false,
|
|
1744
|
+
quiet: false,
|
|
1745
|
+
noColor: false
|
|
1746
|
+
};
|
|
1747
|
+
function main() {
|
|
1748
|
+
const program = new Command2;
|
|
1749
|
+
program.name("danube").description(`Danube CLI — agent-first tool infrastructure.
|
|
1750
|
+
|
|
1751
|
+
` + `search → find tools. execute → run them. connect → authenticate.
|
|
1752
|
+
|
|
1753
|
+
` + "Bias toward action: run 'danube search <task>', then 'danube execute <slug>'.").version(VERSION, "--version", "Show version").option("--human", "Human-readable output (tables, colors)").option("--json", "Machine-readable JSON output").option("--api-key <key>", "Override API key (env: DANUBE_API_KEY)").option("--profile <name>", "Use named profile", "default").option("-v, --verbose", "Verbose output", false).option("-q, --quiet", "Suppress non-essential output", false).option("--no-color", "Disable colored output", false).hook("preAction", (thisCommand) => {
|
|
1754
|
+
const opts = thisCommand.opts();
|
|
1755
|
+
if (opts.json) {
|
|
1756
|
+
ctx2.human = false;
|
|
1757
|
+
} else if (opts.human) {
|
|
1758
|
+
ctx2.human = true;
|
|
1759
|
+
} else {
|
|
1760
|
+
ctx2.human = process.stdout.isTTY === true;
|
|
1761
|
+
}
|
|
1762
|
+
ctx2.apiKey = opts.apiKey;
|
|
1763
|
+
ctx2.profile = opts.profile;
|
|
1764
|
+
ctx2.verbose = opts.verbose;
|
|
1765
|
+
ctx2.quiet = opts.quiet;
|
|
1766
|
+
ctx2.noColor = opts.noColor ?? opts.color === false;
|
|
1767
|
+
setHumanMode(ctx2.human);
|
|
1768
|
+
setQuietMode(ctx2.quiet);
|
|
1769
|
+
});
|
|
1770
|
+
registerCommands(program);
|
|
1771
|
+
program.parse(process.argv);
|
|
1772
|
+
}
|
|
1773
|
+
function registerCommands(program) {
|
|
1774
|
+
(init_auth(), __toCommonJS(exports_auth)).register(program);
|
|
1775
|
+
(init_search(), __toCommonJS(exports_search)).register(program);
|
|
1776
|
+
(init_execute(), __toCommonJS(exports_execute)).register(program);
|
|
1777
|
+
(init_connect(), __toCommonJS(exports_connect)).register(program);
|
|
1778
|
+
(init_completion(), __toCommonJS(exports_completion)).register(program);
|
|
1779
|
+
(init_tools(), __toCommonJS(exports_tools)).register(program);
|
|
1780
|
+
(init_services(), __toCommonJS(exports_services)).register(program);
|
|
1781
|
+
(init_workflows(), __toCommonJS(exports_workflows)).register(program);
|
|
1782
|
+
(init_skills(), __toCommonJS(exports_skills)).register(program);
|
|
1783
|
+
(init_wallet(), __toCommonJS(exports_wallet)).register(program);
|
|
1784
|
+
(init_credentials(), __toCommonJS(exports_credentials)).register(program);
|
|
1785
|
+
(init_keys(), __toCommonJS(exports_keys)).register(program);
|
|
1786
|
+
(init_sites(), __toCommonJS(exports_sites)).register(program);
|
|
1787
|
+
(init_agent(), __toCommonJS(exports_agent)).register(program);
|
|
1788
|
+
(init_config2(), __toCommonJS(exports_config)).register(program);
|
|
1789
|
+
}
|
|
1790
|
+
|
|
1791
|
+
// bin/danube.ts
|
|
1792
|
+
main();
|