@agent-nexus/cli 0.1.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/index.js +3992 -0
- package/package.json +46 -0
package/dist/index.js
ADDED
|
@@ -0,0 +1,3992 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
var __create = Object.create;
|
|
4
|
+
var __defProp = Object.defineProperty;
|
|
5
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
8
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
9
|
+
var __esm = (fn, res) => function __init() {
|
|
10
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
11
|
+
};
|
|
12
|
+
var __export = (target, all) => {
|
|
13
|
+
for (var name in all)
|
|
14
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
15
|
+
};
|
|
16
|
+
var __copyProps = (to, from, except, desc) => {
|
|
17
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
18
|
+
for (let key of __getOwnPropNames(from))
|
|
19
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
20
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
21
|
+
}
|
|
22
|
+
return to;
|
|
23
|
+
};
|
|
24
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
25
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
26
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
27
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
28
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
29
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
30
|
+
mod
|
|
31
|
+
));
|
|
32
|
+
|
|
33
|
+
// src/output.ts
|
|
34
|
+
var output_exports = {};
|
|
35
|
+
__export(output_exports, {
|
|
36
|
+
color: () => color,
|
|
37
|
+
isJsonMode: () => isJsonMode,
|
|
38
|
+
printList: () => printList,
|
|
39
|
+
printPaginationMeta: () => printPaginationMeta,
|
|
40
|
+
printRecord: () => printRecord,
|
|
41
|
+
printSuccess: () => printSuccess,
|
|
42
|
+
printTable: () => printTable,
|
|
43
|
+
setJsonMode: () => setJsonMode
|
|
44
|
+
});
|
|
45
|
+
function setJsonMode(enabled) {
|
|
46
|
+
_jsonMode = enabled;
|
|
47
|
+
}
|
|
48
|
+
function isJsonMode() {
|
|
49
|
+
return _jsonMode;
|
|
50
|
+
}
|
|
51
|
+
function c2(code, text) {
|
|
52
|
+
return NO_COLOR2 ? text : `\x1B[${code}m${text}\x1B[0m`;
|
|
53
|
+
}
|
|
54
|
+
function printTable(rows, columns) {
|
|
55
|
+
if (_jsonMode) {
|
|
56
|
+
console.log(JSON.stringify(rows, null, 2));
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
if (rows.length === 0) {
|
|
60
|
+
console.log(color.dim("No results."));
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const widths = columns.map((col) => {
|
|
64
|
+
const headerLen = col.label.length;
|
|
65
|
+
const maxDataLen = rows.reduce((max, row) => {
|
|
66
|
+
const val = col.format ? col.format(row[col.key]) : String(row[col.key] ?? "");
|
|
67
|
+
return Math.max(max, val.length);
|
|
68
|
+
}, 0);
|
|
69
|
+
return col.width ?? Math.min(Math.max(headerLen, maxDataLen), 50);
|
|
70
|
+
});
|
|
71
|
+
const header = columns.map((col, i) => color.bold(col.label.padEnd(widths[i]))).join(" ");
|
|
72
|
+
console.log(header);
|
|
73
|
+
console.log(columns.map((_, i) => "\u2500".repeat(widths[i])).join(" "));
|
|
74
|
+
for (const row of rows) {
|
|
75
|
+
const line = columns.map((col, i) => {
|
|
76
|
+
const val = col.format ? col.format(row[col.key]) : String(row[col.key] ?? "");
|
|
77
|
+
return val.padEnd(widths[i]).slice(0, widths[i]);
|
|
78
|
+
}).join(" ");
|
|
79
|
+
console.log(line);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function printRecord(data, fields) {
|
|
83
|
+
if (_jsonMode) {
|
|
84
|
+
console.log(JSON.stringify(data, null, 2));
|
|
85
|
+
return;
|
|
86
|
+
}
|
|
87
|
+
const entries = fields ? fields.map((f) => [f.label, f.format ? f.format(data[f.key]) : String(data[f.key] ?? "")]) : Object.entries(data).map(([k, v]) => [k, String(v ?? "")]);
|
|
88
|
+
const maxLabel = entries.reduce((max, [label]) => Math.max(max, label.length), 0);
|
|
89
|
+
for (const [label, value] of entries) {
|
|
90
|
+
console.log(`${color.bold(label.padEnd(maxLabel))} ${value}`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
function printSuccess(message, data) {
|
|
94
|
+
if (_jsonMode) {
|
|
95
|
+
console.log(JSON.stringify({ success: true, ...data }, null, 2));
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
console.log(color.green("\u2713") + " " + message);
|
|
99
|
+
if (data) {
|
|
100
|
+
for (const [key, value] of Object.entries(data)) {
|
|
101
|
+
console.log(` ${color.dim(key + ":")} ${value}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function printPaginationMeta(meta) {
|
|
106
|
+
if (_jsonMode) return;
|
|
107
|
+
const parts = [];
|
|
108
|
+
if (meta.total != null) parts.push(`${meta.total} total`);
|
|
109
|
+
if (meta.page != null) parts.push(`page ${meta.page}`);
|
|
110
|
+
if (meta.hasMore) parts.push("more available");
|
|
111
|
+
if (parts.length > 0) {
|
|
112
|
+
console.log(color.dim(`
|
|
113
|
+
${parts.join(" \xB7 ")}`));
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
function printList(data, meta, columns) {
|
|
117
|
+
if (_jsonMode) {
|
|
118
|
+
console.log(JSON.stringify({ data, meta }, null, 2));
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
printTable(data, columns);
|
|
122
|
+
if (meta) {
|
|
123
|
+
printPaginationMeta(meta);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
var _jsonMode, NO_COLOR2, color;
|
|
127
|
+
var init_output = __esm({
|
|
128
|
+
"src/output.ts"() {
|
|
129
|
+
"use strict";
|
|
130
|
+
_jsonMode = false;
|
|
131
|
+
NO_COLOR2 = !!process.env.NO_COLOR || process.argv.includes("--no-color") || !process.stdout.isTTY;
|
|
132
|
+
color = {
|
|
133
|
+
orange: (t) => c2("38;2;245;70;26", t),
|
|
134
|
+
teal: (t) => c2("38;2;0;183;165", t),
|
|
135
|
+
dim: (t) => c2("2", t),
|
|
136
|
+
bold: (t) => c2("1", t),
|
|
137
|
+
red: (t) => c2("31", t),
|
|
138
|
+
green: (t) => c2("32", t),
|
|
139
|
+
yellow: (t) => c2("33", t),
|
|
140
|
+
cyan: (t) => c2("36", t)
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// src/index.ts
|
|
146
|
+
var import_commander = require("commander");
|
|
147
|
+
|
|
148
|
+
// src/banner.ts
|
|
149
|
+
var NO_COLOR = !!process.env.NO_COLOR || process.argv.includes("--no-color") || !process.stdout.isTTY;
|
|
150
|
+
function c(code, text) {
|
|
151
|
+
return NO_COLOR ? text : `\x1B[${code}m${text}\x1B[0m`;
|
|
152
|
+
}
|
|
153
|
+
var teal = (t) => c("38;2;0;183;165", t);
|
|
154
|
+
var dim = (t) => c("2", t);
|
|
155
|
+
var bold = (t) => c("1", t);
|
|
156
|
+
var WORDMARK = [
|
|
157
|
+
" \u2588\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2557 \u2588\u2588\u2557\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557",
|
|
158
|
+
" \u2588\u2588\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D\u255A\u2588\u2588\u2557\u2588\u2588\u2554\u255D\u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u2550\u2550\u255D",
|
|
159
|
+
" \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2557 \u255A\u2588\u2588\u2588\u2554\u255D \u2588\u2588\u2551 \u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557",
|
|
160
|
+
" \u2588\u2588\u2551\u255A\u2588\u2588\u2557\u2588\u2588\u2551\u2588\u2588\u2554\u2550\u2550\u255D \u2588\u2588\u2554\u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2551\u255A\u2550\u2550\u2550\u2550\u2588\u2588\u2551",
|
|
161
|
+
" \u2588\u2588\u2551 \u255A\u2588\u2588\u2588\u2588\u2551\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u2588\u2588\u2554\u255D \u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2551",
|
|
162
|
+
" \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u255D\u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D\u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D"
|
|
163
|
+
];
|
|
164
|
+
function getBanner(version) {
|
|
165
|
+
const lines = [""];
|
|
166
|
+
for (const line of WORDMARK) {
|
|
167
|
+
lines.push(bold(line));
|
|
168
|
+
}
|
|
169
|
+
lines.push("");
|
|
170
|
+
lines.push(dim(" The AI agent platform") + " " + teal("v" + version));
|
|
171
|
+
lines.push("");
|
|
172
|
+
return lines.join("\n");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// src/client.ts
|
|
176
|
+
var import_sdk = require("@agent-nexus/sdk");
|
|
177
|
+
|
|
178
|
+
// src/config.ts
|
|
179
|
+
var import_node_fs = __toESM(require("fs"));
|
|
180
|
+
var import_node_os = __toESM(require("os"));
|
|
181
|
+
var import_node_path = __toESM(require("path"));
|
|
182
|
+
var URL_MAP = {
|
|
183
|
+
production: "https://api.nexusgpt.io",
|
|
184
|
+
dev: "http://localhost:3001"
|
|
185
|
+
};
|
|
186
|
+
var CONFIG_DIR = import_node_path.default.join(import_node_os.default.homedir(), ".nexus-mcp");
|
|
187
|
+
var CONFIG_FILE = import_node_path.default.join(CONFIG_DIR, "config.json");
|
|
188
|
+
function loadConfig() {
|
|
189
|
+
try {
|
|
190
|
+
const raw = import_node_fs.default.readFileSync(CONFIG_FILE, "utf-8");
|
|
191
|
+
return JSON.parse(raw);
|
|
192
|
+
} catch {
|
|
193
|
+
return {};
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
function saveConfig(config) {
|
|
197
|
+
import_node_fs.default.mkdirSync(CONFIG_DIR, { recursive: true, mode: 448 });
|
|
198
|
+
import_node_fs.default.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2) + "\n", {
|
|
199
|
+
mode: 384
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
function clearConfig() {
|
|
203
|
+
try {
|
|
204
|
+
import_node_fs.default.unlinkSync(CONFIG_FILE);
|
|
205
|
+
} catch {
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
function resolveBaseUrl(override) {
|
|
209
|
+
if (override) return override;
|
|
210
|
+
if (process.env.NEXUS_BASE_URL) return process.env.NEXUS_BASE_URL;
|
|
211
|
+
const config = loadConfig();
|
|
212
|
+
if (config.baseUrl) return config.baseUrl;
|
|
213
|
+
const env = process.env.NEXUS_ENV ?? "production";
|
|
214
|
+
return URL_MAP[env] ?? URL_MAP.production;
|
|
215
|
+
}
|
|
216
|
+
function resolveApiKey(override) {
|
|
217
|
+
if (override) return override;
|
|
218
|
+
if (process.env.NEXUS_API_KEY) return process.env.NEXUS_API_KEY;
|
|
219
|
+
const config = loadConfig();
|
|
220
|
+
if (config.apiKey) return config.apiKey;
|
|
221
|
+
throw new Error("No API key found. Set NEXUS_API_KEY or run:\n nexus auth login");
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
// src/client.ts
|
|
225
|
+
function createClient(opts) {
|
|
226
|
+
return new import_sdk.NexusClient({
|
|
227
|
+
apiKey: resolveApiKey(opts?.apiKey),
|
|
228
|
+
baseUrl: resolveBaseUrl(opts?.baseUrl)
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
// src/errors.ts
|
|
233
|
+
var import_sdk2 = require("@agent-nexus/sdk");
|
|
234
|
+
init_output();
|
|
235
|
+
function handleError(err) {
|
|
236
|
+
if (err instanceof import_sdk2.NexusAuthenticationError) {
|
|
237
|
+
printCliError(
|
|
238
|
+
"Authentication failed \u2014 invalid or missing API key.",
|
|
239
|
+
'Run "nexus auth login" to re-authenticate, or set NEXUS_API_KEY.'
|
|
240
|
+
);
|
|
241
|
+
return 1;
|
|
242
|
+
}
|
|
243
|
+
if (err instanceof import_sdk2.NexusApiError) {
|
|
244
|
+
if (err.status === 404) {
|
|
245
|
+
printCliError(
|
|
246
|
+
`Not found: ${err.message}`,
|
|
247
|
+
'Run "nexus <resource> list" to see available resources.'
|
|
248
|
+
);
|
|
249
|
+
} else if (err.status === 422 || err.code === "VALIDATION_ERROR") {
|
|
250
|
+
printCliError(
|
|
251
|
+
`Validation error: ${err.message}`,
|
|
252
|
+
err.details ? `Details: ${JSON.stringify(err.details)}` : void 0
|
|
253
|
+
);
|
|
254
|
+
} else {
|
|
255
|
+
printCliError(`API error (${err.status}): ${err.message}`);
|
|
256
|
+
}
|
|
257
|
+
return 1;
|
|
258
|
+
}
|
|
259
|
+
if (err instanceof import_sdk2.NexusConnectionError) {
|
|
260
|
+
printCliError(
|
|
261
|
+
"Could not reach the Nexus API.",
|
|
262
|
+
"Check your network connection and base URL configuration."
|
|
263
|
+
);
|
|
264
|
+
return 1;
|
|
265
|
+
}
|
|
266
|
+
if (err instanceof import_sdk2.NexusError) {
|
|
267
|
+
printCliError(err.message);
|
|
268
|
+
return 1;
|
|
269
|
+
}
|
|
270
|
+
if (err instanceof Error) {
|
|
271
|
+
printCliError(err.message);
|
|
272
|
+
return 1;
|
|
273
|
+
}
|
|
274
|
+
printCliError(String(err));
|
|
275
|
+
return 1;
|
|
276
|
+
}
|
|
277
|
+
function printCliError(message, hint) {
|
|
278
|
+
if (isJsonMode()) {
|
|
279
|
+
console.log(JSON.stringify({ error: { message, hint } }, null, 2));
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
console.error(color.red("Error:") + " " + message);
|
|
283
|
+
if (hint) {
|
|
284
|
+
console.error(color.dim(" " + hint));
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// src/commands/agent.ts
|
|
289
|
+
init_output();
|
|
290
|
+
|
|
291
|
+
// src/util/stdin.ts
|
|
292
|
+
function readStdin() {
|
|
293
|
+
return new Promise((resolve, reject) => {
|
|
294
|
+
const chunks = [];
|
|
295
|
+
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
296
|
+
process.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8").trim()));
|
|
297
|
+
process.stdin.on("error", reject);
|
|
298
|
+
if (process.stdin.isTTY) {
|
|
299
|
+
resolve("");
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
async function resolveInputValue(value) {
|
|
304
|
+
if (value === "-") {
|
|
305
|
+
return readStdin();
|
|
306
|
+
}
|
|
307
|
+
try {
|
|
308
|
+
const fs5 = await import("fs");
|
|
309
|
+
if (fs5.existsSync(value) && fs5.statSync(value).isFile()) {
|
|
310
|
+
return fs5.readFileSync(value, "utf-8").trim();
|
|
311
|
+
}
|
|
312
|
+
} catch {
|
|
313
|
+
}
|
|
314
|
+
return value;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// src/util/body.ts
|
|
318
|
+
async function resolveBody(raw) {
|
|
319
|
+
if (raw === void 0) return void 0;
|
|
320
|
+
let jsonStr;
|
|
321
|
+
if (raw === "-") {
|
|
322
|
+
jsonStr = await readStdin();
|
|
323
|
+
} else if (raw.endsWith(".json")) {
|
|
324
|
+
try {
|
|
325
|
+
const fs5 = await import("fs/promises");
|
|
326
|
+
jsonStr = (await fs5.readFile(raw, "utf-8")).trim();
|
|
327
|
+
} catch (err) {
|
|
328
|
+
throw new Error(
|
|
329
|
+
`Could not read file "${raw}": ${err instanceof Error ? err.message : String(err)}`
|
|
330
|
+
);
|
|
331
|
+
}
|
|
332
|
+
} else {
|
|
333
|
+
jsonStr = raw;
|
|
334
|
+
}
|
|
335
|
+
try {
|
|
336
|
+
return JSON.parse(jsonStr);
|
|
337
|
+
} catch {
|
|
338
|
+
throw new Error(
|
|
339
|
+
`Invalid JSON in --body: ${jsonStr.length > 120 ? jsonStr.slice(0, 120) + "\u2026" : jsonStr}`
|
|
340
|
+
);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
function mergeBodyWithFlags(body, flags) {
|
|
344
|
+
const merged = { ...body };
|
|
345
|
+
for (const [key, value] of Object.entries(flags)) {
|
|
346
|
+
if (value !== void 0) merged[key] = value;
|
|
347
|
+
}
|
|
348
|
+
return merged;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// src/util/pagination.ts
|
|
352
|
+
function addPaginationOptions(cmd) {
|
|
353
|
+
return cmd.option("--page <number>", "Page number", parseInt).option("--limit <number>", "Items per page", parseInt);
|
|
354
|
+
}
|
|
355
|
+
function getPaginationParams(opts) {
|
|
356
|
+
const params = {};
|
|
357
|
+
if (typeof opts.page === "number") params.page = opts.page;
|
|
358
|
+
if (typeof opts.limit === "number") params.limit = opts.limit;
|
|
359
|
+
return params;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
// src/commands/agent.ts
|
|
363
|
+
function registerAgentCommands(program2) {
|
|
364
|
+
const agent = program2.command("agent").description("Manage AI agents");
|
|
365
|
+
addPaginationOptions(
|
|
366
|
+
agent.command("list").description("List agents").option("--status <status>", "Filter by status (ACTIVE, DRAFT)").option("--search <query>", "Search by name or role").addHelpText(
|
|
367
|
+
"after",
|
|
368
|
+
`
|
|
369
|
+
Examples:
|
|
370
|
+
$ nexus agent list
|
|
371
|
+
$ nexus agent list --limit 5 --status ACTIVE
|
|
372
|
+
$ nexus agent list --search "support" --json`
|
|
373
|
+
)
|
|
374
|
+
).action(async (opts) => {
|
|
375
|
+
try {
|
|
376
|
+
const client = createClient(program2.optsWithGlobals());
|
|
377
|
+
const { data, meta } = await client.agents.list({
|
|
378
|
+
...getPaginationParams(opts),
|
|
379
|
+
status: opts.status,
|
|
380
|
+
search: opts.search
|
|
381
|
+
});
|
|
382
|
+
printList(
|
|
383
|
+
data,
|
|
384
|
+
meta,
|
|
385
|
+
[
|
|
386
|
+
{ key: "id", label: "ID", width: 36 },
|
|
387
|
+
{ key: "firstName", label: "FIRST NAME", width: 15 },
|
|
388
|
+
{ key: "lastName", label: "LAST NAME", width: 15 },
|
|
389
|
+
{ key: "role", label: "ROLE", width: 25 },
|
|
390
|
+
{ key: "status", label: "STATUS", width: 10 }
|
|
391
|
+
]
|
|
392
|
+
);
|
|
393
|
+
} catch (err) {
|
|
394
|
+
process.exitCode = handleError(err);
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
agent.command("get").description("Get agent details").argument("<id>", "Agent ID").addHelpText(
|
|
398
|
+
"after",
|
|
399
|
+
`
|
|
400
|
+
Examples:
|
|
401
|
+
$ nexus agent get abc-123
|
|
402
|
+
$ nexus agent get abc-123 --json`
|
|
403
|
+
).action(async (id) => {
|
|
404
|
+
try {
|
|
405
|
+
const client = createClient(program2.optsWithGlobals());
|
|
406
|
+
const agent2 = await client.agents.get(id);
|
|
407
|
+
printRecord(agent2, [
|
|
408
|
+
{ key: "id", label: "ID" },
|
|
409
|
+
{ key: "firstName", label: "First Name" },
|
|
410
|
+
{ key: "lastName", label: "Last Name" },
|
|
411
|
+
{ key: "role", label: "Role" },
|
|
412
|
+
{ key: "status", label: "Status" },
|
|
413
|
+
{ key: "model", label: "Model" },
|
|
414
|
+
{ key: "tone", label: "Tone" },
|
|
415
|
+
{ key: "createdAt", label: "Created" }
|
|
416
|
+
]);
|
|
417
|
+
} catch (err) {
|
|
418
|
+
process.exitCode = handleError(err);
|
|
419
|
+
}
|
|
420
|
+
});
|
|
421
|
+
agent.command("create").description("Create a new agent").requiredOption("--first-name <name>", "Agent first name").requiredOption("--last-name <name>", "Agent last name").requiredOption("--role <role>", "Agent role, e.g. 'Customer Support'").option("--bio <text>", "Full biography").option("--short-bio <text>", "Short biography for cards").option("--model <model>", "Model ID").option("--tone <tone>", "Communication tone").option("--prompt <file-or-->", "System prompt (file path, or '-' for stdin)").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
422
|
+
"after",
|
|
423
|
+
`
|
|
424
|
+
Examples:
|
|
425
|
+
$ nexus agent create --first-name Ada --last-name Lovelace --role "Assistant"
|
|
426
|
+
$ nexus agent create --first-name Bot --last-name Helper --role "Support" --model gpt-4o
|
|
427
|
+
$ cat prompt.md | nexus agent create --first-name Ada --last-name Lovelace --role "Assistant" --prompt -
|
|
428
|
+
$ nexus agent create --body '{"firstName":"Ada","lastName":"Lovelace","role":"Assistant"}'`
|
|
429
|
+
).action(async (opts) => {
|
|
430
|
+
try {
|
|
431
|
+
const client = createClient(program2.optsWithGlobals());
|
|
432
|
+
const base = await resolveBody(opts.body);
|
|
433
|
+
const flags = {};
|
|
434
|
+
if (opts.firstName !== void 0) flags.firstName = opts.firstName;
|
|
435
|
+
if (opts.lastName !== void 0) flags.lastName = opts.lastName;
|
|
436
|
+
if (opts.role !== void 0) flags.role = opts.role;
|
|
437
|
+
if (opts.bio !== void 0) flags.bio = opts.bio;
|
|
438
|
+
if (opts.shortBio !== void 0) flags.shortBio = opts.shortBio;
|
|
439
|
+
if (opts.model !== void 0) flags.model = opts.model;
|
|
440
|
+
if (opts.tone !== void 0) flags.tone = opts.tone;
|
|
441
|
+
if (opts.prompt) flags.prompt = await resolveInputValue(opts.prompt);
|
|
442
|
+
const body = mergeBodyWithFlags(base, flags);
|
|
443
|
+
const agent2 = await client.agents.create(body);
|
|
444
|
+
printSuccess("Agent created.", {
|
|
445
|
+
id: agent2.id,
|
|
446
|
+
name: `${agent2.firstName} ${agent2.lastName}`
|
|
447
|
+
});
|
|
448
|
+
} catch (err) {
|
|
449
|
+
process.exitCode = handleError(err);
|
|
450
|
+
}
|
|
451
|
+
});
|
|
452
|
+
agent.command("update").description("Update an agent").argument("<id>", "Agent ID").option("--first-name <name>", "Agent first name").option("--last-name <name>", "Agent last name").option("--role <role>", "Agent role").option("--bio <text>", "Full biography").option("--short-bio <text>", "Short biography").option("--model <model>", "Model ID").option("--tone <tone>", "Communication tone").option("--prompt <file-or-->", "System prompt (file path, or '-' for stdin)").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
453
|
+
"after",
|
|
454
|
+
`
|
|
455
|
+
Examples:
|
|
456
|
+
$ nexus agent update abc-123 --role "Senior Assistant"
|
|
457
|
+
$ echo "You are helpful" | nexus agent update abc-123 --prompt -
|
|
458
|
+
$ nexus agent update abc-123 --model gpt-4o --tone professional
|
|
459
|
+
$ nexus agent update abc-123 --body '{"tone":"friendly"}'`
|
|
460
|
+
).action(async (id, opts) => {
|
|
461
|
+
try {
|
|
462
|
+
const client = createClient(program2.optsWithGlobals());
|
|
463
|
+
const base = await resolveBody(opts.body);
|
|
464
|
+
const flags = {};
|
|
465
|
+
if (opts.firstName !== void 0) flags.firstName = opts.firstName;
|
|
466
|
+
if (opts.lastName !== void 0) flags.lastName = opts.lastName;
|
|
467
|
+
if (opts.role !== void 0) flags.role = opts.role;
|
|
468
|
+
if (opts.bio !== void 0) flags.bio = opts.bio;
|
|
469
|
+
if (opts.shortBio !== void 0) flags.shortBio = opts.shortBio;
|
|
470
|
+
if (opts.model !== void 0) flags.model = opts.model;
|
|
471
|
+
if (opts.tone !== void 0) flags.tone = opts.tone;
|
|
472
|
+
if (opts.prompt) flags.prompt = await resolveInputValue(opts.prompt);
|
|
473
|
+
const body = mergeBodyWithFlags(base, flags);
|
|
474
|
+
const agent2 = await client.agents.update(id, body);
|
|
475
|
+
printSuccess("Agent updated.", { id: agent2.id });
|
|
476
|
+
} catch (err) {
|
|
477
|
+
process.exitCode = handleError(err);
|
|
478
|
+
}
|
|
479
|
+
});
|
|
480
|
+
agent.command("delete").description("Delete an agent").argument("<id>", "Agent ID").option("--yes", "Skip confirmation").option("--dry-run", "Preview without deleting").addHelpText(
|
|
481
|
+
"after",
|
|
482
|
+
`
|
|
483
|
+
Examples:
|
|
484
|
+
$ nexus agent delete abc-123
|
|
485
|
+
$ nexus agent delete abc-123 --yes
|
|
486
|
+
$ nexus agent delete abc-123 --dry-run`
|
|
487
|
+
).action(async (id, opts) => {
|
|
488
|
+
try {
|
|
489
|
+
const client = createClient(program2.optsWithGlobals());
|
|
490
|
+
if (opts.dryRun) {
|
|
491
|
+
const agent2 = await client.agents.get(id);
|
|
492
|
+
console.log(
|
|
493
|
+
color.yellow("DRY RUN:") + ` Would delete agent "${agent2.firstName} ${agent2.lastName}" (${id})`
|
|
494
|
+
);
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
498
|
+
const readline2 = await import("readline/promises");
|
|
499
|
+
const rl = readline2.createInterface({
|
|
500
|
+
input: process.stdin,
|
|
501
|
+
output: process.stdout
|
|
502
|
+
});
|
|
503
|
+
const answer = await rl.question(`Delete agent ${id}? This cannot be undone. [y/N] `);
|
|
504
|
+
rl.close();
|
|
505
|
+
if (answer.toLowerCase() !== "y") {
|
|
506
|
+
console.log("Aborted.");
|
|
507
|
+
return;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
await client.agents.delete(id);
|
|
511
|
+
printSuccess("Agent deleted.", { id });
|
|
512
|
+
} catch (err) {
|
|
513
|
+
process.exitCode = handleError(err);
|
|
514
|
+
}
|
|
515
|
+
});
|
|
516
|
+
agent.command("duplicate").description("Duplicate an agent").argument("<id>", "Agent ID to duplicate").addHelpText(
|
|
517
|
+
"after",
|
|
518
|
+
`
|
|
519
|
+
Examples:
|
|
520
|
+
$ nexus agent duplicate abc-123
|
|
521
|
+
$ nexus agent duplicate abc-123 --json`
|
|
522
|
+
).action(async (id) => {
|
|
523
|
+
try {
|
|
524
|
+
const client = createClient(program2.optsWithGlobals());
|
|
525
|
+
const agent2 = await client.agents.duplicate(id);
|
|
526
|
+
printSuccess("Agent duplicated.", {
|
|
527
|
+
id: agent2.id,
|
|
528
|
+
name: `${agent2.firstName} ${agent2.lastName}`
|
|
529
|
+
});
|
|
530
|
+
} catch (err) {
|
|
531
|
+
process.exitCode = handleError(err);
|
|
532
|
+
}
|
|
533
|
+
});
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// src/commands/agent-tool.ts
|
|
537
|
+
init_output();
|
|
538
|
+
function registerAgentToolCommands(program2) {
|
|
539
|
+
const agentTool = program2.command("agent-tool").description("Manage agent tool configurations");
|
|
540
|
+
agentTool.command("list").description("List tools attached to an agent").argument("<agent-id>", "Agent ID").addHelpText(
|
|
541
|
+
"after",
|
|
542
|
+
`
|
|
543
|
+
Examples:
|
|
544
|
+
$ nexus agent-tool list agt-123
|
|
545
|
+
$ nexus agent-tool list agt-123 --json`
|
|
546
|
+
).action(async (agentId) => {
|
|
547
|
+
try {
|
|
548
|
+
const client = createClient(program2.optsWithGlobals());
|
|
549
|
+
const tools = await client.agents.tools.list(agentId);
|
|
550
|
+
printTable(tools, [
|
|
551
|
+
{ key: "id", label: "ID", width: 36 },
|
|
552
|
+
{ key: "label", label: "LABEL", width: 25 },
|
|
553
|
+
{ key: "type", label: "TYPE", width: 15 },
|
|
554
|
+
{ key: "isActive", label: "ACTIVE", width: 8, format: (v) => v ? "yes" : "no" }
|
|
555
|
+
]);
|
|
556
|
+
} catch (err) {
|
|
557
|
+
process.exitCode = handleError(err);
|
|
558
|
+
}
|
|
559
|
+
});
|
|
560
|
+
agentTool.command("get").description("Get tool configuration details").argument("<agent-id>", "Agent ID").argument("<tool-id>", "Tool config ID").addHelpText(
|
|
561
|
+
"after",
|
|
562
|
+
`
|
|
563
|
+
Examples:
|
|
564
|
+
$ nexus agent-tool get agt-123 tool-456
|
|
565
|
+
$ nexus agent-tool get agt-123 tool-456 --json`
|
|
566
|
+
).action(async (agentId, toolId) => {
|
|
567
|
+
try {
|
|
568
|
+
const client = createClient(program2.optsWithGlobals());
|
|
569
|
+
const tool = await client.agents.tools.get(agentId, toolId);
|
|
570
|
+
printRecord(tool);
|
|
571
|
+
} catch (err) {
|
|
572
|
+
process.exitCode = handleError(err);
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
agentTool.command("create").description("Add a tool to an agent").argument("<agent-id>", "Agent ID").requiredOption("--label <label>", "Tool label").requiredOption("--type <type>", "Tool type (PLUGIN, WORKFLOW, TASK, COLLECTION, etc.)").option("--config <json>", "Tool configuration as JSON").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
576
|
+
"after",
|
|
577
|
+
`
|
|
578
|
+
Examples:
|
|
579
|
+
$ nexus agent-tool create agt-123 --label "Gmail Send" --type PLUGIN
|
|
580
|
+
$ nexus agent-tool create agt-123 --label "Search KB" --type COLLECTION --config '{"collectionId":"col-789"}'
|
|
581
|
+
$ nexus agent-tool create agt-123 --body '{"label":"Search","type":"COLLECTION"}'`
|
|
582
|
+
).action(async (agentId, opts) => {
|
|
583
|
+
try {
|
|
584
|
+
const client = createClient(program2.optsWithGlobals());
|
|
585
|
+
const base = await resolveBody(opts.body);
|
|
586
|
+
const flags = {};
|
|
587
|
+
if (opts.label !== void 0) flags.label = opts.label;
|
|
588
|
+
if (opts.type !== void 0) flags.type = opts.type;
|
|
589
|
+
if (opts.config) Object.assign(flags, JSON.parse(opts.config));
|
|
590
|
+
const body = mergeBodyWithFlags(base, flags);
|
|
591
|
+
const tool = await client.agents.tools.create(agentId, body);
|
|
592
|
+
printSuccess("Tool added to agent.", {
|
|
593
|
+
id: tool.id,
|
|
594
|
+
label: tool.label
|
|
595
|
+
});
|
|
596
|
+
} catch (err) {
|
|
597
|
+
process.exitCode = handleError(err);
|
|
598
|
+
}
|
|
599
|
+
});
|
|
600
|
+
agentTool.command("update").description("Update a tool configuration").argument("<agent-id>", "Agent ID").argument("<tool-id>", "Tool config ID").option("--label <label>", "New label").option("--config <json>", "Updated configuration as JSON").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
601
|
+
"after",
|
|
602
|
+
`
|
|
603
|
+
Examples:
|
|
604
|
+
$ nexus agent-tool update agt-123 tool-456 --label "Renamed Tool"
|
|
605
|
+
$ nexus agent-tool update agt-123 tool-456 --body '{"label":"Renamed"}'`
|
|
606
|
+
).action(async (agentId, toolId, opts) => {
|
|
607
|
+
try {
|
|
608
|
+
const client = createClient(program2.optsWithGlobals());
|
|
609
|
+
const base = await resolveBody(opts.body);
|
|
610
|
+
const flags = {};
|
|
611
|
+
if (opts.label !== void 0) flags.label = opts.label;
|
|
612
|
+
if (opts.config) Object.assign(flags, JSON.parse(opts.config));
|
|
613
|
+
const body = mergeBodyWithFlags(base, flags);
|
|
614
|
+
await client.agents.tools.update(agentId, toolId, body);
|
|
615
|
+
printSuccess("Tool updated.", { id: toolId });
|
|
616
|
+
} catch (err) {
|
|
617
|
+
process.exitCode = handleError(err);
|
|
618
|
+
}
|
|
619
|
+
});
|
|
620
|
+
agentTool.command("delete").description("Remove a tool from an agent").argument("<agent-id>", "Agent ID").argument("<tool-id>", "Tool config ID").option("--yes", "Skip confirmation").addHelpText(
|
|
621
|
+
"after",
|
|
622
|
+
`
|
|
623
|
+
Examples:
|
|
624
|
+
$ nexus agent-tool delete agt-123 tool-456
|
|
625
|
+
$ nexus agent-tool delete agt-123 tool-456 --yes`
|
|
626
|
+
).action(async (agentId, toolId, opts) => {
|
|
627
|
+
try {
|
|
628
|
+
const client = createClient(program2.optsWithGlobals());
|
|
629
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
630
|
+
const readline2 = await import("readline/promises");
|
|
631
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
632
|
+
const answer = await rl.question(`Remove tool ${toolId} from agent? [y/N] `);
|
|
633
|
+
rl.close();
|
|
634
|
+
if (answer.toLowerCase() !== "y") {
|
|
635
|
+
console.log("Aborted.");
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
await client.agents.tools.delete(agentId, toolId);
|
|
640
|
+
printSuccess("Tool removed from agent.", { id: toolId });
|
|
641
|
+
} catch (err) {
|
|
642
|
+
process.exitCode = handleError(err);
|
|
643
|
+
}
|
|
644
|
+
});
|
|
645
|
+
agentTool.command("attach-collection").description("Attach a knowledge collection to an agent").argument("<agent-id>", "Agent ID").requiredOption("--collection-id <id>", "Collection ID").option("--label <label>", "Tool label").option("--instructions <text>", "Usage instructions").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
646
|
+
"after",
|
|
647
|
+
`
|
|
648
|
+
Examples:
|
|
649
|
+
$ nexus agent-tool attach-collection agt-123 --collection-id col-456
|
|
650
|
+
$ nexus agent-tool attach-collection agt-123 --collection-id col-456 --label "FAQ Search"
|
|
651
|
+
$ nexus agent-tool attach-collection agt-123 --body '{"collectionId":"col-456","label":"FAQ"}'`
|
|
652
|
+
).action(async (agentId, opts) => {
|
|
653
|
+
try {
|
|
654
|
+
const client = createClient(program2.optsWithGlobals());
|
|
655
|
+
const base = await resolveBody(opts.body);
|
|
656
|
+
const body = mergeBodyWithFlags(base, {
|
|
657
|
+
...opts.collectionId !== void 0 && { collectionId: opts.collectionId },
|
|
658
|
+
...opts.label !== void 0 && { label: opts.label },
|
|
659
|
+
...opts.instructions !== void 0 && { instructions: opts.instructions }
|
|
660
|
+
});
|
|
661
|
+
const tool = await client.agents.tools.attachCollection(agentId, body);
|
|
662
|
+
printSuccess("Collection attached to agent.", {
|
|
663
|
+
id: tool.id,
|
|
664
|
+
label: tool.label
|
|
665
|
+
});
|
|
666
|
+
} catch (err) {
|
|
667
|
+
process.exitCode = handleError(err);
|
|
668
|
+
}
|
|
669
|
+
});
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
// src/commands/analytics.ts
|
|
673
|
+
init_output();
|
|
674
|
+
function registerAnalyticsCommands(program2) {
|
|
675
|
+
const analytics = program2.command("analytics").description("View analytics and metrics");
|
|
676
|
+
analytics.command("overview").description("Get analytics overview").option("--time-period <period>", "Time period (7d, 30d, 90d, etc.)").option("--deployment-id <id>", "Filter by deployment ID").addHelpText(
|
|
677
|
+
"after",
|
|
678
|
+
`
|
|
679
|
+
Examples:
|
|
680
|
+
$ nexus analytics overview
|
|
681
|
+
$ nexus analytics overview --time-period 30d
|
|
682
|
+
$ nexus analytics overview --deployment-id dep-123 --json`
|
|
683
|
+
).action(async (opts) => {
|
|
684
|
+
try {
|
|
685
|
+
const client = createClient(program2.optsWithGlobals());
|
|
686
|
+
const result = await client.analytics.getOverview({
|
|
687
|
+
timePeriod: opts.timePeriod,
|
|
688
|
+
deploymentId: opts.deploymentId
|
|
689
|
+
});
|
|
690
|
+
printRecord(result);
|
|
691
|
+
} catch (err) {
|
|
692
|
+
process.exitCode = handleError(err);
|
|
693
|
+
}
|
|
694
|
+
});
|
|
695
|
+
addPaginationOptions(
|
|
696
|
+
analytics.command("feedback").description("List satisfaction feedback").option("--time-period <period>", "Time period").option("--deployment-id <id>", "Filter by deployment").option("--score <number>", "Filter by score", parseInt).addHelpText(
|
|
697
|
+
"after",
|
|
698
|
+
`
|
|
699
|
+
Examples:
|
|
700
|
+
$ nexus analytics feedback
|
|
701
|
+
$ nexus analytics feedback --time-period 7d --score 5
|
|
702
|
+
$ nexus analytics feedback --limit 20 --json`
|
|
703
|
+
)
|
|
704
|
+
).action(async (opts) => {
|
|
705
|
+
try {
|
|
706
|
+
const client = createClient(program2.optsWithGlobals());
|
|
707
|
+
const result = await client.analytics.listFeedback({
|
|
708
|
+
...getPaginationParams(opts),
|
|
709
|
+
timePeriod: opts.timePeriod,
|
|
710
|
+
deploymentId: opts.deploymentId,
|
|
711
|
+
score: opts.score
|
|
712
|
+
});
|
|
713
|
+
const data = result.data ?? [];
|
|
714
|
+
const meta = result.meta;
|
|
715
|
+
printList(data, meta, [
|
|
716
|
+
{ key: "id", label: "ID", width: 36 },
|
|
717
|
+
{ key: "score", label: "SCORE", width: 6 },
|
|
718
|
+
{ key: "comment", label: "COMMENT", width: 40 },
|
|
719
|
+
{ key: "createdAt", label: "DATE", width: 20 }
|
|
720
|
+
]);
|
|
721
|
+
} catch (err) {
|
|
722
|
+
process.exitCode = handleError(err);
|
|
723
|
+
}
|
|
724
|
+
});
|
|
725
|
+
analytics.command("export").description("Export analytics as CSV").option("--time-period <period>", "Time period").option("--deployment-id <id>", "Filter by deployment").addHelpText(
|
|
726
|
+
"after",
|
|
727
|
+
`
|
|
728
|
+
Examples:
|
|
729
|
+
$ nexus analytics export
|
|
730
|
+
$ nexus analytics export --time-period 30d > analytics.csv
|
|
731
|
+
$ nexus analytics export --deployment-id dep-123`
|
|
732
|
+
).action(async (opts) => {
|
|
733
|
+
try {
|
|
734
|
+
const client = createClient(program2.optsWithGlobals());
|
|
735
|
+
const result = await client.analytics.exportCsv({
|
|
736
|
+
timePeriod: opts.timePeriod,
|
|
737
|
+
deploymentId: opts.deploymentId
|
|
738
|
+
});
|
|
739
|
+
if (typeof result === "string") {
|
|
740
|
+
console.log(result);
|
|
741
|
+
} else {
|
|
742
|
+
console.log(JSON.stringify(result, null, 2));
|
|
743
|
+
}
|
|
744
|
+
} catch (err) {
|
|
745
|
+
process.exitCode = handleError(err);
|
|
746
|
+
}
|
|
747
|
+
});
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
// src/commands/api.ts
|
|
751
|
+
var import_sdk3 = require("@agent-nexus/sdk");
|
|
752
|
+
init_output();
|
|
753
|
+
function registerApiCommand(program2) {
|
|
754
|
+
program2.command("api").description("Call any Nexus API endpoint directly").argument("<method>", "HTTP method (GET, POST, PATCH, PUT, DELETE)").argument("<path>", "API path relative to /api/public/v1 (e.g. /models)").option("--body <json>", "Request body as JSON string, .json file path, or '-' for stdin").option("--query <key=value...>", "Query parameters (repeatable)", collect, []).addHelpText(
|
|
755
|
+
"after",
|
|
756
|
+
`
|
|
757
|
+
Examples:
|
|
758
|
+
$ nexus api GET /models
|
|
759
|
+
$ nexus api POST /agents --body '{"firstName":"Test","lastName":"Bot","role":"QA"}'
|
|
760
|
+
$ nexus api GET /agents --query page=1 --query limit=5
|
|
761
|
+
$ nexus api PATCH /agents/abc-123 --body payload.json
|
|
762
|
+
$ echo '{"text":"hello"}' | nexus api POST /emulator/dep-1/sessions/s-1/messages --body -`
|
|
763
|
+
).action(async (method, path5, opts) => {
|
|
764
|
+
try {
|
|
765
|
+
const globals = program2.optsWithGlobals();
|
|
766
|
+
const http = new import_sdk3.HttpClient({
|
|
767
|
+
baseUrl: resolveBaseUrl(globals.baseUrl),
|
|
768
|
+
apiKey: resolveApiKey(globals.apiKey)
|
|
769
|
+
});
|
|
770
|
+
const body = await resolveBody(opts.body);
|
|
771
|
+
const query = parseQueryPairs(opts.query);
|
|
772
|
+
const normalizedPath = path5.startsWith("/") ? path5 : `/${path5}`;
|
|
773
|
+
const { data, meta } = await http.requestWithMeta(
|
|
774
|
+
method.toUpperCase(),
|
|
775
|
+
normalizedPath,
|
|
776
|
+
{ body, query }
|
|
777
|
+
);
|
|
778
|
+
const output = meta ? { data, meta } : { data };
|
|
779
|
+
console.log(JSON.stringify(output, null, isJsonMode() ? void 0 : 2));
|
|
780
|
+
} catch (err) {
|
|
781
|
+
process.exitCode = handleError(err);
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
}
|
|
785
|
+
function collect(value, previous) {
|
|
786
|
+
return [...previous, value];
|
|
787
|
+
}
|
|
788
|
+
function parseQueryPairs(pairs) {
|
|
789
|
+
if (pairs.length === 0) return void 0;
|
|
790
|
+
const result = {};
|
|
791
|
+
for (const pair of pairs) {
|
|
792
|
+
const eq = pair.indexOf("=");
|
|
793
|
+
if (eq === -1) {
|
|
794
|
+
result[pair] = "true";
|
|
795
|
+
} else {
|
|
796
|
+
result[pair.slice(0, eq)] = pair.slice(eq + 1);
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
return result;
|
|
800
|
+
}
|
|
801
|
+
|
|
802
|
+
// src/commands/auth.ts
|
|
803
|
+
var import_node_child_process = require("child_process");
|
|
804
|
+
var import_node_process = require("process");
|
|
805
|
+
var import_promises = __toESM(require("readline/promises"));
|
|
806
|
+
init_output();
|
|
807
|
+
var SETTINGS_URL = "https://app.nexusgpt.io/app/settings/api-keys";
|
|
808
|
+
function registerAuthCommands(program2) {
|
|
809
|
+
const auth = program2.command("auth").description("Manage authentication");
|
|
810
|
+
auth.command("login").description("Authenticate with the Nexus API").option("--api-key <key>", "API key (skip interactive prompt)").option("--env <env>", "Environment: dev or production", "production").addHelpText(
|
|
811
|
+
"after",
|
|
812
|
+
`
|
|
813
|
+
Examples:
|
|
814
|
+
$ nexus auth login
|
|
815
|
+
$ nexus auth login --api-key nxs_abc123
|
|
816
|
+
$ nexus auth login --env dev`
|
|
817
|
+
).action(async (opts) => {
|
|
818
|
+
const config = loadConfig();
|
|
819
|
+
if (opts.env === "dev") {
|
|
820
|
+
config.baseUrl = "http://localhost:3001";
|
|
821
|
+
}
|
|
822
|
+
const baseUrl = config.baseUrl ?? resolveBaseUrl();
|
|
823
|
+
let apiKey = opts.apiKey;
|
|
824
|
+
if (!apiKey) {
|
|
825
|
+
console.log(`Opening ${color.cyan(SETTINGS_URL)} ...`);
|
|
826
|
+
console.log("Create or copy an API key from the settings page.\n");
|
|
827
|
+
openUrl(SETTINGS_URL);
|
|
828
|
+
const rl = import_promises.default.createInterface({ input: import_node_process.stdin, output: import_node_process.stdout });
|
|
829
|
+
try {
|
|
830
|
+
apiKey = (await rl.question("Paste your API key (nxs_...): ")).trim();
|
|
831
|
+
} finally {
|
|
832
|
+
rl.close();
|
|
833
|
+
}
|
|
834
|
+
}
|
|
835
|
+
if (!apiKey) {
|
|
836
|
+
console.error(color.red("Error:") + " No key entered. Aborting.");
|
|
837
|
+
process.exitCode = 1;
|
|
838
|
+
return;
|
|
839
|
+
}
|
|
840
|
+
if (!apiKey.startsWith("nxs_")) {
|
|
841
|
+
console.error(
|
|
842
|
+
color.red("Error:") + ' Invalid key format \u2014 API keys start with "nxs_".\n nexus auth login --api-key nxs_YOUR_KEY'
|
|
843
|
+
);
|
|
844
|
+
process.exitCode = 1;
|
|
845
|
+
return;
|
|
846
|
+
}
|
|
847
|
+
console.log("Validating...");
|
|
848
|
+
const res = await fetch(`${baseUrl}/api/public/v1/agents?limit=1`, {
|
|
849
|
+
headers: { "api-key": apiKey, Accept: "application/json" }
|
|
850
|
+
});
|
|
851
|
+
if (!res.ok) {
|
|
852
|
+
console.error(
|
|
853
|
+
color.red("Error:") + ` Validation failed (HTTP ${res.status}). Check your key and try again.`
|
|
854
|
+
);
|
|
855
|
+
process.exitCode = 1;
|
|
856
|
+
return;
|
|
857
|
+
}
|
|
858
|
+
config.apiKey = apiKey;
|
|
859
|
+
if (opts.env === "dev") config.baseUrl = "http://localhost:3001";
|
|
860
|
+
saveConfig(config);
|
|
861
|
+
printSuccess("Logged in successfully.", {
|
|
862
|
+
config: "~/.nexus-mcp/config.json"
|
|
863
|
+
});
|
|
864
|
+
});
|
|
865
|
+
auth.command("logout").description("Remove stored credentials").addHelpText(
|
|
866
|
+
"after",
|
|
867
|
+
`
|
|
868
|
+
Examples:
|
|
869
|
+
$ nexus auth logout`
|
|
870
|
+
).action(() => {
|
|
871
|
+
clearConfig();
|
|
872
|
+
printSuccess("Logged out. Credentials removed from ~/.nexus-mcp/config.json");
|
|
873
|
+
});
|
|
874
|
+
auth.command("whoami").description("Show current authentication status").addHelpText(
|
|
875
|
+
"after",
|
|
876
|
+
`
|
|
877
|
+
Examples:
|
|
878
|
+
$ nexus auth whoami`
|
|
879
|
+
).action(async () => {
|
|
880
|
+
try {
|
|
881
|
+
const apiKey = resolveApiKey();
|
|
882
|
+
const baseUrl = resolveBaseUrl();
|
|
883
|
+
const res = await fetch(`${baseUrl}/api/public/v1/agents?limit=1`, {
|
|
884
|
+
headers: { "api-key": apiKey, Accept: "application/json" }
|
|
885
|
+
});
|
|
886
|
+
if (!res.ok) {
|
|
887
|
+
console.error(
|
|
888
|
+
color.red("Error:") + " API key is invalid or expired. Run: nexus auth login"
|
|
889
|
+
);
|
|
890
|
+
process.exitCode = 1;
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
printSuccess("Authenticated.", {
|
|
894
|
+
api: baseUrl,
|
|
895
|
+
key: apiKey.slice(0, 8) + "..." + apiKey.slice(-4)
|
|
896
|
+
});
|
|
897
|
+
} catch (err) {
|
|
898
|
+
console.error(color.red("Error:") + " Not logged in. Run: nexus auth login");
|
|
899
|
+
process.exitCode = 1;
|
|
900
|
+
}
|
|
901
|
+
});
|
|
902
|
+
}
|
|
903
|
+
function openUrl(url) {
|
|
904
|
+
const platform = process.platform;
|
|
905
|
+
const cmd = platform === "darwin" ? "open" : platform === "win32" ? "start" : "xdg-open";
|
|
906
|
+
(0, import_node_child_process.exec)(`${cmd} ${JSON.stringify(url)}`);
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
// src/commands/collection.ts
|
|
910
|
+
init_output();
|
|
911
|
+
function registerCollectionCommands(program2) {
|
|
912
|
+
const collection = program2.command("collection").description("Manage knowledge collections");
|
|
913
|
+
collection.command("list").description("List knowledge collections").option("--search <query>", "Search by name").option("--limit <number>", "Max results", parseInt).addHelpText(
|
|
914
|
+
"after",
|
|
915
|
+
`
|
|
916
|
+
Examples:
|
|
917
|
+
$ nexus collection list
|
|
918
|
+
$ nexus collection list --search "product" --limit 10
|
|
919
|
+
$ nexus collection list --json`
|
|
920
|
+
).action(async (opts) => {
|
|
921
|
+
try {
|
|
922
|
+
const client = createClient(program2.optsWithGlobals());
|
|
923
|
+
const result = await client.skills.listCollections({
|
|
924
|
+
search: opts.search,
|
|
925
|
+
limit: opts.limit
|
|
926
|
+
});
|
|
927
|
+
const items = result.items ?? [];
|
|
928
|
+
printTable(items, [
|
|
929
|
+
{ key: "id", label: "ID", width: 36 },
|
|
930
|
+
{ key: "name", label: "NAME", width: 25 },
|
|
931
|
+
{ key: "displayName", label: "DISPLAY NAME", width: 25 },
|
|
932
|
+
{ key: "documentCount", label: "DOCS", width: 6 }
|
|
933
|
+
]);
|
|
934
|
+
} catch (err) {
|
|
935
|
+
process.exitCode = handleError(err);
|
|
936
|
+
}
|
|
937
|
+
});
|
|
938
|
+
collection.command("get").description("Get collection details").argument("<id>", "Collection ID").addHelpText(
|
|
939
|
+
"after",
|
|
940
|
+
`
|
|
941
|
+
Examples:
|
|
942
|
+
$ nexus collection get col-123
|
|
943
|
+
$ nexus collection get col-123 --json`
|
|
944
|
+
).action(async (id) => {
|
|
945
|
+
try {
|
|
946
|
+
const client = createClient(program2.optsWithGlobals());
|
|
947
|
+
const col = await client.skills.getCollection(id);
|
|
948
|
+
printRecord(col, [
|
|
949
|
+
{ key: "id", label: "ID" },
|
|
950
|
+
{ key: "name", label: "Name" },
|
|
951
|
+
{ key: "displayName", label: "Display Name" },
|
|
952
|
+
{ key: "description", label: "Description" },
|
|
953
|
+
{ key: "k", label: "k (results)" },
|
|
954
|
+
{ key: "reranker", label: "Reranker", format: (v) => v ? "yes" : "no" },
|
|
955
|
+
{ key: "documentCount", label: "Documents" }
|
|
956
|
+
]);
|
|
957
|
+
} catch (err) {
|
|
958
|
+
process.exitCode = handleError(err);
|
|
959
|
+
}
|
|
960
|
+
});
|
|
961
|
+
collection.command("create").description("Create a knowledge collection").requiredOption("--name <name>", "Collection name (unique slug)").option("--display-name <name>", "Human-readable display name").option("--description <text>", "Collection description").option("--k <number>", "Number of results to retrieve", parseInt).option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
962
|
+
"after",
|
|
963
|
+
`
|
|
964
|
+
Examples:
|
|
965
|
+
$ nexus collection create --name "product-docs"
|
|
966
|
+
$ nexus collection create --name "faq" --display-name "FAQ" --k 15
|
|
967
|
+
$ nexus collection create --body '{"name":"faq","displayName":"FAQ"}'`
|
|
968
|
+
).action(async (opts) => {
|
|
969
|
+
try {
|
|
970
|
+
const client = createClient(program2.optsWithGlobals());
|
|
971
|
+
const base = await resolveBody(opts.body);
|
|
972
|
+
const body = mergeBodyWithFlags(base, {
|
|
973
|
+
...opts.name !== void 0 && { name: opts.name },
|
|
974
|
+
...opts.displayName !== void 0 && { displayName: opts.displayName },
|
|
975
|
+
...opts.description !== void 0 && { description: opts.description },
|
|
976
|
+
...opts.k !== void 0 && { k: opts.k }
|
|
977
|
+
});
|
|
978
|
+
const col = await client.skills.createCollection(body);
|
|
979
|
+
printSuccess("Collection created.", {
|
|
980
|
+
id: col.id,
|
|
981
|
+
name: col.name
|
|
982
|
+
});
|
|
983
|
+
} catch (err) {
|
|
984
|
+
process.exitCode = handleError(err);
|
|
985
|
+
}
|
|
986
|
+
});
|
|
987
|
+
collection.command("update").description("Update a collection").argument("<id>", "Collection ID").option("--display-name <name>", "Display name").option("--description <text>", "Description").option("--k <number>", "Number of results", parseInt).option("--reranker <bool>", "Enable reranker (true/false)").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
988
|
+
"after",
|
|
989
|
+
`
|
|
990
|
+
Examples:
|
|
991
|
+
$ nexus collection update col-123 --display-name "Updated FAQ"
|
|
992
|
+
$ nexus collection update col-123 --k 20 --reranker true
|
|
993
|
+
$ nexus collection update col-123 --body '{"displayName":"Updated"}'`
|
|
994
|
+
).action(async (id, opts) => {
|
|
995
|
+
try {
|
|
996
|
+
const client = createClient(program2.optsWithGlobals());
|
|
997
|
+
const base = await resolveBody(opts.body);
|
|
998
|
+
const flags = {};
|
|
999
|
+
if (opts.displayName !== void 0) flags.displayName = opts.displayName;
|
|
1000
|
+
if (opts.description !== void 0) flags.description = opts.description;
|
|
1001
|
+
if (opts.k !== void 0) flags.k = opts.k;
|
|
1002
|
+
if (opts.reranker !== void 0) flags.reranker = opts.reranker === "true";
|
|
1003
|
+
const body = mergeBodyWithFlags(base, flags);
|
|
1004
|
+
await client.skills.updateCollection(id, body);
|
|
1005
|
+
printSuccess("Collection updated.", { id });
|
|
1006
|
+
} catch (err) {
|
|
1007
|
+
process.exitCode = handleError(err);
|
|
1008
|
+
}
|
|
1009
|
+
});
|
|
1010
|
+
collection.command("delete").description("Delete a collection").argument("<id>", "Collection ID").option("--yes", "Skip confirmation").addHelpText(
|
|
1011
|
+
"after",
|
|
1012
|
+
`
|
|
1013
|
+
Examples:
|
|
1014
|
+
$ nexus collection delete col-123
|
|
1015
|
+
$ nexus collection delete col-123 --yes`
|
|
1016
|
+
).action(async (id, opts) => {
|
|
1017
|
+
try {
|
|
1018
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1019
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
1020
|
+
const readline2 = await import("readline/promises");
|
|
1021
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
1022
|
+
const answer = await rl.question(`Delete collection ${id}? [y/N] `);
|
|
1023
|
+
rl.close();
|
|
1024
|
+
if (answer.toLowerCase() !== "y") {
|
|
1025
|
+
console.log("Aborted.");
|
|
1026
|
+
return;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
await client.skills.deleteCollection(id);
|
|
1030
|
+
printSuccess("Collection deleted.", { id });
|
|
1031
|
+
} catch (err) {
|
|
1032
|
+
process.exitCode = handleError(err);
|
|
1033
|
+
}
|
|
1034
|
+
});
|
|
1035
|
+
collection.command("search").description("Search a collection").argument("<id>", "Collection ID").requiredOption("--query <query>", "Search query").option("--limit <number>", "Max results", parseInt).addHelpText(
|
|
1036
|
+
"after",
|
|
1037
|
+
`
|
|
1038
|
+
Examples:
|
|
1039
|
+
$ nexus collection search col-123 --query "how to reset password"
|
|
1040
|
+
$ nexus collection search col-123 --query "pricing" --limit 5 --json`
|
|
1041
|
+
).action(async (id, opts) => {
|
|
1042
|
+
try {
|
|
1043
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1044
|
+
const result = await client.skills.searchCollection(id, {
|
|
1045
|
+
query: opts.query,
|
|
1046
|
+
limit: opts.limit
|
|
1047
|
+
});
|
|
1048
|
+
if (isJsonMode()) {
|
|
1049
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1050
|
+
} else {
|
|
1051
|
+
const results = result.results ?? result;
|
|
1052
|
+
if (Array.isArray(results)) {
|
|
1053
|
+
for (const r of results) {
|
|
1054
|
+
console.log(
|
|
1055
|
+
`\u2500 ${r.score?.toFixed(3) ?? "N/A"} ${r.content?.slice(0, 100) ?? JSON.stringify(r).slice(0, 100)}...`
|
|
1056
|
+
);
|
|
1057
|
+
}
|
|
1058
|
+
} else {
|
|
1059
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1060
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
} catch (err) {
|
|
1063
|
+
process.exitCode = handleError(err);
|
|
1064
|
+
}
|
|
1065
|
+
});
|
|
1066
|
+
addPaginationOptions(
|
|
1067
|
+
collection.command("documents").description("List documents in a collection").argument("<id>", "Collection ID").addHelpText(
|
|
1068
|
+
"after",
|
|
1069
|
+
`
|
|
1070
|
+
Examples:
|
|
1071
|
+
$ nexus collection documents col-123
|
|
1072
|
+
$ nexus collection documents col-123 --limit 20 --json`
|
|
1073
|
+
)
|
|
1074
|
+
).action(async (id, opts) => {
|
|
1075
|
+
try {
|
|
1076
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1077
|
+
const result = await client.skills.listCollectionDocuments(
|
|
1078
|
+
id,
|
|
1079
|
+
getPaginationParams(opts)
|
|
1080
|
+
);
|
|
1081
|
+
const data = result.data ?? result.items ?? result;
|
|
1082
|
+
const meta = result.meta;
|
|
1083
|
+
printList(Array.isArray(data) ? data : [data], meta, [
|
|
1084
|
+
{ key: "id", label: "ID", width: 36 },
|
|
1085
|
+
{ key: "name", label: "NAME", width: 30 },
|
|
1086
|
+
{ key: "type", label: "TYPE", width: 12 },
|
|
1087
|
+
{ key: "status", label: "STATUS", width: 12 }
|
|
1088
|
+
]);
|
|
1089
|
+
} catch (err) {
|
|
1090
|
+
process.exitCode = handleError(err);
|
|
1091
|
+
}
|
|
1092
|
+
});
|
|
1093
|
+
collection.command("attach-documents").description("Attach documents to a collection").argument("<id>", "Collection ID").requiredOption("--document-ids <ids>", "Comma-separated document IDs").addHelpText(
|
|
1094
|
+
"after",
|
|
1095
|
+
`
|
|
1096
|
+
Examples:
|
|
1097
|
+
$ nexus collection attach-documents col-123 --document-ids doc-1,doc-2,doc-3`
|
|
1098
|
+
).action(async (id, opts) => {
|
|
1099
|
+
try {
|
|
1100
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1101
|
+
await client.skills.attachDocumentsToCollection(id, {
|
|
1102
|
+
documentIds: opts.documentIds.split(",")
|
|
1103
|
+
});
|
|
1104
|
+
printSuccess("Documents attached to collection.", { id });
|
|
1105
|
+
} catch (err) {
|
|
1106
|
+
process.exitCode = handleError(err);
|
|
1107
|
+
}
|
|
1108
|
+
});
|
|
1109
|
+
collection.command("remove-document").description("Remove a document from a collection").argument("<id>", "Collection ID").argument("<document-id>", "Document ID").addHelpText(
|
|
1110
|
+
"after",
|
|
1111
|
+
`
|
|
1112
|
+
Examples:
|
|
1113
|
+
$ nexus collection remove-document col-123 doc-456`
|
|
1114
|
+
).action(async (id, documentId) => {
|
|
1115
|
+
try {
|
|
1116
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1117
|
+
await client.skills.removeCollectionDocument(id, documentId);
|
|
1118
|
+
printSuccess("Document removed from collection.", { id, documentId });
|
|
1119
|
+
} catch (err) {
|
|
1120
|
+
process.exitCode = handleError(err);
|
|
1121
|
+
}
|
|
1122
|
+
});
|
|
1123
|
+
collection.command("stats").description("Get collection statistics").argument("<id>", "Collection ID").addHelpText(
|
|
1124
|
+
"after",
|
|
1125
|
+
`
|
|
1126
|
+
Examples:
|
|
1127
|
+
$ nexus collection stats col-123
|
|
1128
|
+
$ nexus collection stats col-123 --json`
|
|
1129
|
+
).action(async (id) => {
|
|
1130
|
+
try {
|
|
1131
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1132
|
+
const stats = await client.skills.getCollectionStatistics(id);
|
|
1133
|
+
printRecord(stats);
|
|
1134
|
+
} catch (err) {
|
|
1135
|
+
process.exitCode = handleError(err);
|
|
1136
|
+
}
|
|
1137
|
+
});
|
|
1138
|
+
}
|
|
1139
|
+
|
|
1140
|
+
// src/commands/deployment.ts
|
|
1141
|
+
init_output();
|
|
1142
|
+
function registerDeploymentCommands(program2) {
|
|
1143
|
+
const deployment = program2.command("deployment").description("Manage agent deployments");
|
|
1144
|
+
addPaginationOptions(
|
|
1145
|
+
deployment.command("list").description("List deployments").option("--search <query>", "Search by name").option("--type <type>", "Filter by deployment type").option("--active", "Show only active deployments").addHelpText(
|
|
1146
|
+
"after",
|
|
1147
|
+
`
|
|
1148
|
+
Examples:
|
|
1149
|
+
$ nexus deployment list
|
|
1150
|
+
$ nexus deployment list --type whatsapp --limit 10
|
|
1151
|
+
$ nexus deployment list --active --json`
|
|
1152
|
+
)
|
|
1153
|
+
).action(async (opts) => {
|
|
1154
|
+
try {
|
|
1155
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1156
|
+
const { data, meta } = await client.deployments.list({
|
|
1157
|
+
...getPaginationParams(opts),
|
|
1158
|
+
search: opts.search,
|
|
1159
|
+
type: opts.type,
|
|
1160
|
+
isActive: opts.active ? true : void 0
|
|
1161
|
+
});
|
|
1162
|
+
printList(data, meta, [
|
|
1163
|
+
{ key: "id", label: "ID", width: 36 },
|
|
1164
|
+
{ key: "name", label: "NAME", width: 25 },
|
|
1165
|
+
{ key: "type", label: "TYPE", width: 15 },
|
|
1166
|
+
{ key: "isActive", label: "ACTIVE", width: 8, format: (v) => v ? "yes" : "no" },
|
|
1167
|
+
{ key: "agentId", label: "AGENT ID", width: 36 }
|
|
1168
|
+
]);
|
|
1169
|
+
} catch (err) {
|
|
1170
|
+
process.exitCode = handleError(err);
|
|
1171
|
+
}
|
|
1172
|
+
});
|
|
1173
|
+
deployment.command("get").description("Get deployment details").argument("<id>", "Deployment ID").addHelpText(
|
|
1174
|
+
"after",
|
|
1175
|
+
`
|
|
1176
|
+
Examples:
|
|
1177
|
+
$ nexus deployment get dep-123
|
|
1178
|
+
$ nexus deployment get dep-123 --json`
|
|
1179
|
+
).action(async (id) => {
|
|
1180
|
+
try {
|
|
1181
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1182
|
+
const dep = await client.deployments.get(id);
|
|
1183
|
+
printRecord(dep, [
|
|
1184
|
+
{ key: "id", label: "ID" },
|
|
1185
|
+
{ key: "name", label: "Name" },
|
|
1186
|
+
{ key: "type", label: "Type" },
|
|
1187
|
+
{ key: "isActive", label: "Active", format: (v) => v ? "yes" : "no" },
|
|
1188
|
+
{ key: "agentId", label: "Agent ID" },
|
|
1189
|
+
{ key: "description", label: "Description" },
|
|
1190
|
+
{ key: "createdAt", label: "Created" }
|
|
1191
|
+
]);
|
|
1192
|
+
} catch (err) {
|
|
1193
|
+
process.exitCode = handleError(err);
|
|
1194
|
+
}
|
|
1195
|
+
});
|
|
1196
|
+
deployment.command("create").description("Create a new deployment").requiredOption("--name <name>", "Deployment name").requiredOption("--type <type>", "Deployment type (web, whatsapp, telegram, slack, etc.)").option("--agent-id <id>", "Agent ID to deploy").option("--description <text>", "Deployment description").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
1197
|
+
"after",
|
|
1198
|
+
`
|
|
1199
|
+
Examples:
|
|
1200
|
+
$ nexus deployment create --name "Web Widget" --type web --agent-id agt-123
|
|
1201
|
+
$ nexus deployment create --name "WhatsApp Bot" --type whatsapp --agent-id agt-456
|
|
1202
|
+
$ nexus deployment create --body '{"name":"Widget","type":"web","agentId":"agt-123"}'`
|
|
1203
|
+
).action(async (opts) => {
|
|
1204
|
+
try {
|
|
1205
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1206
|
+
const base = await resolveBody(opts.body);
|
|
1207
|
+
const body = mergeBodyWithFlags(base, {
|
|
1208
|
+
...opts.name !== void 0 && { name: opts.name },
|
|
1209
|
+
...opts.type !== void 0 && { type: opts.type },
|
|
1210
|
+
...opts.agentId !== void 0 && { agentId: opts.agentId },
|
|
1211
|
+
...opts.description !== void 0 && { description: opts.description }
|
|
1212
|
+
});
|
|
1213
|
+
const dep = await client.deployments.create(body);
|
|
1214
|
+
printSuccess("Deployment created.", {
|
|
1215
|
+
id: dep.id,
|
|
1216
|
+
name: dep.name,
|
|
1217
|
+
type: dep.type
|
|
1218
|
+
});
|
|
1219
|
+
} catch (err) {
|
|
1220
|
+
process.exitCode = handleError(err);
|
|
1221
|
+
}
|
|
1222
|
+
});
|
|
1223
|
+
deployment.command("update").description("Update a deployment").argument("<id>", "Deployment ID").option("--name <name>", "Deployment name").option("--description <text>", "Description (use 'null' to clear)").option("--agent-id <id>", "Agent ID (use 'null' to detach)").option("--active <bool>", "Set active status (true/false)").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
1224
|
+
"after",
|
|
1225
|
+
`
|
|
1226
|
+
Examples:
|
|
1227
|
+
$ nexus deployment update dep-123 --name "Renamed Widget"
|
|
1228
|
+
$ nexus deployment update dep-123 --active false
|
|
1229
|
+
$ nexus deployment update dep-123 --agent-id agt-456
|
|
1230
|
+
$ nexus deployment update dep-123 --body '{"name":"Renamed"}'`
|
|
1231
|
+
).action(async (id, opts) => {
|
|
1232
|
+
try {
|
|
1233
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1234
|
+
const base = await resolveBody(opts.body);
|
|
1235
|
+
const flags = {};
|
|
1236
|
+
if (opts.name !== void 0) flags.name = opts.name;
|
|
1237
|
+
if (opts.description !== void 0) {
|
|
1238
|
+
flags.description = opts.description === "null" ? null : opts.description;
|
|
1239
|
+
}
|
|
1240
|
+
if (opts.agentId !== void 0) {
|
|
1241
|
+
flags.agentId = opts.agentId === "null" ? null : opts.agentId;
|
|
1242
|
+
}
|
|
1243
|
+
if (opts.active !== void 0) {
|
|
1244
|
+
flags.isActive = opts.active === "true";
|
|
1245
|
+
}
|
|
1246
|
+
const body = mergeBodyWithFlags(base, flags);
|
|
1247
|
+
await client.deployments.update(id, body);
|
|
1248
|
+
printSuccess("Deployment updated.", { id });
|
|
1249
|
+
} catch (err) {
|
|
1250
|
+
process.exitCode = handleError(err);
|
|
1251
|
+
}
|
|
1252
|
+
});
|
|
1253
|
+
deployment.command("delete").description("Delete a deployment").argument("<id>", "Deployment ID").option("--yes", "Skip confirmation").option("--dry-run", "Preview without deleting").addHelpText(
|
|
1254
|
+
"after",
|
|
1255
|
+
`
|
|
1256
|
+
Examples:
|
|
1257
|
+
$ nexus deployment delete dep-123
|
|
1258
|
+
$ nexus deployment delete dep-123 --yes
|
|
1259
|
+
$ nexus deployment delete dep-123 --dry-run`
|
|
1260
|
+
).action(async (id, opts) => {
|
|
1261
|
+
try {
|
|
1262
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1263
|
+
if (opts.dryRun) {
|
|
1264
|
+
const dep = await client.deployments.get(id);
|
|
1265
|
+
console.log(
|
|
1266
|
+
color.yellow("DRY RUN:") + ` Would delete deployment "${dep.name}" (${id})`
|
|
1267
|
+
);
|
|
1268
|
+
return;
|
|
1269
|
+
}
|
|
1270
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
1271
|
+
const readline2 = await import("readline/promises");
|
|
1272
|
+
const rl = readline2.createInterface({
|
|
1273
|
+
input: process.stdin,
|
|
1274
|
+
output: process.stdout
|
|
1275
|
+
});
|
|
1276
|
+
const answer = await rl.question(
|
|
1277
|
+
`Delete deployment ${id}? This cannot be undone. [y/N] `
|
|
1278
|
+
);
|
|
1279
|
+
rl.close();
|
|
1280
|
+
if (answer.toLowerCase() !== "y") {
|
|
1281
|
+
console.log("Aborted.");
|
|
1282
|
+
return;
|
|
1283
|
+
}
|
|
1284
|
+
}
|
|
1285
|
+
await client.deployments.delete(id);
|
|
1286
|
+
printSuccess("Deployment deleted.", { id });
|
|
1287
|
+
} catch (err) {
|
|
1288
|
+
process.exitCode = handleError(err);
|
|
1289
|
+
}
|
|
1290
|
+
});
|
|
1291
|
+
deployment.command("stats").description("Get deployment statistics").argument("<id>", "Deployment ID").addHelpText(
|
|
1292
|
+
"after",
|
|
1293
|
+
`
|
|
1294
|
+
Examples:
|
|
1295
|
+
$ nexus deployment stats dep-123
|
|
1296
|
+
$ nexus deployment stats dep-123 --json`
|
|
1297
|
+
).action(async (id) => {
|
|
1298
|
+
try {
|
|
1299
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1300
|
+
const stats = await client.deployments.getStatistics(id);
|
|
1301
|
+
printRecord(stats);
|
|
1302
|
+
} catch (err) {
|
|
1303
|
+
process.exitCode = handleError(err);
|
|
1304
|
+
}
|
|
1305
|
+
});
|
|
1306
|
+
deployment.command("duplicate").description("Duplicate a deployment").argument("<id>", "Deployment ID").addHelpText(
|
|
1307
|
+
"after",
|
|
1308
|
+
`
|
|
1309
|
+
Examples:
|
|
1310
|
+
$ nexus deployment duplicate dep-123`
|
|
1311
|
+
).action(async (id) => {
|
|
1312
|
+
try {
|
|
1313
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1314
|
+
const dep = await client.deployments.duplicate(id);
|
|
1315
|
+
printSuccess("Deployment duplicated.", {
|
|
1316
|
+
id: dep.id,
|
|
1317
|
+
name: dep.name
|
|
1318
|
+
});
|
|
1319
|
+
} catch (err) {
|
|
1320
|
+
process.exitCode = handleError(err);
|
|
1321
|
+
}
|
|
1322
|
+
});
|
|
1323
|
+
deployment.command("embed-config").description("Get deployment embed configuration").argument("<id>", "Deployment ID").addHelpText(
|
|
1324
|
+
"after",
|
|
1325
|
+
`
|
|
1326
|
+
Examples:
|
|
1327
|
+
$ nexus deployment embed-config dep-123
|
|
1328
|
+
$ nexus deployment embed-config dep-123 --json`
|
|
1329
|
+
).action(async (id) => {
|
|
1330
|
+
try {
|
|
1331
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1332
|
+
const config = await client.deployments.getEmbedConfig(id);
|
|
1333
|
+
printRecord(config);
|
|
1334
|
+
} catch (err) {
|
|
1335
|
+
process.exitCode = handleError(err);
|
|
1336
|
+
}
|
|
1337
|
+
});
|
|
1338
|
+
deployment.command("embed-config-update").description("Update deployment embed configuration").argument("<id>", "Deployment ID").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
1339
|
+
"after",
|
|
1340
|
+
`
|
|
1341
|
+
Examples:
|
|
1342
|
+
$ nexus deployment embed-config-update dep-123 --body '{"theme":"dark"}'
|
|
1343
|
+
$ nexus deployment embed-config-update dep-123 --body config.json`
|
|
1344
|
+
).action(async (id, opts) => {
|
|
1345
|
+
try {
|
|
1346
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1347
|
+
const body = await resolveBody(opts.body) ?? {};
|
|
1348
|
+
await client.deployments.updateEmbedConfig(id, body);
|
|
1349
|
+
printSuccess("Embed config updated.", { id });
|
|
1350
|
+
} catch (err) {
|
|
1351
|
+
process.exitCode = handleError(err);
|
|
1352
|
+
}
|
|
1353
|
+
});
|
|
1354
|
+
const depFolder = deployment.command("folder").description("Manage deployment folders");
|
|
1355
|
+
depFolder.command("list").description("List deployment folders").addHelpText(
|
|
1356
|
+
"after",
|
|
1357
|
+
`
|
|
1358
|
+
Examples:
|
|
1359
|
+
$ nexus deployment folder list
|
|
1360
|
+
$ nexus deployment folder list --json`
|
|
1361
|
+
).action(async () => {
|
|
1362
|
+
try {
|
|
1363
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1364
|
+
const result = await client.deploymentFolders.list();
|
|
1365
|
+
const folders = result.folders ?? result.data ?? result;
|
|
1366
|
+
printTable(Array.isArray(folders) ? folders : [folders], [
|
|
1367
|
+
{ key: "id", label: "ID", width: 36 },
|
|
1368
|
+
{ key: "name", label: "NAME", width: 30 }
|
|
1369
|
+
]);
|
|
1370
|
+
} catch (err) {
|
|
1371
|
+
process.exitCode = handleError(err);
|
|
1372
|
+
}
|
|
1373
|
+
});
|
|
1374
|
+
depFolder.command("create").description("Create a deployment folder").requiredOption("--name <name>", "Folder name").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
1375
|
+
"after",
|
|
1376
|
+
`
|
|
1377
|
+
Examples:
|
|
1378
|
+
$ nexus deployment folder create --name "Production"
|
|
1379
|
+
$ nexus deployment folder create --body '{"name":"Staging"}'`
|
|
1380
|
+
).action(async (opts) => {
|
|
1381
|
+
try {
|
|
1382
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1383
|
+
const base = await resolveBody(opts.body);
|
|
1384
|
+
const body = mergeBodyWithFlags(base, {
|
|
1385
|
+
...opts.name !== void 0 && { name: opts.name }
|
|
1386
|
+
});
|
|
1387
|
+
const folder = await client.deploymentFolders.create(body);
|
|
1388
|
+
printSuccess("Deployment folder created.", {
|
|
1389
|
+
id: folder.id,
|
|
1390
|
+
name: folder.name
|
|
1391
|
+
});
|
|
1392
|
+
} catch (err) {
|
|
1393
|
+
process.exitCode = handleError(err);
|
|
1394
|
+
}
|
|
1395
|
+
});
|
|
1396
|
+
depFolder.command("update").description("Update a deployment folder").argument("<id>", "Folder ID").option("--name <name>", "Folder name").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
1397
|
+
"after",
|
|
1398
|
+
`
|
|
1399
|
+
Examples:
|
|
1400
|
+
$ nexus deployment folder update fld-123 --name "Renamed"
|
|
1401
|
+
$ nexus deployment folder update fld-123 --body '{"name":"Renamed"}'`
|
|
1402
|
+
).action(async (id, opts) => {
|
|
1403
|
+
try {
|
|
1404
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1405
|
+
const base = await resolveBody(opts.body);
|
|
1406
|
+
const body = mergeBodyWithFlags(base, {
|
|
1407
|
+
...opts.name !== void 0 && { name: opts.name }
|
|
1408
|
+
});
|
|
1409
|
+
await client.deploymentFolders.update(id, body);
|
|
1410
|
+
printSuccess("Deployment folder updated.", { id });
|
|
1411
|
+
} catch (err) {
|
|
1412
|
+
process.exitCode = handleError(err);
|
|
1413
|
+
}
|
|
1414
|
+
});
|
|
1415
|
+
depFolder.command("delete").description("Delete a deployment folder").argument("<id>", "Folder ID").option("--yes", "Skip confirmation").addHelpText(
|
|
1416
|
+
"after",
|
|
1417
|
+
`
|
|
1418
|
+
Examples:
|
|
1419
|
+
$ nexus deployment folder delete fld-123
|
|
1420
|
+
$ nexus deployment folder delete fld-123 --yes`
|
|
1421
|
+
).action(async (id, opts) => {
|
|
1422
|
+
try {
|
|
1423
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1424
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
1425
|
+
const readline2 = await import("readline/promises");
|
|
1426
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
1427
|
+
const answer = await rl.question(`Delete deployment folder ${id}? [y/N] `);
|
|
1428
|
+
rl.close();
|
|
1429
|
+
if (answer.toLowerCase() !== "y") {
|
|
1430
|
+
console.log("Aborted.");
|
|
1431
|
+
return;
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
await client.deploymentFolders.delete(id);
|
|
1435
|
+
printSuccess("Deployment folder deleted.", { id });
|
|
1436
|
+
} catch (err) {
|
|
1437
|
+
process.exitCode = handleError(err);
|
|
1438
|
+
}
|
|
1439
|
+
});
|
|
1440
|
+
depFolder.command("assign").description("Assign a deployment to a folder").requiredOption("--deployment-id <id>", "Deployment ID").requiredOption("--folder-id <id>", "Folder ID").addHelpText(
|
|
1441
|
+
"after",
|
|
1442
|
+
`
|
|
1443
|
+
Examples:
|
|
1444
|
+
$ nexus deployment folder assign --deployment-id dep-123 --folder-id fld-456`
|
|
1445
|
+
).action(async (opts) => {
|
|
1446
|
+
try {
|
|
1447
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1448
|
+
await client.deploymentFolders.assign({
|
|
1449
|
+
deploymentId: opts.deploymentId,
|
|
1450
|
+
folderId: opts.folderId
|
|
1451
|
+
});
|
|
1452
|
+
printSuccess("Deployment assigned to folder.", {
|
|
1453
|
+
deploymentId: opts.deploymentId,
|
|
1454
|
+
folderId: opts.folderId
|
|
1455
|
+
});
|
|
1456
|
+
} catch (err) {
|
|
1457
|
+
process.exitCode = handleError(err);
|
|
1458
|
+
}
|
|
1459
|
+
});
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
// src/commands/document.ts
|
|
1463
|
+
var import_node_fs2 = __toESM(require("fs"));
|
|
1464
|
+
var import_node_path2 = __toESM(require("path"));
|
|
1465
|
+
init_output();
|
|
1466
|
+
function registerDocumentCommands(program2) {
|
|
1467
|
+
const document = program2.command("document").description("Manage knowledge documents");
|
|
1468
|
+
addPaginationOptions(
|
|
1469
|
+
document.command("list").description("List documents").option("--search <query>", "Search by name").option("--type <type>", "Filter by type").option("--status <status>", "Filter by status").addHelpText(
|
|
1470
|
+
"after",
|
|
1471
|
+
`
|
|
1472
|
+
Examples:
|
|
1473
|
+
$ nexus document list
|
|
1474
|
+
$ nexus document list --search "report" --limit 10
|
|
1475
|
+
$ nexus document list --status PROCESSED --json`
|
|
1476
|
+
)
|
|
1477
|
+
).action(async (opts) => {
|
|
1478
|
+
try {
|
|
1479
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1480
|
+
const { data, meta } = await client.documents.list({
|
|
1481
|
+
...getPaginationParams(opts),
|
|
1482
|
+
search: opts.search,
|
|
1483
|
+
type: opts.type,
|
|
1484
|
+
status: opts.status
|
|
1485
|
+
});
|
|
1486
|
+
printList(data, meta, [
|
|
1487
|
+
{ key: "id", label: "ID", width: 36 },
|
|
1488
|
+
{ key: "name", label: "NAME", width: 30 },
|
|
1489
|
+
{ key: "type", label: "TYPE", width: 12 },
|
|
1490
|
+
{ key: "status", label: "STATUS", width: 12 }
|
|
1491
|
+
]);
|
|
1492
|
+
} catch (err) {
|
|
1493
|
+
process.exitCode = handleError(err);
|
|
1494
|
+
}
|
|
1495
|
+
});
|
|
1496
|
+
document.command("get").description("Get document details").argument("<id>", "Document ID").addHelpText(
|
|
1497
|
+
"after",
|
|
1498
|
+
`
|
|
1499
|
+
Examples:
|
|
1500
|
+
$ nexus document get doc-123
|
|
1501
|
+
$ nexus document get doc-123 --json`
|
|
1502
|
+
).action(async (id) => {
|
|
1503
|
+
try {
|
|
1504
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1505
|
+
const doc = await client.documents.get(id);
|
|
1506
|
+
printRecord(doc, [
|
|
1507
|
+
{ key: "id", label: "ID" },
|
|
1508
|
+
{ key: "name", label: "Name" },
|
|
1509
|
+
{ key: "type", label: "Type" },
|
|
1510
|
+
{ key: "status", label: "Status" },
|
|
1511
|
+
{ key: "processingProgress", label: "Progress" },
|
|
1512
|
+
{ key: "createdAt", label: "Created" }
|
|
1513
|
+
]);
|
|
1514
|
+
} catch (err) {
|
|
1515
|
+
process.exitCode = handleError(err);
|
|
1516
|
+
}
|
|
1517
|
+
});
|
|
1518
|
+
document.command("upload").description("Upload a file as a document").argument("<file-path>", "Path to the file").option("--description <text>", "Document description").addHelpText(
|
|
1519
|
+
"after",
|
|
1520
|
+
`
|
|
1521
|
+
Examples:
|
|
1522
|
+
$ nexus document upload ./report.pdf
|
|
1523
|
+
$ nexus document upload ./data.csv --description "Q4 sales data"
|
|
1524
|
+
$ nexus document upload ./manual.txt --json`
|
|
1525
|
+
).action(async (filePath, opts) => {
|
|
1526
|
+
try {
|
|
1527
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1528
|
+
const absPath = import_node_path2.default.resolve(filePath);
|
|
1529
|
+
if (!import_node_fs2.default.existsSync(absPath)) {
|
|
1530
|
+
console.error(`Error: File not found: ${absPath}`);
|
|
1531
|
+
process.exitCode = 1;
|
|
1532
|
+
return;
|
|
1533
|
+
}
|
|
1534
|
+
const buffer = import_node_fs2.default.readFileSync(absPath);
|
|
1535
|
+
const blob = new Blob([buffer]);
|
|
1536
|
+
const fileName = import_node_path2.default.basename(absPath);
|
|
1537
|
+
const doc = await client.documents.uploadFile(blob, fileName, opts.description);
|
|
1538
|
+
printSuccess("Document uploaded.", {
|
|
1539
|
+
id: doc.id,
|
|
1540
|
+
name: doc.name ?? fileName
|
|
1541
|
+
});
|
|
1542
|
+
} catch (err) {
|
|
1543
|
+
process.exitCode = handleError(err);
|
|
1544
|
+
}
|
|
1545
|
+
});
|
|
1546
|
+
document.command("create-text").description("Create a text document").requiredOption("--name <name>", "Document name").requiredOption("--content <text-or-->", "Content (text, or '-' for stdin)").option("--description <text>", "Document description").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
1547
|
+
"after",
|
|
1548
|
+
`
|
|
1549
|
+
Examples:
|
|
1550
|
+
$ nexus document create-text --name "FAQ" --content "Q: How do I...\\nA: You can..."
|
|
1551
|
+
$ cat content.md | nexus document create-text --name "Guide" --content -
|
|
1552
|
+
$ nexus document create-text --body '{"name":"FAQ","content":"..."}'`
|
|
1553
|
+
).action(async (opts) => {
|
|
1554
|
+
try {
|
|
1555
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1556
|
+
const base = await resolveBody(opts.body);
|
|
1557
|
+
const flags = {};
|
|
1558
|
+
if (opts.name !== void 0) flags.name = opts.name;
|
|
1559
|
+
if (opts.content) flags.content = await resolveInputValue(opts.content);
|
|
1560
|
+
if (opts.description !== void 0) flags.description = opts.description;
|
|
1561
|
+
const body = mergeBodyWithFlags(base, flags);
|
|
1562
|
+
const doc = await client.documents.createText(body);
|
|
1563
|
+
printSuccess("Text document created.", {
|
|
1564
|
+
id: doc.id,
|
|
1565
|
+
name: doc.name
|
|
1566
|
+
});
|
|
1567
|
+
} catch (err) {
|
|
1568
|
+
process.exitCode = handleError(err);
|
|
1569
|
+
}
|
|
1570
|
+
});
|
|
1571
|
+
document.command("add-website").description("Crawl a website and create document(s)").requiredOption("--url <url>", "Website URL").option("--mode <mode>", "Crawl mode: sitemap, single, etc.", "single").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
1572
|
+
"after",
|
|
1573
|
+
`
|
|
1574
|
+
Examples:
|
|
1575
|
+
$ nexus document add-website --url https://docs.example.com --mode sitemap
|
|
1576
|
+
$ nexus document add-website --url https://example.com/page --mode single
|
|
1577
|
+
$ nexus document add-website --body '{"url":"https://example.com","mode":"sitemap"}'`
|
|
1578
|
+
).action(async (opts) => {
|
|
1579
|
+
try {
|
|
1580
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1581
|
+
const base = await resolveBody(opts.body);
|
|
1582
|
+
const body = mergeBodyWithFlags(base, {
|
|
1583
|
+
...opts.url !== void 0 && { url: opts.url },
|
|
1584
|
+
...opts.mode !== void 0 && { mode: opts.mode }
|
|
1585
|
+
});
|
|
1586
|
+
const doc = await client.documents.addWebsite(body);
|
|
1587
|
+
printSuccess("Website document created.", {
|
|
1588
|
+
id: doc.id,
|
|
1589
|
+
name: doc.name
|
|
1590
|
+
});
|
|
1591
|
+
} catch (err) {
|
|
1592
|
+
process.exitCode = handleError(err);
|
|
1593
|
+
}
|
|
1594
|
+
});
|
|
1595
|
+
document.command("delete").description("Delete a document").argument("<id>", "Document ID").option("--yes", "Skip confirmation").addHelpText(
|
|
1596
|
+
"after",
|
|
1597
|
+
`
|
|
1598
|
+
Examples:
|
|
1599
|
+
$ nexus document delete doc-123
|
|
1600
|
+
$ nexus document delete doc-123 --yes`
|
|
1601
|
+
).action(async (id, opts) => {
|
|
1602
|
+
try {
|
|
1603
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1604
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
1605
|
+
const readline2 = await import("readline/promises");
|
|
1606
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
1607
|
+
const answer = await rl.question(`Delete document ${id}? [y/N] `);
|
|
1608
|
+
rl.close();
|
|
1609
|
+
if (answer.toLowerCase() !== "y") {
|
|
1610
|
+
console.log("Aborted.");
|
|
1611
|
+
return;
|
|
1612
|
+
}
|
|
1613
|
+
}
|
|
1614
|
+
await client.documents.delete(id);
|
|
1615
|
+
printSuccess("Document deleted.", { id });
|
|
1616
|
+
} catch (err) {
|
|
1617
|
+
process.exitCode = handleError(err);
|
|
1618
|
+
}
|
|
1619
|
+
});
|
|
1620
|
+
}
|
|
1621
|
+
|
|
1622
|
+
// src/commands/emulator.ts
|
|
1623
|
+
init_output();
|
|
1624
|
+
function registerEmulatorCommands(program2) {
|
|
1625
|
+
const emulator = program2.command("emulator").description("Test deployments via the emulator");
|
|
1626
|
+
const session = emulator.command("session").description("Manage emulator sessions");
|
|
1627
|
+
session.command("create").description("Create an emulator session").argument("<deployment-id>", "Deployment ID").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
1628
|
+
"after",
|
|
1629
|
+
`
|
|
1630
|
+
Examples:
|
|
1631
|
+
$ nexus emulator session create dep-123
|
|
1632
|
+
$ nexus emulator session create dep-123 --body '{"participant":"user-1"}'
|
|
1633
|
+
$ nexus emulator session create dep-123 --json`
|
|
1634
|
+
).action(async (deploymentId, opts) => {
|
|
1635
|
+
try {
|
|
1636
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1637
|
+
const body = await resolveBody(opts.body);
|
|
1638
|
+
const s = await client.emulator.createSession(deploymentId, body);
|
|
1639
|
+
printRecord(s, [
|
|
1640
|
+
{ key: "id", label: "ID" },
|
|
1641
|
+
{ key: "deploymentId", label: "Deployment ID" },
|
|
1642
|
+
{ key: "status", label: "Status" },
|
|
1643
|
+
{ key: "createdAt", label: "Created" }
|
|
1644
|
+
]);
|
|
1645
|
+
} catch (err) {
|
|
1646
|
+
process.exitCode = handleError(err);
|
|
1647
|
+
}
|
|
1648
|
+
});
|
|
1649
|
+
session.command("list").description("List emulator sessions").argument("<deployment-id>", "Deployment ID").addHelpText(
|
|
1650
|
+
"after",
|
|
1651
|
+
`
|
|
1652
|
+
Examples:
|
|
1653
|
+
$ nexus emulator session list dep-123
|
|
1654
|
+
$ nexus emulator session list dep-123 --json`
|
|
1655
|
+
).action(async (deploymentId) => {
|
|
1656
|
+
try {
|
|
1657
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1658
|
+
const result = await client.emulator.listSessions(deploymentId);
|
|
1659
|
+
const items = Array.isArray(result) ? result : result.data ?? result;
|
|
1660
|
+
printList(items, void 0, [
|
|
1661
|
+
{ key: "id", label: "ID", width: 36 },
|
|
1662
|
+
{ key: "createdAt", label: "CREATED", width: 26 }
|
|
1663
|
+
]);
|
|
1664
|
+
} catch (err) {
|
|
1665
|
+
process.exitCode = handleError(err);
|
|
1666
|
+
}
|
|
1667
|
+
});
|
|
1668
|
+
session.command("get").description("Get emulator session details (with messages)").argument("<deployment-id>", "Deployment ID").argument("<session-id>", "Session ID").addHelpText(
|
|
1669
|
+
"after",
|
|
1670
|
+
`
|
|
1671
|
+
Examples:
|
|
1672
|
+
$ nexus emulator session get dep-123 sess-456
|
|
1673
|
+
$ nexus emulator session get dep-123 sess-456 --json`
|
|
1674
|
+
).action(async (deploymentId, sessionId) => {
|
|
1675
|
+
try {
|
|
1676
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1677
|
+
const s = await client.emulator.getSession(deploymentId, sessionId);
|
|
1678
|
+
printRecord(s, [
|
|
1679
|
+
{ key: "id", label: "ID" },
|
|
1680
|
+
{ key: "deploymentId", label: "Deployment ID" },
|
|
1681
|
+
{ key: "status", label: "Status" },
|
|
1682
|
+
{ key: "messages", label: "Messages" },
|
|
1683
|
+
{ key: "createdAt", label: "Created" }
|
|
1684
|
+
]);
|
|
1685
|
+
} catch (err) {
|
|
1686
|
+
process.exitCode = handleError(err);
|
|
1687
|
+
}
|
|
1688
|
+
});
|
|
1689
|
+
session.command("delete").description("Delete an emulator session").argument("<deployment-id>", "Deployment ID").argument("<session-id>", "Session ID").option("--yes", "Skip confirmation").addHelpText(
|
|
1690
|
+
"after",
|
|
1691
|
+
`
|
|
1692
|
+
Examples:
|
|
1693
|
+
$ nexus emulator session delete dep-123 sess-456
|
|
1694
|
+
$ nexus emulator session delete dep-123 sess-456 --yes`
|
|
1695
|
+
).action(async (deploymentId, sessionId, opts) => {
|
|
1696
|
+
try {
|
|
1697
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1698
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
1699
|
+
const readline2 = await import("readline/promises");
|
|
1700
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
1701
|
+
const answer = await rl.question(`Delete emulator session ${sessionId}? [y/N] `);
|
|
1702
|
+
rl.close();
|
|
1703
|
+
if (answer.toLowerCase() !== "y") {
|
|
1704
|
+
console.log("Aborted.");
|
|
1705
|
+
return;
|
|
1706
|
+
}
|
|
1707
|
+
}
|
|
1708
|
+
await client.emulator.deleteSession(deploymentId, sessionId);
|
|
1709
|
+
printSuccess("Session deleted.", { sessionId });
|
|
1710
|
+
} catch (err) {
|
|
1711
|
+
process.exitCode = handleError(err);
|
|
1712
|
+
}
|
|
1713
|
+
});
|
|
1714
|
+
emulator.command("send").description("Send a message in an emulator session").argument("<deployment-id>", "Deployment ID").argument("<session-id>", "Session ID").option("--text <message>", "Message text").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
1715
|
+
"after",
|
|
1716
|
+
`
|
|
1717
|
+
Examples:
|
|
1718
|
+
$ nexus emulator send dep-123 sess-456 --text "Hello, agent!"
|
|
1719
|
+
$ nexus emulator send dep-123 sess-456 --body '{"text":"Hi","participant":"user-1","debug":true}'
|
|
1720
|
+
$ nexus emulator send dep-123 sess-456 --text "Test" --json`
|
|
1721
|
+
).action(async (deploymentId, sessionId, opts) => {
|
|
1722
|
+
try {
|
|
1723
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1724
|
+
const base = await resolveBody(opts.body);
|
|
1725
|
+
const body = mergeBodyWithFlags(base, {
|
|
1726
|
+
text: opts.text
|
|
1727
|
+
});
|
|
1728
|
+
const result = await client.emulator.sendMessage(deploymentId, sessionId, body);
|
|
1729
|
+
printRecord(result);
|
|
1730
|
+
} catch (err) {
|
|
1731
|
+
process.exitCode = handleError(err);
|
|
1732
|
+
}
|
|
1733
|
+
});
|
|
1734
|
+
const scenario = emulator.command("scenario").description("Manage emulator scenarios");
|
|
1735
|
+
scenario.command("save").description("Save an emulator session as a scenario").option("--session-id <id>", "Session ID").option("--deployment-id <id>", "Deployment ID").option("--name <name>", "Scenario name").option("--description <text>", "Scenario description").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
1736
|
+
"after",
|
|
1737
|
+
`
|
|
1738
|
+
Examples:
|
|
1739
|
+
$ nexus emulator scenario save --session-id sess-123 --deployment-id dep-456 --name "Happy path"
|
|
1740
|
+
$ nexus emulator scenario save --body '{"sessionId":"sess-123","deploymentId":"dep-456","name":"Edge case"}'`
|
|
1741
|
+
).action(async (opts) => {
|
|
1742
|
+
try {
|
|
1743
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1744
|
+
const base = await resolveBody(opts.body);
|
|
1745
|
+
const body = mergeBodyWithFlags(base, {
|
|
1746
|
+
sessionId: opts.sessionId,
|
|
1747
|
+
deploymentId: opts.deploymentId,
|
|
1748
|
+
name: opts.name,
|
|
1749
|
+
description: opts.description
|
|
1750
|
+
});
|
|
1751
|
+
const result = await client.emulator.saveScenario(body);
|
|
1752
|
+
printRecord(result, [
|
|
1753
|
+
{ key: "id", label: "ID" },
|
|
1754
|
+
{ key: "name", label: "Name" },
|
|
1755
|
+
{ key: "description", label: "Description" },
|
|
1756
|
+
{ key: "deploymentId", label: "Deployment ID" },
|
|
1757
|
+
{ key: "sessionId", label: "Session ID" },
|
|
1758
|
+
{ key: "createdAt", label: "Created" }
|
|
1759
|
+
]);
|
|
1760
|
+
} catch (err) {
|
|
1761
|
+
process.exitCode = handleError(err);
|
|
1762
|
+
}
|
|
1763
|
+
});
|
|
1764
|
+
scenario.command("list").description("List emulator scenarios").option("--deployment-id <id>", "Filter by deployment ID").addHelpText(
|
|
1765
|
+
"after",
|
|
1766
|
+
`
|
|
1767
|
+
Examples:
|
|
1768
|
+
$ nexus emulator scenario list
|
|
1769
|
+
$ nexus emulator scenario list --deployment-id dep-123
|
|
1770
|
+
$ nexus emulator scenario list --json`
|
|
1771
|
+
).action(async (opts) => {
|
|
1772
|
+
try {
|
|
1773
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1774
|
+
const result = await client.emulator.listScenarios({
|
|
1775
|
+
deploymentId: opts.deploymentId
|
|
1776
|
+
});
|
|
1777
|
+
const items = Array.isArray(result) ? result : result.data ?? result;
|
|
1778
|
+
printList(items, void 0, [
|
|
1779
|
+
{ key: "id", label: "ID", width: 36 },
|
|
1780
|
+
{ key: "name", label: "NAME", width: 30 },
|
|
1781
|
+
{ key: "deploymentId", label: "DEPLOYMENT", width: 36 },
|
|
1782
|
+
{ key: "createdAt", label: "CREATED", width: 26 }
|
|
1783
|
+
]);
|
|
1784
|
+
} catch (err) {
|
|
1785
|
+
process.exitCode = handleError(err);
|
|
1786
|
+
}
|
|
1787
|
+
});
|
|
1788
|
+
scenario.command("get").description("Get scenario details").argument("<scenario-id>", "Scenario ID").addHelpText(
|
|
1789
|
+
"after",
|
|
1790
|
+
`
|
|
1791
|
+
Examples:
|
|
1792
|
+
$ nexus emulator scenario get scn-123
|
|
1793
|
+
$ nexus emulator scenario get scn-123 --json`
|
|
1794
|
+
).action(async (scenarioId) => {
|
|
1795
|
+
try {
|
|
1796
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1797
|
+
const s = await client.emulator.getScenario(scenarioId);
|
|
1798
|
+
printRecord(s, [
|
|
1799
|
+
{ key: "id", label: "ID" },
|
|
1800
|
+
{ key: "name", label: "Name" },
|
|
1801
|
+
{ key: "description", label: "Description" },
|
|
1802
|
+
{ key: "deploymentId", label: "Deployment ID" },
|
|
1803
|
+
{ key: "sessionId", label: "Session ID" },
|
|
1804
|
+
{ key: "messages", label: "Messages" },
|
|
1805
|
+
{ key: "createdAt", label: "Created" }
|
|
1806
|
+
]);
|
|
1807
|
+
} catch (err) {
|
|
1808
|
+
process.exitCode = handleError(err);
|
|
1809
|
+
}
|
|
1810
|
+
});
|
|
1811
|
+
scenario.command("replay").description("Replay a scenario against a deployment").argument("<scenario-id>", "Scenario ID").option("--deployment-id <id>", "Deployment ID to replay against").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
1812
|
+
"after",
|
|
1813
|
+
`
|
|
1814
|
+
Examples:
|
|
1815
|
+
$ nexus emulator scenario replay scn-123 --deployment-id dep-456
|
|
1816
|
+
$ nexus emulator scenario replay scn-123 --body '{"deploymentId":"dep-456"}'
|
|
1817
|
+
$ nexus emulator scenario replay scn-123 --deployment-id dep-456 --json`
|
|
1818
|
+
).action(async (scenarioId, opts) => {
|
|
1819
|
+
try {
|
|
1820
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1821
|
+
const base = await resolveBody(opts.body);
|
|
1822
|
+
const body = mergeBodyWithFlags(base, {
|
|
1823
|
+
deploymentId: opts.deploymentId
|
|
1824
|
+
});
|
|
1825
|
+
const result = await client.emulator.replayScenario(scenarioId, body);
|
|
1826
|
+
printRecord(result);
|
|
1827
|
+
} catch (err) {
|
|
1828
|
+
process.exitCode = handleError(err);
|
|
1829
|
+
}
|
|
1830
|
+
});
|
|
1831
|
+
scenario.command("delete").description("Delete a scenario").argument("<scenario-id>", "Scenario ID").option("--yes", "Skip confirmation").addHelpText(
|
|
1832
|
+
"after",
|
|
1833
|
+
`
|
|
1834
|
+
Examples:
|
|
1835
|
+
$ nexus emulator scenario delete scn-123
|
|
1836
|
+
$ nexus emulator scenario delete scn-123 --yes`
|
|
1837
|
+
).action(async (scenarioId, opts) => {
|
|
1838
|
+
try {
|
|
1839
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1840
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
1841
|
+
const readline2 = await import("readline/promises");
|
|
1842
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
1843
|
+
const answer = await rl.question(`Delete scenario ${scenarioId}? [y/N] `);
|
|
1844
|
+
rl.close();
|
|
1845
|
+
if (answer.toLowerCase() !== "y") {
|
|
1846
|
+
console.log("Aborted.");
|
|
1847
|
+
return;
|
|
1848
|
+
}
|
|
1849
|
+
}
|
|
1850
|
+
await client.emulator.deleteScenario(scenarioId);
|
|
1851
|
+
printSuccess("Scenario deleted.", { scenarioId });
|
|
1852
|
+
} catch (err) {
|
|
1853
|
+
process.exitCode = handleError(err);
|
|
1854
|
+
}
|
|
1855
|
+
});
|
|
1856
|
+
}
|
|
1857
|
+
|
|
1858
|
+
// src/commands/evaluation.ts
|
|
1859
|
+
init_output();
|
|
1860
|
+
function registerEvaluationCommands(program2) {
|
|
1861
|
+
const eval_ = program2.command("eval").description("Manage evaluations for AI tasks");
|
|
1862
|
+
const session = eval_.command("session").description("Manage evaluation sessions");
|
|
1863
|
+
session.command("create").description("Create an evaluation session").argument("<task-id>", "Task ID").option("--name <name>", "Session name").option("--description <text>", "Session description").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
1864
|
+
"after",
|
|
1865
|
+
`
|
|
1866
|
+
Examples:
|
|
1867
|
+
$ nexus eval session create task-123 --name "Accuracy Test v1"
|
|
1868
|
+
$ nexus eval session create task-123 --name "Edge cases" --description "Tests edge cases"
|
|
1869
|
+
$ nexus eval session create task-123 --body '{"name":"Full test","description":"..."}'`
|
|
1870
|
+
).action(async (taskId, opts) => {
|
|
1871
|
+
try {
|
|
1872
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1873
|
+
const base = await resolveBody(opts.body);
|
|
1874
|
+
const body = mergeBodyWithFlags(base, {
|
|
1875
|
+
name: opts.name,
|
|
1876
|
+
description: opts.description
|
|
1877
|
+
});
|
|
1878
|
+
const s = await client.evaluations.createSession(taskId, body);
|
|
1879
|
+
printRecord(s, [
|
|
1880
|
+
{ key: "id", label: "ID" },
|
|
1881
|
+
{ key: "name", label: "Name" },
|
|
1882
|
+
{ key: "description", label: "Description" },
|
|
1883
|
+
{ key: "status", label: "Status" },
|
|
1884
|
+
{ key: "createdAt", label: "Created" }
|
|
1885
|
+
]);
|
|
1886
|
+
} catch (err) {
|
|
1887
|
+
process.exitCode = handleError(err);
|
|
1888
|
+
}
|
|
1889
|
+
});
|
|
1890
|
+
addPaginationOptions(
|
|
1891
|
+
session.command("list").description("List evaluation sessions").argument("<task-id>", "Task ID").addHelpText(
|
|
1892
|
+
"after",
|
|
1893
|
+
`
|
|
1894
|
+
Examples:
|
|
1895
|
+
$ nexus eval session list task-123
|
|
1896
|
+
$ nexus eval session list task-123 --limit 10
|
|
1897
|
+
$ nexus eval session list task-123 --json`
|
|
1898
|
+
)
|
|
1899
|
+
).action(async (taskId, opts) => {
|
|
1900
|
+
try {
|
|
1901
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1902
|
+
const { data, meta } = await client.evaluations.listSessions(taskId, {
|
|
1903
|
+
...getPaginationParams(opts)
|
|
1904
|
+
});
|
|
1905
|
+
printList(
|
|
1906
|
+
data,
|
|
1907
|
+
meta,
|
|
1908
|
+
[
|
|
1909
|
+
{ key: "id", label: "ID", width: 36 },
|
|
1910
|
+
{ key: "name", label: "NAME", width: 30 },
|
|
1911
|
+
{ key: "status", label: "STATUS", width: 15 },
|
|
1912
|
+
{ key: "createdAt", label: "CREATED", width: 26 }
|
|
1913
|
+
]
|
|
1914
|
+
);
|
|
1915
|
+
} catch (err) {
|
|
1916
|
+
process.exitCode = handleError(err);
|
|
1917
|
+
}
|
|
1918
|
+
});
|
|
1919
|
+
session.command("get").description("Get evaluation session details").argument("<task-id>", "Task ID").argument("<session-id>", "Session ID").addHelpText(
|
|
1920
|
+
"after",
|
|
1921
|
+
`
|
|
1922
|
+
Examples:
|
|
1923
|
+
$ nexus eval session get task-123 sess-456
|
|
1924
|
+
$ nexus eval session get task-123 sess-456 --json`
|
|
1925
|
+
).action(async (taskId, sessionId) => {
|
|
1926
|
+
try {
|
|
1927
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1928
|
+
const s = await client.evaluations.getSession(taskId, sessionId);
|
|
1929
|
+
printRecord(s, [
|
|
1930
|
+
{ key: "id", label: "ID" },
|
|
1931
|
+
{ key: "name", label: "Name" },
|
|
1932
|
+
{ key: "description", label: "Description" },
|
|
1933
|
+
{ key: "status", label: "Status" },
|
|
1934
|
+
{ key: "rowCount", label: "Rows" },
|
|
1935
|
+
{ key: "createdAt", label: "Created" }
|
|
1936
|
+
]);
|
|
1937
|
+
} catch (err) {
|
|
1938
|
+
process.exitCode = handleError(err);
|
|
1939
|
+
}
|
|
1940
|
+
});
|
|
1941
|
+
session.command("delete").description("Delete an evaluation session").argument("<task-id>", "Task ID").argument("<session-id>", "Session ID").option("--yes", "Skip confirmation").addHelpText(
|
|
1942
|
+
"after",
|
|
1943
|
+
`
|
|
1944
|
+
Examples:
|
|
1945
|
+
$ nexus eval session delete task-123 sess-456
|
|
1946
|
+
$ nexus eval session delete task-123 sess-456 --yes`
|
|
1947
|
+
).action(async (taskId, sessionId, opts) => {
|
|
1948
|
+
try {
|
|
1949
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1950
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
1951
|
+
const readline2 = await import("readline/promises");
|
|
1952
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
1953
|
+
const answer = await rl.question(`Delete evaluation session ${sessionId}? [y/N] `);
|
|
1954
|
+
rl.close();
|
|
1955
|
+
if (answer.toLowerCase() !== "y") {
|
|
1956
|
+
console.log("Aborted.");
|
|
1957
|
+
return;
|
|
1958
|
+
}
|
|
1959
|
+
}
|
|
1960
|
+
await client.evaluations.deleteSession(taskId, sessionId);
|
|
1961
|
+
printSuccess("Evaluation session deleted.", { sessionId });
|
|
1962
|
+
} catch (err) {
|
|
1963
|
+
process.exitCode = handleError(err);
|
|
1964
|
+
}
|
|
1965
|
+
});
|
|
1966
|
+
const dataset = eval_.command("dataset").description("Manage evaluation dataset rows");
|
|
1967
|
+
addPaginationOptions(
|
|
1968
|
+
dataset.command("list").description("List dataset rows").argument("<task-id>", "Task ID").argument("<session-id>", "Session ID").addHelpText(
|
|
1969
|
+
"after",
|
|
1970
|
+
`
|
|
1971
|
+
Examples:
|
|
1972
|
+
$ nexus eval dataset list task-123 sess-456
|
|
1973
|
+
$ nexus eval dataset list task-123 sess-456 --limit 20
|
|
1974
|
+
$ nexus eval dataset list task-123 sess-456 --json`
|
|
1975
|
+
)
|
|
1976
|
+
).action(async (taskId, sessionId, opts) => {
|
|
1977
|
+
try {
|
|
1978
|
+
const client = createClient(program2.optsWithGlobals());
|
|
1979
|
+
const { data, meta } = await client.evaluations.getDatasetRows(taskId, sessionId, {
|
|
1980
|
+
...getPaginationParams(opts)
|
|
1981
|
+
});
|
|
1982
|
+
printList(
|
|
1983
|
+
data,
|
|
1984
|
+
meta,
|
|
1985
|
+
[
|
|
1986
|
+
{ key: "id", label: "ID", width: 36 },
|
|
1987
|
+
{ key: "input", label: "INPUT", width: 40 },
|
|
1988
|
+
{ key: "expectedOutput", label: "EXPECTED OUTPUT", width: 40 }
|
|
1989
|
+
]
|
|
1990
|
+
);
|
|
1991
|
+
} catch (err) {
|
|
1992
|
+
process.exitCode = handleError(err);
|
|
1993
|
+
}
|
|
1994
|
+
});
|
|
1995
|
+
dataset.command("add").description("Add a row to the evaluation dataset").argument("<task-id>", "Task ID").argument("<session-id>", "Session ID").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
1996
|
+
"after",
|
|
1997
|
+
`
|
|
1998
|
+
Examples:
|
|
1999
|
+
$ nexus eval dataset add task-123 sess-456 --body '{"input":"Hello","expectedOutput":"Hi there"}'
|
|
2000
|
+
$ nexus eval dataset add task-123 sess-456 --body dataset-row.json`
|
|
2001
|
+
).action(async (taskId, sessionId, opts) => {
|
|
2002
|
+
try {
|
|
2003
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2004
|
+
const body = await resolveBody(opts.body);
|
|
2005
|
+
const row = await client.evaluations.addDatasetRow(taskId, sessionId, body);
|
|
2006
|
+
printRecord(row, [
|
|
2007
|
+
{ key: "id", label: "ID" },
|
|
2008
|
+
{ key: "input", label: "Input" },
|
|
2009
|
+
{ key: "expectedOutput", label: "Expected Output" }
|
|
2010
|
+
]);
|
|
2011
|
+
} catch (err) {
|
|
2012
|
+
process.exitCode = handleError(err);
|
|
2013
|
+
}
|
|
2014
|
+
});
|
|
2015
|
+
eval_.command("execute").description("Execute an evaluation run").argument("<task-id>", "Task ID").argument("<session-id>", "Session ID").addHelpText(
|
|
2016
|
+
"after",
|
|
2017
|
+
`
|
|
2018
|
+
Examples:
|
|
2019
|
+
$ nexus eval execute task-123 sess-456
|
|
2020
|
+
$ nexus eval execute task-123 sess-456 --json`
|
|
2021
|
+
).action(async (taskId, sessionId) => {
|
|
2022
|
+
try {
|
|
2023
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2024
|
+
const result = await client.evaluations.execute(taskId, sessionId);
|
|
2025
|
+
printRecord(result);
|
|
2026
|
+
} catch (err) {
|
|
2027
|
+
process.exitCode = handleError(err);
|
|
2028
|
+
}
|
|
2029
|
+
});
|
|
2030
|
+
eval_.command("judge").description("Judge evaluation results with AI").argument("<task-id>", "Task ID").argument("<session-id>", "Session ID").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
2031
|
+
"after",
|
|
2032
|
+
`
|
|
2033
|
+
Examples:
|
|
2034
|
+
$ nexus eval judge task-123 sess-456
|
|
2035
|
+
$ nexus eval judge task-123 sess-456 --body '{"judgeModel":"gpt-4o","judgePrompt":"Rate accuracy"}'
|
|
2036
|
+
$ nexus eval judge task-123 sess-456 --json`
|
|
2037
|
+
).action(async (taskId, sessionId, opts) => {
|
|
2038
|
+
try {
|
|
2039
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2040
|
+
const body = await resolveBody(opts.body);
|
|
2041
|
+
const result = await client.evaluations.judge(taskId, sessionId, body);
|
|
2042
|
+
printRecord(result);
|
|
2043
|
+
} catch (err) {
|
|
2044
|
+
process.exitCode = handleError(err);
|
|
2045
|
+
}
|
|
2046
|
+
});
|
|
2047
|
+
addPaginationOptions(
|
|
2048
|
+
eval_.command("results").description("Get evaluation results").argument("<task-id>", "Task ID").argument("<session-id>", "Session ID").addHelpText(
|
|
2049
|
+
"after",
|
|
2050
|
+
`
|
|
2051
|
+
Examples:
|
|
2052
|
+
$ nexus eval results task-123 sess-456
|
|
2053
|
+
$ nexus eval results task-123 sess-456 --limit 50
|
|
2054
|
+
$ nexus eval results task-123 sess-456 --json`
|
|
2055
|
+
)
|
|
2056
|
+
).action(async (taskId, sessionId, opts) => {
|
|
2057
|
+
try {
|
|
2058
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2059
|
+
const { data, meta } = await client.evaluations.getResults(taskId, sessionId, {
|
|
2060
|
+
...getPaginationParams(opts)
|
|
2061
|
+
});
|
|
2062
|
+
printList(
|
|
2063
|
+
data,
|
|
2064
|
+
meta,
|
|
2065
|
+
[
|
|
2066
|
+
{ key: "id", label: "ID", width: 36 },
|
|
2067
|
+
{ key: "input", label: "INPUT", width: 30 },
|
|
2068
|
+
{ key: "output", label: "OUTPUT", width: 30 },
|
|
2069
|
+
{ key: "score", label: "SCORE", width: 8 },
|
|
2070
|
+
{ key: "passed", label: "PASSED", width: 8 }
|
|
2071
|
+
]
|
|
2072
|
+
);
|
|
2073
|
+
} catch (err) {
|
|
2074
|
+
process.exitCode = handleError(err);
|
|
2075
|
+
}
|
|
2076
|
+
});
|
|
2077
|
+
eval_.command("formats").description("List available evaluation formats").addHelpText(
|
|
2078
|
+
"after",
|
|
2079
|
+
`
|
|
2080
|
+
Examples:
|
|
2081
|
+
$ nexus eval formats
|
|
2082
|
+
$ nexus eval formats --json`
|
|
2083
|
+
).action(async () => {
|
|
2084
|
+
try {
|
|
2085
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2086
|
+
const result = await client.evaluations.listFormats();
|
|
2087
|
+
const items = Array.isArray(result) ? result : result.data ?? result;
|
|
2088
|
+
printList(items, void 0, [
|
|
2089
|
+
{ key: "id", label: "ID", width: 36 },
|
|
2090
|
+
{ key: "name", label: "NAME", width: 30 },
|
|
2091
|
+
{ key: "description", label: "DESCRIPTION", width: 50 }
|
|
2092
|
+
]);
|
|
2093
|
+
} catch (err) {
|
|
2094
|
+
process.exitCode = handleError(err);
|
|
2095
|
+
}
|
|
2096
|
+
});
|
|
2097
|
+
eval_.command("judges").description("List available judge models").addHelpText(
|
|
2098
|
+
"after",
|
|
2099
|
+
`
|
|
2100
|
+
Examples:
|
|
2101
|
+
$ nexus eval judges
|
|
2102
|
+
$ nexus eval judges --json`
|
|
2103
|
+
).action(async () => {
|
|
2104
|
+
try {
|
|
2105
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2106
|
+
const result = await client.evaluations.listJudges();
|
|
2107
|
+
const items = Array.isArray(result) ? result : result.data ?? result;
|
|
2108
|
+
printList(items, void 0, [
|
|
2109
|
+
{ key: "id", label: "ID", width: 36 },
|
|
2110
|
+
{ key: "name", label: "NAME", width: 30 },
|
|
2111
|
+
{ key: "provider", label: "PROVIDER", width: 20 }
|
|
2112
|
+
]);
|
|
2113
|
+
} catch (err) {
|
|
2114
|
+
process.exitCode = handleError(err);
|
|
2115
|
+
}
|
|
2116
|
+
});
|
|
2117
|
+
}
|
|
2118
|
+
|
|
2119
|
+
// src/commands/execution.ts
|
|
2120
|
+
init_output();
|
|
2121
|
+
function registerExecutionCommands(program2) {
|
|
2122
|
+
const execution = program2.command("execution").description("View workflow execution history");
|
|
2123
|
+
addPaginationOptions(
|
|
2124
|
+
execution.command("list").description("List workflow executions").option("--workflow-id <id>", "Filter by workflow ID").option("--status <status>", "Filter by status").addHelpText(
|
|
2125
|
+
"after",
|
|
2126
|
+
`
|
|
2127
|
+
Examples:
|
|
2128
|
+
$ nexus execution list
|
|
2129
|
+
$ nexus execution list --workflow-id wf-123 --limit 5
|
|
2130
|
+
$ nexus execution list --status COMPLETED --json`
|
|
2131
|
+
)
|
|
2132
|
+
).action(async (opts) => {
|
|
2133
|
+
try {
|
|
2134
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2135
|
+
let result;
|
|
2136
|
+
if (opts.workflowId) {
|
|
2137
|
+
result = await client.workflowExecutions.listByWorkflow(opts.workflowId, {
|
|
2138
|
+
...getPaginationParams(opts),
|
|
2139
|
+
status: opts.status
|
|
2140
|
+
});
|
|
2141
|
+
} else {
|
|
2142
|
+
result = await client.workflowExecutions.list({
|
|
2143
|
+
...getPaginationParams(opts),
|
|
2144
|
+
status: opts.status
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
const data = result.data ?? result;
|
|
2148
|
+
const meta = result.meta;
|
|
2149
|
+
printList(Array.isArray(data) ? data : [data], meta, [
|
|
2150
|
+
{ key: "id", label: "ID", width: 36 },
|
|
2151
|
+
{ key: "workflowId", label: "WORKFLOW", width: 36 },
|
|
2152
|
+
{ key: "status", label: "STATUS", width: 12 },
|
|
2153
|
+
{ key: "createdAt", label: "STARTED", width: 20 }
|
|
2154
|
+
]);
|
|
2155
|
+
} catch (err) {
|
|
2156
|
+
process.exitCode = handleError(err);
|
|
2157
|
+
}
|
|
2158
|
+
});
|
|
2159
|
+
execution.command("get").description("Get execution details").argument("<id>", "Execution ID").addHelpText(
|
|
2160
|
+
"after",
|
|
2161
|
+
`
|
|
2162
|
+
Examples:
|
|
2163
|
+
$ nexus execution get exec-123
|
|
2164
|
+
$ nexus execution get exec-123 --json`
|
|
2165
|
+
).action(async (id) => {
|
|
2166
|
+
try {
|
|
2167
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2168
|
+
const exec2 = await client.workflowExecutions.get(id);
|
|
2169
|
+
printRecord(exec2, [
|
|
2170
|
+
{ key: "id", label: "ID" },
|
|
2171
|
+
{ key: "workflowId", label: "Workflow" },
|
|
2172
|
+
{ key: "status", label: "Status" },
|
|
2173
|
+
{ key: "createdAt", label: "Started" },
|
|
2174
|
+
{ key: "completedAt", label: "Completed" },
|
|
2175
|
+
{ key: "duration", label: "Duration" }
|
|
2176
|
+
]);
|
|
2177
|
+
} catch (err) {
|
|
2178
|
+
process.exitCode = handleError(err);
|
|
2179
|
+
}
|
|
2180
|
+
});
|
|
2181
|
+
execution.command("graph").description("Get execution graph (node-level results)").argument("<id>", "Execution ID").addHelpText(
|
|
2182
|
+
"after",
|
|
2183
|
+
`
|
|
2184
|
+
Examples:
|
|
2185
|
+
$ nexus execution graph exec-123
|
|
2186
|
+
$ nexus execution graph exec-123 --json`
|
|
2187
|
+
).action(async (id) => {
|
|
2188
|
+
try {
|
|
2189
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2190
|
+
const graph = await client.workflowExecutions.getGraph(id);
|
|
2191
|
+
printRecord(graph);
|
|
2192
|
+
} catch (err) {
|
|
2193
|
+
process.exitCode = handleError(err);
|
|
2194
|
+
}
|
|
2195
|
+
});
|
|
2196
|
+
execution.command("output").description("Get execution output").argument("<id>", "Execution ID").addHelpText(
|
|
2197
|
+
"after",
|
|
2198
|
+
`
|
|
2199
|
+
Examples:
|
|
2200
|
+
$ nexus execution output exec-123
|
|
2201
|
+
$ nexus execution output exec-123 --json`
|
|
2202
|
+
).action(async (id) => {
|
|
2203
|
+
try {
|
|
2204
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2205
|
+
const output = await client.workflowExecutions.getOutput(id);
|
|
2206
|
+
printRecord(output);
|
|
2207
|
+
} catch (err) {
|
|
2208
|
+
process.exitCode = handleError(err);
|
|
2209
|
+
}
|
|
2210
|
+
});
|
|
2211
|
+
execution.command("retry").description("Retry a failed node in an execution").argument("<id>", "Execution ID").argument("<node-id>", "Node ID to retry").addHelpText(
|
|
2212
|
+
"after",
|
|
2213
|
+
`
|
|
2214
|
+
Examples:
|
|
2215
|
+
$ nexus execution retry exec-123 node-456`
|
|
2216
|
+
).action(async (id, nodeId) => {
|
|
2217
|
+
try {
|
|
2218
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2219
|
+
const result = await client.workflowExecutions.retryNode(id, nodeId);
|
|
2220
|
+
printSuccess("Node retry initiated.", { executionId: id, nodeId, ...result });
|
|
2221
|
+
} catch (err) {
|
|
2222
|
+
process.exitCode = handleError(err);
|
|
2223
|
+
}
|
|
2224
|
+
});
|
|
2225
|
+
execution.command("export").description("Export execution data").argument("<id>", "Execution ID").addHelpText(
|
|
2226
|
+
"after",
|
|
2227
|
+
`
|
|
2228
|
+
Examples:
|
|
2229
|
+
$ nexus execution export exec-123
|
|
2230
|
+
$ nexus execution export exec-123 --json`
|
|
2231
|
+
).action(async (id) => {
|
|
2232
|
+
try {
|
|
2233
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2234
|
+
const data = await client.workflowExecutions.export(id);
|
|
2235
|
+
printRecord(data);
|
|
2236
|
+
} catch (err) {
|
|
2237
|
+
process.exitCode = handleError(err);
|
|
2238
|
+
}
|
|
2239
|
+
});
|
|
2240
|
+
execution.command("node-result").description("Get result of a specific node in an execution").argument("<id>", "Execution ID").argument("<node-id>", "Node ID").addHelpText(
|
|
2241
|
+
"after",
|
|
2242
|
+
`
|
|
2243
|
+
Examples:
|
|
2244
|
+
$ nexus execution node-result exec-123 node-456
|
|
2245
|
+
$ nexus execution node-result exec-123 node-456 --json`
|
|
2246
|
+
).action(async (id, nodeId) => {
|
|
2247
|
+
try {
|
|
2248
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2249
|
+
const result = await client.workflowExecutions.getNodeResult(id, nodeId);
|
|
2250
|
+
printRecord(result);
|
|
2251
|
+
} catch (err) {
|
|
2252
|
+
process.exitCode = handleError(err);
|
|
2253
|
+
}
|
|
2254
|
+
});
|
|
2255
|
+
}
|
|
2256
|
+
|
|
2257
|
+
// src/commands/external-tool.ts
|
|
2258
|
+
init_output();
|
|
2259
|
+
function registerExternalToolCommands(program2) {
|
|
2260
|
+
const externalTool = program2.command("external-tool").description("Manage external tools (OpenAPI integrations)");
|
|
2261
|
+
externalTool.command("list").description("List external tools").option("--search <query>", "Search by name").option("--limit <number>", "Max results", parseInt).addHelpText(
|
|
2262
|
+
"after",
|
|
2263
|
+
`
|
|
2264
|
+
Examples:
|
|
2265
|
+
$ nexus external-tool list
|
|
2266
|
+
$ nexus external-tool list --search "weather" --limit 10
|
|
2267
|
+
$ nexus external-tool list --json`
|
|
2268
|
+
).action(async (opts) => {
|
|
2269
|
+
try {
|
|
2270
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2271
|
+
const result = await client.skills.listExternalTools({
|
|
2272
|
+
search: opts.search,
|
|
2273
|
+
limit: opts.limit
|
|
2274
|
+
});
|
|
2275
|
+
const items = Array.isArray(result) ? result : result.items ?? result.data ?? result;
|
|
2276
|
+
printList(items, void 0, [
|
|
2277
|
+
{ key: "id", label: "ID", width: 36 },
|
|
2278
|
+
{ key: "name", label: "NAME", width: 30 },
|
|
2279
|
+
{ key: "description", label: "DESCRIPTION", width: 40 },
|
|
2280
|
+
{ key: "createdAt", label: "CREATED", width: 26 }
|
|
2281
|
+
]);
|
|
2282
|
+
} catch (err) {
|
|
2283
|
+
process.exitCode = handleError(err);
|
|
2284
|
+
}
|
|
2285
|
+
});
|
|
2286
|
+
externalTool.command("get").description("Get external tool details").argument("<id>", "External tool ID").addHelpText(
|
|
2287
|
+
"after",
|
|
2288
|
+
`
|
|
2289
|
+
Examples:
|
|
2290
|
+
$ nexus external-tool get ext-123
|
|
2291
|
+
$ nexus external-tool get ext-123 --json`
|
|
2292
|
+
).action(async (id) => {
|
|
2293
|
+
try {
|
|
2294
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2295
|
+
const t = await client.skills.getExternalTool(id);
|
|
2296
|
+
printRecord(t, [
|
|
2297
|
+
{ key: "id", label: "ID" },
|
|
2298
|
+
{ key: "name", label: "Name" },
|
|
2299
|
+
{ key: "description", label: "Description" },
|
|
2300
|
+
{ key: "baseUrl", label: "Base URL" },
|
|
2301
|
+
{ key: "createdAt", label: "Created" },
|
|
2302
|
+
{ key: "updatedAt", label: "Updated" }
|
|
2303
|
+
]);
|
|
2304
|
+
} catch (err) {
|
|
2305
|
+
process.exitCode = handleError(err);
|
|
2306
|
+
}
|
|
2307
|
+
});
|
|
2308
|
+
externalTool.command("create").description("Create an external tool from an OpenAPI spec").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
2309
|
+
"after",
|
|
2310
|
+
`
|
|
2311
|
+
Examples:
|
|
2312
|
+
$ nexus external-tool create --body openapi-tool.json
|
|
2313
|
+
$ nexus external-tool create --body '{"name":"Weather API","spec":{...}}'
|
|
2314
|
+
$ cat spec.json | nexus external-tool create --body -`
|
|
2315
|
+
).action(async (opts) => {
|
|
2316
|
+
try {
|
|
2317
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2318
|
+
const body = await resolveBody(opts.body);
|
|
2319
|
+
const t = await client.skills.createExternalTool(body);
|
|
2320
|
+
printSuccess("External tool created.", {
|
|
2321
|
+
id: t.id,
|
|
2322
|
+
name: t.name
|
|
2323
|
+
});
|
|
2324
|
+
} catch (err) {
|
|
2325
|
+
process.exitCode = handleError(err);
|
|
2326
|
+
}
|
|
2327
|
+
});
|
|
2328
|
+
externalTool.command("test").description("Test an external tool operation").argument("<id>", "External tool ID").option("--operation-id <op>", "Operation ID to test").option("--input <json>", "Input parameters as JSON").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
2329
|
+
"after",
|
|
2330
|
+
`
|
|
2331
|
+
Examples:
|
|
2332
|
+
$ nexus external-tool test ext-123 --operation-id getWeather --input '{"city":"London"}'
|
|
2333
|
+
$ nexus external-tool test ext-123 --body '{"operationId":"getWeather","input":{"city":"London"}}'
|
|
2334
|
+
$ nexus external-tool test ext-123 --operation-id listItems --json`
|
|
2335
|
+
).action(async (id, opts) => {
|
|
2336
|
+
try {
|
|
2337
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2338
|
+
const base = await resolveBody(opts.body);
|
|
2339
|
+
const flags = {};
|
|
2340
|
+
if (opts.operationId) flags.operationId = opts.operationId;
|
|
2341
|
+
if (opts.input) flags.input = JSON.parse(opts.input);
|
|
2342
|
+
const body = mergeBodyWithFlags(base, flags);
|
|
2343
|
+
const result = await client.skills.testExternalTool(id, body);
|
|
2344
|
+
printRecord(result);
|
|
2345
|
+
} catch (err) {
|
|
2346
|
+
process.exitCode = handleError(err);
|
|
2347
|
+
}
|
|
2348
|
+
});
|
|
2349
|
+
}
|
|
2350
|
+
|
|
2351
|
+
// src/commands/folder.ts
|
|
2352
|
+
init_output();
|
|
2353
|
+
function registerFolderCommands(program2) {
|
|
2354
|
+
const folder = program2.command("folder").description("Manage agent folders");
|
|
2355
|
+
folder.command("list").description("List all folders").addHelpText(
|
|
2356
|
+
"after",
|
|
2357
|
+
`
|
|
2358
|
+
Examples:
|
|
2359
|
+
$ nexus folder list
|
|
2360
|
+
$ nexus folder list --json`
|
|
2361
|
+
).action(async () => {
|
|
2362
|
+
try {
|
|
2363
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2364
|
+
const result = await client.folders.list();
|
|
2365
|
+
const folders = result.folders ?? result;
|
|
2366
|
+
printTable(Array.isArray(folders) ? folders : [folders], [
|
|
2367
|
+
{ key: "id", label: "ID", width: 36 },
|
|
2368
|
+
{ key: "name", label: "NAME", width: 30 },
|
|
2369
|
+
{ key: "parentId", label: "PARENT", width: 36 }
|
|
2370
|
+
]);
|
|
2371
|
+
} catch (err) {
|
|
2372
|
+
process.exitCode = handleError(err);
|
|
2373
|
+
}
|
|
2374
|
+
});
|
|
2375
|
+
folder.command("create").description("Create a new folder").requiredOption("--name <name>", "Folder name").option("--parent-id <id>", "Parent folder ID for nesting").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
2376
|
+
"after",
|
|
2377
|
+
`
|
|
2378
|
+
Examples:
|
|
2379
|
+
$ nexus folder create --name "Customer Support"
|
|
2380
|
+
$ nexus folder create --name "Sub Team" --parent-id abc-123
|
|
2381
|
+
$ nexus folder create --body '{"name":"Support"}'`
|
|
2382
|
+
).action(async (opts) => {
|
|
2383
|
+
try {
|
|
2384
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2385
|
+
const base = await resolveBody(opts.body);
|
|
2386
|
+
const body = mergeBodyWithFlags(base, {
|
|
2387
|
+
...opts.name !== void 0 && { name: opts.name },
|
|
2388
|
+
...opts.parentId !== void 0 && { parentId: opts.parentId }
|
|
2389
|
+
});
|
|
2390
|
+
const folder2 = await client.folders.create(body);
|
|
2391
|
+
printSuccess("Folder created.", {
|
|
2392
|
+
id: folder2.id,
|
|
2393
|
+
name: folder2.name
|
|
2394
|
+
});
|
|
2395
|
+
} catch (err) {
|
|
2396
|
+
process.exitCode = handleError(err);
|
|
2397
|
+
}
|
|
2398
|
+
});
|
|
2399
|
+
folder.command("update").description("Update a folder").argument("<id>", "Folder ID").option("--name <name>", "New folder name").option("--parent-id <id>", "New parent folder ID (use 'null' for root)").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
2400
|
+
"after",
|
|
2401
|
+
`
|
|
2402
|
+
Examples:
|
|
2403
|
+
$ nexus folder update abc-123 --name "Renamed Folder"
|
|
2404
|
+
$ nexus folder update abc-123 --parent-id null
|
|
2405
|
+
$ nexus folder update abc-123 --body '{"name":"Renamed"}'`
|
|
2406
|
+
).action(async (id, opts) => {
|
|
2407
|
+
try {
|
|
2408
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2409
|
+
const base = await resolveBody(opts.body);
|
|
2410
|
+
const flags = {};
|
|
2411
|
+
if (opts.name !== void 0) flags.name = opts.name;
|
|
2412
|
+
if (opts.parentId !== void 0) {
|
|
2413
|
+
flags.parentId = opts.parentId === "null" ? null : opts.parentId;
|
|
2414
|
+
}
|
|
2415
|
+
const body = mergeBodyWithFlags(base, flags);
|
|
2416
|
+
await client.folders.update(id, body);
|
|
2417
|
+
printSuccess("Folder updated.", { id });
|
|
2418
|
+
} catch (err) {
|
|
2419
|
+
process.exitCode = handleError(err);
|
|
2420
|
+
}
|
|
2421
|
+
});
|
|
2422
|
+
folder.command("delete").description("Delete a folder (agents are unassigned, not deleted)").argument("<id>", "Folder ID").option("--yes", "Skip confirmation").addHelpText(
|
|
2423
|
+
"after",
|
|
2424
|
+
`
|
|
2425
|
+
Examples:
|
|
2426
|
+
$ nexus folder delete abc-123
|
|
2427
|
+
$ nexus folder delete abc-123 --yes`
|
|
2428
|
+
).action(async (id, opts) => {
|
|
2429
|
+
try {
|
|
2430
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2431
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
2432
|
+
const readline2 = await import("readline/promises");
|
|
2433
|
+
const rl = readline2.createInterface({
|
|
2434
|
+
input: process.stdin,
|
|
2435
|
+
output: process.stdout
|
|
2436
|
+
});
|
|
2437
|
+
const answer = await rl.question(
|
|
2438
|
+
`Delete folder ${id}? Agents will be unassigned. [y/N] `
|
|
2439
|
+
);
|
|
2440
|
+
rl.close();
|
|
2441
|
+
if (answer.toLowerCase() !== "y") {
|
|
2442
|
+
console.log("Aborted.");
|
|
2443
|
+
return;
|
|
2444
|
+
}
|
|
2445
|
+
}
|
|
2446
|
+
await client.folders.delete(id);
|
|
2447
|
+
printSuccess("Folder deleted.", { id });
|
|
2448
|
+
} catch (err) {
|
|
2449
|
+
process.exitCode = handleError(err);
|
|
2450
|
+
}
|
|
2451
|
+
});
|
|
2452
|
+
folder.command("assign").description("Assign an agent to a folder (or remove from folder)").requiredOption("--agent-id <id>", "Agent ID").requiredOption("--folder-id <id>", "Folder ID (use 'null' to remove)").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
2453
|
+
"after",
|
|
2454
|
+
`
|
|
2455
|
+
Examples:
|
|
2456
|
+
$ nexus folder assign --agent-id agt-123 --folder-id fld-456
|
|
2457
|
+
$ nexus folder assign --agent-id agt-123 --folder-id null
|
|
2458
|
+
$ nexus folder assign --body '{"agentId":"agt-123","folderId":"fld-456"}'`
|
|
2459
|
+
).action(async (opts) => {
|
|
2460
|
+
try {
|
|
2461
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2462
|
+
const base = await resolveBody(opts.body);
|
|
2463
|
+
const flags = {};
|
|
2464
|
+
if (opts.agentId !== void 0) flags.agentId = opts.agentId;
|
|
2465
|
+
if (opts.folderId !== void 0) {
|
|
2466
|
+
flags.folderId = opts.folderId === "null" ? null : opts.folderId;
|
|
2467
|
+
}
|
|
2468
|
+
const assignBody = mergeBodyWithFlags(base, flags);
|
|
2469
|
+
const folderId = assignBody.folderId;
|
|
2470
|
+
await client.folders.assignAgent(assignBody);
|
|
2471
|
+
if (folderId) {
|
|
2472
|
+
printSuccess("Agent assigned to folder.", {
|
|
2473
|
+
agentId: opts.agentId,
|
|
2474
|
+
folderId
|
|
2475
|
+
});
|
|
2476
|
+
} else {
|
|
2477
|
+
printSuccess("Agent removed from folder.", {
|
|
2478
|
+
agentId: opts.agentId
|
|
2479
|
+
});
|
|
2480
|
+
}
|
|
2481
|
+
} catch (err) {
|
|
2482
|
+
process.exitCode = handleError(err);
|
|
2483
|
+
}
|
|
2484
|
+
});
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
// src/commands/model.ts
|
|
2488
|
+
init_output();
|
|
2489
|
+
function registerModelCommands(program2) {
|
|
2490
|
+
const model = program2.command("model").description("Manage AI models");
|
|
2491
|
+
model.command("list").description("List available AI models").addHelpText(
|
|
2492
|
+
"after",
|
|
2493
|
+
`
|
|
2494
|
+
Examples:
|
|
2495
|
+
$ nexus model list
|
|
2496
|
+
$ nexus model list --json`
|
|
2497
|
+
).action(async () => {
|
|
2498
|
+
try {
|
|
2499
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2500
|
+
const result = await client.models.list();
|
|
2501
|
+
const items = Array.isArray(result) ? result : result.data ?? result;
|
|
2502
|
+
printList(items, void 0, [
|
|
2503
|
+
{ key: "name", label: "NAME", width: 30 },
|
|
2504
|
+
{ key: "provider", label: "PROVIDER", width: 20 },
|
|
2505
|
+
{ key: "id", label: "ID", width: 36 },
|
|
2506
|
+
{ key: "contextWindow", label: "CONTEXT", width: 12 }
|
|
2507
|
+
]);
|
|
2508
|
+
} catch (err) {
|
|
2509
|
+
process.exitCode = handleError(err);
|
|
2510
|
+
}
|
|
2511
|
+
});
|
|
2512
|
+
}
|
|
2513
|
+
|
|
2514
|
+
// src/commands/prompt-assistant.ts
|
|
2515
|
+
init_output();
|
|
2516
|
+
function registerPromptAssistantCommands(program2) {
|
|
2517
|
+
const pa = program2.command("prompt-assistant").description("AI-powered prompt writing assistant");
|
|
2518
|
+
pa.command("chat").description("Send a message to the prompt assistant").option("--message <text-or->", "Message text (or '-' for stdin)").option("--mode <mode>", "Mode: agent or ai-task").option("--thread-id <id>", "Thread ID for multi-turn conversations").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
2519
|
+
"after",
|
|
2520
|
+
`
|
|
2521
|
+
Examples:
|
|
2522
|
+
$ nexus prompt-assistant chat --message "Create a customer support agent" --mode agent
|
|
2523
|
+
$ nexus prompt-assistant chat --message "Improve the prompt" --thread-id thr-123
|
|
2524
|
+
$ echo "Write a summarization task" | nexus prompt-assistant chat --message - --mode ai-task
|
|
2525
|
+
$ nexus prompt-assistant chat --body '{"message":"Help me","mode":"agent"}'`
|
|
2526
|
+
).action(async (opts) => {
|
|
2527
|
+
try {
|
|
2528
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2529
|
+
const base = await resolveBody(opts.body);
|
|
2530
|
+
const flags = {};
|
|
2531
|
+
if (opts.mode) flags.mode = opts.mode;
|
|
2532
|
+
if (opts.threadId) flags.threadId = opts.threadId;
|
|
2533
|
+
if (opts.message) flags.message = await resolveInputValue(opts.message);
|
|
2534
|
+
const body = mergeBodyWithFlags(base, flags);
|
|
2535
|
+
const result = await client.promptAssistant.chat(body);
|
|
2536
|
+
printRecord(result);
|
|
2537
|
+
} catch (err) {
|
|
2538
|
+
process.exitCode = handleError(err);
|
|
2539
|
+
}
|
|
2540
|
+
});
|
|
2541
|
+
pa.command("get-thread").description("Get a prompt assistant thread with messages").argument("<thread-id>", "Thread ID").addHelpText(
|
|
2542
|
+
"after",
|
|
2543
|
+
`
|
|
2544
|
+
Examples:
|
|
2545
|
+
$ nexus prompt-assistant get-thread thr-123
|
|
2546
|
+
$ nexus prompt-assistant get-thread thr-123 --json`
|
|
2547
|
+
).action(async (threadId) => {
|
|
2548
|
+
try {
|
|
2549
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2550
|
+
const t = await client.promptAssistant.getThread(threadId);
|
|
2551
|
+
printRecord(t, [
|
|
2552
|
+
{ key: "id", label: "ID" },
|
|
2553
|
+
{ key: "mode", label: "Mode" },
|
|
2554
|
+
{ key: "messages", label: "Messages" },
|
|
2555
|
+
{ key: "promptResult", label: "Prompt Result" },
|
|
2556
|
+
{ key: "createdAt", label: "Created" }
|
|
2557
|
+
]);
|
|
2558
|
+
} catch (err) {
|
|
2559
|
+
process.exitCode = handleError(err);
|
|
2560
|
+
}
|
|
2561
|
+
});
|
|
2562
|
+
pa.command("delete-thread").description("Delete a prompt assistant thread").argument("<thread-id>", "Thread ID").option("--yes", "Skip confirmation").addHelpText(
|
|
2563
|
+
"after",
|
|
2564
|
+
`
|
|
2565
|
+
Examples:
|
|
2566
|
+
$ nexus prompt-assistant delete-thread thr-123
|
|
2567
|
+
$ nexus prompt-assistant delete-thread thr-123 --yes`
|
|
2568
|
+
).action(async (threadId, opts) => {
|
|
2569
|
+
try {
|
|
2570
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2571
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
2572
|
+
const readline2 = await import("readline/promises");
|
|
2573
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
2574
|
+
const answer = await rl.question(`Delete thread ${threadId}? [y/N] `);
|
|
2575
|
+
rl.close();
|
|
2576
|
+
if (answer.toLowerCase() !== "y") {
|
|
2577
|
+
console.log("Aborted.");
|
|
2578
|
+
return;
|
|
2579
|
+
}
|
|
2580
|
+
}
|
|
2581
|
+
await client.promptAssistant.deleteThread(threadId);
|
|
2582
|
+
printSuccess("Thread deleted.", { threadId });
|
|
2583
|
+
} catch (err) {
|
|
2584
|
+
process.exitCode = handleError(err);
|
|
2585
|
+
}
|
|
2586
|
+
});
|
|
2587
|
+
}
|
|
2588
|
+
|
|
2589
|
+
// src/commands/task.ts
|
|
2590
|
+
init_output();
|
|
2591
|
+
function registerTaskCommands(program2) {
|
|
2592
|
+
const task = program2.command("task").description("Manage AI tasks");
|
|
2593
|
+
task.command("list").description("List AI tasks").option("--search <query>", "Search by name").option("--limit <number>", "Max results", parseInt).addHelpText(
|
|
2594
|
+
"after",
|
|
2595
|
+
`
|
|
2596
|
+
Examples:
|
|
2597
|
+
$ nexus task list
|
|
2598
|
+
$ nexus task list --search "summarize" --limit 10
|
|
2599
|
+
$ nexus task list --json`
|
|
2600
|
+
).action(async (opts) => {
|
|
2601
|
+
try {
|
|
2602
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2603
|
+
const result = await client.skills.listTasks({
|
|
2604
|
+
search: opts.search,
|
|
2605
|
+
limit: opts.limit
|
|
2606
|
+
});
|
|
2607
|
+
const items = result.items ?? [];
|
|
2608
|
+
printTable(items, [
|
|
2609
|
+
{ key: "id", label: "ID", width: 36 },
|
|
2610
|
+
{ key: "name", label: "NAME", width: 30 },
|
|
2611
|
+
{ key: "category", label: "CATEGORY", width: 15 },
|
|
2612
|
+
{ key: "inputFormat", label: "INPUT", width: 10 },
|
|
2613
|
+
{ key: "outputFormat", label: "OUTPUT", width: 10 }
|
|
2614
|
+
]);
|
|
2615
|
+
} catch (err) {
|
|
2616
|
+
process.exitCode = handleError(err);
|
|
2617
|
+
}
|
|
2618
|
+
});
|
|
2619
|
+
task.command("get").description("Get AI task details").argument("<id>", "Task ID").addHelpText(
|
|
2620
|
+
"after",
|
|
2621
|
+
`
|
|
2622
|
+
Examples:
|
|
2623
|
+
$ nexus task get task-123
|
|
2624
|
+
$ nexus task get task-123 --json`
|
|
2625
|
+
).action(async (id) => {
|
|
2626
|
+
try {
|
|
2627
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2628
|
+
const t = await client.skills.getTask(id);
|
|
2629
|
+
printRecord(t, [
|
|
2630
|
+
{ key: "id", label: "ID" },
|
|
2631
|
+
{ key: "name", label: "Name" },
|
|
2632
|
+
{ key: "category", label: "Category" },
|
|
2633
|
+
{ key: "modelName", label: "Model" },
|
|
2634
|
+
{ key: "modelProvider", label: "Provider" },
|
|
2635
|
+
{ key: "inputFormat", label: "Input Format" },
|
|
2636
|
+
{ key: "outputFormat", label: "Output Format" }
|
|
2637
|
+
]);
|
|
2638
|
+
} catch (err) {
|
|
2639
|
+
process.exitCode = handleError(err);
|
|
2640
|
+
}
|
|
2641
|
+
});
|
|
2642
|
+
task.command("create").description("Create an AI task").requiredOption("--name <name>", "Task name").requiredOption("--model-name <model>", "Model name (e.g. gpt-4o)").requiredOption("--model-provider <provider>", "Model provider (e.g. OPEN_AI)").option("--expected-input <text>", "Description of expected input").option("--expected-output <text>", "Description of expected output").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
2643
|
+
"after",
|
|
2644
|
+
`
|
|
2645
|
+
Examples:
|
|
2646
|
+
$ nexus task create --name "Summarize Email" --model-name gpt-4o --model-provider OPEN_AI
|
|
2647
|
+
$ nexus task create --name "Classify" --model-name gpt-4o --model-provider OPEN_AI --expected-input "Raw text" --expected-output "Category label"
|
|
2648
|
+
$ nexus task create --body '{"name":"Summarize","modelName":"gpt-4o","modelProvider":"OPEN_AI"}'`
|
|
2649
|
+
).action(async (opts) => {
|
|
2650
|
+
try {
|
|
2651
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2652
|
+
const base = await resolveBody(opts.body);
|
|
2653
|
+
const flags = {};
|
|
2654
|
+
if (opts.name !== void 0) flags.name = opts.name;
|
|
2655
|
+
if (opts.modelName !== void 0) flags.modelName = opts.modelName;
|
|
2656
|
+
if (opts.modelProvider !== void 0) flags.modelProvider = opts.modelProvider;
|
|
2657
|
+
if (opts.expectedInput || opts.expectedOutput) {
|
|
2658
|
+
flags.generation = {
|
|
2659
|
+
expectedInput: opts.expectedInput,
|
|
2660
|
+
expectedOutput: opts.expectedOutput
|
|
2661
|
+
};
|
|
2662
|
+
}
|
|
2663
|
+
const body = mergeBodyWithFlags(base, flags);
|
|
2664
|
+
const t = await client.skills.createTask(body);
|
|
2665
|
+
printSuccess("Task created.", {
|
|
2666
|
+
id: t.id,
|
|
2667
|
+
name: t.name
|
|
2668
|
+
});
|
|
2669
|
+
} catch (err) {
|
|
2670
|
+
process.exitCode = handleError(err);
|
|
2671
|
+
}
|
|
2672
|
+
});
|
|
2673
|
+
task.command("execute").description("Execute an AI task").argument("<id>", "Task ID").requiredOption("--input <text-or-->", "Input text (or '-' for stdin)").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
2674
|
+
"after",
|
|
2675
|
+
`
|
|
2676
|
+
Examples:
|
|
2677
|
+
$ nexus task execute task-123 --input "Summarize this email..."
|
|
2678
|
+
$ cat document.txt | nexus task execute task-123 --input -
|
|
2679
|
+
$ nexus task execute task-123 --input "Hello world" --json
|
|
2680
|
+
$ nexus task execute task-123 --body '{"input":"Hello world"}'`
|
|
2681
|
+
).action(async (id, opts) => {
|
|
2682
|
+
try {
|
|
2683
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2684
|
+
const base = await resolveBody(opts.body);
|
|
2685
|
+
const flags = {};
|
|
2686
|
+
if (opts.input) flags.input = await resolveInputValue(opts.input);
|
|
2687
|
+
const execBody = mergeBodyWithFlags(base, flags);
|
|
2688
|
+
const result = await client.skills.executeTask(id, execBody);
|
|
2689
|
+
if (isJsonMode()) {
|
|
2690
|
+
console.log(JSON.stringify(result, null, 2));
|
|
2691
|
+
} else {
|
|
2692
|
+
console.log(result.output ?? JSON.stringify(result, null, 2));
|
|
2693
|
+
}
|
|
2694
|
+
} catch (err) {
|
|
2695
|
+
process.exitCode = handleError(err);
|
|
2696
|
+
}
|
|
2697
|
+
});
|
|
2698
|
+
}
|
|
2699
|
+
|
|
2700
|
+
// src/commands/template.ts
|
|
2701
|
+
var import_node_fs3 = __toESM(require("fs"));
|
|
2702
|
+
var import_node_path3 = __toESM(require("path"));
|
|
2703
|
+
init_output();
|
|
2704
|
+
function registerTemplateCommands(program2) {
|
|
2705
|
+
const template = program2.command("template").description("Manage document templates");
|
|
2706
|
+
template.command("list").description("List document templates").option("--search <query>", "Search by name").option("--limit <number>", "Max results", parseInt).addHelpText(
|
|
2707
|
+
"after",
|
|
2708
|
+
`
|
|
2709
|
+
Examples:
|
|
2710
|
+
$ nexus template list
|
|
2711
|
+
$ nexus template list --search "invoice" --limit 10
|
|
2712
|
+
$ nexus template list --json`
|
|
2713
|
+
).action(async (opts) => {
|
|
2714
|
+
try {
|
|
2715
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2716
|
+
const result = await client.skills.listDocumentTemplates({
|
|
2717
|
+
search: opts.search,
|
|
2718
|
+
limit: opts.limit
|
|
2719
|
+
});
|
|
2720
|
+
const items = Array.isArray(result) ? result : result.items ?? result.data ?? result;
|
|
2721
|
+
printList(items, void 0, [
|
|
2722
|
+
{ key: "id", label: "ID", width: 36 },
|
|
2723
|
+
{ key: "name", label: "NAME", width: 30 },
|
|
2724
|
+
{ key: "description", label: "DESCRIPTION", width: 40 },
|
|
2725
|
+
{ key: "createdAt", label: "CREATED", width: 26 }
|
|
2726
|
+
]);
|
|
2727
|
+
} catch (err) {
|
|
2728
|
+
process.exitCode = handleError(err);
|
|
2729
|
+
}
|
|
2730
|
+
});
|
|
2731
|
+
template.command("get").description("Get document template details").argument("<id>", "Template ID").addHelpText(
|
|
2732
|
+
"after",
|
|
2733
|
+
`
|
|
2734
|
+
Examples:
|
|
2735
|
+
$ nexus template get tmpl-123
|
|
2736
|
+
$ nexus template get tmpl-123 --json`
|
|
2737
|
+
).action(async (id) => {
|
|
2738
|
+
try {
|
|
2739
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2740
|
+
const t = await client.skills.getDocumentTemplate(id);
|
|
2741
|
+
printRecord(t, [
|
|
2742
|
+
{ key: "id", label: "ID" },
|
|
2743
|
+
{ key: "name", label: "Name" },
|
|
2744
|
+
{ key: "description", label: "Description" },
|
|
2745
|
+
{ key: "fileName", label: "File Name" },
|
|
2746
|
+
{ key: "createdAt", label: "Created" },
|
|
2747
|
+
{ key: "updatedAt", label: "Updated" }
|
|
2748
|
+
]);
|
|
2749
|
+
} catch (err) {
|
|
2750
|
+
process.exitCode = handleError(err);
|
|
2751
|
+
}
|
|
2752
|
+
});
|
|
2753
|
+
template.command("create").description("Create a document template").option("--name <name>", "Template name").option("--description <text>", "Template description").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
2754
|
+
"after",
|
|
2755
|
+
`
|
|
2756
|
+
Examples:
|
|
2757
|
+
$ nexus template create --name "Invoice Template"
|
|
2758
|
+
$ nexus template create --name "Report" --description "Monthly report template"
|
|
2759
|
+
$ nexus template create --body '{"name":"Contract","description":"Standard contract"}'`
|
|
2760
|
+
).action(async (opts) => {
|
|
2761
|
+
try {
|
|
2762
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2763
|
+
const base = await resolveBody(opts.body);
|
|
2764
|
+
const body = mergeBodyWithFlags(base, {
|
|
2765
|
+
name: opts.name,
|
|
2766
|
+
description: opts.description
|
|
2767
|
+
});
|
|
2768
|
+
const t = await client.skills.createDocumentTemplate(body);
|
|
2769
|
+
printSuccess("Template created.", {
|
|
2770
|
+
id: t.id,
|
|
2771
|
+
name: t.name
|
|
2772
|
+
});
|
|
2773
|
+
} catch (err) {
|
|
2774
|
+
process.exitCode = handleError(err);
|
|
2775
|
+
}
|
|
2776
|
+
});
|
|
2777
|
+
template.command("upload").description("Upload a file to a document template").argument("<id>", "Template ID").requiredOption("--file <path>", "Path to the template file").addHelpText(
|
|
2778
|
+
"after",
|
|
2779
|
+
`
|
|
2780
|
+
Examples:
|
|
2781
|
+
$ nexus template upload tmpl-123 --file ./invoice.docx
|
|
2782
|
+
$ nexus template upload tmpl-123 --file ./report.pdf`
|
|
2783
|
+
).action(async (id, opts) => {
|
|
2784
|
+
try {
|
|
2785
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2786
|
+
const absPath = import_node_path3.default.resolve(opts.file);
|
|
2787
|
+
if (!import_node_fs3.default.existsSync(absPath)) {
|
|
2788
|
+
console.error(`Error: File not found: ${absPath}`);
|
|
2789
|
+
process.exitCode = 1;
|
|
2790
|
+
return;
|
|
2791
|
+
}
|
|
2792
|
+
const buffer = import_node_fs3.default.readFileSync(absPath);
|
|
2793
|
+
const blob = new Blob([buffer]);
|
|
2794
|
+
const fileName = import_node_path3.default.basename(absPath);
|
|
2795
|
+
const result = await client.skills.uploadDocumentTemplateFile(id, blob, fileName);
|
|
2796
|
+
printSuccess("File uploaded to template.", {
|
|
2797
|
+
templateId: id,
|
|
2798
|
+
fileName
|
|
2799
|
+
});
|
|
2800
|
+
} catch (err) {
|
|
2801
|
+
process.exitCode = handleError(err);
|
|
2802
|
+
}
|
|
2803
|
+
});
|
|
2804
|
+
template.command("generate").description("Generate a document from a template").argument("<id>", "Template ID").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
2805
|
+
"after",
|
|
2806
|
+
`
|
|
2807
|
+
Examples:
|
|
2808
|
+
$ nexus template generate tmpl-123 --body '{"variables":{"name":"Acme Corp","date":"2026-01-01"}}'
|
|
2809
|
+
$ nexus template generate tmpl-123 --body variables.json
|
|
2810
|
+
$ nexus template generate tmpl-123 --body '{"variables":{"amount":100}}' --json`
|
|
2811
|
+
).action(async (id, opts) => {
|
|
2812
|
+
try {
|
|
2813
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2814
|
+
const body = await resolveBody(opts.body);
|
|
2815
|
+
const result = await client.skills.generateDocumentTemplate(id, body);
|
|
2816
|
+
printRecord(result);
|
|
2817
|
+
} catch (err) {
|
|
2818
|
+
process.exitCode = handleError(err);
|
|
2819
|
+
}
|
|
2820
|
+
});
|
|
2821
|
+
}
|
|
2822
|
+
|
|
2823
|
+
// src/commands/ticket.ts
|
|
2824
|
+
init_output();
|
|
2825
|
+
function registerTicketCommands(program2) {
|
|
2826
|
+
const ticket = program2.command("ticket").description("Manage tickets (bugs, feature requests, improvements)");
|
|
2827
|
+
addPaginationOptions(
|
|
2828
|
+
ticket.command("list").description("List tickets").option("--type <type>", "Filter by type (BUG, FEATURE_REQUEST, IMPROVEMENT)").option("--priority <priority>", "Filter by priority (NONE, URGENT, HIGH, MEDIUM, LOW)").option("--status <status>", "Filter by status").option("--search <query>", "Search by title or description").addHelpText(
|
|
2829
|
+
"after",
|
|
2830
|
+
`
|
|
2831
|
+
Examples:
|
|
2832
|
+
$ nexus ticket list
|
|
2833
|
+
$ nexus ticket list --type BUG --priority HIGH
|
|
2834
|
+
$ nexus ticket list --search "login" --json`
|
|
2835
|
+
)
|
|
2836
|
+
).action(async (opts) => {
|
|
2837
|
+
try {
|
|
2838
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2839
|
+
const { data, meta } = await client.tickets.list({
|
|
2840
|
+
...getPaginationParams(opts),
|
|
2841
|
+
type: opts.type,
|
|
2842
|
+
priority: opts.priority,
|
|
2843
|
+
status: opts.status,
|
|
2844
|
+
search: opts.search
|
|
2845
|
+
});
|
|
2846
|
+
printList(
|
|
2847
|
+
data,
|
|
2848
|
+
meta,
|
|
2849
|
+
[
|
|
2850
|
+
{ key: "identifier", label: "IDENTIFIER", width: 12 },
|
|
2851
|
+
{ key: "title", label: "TITLE", width: 40 },
|
|
2852
|
+
{ key: "type", label: "TYPE", width: 18 },
|
|
2853
|
+
{ key: "priority", label: "PRIORITY", width: 10 },
|
|
2854
|
+
{ key: "status", label: "STATUS", width: 15 }
|
|
2855
|
+
]
|
|
2856
|
+
);
|
|
2857
|
+
} catch (err) {
|
|
2858
|
+
process.exitCode = handleError(err);
|
|
2859
|
+
}
|
|
2860
|
+
});
|
|
2861
|
+
ticket.command("get").description("Get ticket details").argument("<id>", "Ticket ID or identifier").addHelpText(
|
|
2862
|
+
"after",
|
|
2863
|
+
`
|
|
2864
|
+
Examples:
|
|
2865
|
+
$ nexus ticket get TKT-42
|
|
2866
|
+
$ nexus ticket get TKT-42 --json`
|
|
2867
|
+
).action(async (id) => {
|
|
2868
|
+
try {
|
|
2869
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2870
|
+
const t = await client.tickets.get(id);
|
|
2871
|
+
printRecord(t, [
|
|
2872
|
+
{ key: "id", label: "ID" },
|
|
2873
|
+
{ key: "identifier", label: "Identifier" },
|
|
2874
|
+
{ key: "title", label: "Title" },
|
|
2875
|
+
{ key: "type", label: "Type" },
|
|
2876
|
+
{ key: "priority", label: "Priority" },
|
|
2877
|
+
{ key: "status", label: "Status" },
|
|
2878
|
+
{ key: "url", label: "URL" },
|
|
2879
|
+
{ key: "description", label: "Description" },
|
|
2880
|
+
{ key: "createdAt", label: "Created" },
|
|
2881
|
+
{ key: "updatedAt", label: "Updated" }
|
|
2882
|
+
]);
|
|
2883
|
+
} catch (err) {
|
|
2884
|
+
process.exitCode = handleError(err);
|
|
2885
|
+
}
|
|
2886
|
+
});
|
|
2887
|
+
ticket.command("create").description("Create a new ticket").requiredOption("--title <title>", "Ticket title").option("--type <type>", "Ticket type (BUG, FEATURE_REQUEST, IMPROVEMENT)").option("--priority <priority>", "Priority (NONE, URGENT, HIGH, MEDIUM, LOW)").option("--description <text>", "Ticket description").option("--data <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
2888
|
+
"after",
|
|
2889
|
+
`
|
|
2890
|
+
Examples:
|
|
2891
|
+
$ nexus ticket create --title "Login fails with SSO"
|
|
2892
|
+
$ nexus ticket create --title "Add dark mode" --type FEATURE_REQUEST --priority MEDIUM
|
|
2893
|
+
$ nexus ticket create --title "Bug report" --type BUG --description "Steps to reproduce..."
|
|
2894
|
+
$ nexus ticket create --data '{"title":"Bug","type":"BUG"}'`
|
|
2895
|
+
).action(async (opts) => {
|
|
2896
|
+
try {
|
|
2897
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2898
|
+
const base = await resolveBody(opts.data);
|
|
2899
|
+
const body = mergeBodyWithFlags(base, {
|
|
2900
|
+
...opts.title !== void 0 && { title: opts.title },
|
|
2901
|
+
...opts.type !== void 0 && { type: opts.type },
|
|
2902
|
+
...opts.priority !== void 0 && { priority: opts.priority },
|
|
2903
|
+
...opts.description !== void 0 && { description: opts.description }
|
|
2904
|
+
});
|
|
2905
|
+
const t = await client.tickets.create(body);
|
|
2906
|
+
printRecord(t, [
|
|
2907
|
+
{ key: "id", label: "ID" },
|
|
2908
|
+
{ key: "identifier", label: "Identifier" },
|
|
2909
|
+
{ key: "title", label: "Title" },
|
|
2910
|
+
{ key: "type", label: "Type" },
|
|
2911
|
+
{ key: "priority", label: "Priority" },
|
|
2912
|
+
{ key: "status", label: "Status" },
|
|
2913
|
+
{ key: "url", label: "URL" }
|
|
2914
|
+
]);
|
|
2915
|
+
} catch (err) {
|
|
2916
|
+
process.exitCode = handleError(err);
|
|
2917
|
+
}
|
|
2918
|
+
});
|
|
2919
|
+
ticket.command("update").description("Update a ticket").argument("<id>", "Ticket ID or identifier").option("--title <title>", "Updated title").option("--type <type>", "Updated type (BUG, FEATURE_REQUEST, IMPROVEMENT)").option("--priority <priority>", "Updated priority (NONE, URGENT, HIGH, MEDIUM, LOW)").option("--description <text>", "Updated description").option("--data <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
2920
|
+
"after",
|
|
2921
|
+
`
|
|
2922
|
+
Examples:
|
|
2923
|
+
$ nexus ticket update TKT-42 --priority URGENT
|
|
2924
|
+
$ nexus ticket update TKT-42 --title "Updated title" --type BUG
|
|
2925
|
+
$ nexus ticket update TKT-42 --data '{"priority":"URGENT"}'`
|
|
2926
|
+
).action(async (id, opts) => {
|
|
2927
|
+
try {
|
|
2928
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2929
|
+
const base = await resolveBody(opts.data);
|
|
2930
|
+
const body = mergeBodyWithFlags(base, {
|
|
2931
|
+
...opts.title !== void 0 && { title: opts.title },
|
|
2932
|
+
...opts.type !== void 0 && { type: opts.type },
|
|
2933
|
+
...opts.priority !== void 0 && { priority: opts.priority },
|
|
2934
|
+
...opts.description !== void 0 && { description: opts.description }
|
|
2935
|
+
});
|
|
2936
|
+
const t = await client.tickets.update(id, body);
|
|
2937
|
+
printRecord(t, [
|
|
2938
|
+
{ key: "id", label: "ID" },
|
|
2939
|
+
{ key: "identifier", label: "Identifier" },
|
|
2940
|
+
{ key: "title", label: "Title" },
|
|
2941
|
+
{ key: "type", label: "Type" },
|
|
2942
|
+
{ key: "priority", label: "Priority" },
|
|
2943
|
+
{ key: "status", label: "Status" },
|
|
2944
|
+
{ key: "url", label: "URL" }
|
|
2945
|
+
]);
|
|
2946
|
+
} catch (err) {
|
|
2947
|
+
process.exitCode = handleError(err);
|
|
2948
|
+
}
|
|
2949
|
+
});
|
|
2950
|
+
ticket.command("comment").description("Add a comment to a ticket").argument("<id>", "Ticket ID or identifier").requiredOption("--body <text-or-->", "Comment body (text or '-' for stdin)").addHelpText(
|
|
2951
|
+
"after",
|
|
2952
|
+
`
|
|
2953
|
+
Examples:
|
|
2954
|
+
$ nexus ticket comment TKT-42 --body "This is fixed in v2.1"
|
|
2955
|
+
$ echo "Detailed comment" | nexus ticket comment TKT-42 --body -`
|
|
2956
|
+
).action(async (id, opts) => {
|
|
2957
|
+
try {
|
|
2958
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2959
|
+
const body = await resolveInputValue(opts.body);
|
|
2960
|
+
await client.tickets.addComment(id, { body });
|
|
2961
|
+
printSuccess("Comment added.", { ticketId: id });
|
|
2962
|
+
} catch (err) {
|
|
2963
|
+
process.exitCode = handleError(err);
|
|
2964
|
+
}
|
|
2965
|
+
});
|
|
2966
|
+
ticket.command("comments").description("List comments on a ticket").argument("<id>", "Ticket ID or identifier").addHelpText(
|
|
2967
|
+
"after",
|
|
2968
|
+
`
|
|
2969
|
+
Examples:
|
|
2970
|
+
$ nexus ticket comments TKT-42
|
|
2971
|
+
$ nexus ticket comments TKT-42 --json`
|
|
2972
|
+
).action(async (id) => {
|
|
2973
|
+
try {
|
|
2974
|
+
const client = createClient(program2.optsWithGlobals());
|
|
2975
|
+
const result = await client.tickets.listComments(id);
|
|
2976
|
+
const comments = result.comments ?? result;
|
|
2977
|
+
printList(comments, void 0, [
|
|
2978
|
+
{ key: "id", label: "ID", width: 36 },
|
|
2979
|
+
{ key: "authorName", label: "AUTHOR", width: 20 },
|
|
2980
|
+
{ key: "body", label: "BODY", width: 50 },
|
|
2981
|
+
{ key: "createdAt", label: "CREATED", width: 20 }
|
|
2982
|
+
]);
|
|
2983
|
+
} catch (err) {
|
|
2984
|
+
process.exitCode = handleError(err);
|
|
2985
|
+
}
|
|
2986
|
+
});
|
|
2987
|
+
}
|
|
2988
|
+
|
|
2989
|
+
// src/commands/tool.ts
|
|
2990
|
+
init_output();
|
|
2991
|
+
function registerToolCommands(program2) {
|
|
2992
|
+
const tool = program2.command("tool").description("Discover and manage marketplace tools");
|
|
2993
|
+
tool.command("search").description("Search marketplace tools").option("--query <query>", "Search query").option("--category <category>", "Filter by category").option("--type <type>", "Filter by type").option("--limit <number>", "Max results", parseInt).addHelpText(
|
|
2994
|
+
"after",
|
|
2995
|
+
`
|
|
2996
|
+
Examples:
|
|
2997
|
+
$ nexus tool search --query "gmail"
|
|
2998
|
+
$ nexus tool search --category "Communication" --limit 10
|
|
2999
|
+
$ nexus tool search --query "slack" --json`
|
|
3000
|
+
).action(async (opts) => {
|
|
3001
|
+
try {
|
|
3002
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3003
|
+
const result = await client.tools.search({
|
|
3004
|
+
q: opts.query,
|
|
3005
|
+
category: opts.category,
|
|
3006
|
+
type: opts.type,
|
|
3007
|
+
limit: opts.limit
|
|
3008
|
+
});
|
|
3009
|
+
const tools = result.tools ?? [];
|
|
3010
|
+
printTable(tools, [
|
|
3011
|
+
{ key: "id", label: "ID", width: 36 },
|
|
3012
|
+
{ key: "name", label: "NAME", width: 25 },
|
|
3013
|
+
{ key: "type", label: "TYPE", width: 12 },
|
|
3014
|
+
{ key: "description", label: "DESCRIPTION", width: 40 }
|
|
3015
|
+
]);
|
|
3016
|
+
} catch (err) {
|
|
3017
|
+
process.exitCode = handleError(err);
|
|
3018
|
+
}
|
|
3019
|
+
});
|
|
3020
|
+
tool.command("get").description("Get marketplace tool details").argument("<id>", "Tool ID").addHelpText(
|
|
3021
|
+
"after",
|
|
3022
|
+
`
|
|
3023
|
+
Examples:
|
|
3024
|
+
$ nexus tool get tool-123
|
|
3025
|
+
$ nexus tool get tool-123 --json`
|
|
3026
|
+
).action(async (id) => {
|
|
3027
|
+
try {
|
|
3028
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3029
|
+
const detail = await client.tools.get(id);
|
|
3030
|
+
printRecord(detail);
|
|
3031
|
+
} catch (err) {
|
|
3032
|
+
process.exitCode = handleError(err);
|
|
3033
|
+
}
|
|
3034
|
+
});
|
|
3035
|
+
tool.command("credentials").description("List credentials for a marketplace tool").argument("<id>", "Tool ID").addHelpText(
|
|
3036
|
+
"after",
|
|
3037
|
+
`
|
|
3038
|
+
Examples:
|
|
3039
|
+
$ nexus tool credentials tool-123
|
|
3040
|
+
$ nexus tool credentials tool-123 --json`
|
|
3041
|
+
).action(async (id) => {
|
|
3042
|
+
try {
|
|
3043
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3044
|
+
const result = await client.tools.credentials(id);
|
|
3045
|
+
const creds = result.credentials ?? [];
|
|
3046
|
+
printTable(creds, [
|
|
3047
|
+
{ key: "id", label: "ID", width: 36 },
|
|
3048
|
+
{ key: "name", label: "NAME", width: 25 },
|
|
3049
|
+
{ key: "type", label: "TYPE", width: 12 },
|
|
3050
|
+
{ key: "createdAt", label: "CREATED", width: 20 }
|
|
3051
|
+
]);
|
|
3052
|
+
} catch (err) {
|
|
3053
|
+
process.exitCode = handleError(err);
|
|
3054
|
+
}
|
|
3055
|
+
});
|
|
3056
|
+
tool.command("connect").description("Connect a tool via OAuth or HTTP credentials").argument("<id>", "Tool ID").option("--auth-type <type>", "Auth type: oauth or http", "oauth").option("--api-key-value <key>", "API key for HTTP auth").option("--auth-header <header>", "Authorization header type for HTTP auth", "bearer").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
3057
|
+
"after",
|
|
3058
|
+
`
|
|
3059
|
+
Examples:
|
|
3060
|
+
$ nexus tool connect tool-123
|
|
3061
|
+
$ nexus tool connect tool-123 --auth-type http --api-key-value sk-abc123
|
|
3062
|
+
$ nexus tool connect tool-123 --body '{"authType":"http","apiKey":"sk-abc"}'`
|
|
3063
|
+
).action(async (id, opts) => {
|
|
3064
|
+
try {
|
|
3065
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3066
|
+
const base = await resolveBody(opts.body);
|
|
3067
|
+
if (base) {
|
|
3068
|
+
const flags = {};
|
|
3069
|
+
if (opts.authType !== void 0) flags.authType = opts.authType;
|
|
3070
|
+
if (opts.apiKeyValue !== void 0) flags.apiKey = opts.apiKeyValue;
|
|
3071
|
+
if (opts.authHeader !== void 0) flags.authorizationType = opts.authHeader;
|
|
3072
|
+
const body = mergeBodyWithFlags(base, flags);
|
|
3073
|
+
const result = await client.toolConnection.connect(id, body);
|
|
3074
|
+
printSuccess("Tool connected.", result);
|
|
3075
|
+
} else if (opts.authType === "http") {
|
|
3076
|
+
if (!opts.apiKeyValue) {
|
|
3077
|
+
console.error(
|
|
3078
|
+
"Error: --api-key-value is required for HTTP auth.\n nexus tool connect <id> --auth-type http --api-key-value <key>"
|
|
3079
|
+
);
|
|
3080
|
+
process.exitCode = 1;
|
|
3081
|
+
return;
|
|
3082
|
+
}
|
|
3083
|
+
const result = await client.toolConnection.connect(id, {
|
|
3084
|
+
authType: "http",
|
|
3085
|
+
apiKey: opts.apiKeyValue,
|
|
3086
|
+
authorizationType: opts.authHeader
|
|
3087
|
+
});
|
|
3088
|
+
printSuccess("Tool connected via HTTP.", result);
|
|
3089
|
+
} else {
|
|
3090
|
+
const result = await client.toolConnection.connect(id, {
|
|
3091
|
+
authType: "oauth"
|
|
3092
|
+
});
|
|
3093
|
+
printSuccess("OAuth flow initiated.", result);
|
|
3094
|
+
}
|
|
3095
|
+
} catch (err) {
|
|
3096
|
+
process.exitCode = handleError(err);
|
|
3097
|
+
}
|
|
3098
|
+
});
|
|
3099
|
+
}
|
|
3100
|
+
|
|
3101
|
+
// src/commands/version.ts
|
|
3102
|
+
init_output();
|
|
3103
|
+
function registerVersionCommands(program2) {
|
|
3104
|
+
const version = program2.command("version").description("Manage agent prompt versions");
|
|
3105
|
+
addPaginationOptions(
|
|
3106
|
+
version.command("list").description("List prompt versions for an agent").argument("<agent-id>", "Agent ID").option("--type <type>", "Filter by type (AUTO, CHECKPOINT)").addHelpText(
|
|
3107
|
+
"after",
|
|
3108
|
+
`
|
|
3109
|
+
Examples:
|
|
3110
|
+
$ nexus version list agt-123
|
|
3111
|
+
$ nexus version list agt-123 --type CHECKPOINT
|
|
3112
|
+
$ nexus version list agt-123 --limit 5 --json`
|
|
3113
|
+
)
|
|
3114
|
+
).action(async (agentId, opts) => {
|
|
3115
|
+
try {
|
|
3116
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3117
|
+
const { data, meta } = await client.agents.versions.list(agentId, {
|
|
3118
|
+
...getPaginationParams(opts),
|
|
3119
|
+
type: opts.type
|
|
3120
|
+
});
|
|
3121
|
+
printList(
|
|
3122
|
+
data,
|
|
3123
|
+
meta,
|
|
3124
|
+
[
|
|
3125
|
+
{ key: "id", label: "ID", width: 36 },
|
|
3126
|
+
{ key: "name", label: "NAME", width: 25 },
|
|
3127
|
+
{ key: "type", label: "TYPE", width: 12 },
|
|
3128
|
+
{ key: "isProduction", label: "PROD", width: 6, format: (v) => v ? "yes" : "no" },
|
|
3129
|
+
{ key: "createdAt", label: "CREATED", width: 20 }
|
|
3130
|
+
]
|
|
3131
|
+
);
|
|
3132
|
+
} catch (err) {
|
|
3133
|
+
process.exitCode = handleError(err);
|
|
3134
|
+
}
|
|
3135
|
+
});
|
|
3136
|
+
version.command("get").description("Get version details with full prompt").argument("<agent-id>", "Agent ID").argument("<version-id>", "Version ID").addHelpText(
|
|
3137
|
+
"after",
|
|
3138
|
+
`
|
|
3139
|
+
Examples:
|
|
3140
|
+
$ nexus version get agt-123 ver-456
|
|
3141
|
+
$ nexus version get agt-123 ver-456 --json`
|
|
3142
|
+
).action(async (agentId, versionId) => {
|
|
3143
|
+
try {
|
|
3144
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3145
|
+
const ver = await client.agents.versions.get(agentId, versionId);
|
|
3146
|
+
printRecord(ver, [
|
|
3147
|
+
{ key: "id", label: "ID" },
|
|
3148
|
+
{ key: "name", label: "Name" },
|
|
3149
|
+
{ key: "type", label: "Type" },
|
|
3150
|
+
{ key: "isProduction", label: "Production", format: (v) => v ? "yes" : "no" },
|
|
3151
|
+
{ key: "prompt", label: "Prompt" },
|
|
3152
|
+
{ key: "createdAt", label: "Created" }
|
|
3153
|
+
]);
|
|
3154
|
+
} catch (err) {
|
|
3155
|
+
process.exitCode = handleError(err);
|
|
3156
|
+
}
|
|
3157
|
+
});
|
|
3158
|
+
version.command("create").description("Create a named checkpoint of the current prompt").argument("<agent-id>", "Agent ID").option("--name <name>", "Checkpoint name").option("--description <text>", "Checkpoint description").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
3159
|
+
"after",
|
|
3160
|
+
`
|
|
3161
|
+
Examples:
|
|
3162
|
+
$ nexus version create agt-123
|
|
3163
|
+
$ nexus version create agt-123 --name "v1.0" --description "Initial release"
|
|
3164
|
+
$ nexus version create agt-123 --body '{"name":"v1.0"}'`
|
|
3165
|
+
).action(async (agentId, opts) => {
|
|
3166
|
+
try {
|
|
3167
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3168
|
+
const base = await resolveBody(opts.body);
|
|
3169
|
+
const body = mergeBodyWithFlags(base, {
|
|
3170
|
+
...opts.name !== void 0 && { name: opts.name },
|
|
3171
|
+
...opts.description !== void 0 && { description: opts.description }
|
|
3172
|
+
});
|
|
3173
|
+
const ver = await client.agents.versions.createCheckpoint(agentId, body);
|
|
3174
|
+
printSuccess("Checkpoint created.", {
|
|
3175
|
+
id: ver.id,
|
|
3176
|
+
name: ver.name ?? "(unnamed)"
|
|
3177
|
+
});
|
|
3178
|
+
} catch (err) {
|
|
3179
|
+
process.exitCode = handleError(err);
|
|
3180
|
+
}
|
|
3181
|
+
});
|
|
3182
|
+
version.command("update").description("Update version metadata").argument("<agent-id>", "Agent ID").argument("<version-id>", "Version ID").option("--name <name>", "New name").option("--description <text>", "New description").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
3183
|
+
"after",
|
|
3184
|
+
`
|
|
3185
|
+
Examples:
|
|
3186
|
+
$ nexus version update agt-123 ver-456 --name "v1.1"
|
|
3187
|
+
$ nexus version update agt-123 ver-456 --body '{"name":"v1.1"}'`
|
|
3188
|
+
).action(async (agentId, versionId, opts) => {
|
|
3189
|
+
try {
|
|
3190
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3191
|
+
const base = await resolveBody(opts.body);
|
|
3192
|
+
const body = mergeBodyWithFlags(base, {
|
|
3193
|
+
...opts.name !== void 0 && { name: opts.name },
|
|
3194
|
+
...opts.description !== void 0 && { description: opts.description }
|
|
3195
|
+
});
|
|
3196
|
+
await client.agents.versions.update(agentId, versionId, body);
|
|
3197
|
+
printSuccess("Version updated.", { id: versionId });
|
|
3198
|
+
} catch (err) {
|
|
3199
|
+
process.exitCode = handleError(err);
|
|
3200
|
+
}
|
|
3201
|
+
});
|
|
3202
|
+
version.command("delete").description("Delete a prompt version").argument("<agent-id>", "Agent ID").argument("<version-id>", "Version ID").option("--yes", "Skip confirmation").addHelpText(
|
|
3203
|
+
"after",
|
|
3204
|
+
`
|
|
3205
|
+
Examples:
|
|
3206
|
+
$ nexus version delete agt-123 ver-456
|
|
3207
|
+
$ nexus version delete agt-123 ver-456 --yes`
|
|
3208
|
+
).action(async (agentId, versionId, opts) => {
|
|
3209
|
+
try {
|
|
3210
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3211
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
3212
|
+
const readline2 = await import("readline/promises");
|
|
3213
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
3214
|
+
const answer = await rl.question(`Delete version ${versionId}? [y/N] `);
|
|
3215
|
+
rl.close();
|
|
3216
|
+
if (answer.toLowerCase() !== "y") {
|
|
3217
|
+
console.log("Aborted.");
|
|
3218
|
+
return;
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3221
|
+
await client.agents.versions.delete(agentId, versionId);
|
|
3222
|
+
printSuccess("Version deleted.", { id: versionId });
|
|
3223
|
+
} catch (err) {
|
|
3224
|
+
process.exitCode = handleError(err);
|
|
3225
|
+
}
|
|
3226
|
+
});
|
|
3227
|
+
version.command("restore").description("Restore agent prompt to a previous version").argument("<agent-id>", "Agent ID").argument("<version-id>", "Version ID to restore").option("--yes", "Skip confirmation").addHelpText(
|
|
3228
|
+
"after",
|
|
3229
|
+
`
|
|
3230
|
+
Examples:
|
|
3231
|
+
$ nexus version restore agt-123 ver-456
|
|
3232
|
+
$ nexus version restore agt-123 ver-456 --yes`
|
|
3233
|
+
).action(async (agentId, versionId, opts) => {
|
|
3234
|
+
try {
|
|
3235
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3236
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
3237
|
+
const readline2 = await import("readline/promises");
|
|
3238
|
+
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
3239
|
+
const answer = await rl.question(
|
|
3240
|
+
`Restore agent ${agentId} to version ${versionId}? This will overwrite the current prompt. [y/N] `
|
|
3241
|
+
);
|
|
3242
|
+
rl.close();
|
|
3243
|
+
if (answer.toLowerCase() !== "y") {
|
|
3244
|
+
console.log("Aborted.");
|
|
3245
|
+
return;
|
|
3246
|
+
}
|
|
3247
|
+
}
|
|
3248
|
+
const result = await client.agents.versions.restore(agentId, versionId);
|
|
3249
|
+
printSuccess("Version restored.", { agentId, versionId, ...result });
|
|
3250
|
+
} catch (err) {
|
|
3251
|
+
process.exitCode = handleError(err);
|
|
3252
|
+
}
|
|
3253
|
+
});
|
|
3254
|
+
version.command("publish").description("Publish a version to production").argument("<agent-id>", "Agent ID").argument("<version-id>", "Version ID to publish").addHelpText(
|
|
3255
|
+
"after",
|
|
3256
|
+
`
|
|
3257
|
+
Examples:
|
|
3258
|
+
$ nexus version publish agt-123 ver-456`
|
|
3259
|
+
).action(async (agentId, versionId) => {
|
|
3260
|
+
try {
|
|
3261
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3262
|
+
const result = await client.agents.versions.publish(agentId, versionId);
|
|
3263
|
+
printSuccess("Version published to production.", {
|
|
3264
|
+
id: result.id,
|
|
3265
|
+
isProduction: "true"
|
|
3266
|
+
});
|
|
3267
|
+
} catch (err) {
|
|
3268
|
+
process.exitCode = handleError(err);
|
|
3269
|
+
}
|
|
3270
|
+
});
|
|
3271
|
+
}
|
|
3272
|
+
|
|
3273
|
+
// src/commands/workflow.ts
|
|
3274
|
+
init_output();
|
|
3275
|
+
|
|
3276
|
+
// src/commands/workflow-builder.ts
|
|
3277
|
+
init_output();
|
|
3278
|
+
function registerWorkflowBuilderCommands(workflow, program2) {
|
|
3279
|
+
const node = workflow.command("node").description("Manage workflow nodes");
|
|
3280
|
+
node.command("create").description("Create a node in a workflow").argument("<wf-id>", "Workflow ID").requiredOption("--type <type>", "Node type").option("--body <json-or-file-or-->", "Additional body JSON (merged with --type)").addHelpText(
|
|
3281
|
+
"after",
|
|
3282
|
+
`
|
|
3283
|
+
Examples:
|
|
3284
|
+
$ nexus workflow node create wf-123 --type action
|
|
3285
|
+
$ nexus workflow node create wf-123 --type condition --body '{"position":{"x":100,"y":200}}'
|
|
3286
|
+
$ nexus workflow node create wf-123 --type action --body payload.json`
|
|
3287
|
+
).action(async (wfId, opts) => {
|
|
3288
|
+
try {
|
|
3289
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3290
|
+
const extra = await resolveBody(opts.body);
|
|
3291
|
+
const body = mergeBodyWithFlags(extra, { type: opts.type });
|
|
3292
|
+
const result = await client.workflows.createNode(wfId, body);
|
|
3293
|
+
printRecord(result, [
|
|
3294
|
+
{ key: "id", label: "ID" },
|
|
3295
|
+
{ key: "type", label: "Type" },
|
|
3296
|
+
{ key: "position", label: "Position" }
|
|
3297
|
+
]);
|
|
3298
|
+
} catch (err) {
|
|
3299
|
+
process.exitCode = handleError(err);
|
|
3300
|
+
}
|
|
3301
|
+
});
|
|
3302
|
+
node.command("get").description("Get node details").argument("<wf-id>", "Workflow ID").argument("<node-id>", "Node ID").addHelpText(
|
|
3303
|
+
"after",
|
|
3304
|
+
`
|
|
3305
|
+
Examples:
|
|
3306
|
+
$ nexus workflow node get wf-123 node-456
|
|
3307
|
+
$ nexus workflow node get wf-123 node-456 --json`
|
|
3308
|
+
).action(async (wfId, nodeId) => {
|
|
3309
|
+
try {
|
|
3310
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3311
|
+
const result = await client.workflows.getNode(wfId, nodeId);
|
|
3312
|
+
printRecord(result);
|
|
3313
|
+
} catch (err) {
|
|
3314
|
+
process.exitCode = handleError(err);
|
|
3315
|
+
}
|
|
3316
|
+
});
|
|
3317
|
+
node.command("update").description("Update node data/config").argument("<wf-id>", "Workflow ID").argument("<node-id>", "Node ID").requiredOption("--body <json-or-file-or-->", "Node data/config JSON").addHelpText(
|
|
3318
|
+
"after",
|
|
3319
|
+
`
|
|
3320
|
+
Examples:
|
|
3321
|
+
$ nexus workflow node update wf-123 node-456 --body '{"data":{"message":"hello"}}'
|
|
3322
|
+
$ nexus workflow node update wf-123 node-456 --body config.json
|
|
3323
|
+
$ echo '{"data":{"key":"val"}}' | nexus workflow node update wf-123 node-456 --body -`
|
|
3324
|
+
).action(async (wfId, nodeId, opts) => {
|
|
3325
|
+
try {
|
|
3326
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3327
|
+
const body = await resolveBody(opts.body);
|
|
3328
|
+
const result = await client.workflows.updateNode(wfId, nodeId, body);
|
|
3329
|
+
printRecord(result);
|
|
3330
|
+
} catch (err) {
|
|
3331
|
+
process.exitCode = handleError(err);
|
|
3332
|
+
}
|
|
3333
|
+
});
|
|
3334
|
+
node.command("delete").description("Delete a node from a workflow").argument("<wf-id>", "Workflow ID").argument("<node-id>", "Node ID").option("--yes", "Skip confirmation").addHelpText(
|
|
3335
|
+
"after",
|
|
3336
|
+
`
|
|
3337
|
+
Examples:
|
|
3338
|
+
$ nexus workflow node delete wf-123 node-456
|
|
3339
|
+
$ nexus workflow node delete wf-123 node-456 --yes`
|
|
3340
|
+
).action(async (wfId, nodeId, opts) => {
|
|
3341
|
+
try {
|
|
3342
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3343
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
3344
|
+
const readline2 = await import("readline/promises");
|
|
3345
|
+
const rl = readline2.createInterface({
|
|
3346
|
+
input: process.stdin,
|
|
3347
|
+
output: process.stdout
|
|
3348
|
+
});
|
|
3349
|
+
const answer = await rl.question(`Delete node ${nodeId} from workflow ${wfId}? [y/N] `);
|
|
3350
|
+
rl.close();
|
|
3351
|
+
if (answer.toLowerCase() !== "y") {
|
|
3352
|
+
console.log("Aborted.");
|
|
3353
|
+
return;
|
|
3354
|
+
}
|
|
3355
|
+
}
|
|
3356
|
+
await client.workflows.deleteNode(wfId, nodeId);
|
|
3357
|
+
printSuccess("Node deleted.", { workflowId: wfId, nodeId });
|
|
3358
|
+
} catch (err) {
|
|
3359
|
+
process.exitCode = handleError(err);
|
|
3360
|
+
}
|
|
3361
|
+
});
|
|
3362
|
+
node.command("test").description("Run a test execution of a single node").argument("<wf-id>", "Workflow ID").argument("<node-id>", "Node ID").option("--body <json-or-file-or-->", "Optional mock data JSON").addHelpText(
|
|
3363
|
+
"after",
|
|
3364
|
+
`
|
|
3365
|
+
Examples:
|
|
3366
|
+
$ nexus workflow node test wf-123 node-456
|
|
3367
|
+
$ nexus workflow node test wf-123 node-456 --body '{"input":"test"}'`
|
|
3368
|
+
).action(async (wfId, nodeId, opts) => {
|
|
3369
|
+
try {
|
|
3370
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3371
|
+
const body = await resolveBody(opts.body);
|
|
3372
|
+
const result = await client.workflows.testNode(wfId, nodeId, body);
|
|
3373
|
+
printRecord(result);
|
|
3374
|
+
} catch (err) {
|
|
3375
|
+
process.exitCode = handleError(err);
|
|
3376
|
+
}
|
|
3377
|
+
});
|
|
3378
|
+
node.command("variables").description("List available upstream variables for a node").argument("<wf-id>", "Workflow ID").argument("<node-id>", "Node ID").addHelpText(
|
|
3379
|
+
"after",
|
|
3380
|
+
`
|
|
3381
|
+
Examples:
|
|
3382
|
+
$ nexus workflow node variables wf-123 node-456
|
|
3383
|
+
$ nexus workflow node variables wf-123 node-456 --json`
|
|
3384
|
+
).action(async (wfId, nodeId) => {
|
|
3385
|
+
try {
|
|
3386
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3387
|
+
const result = await client.workflows.getAvailableVariables(wfId, nodeId);
|
|
3388
|
+
printRecord(result);
|
|
3389
|
+
} catch (err) {
|
|
3390
|
+
process.exitCode = handleError(err);
|
|
3391
|
+
}
|
|
3392
|
+
});
|
|
3393
|
+
node.command("output-format").description("Show node output schema").argument("<wf-id>", "Workflow ID").argument("<node-id>", "Node ID").addHelpText(
|
|
3394
|
+
"after",
|
|
3395
|
+
`
|
|
3396
|
+
Examples:
|
|
3397
|
+
$ nexus workflow node output-format wf-123 node-456
|
|
3398
|
+
$ nexus workflow node output-format wf-123 node-456 --json`
|
|
3399
|
+
).action(async (wfId, nodeId) => {
|
|
3400
|
+
try {
|
|
3401
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3402
|
+
const result = await client.workflows.getOutputFormat(wfId, nodeId);
|
|
3403
|
+
printRecord(result);
|
|
3404
|
+
} catch (err) {
|
|
3405
|
+
process.exitCode = handleError(err);
|
|
3406
|
+
}
|
|
3407
|
+
});
|
|
3408
|
+
node.command("reload-props").description("Reload dynamic props for a Pipedream node").argument("<wf-id>", "Workflow ID").argument("<node-id>", "Node ID").requiredOption("--body <json-or-file-or-->", "Configured props JSON").addHelpText(
|
|
3409
|
+
"after",
|
|
3410
|
+
`
|
|
3411
|
+
Examples:
|
|
3412
|
+
$ nexus workflow node reload-props wf-123 node-456 --body '{"configuredProps":{"account":"acc-1"}}'
|
|
3413
|
+
$ nexus workflow node reload-props wf-123 node-456 --body props.json`
|
|
3414
|
+
).action(async (wfId, nodeId, opts) => {
|
|
3415
|
+
try {
|
|
3416
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3417
|
+
const body = await resolveBody(opts.body);
|
|
3418
|
+
const result = await client.workflows.reloadProps(wfId, nodeId, body);
|
|
3419
|
+
printRecord(result);
|
|
3420
|
+
} catch (err) {
|
|
3421
|
+
process.exitCode = handleError(err);
|
|
3422
|
+
}
|
|
3423
|
+
});
|
|
3424
|
+
const edge = workflow.command("edge").description("Manage workflow edges (connections between nodes)");
|
|
3425
|
+
edge.command("create").description("Create an edge between two nodes").argument("<wf-id>", "Workflow ID").requiredOption("--source <node-id>", "Source node ID").requiredOption("--target <node-id>", "Target node ID").option("--source-handle <handle>", "Source handle identifier").option("--body <json-or-file-or-->", "Additional body JSON").addHelpText(
|
|
3426
|
+
"after",
|
|
3427
|
+
`
|
|
3428
|
+
Examples:
|
|
3429
|
+
$ nexus workflow edge create wf-123 --source node-1 --target node-2
|
|
3430
|
+
$ nexus workflow edge create wf-123 --source node-1 --target node-2 --source-handle branch-a
|
|
3431
|
+
$ nexus workflow edge create wf-123 --source node-1 --target node-2 --body '{"type":"conditional"}'`
|
|
3432
|
+
).action(async (wfId, opts) => {
|
|
3433
|
+
try {
|
|
3434
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3435
|
+
const extra = await resolveBody(opts.body);
|
|
3436
|
+
const body = mergeBodyWithFlags(extra, {
|
|
3437
|
+
source: opts.source,
|
|
3438
|
+
target: opts.target,
|
|
3439
|
+
...opts.sourceHandle ? { sourceHandle: opts.sourceHandle } : {}
|
|
3440
|
+
});
|
|
3441
|
+
const result = await client.workflows.createEdge(wfId, body);
|
|
3442
|
+
printRecord(result, [
|
|
3443
|
+
{ key: "id", label: "ID" },
|
|
3444
|
+
{ key: "source", label: "Source" },
|
|
3445
|
+
{ key: "target", label: "Target" },
|
|
3446
|
+
{ key: "sourceHandle", label: "Source Handle" },
|
|
3447
|
+
{ key: "type", label: "Type" }
|
|
3448
|
+
]);
|
|
3449
|
+
} catch (err) {
|
|
3450
|
+
process.exitCode = handleError(err);
|
|
3451
|
+
}
|
|
3452
|
+
});
|
|
3453
|
+
edge.command("delete").description("Delete an edge from a workflow").argument("<wf-id>", "Workflow ID").argument("<edge-id>", "Edge ID").option("--yes", "Skip confirmation").addHelpText(
|
|
3454
|
+
"after",
|
|
3455
|
+
`
|
|
3456
|
+
Examples:
|
|
3457
|
+
$ nexus workflow edge delete wf-123 edge-789
|
|
3458
|
+
$ nexus workflow edge delete wf-123 edge-789 --yes`
|
|
3459
|
+
).action(async (wfId, edgeId, opts) => {
|
|
3460
|
+
try {
|
|
3461
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3462
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
3463
|
+
const readline2 = await import("readline/promises");
|
|
3464
|
+
const rl = readline2.createInterface({
|
|
3465
|
+
input: process.stdin,
|
|
3466
|
+
output: process.stdout
|
|
3467
|
+
});
|
|
3468
|
+
const answer = await rl.question(`Delete edge ${edgeId} from workflow ${wfId}? [y/N] `);
|
|
3469
|
+
rl.close();
|
|
3470
|
+
if (answer.toLowerCase() !== "y") {
|
|
3471
|
+
console.log("Aborted.");
|
|
3472
|
+
return;
|
|
3473
|
+
}
|
|
3474
|
+
}
|
|
3475
|
+
await client.workflows.deleteEdge(wfId, edgeId);
|
|
3476
|
+
printSuccess("Edge deleted.", { workflowId: wfId, edgeId });
|
|
3477
|
+
} catch (err) {
|
|
3478
|
+
process.exitCode = handleError(err);
|
|
3479
|
+
}
|
|
3480
|
+
});
|
|
3481
|
+
const branch = workflow.command("branch").description("Manage branches on condition/router nodes");
|
|
3482
|
+
branch.command("list").description("List branches on a node").argument("<wf-id>", "Workflow ID").argument("<node-id>", "Node ID").addHelpText(
|
|
3483
|
+
"after",
|
|
3484
|
+
`
|
|
3485
|
+
Examples:
|
|
3486
|
+
$ nexus workflow branch list wf-123 node-456
|
|
3487
|
+
$ nexus workflow branch list wf-123 node-456 --json`
|
|
3488
|
+
).action(async (wfId, nodeId) => {
|
|
3489
|
+
try {
|
|
3490
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3491
|
+
const result = await client.workflows.listBranches(wfId, nodeId);
|
|
3492
|
+
const branches = Array.isArray(result) ? result : result.data ?? result;
|
|
3493
|
+
printList(branches, void 0, [
|
|
3494
|
+
{ key: "id", label: "ID", width: 36 },
|
|
3495
|
+
{ key: "name", label: "NAME", width: 30 },
|
|
3496
|
+
{ key: "conditions", label: "CONDITIONS", width: 40 }
|
|
3497
|
+
]);
|
|
3498
|
+
} catch (err) {
|
|
3499
|
+
process.exitCode = handleError(err);
|
|
3500
|
+
}
|
|
3501
|
+
});
|
|
3502
|
+
branch.command("create").description("Create a branch on a node").argument("<wf-id>", "Workflow ID").argument("<node-id>", "Node ID").requiredOption("--name <name>", "Branch name").option("--body <json-or-file-or-->", "Additional body JSON (conditions, etc.)").addHelpText(
|
|
3503
|
+
"after",
|
|
3504
|
+
`
|
|
3505
|
+
Examples:
|
|
3506
|
+
$ nexus workflow branch create wf-123 node-456 --name "Has email"
|
|
3507
|
+
$ nexus workflow branch create wf-123 node-456 --name "VIP" --body '{"conditions":[{"field":"tier","op":"eq","value":"vip"}]}'`
|
|
3508
|
+
).action(async (wfId, nodeId, opts) => {
|
|
3509
|
+
try {
|
|
3510
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3511
|
+
const extra = await resolveBody(opts.body);
|
|
3512
|
+
const body = mergeBodyWithFlags(extra, { name: opts.name });
|
|
3513
|
+
const result = await client.workflows.createBranch(wfId, nodeId, body);
|
|
3514
|
+
printRecord(result, [
|
|
3515
|
+
{ key: "id", label: "ID" },
|
|
3516
|
+
{ key: "name", label: "Name" },
|
|
3517
|
+
{ key: "conditions", label: "Conditions" }
|
|
3518
|
+
]);
|
|
3519
|
+
} catch (err) {
|
|
3520
|
+
process.exitCode = handleError(err);
|
|
3521
|
+
}
|
|
3522
|
+
});
|
|
3523
|
+
branch.command("update").description("Update a branch").argument("<wf-id>", "Workflow ID").argument("<node-id>", "Node ID").argument("<branch-id>", "Branch ID").requiredOption("--body <json-or-file-or-->", "Updated branch JSON (name, conditions)").addHelpText(
|
|
3524
|
+
"after",
|
|
3525
|
+
`
|
|
3526
|
+
Examples:
|
|
3527
|
+
$ nexus workflow branch update wf-123 node-456 br-789 --body '{"name":"Renamed","conditions":[]}'
|
|
3528
|
+
$ nexus workflow branch update wf-123 node-456 br-789 --body branch.json`
|
|
3529
|
+
).action(async (wfId, nodeId, branchId, opts) => {
|
|
3530
|
+
try {
|
|
3531
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3532
|
+
const body = await resolveBody(opts.body);
|
|
3533
|
+
const result = await client.workflows.updateBranch(wfId, nodeId, branchId, body);
|
|
3534
|
+
printRecord(result, [
|
|
3535
|
+
{ key: "id", label: "ID" },
|
|
3536
|
+
{ key: "name", label: "Name" },
|
|
3537
|
+
{ key: "conditions", label: "Conditions" }
|
|
3538
|
+
]);
|
|
3539
|
+
} catch (err) {
|
|
3540
|
+
process.exitCode = handleError(err);
|
|
3541
|
+
}
|
|
3542
|
+
});
|
|
3543
|
+
branch.command("delete").description("Delete a branch from a node").argument("<wf-id>", "Workflow ID").argument("<node-id>", "Node ID").argument("<branch-id>", "Branch ID").option("--yes", "Skip confirmation").addHelpText(
|
|
3544
|
+
"after",
|
|
3545
|
+
`
|
|
3546
|
+
Examples:
|
|
3547
|
+
$ nexus workflow branch delete wf-123 node-456 br-789
|
|
3548
|
+
$ nexus workflow branch delete wf-123 node-456 br-789 --yes`
|
|
3549
|
+
).action(async (wfId, nodeId, branchId, opts) => {
|
|
3550
|
+
try {
|
|
3551
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3552
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
3553
|
+
const readline2 = await import("readline/promises");
|
|
3554
|
+
const rl = readline2.createInterface({
|
|
3555
|
+
input: process.stdin,
|
|
3556
|
+
output: process.stdout
|
|
3557
|
+
});
|
|
3558
|
+
const answer = await rl.question(`Delete branch ${branchId} from node ${nodeId}? [y/N] `);
|
|
3559
|
+
rl.close();
|
|
3560
|
+
if (answer.toLowerCase() !== "y") {
|
|
3561
|
+
console.log("Aborted.");
|
|
3562
|
+
return;
|
|
3563
|
+
}
|
|
3564
|
+
}
|
|
3565
|
+
await client.workflows.deleteBranch(wfId, nodeId, branchId);
|
|
3566
|
+
printSuccess("Branch deleted.", { workflowId: wfId, nodeId, branchId });
|
|
3567
|
+
} catch (err) {
|
|
3568
|
+
process.exitCode = handleError(err);
|
|
3569
|
+
}
|
|
3570
|
+
});
|
|
3571
|
+
workflow.command("node-types").description("List available node types").addHelpText(
|
|
3572
|
+
"after",
|
|
3573
|
+
`
|
|
3574
|
+
Examples:
|
|
3575
|
+
$ nexus workflow node-types
|
|
3576
|
+
$ nexus workflow node-types --json`
|
|
3577
|
+
).action(async () => {
|
|
3578
|
+
try {
|
|
3579
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3580
|
+
const result = await client.workflows.listNodeTypes();
|
|
3581
|
+
const types = Array.isArray(result) ? result : result.data ?? result;
|
|
3582
|
+
printList(types, void 0, [
|
|
3583
|
+
{ key: "type", label: "TYPE", width: 30 },
|
|
3584
|
+
{ key: "category", label: "CATEGORY", width: 20 },
|
|
3585
|
+
{ key: "label", label: "LABEL", width: 30 }
|
|
3586
|
+
]);
|
|
3587
|
+
} catch (err) {
|
|
3588
|
+
process.exitCode = handleError(err);
|
|
3589
|
+
}
|
|
3590
|
+
});
|
|
3591
|
+
workflow.command("node-type").description("Get full schema for a node type").argument("<type>", "Node type identifier").addHelpText(
|
|
3592
|
+
"after",
|
|
3593
|
+
`
|
|
3594
|
+
Examples:
|
|
3595
|
+
$ nexus workflow node-type action
|
|
3596
|
+
$ nexus workflow node-type condition --json`
|
|
3597
|
+
).action(async (type) => {
|
|
3598
|
+
try {
|
|
3599
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3600
|
+
const result = await client.workflows.getNodeTypeSchema(type);
|
|
3601
|
+
printRecord(result);
|
|
3602
|
+
} catch (err) {
|
|
3603
|
+
process.exitCode = handleError(err);
|
|
3604
|
+
}
|
|
3605
|
+
});
|
|
3606
|
+
workflow.command("overview").description("Get high-level workflow overview with per-node config status").argument("<wf-id>", "Workflow ID").addHelpText(
|
|
3607
|
+
"after",
|
|
3608
|
+
`
|
|
3609
|
+
Examples:
|
|
3610
|
+
$ nexus workflow overview wf-123
|
|
3611
|
+
$ nexus workflow overview wf-123 --json`
|
|
3612
|
+
).action(async (wfId) => {
|
|
3613
|
+
try {
|
|
3614
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3615
|
+
const result = await client.workflows.getOverview(wfId);
|
|
3616
|
+
printRecord(result);
|
|
3617
|
+
} catch (err) {
|
|
3618
|
+
process.exitCode = handleError(err);
|
|
3619
|
+
}
|
|
3620
|
+
});
|
|
3621
|
+
workflow.command("layout").description("Auto-position nodes in a workflow").argument("<wf-id>", "Workflow ID").addHelpText(
|
|
3622
|
+
"after",
|
|
3623
|
+
`
|
|
3624
|
+
Examples:
|
|
3625
|
+
$ nexus workflow layout wf-123`
|
|
3626
|
+
).action(async (wfId) => {
|
|
3627
|
+
try {
|
|
3628
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3629
|
+
await client.workflows.layout(wfId);
|
|
3630
|
+
printSuccess("Workflow layout applied.", { workflowId: wfId });
|
|
3631
|
+
} catch (err) {
|
|
3632
|
+
process.exitCode = handleError(err);
|
|
3633
|
+
}
|
|
3634
|
+
});
|
|
3635
|
+
workflow.command("trigger").description("Replace the trigger node of a workflow").argument("<wf-id>", "Workflow ID").requiredOption("--type <type>", "New trigger type").option("--body <json-or-file-or-->", "Additional body JSON").addHelpText(
|
|
3636
|
+
"after",
|
|
3637
|
+
`
|
|
3638
|
+
Examples:
|
|
3639
|
+
$ nexus workflow trigger wf-123 --type webhook
|
|
3640
|
+
$ nexus workflow trigger wf-123 --type schedule --body '{"cron":"0 9 * * *"}'`
|
|
3641
|
+
).action(async (wfId, opts) => {
|
|
3642
|
+
try {
|
|
3643
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3644
|
+
const extra = await resolveBody(opts.body);
|
|
3645
|
+
const body = mergeBodyWithFlags(extra, { type: opts.type });
|
|
3646
|
+
const result = await client.workflows.replaceTrigger(wfId, body);
|
|
3647
|
+
printRecord(result);
|
|
3648
|
+
} catch (err) {
|
|
3649
|
+
process.exitCode = handleError(err);
|
|
3650
|
+
}
|
|
3651
|
+
});
|
|
3652
|
+
}
|
|
3653
|
+
|
|
3654
|
+
// src/commands/workflow.ts
|
|
3655
|
+
function registerWorkflowCommands(program2) {
|
|
3656
|
+
const workflow = program2.command("workflow").description("Manage workflows");
|
|
3657
|
+
addPaginationOptions(
|
|
3658
|
+
workflow.command("list").description("List workflows").option("--status <status>", "Filter by status (DRAFT, PUBLISHED)").option("--search <query>", "Search by name").addHelpText(
|
|
3659
|
+
"after",
|
|
3660
|
+
`
|
|
3661
|
+
Examples:
|
|
3662
|
+
$ nexus workflow list
|
|
3663
|
+
$ nexus workflow list --status PUBLISHED --limit 10
|
|
3664
|
+
$ nexus workflow list --search "onboarding" --json`
|
|
3665
|
+
)
|
|
3666
|
+
).action(async (opts) => {
|
|
3667
|
+
try {
|
|
3668
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3669
|
+
const { data, meta } = await client.workflows.list({
|
|
3670
|
+
...getPaginationParams(opts),
|
|
3671
|
+
status: opts.status,
|
|
3672
|
+
search: opts.search
|
|
3673
|
+
});
|
|
3674
|
+
printList(
|
|
3675
|
+
data,
|
|
3676
|
+
meta,
|
|
3677
|
+
[
|
|
3678
|
+
{ key: "id", label: "ID", width: 36 },
|
|
3679
|
+
{ key: "name", label: "NAME", width: 30 },
|
|
3680
|
+
{ key: "status", label: "STATUS", width: 12 },
|
|
3681
|
+
{ key: "createdAt", label: "CREATED", width: 20 }
|
|
3682
|
+
]
|
|
3683
|
+
);
|
|
3684
|
+
} catch (err) {
|
|
3685
|
+
process.exitCode = handleError(err);
|
|
3686
|
+
}
|
|
3687
|
+
});
|
|
3688
|
+
workflow.command("get").description("Get workflow details").argument("<id>", "Workflow ID").addHelpText(
|
|
3689
|
+
"after",
|
|
3690
|
+
`
|
|
3691
|
+
Examples:
|
|
3692
|
+
$ nexus workflow get wf-123
|
|
3693
|
+
$ nexus workflow get wf-123 --json`
|
|
3694
|
+
).action(async (id) => {
|
|
3695
|
+
try {
|
|
3696
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3697
|
+
const wf = await client.workflows.get(id);
|
|
3698
|
+
printRecord(wf, [
|
|
3699
|
+
{ key: "id", label: "ID" },
|
|
3700
|
+
{ key: "name", label: "Name" },
|
|
3701
|
+
{ key: "description", label: "Description" },
|
|
3702
|
+
{ key: "status", label: "Status" },
|
|
3703
|
+
{ key: "createdAt", label: "Created" },
|
|
3704
|
+
{ key: "updatedAt", label: "Updated" }
|
|
3705
|
+
]);
|
|
3706
|
+
} catch (err) {
|
|
3707
|
+
process.exitCode = handleError(err);
|
|
3708
|
+
}
|
|
3709
|
+
});
|
|
3710
|
+
workflow.command("create").description("Create a new workflow").requiredOption("--name <name>", "Workflow name").option("--description <text>", "Workflow description").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
3711
|
+
"after",
|
|
3712
|
+
`
|
|
3713
|
+
Examples:
|
|
3714
|
+
$ nexus workflow create --name "Customer Onboarding"
|
|
3715
|
+
$ nexus workflow create --name "Data Pipeline" --description "ETL workflow"
|
|
3716
|
+
$ nexus workflow create --body '{"name":"Pipeline","description":"ETL"}'`
|
|
3717
|
+
).action(async (opts) => {
|
|
3718
|
+
try {
|
|
3719
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3720
|
+
const base = await resolveBody(opts.body);
|
|
3721
|
+
const body = mergeBodyWithFlags(base, {
|
|
3722
|
+
...opts.name !== void 0 && { name: opts.name },
|
|
3723
|
+
...opts.description !== void 0 && { description: opts.description }
|
|
3724
|
+
});
|
|
3725
|
+
const wf = await client.workflows.create(body);
|
|
3726
|
+
printSuccess("Workflow created.", {
|
|
3727
|
+
id: wf.id,
|
|
3728
|
+
name: wf.name
|
|
3729
|
+
});
|
|
3730
|
+
} catch (err) {
|
|
3731
|
+
process.exitCode = handleError(err);
|
|
3732
|
+
}
|
|
3733
|
+
});
|
|
3734
|
+
workflow.command("update").description("Update a workflow").argument("<id>", "Workflow ID").option("--name <name>", "Workflow name").option("--description <text>", "Workflow description").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
3735
|
+
"after",
|
|
3736
|
+
`
|
|
3737
|
+
Examples:
|
|
3738
|
+
$ nexus workflow update wf-123 --name "Renamed Workflow"
|
|
3739
|
+
$ nexus workflow update wf-123 --description "Updated description"
|
|
3740
|
+
$ nexus workflow update wf-123 --body '{"name":"Renamed"}'`
|
|
3741
|
+
).action(async (id, opts) => {
|
|
3742
|
+
try {
|
|
3743
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3744
|
+
const base = await resolveBody(opts.body);
|
|
3745
|
+
const body = mergeBodyWithFlags(base, {
|
|
3746
|
+
...opts.name !== void 0 && { name: opts.name },
|
|
3747
|
+
...opts.description !== void 0 && { description: opts.description }
|
|
3748
|
+
});
|
|
3749
|
+
await client.workflows.update(id, body);
|
|
3750
|
+
printSuccess("Workflow updated.", { id });
|
|
3751
|
+
} catch (err) {
|
|
3752
|
+
process.exitCode = handleError(err);
|
|
3753
|
+
}
|
|
3754
|
+
});
|
|
3755
|
+
workflow.command("delete").description("Delete a workflow").argument("<id>", "Workflow ID").option("--yes", "Skip confirmation").option("--dry-run", "Preview without deleting").addHelpText(
|
|
3756
|
+
"after",
|
|
3757
|
+
`
|
|
3758
|
+
Examples:
|
|
3759
|
+
$ nexus workflow delete wf-123
|
|
3760
|
+
$ nexus workflow delete wf-123 --yes
|
|
3761
|
+
$ nexus workflow delete wf-123 --dry-run`
|
|
3762
|
+
).action(async (id, opts) => {
|
|
3763
|
+
try {
|
|
3764
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3765
|
+
if (opts.dryRun) {
|
|
3766
|
+
const wf = await client.workflows.get(id);
|
|
3767
|
+
console.log(
|
|
3768
|
+
color.yellow("DRY RUN:") + ` Would delete workflow "${wf.name}" (${id})`
|
|
3769
|
+
);
|
|
3770
|
+
return;
|
|
3771
|
+
}
|
|
3772
|
+
if (!opts.yes && process.stdout.isTTY) {
|
|
3773
|
+
const readline2 = await import("readline/promises");
|
|
3774
|
+
const rl = readline2.createInterface({
|
|
3775
|
+
input: process.stdin,
|
|
3776
|
+
output: process.stdout
|
|
3777
|
+
});
|
|
3778
|
+
const answer = await rl.question(`Delete workflow ${id}? This cannot be undone. [y/N] `);
|
|
3779
|
+
rl.close();
|
|
3780
|
+
if (answer.toLowerCase() !== "y") {
|
|
3781
|
+
console.log("Aborted.");
|
|
3782
|
+
return;
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
await client.workflows.delete(id);
|
|
3786
|
+
printSuccess("Workflow deleted.", { id });
|
|
3787
|
+
} catch (err) {
|
|
3788
|
+
process.exitCode = handleError(err);
|
|
3789
|
+
}
|
|
3790
|
+
});
|
|
3791
|
+
workflow.command("duplicate").description("Duplicate a workflow").argument("<id>", "Workflow ID").addHelpText(
|
|
3792
|
+
"after",
|
|
3793
|
+
`
|
|
3794
|
+
Examples:
|
|
3795
|
+
$ nexus workflow duplicate wf-123`
|
|
3796
|
+
).action(async (id) => {
|
|
3797
|
+
try {
|
|
3798
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3799
|
+
const wf = await client.workflows.duplicate(id);
|
|
3800
|
+
printSuccess("Workflow duplicated.", {
|
|
3801
|
+
id: wf.id,
|
|
3802
|
+
name: wf.name
|
|
3803
|
+
});
|
|
3804
|
+
} catch (err) {
|
|
3805
|
+
process.exitCode = handleError(err);
|
|
3806
|
+
}
|
|
3807
|
+
});
|
|
3808
|
+
workflow.command("publish").description("Publish a workflow").argument("<id>", "Workflow ID").addHelpText(
|
|
3809
|
+
"after",
|
|
3810
|
+
`
|
|
3811
|
+
Examples:
|
|
3812
|
+
$ nexus workflow publish wf-123`
|
|
3813
|
+
).action(async (id) => {
|
|
3814
|
+
try {
|
|
3815
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3816
|
+
const result = await client.workflows.publish(id);
|
|
3817
|
+
printSuccess("Workflow published.", { id, ...result });
|
|
3818
|
+
} catch (err) {
|
|
3819
|
+
process.exitCode = handleError(err);
|
|
3820
|
+
}
|
|
3821
|
+
});
|
|
3822
|
+
workflow.command("unpublish").description("Unpublish a workflow").argument("<id>", "Workflow ID").addHelpText(
|
|
3823
|
+
"after",
|
|
3824
|
+
`
|
|
3825
|
+
Examples:
|
|
3826
|
+
$ nexus workflow unpublish wf-123`
|
|
3827
|
+
).action(async (id) => {
|
|
3828
|
+
try {
|
|
3829
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3830
|
+
const result = await client.workflows.unpublish(id);
|
|
3831
|
+
printSuccess("Workflow unpublished.", { id, ...result });
|
|
3832
|
+
} catch (err) {
|
|
3833
|
+
process.exitCode = handleError(err);
|
|
3834
|
+
}
|
|
3835
|
+
});
|
|
3836
|
+
workflow.command("validate").description("Validate a workflow").argument("<id>", "Workflow ID").addHelpText(
|
|
3837
|
+
"after",
|
|
3838
|
+
`
|
|
3839
|
+
Examples:
|
|
3840
|
+
$ nexus workflow validate wf-123
|
|
3841
|
+
$ nexus workflow validate wf-123 --json`
|
|
3842
|
+
).action(async (id) => {
|
|
3843
|
+
try {
|
|
3844
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3845
|
+
const report = await client.workflows.validate(id);
|
|
3846
|
+
printRecord(report);
|
|
3847
|
+
} catch (err) {
|
|
3848
|
+
process.exitCode = handleError(err);
|
|
3849
|
+
}
|
|
3850
|
+
});
|
|
3851
|
+
workflow.command("test").description("Run a test execution of a workflow").argument("<id>", "Workflow ID").option("--input <json>", "Input JSON for the test").option("--body <json>", "Request body as JSON, .json file, or '-' for stdin").addHelpText(
|
|
3852
|
+
"after",
|
|
3853
|
+
`
|
|
3854
|
+
Examples:
|
|
3855
|
+
$ nexus workflow test wf-123 --input '{"message": "hello"}'
|
|
3856
|
+
$ nexus workflow test wf-123 --body '{"message": "hello"}'
|
|
3857
|
+
$ nexus workflow test wf-123 --json`
|
|
3858
|
+
).action(async (id, opts) => {
|
|
3859
|
+
try {
|
|
3860
|
+
const client = createClient(program2.optsWithGlobals());
|
|
3861
|
+
const base = await resolveBody(opts.body);
|
|
3862
|
+
const input = opts.input ? JSON.parse(opts.input) : base ?? {};
|
|
3863
|
+
const result = await client.workflows.testWorkflow(id, input);
|
|
3864
|
+
printRecord(result);
|
|
3865
|
+
} catch (err) {
|
|
3866
|
+
process.exitCode = handleError(err);
|
|
3867
|
+
}
|
|
3868
|
+
});
|
|
3869
|
+
registerWorkflowBuilderCommands(workflow, program2);
|
|
3870
|
+
}
|
|
3871
|
+
|
|
3872
|
+
// src/index.ts
|
|
3873
|
+
init_output();
|
|
3874
|
+
|
|
3875
|
+
// src/util/version-check.ts
|
|
3876
|
+
var import_node_fs4 = __toESM(require("fs"));
|
|
3877
|
+
var import_node_os2 = __toESM(require("os"));
|
|
3878
|
+
var import_node_path4 = __toESM(require("path"));
|
|
3879
|
+
var PACKAGE_NAME = "@agent-nexus/cli";
|
|
3880
|
+
var CHECK_INTERVAL_MS = 24 * 60 * 60 * 1e3;
|
|
3881
|
+
var FETCH_TIMEOUT_MS = 3e3;
|
|
3882
|
+
var CACHE_FILE = import_node_path4.default.join(import_node_os2.default.homedir(), ".nexus-mcp", "version-check.json");
|
|
3883
|
+
function loadCache() {
|
|
3884
|
+
try {
|
|
3885
|
+
return JSON.parse(import_node_fs4.default.readFileSync(CACHE_FILE, "utf-8"));
|
|
3886
|
+
} catch {
|
|
3887
|
+
return null;
|
|
3888
|
+
}
|
|
3889
|
+
}
|
|
3890
|
+
function saveCache(cache) {
|
|
3891
|
+
try {
|
|
3892
|
+
const dir = import_node_path4.default.dirname(CACHE_FILE);
|
|
3893
|
+
import_node_fs4.default.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
3894
|
+
import_node_fs4.default.writeFileSync(CACHE_FILE, JSON.stringify(cache), { mode: 384 });
|
|
3895
|
+
} catch {
|
|
3896
|
+
}
|
|
3897
|
+
}
|
|
3898
|
+
async function fetchLatestVersion() {
|
|
3899
|
+
try {
|
|
3900
|
+
const controller = new AbortController();
|
|
3901
|
+
const timer = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);
|
|
3902
|
+
const res = await fetch(`https://registry.npmjs.org/${PACKAGE_NAME}/latest`, {
|
|
3903
|
+
signal: controller.signal
|
|
3904
|
+
});
|
|
3905
|
+
clearTimeout(timer);
|
|
3906
|
+
if (!res.ok) return null;
|
|
3907
|
+
const json = await res.json();
|
|
3908
|
+
return json.version ?? null;
|
|
3909
|
+
} catch {
|
|
3910
|
+
return null;
|
|
3911
|
+
}
|
|
3912
|
+
}
|
|
3913
|
+
function compareSemver(a, b) {
|
|
3914
|
+
const pa = a.split(".").map(Number);
|
|
3915
|
+
const pb = b.split(".").map(Number);
|
|
3916
|
+
for (let i = 0; i < 3; i++) {
|
|
3917
|
+
const diff = (pa[i] ?? 0) - (pb[i] ?? 0);
|
|
3918
|
+
if (diff !== 0) return diff < 0 ? -1 : 1;
|
|
3919
|
+
}
|
|
3920
|
+
return 0;
|
|
3921
|
+
}
|
|
3922
|
+
async function checkForUpdate(currentVersion) {
|
|
3923
|
+
try {
|
|
3924
|
+
const cache = loadCache();
|
|
3925
|
+
if (cache && Date.now() - cache.lastChecked < CHECK_INTERVAL_MS) {
|
|
3926
|
+
if (compareSemver(currentVersion, cache.latestVersion) < 0) {
|
|
3927
|
+
return formatUpdateMessage(currentVersion, cache.latestVersion);
|
|
3928
|
+
}
|
|
3929
|
+
return null;
|
|
3930
|
+
}
|
|
3931
|
+
const latest = await fetchLatestVersion();
|
|
3932
|
+
if (!latest) return null;
|
|
3933
|
+
saveCache({ lastChecked: Date.now(), latestVersion: latest });
|
|
3934
|
+
if (compareSemver(currentVersion, latest) < 0) {
|
|
3935
|
+
return formatUpdateMessage(currentVersion, latest);
|
|
3936
|
+
}
|
|
3937
|
+
return null;
|
|
3938
|
+
} catch {
|
|
3939
|
+
return null;
|
|
3940
|
+
}
|
|
3941
|
+
}
|
|
3942
|
+
function formatUpdateMessage(current, latest) {
|
|
3943
|
+
return `
|
|
3944
|
+
Update available: ${current} \u2192 ${latest}
|
|
3945
|
+
Run "npm update -g ${PACKAGE_NAME}" to update.
|
|
3946
|
+
IMPORTANT: You MUST update before running any other nexus commands. Results from an outdated CLI may be incorrect.
|
|
3947
|
+
`;
|
|
3948
|
+
}
|
|
3949
|
+
|
|
3950
|
+
// src/index.ts
|
|
3951
|
+
var VERSION = "0.1.0";
|
|
3952
|
+
var program = new import_commander.Command().name("nexus").description("Official CLI for the Nexus AI agent platform").version(VERSION, "-v, --version").option("--json", "Output as JSON").option("--api-key <key>", "Override API key for this invocation").option("--base-url <url>", "Override API base URL").hook("preAction", (thisCommand) => {
|
|
3953
|
+
const opts = thisCommand.optsWithGlobals();
|
|
3954
|
+
if (opts.json) setJsonMode(true);
|
|
3955
|
+
});
|
|
3956
|
+
program.addHelpText("before", getBanner(VERSION));
|
|
3957
|
+
program.configureHelp({
|
|
3958
|
+
sortSubcommands: true
|
|
3959
|
+
});
|
|
3960
|
+
registerAuthCommands(program);
|
|
3961
|
+
registerAgentCommands(program);
|
|
3962
|
+
registerAgentToolCommands(program);
|
|
3963
|
+
registerVersionCommands(program);
|
|
3964
|
+
registerFolderCommands(program);
|
|
3965
|
+
registerDeploymentCommands(program);
|
|
3966
|
+
registerWorkflowCommands(program);
|
|
3967
|
+
registerExecutionCommands(program);
|
|
3968
|
+
registerDocumentCommands(program);
|
|
3969
|
+
registerCollectionCommands(program);
|
|
3970
|
+
registerTaskCommands(program);
|
|
3971
|
+
registerToolCommands(program);
|
|
3972
|
+
registerAnalyticsCommands(program);
|
|
3973
|
+
registerTicketCommands(program);
|
|
3974
|
+
registerApiCommand(program);
|
|
3975
|
+
registerEmulatorCommands(program);
|
|
3976
|
+
registerEvaluationCommands(program);
|
|
3977
|
+
registerTemplateCommands(program);
|
|
3978
|
+
registerExternalToolCommands(program);
|
|
3979
|
+
registerPromptAssistantCommands(program);
|
|
3980
|
+
registerModelCommands(program);
|
|
3981
|
+
if (process.argv.length <= 2) {
|
|
3982
|
+
program.help();
|
|
3983
|
+
}
|
|
3984
|
+
program.parseAsync(process.argv).then(async () => {
|
|
3985
|
+
const updateMsg = await checkForUpdate(VERSION);
|
|
3986
|
+
if (updateMsg && !isJsonMode()) {
|
|
3987
|
+
const { color: color2 } = await Promise.resolve().then(() => (init_output(), output_exports));
|
|
3988
|
+
process.stderr.write(color2.yellow(updateMsg));
|
|
3989
|
+
}
|
|
3990
|
+
}).catch((err) => {
|
|
3991
|
+
process.exitCode = handleError(err);
|
|
3992
|
+
});
|