@pixelml/agenticflow-cli 1.0.5 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +37 -1
- package/dist/cli/local-validation.d.ts +16 -0
- package/dist/cli/local-validation.d.ts.map +1 -0
- package/dist/cli/local-validation.js +298 -0
- package/dist/cli/local-validation.js.map +1 -0
- package/dist/cli/main.d.ts +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +1086 -29
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/playbooks.d.ts.map +1 -1
- package/dist/cli/playbooks.js +87 -0
- package/dist/cli/playbooks.js.map +1 -1
- package/dist/cli/template-cache.d.ts +41 -0
- package/dist/cli/template-cache.d.ts.map +1 -0
- package/dist/cli/template-cache.js +131 -0
- package/dist/cli/template-cache.js.map +1 -0
- package/dist/cli/template-duplicate.d.ts +24 -0
- package/dist/cli/template-duplicate.d.ts.map +1 -0
- package/dist/cli/template-duplicate.js +171 -0
- package/dist/cli/template-duplicate.js.map +1 -0
- package/package.json +1 -1
package/dist/cli/main.js
CHANGED
|
@@ -2,11 +2,11 @@
|
|
|
2
2
|
* Main CLI program definition with Commander.js.
|
|
3
3
|
* Resource commands (workflow, agent, node-types, connections, uploads)
|
|
4
4
|
* use the SDK resource classes. Generic commands (call, ops, catalog,
|
|
5
|
-
* doctor, auth, policy, playbook) remain spec-based.
|
|
5
|
+
* doctor, auth, policy, playbook, templates) remain spec-based.
|
|
6
6
|
*/
|
|
7
7
|
import { Command } from "commander";
|
|
8
|
-
import { readFileSync, existsSync, mkdirSync, writeFileSync, unlinkSync } from "node:fs";
|
|
9
|
-
import { resolve, dirname, join } from "node:path";
|
|
8
|
+
import { readFileSync, existsSync, mkdirSync, writeFileSync, unlinkSync, readdirSync } from "node:fs";
|
|
9
|
+
import { resolve, dirname, join, basename } from "node:path";
|
|
10
10
|
import { fileURLToPath } from "node:url";
|
|
11
11
|
import { homedir } from "node:os";
|
|
12
12
|
import { createInterface } from "node:readline";
|
|
@@ -15,12 +15,22 @@ import { OperationRegistry, defaultSpecPath, loadOpenapiSpec, isPublic, } from "
|
|
|
15
15
|
import { listPlaybooks, getPlaybook } from "./playbooks.js";
|
|
16
16
|
import { loadPolicy, writeDefaultPolicy, policyFilePath, } from "./policy.js";
|
|
17
17
|
import { parseKeyValuePairs, loadJsonPayload, buildRequestSpec } from "./client.js";
|
|
18
|
+
import { TEMPLATE_CACHE_SCHEMA_VERSION, readTemplateCacheManifest, writeTemplateCache, } from "./template-cache.js";
|
|
19
|
+
import { validateWorkflowCreatePayload, validateWorkflowUpdatePayload, validateWorkflowRunPayload, validateAgentCreatePayload, validateAgentUpdatePayload, validateAgentStreamPayload, } from "./local-validation.js";
|
|
20
|
+
import { buildWorkflowCreatePayloadFromTemplate, extractAgentTemplateWorkflowReferences, buildAgentCreatePayloadFromTemplate, indexTemplatesById, } from "./template-duplicate.js";
|
|
18
21
|
// --- Constants ---
|
|
19
22
|
const AUTH_ENV_API_KEY = "AGENTICFLOW_PUBLIC_API_KEY";
|
|
20
23
|
const DOCTOR_SCHEMA_VERSION = "agenticflow.doctor.v1";
|
|
21
24
|
const CATALOG_EXPORT_SCHEMA_VERSION = "agenticflow.catalog.export.v1";
|
|
22
25
|
const CATALOG_RANK_SCHEMA_VERSION = "agenticflow.catalog.rank.v1";
|
|
23
26
|
const ERROR_SCHEMA_VERSION = "agenticflow.error.v1";
|
|
27
|
+
const PLAYBOOK_LIST_SCHEMA_VERSION = "agenticflow.playbook.list.v1";
|
|
28
|
+
const PLAYBOOK_SCHEMA_VERSION = "agenticflow.playbook.v1";
|
|
29
|
+
const DISCOVER_SCHEMA_VERSION = "agenticflow.discover.v1";
|
|
30
|
+
const TEMPLATE_SYNC_SCHEMA_VERSION = "agenticflow.templates.sync.v1";
|
|
31
|
+
const TEMPLATE_INDEX_SCHEMA_VERSION = "agenticflow.templates.index.v1";
|
|
32
|
+
const TEMPLATE_DUPLICATE_SCHEMA_VERSION = "agenticflow.templates.duplicate.v1";
|
|
33
|
+
const LOCAL_VALIDATION_SCHEMA_VERSION = "agenticflow.local_validation.v1";
|
|
24
34
|
// ═══════════════════════════════════════════════════════════════════
|
|
25
35
|
// Helpers
|
|
26
36
|
// ═══════════════════════════════════════════════════════════════════
|
|
@@ -52,6 +62,15 @@ function fail(code, message, hint, details) {
|
|
|
52
62
|
printError(code, message, hint, details);
|
|
53
63
|
process.exit(1);
|
|
54
64
|
}
|
|
65
|
+
function ensureLocalValidation(target, issues) {
|
|
66
|
+
if (issues.length === 0)
|
|
67
|
+
return;
|
|
68
|
+
fail("local_schema_validation_failed", `Local schema validation failed for ${target} payload (${issues.length} issue${issues.length === 1 ? "" : "s"}).`, "Fix payload fields and retry. Use `agenticflow discover --json` and `agenticflow playbook first-touch` for payload guidance.", {
|
|
69
|
+
schema: LOCAL_VALIDATION_SCHEMA_VERSION,
|
|
70
|
+
target,
|
|
71
|
+
issues,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
55
74
|
function parseOptionalInteger(rawValue, optionName, minimum) {
|
|
56
75
|
if (rawValue == null)
|
|
57
76
|
return undefined;
|
|
@@ -67,6 +86,63 @@ function parseOptionalInteger(rawValue, optionName, minimum) {
|
|
|
67
86
|
}
|
|
68
87
|
return parsed;
|
|
69
88
|
}
|
|
89
|
+
function readJsonFileWithWarnings(filePath, warnings) {
|
|
90
|
+
try {
|
|
91
|
+
const raw = readFileSync(filePath, "utf-8");
|
|
92
|
+
return JSON.parse(raw);
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
96
|
+
warnings.push(`${filePath}: ${message}`);
|
|
97
|
+
return undefined;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
function loadLocalWorkflowTemplateCache(cacheDir) {
|
|
101
|
+
const resolvedCacheDir = resolve(cacheDir);
|
|
102
|
+
const warnings = [];
|
|
103
|
+
const items = [];
|
|
104
|
+
const collectionPath = join(resolvedCacheDir, "workflow_templates.json");
|
|
105
|
+
if (existsSync(collectionPath)) {
|
|
106
|
+
const collection = readJsonFileWithWarnings(collectionPath, warnings);
|
|
107
|
+
if (Array.isArray(collection)) {
|
|
108
|
+
items.push(...collection);
|
|
109
|
+
}
|
|
110
|
+
else if (collection !== undefined) {
|
|
111
|
+
warnings.push(`${collectionPath}: expected array payload`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
const itemDir = join(resolvedCacheDir, "workflow");
|
|
115
|
+
if (existsSync(itemDir)) {
|
|
116
|
+
const files = readdirSync(itemDir, { withFileTypes: true });
|
|
117
|
+
for (const file of files) {
|
|
118
|
+
if (!file.isFile() || !file.name.endsWith(".json"))
|
|
119
|
+
continue;
|
|
120
|
+
const itemPath = join(itemDir, file.name);
|
|
121
|
+
const item = readJsonFileWithWarnings(itemPath, warnings);
|
|
122
|
+
if (item !== undefined)
|
|
123
|
+
items.push(item);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const byId = indexTemplatesById(items);
|
|
127
|
+
return {
|
|
128
|
+
cacheDir: resolvedCacheDir,
|
|
129
|
+
byId,
|
|
130
|
+
warnings,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
function inferTemplateCacheDirFromTemplateFile(templateFile) {
|
|
134
|
+
const absolute = resolve(templateFile);
|
|
135
|
+
const parent = dirname(absolute);
|
|
136
|
+
const parentName = basename(parent).toLowerCase();
|
|
137
|
+
if (parentName === "workflow" || parentName === "agent" || parentName === "workforce") {
|
|
138
|
+
return dirname(parent);
|
|
139
|
+
}
|
|
140
|
+
const fileName = basename(absolute).toLowerCase();
|
|
141
|
+
if (fileName.endsWith("_templates.json")) {
|
|
142
|
+
return parent;
|
|
143
|
+
}
|
|
144
|
+
return undefined;
|
|
145
|
+
}
|
|
70
146
|
function shouldUseColor(parentOpts) {
|
|
71
147
|
return process.stdout.isTTY && process.stderr.isTTY && parentOpts.color !== false && !("NO_COLOR" in process.env);
|
|
72
148
|
}
|
|
@@ -215,6 +291,49 @@ function formatOperationHint(suggestions) {
|
|
|
215
291
|
return undefined;
|
|
216
292
|
return `Try one of: ${suggestions.join(", ")}`;
|
|
217
293
|
}
|
|
294
|
+
function suggestPlaybookTopics(rawQuery) {
|
|
295
|
+
const query = normalizeForMatch(rawQuery);
|
|
296
|
+
const topics = listPlaybooks().map((pb) => pb.topic);
|
|
297
|
+
if (!query)
|
|
298
|
+
return topics.slice(0, 5);
|
|
299
|
+
const scored = topics.map((topic) => {
|
|
300
|
+
const normalizedTopic = normalizeForMatch(topic);
|
|
301
|
+
let score = 0;
|
|
302
|
+
if (normalizedTopic === query)
|
|
303
|
+
score += 10_000;
|
|
304
|
+
if (normalizedTopic.startsWith(query))
|
|
305
|
+
score += 500;
|
|
306
|
+
if (normalizedTopic.includes(query))
|
|
307
|
+
score += 250;
|
|
308
|
+
for (const term of query.split(/\s+/)) {
|
|
309
|
+
if (term.length >= 2 && normalizedTopic.includes(term))
|
|
310
|
+
score += 25;
|
|
311
|
+
}
|
|
312
|
+
return { topic, score };
|
|
313
|
+
});
|
|
314
|
+
return scored
|
|
315
|
+
.sort((a, b) => b.score - a.score || a.topic.localeCompare(b.topic))
|
|
316
|
+
.slice(0, 5)
|
|
317
|
+
.map((item) => item.topic);
|
|
318
|
+
}
|
|
319
|
+
function describeCommand(cmd, depth = 0) {
|
|
320
|
+
const options = cmd.options
|
|
321
|
+
.filter((opt) => !opt.flags.includes("--help"))
|
|
322
|
+
.map((opt) => ({
|
|
323
|
+
flags: opt.flags,
|
|
324
|
+
description: opt.description ?? "",
|
|
325
|
+
}));
|
|
326
|
+
const description = cmd.description();
|
|
327
|
+
const descriptor = {
|
|
328
|
+
name: cmd.name(),
|
|
329
|
+
description: typeof description === "string" ? description : "",
|
|
330
|
+
options,
|
|
331
|
+
};
|
|
332
|
+
if (depth < 1 && cmd.commands.length > 0) {
|
|
333
|
+
descriptor["subcommands"] = cmd.commands.map((sub) => describeCommand(sub, depth + 1));
|
|
334
|
+
}
|
|
335
|
+
return descriptor;
|
|
336
|
+
}
|
|
218
337
|
// --- Auth helpers ---
|
|
219
338
|
function defaultAuthConfigPath() {
|
|
220
339
|
const envDir = process.env["AGENTICFLOW_CLI_DIR"];
|
|
@@ -250,6 +369,13 @@ function parseKeyValueEnv(line) {
|
|
|
250
369
|
// ═══════════════════════════════════════════════════════════════════
|
|
251
370
|
export function createProgram() {
|
|
252
371
|
const program = new Command();
|
|
372
|
+
program.configureOutput({
|
|
373
|
+
outputError: (str, write) => {
|
|
374
|
+
if (isJsonFlagEnabled())
|
|
375
|
+
return;
|
|
376
|
+
write(str);
|
|
377
|
+
},
|
|
378
|
+
});
|
|
253
379
|
// Read version from package.json so --version stays in sync
|
|
254
380
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
255
381
|
const pkgPath = join(__dirname, "..", "..", "package.json");
|
|
@@ -258,17 +384,64 @@ export function createProgram() {
|
|
|
258
384
|
.name("agenticflow")
|
|
259
385
|
.description("AgenticFlow CLI for agent-native API operations.")
|
|
260
386
|
.version(pkgVersion)
|
|
261
|
-
.showHelpAfterError()
|
|
262
|
-
.showSuggestionAfterError(true)
|
|
263
387
|
.option("--api-key <key>", "API key for authentication")
|
|
264
388
|
.option("--workspace-id <id>", "Default workspace ID")
|
|
265
389
|
.option("--project-id <id>", "Default project ID")
|
|
266
390
|
.option("--spec-file <path>", "Path to OpenAPI spec JSON file")
|
|
267
391
|
.option("--no-color", "Disable ANSI colors in text output")
|
|
268
392
|
.option("--json", "Force JSON output");
|
|
393
|
+
if (isJsonFlagEnabled()) {
|
|
394
|
+
program.showSuggestionAfterError(false);
|
|
395
|
+
}
|
|
396
|
+
else {
|
|
397
|
+
program.showSuggestionAfterError(true);
|
|
398
|
+
}
|
|
399
|
+
program.exitOverride();
|
|
269
400
|
// ═════════════════════════════════════════════════════════════════
|
|
270
401
|
// doctor
|
|
271
402
|
// ═════════════════════════════════════════════════════════════════
|
|
403
|
+
program
|
|
404
|
+
.command("discover")
|
|
405
|
+
.description("Machine-readable CLI capability index for autonomous agents.")
|
|
406
|
+
.option("--json", "JSON output")
|
|
407
|
+
.action((opts) => {
|
|
408
|
+
const parentOpts = program.opts();
|
|
409
|
+
const commands = program.commands
|
|
410
|
+
.filter((cmd) => cmd.name() !== "discover")
|
|
411
|
+
.map((cmd) => describeCommand(cmd));
|
|
412
|
+
const payload = {
|
|
413
|
+
schema: DISCOVER_SCHEMA_VERSION,
|
|
414
|
+
cli: {
|
|
415
|
+
name: program.name(),
|
|
416
|
+
version: program.version(),
|
|
417
|
+
},
|
|
418
|
+
entrypoints: {
|
|
419
|
+
first_touch: "agenticflow playbook first-touch",
|
|
420
|
+
discover_playbooks: "agenticflow playbook --list --json",
|
|
421
|
+
strict_preflight: "agenticflow doctor --json --strict",
|
|
422
|
+
seed_templates: "agenticflow templates sync --json",
|
|
423
|
+
duplicate_from_template: "agenticflow templates duplicate workflow --template-id <id> --json",
|
|
424
|
+
},
|
|
425
|
+
contracts: {
|
|
426
|
+
error_schema: ERROR_SCHEMA_VERSION,
|
|
427
|
+
playbook_list_schema: PLAYBOOK_LIST_SCHEMA_VERSION,
|
|
428
|
+
playbook_schema: PLAYBOOK_SCHEMA_VERSION,
|
|
429
|
+
doctor_schema: DOCTOR_SCHEMA_VERSION,
|
|
430
|
+
template_cache_schema: TEMPLATE_CACHE_SCHEMA_VERSION,
|
|
431
|
+
local_validation_schema: LOCAL_VALIDATION_SCHEMA_VERSION,
|
|
432
|
+
},
|
|
433
|
+
commands,
|
|
434
|
+
};
|
|
435
|
+
if (opts.json || parentOpts.json) {
|
|
436
|
+
printJson(payload);
|
|
437
|
+
}
|
|
438
|
+
else {
|
|
439
|
+
console.log("AgenticFlow CLI Capability Index");
|
|
440
|
+
console.log(`- Version: ${program.version()}`);
|
|
441
|
+
console.log(`- First touch: ${payload.entrypoints.first_touch}`);
|
|
442
|
+
console.log("- Use `agenticflow discover --json` for machine-readable capability metadata.");
|
|
443
|
+
}
|
|
444
|
+
});
|
|
272
445
|
program
|
|
273
446
|
.command("doctor")
|
|
274
447
|
.description("Preflight checks for CLI configuration and connectivity.")
|
|
@@ -468,9 +641,23 @@ export function createProgram() {
|
|
|
468
641
|
.command("playbook [topic]")
|
|
469
642
|
.description("View built-in playbooks for AgenticFlow workflows.")
|
|
470
643
|
.option("--list", "List available playbooks")
|
|
644
|
+
.option("--json", "JSON output")
|
|
471
645
|
.action((topic, opts) => {
|
|
646
|
+
const parentOpts = program.opts();
|
|
472
647
|
if (opts.list || !topic) {
|
|
473
648
|
const playbooks = listPlaybooks();
|
|
649
|
+
if (opts.json || parentOpts.json) {
|
|
650
|
+
printJson({
|
|
651
|
+
schema: PLAYBOOK_LIST_SCHEMA_VERSION,
|
|
652
|
+
count: playbooks.length,
|
|
653
|
+
playbooks: playbooks.map((pb) => ({
|
|
654
|
+
topic: pb.topic,
|
|
655
|
+
title: pb.title,
|
|
656
|
+
summary: pb.summary,
|
|
657
|
+
})),
|
|
658
|
+
});
|
|
659
|
+
return;
|
|
660
|
+
}
|
|
474
661
|
for (const pb of playbooks) {
|
|
475
662
|
console.log(` ${pb.topic.padEnd(20)} ${pb.title} — ${pb.summary}`);
|
|
476
663
|
}
|
|
@@ -478,8 +665,16 @@ export function createProgram() {
|
|
|
478
665
|
}
|
|
479
666
|
const pb = getPlaybook(topic);
|
|
480
667
|
if (!pb) {
|
|
481
|
-
|
|
482
|
-
|
|
668
|
+
const suggestions = suggestPlaybookTopics(topic);
|
|
669
|
+
const hint = suggestions.length > 0 ? `Available topics: ${suggestions.join(", ")}` : undefined;
|
|
670
|
+
fail("playbook_not_found", `Playbook not found: ${topic}`, hint);
|
|
671
|
+
}
|
|
672
|
+
if (opts.json || parentOpts.json) {
|
|
673
|
+
printJson({
|
|
674
|
+
schema: PLAYBOOK_SCHEMA_VERSION,
|
|
675
|
+
playbook: pb,
|
|
676
|
+
});
|
|
677
|
+
return;
|
|
483
678
|
}
|
|
484
679
|
console.log(`# ${pb.title}\n`);
|
|
485
680
|
console.log(pb.content);
|
|
@@ -799,6 +994,536 @@ export function createProgram() {
|
|
|
799
994
|
}
|
|
800
995
|
});
|
|
801
996
|
// ═════════════════════════════════════════════════════════════════
|
|
997
|
+
// templates (spec-backed, local bootstrap cache)
|
|
998
|
+
// ═════════════════════════════════════════════════════════════════
|
|
999
|
+
const templatesCmd = program
|
|
1000
|
+
.command("templates")
|
|
1001
|
+
.description("Template bootstrap helpers for cold-start agents.");
|
|
1002
|
+
templatesCmd
|
|
1003
|
+
.command("sync")
|
|
1004
|
+
.description("Fetch workflow/agent/workforce templates and serialize them to a local cache.")
|
|
1005
|
+
.option("--dir <path>", "Output directory for template cache", ".agenticflow/templates")
|
|
1006
|
+
.option("--limit <n>", "Template limit per source", "100")
|
|
1007
|
+
.option("--offset <n>", "Template offset per source", "0")
|
|
1008
|
+
.option("--sort-order <order>", "Workflow sort order: asc or desc", "desc")
|
|
1009
|
+
.option("--workforce-id <id>", "Optional workforce ID filter for workforce template fetch")
|
|
1010
|
+
.option("--strict", "Exit non-zero if any template source fails")
|
|
1011
|
+
.option("--json", "JSON output")
|
|
1012
|
+
.action(async (opts) => {
|
|
1013
|
+
const parentOpts = program.opts();
|
|
1014
|
+
const baseUrl = DEFAULT_BASE_URL;
|
|
1015
|
+
const token = resolveToken(parentOpts);
|
|
1016
|
+
const limit = parseOptionalInteger(opts.limit, "--limit", 1) ?? 100;
|
|
1017
|
+
const offset = parseOptionalInteger(opts.offset, "--offset", 0) ?? 0;
|
|
1018
|
+
const sortOrder = String(opts.sortOrder ?? "desc").toLowerCase();
|
|
1019
|
+
if (sortOrder !== "asc" && sortOrder !== "desc") {
|
|
1020
|
+
fail("invalid_option_value", `Invalid value for --sort-order: ${opts.sortOrder}`, "Use either 'asc' or 'desc'.");
|
|
1021
|
+
}
|
|
1022
|
+
const specFile = parentOpts.specFile ?? defaultSpecPath();
|
|
1023
|
+
const registry = loadRegistry(specFile);
|
|
1024
|
+
if (!registry)
|
|
1025
|
+
fail("spec_load_failed", "Failed to load OpenAPI spec.");
|
|
1026
|
+
const sourceConfigs = [
|
|
1027
|
+
{
|
|
1028
|
+
kind: "workflow",
|
|
1029
|
+
operationId: "get_workflow_templates_v1_workflow_templates__get",
|
|
1030
|
+
query: {
|
|
1031
|
+
limit: String(limit),
|
|
1032
|
+
offset: String(offset),
|
|
1033
|
+
sort_order: sortOrder,
|
|
1034
|
+
},
|
|
1035
|
+
},
|
|
1036
|
+
{
|
|
1037
|
+
kind: "agent",
|
|
1038
|
+
operationId: "get_public_v1_agent_templates_public_get",
|
|
1039
|
+
query: {
|
|
1040
|
+
limit: String(limit),
|
|
1041
|
+
offset: String(offset),
|
|
1042
|
+
},
|
|
1043
|
+
},
|
|
1044
|
+
{
|
|
1045
|
+
kind: "workforce",
|
|
1046
|
+
operationId: "get_mas_templates_v1_mas_templates__get",
|
|
1047
|
+
query: {
|
|
1048
|
+
limit: String(limit),
|
|
1049
|
+
offset: String(offset),
|
|
1050
|
+
workforce_id: opts.workforceId,
|
|
1051
|
+
},
|
|
1052
|
+
},
|
|
1053
|
+
];
|
|
1054
|
+
const datasets = [];
|
|
1055
|
+
const issues = [];
|
|
1056
|
+
for (const source of sourceConfigs) {
|
|
1057
|
+
const operation = registry.getOperationById(source.operationId);
|
|
1058
|
+
if (!operation) {
|
|
1059
|
+
issues.push({
|
|
1060
|
+
kind: source.kind,
|
|
1061
|
+
code: "operation_not_found",
|
|
1062
|
+
message: `Operation not found in spec: ${source.operationId}`,
|
|
1063
|
+
hint: "Update the bundled OpenAPI spec or pass --spec-file with a newer spec.",
|
|
1064
|
+
});
|
|
1065
|
+
continue;
|
|
1066
|
+
}
|
|
1067
|
+
const queryParams = {};
|
|
1068
|
+
for (const [key, value] of Object.entries(source.query)) {
|
|
1069
|
+
if (typeof value === "string" && value.length > 0)
|
|
1070
|
+
queryParams[key] = value;
|
|
1071
|
+
}
|
|
1072
|
+
let requestSpec;
|
|
1073
|
+
try {
|
|
1074
|
+
requestSpec = buildRequestSpec(operation, baseUrl, {}, queryParams, {}, token, undefined);
|
|
1075
|
+
}
|
|
1076
|
+
catch (err) {
|
|
1077
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1078
|
+
issues.push({
|
|
1079
|
+
kind: source.kind,
|
|
1080
|
+
code: "invalid_request_options",
|
|
1081
|
+
message,
|
|
1082
|
+
});
|
|
1083
|
+
continue;
|
|
1084
|
+
}
|
|
1085
|
+
const query = new URLSearchParams(requestSpec.params).toString();
|
|
1086
|
+
const url = query ? `${requestSpec.url}?${query}` : requestSpec.url;
|
|
1087
|
+
try {
|
|
1088
|
+
const response = await fetch(url, {
|
|
1089
|
+
method: requestSpec.method,
|
|
1090
|
+
headers: requestSpec.headers,
|
|
1091
|
+
});
|
|
1092
|
+
const text = await response.text();
|
|
1093
|
+
let data = text;
|
|
1094
|
+
try {
|
|
1095
|
+
data = JSON.parse(text);
|
|
1096
|
+
}
|
|
1097
|
+
catch {
|
|
1098
|
+
// non-json responses are captured below
|
|
1099
|
+
}
|
|
1100
|
+
if (!response.ok) {
|
|
1101
|
+
const hint = source.kind === "workforce" && !opts.workforceId && response.status === 400
|
|
1102
|
+
? "Retry with --workforce-id <id> if your backend requires a source workforce filter."
|
|
1103
|
+
: undefined;
|
|
1104
|
+
issues.push({
|
|
1105
|
+
kind: source.kind,
|
|
1106
|
+
code: "template_source_failed",
|
|
1107
|
+
message: `Template fetch failed for ${source.kind} source (${response.status}).`,
|
|
1108
|
+
status: response.status,
|
|
1109
|
+
hint,
|
|
1110
|
+
});
|
|
1111
|
+
continue;
|
|
1112
|
+
}
|
|
1113
|
+
if (!Array.isArray(data)) {
|
|
1114
|
+
issues.push({
|
|
1115
|
+
kind: source.kind,
|
|
1116
|
+
code: "unexpected_payload_shape",
|
|
1117
|
+
message: `Expected an array response for ${source.kind} templates.`,
|
|
1118
|
+
hint: "Validate response schema for this operation or inspect the endpoint manually with `agenticflow call`.",
|
|
1119
|
+
});
|
|
1120
|
+
continue;
|
|
1121
|
+
}
|
|
1122
|
+
datasets.push({
|
|
1123
|
+
kind: source.kind,
|
|
1124
|
+
operationId: source.operationId,
|
|
1125
|
+
query: source.query,
|
|
1126
|
+
items: data,
|
|
1127
|
+
});
|
|
1128
|
+
}
|
|
1129
|
+
catch (err) {
|
|
1130
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1131
|
+
issues.push({
|
|
1132
|
+
kind: source.kind,
|
|
1133
|
+
code: "request_failed",
|
|
1134
|
+
message: `Template fetch request failed for ${source.kind}: ${message}`,
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
}
|
|
1138
|
+
const manifest = writeTemplateCache(opts.dir, datasets, issues);
|
|
1139
|
+
const fetchedCount = datasets.reduce((sum, dataset) => sum + dataset.items.length, 0);
|
|
1140
|
+
const payload = {
|
|
1141
|
+
schema: TEMPLATE_SYNC_SCHEMA_VERSION,
|
|
1142
|
+
ok: issues.length === 0,
|
|
1143
|
+
cache: manifest,
|
|
1144
|
+
fetched_templates: fetchedCount,
|
|
1145
|
+
source_count: sourceConfigs.length,
|
|
1146
|
+
};
|
|
1147
|
+
if (opts.json || parentOpts.json) {
|
|
1148
|
+
printJson(payload);
|
|
1149
|
+
}
|
|
1150
|
+
else {
|
|
1151
|
+
console.log("Template cache sync complete.");
|
|
1152
|
+
console.log(`- Cache dir: ${manifest.cache_dir}`);
|
|
1153
|
+
for (const dataset of manifest.datasets) {
|
|
1154
|
+
console.log(`- ${dataset.kind}: ${dataset.count} templates`);
|
|
1155
|
+
}
|
|
1156
|
+
if (manifest.issues.length > 0) {
|
|
1157
|
+
console.log(`- Issues: ${manifest.issues.length} (inspect ${manifest.cache_dir}/manifest.json)`);
|
|
1158
|
+
}
|
|
1159
|
+
}
|
|
1160
|
+
if (opts.strict && issues.length > 0) {
|
|
1161
|
+
process.exitCode = 1;
|
|
1162
|
+
}
|
|
1163
|
+
if (datasets.length === 0) {
|
|
1164
|
+
process.exitCode = 1;
|
|
1165
|
+
}
|
|
1166
|
+
});
|
|
1167
|
+
const templatesDuplicateCmd = templatesCmd
|
|
1168
|
+
.command("duplicate")
|
|
1169
|
+
.description("Create new resources from template samples.");
|
|
1170
|
+
templatesDuplicateCmd
|
|
1171
|
+
.command("workflow")
|
|
1172
|
+
.description("Duplicate a workflow template into a new workflow.")
|
|
1173
|
+
.option("--template-id <id>", "Workflow template ID")
|
|
1174
|
+
.option("--template-file <path>", "Local workflow template JSON file")
|
|
1175
|
+
.option("--cache-dir <path>", "Local template cache dir (from `templates sync`)")
|
|
1176
|
+
.option("--workspace-id <id>", "Workspace ID override")
|
|
1177
|
+
.option("--project-id <id>", "Project ID override")
|
|
1178
|
+
.option("--name-suffix <suffix>", "Suffix for duplicated workflow name", " [Copy]")
|
|
1179
|
+
.option("--dry-run", "Build and print create payload without creating workflow")
|
|
1180
|
+
.option("--json", "JSON output")
|
|
1181
|
+
.action(async (opts) => {
|
|
1182
|
+
const parentOpts = program.opts();
|
|
1183
|
+
const client = buildClient(parentOpts);
|
|
1184
|
+
const templateId = opts.templateId;
|
|
1185
|
+
const templateFile = opts.templateFile;
|
|
1186
|
+
const explicitCacheDir = opts.cacheDir;
|
|
1187
|
+
if ((templateId == null || templateId.trim() === "") && !templateFile) {
|
|
1188
|
+
fail("missing_required_option", "Provide --template-id or --template-file.", "Use `templates sync` to fetch templates locally, then pass --template-file.");
|
|
1189
|
+
}
|
|
1190
|
+
if (templateId && templateFile) {
|
|
1191
|
+
fail("invalid_request_options", "Use either --template-id or --template-file, not both.");
|
|
1192
|
+
}
|
|
1193
|
+
if (explicitCacheDir && !existsSync(resolve(explicitCacheDir))) {
|
|
1194
|
+
fail("template_cache_not_found", `Template cache directory not found: ${resolve(explicitCacheDir)}`, "Run `agenticflow templates sync --dir <path>` first or use an existing cache dir.");
|
|
1195
|
+
}
|
|
1196
|
+
const inferredCacheDir = templateFile ? inferTemplateCacheDirFromTemplateFile(templateFile) : undefined;
|
|
1197
|
+
const cacheDir = explicitCacheDir ?? inferredCacheDir;
|
|
1198
|
+
const localWorkflowCache = cacheDir ? loadLocalWorkflowTemplateCache(cacheDir) : null;
|
|
1199
|
+
const projectId = resolveProjectId(opts.projectId);
|
|
1200
|
+
if (!projectId) {
|
|
1201
|
+
fail("missing_project_id", "Project ID is required to duplicate templates.", "Set AGENTICFLOW_PROJECT_ID or pass --project-id.");
|
|
1202
|
+
}
|
|
1203
|
+
let templateData;
|
|
1204
|
+
let templateSource = "api";
|
|
1205
|
+
if (templateFile) {
|
|
1206
|
+
templateData = loadJsonPayload(`@${templateFile}`);
|
|
1207
|
+
templateSource = "file";
|
|
1208
|
+
}
|
|
1209
|
+
else {
|
|
1210
|
+
const localTemplate = localWorkflowCache?.byId.get(templateId);
|
|
1211
|
+
if (localTemplate !== undefined) {
|
|
1212
|
+
templateData = localTemplate;
|
|
1213
|
+
templateSource = "cache";
|
|
1214
|
+
}
|
|
1215
|
+
else {
|
|
1216
|
+
try {
|
|
1217
|
+
templateData = (await client.sdk.get(`/v1/workflow_templates/${templateId}`)).data;
|
|
1218
|
+
templateSource = "api";
|
|
1219
|
+
}
|
|
1220
|
+
catch (err) {
|
|
1221
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1222
|
+
fail("request_failed", message);
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
}
|
|
1226
|
+
let createPayload;
|
|
1227
|
+
try {
|
|
1228
|
+
createPayload = buildWorkflowCreatePayloadFromTemplate(templateData, projectId, opts.nameSuffix);
|
|
1229
|
+
}
|
|
1230
|
+
catch (err) {
|
|
1231
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1232
|
+
fail("template_payload_invalid", message);
|
|
1233
|
+
}
|
|
1234
|
+
ensureLocalValidation("workflow.create", validateWorkflowCreatePayload(createPayload));
|
|
1235
|
+
if (opts.dryRun) {
|
|
1236
|
+
const payload = {
|
|
1237
|
+
schema: TEMPLATE_DUPLICATE_SCHEMA_VERSION,
|
|
1238
|
+
kind: "workflow",
|
|
1239
|
+
dry_run: true,
|
|
1240
|
+
template_source: templateSource,
|
|
1241
|
+
cache_dir: localWorkflowCache?.cacheDir ?? null,
|
|
1242
|
+
cache_warnings: localWorkflowCache?.warnings ?? [],
|
|
1243
|
+
create_payload: createPayload,
|
|
1244
|
+
};
|
|
1245
|
+
if (opts.json || parentOpts.json) {
|
|
1246
|
+
printJson(payload);
|
|
1247
|
+
}
|
|
1248
|
+
else {
|
|
1249
|
+
console.log("Workflow template duplication dry-run payload:");
|
|
1250
|
+
printJson(payload);
|
|
1251
|
+
}
|
|
1252
|
+
return;
|
|
1253
|
+
}
|
|
1254
|
+
const workspaceId = resolveWorkspaceId(opts.workspaceId);
|
|
1255
|
+
if (!workspaceId) {
|
|
1256
|
+
fail("missing_workspace_id", "Workspace ID is required to create duplicated workflows.", "Set AGENTICFLOW_WORKSPACE_ID or pass --workspace-id.");
|
|
1257
|
+
}
|
|
1258
|
+
try {
|
|
1259
|
+
const created = await client.workflows.create(createPayload, workspaceId);
|
|
1260
|
+
const payload = {
|
|
1261
|
+
schema: TEMPLATE_DUPLICATE_SCHEMA_VERSION,
|
|
1262
|
+
kind: "workflow",
|
|
1263
|
+
dry_run: false,
|
|
1264
|
+
template_source: templateSource,
|
|
1265
|
+
cache_dir: localWorkflowCache?.cacheDir ?? null,
|
|
1266
|
+
cache_warnings: localWorkflowCache?.warnings ?? [],
|
|
1267
|
+
created,
|
|
1268
|
+
};
|
|
1269
|
+
if (opts.json || parentOpts.json) {
|
|
1270
|
+
printJson(payload);
|
|
1271
|
+
}
|
|
1272
|
+
else {
|
|
1273
|
+
console.log("Workflow duplicated from template successfully.");
|
|
1274
|
+
printJson(payload);
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
catch (err) {
|
|
1278
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1279
|
+
fail("request_failed", message);
|
|
1280
|
+
}
|
|
1281
|
+
});
|
|
1282
|
+
templatesDuplicateCmd
|
|
1283
|
+
.command("agent")
|
|
1284
|
+
.description("Duplicate an agent template and its workflow-template tools.")
|
|
1285
|
+
.option("--template-id <id>", "Agent template ID")
|
|
1286
|
+
.option("--template-file <path>", "Local agent template JSON file")
|
|
1287
|
+
.option("--cache-dir <path>", "Local template cache dir (from `templates sync`)")
|
|
1288
|
+
.option("--workspace-id <id>", "Workspace ID override")
|
|
1289
|
+
.option("--project-id <id>", "Project ID override")
|
|
1290
|
+
.option("--name-suffix <suffix>", "Suffix for duplicated agent name", " [Copy]")
|
|
1291
|
+
.option("--workflow-name-suffix <suffix>", "Suffix for duplicated tool workflows", " [Tool Copy]")
|
|
1292
|
+
.option("--skip-missing-tools", "Skip tools whose workflow templates cannot be duplicated")
|
|
1293
|
+
.option("--dry-run", "Build and print create payloads without creating resources")
|
|
1294
|
+
.option("--json", "JSON output")
|
|
1295
|
+
.action(async (opts) => {
|
|
1296
|
+
const parentOpts = program.opts();
|
|
1297
|
+
const client = buildClient(parentOpts);
|
|
1298
|
+
const templateId = opts.templateId;
|
|
1299
|
+
const templateFile = opts.templateFile;
|
|
1300
|
+
const explicitCacheDir = opts.cacheDir;
|
|
1301
|
+
if ((templateId == null || templateId.trim() === "") && !templateFile) {
|
|
1302
|
+
fail("missing_required_option", "Provide --template-id or --template-file.", "Use `templates sync` to fetch templates locally, then pass --template-file.");
|
|
1303
|
+
}
|
|
1304
|
+
if (templateId && templateFile) {
|
|
1305
|
+
fail("invalid_request_options", "Use either --template-id or --template-file, not both.");
|
|
1306
|
+
}
|
|
1307
|
+
if (explicitCacheDir && !existsSync(resolve(explicitCacheDir))) {
|
|
1308
|
+
fail("template_cache_not_found", `Template cache directory not found: ${resolve(explicitCacheDir)}`, "Run `agenticflow templates sync --dir <path>` first or use an existing cache dir.");
|
|
1309
|
+
}
|
|
1310
|
+
const inferredCacheDir = templateFile ? inferTemplateCacheDirFromTemplateFile(templateFile) : undefined;
|
|
1311
|
+
const cacheDir = explicitCacheDir ?? inferredCacheDir;
|
|
1312
|
+
const localWorkflowCache = cacheDir ? loadLocalWorkflowTemplateCache(cacheDir) : null;
|
|
1313
|
+
const projectId = resolveProjectId(opts.projectId);
|
|
1314
|
+
if (!projectId) {
|
|
1315
|
+
fail("missing_project_id", "Project ID is required to duplicate templates.", "Set AGENTICFLOW_PROJECT_ID or pass --project-id.");
|
|
1316
|
+
}
|
|
1317
|
+
const workspaceId = resolveWorkspaceId(opts.workspaceId);
|
|
1318
|
+
if (!workspaceId && !opts.dryRun) {
|
|
1319
|
+
fail("missing_workspace_id", "Workspace ID is required to duplicate agent template tools.", "Set AGENTICFLOW_WORKSPACE_ID or pass --workspace-id.");
|
|
1320
|
+
}
|
|
1321
|
+
let agentTemplate;
|
|
1322
|
+
if (templateFile) {
|
|
1323
|
+
agentTemplate = loadJsonPayload(`@${templateFile}`);
|
|
1324
|
+
}
|
|
1325
|
+
else {
|
|
1326
|
+
try {
|
|
1327
|
+
agentTemplate = (await client.sdk.get(`/v1/agent-templates/${templateId}`)).data;
|
|
1328
|
+
}
|
|
1329
|
+
catch (err) {
|
|
1330
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1331
|
+
fail("request_failed", message);
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
const toolRefs = extractAgentTemplateWorkflowReferences(agentTemplate);
|
|
1335
|
+
const duplicatedTools = [];
|
|
1336
|
+
const createdWorkflows = [];
|
|
1337
|
+
const skippedTools = [];
|
|
1338
|
+
const toolTemplateResolution = {
|
|
1339
|
+
from_cache: 0,
|
|
1340
|
+
from_api: 0,
|
|
1341
|
+
};
|
|
1342
|
+
for (let i = 0; i < toolRefs.length; i++) {
|
|
1343
|
+
const ref = toolRefs[i];
|
|
1344
|
+
let workflowTemplate;
|
|
1345
|
+
const localTemplate = localWorkflowCache?.byId.get(ref.workflowTemplateId);
|
|
1346
|
+
if (localTemplate !== undefined) {
|
|
1347
|
+
workflowTemplate = localTemplate;
|
|
1348
|
+
toolTemplateResolution.from_cache += 1;
|
|
1349
|
+
}
|
|
1350
|
+
else {
|
|
1351
|
+
try {
|
|
1352
|
+
workflowTemplate = (await client.sdk.get(`/v1/workflow_templates/${ref.workflowTemplateId}`)).data;
|
|
1353
|
+
toolTemplateResolution.from_api += 1;
|
|
1354
|
+
}
|
|
1355
|
+
catch (err) {
|
|
1356
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1357
|
+
if (opts.skipMissingTools) {
|
|
1358
|
+
const reason = localWorkflowCache
|
|
1359
|
+
? `Not found in local cache and API fetch failed: ${message}`
|
|
1360
|
+
: message;
|
|
1361
|
+
skippedTools.push({
|
|
1362
|
+
workflow_template_id: ref.workflowTemplateId,
|
|
1363
|
+
reason,
|
|
1364
|
+
});
|
|
1365
|
+
continue;
|
|
1366
|
+
}
|
|
1367
|
+
fail("request_failed", `Unable to fetch tool workflow template ${ref.workflowTemplateId}: ${message}`, "Use --skip-missing-tools to proceed without unavailable tool templates.");
|
|
1368
|
+
}
|
|
1369
|
+
}
|
|
1370
|
+
let workflowCreatePayload;
|
|
1371
|
+
try {
|
|
1372
|
+
workflowCreatePayload = buildWorkflowCreatePayloadFromTemplate(workflowTemplate, projectId, opts.workflowNameSuffix);
|
|
1373
|
+
}
|
|
1374
|
+
catch (err) {
|
|
1375
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1376
|
+
if (opts.skipMissingTools) {
|
|
1377
|
+
skippedTools.push({
|
|
1378
|
+
workflow_template_id: ref.workflowTemplateId,
|
|
1379
|
+
reason: message,
|
|
1380
|
+
});
|
|
1381
|
+
continue;
|
|
1382
|
+
}
|
|
1383
|
+
fail("template_payload_invalid", message);
|
|
1384
|
+
}
|
|
1385
|
+
ensureLocalValidation("workflow.create", validateWorkflowCreatePayload(workflowCreatePayload));
|
|
1386
|
+
if (opts.dryRun) {
|
|
1387
|
+
const placeholderWorkflowId = `__tool_workflow_${i + 1}__`;
|
|
1388
|
+
duplicatedTools.push({
|
|
1389
|
+
workflowTemplateId: ref.workflowTemplateId,
|
|
1390
|
+
workflowId: placeholderWorkflowId,
|
|
1391
|
+
runBehavior: ref.runBehavior,
|
|
1392
|
+
description: ref.description,
|
|
1393
|
+
timeout: ref.timeout,
|
|
1394
|
+
inputConfig: ref.inputConfig,
|
|
1395
|
+
});
|
|
1396
|
+
createdWorkflows.push({
|
|
1397
|
+
workflow_template_id: ref.workflowTemplateId,
|
|
1398
|
+
dry_run_workflow_id: placeholderWorkflowId,
|
|
1399
|
+
create_payload: workflowCreatePayload,
|
|
1400
|
+
});
|
|
1401
|
+
continue;
|
|
1402
|
+
}
|
|
1403
|
+
try {
|
|
1404
|
+
const created = await client.workflows.create(workflowCreatePayload, workspaceId);
|
|
1405
|
+
const createdRecord = (created && typeof created === "object")
|
|
1406
|
+
? created
|
|
1407
|
+
: {};
|
|
1408
|
+
const createdId = typeof createdRecord["id"] === "string" ? createdRecord["id"] : null;
|
|
1409
|
+
if (!createdId) {
|
|
1410
|
+
fail("template_duplicate_failed", `Duplicated tool workflow from ${ref.workflowTemplateId} has no id in response.`);
|
|
1411
|
+
}
|
|
1412
|
+
duplicatedTools.push({
|
|
1413
|
+
workflowTemplateId: ref.workflowTemplateId,
|
|
1414
|
+
workflowId: createdId,
|
|
1415
|
+
runBehavior: ref.runBehavior,
|
|
1416
|
+
description: ref.description,
|
|
1417
|
+
timeout: ref.timeout,
|
|
1418
|
+
inputConfig: ref.inputConfig,
|
|
1419
|
+
});
|
|
1420
|
+
createdWorkflows.push({
|
|
1421
|
+
workflow_template_id: ref.workflowTemplateId,
|
|
1422
|
+
workflow: createdRecord,
|
|
1423
|
+
});
|
|
1424
|
+
}
|
|
1425
|
+
catch (err) {
|
|
1426
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1427
|
+
if (opts.skipMissingTools) {
|
|
1428
|
+
skippedTools.push({
|
|
1429
|
+
workflow_template_id: ref.workflowTemplateId,
|
|
1430
|
+
reason: message,
|
|
1431
|
+
});
|
|
1432
|
+
continue;
|
|
1433
|
+
}
|
|
1434
|
+
fail("request_failed", `Failed to create tool workflow for template ${ref.workflowTemplateId}: ${message}`, "Use --skip-missing-tools to proceed without unavailable tool templates.");
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
let agentCreatePayload;
|
|
1438
|
+
try {
|
|
1439
|
+
agentCreatePayload = buildAgentCreatePayloadFromTemplate(agentTemplate, projectId, duplicatedTools, opts.nameSuffix);
|
|
1440
|
+
}
|
|
1441
|
+
catch (err) {
|
|
1442
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1443
|
+
fail("template_payload_invalid", message);
|
|
1444
|
+
}
|
|
1445
|
+
ensureLocalValidation("agent.create", validateAgentCreatePayload(agentCreatePayload));
|
|
1446
|
+
if (opts.dryRun) {
|
|
1447
|
+
const payload = {
|
|
1448
|
+
schema: TEMPLATE_DUPLICATE_SCHEMA_VERSION,
|
|
1449
|
+
kind: "agent",
|
|
1450
|
+
dry_run: true,
|
|
1451
|
+
cache_dir: localWorkflowCache?.cacheDir ?? null,
|
|
1452
|
+
cache_warnings: localWorkflowCache?.warnings ?? [],
|
|
1453
|
+
tool_template_resolution: toolTemplateResolution,
|
|
1454
|
+
created_tool_workflows: createdWorkflows,
|
|
1455
|
+
skipped_tools: skippedTools,
|
|
1456
|
+
create_payload: agentCreatePayload,
|
|
1457
|
+
};
|
|
1458
|
+
if (opts.json || parentOpts.json) {
|
|
1459
|
+
printJson(payload);
|
|
1460
|
+
}
|
|
1461
|
+
else {
|
|
1462
|
+
console.log("Agent template duplication dry-run payload:");
|
|
1463
|
+
printJson(payload);
|
|
1464
|
+
}
|
|
1465
|
+
return;
|
|
1466
|
+
}
|
|
1467
|
+
try {
|
|
1468
|
+
const createdAgent = await client.agents.create(agentCreatePayload);
|
|
1469
|
+
const payload = {
|
|
1470
|
+
schema: TEMPLATE_DUPLICATE_SCHEMA_VERSION,
|
|
1471
|
+
kind: "agent",
|
|
1472
|
+
dry_run: false,
|
|
1473
|
+
cache_dir: localWorkflowCache?.cacheDir ?? null,
|
|
1474
|
+
cache_warnings: localWorkflowCache?.warnings ?? [],
|
|
1475
|
+
tool_template_resolution: toolTemplateResolution,
|
|
1476
|
+
created_tool_workflows: createdWorkflows,
|
|
1477
|
+
skipped_tools: skippedTools,
|
|
1478
|
+
created_agent: createdAgent,
|
|
1479
|
+
};
|
|
1480
|
+
if (opts.json || parentOpts.json) {
|
|
1481
|
+
printJson(payload);
|
|
1482
|
+
}
|
|
1483
|
+
else {
|
|
1484
|
+
console.log("Agent duplicated from template successfully.");
|
|
1485
|
+
printJson(payload);
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
catch (err) {
|
|
1489
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1490
|
+
fail("request_failed", message);
|
|
1491
|
+
}
|
|
1492
|
+
});
|
|
1493
|
+
templatesCmd
|
|
1494
|
+
.command("index")
|
|
1495
|
+
.description("Inspect a local template cache manifest.")
|
|
1496
|
+
.option("--dir <path>", "Template cache directory", ".agenticflow/templates")
|
|
1497
|
+
.option("--json", "JSON output")
|
|
1498
|
+
.action((opts) => {
|
|
1499
|
+
const parentOpts = program.opts();
|
|
1500
|
+
let manifest;
|
|
1501
|
+
try {
|
|
1502
|
+
manifest = readTemplateCacheManifest(opts.dir);
|
|
1503
|
+
}
|
|
1504
|
+
catch (err) {
|
|
1505
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
1506
|
+
fail("template_cache_not_found", `Unable to read template cache manifest at ${resolve(opts.dir)}.`, "Run `agenticflow templates sync --json` first.", { error: message });
|
|
1507
|
+
}
|
|
1508
|
+
const payload = {
|
|
1509
|
+
schema: TEMPLATE_INDEX_SCHEMA_VERSION,
|
|
1510
|
+
cache: manifest,
|
|
1511
|
+
};
|
|
1512
|
+
if (opts.json || parentOpts.json) {
|
|
1513
|
+
printJson(payload);
|
|
1514
|
+
}
|
|
1515
|
+
else {
|
|
1516
|
+
console.log(`Template cache: ${manifest.cache_dir}`);
|
|
1517
|
+
console.log(`Fetched at: ${manifest.fetched_at}`);
|
|
1518
|
+
for (const dataset of manifest.datasets) {
|
|
1519
|
+
console.log(`- ${dataset.kind}: ${dataset.count} templates`);
|
|
1520
|
+
}
|
|
1521
|
+
if (manifest.issues.length > 0) {
|
|
1522
|
+
console.log(`Issues: ${manifest.issues.length} (see manifest.json for details)`);
|
|
1523
|
+
}
|
|
1524
|
+
}
|
|
1525
|
+
});
|
|
1526
|
+
// ═════════════════════════════════════════════════════════════════
|
|
802
1527
|
// workflow (SDK-based)
|
|
803
1528
|
// ═════════════════════════════════════════════════════════════════
|
|
804
1529
|
const workflowCmd = program
|
|
@@ -844,6 +1569,7 @@ export function createProgram() {
|
|
|
844
1569
|
.action(async (opts) => {
|
|
845
1570
|
const client = buildClient(program.opts());
|
|
846
1571
|
const body = loadJsonPayload(opts.body);
|
|
1572
|
+
ensureLocalValidation("workflow.create", validateWorkflowCreatePayload(body));
|
|
847
1573
|
await run(() => client.workflows.create(body, opts.workspaceId));
|
|
848
1574
|
});
|
|
849
1575
|
workflowCmd
|
|
@@ -855,6 +1581,7 @@ export function createProgram() {
|
|
|
855
1581
|
.action(async (opts) => {
|
|
856
1582
|
const client = buildClient(program.opts());
|
|
857
1583
|
const body = loadJsonPayload(opts.body);
|
|
1584
|
+
ensureLocalValidation("workflow.update", validateWorkflowUpdatePayload(body));
|
|
858
1585
|
await run(() => client.workflows.update(opts.workflowId, body, opts.workspaceId));
|
|
859
1586
|
});
|
|
860
1587
|
workflowCmd
|
|
@@ -878,6 +1605,7 @@ export function createProgram() {
|
|
|
878
1605
|
const body = { workflow_id: opts.workflowId };
|
|
879
1606
|
if (opts.input)
|
|
880
1607
|
body["input"] = loadJsonPayload(opts.input);
|
|
1608
|
+
ensureLocalValidation("workflow.run", validateWorkflowRunPayload(body));
|
|
881
1609
|
const executeRun = () => token
|
|
882
1610
|
? client.workflows.run(body)
|
|
883
1611
|
: client.workflows.runAnonymous(body);
|
|
@@ -1044,9 +1772,27 @@ export function createProgram() {
|
|
|
1044
1772
|
.command("validate")
|
|
1045
1773
|
.description("Validate a workflow payload.")
|
|
1046
1774
|
.requiredOption("--body <body>", "JSON body (inline or @file)")
|
|
1775
|
+
.option("--local-only", "Validate locally only (skip API validate endpoint)")
|
|
1047
1776
|
.action(async (opts) => {
|
|
1777
|
+
const parentOpts = program.opts();
|
|
1048
1778
|
const client = buildClient(program.opts());
|
|
1049
1779
|
const body = loadJsonPayload(opts.body);
|
|
1780
|
+
ensureLocalValidation("workflow.create", validateWorkflowCreatePayload(body));
|
|
1781
|
+
if (opts.localOnly) {
|
|
1782
|
+
const payload = {
|
|
1783
|
+
schema: LOCAL_VALIDATION_SCHEMA_VERSION,
|
|
1784
|
+
target: "workflow.create",
|
|
1785
|
+
valid: true,
|
|
1786
|
+
issues: [],
|
|
1787
|
+
};
|
|
1788
|
+
if (opts.json || parentOpts.json) {
|
|
1789
|
+
printJson(payload);
|
|
1790
|
+
}
|
|
1791
|
+
else {
|
|
1792
|
+
console.log("Local validation passed for workflow.create payload.");
|
|
1793
|
+
}
|
|
1794
|
+
return;
|
|
1795
|
+
}
|
|
1050
1796
|
await run(() => client.workflows.validate(body));
|
|
1051
1797
|
});
|
|
1052
1798
|
workflowCmd
|
|
@@ -1062,22 +1808,6 @@ export function createProgram() {
|
|
|
1062
1808
|
offset: parseOptionalInteger(opts.offset, "--offset", 0),
|
|
1063
1809
|
}));
|
|
1064
1810
|
});
|
|
1065
|
-
workflowCmd
|
|
1066
|
-
.command("like-status")
|
|
1067
|
-
.description("Get like status for a workflow.")
|
|
1068
|
-
.requiredOption("--workflow-id <id>", "Workflow ID")
|
|
1069
|
-
.action(async (opts) => {
|
|
1070
|
-
const client = buildClient(program.opts());
|
|
1071
|
-
await run(() => client.workflows.getLikeStatus(opts.workflowId));
|
|
1072
|
-
});
|
|
1073
|
-
workflowCmd
|
|
1074
|
-
.command("reference-impact")
|
|
1075
|
-
.description("Get reference impact analysis for a workflow.")
|
|
1076
|
-
.requiredOption("--workflow-id <id>", "Workflow ID")
|
|
1077
|
-
.action(async (opts) => {
|
|
1078
|
-
const client = buildClient(program.opts());
|
|
1079
|
-
await run(() => client.workflows.getReferenceImpact(opts.workflowId));
|
|
1080
|
-
});
|
|
1081
1811
|
// ═════════════════════════════════════════════════════════════════
|
|
1082
1812
|
// agent (SDK-based)
|
|
1083
1813
|
// ═════════════════════════════════════════════════════════════════
|
|
@@ -1121,6 +1851,7 @@ export function createProgram() {
|
|
|
1121
1851
|
.action(async (opts) => {
|
|
1122
1852
|
const client = buildClient(program.opts());
|
|
1123
1853
|
const body = loadJsonPayload(opts.body);
|
|
1854
|
+
ensureLocalValidation("agent.create", validateAgentCreatePayload(body));
|
|
1124
1855
|
await run(() => client.agents.create(body));
|
|
1125
1856
|
});
|
|
1126
1857
|
agentCmd
|
|
@@ -1131,6 +1862,7 @@ export function createProgram() {
|
|
|
1131
1862
|
.action(async (opts) => {
|
|
1132
1863
|
const client = buildClient(program.opts());
|
|
1133
1864
|
const body = loadJsonPayload(opts.body);
|
|
1865
|
+
ensureLocalValidation("agent.update", validateAgentUpdatePayload(body));
|
|
1134
1866
|
await run(() => client.agents.update(opts.agentId, body));
|
|
1135
1867
|
});
|
|
1136
1868
|
agentCmd
|
|
@@ -1150,20 +1882,49 @@ export function createProgram() {
|
|
|
1150
1882
|
const client = buildClient(program.opts());
|
|
1151
1883
|
const token = resolveToken(program.opts());
|
|
1152
1884
|
const body = loadJsonPayload(opts.body);
|
|
1885
|
+
ensureLocalValidation("agent.stream", validateAgentStreamPayload(body));
|
|
1886
|
+
const streamBody = body;
|
|
1887
|
+
if (token) {
|
|
1888
|
+
const stream = await client.agents.stream(opts.agentId, streamBody);
|
|
1889
|
+
const text = await stream.text();
|
|
1890
|
+
await run(() => Promise.resolve(text));
|
|
1891
|
+
}
|
|
1892
|
+
else {
|
|
1893
|
+
const stream = await client.agents.streamAnonymous(opts.agentId, streamBody);
|
|
1894
|
+
const text = await stream.text();
|
|
1895
|
+
await run(() => Promise.resolve(text));
|
|
1896
|
+
}
|
|
1897
|
+
});
|
|
1898
|
+
agentCmd
|
|
1899
|
+
.command("upload-file")
|
|
1900
|
+
.description("Upload a file for an agent.")
|
|
1901
|
+
.requiredOption("--agent-id <id>", "Agent ID")
|
|
1902
|
+
.requiredOption("--body <body>", "JSON body (inline or @file)")
|
|
1903
|
+
.action(async (opts) => {
|
|
1904
|
+
const client = buildClient(program.opts());
|
|
1905
|
+
const token = resolveToken(program.opts());
|
|
1906
|
+
const body = loadJsonPayload(opts.body);
|
|
1153
1907
|
if (token) {
|
|
1154
|
-
await run(() => client.agents.
|
|
1908
|
+
await run(() => client.agents.uploadFile(opts.agentId, body));
|
|
1155
1909
|
}
|
|
1156
1910
|
else {
|
|
1157
|
-
await run(() => client.agents.
|
|
1911
|
+
await run(() => client.agents.uploadFileAnonymous(opts.agentId, body));
|
|
1158
1912
|
}
|
|
1159
1913
|
});
|
|
1160
1914
|
agentCmd
|
|
1161
|
-
.command("
|
|
1162
|
-
.description("Get
|
|
1915
|
+
.command("upload-session")
|
|
1916
|
+
.description("Get upload session status for an agent.")
|
|
1163
1917
|
.requiredOption("--agent-id <id>", "Agent ID")
|
|
1918
|
+
.requiredOption("--session-id <id>", "Upload session ID")
|
|
1164
1919
|
.action(async (opts) => {
|
|
1165
1920
|
const client = buildClient(program.opts());
|
|
1166
|
-
|
|
1921
|
+
const token = resolveToken(program.opts());
|
|
1922
|
+
if (token) {
|
|
1923
|
+
await run(() => client.agents.getUploadSession(opts.agentId, opts.sessionId));
|
|
1924
|
+
}
|
|
1925
|
+
else {
|
|
1926
|
+
await run(() => client.agents.getUploadSessionAnonymous(opts.agentId, opts.sessionId));
|
|
1927
|
+
}
|
|
1167
1928
|
});
|
|
1168
1929
|
// ═════════════════════════════════════════════════════════════════
|
|
1169
1930
|
// node-types (SDK-based)
|
|
@@ -1176,6 +1937,9 @@ export function createProgram() {
|
|
|
1176
1937
|
.description("List available node types.")
|
|
1177
1938
|
.option("--limit <n>", "Limit")
|
|
1178
1939
|
.option("--offset <n>", "Offset")
|
|
1940
|
+
.option("--sort-order <order>", "Sort order (asc|desc)")
|
|
1941
|
+
.option("--connection <name>", "Filter by connection")
|
|
1942
|
+
.option("--search <query>", "Search query")
|
|
1179
1943
|
.action(async (opts) => {
|
|
1180
1944
|
const client = buildClient(program.opts());
|
|
1181
1945
|
const queryParams = {};
|
|
@@ -1185,6 +1949,12 @@ export function createProgram() {
|
|
|
1185
1949
|
queryParams["limit"] = limit;
|
|
1186
1950
|
if (offset != null)
|
|
1187
1951
|
queryParams["offset"] = offset;
|
|
1952
|
+
if (opts.sortOrder)
|
|
1953
|
+
queryParams["sort_order"] = opts.sortOrder;
|
|
1954
|
+
if (opts.connection)
|
|
1955
|
+
queryParams["connection"] = opts.connection;
|
|
1956
|
+
if (opts.search)
|
|
1957
|
+
queryParams["search"] = opts.search;
|
|
1188
1958
|
await run(() => client.nodeTypes.list(queryParams));
|
|
1189
1959
|
});
|
|
1190
1960
|
nodeTypesCmd
|
|
@@ -1275,6 +2045,34 @@ export function createProgram() {
|
|
|
1275
2045
|
const client = buildClient(program.opts());
|
|
1276
2046
|
await run(() => client.connections.delete(opts.connectionId, opts.workspaceId));
|
|
1277
2047
|
});
|
|
2048
|
+
connectionsCmd
|
|
2049
|
+
.command("get-default")
|
|
2050
|
+
.description("Get the default connection for a category.")
|
|
2051
|
+
.requiredOption("--category-name <name>", "Connection category name")
|
|
2052
|
+
.option("--workspace-id <id>", "Workspace ID")
|
|
2053
|
+
.option("--project-id <id>", "Project ID")
|
|
2054
|
+
.action(async (opts) => {
|
|
2055
|
+
const client = buildClient(program.opts());
|
|
2056
|
+
await run(() => client.connections.getDefault({
|
|
2057
|
+
categoryName: opts.categoryName,
|
|
2058
|
+
workspaceId: opts.workspaceId,
|
|
2059
|
+
projectId: opts.projectId,
|
|
2060
|
+
}));
|
|
2061
|
+
});
|
|
2062
|
+
connectionsCmd
|
|
2063
|
+
.command("categories")
|
|
2064
|
+
.description("List connection categories.")
|
|
2065
|
+
.option("--workspace-id <id>", "Workspace ID")
|
|
2066
|
+
.option("--limit <n>", "Limit")
|
|
2067
|
+
.option("--offset <n>", "Offset")
|
|
2068
|
+
.action(async (opts) => {
|
|
2069
|
+
const client = buildClient(program.opts());
|
|
2070
|
+
await run(() => client.connections.categories({
|
|
2071
|
+
workspaceId: opts.workspaceId,
|
|
2072
|
+
limit: parseOptionalInteger(opts.limit, "--limit", 1),
|
|
2073
|
+
offset: parseOptionalInteger(opts.offset, "--offset", 0),
|
|
2074
|
+
}));
|
|
2075
|
+
});
|
|
1278
2076
|
// ═════════════════════════════════════════════════════════════════
|
|
1279
2077
|
// uploads (SDK-based)
|
|
1280
2078
|
// ═════════════════════════════════════════════════════════════════
|
|
@@ -1298,10 +2096,269 @@ export function createProgram() {
|
|
|
1298
2096
|
const client = buildClient(program.opts());
|
|
1299
2097
|
await run(() => client.uploads.inputStatus(opts.sessionId));
|
|
1300
2098
|
});
|
|
2099
|
+
// ═════════════════════════════════════════════════════════════════
|
|
2100
|
+
// agent-threads (SDK-based)
|
|
2101
|
+
// ═════════════════════════════════════════════════════════════════
|
|
2102
|
+
const agentThreadsCmd = program
|
|
2103
|
+
.command("agent-threads")
|
|
2104
|
+
.description("Agent thread management.");
|
|
2105
|
+
agentThreadsCmd
|
|
2106
|
+
.command("list")
|
|
2107
|
+
.description("List threads for an agent.")
|
|
2108
|
+
.requiredOption("--agent-id <id>", "Agent ID")
|
|
2109
|
+
.option("--limit <n>", "Limit")
|
|
2110
|
+
.option("--offset <n>", "Offset")
|
|
2111
|
+
.option("--status <status>", "Filter by status")
|
|
2112
|
+
.option("--search <query>", "Search query")
|
|
2113
|
+
.action(async (opts) => {
|
|
2114
|
+
const client = buildClient(program.opts());
|
|
2115
|
+
await run(() => client.agentThreads.list(opts.agentId, {
|
|
2116
|
+
limit: parseOptionalInteger(opts.limit, "--limit", 1),
|
|
2117
|
+
offset: parseOptionalInteger(opts.offset, "--offset", 0),
|
|
2118
|
+
status: opts.status,
|
|
2119
|
+
searchQuery: opts.search,
|
|
2120
|
+
}));
|
|
2121
|
+
});
|
|
2122
|
+
agentThreadsCmd
|
|
2123
|
+
.command("list-by-project")
|
|
2124
|
+
.description("List threads for a project.")
|
|
2125
|
+
.option("--project-id <id>", "Project ID")
|
|
2126
|
+
.option("--agent-id <id>", "Agent ID")
|
|
2127
|
+
.option("--visibility <v>", "Visibility filter")
|
|
2128
|
+
.option("--user-id <id>", "User ID filter")
|
|
2129
|
+
.option("--status <status>", "Status filter")
|
|
2130
|
+
.option("--sort-by <field>", "Sort field")
|
|
2131
|
+
.option("--sort-order <order>", "Sort order (asc|desc)")
|
|
2132
|
+
.option("--created-from <date>", "Created from (ISO date)")
|
|
2133
|
+
.option("--created-to <date>", "Created to (ISO date)")
|
|
2134
|
+
.option("--search <query>", "Search query")
|
|
2135
|
+
.option("--page <n>", "Page number")
|
|
2136
|
+
.option("--size <n>", "Page size")
|
|
2137
|
+
.action(async (opts) => {
|
|
2138
|
+
const client = buildClient(program.opts());
|
|
2139
|
+
const projId = opts.projectId ?? resolveProjectId(program.opts().projectId);
|
|
2140
|
+
if (!projId)
|
|
2141
|
+
fail("missing_project_id", "Project ID is required.", "Set AGENTICFLOW_PROJECT_ID or pass --project-id.");
|
|
2142
|
+
await run(() => client.agentThreads.listByProject(projId, {
|
|
2143
|
+
agentId: opts.agentId,
|
|
2144
|
+
visibility: opts.visibility,
|
|
2145
|
+
userId: opts.userId,
|
|
2146
|
+
status: opts.status,
|
|
2147
|
+
sortBy: opts.sortBy,
|
|
2148
|
+
sortOrder: opts.sortOrder,
|
|
2149
|
+
createdFrom: opts.createdFrom,
|
|
2150
|
+
createdTo: opts.createdTo,
|
|
2151
|
+
searchQuery: opts.search,
|
|
2152
|
+
page: parseOptionalInteger(opts.page, "--page", 1),
|
|
2153
|
+
size: parseOptionalInteger(opts.size, "--size", 1),
|
|
2154
|
+
}));
|
|
2155
|
+
});
|
|
2156
|
+
agentThreadsCmd
|
|
2157
|
+
.command("get")
|
|
2158
|
+
.description("Get a thread by ID.")
|
|
2159
|
+
.requiredOption("--thread-id <id>", "Thread ID")
|
|
2160
|
+
.action(async (opts) => {
|
|
2161
|
+
const client = buildClient(program.opts());
|
|
2162
|
+
await run(() => client.agentThreads.get(opts.threadId));
|
|
2163
|
+
});
|
|
2164
|
+
agentThreadsCmd
|
|
2165
|
+
.command("delete")
|
|
2166
|
+
.description("Delete a thread.")
|
|
2167
|
+
.requiredOption("--thread-id <id>", "Thread ID")
|
|
2168
|
+
.action(async (opts) => {
|
|
2169
|
+
const client = buildClient(program.opts());
|
|
2170
|
+
await run(() => client.agentThreads.delete(opts.threadId));
|
|
2171
|
+
});
|
|
2172
|
+
agentThreadsCmd
|
|
2173
|
+
.command("messages")
|
|
2174
|
+
.description("Get messages for a thread.")
|
|
2175
|
+
.requiredOption("--thread-id <id>", "Thread ID")
|
|
2176
|
+
.action(async (opts) => {
|
|
2177
|
+
const client = buildClient(program.opts());
|
|
2178
|
+
await run(() => client.agentThreads.getMessages(opts.threadId));
|
|
2179
|
+
});
|
|
2180
|
+
// ═════════════════════════════════════════════════════════════════
|
|
2181
|
+
// knowledge (SDK-based)
|
|
2182
|
+
// ═════════════════════════════════════════════════════════════════
|
|
2183
|
+
const knowledgeCmd = program
|
|
2184
|
+
.command("knowledge")
|
|
2185
|
+
.description("Knowledge dataset management.");
|
|
2186
|
+
knowledgeCmd
|
|
2187
|
+
.command("list")
|
|
2188
|
+
.description("List knowledge datasets.")
|
|
2189
|
+
.option("--workspace-id <id>", "Workspace ID")
|
|
2190
|
+
.option("--project-id <id>", "Project ID")
|
|
2191
|
+
.option("--limit <n>", "Limit")
|
|
2192
|
+
.option("--offset <n>", "Offset")
|
|
2193
|
+
.option("--format-type <type>", "Format type filter")
|
|
2194
|
+
.option("--search <query>", "Search query")
|
|
2195
|
+
.action(async (opts) => {
|
|
2196
|
+
const client = buildClient(program.opts());
|
|
2197
|
+
await run(() => client.knowledge.list({
|
|
2198
|
+
workspaceId: opts.workspaceId,
|
|
2199
|
+
projectId: opts.projectId,
|
|
2200
|
+
limit: parseOptionalInteger(opts.limit, "--limit", 1),
|
|
2201
|
+
offset: parseOptionalInteger(opts.offset, "--offset", 0),
|
|
2202
|
+
formatType: opts.formatType,
|
|
2203
|
+
searchQuery: opts.search,
|
|
2204
|
+
}));
|
|
2205
|
+
});
|
|
2206
|
+
knowledgeCmd
|
|
2207
|
+
.command("get")
|
|
2208
|
+
.description("Get a knowledge dataset by ID.")
|
|
2209
|
+
.requiredOption("--dataset-id <id>", "Dataset ID")
|
|
2210
|
+
.action(async (opts) => {
|
|
2211
|
+
const client = buildClient(program.opts());
|
|
2212
|
+
await run(() => client.knowledge.get(opts.datasetId));
|
|
2213
|
+
});
|
|
2214
|
+
knowledgeCmd
|
|
2215
|
+
.command("delete")
|
|
2216
|
+
.description("Delete a knowledge dataset.")
|
|
2217
|
+
.requiredOption("--dataset-id <id>", "Dataset ID")
|
|
2218
|
+
.action(async (opts) => {
|
|
2219
|
+
const client = buildClient(program.opts());
|
|
2220
|
+
await run(() => client.knowledge.delete(opts.datasetId));
|
|
2221
|
+
});
|
|
2222
|
+
knowledgeCmd
|
|
2223
|
+
.command("list-rows")
|
|
2224
|
+
.description("List rows for a knowledge dataset.")
|
|
2225
|
+
.requiredOption("--dataset-id <id>", "Dataset ID")
|
|
2226
|
+
.option("--limit <n>", "Limit")
|
|
2227
|
+
.option("--offset <n>", "Offset")
|
|
2228
|
+
.option("--sort <field>", "Sort field")
|
|
2229
|
+
.action(async (opts) => {
|
|
2230
|
+
const client = buildClient(program.opts());
|
|
2231
|
+
await run(() => client.knowledge.listRows(opts.datasetId, {
|
|
2232
|
+
limit: parseOptionalInteger(opts.limit, "--limit", 1),
|
|
2233
|
+
offset: parseOptionalInteger(opts.offset, "--offset", 0),
|
|
2234
|
+
sort: opts.sort,
|
|
2235
|
+
}));
|
|
2236
|
+
});
|
|
2237
|
+
knowledgeCmd
|
|
2238
|
+
.command("search-rows")
|
|
2239
|
+
.description("Search rows in a knowledge dataset.")
|
|
2240
|
+
.requiredOption("--dataset-id <id>", "Dataset ID")
|
|
2241
|
+
.requiredOption("--search-term <term>", "Search term")
|
|
2242
|
+
.option("--limit <n>", "Limit")
|
|
2243
|
+
.action(async (opts) => {
|
|
2244
|
+
const client = buildClient(program.opts());
|
|
2245
|
+
await run(() => client.knowledge.searchRows(opts.datasetId, opts.searchTerm, {
|
|
2246
|
+
limit: parseOptionalInteger(opts.limit, "--limit", 1),
|
|
2247
|
+
}));
|
|
2248
|
+
});
|
|
2249
|
+
// ═════════════════════════════════════════════════════════════════
|
|
2250
|
+
// database (SDK-based)
|
|
2251
|
+
// ═════════════════════════════════════════════════════════════════
|
|
2252
|
+
const databaseCmd = program
|
|
2253
|
+
.command("database")
|
|
2254
|
+
.description("Database dataset management.");
|
|
2255
|
+
databaseCmd
|
|
2256
|
+
.command("list")
|
|
2257
|
+
.description("List database datasets.")
|
|
2258
|
+
.option("--workspace-id <id>", "Workspace ID")
|
|
2259
|
+
.option("--project-id <id>", "Project ID")
|
|
2260
|
+
.option("--limit <n>", "Limit")
|
|
2261
|
+
.option("--offset <n>", "Offset")
|
|
2262
|
+
.option("--search <query>", "Search query")
|
|
2263
|
+
.action(async (opts) => {
|
|
2264
|
+
const client = buildClient(program.opts());
|
|
2265
|
+
await run(() => client.database.list({
|
|
2266
|
+
workspaceId: opts.workspaceId,
|
|
2267
|
+
projectId: opts.projectId,
|
|
2268
|
+
limit: parseOptionalInteger(opts.limit, "--limit", 1),
|
|
2269
|
+
offset: parseOptionalInteger(opts.offset, "--offset", 0),
|
|
2270
|
+
searchQuery: opts.search,
|
|
2271
|
+
}));
|
|
2272
|
+
});
|
|
2273
|
+
databaseCmd
|
|
2274
|
+
.command("create")
|
|
2275
|
+
.description("Create a database dataset.")
|
|
2276
|
+
.requiredOption("--body <body>", "JSON body (inline or @file)")
|
|
2277
|
+
.action(async (opts) => {
|
|
2278
|
+
const client = buildClient(program.opts());
|
|
2279
|
+
const body = loadJsonPayload(opts.body);
|
|
2280
|
+
await run(() => client.database.create(body));
|
|
2281
|
+
});
|
|
2282
|
+
databaseCmd
|
|
2283
|
+
.command("get")
|
|
2284
|
+
.description("Get a database dataset by ID.")
|
|
2285
|
+
.requiredOption("--dataset-id <id>", "Dataset ID")
|
|
2286
|
+
.action(async (opts) => {
|
|
2287
|
+
const client = buildClient(program.opts());
|
|
2288
|
+
await run(() => client.database.get(opts.datasetId));
|
|
2289
|
+
});
|
|
2290
|
+
databaseCmd
|
|
2291
|
+
.command("update")
|
|
2292
|
+
.description("Update a database dataset.")
|
|
2293
|
+
.requiredOption("--dataset-id <id>", "Dataset ID")
|
|
2294
|
+
.requiredOption("--body <body>", "JSON body (inline or @file)")
|
|
2295
|
+
.action(async (opts) => {
|
|
2296
|
+
const client = buildClient(program.opts());
|
|
2297
|
+
const body = loadJsonPayload(opts.body);
|
|
2298
|
+
await run(() => client.database.update(opts.datasetId, body));
|
|
2299
|
+
});
|
|
2300
|
+
databaseCmd
|
|
2301
|
+
.command("delete")
|
|
2302
|
+
.description("Delete a database dataset.")
|
|
2303
|
+
.requiredOption("--dataset-id <id>", "Dataset ID")
|
|
2304
|
+
.action(async (opts) => {
|
|
2305
|
+
const client = buildClient(program.opts());
|
|
2306
|
+
await run(() => client.database.delete(opts.datasetId));
|
|
2307
|
+
});
|
|
2308
|
+
// ═════════════════════════════════════════════════════════════════
|
|
2309
|
+
// mcp-clients (SDK-based)
|
|
2310
|
+
// ═════════════════════════════════════════════════════════════════
|
|
2311
|
+
const mcpClientsCmd = program
|
|
2312
|
+
.command("mcp-clients")
|
|
2313
|
+
.description("MCP client management.");
|
|
2314
|
+
mcpClientsCmd
|
|
2315
|
+
.command("list")
|
|
2316
|
+
.description("List MCP clients.")
|
|
2317
|
+
.option("--workspace-id <id>", "Workspace ID")
|
|
2318
|
+
.option("--project-id <id>", "Project ID")
|
|
2319
|
+
.option("--limit <n>", "Limit")
|
|
2320
|
+
.option("--offset <n>", "Offset")
|
|
2321
|
+
.action(async (opts) => {
|
|
2322
|
+
const client = buildClient(program.opts());
|
|
2323
|
+
await run(() => client.mcpClients.list({
|
|
2324
|
+
workspaceId: opts.workspaceId,
|
|
2325
|
+
projectId: opts.projectId,
|
|
2326
|
+
limit: parseOptionalInteger(opts.limit, "--limit", 1),
|
|
2327
|
+
offset: parseOptionalInteger(opts.offset, "--offset", 0),
|
|
2328
|
+
}));
|
|
2329
|
+
});
|
|
2330
|
+
mcpClientsCmd
|
|
2331
|
+
.command("get")
|
|
2332
|
+
.description("Get MCP client details.")
|
|
2333
|
+
.requiredOption("--client-id <id>", "MCP client ID")
|
|
2334
|
+
.action(async (opts) => {
|
|
2335
|
+
const client = buildClient(program.opts());
|
|
2336
|
+
await run(() => client.mcpClients.get(opts.clientId));
|
|
2337
|
+
});
|
|
1301
2338
|
return program;
|
|
1302
2339
|
}
|
|
1303
2340
|
export async function runCli(argv) {
|
|
1304
2341
|
const program = createProgram();
|
|
1305
|
-
|
|
2342
|
+
try {
|
|
2343
|
+
await program.parseAsync(argv ?? process.argv);
|
|
2344
|
+
}
|
|
2345
|
+
catch (err) {
|
|
2346
|
+
const code = typeof err === "object" && err != null && "code" in err
|
|
2347
|
+
? String(err.code)
|
|
2348
|
+
: "";
|
|
2349
|
+
if (code.startsWith("commander.")) {
|
|
2350
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
2351
|
+
if (code === "commander.helpDisplayed" || code === "commander.version") {
|
|
2352
|
+
process.exit(0);
|
|
2353
|
+
}
|
|
2354
|
+
if (isJsonFlagEnabled()) {
|
|
2355
|
+
fail("cli_parse_error", message);
|
|
2356
|
+
}
|
|
2357
|
+
process.exit(typeof err === "object" && err != null && "exitCode" in err
|
|
2358
|
+
? Number(err.exitCode) || 1
|
|
2359
|
+
: 1);
|
|
2360
|
+
}
|
|
2361
|
+
throw err;
|
|
2362
|
+
}
|
|
1306
2363
|
}
|
|
1307
2364
|
//# sourceMappingURL=main.js.map
|