@pixelml/agenticflow-cli 0.1.0 → 1.0.1
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 +166 -36
- package/dist/bin/agenticflow.d.ts +6 -0
- package/dist/bin/agenticflow.d.ts.map +1 -0
- package/dist/bin/agenticflow.js +10 -0
- package/dist/bin/agenticflow.js.map +1 -0
- package/dist/cli/client.d.ts +17 -0
- package/dist/cli/client.d.ts.map +1 -0
- package/dist/cli/client.js +102 -0
- package/dist/cli/client.js.map +1 -0
- package/dist/cli/data/openapi.json +27948 -0
- package/dist/cli/data/public_ops_manifest.json +739 -0
- package/dist/cli/main.d.ts +10 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +1100 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/operation-ids.d.ts +10 -0
- package/dist/cli/operation-ids.d.ts.map +1 -0
- package/dist/cli/operation-ids.js +53 -0
- package/dist/cli/operation-ids.js.map +1 -0
- package/dist/cli/playbooks.d.ts +13 -0
- package/dist/cli/playbooks.d.ts.map +1 -0
- package/dist/cli/playbooks.js +102 -0
- package/dist/cli/playbooks.js.map +1 -0
- package/dist/cli/policy.d.ts +61 -0
- package/dist/cli/policy.d.ts.map +1 -0
- package/dist/cli/policy.js +158 -0
- package/dist/cli/policy.js.map +1 -0
- package/dist/cli/spec.d.ts +33 -0
- package/dist/cli/spec.d.ts.map +1 -0
- package/dist/cli/spec.js +154 -0
- package/dist/cli/spec.js.map +1 -0
- package/package.json +19 -18
- package/LICENSE +0 -201
- package/bin/agenticflow.js +0 -42
package/dist/cli/main.js
ADDED
|
@@ -0,0 +1,1100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Main CLI program definition with Commander.js.
|
|
3
|
+
* Resource commands (workflow, agent, node-types, connections, uploads)
|
|
4
|
+
* use the SDK resource classes. Generic commands (call, ops, catalog,
|
|
5
|
+
* doctor, auth, policy, playbook) remain spec-based.
|
|
6
|
+
*/
|
|
7
|
+
import { Command } from "commander";
|
|
8
|
+
import { readFileSync, existsSync, mkdirSync, writeFileSync, unlinkSync } from "node:fs";
|
|
9
|
+
import { resolve, dirname } from "node:path";
|
|
10
|
+
import { homedir } from "node:os";
|
|
11
|
+
import { createInterface } from "node:readline";
|
|
12
|
+
import { createClient, DEFAULT_BASE_URL, AGENTICFLOW_API_KEY, } from "@pixelml/agenticflow-sdk";
|
|
13
|
+
import { OperationRegistry, defaultSpecPath, loadOpenapiSpec, isPublic, } from "./spec.js";
|
|
14
|
+
import { listPlaybooks, getPlaybook } from "./playbooks.js";
|
|
15
|
+
import { loadPolicy, writeDefaultPolicy, policyFilePath, } from "./policy.js";
|
|
16
|
+
import { parseKeyValuePairs, loadJsonPayload, buildRequestSpec } from "./client.js";
|
|
17
|
+
// --- Constants ---
|
|
18
|
+
const AUTH_ENV_API_KEY = "AGENTICFLOW_PUBLIC_API_KEY";
|
|
19
|
+
const DOCTOR_SCHEMA_VERSION = "agenticflow.doctor.v1";
|
|
20
|
+
const CATALOG_EXPORT_SCHEMA_VERSION = "agenticflow.catalog.export.v1";
|
|
21
|
+
const CATALOG_RANK_SCHEMA_VERSION = "agenticflow.catalog.rank.v1";
|
|
22
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
23
|
+
// Helpers
|
|
24
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
25
|
+
function printJson(data) {
|
|
26
|
+
console.log(JSON.stringify(data, null, 2));
|
|
27
|
+
}
|
|
28
|
+
/** Print an SDK result in CLI-friendly format. */
|
|
29
|
+
function printResult(data) {
|
|
30
|
+
printJson(data);
|
|
31
|
+
}
|
|
32
|
+
/** Load the active auth profile from ~/.agenticflow/auth.json */
|
|
33
|
+
function loadActiveProfile() {
|
|
34
|
+
try {
|
|
35
|
+
const config = loadAuthFile(defaultAuthConfigPath());
|
|
36
|
+
const profileName = config["default_profile"] ?? "default";
|
|
37
|
+
const profiles = config["profiles"];
|
|
38
|
+
return profiles?.[profileName] ?? {};
|
|
39
|
+
}
|
|
40
|
+
catch {
|
|
41
|
+
return {};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Resolve a value with priority: flag → env var → auth.json profile → fallback.
|
|
46
|
+
*/
|
|
47
|
+
function resolveToken(options) {
|
|
48
|
+
if (options.apiKey)
|
|
49
|
+
return options.apiKey;
|
|
50
|
+
const fromEnv = process.env[AGENTICFLOW_API_KEY] ?? process.env[AUTH_ENV_API_KEY];
|
|
51
|
+
if (fromEnv)
|
|
52
|
+
return fromEnv;
|
|
53
|
+
return loadActiveProfile()["api_key"] ?? null;
|
|
54
|
+
}
|
|
55
|
+
function resolveWorkspaceId(explicit) {
|
|
56
|
+
if (explicit)
|
|
57
|
+
return explicit;
|
|
58
|
+
const fromEnv = process.env["AGENTICFLOW_WORKSPACE_ID"];
|
|
59
|
+
if (fromEnv)
|
|
60
|
+
return fromEnv;
|
|
61
|
+
return loadActiveProfile()["workspace_id"] ?? undefined;
|
|
62
|
+
}
|
|
63
|
+
function resolveProjectId(explicit) {
|
|
64
|
+
if (explicit)
|
|
65
|
+
return explicit;
|
|
66
|
+
const fromEnv = process.env["AGENTICFLOW_PROJECT_ID"];
|
|
67
|
+
if (fromEnv)
|
|
68
|
+
return fromEnv;
|
|
69
|
+
return loadActiveProfile()["project_id"] ?? undefined;
|
|
70
|
+
}
|
|
71
|
+
/** Build an SDK client from global CLI options. */
|
|
72
|
+
function buildClient(parentOpts) {
|
|
73
|
+
return createClient({
|
|
74
|
+
apiKey: resolveToken(parentOpts),
|
|
75
|
+
workspaceId: resolveWorkspaceId(parentOpts.workspaceId),
|
|
76
|
+
projectId: resolveProjectId(parentOpts.projectId),
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
/** Wrap an async SDK call with error handling. */
|
|
80
|
+
async function run(fn) {
|
|
81
|
+
try {
|
|
82
|
+
const result = await fn();
|
|
83
|
+
printResult(result);
|
|
84
|
+
}
|
|
85
|
+
catch (err) {
|
|
86
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
87
|
+
process.exit(1);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
91
|
+
// Spec-based helpers (for generic commands: call, ops, catalog, doctor)
|
|
92
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
93
|
+
function loadRegistry(specFile) {
|
|
94
|
+
try {
|
|
95
|
+
const spec = loadOpenapiSpec(specFile);
|
|
96
|
+
return OperationRegistry.fromSpec(spec);
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
console.error(`Warning: Unable to load OpenAPI spec from ${specFile}: ${err}`);
|
|
100
|
+
return null;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
function catalogOperationItem(op) {
|
|
104
|
+
return {
|
|
105
|
+
operation_id: op.operationId,
|
|
106
|
+
method: op.method,
|
|
107
|
+
path: op.path,
|
|
108
|
+
summary: op.summary ?? "",
|
|
109
|
+
tags: op.tags,
|
|
110
|
+
public: isPublic(op),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
// --- Auth helpers ---
|
|
114
|
+
function defaultAuthConfigPath() {
|
|
115
|
+
const envDir = process.env["AGENTICFLOW_CLI_DIR"];
|
|
116
|
+
const dir = envDir ?? resolve(homedir(), ".agenticflow");
|
|
117
|
+
return resolve(dir, "auth.json");
|
|
118
|
+
}
|
|
119
|
+
function loadAuthFile(path) {
|
|
120
|
+
if (!existsSync(path))
|
|
121
|
+
return {};
|
|
122
|
+
try {
|
|
123
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
124
|
+
}
|
|
125
|
+
catch {
|
|
126
|
+
return {};
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
function parseKeyValueEnv(line) {
|
|
130
|
+
const trimmed = line.trim();
|
|
131
|
+
if (!trimmed || trimmed.startsWith("#"))
|
|
132
|
+
return null;
|
|
133
|
+
const idx = trimmed.indexOf("=");
|
|
134
|
+
if (idx === -1)
|
|
135
|
+
return null;
|
|
136
|
+
const key = trimmed.slice(0, idx).trim();
|
|
137
|
+
let value = trimmed.slice(idx + 1).trim();
|
|
138
|
+
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
|
139
|
+
value = value.slice(1, -1);
|
|
140
|
+
}
|
|
141
|
+
return [key, value];
|
|
142
|
+
}
|
|
143
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
144
|
+
// Main program
|
|
145
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
146
|
+
export function createProgram() {
|
|
147
|
+
const program = new Command();
|
|
148
|
+
program
|
|
149
|
+
.name("agenticflow")
|
|
150
|
+
.description("AgenticFlow CLI for agent-native API operations.")
|
|
151
|
+
.version("1.0.0")
|
|
152
|
+
.option("--api-key <key>", "API key for authentication")
|
|
153
|
+
.option("--workspace-id <id>", "Default workspace ID")
|
|
154
|
+
.option("--project-id <id>", "Default project ID")
|
|
155
|
+
.option("--spec-file <path>", "Path to OpenAPI spec JSON file")
|
|
156
|
+
.option("--json", "Force JSON output");
|
|
157
|
+
// ═════════════════════════════════════════════════════════════════
|
|
158
|
+
// doctor
|
|
159
|
+
// ═════════════════════════════════════════════════════════════════
|
|
160
|
+
program
|
|
161
|
+
.command("doctor")
|
|
162
|
+
.description("Preflight checks for CLI configuration and connectivity.")
|
|
163
|
+
.option("--json", "JSON output")
|
|
164
|
+
.action(async (opts) => {
|
|
165
|
+
const parentOpts = program.opts();
|
|
166
|
+
const baseUrl = DEFAULT_BASE_URL;
|
|
167
|
+
const token = resolveToken(parentOpts);
|
|
168
|
+
const wsId = resolveWorkspaceId(parentOpts.workspaceId);
|
|
169
|
+
const projId = resolveProjectId(parentOpts.projectId);
|
|
170
|
+
const specFile = parentOpts.specFile ?? defaultSpecPath();
|
|
171
|
+
const registry = loadRegistry(specFile);
|
|
172
|
+
const configPath = defaultAuthConfigPath();
|
|
173
|
+
const configExists = existsSync(configPath);
|
|
174
|
+
const tokenSource = parentOpts.apiKey ? "flag" : (process.env[AUTH_ENV_API_KEY] ? "env" : (configExists ? "config" : "none"));
|
|
175
|
+
// Health check
|
|
176
|
+
let healthOk = false;
|
|
177
|
+
let healthStatus = 0;
|
|
178
|
+
let healthError = "";
|
|
179
|
+
try {
|
|
180
|
+
const response = await fetch(`${baseUrl.replace(/\/+$/, "")}/v1/health`);
|
|
181
|
+
healthOk = response.ok;
|
|
182
|
+
healthStatus = response.status;
|
|
183
|
+
}
|
|
184
|
+
catch (err) {
|
|
185
|
+
healthError = err instanceof Error ? err.message : String(err);
|
|
186
|
+
}
|
|
187
|
+
const checks = {
|
|
188
|
+
config: configExists,
|
|
189
|
+
token: !!token,
|
|
190
|
+
tokenSource,
|
|
191
|
+
workspaceId: wsId ?? null,
|
|
192
|
+
projectId: projId ?? null,
|
|
193
|
+
baseUrl,
|
|
194
|
+
health: healthOk,
|
|
195
|
+
healthStatus,
|
|
196
|
+
healthError,
|
|
197
|
+
specFile,
|
|
198
|
+
operationsLoaded: registry?.listOperations().length ?? 0,
|
|
199
|
+
};
|
|
200
|
+
if (opts.json || parentOpts.json) {
|
|
201
|
+
printJson({ schema: DOCTOR_SCHEMA_VERSION, ...checks });
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
const ok = (v) => v ? "✓" : "✗";
|
|
205
|
+
const dim = (s) => `\x1b[2m${s}\x1b[0m`;
|
|
206
|
+
console.log("");
|
|
207
|
+
console.log(" Environment");
|
|
208
|
+
console.log(` └ Version: ${program.version()}`);
|
|
209
|
+
console.log(` └ Node.js: ${process.version}`);
|
|
210
|
+
console.log(` └ Platform: ${process.platform} ${process.arch}`);
|
|
211
|
+
console.log("");
|
|
212
|
+
console.log(" Authentication");
|
|
213
|
+
console.log(` └ API Key: ${token ? `${ok(true)} present ${dim(`(source: ${tokenSource})`)}` : `${ok(false)} not set`}`);
|
|
214
|
+
console.log(` └ Workspace ID: ${wsId ?? "not set"}`);
|
|
215
|
+
console.log(` └ Project ID: ${projId ?? "not set"}`);
|
|
216
|
+
console.log(` └ Config: ${configExists ? configPath : `${ok(false)} not found`}`);
|
|
217
|
+
console.log("");
|
|
218
|
+
console.log(" API Connectivity");
|
|
219
|
+
console.log(` └ Base URL: ${baseUrl}`);
|
|
220
|
+
console.log(` └ Health: ${healthOk ? `${ok(true)} reachable ${dim(`(HTTP ${healthStatus})`)}` : `${ok(false)} ${healthError || `HTTP ${healthStatus}`}`}`);
|
|
221
|
+
console.log("");
|
|
222
|
+
console.log(" OpenAPI Spec");
|
|
223
|
+
console.log(` └ Spec file: ${registry ? ok(true) : ok(false)} ${specFile}`);
|
|
224
|
+
console.log(` └ Operations: ${checks.operationsLoaded} loaded`);
|
|
225
|
+
console.log("");
|
|
226
|
+
}
|
|
227
|
+
});
|
|
228
|
+
// ═════════════════════════════════════════════════════════════════
|
|
229
|
+
// ops
|
|
230
|
+
// ═════════════════════════════════════════════════════════════════
|
|
231
|
+
const opsCmd = program
|
|
232
|
+
.command("ops")
|
|
233
|
+
.description("OpenAPI operation discovery.");
|
|
234
|
+
opsCmd
|
|
235
|
+
.command("list")
|
|
236
|
+
.description("List available operations.")
|
|
237
|
+
.option("--public-only", "Show only public operations")
|
|
238
|
+
.option("--tag <tag>", "Filter by tag")
|
|
239
|
+
.action((opts) => {
|
|
240
|
+
const parentOpts = program.opts();
|
|
241
|
+
const specFile = parentOpts.specFile ?? defaultSpecPath();
|
|
242
|
+
const registry = loadRegistry(specFile);
|
|
243
|
+
if (!registry) {
|
|
244
|
+
console.error("Failed to load OpenAPI spec.");
|
|
245
|
+
process.exit(1);
|
|
246
|
+
}
|
|
247
|
+
const operations = registry.listOperations({ publicOnly: opts.publicOnly, tag: opts.tag });
|
|
248
|
+
console.log(`${operations.length} operations found:\n`);
|
|
249
|
+
for (const op of operations) {
|
|
250
|
+
console.log(` ${op.method.padEnd(7)} ${op.path}`);
|
|
251
|
+
console.log(` ${op.operationId}`);
|
|
252
|
+
}
|
|
253
|
+
});
|
|
254
|
+
opsCmd
|
|
255
|
+
.command("show <operationId>")
|
|
256
|
+
.description("Show details for a specific operation.")
|
|
257
|
+
.action((operationId) => {
|
|
258
|
+
const parentOpts = program.opts();
|
|
259
|
+
const specFile = parentOpts.specFile ?? defaultSpecPath();
|
|
260
|
+
const registry = loadRegistry(specFile);
|
|
261
|
+
if (!registry) {
|
|
262
|
+
console.error("Failed to load OpenAPI spec.");
|
|
263
|
+
process.exit(1);
|
|
264
|
+
}
|
|
265
|
+
const operation = registry.getOperationById(operationId);
|
|
266
|
+
if (!operation) {
|
|
267
|
+
console.error(`Operation not found: ${operationId}`);
|
|
268
|
+
process.exit(1);
|
|
269
|
+
}
|
|
270
|
+
printJson(catalogOperationItem(operation));
|
|
271
|
+
});
|
|
272
|
+
// ═════════════════════════════════════════════════════════════════
|
|
273
|
+
// catalog
|
|
274
|
+
// ═════════════════════════════════════════════════════════════════
|
|
275
|
+
const catalogCmd = program
|
|
276
|
+
.command("catalog")
|
|
277
|
+
.description("Operation catalog tools.");
|
|
278
|
+
catalogCmd
|
|
279
|
+
.command("export")
|
|
280
|
+
.description("Export operation catalog.")
|
|
281
|
+
.option("--public-only", "Export only public operations")
|
|
282
|
+
.option("--json", "JSON output")
|
|
283
|
+
.action((opts) => {
|
|
284
|
+
const parentOpts = program.opts();
|
|
285
|
+
const specFile = parentOpts.specFile ?? defaultSpecPath();
|
|
286
|
+
const registry = loadRegistry(specFile);
|
|
287
|
+
if (!registry) {
|
|
288
|
+
console.error("Failed to load OpenAPI spec.");
|
|
289
|
+
process.exit(1);
|
|
290
|
+
}
|
|
291
|
+
const operations = registry.listOperations({ publicOnly: opts.publicOnly });
|
|
292
|
+
const items = operations.map(catalogOperationItem);
|
|
293
|
+
if (opts.json || parentOpts.json) {
|
|
294
|
+
printJson({ schema: CATALOG_EXPORT_SCHEMA_VERSION, count: items.length, operations: items });
|
|
295
|
+
}
|
|
296
|
+
else {
|
|
297
|
+
for (const item of items) {
|
|
298
|
+
console.log(`${item["method"].padEnd(7)} ${item["path"]} ${item["operation_id"]}`);
|
|
299
|
+
}
|
|
300
|
+
console.log(`\n${items.length} operations.`);
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
catalogCmd
|
|
304
|
+
.command("rank")
|
|
305
|
+
.description("Rank operations for a task.")
|
|
306
|
+
.requiredOption("--task <task>", "Task description")
|
|
307
|
+
.option("--public-only", "Only public operations")
|
|
308
|
+
.option("--json", "JSON output")
|
|
309
|
+
.option("--top <n>", "Top N results", "10")
|
|
310
|
+
.action((opts) => {
|
|
311
|
+
const parentOpts = program.opts();
|
|
312
|
+
const specFile = parentOpts.specFile ?? defaultSpecPath();
|
|
313
|
+
const registry = loadRegistry(specFile);
|
|
314
|
+
if (!registry) {
|
|
315
|
+
console.error("Failed to load OpenAPI spec.");
|
|
316
|
+
process.exit(1);
|
|
317
|
+
}
|
|
318
|
+
const operations = registry.listOperations({ publicOnly: opts.publicOnly });
|
|
319
|
+
const task = opts.task.toLowerCase();
|
|
320
|
+
const taskTerms = [...new Set(task.split(/\s+/))];
|
|
321
|
+
const scored = operations.map((op) => {
|
|
322
|
+
const text = [op.operationId, op.summary ?? "", op.description ?? "", ...op.tags, op.method, op.path].join(" ").toLowerCase();
|
|
323
|
+
let score = 0;
|
|
324
|
+
for (const term of taskTerms) {
|
|
325
|
+
if (text.includes(term))
|
|
326
|
+
score += 1;
|
|
327
|
+
}
|
|
328
|
+
return { op, score };
|
|
329
|
+
});
|
|
330
|
+
scored.sort((a, b) => b.score - a.score);
|
|
331
|
+
const top = scored.slice(0, parseInt(opts.top, 10));
|
|
332
|
+
if (opts.json || parentOpts.json) {
|
|
333
|
+
printJson({
|
|
334
|
+
schema: CATALOG_RANK_SCHEMA_VERSION,
|
|
335
|
+
task: opts.task,
|
|
336
|
+
results: top.map((r) => ({ ...catalogOperationItem(r.op), score: r.score })),
|
|
337
|
+
});
|
|
338
|
+
}
|
|
339
|
+
else {
|
|
340
|
+
for (const r of top) {
|
|
341
|
+
console.log(`[${r.score}] ${r.op.method.padEnd(7)} ${r.op.path} ${r.op.operationId}`);
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
});
|
|
345
|
+
// ═════════════════════════════════════════════════════════════════
|
|
346
|
+
// playbook
|
|
347
|
+
// ═════════════════════════════════════════════════════════════════
|
|
348
|
+
program
|
|
349
|
+
.command("playbook [topic]")
|
|
350
|
+
.description("View built-in playbooks for AgenticFlow workflows.")
|
|
351
|
+
.option("--list", "List available playbooks")
|
|
352
|
+
.action((topic, opts) => {
|
|
353
|
+
if (opts.list || !topic) {
|
|
354
|
+
const playbooks = listPlaybooks();
|
|
355
|
+
for (const pb of playbooks) {
|
|
356
|
+
console.log(` ${pb.topic.padEnd(20)} ${pb.title} — ${pb.summary}`);
|
|
357
|
+
}
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
const pb = getPlaybook(topic);
|
|
361
|
+
if (!pb) {
|
|
362
|
+
console.error(`Playbook not found: ${topic}`);
|
|
363
|
+
process.exit(1);
|
|
364
|
+
}
|
|
365
|
+
console.log(`# ${pb.title}\n`);
|
|
366
|
+
console.log(pb.content);
|
|
367
|
+
});
|
|
368
|
+
// ═════════════════════════════════════════════════════════════════
|
|
369
|
+
// login (top-level)
|
|
370
|
+
// ═════════════════════════════════════════════════════════════════
|
|
371
|
+
program
|
|
372
|
+
.command("login")
|
|
373
|
+
.description("Interactively configure your credentials.")
|
|
374
|
+
.option("--profile <profile>", "Profile name", "default")
|
|
375
|
+
.action(async (opts) => {
|
|
376
|
+
const parentOpts = program.opts();
|
|
377
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
378
|
+
const ask = (q) => new Promise((res) => rl.question(q, (a) => res(a.trim())));
|
|
379
|
+
console.log("\n🔑 AgenticFlow Login\n");
|
|
380
|
+
const apiKey = parentOpts.apiKey || await ask(" API Key: ");
|
|
381
|
+
if (!apiKey) {
|
|
382
|
+
console.error("\n✗ API key is required.");
|
|
383
|
+
rl.close();
|
|
384
|
+
process.exit(1);
|
|
385
|
+
}
|
|
386
|
+
if (parentOpts.apiKey)
|
|
387
|
+
console.log(" API Key: ••••••••");
|
|
388
|
+
const workspaceId = parentOpts.workspaceId || await ask(" Workspace ID: ");
|
|
389
|
+
if (parentOpts.workspaceId)
|
|
390
|
+
console.log(` Workspace ID: ${parentOpts.workspaceId}`);
|
|
391
|
+
const projectId = parentOpts.projectId || await ask(" Project ID: ");
|
|
392
|
+
if (parentOpts.projectId)
|
|
393
|
+
console.log(` Project ID: ${parentOpts.projectId}`);
|
|
394
|
+
rl.close();
|
|
395
|
+
// Validate the API key by calling the health endpoint
|
|
396
|
+
console.log("\n Verifying credentials...");
|
|
397
|
+
try {
|
|
398
|
+
const client = createClient({ apiKey });
|
|
399
|
+
await client.sdk.get("/health");
|
|
400
|
+
console.log(" ✓ API key is valid.\n");
|
|
401
|
+
}
|
|
402
|
+
catch {
|
|
403
|
+
console.error(" ✗ Could not verify API key. Saving anyway.\n");
|
|
404
|
+
}
|
|
405
|
+
const configPath = defaultAuthConfigPath();
|
|
406
|
+
const config = loadAuthFile(configPath);
|
|
407
|
+
const profiles = config["profiles"] ?? {};
|
|
408
|
+
const profile = { api_key: apiKey };
|
|
409
|
+
if (workspaceId)
|
|
410
|
+
profile["workspace_id"] = workspaceId;
|
|
411
|
+
if (projectId)
|
|
412
|
+
profile["project_id"] = projectId;
|
|
413
|
+
profiles[opts.profile] = profile;
|
|
414
|
+
if (!config["default_profile"])
|
|
415
|
+
config["default_profile"] = opts.profile;
|
|
416
|
+
config["profiles"] = profiles;
|
|
417
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
418
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
419
|
+
console.log(`Saved to profile '${opts.profile}' at ${configPath}`);
|
|
420
|
+
});
|
|
421
|
+
// ═════════════════════════════════════════════════════════════════
|
|
422
|
+
// logout (top-level)
|
|
423
|
+
// ═════════════════════════════════════════════════════════════════
|
|
424
|
+
program
|
|
425
|
+
.command("logout")
|
|
426
|
+
.description("Remove saved credentials.")
|
|
427
|
+
.option("--profile <profile>", "Profile to remove (default: all)")
|
|
428
|
+
.option("-y, --yes", "Skip confirmation")
|
|
429
|
+
.action(async (opts) => {
|
|
430
|
+
const configPath = defaultAuthConfigPath();
|
|
431
|
+
if (!existsSync(configPath)) {
|
|
432
|
+
console.log("No credentials found. Already logged out.");
|
|
433
|
+
return;
|
|
434
|
+
}
|
|
435
|
+
if (!opts.yes) {
|
|
436
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
437
|
+
const answer = await new Promise((res) => rl.question(opts.profile
|
|
438
|
+
? `Remove profile '${opts.profile}'? (y/N) `
|
|
439
|
+
: "Remove all saved credentials? (y/N) ", (a) => { res(a.trim().toLowerCase()); rl.close(); }));
|
|
440
|
+
if (answer !== "y" && answer !== "yes") {
|
|
441
|
+
console.log("Cancelled.");
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
if (opts.profile) {
|
|
446
|
+
// Remove a single profile
|
|
447
|
+
const config = loadAuthFile(configPath);
|
|
448
|
+
const profiles = config["profiles"];
|
|
449
|
+
if (profiles && opts.profile in profiles) {
|
|
450
|
+
delete profiles[opts.profile];
|
|
451
|
+
if (config["default_profile"] === opts.profile) {
|
|
452
|
+
const remaining = Object.keys(profiles);
|
|
453
|
+
config["default_profile"] = remaining[0] ?? "default";
|
|
454
|
+
}
|
|
455
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
456
|
+
console.log(`✓ Removed profile '${opts.profile}'.`);
|
|
457
|
+
}
|
|
458
|
+
else {
|
|
459
|
+
console.log(`Profile '${opts.profile}' not found.`);
|
|
460
|
+
}
|
|
461
|
+
}
|
|
462
|
+
else {
|
|
463
|
+
// Remove the entire auth file
|
|
464
|
+
unlinkSync(configPath);
|
|
465
|
+
console.log(`✓ Removed ${configPath}`);
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
// ═════════════════════════════════════════════════════════════════
|
|
469
|
+
// whoami (top-level)
|
|
470
|
+
// ═════════════════════════════════════════════════════════════════
|
|
471
|
+
program
|
|
472
|
+
.command("whoami")
|
|
473
|
+
.description("Show current authentication state.")
|
|
474
|
+
.option("--json", "JSON output")
|
|
475
|
+
.action((opts) => {
|
|
476
|
+
const parentOpts = program.opts();
|
|
477
|
+
const token = resolveToken(parentOpts);
|
|
478
|
+
const wsId = resolveWorkspaceId(parentOpts.workspaceId);
|
|
479
|
+
const projId = resolveProjectId(parentOpts.projectId);
|
|
480
|
+
const configPath = defaultAuthConfigPath();
|
|
481
|
+
const config = loadAuthFile(configPath);
|
|
482
|
+
const profileName = config["default_profile"] ?? "default";
|
|
483
|
+
const result = {
|
|
484
|
+
profile: profileName,
|
|
485
|
+
api_key_present: !!token,
|
|
486
|
+
workspace_id: wsId ?? "not set",
|
|
487
|
+
project_id: projId ?? "not set",
|
|
488
|
+
config_path: configPath,
|
|
489
|
+
};
|
|
490
|
+
if (opts.json || parentOpts.json) {
|
|
491
|
+
printJson(result);
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
console.log(`Profile: ${result.profile}`);
|
|
495
|
+
console.log(`API Key: ${result.api_key_present ? "present" : "not set"}`);
|
|
496
|
+
console.log(`Workspace ID: ${result.workspace_id}`);
|
|
497
|
+
console.log(`Project ID: ${result.project_id}`);
|
|
498
|
+
console.log(`Config: ${result.config_path}`);
|
|
499
|
+
}
|
|
500
|
+
});
|
|
501
|
+
// ═════════════════════════════════════════════════════════════════
|
|
502
|
+
// auth (import-env stays here)
|
|
503
|
+
// ═════════════════════════════════════════════════════════════════
|
|
504
|
+
const authCmd = program
|
|
505
|
+
.command("auth")
|
|
506
|
+
.description("Authentication management.");
|
|
507
|
+
authCmd
|
|
508
|
+
.command("import-env")
|
|
509
|
+
.description("Import credentials from an env file.")
|
|
510
|
+
.requiredOption("--file <path>", "Path to .env file")
|
|
511
|
+
.option("--profile <profile>", "Profile name", "default")
|
|
512
|
+
.action((opts) => {
|
|
513
|
+
const envPath = resolve(opts.file);
|
|
514
|
+
if (!existsSync(envPath)) {
|
|
515
|
+
console.error(`File not found: ${envPath}`);
|
|
516
|
+
process.exit(1);
|
|
517
|
+
}
|
|
518
|
+
const content = readFileSync(envPath, "utf-8");
|
|
519
|
+
const env = {};
|
|
520
|
+
for (const line of content.split("\n")) {
|
|
521
|
+
const parsed = parseKeyValueEnv(line);
|
|
522
|
+
if (parsed)
|
|
523
|
+
env[parsed[0]] = parsed[1];
|
|
524
|
+
}
|
|
525
|
+
const apiKey = env["AGENTICFLOW_API_KEY"] ?? env["AGENTICFLOW_PUBLIC_API_KEY"];
|
|
526
|
+
const workspaceId = env["AGENTICFLOW_WORKSPACE_ID"];
|
|
527
|
+
const projectId = env["AGENTICFLOW_PROJECT_ID"];
|
|
528
|
+
if (!apiKey) {
|
|
529
|
+
console.error("No AGENTICFLOW_API_KEY found in env file.");
|
|
530
|
+
process.exit(1);
|
|
531
|
+
}
|
|
532
|
+
const configPath = defaultAuthConfigPath();
|
|
533
|
+
const config = loadAuthFile(configPath);
|
|
534
|
+
const profiles = config["profiles"] ?? {};
|
|
535
|
+
const profile = { api_key: apiKey };
|
|
536
|
+
if (workspaceId)
|
|
537
|
+
profile["workspace_id"] = workspaceId;
|
|
538
|
+
if (projectId)
|
|
539
|
+
profile["project_id"] = projectId;
|
|
540
|
+
profiles[opts.profile] = profile;
|
|
541
|
+
if (!config["default_profile"])
|
|
542
|
+
config["default_profile"] = opts.profile;
|
|
543
|
+
config["profiles"] = profiles;
|
|
544
|
+
mkdirSync(dirname(configPath), { recursive: true });
|
|
545
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n", "utf-8");
|
|
546
|
+
console.log(`Imported credentials to profile '${opts.profile}' at ${configPath}`);
|
|
547
|
+
});
|
|
548
|
+
// ═════════════════════════════════════════════════════════════════
|
|
549
|
+
// policy
|
|
550
|
+
// ═════════════════════════════════════════════════════════════════
|
|
551
|
+
const policyCmd = program
|
|
552
|
+
.command("policy")
|
|
553
|
+
.description("Local policy guardrails management.");
|
|
554
|
+
policyCmd
|
|
555
|
+
.command("show")
|
|
556
|
+
.description("Show current policy configuration.")
|
|
557
|
+
.option("--json", "JSON output")
|
|
558
|
+
.action((opts) => {
|
|
559
|
+
const parentOpts = program.opts();
|
|
560
|
+
try {
|
|
561
|
+
const policy = loadPolicy();
|
|
562
|
+
const filePath = policyFilePath();
|
|
563
|
+
if (opts.json || parentOpts.json) {
|
|
564
|
+
printJson({ file: filePath, ...policy });
|
|
565
|
+
}
|
|
566
|
+
else {
|
|
567
|
+
console.log(`Policy file: ${filePath}`);
|
|
568
|
+
console.log(`Spend ceiling: ${policy.spendCeiling ?? "none"}`);
|
|
569
|
+
console.log(`Allowlist: ${policy.allowlist.length > 0 ? policy.allowlist.join(", ") : "none"}`);
|
|
570
|
+
console.log(`Blocklist: ${policy.blocklist.length > 0 ? policy.blocklist.join(", ") : "none"}`);
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
catch (err) {
|
|
574
|
+
console.error(`Policy error: ${err instanceof Error ? err.message : err}`);
|
|
575
|
+
process.exit(1);
|
|
576
|
+
}
|
|
577
|
+
});
|
|
578
|
+
policyCmd
|
|
579
|
+
.command("init")
|
|
580
|
+
.description("Initialize default policy file.")
|
|
581
|
+
.option("--force", "Overwrite existing policy file")
|
|
582
|
+
.option("--spend-ceiling <amount>", "Set spend ceiling")
|
|
583
|
+
.action((opts) => {
|
|
584
|
+
try {
|
|
585
|
+
const filePath = writeDefaultPolicy({
|
|
586
|
+
force: opts.force,
|
|
587
|
+
spendCeiling: opts.spendCeiling ? parseFloat(opts.spendCeiling) : undefined,
|
|
588
|
+
});
|
|
589
|
+
console.log(`Policy file created: ${filePath}`);
|
|
590
|
+
}
|
|
591
|
+
catch (err) {
|
|
592
|
+
console.error(`Error: ${err instanceof Error ? err.message : err}`);
|
|
593
|
+
process.exit(1);
|
|
594
|
+
}
|
|
595
|
+
});
|
|
596
|
+
// ═════════════════════════════════════════════════════════════════
|
|
597
|
+
// call (generic, spec-based)
|
|
598
|
+
// ═════════════════════════════════════════════════════════════════
|
|
599
|
+
program
|
|
600
|
+
.command("call")
|
|
601
|
+
.description("Low-level OpenAPI transport — execute an operation directly.")
|
|
602
|
+
.option("--operation-id <id>", "Operation ID to invoke")
|
|
603
|
+
.option("--method <method>", "HTTP method")
|
|
604
|
+
.option("--path <path>", "API path")
|
|
605
|
+
.option("-P, --path-param <params...>", "Path parameters (key=value)")
|
|
606
|
+
.option("-Q, --query-param <params...>", "Query parameters (key=value)")
|
|
607
|
+
.option("-H, --header <headers...>", "Extra headers (key=value)")
|
|
608
|
+
.option("--body <body>", "JSON body (inline or @file)")
|
|
609
|
+
.option("--dry-run", "Show request without executing")
|
|
610
|
+
.action(async (opts) => {
|
|
611
|
+
const parentOpts = program.opts();
|
|
612
|
+
const baseUrl = DEFAULT_BASE_URL;
|
|
613
|
+
const token = resolveToken(parentOpts);
|
|
614
|
+
const specFile = parentOpts.specFile ?? defaultSpecPath();
|
|
615
|
+
const registry = loadRegistry(specFile);
|
|
616
|
+
if (!registry) {
|
|
617
|
+
console.error("Failed to load OpenAPI spec.");
|
|
618
|
+
process.exit(1);
|
|
619
|
+
}
|
|
620
|
+
// Resolve operation
|
|
621
|
+
let operation = null;
|
|
622
|
+
if (opts.operationId) {
|
|
623
|
+
operation = registry.getOperationById(opts.operationId);
|
|
624
|
+
}
|
|
625
|
+
else if (opts.method && opts.path) {
|
|
626
|
+
operation = registry.getOperationByMethodPath(opts.method, opts.path);
|
|
627
|
+
}
|
|
628
|
+
if (!operation && opts.method && opts.path) {
|
|
629
|
+
operation = {
|
|
630
|
+
operationId: `${opts.method.toLowerCase()}_${opts.path.replace(/^\//, "").replace(/\//g, "_")}`,
|
|
631
|
+
method: opts.method.toUpperCase(),
|
|
632
|
+
path: opts.path,
|
|
633
|
+
tags: [], security: [], parameters: [],
|
|
634
|
+
requestBody: null, summary: null, description: null, raw: {},
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
if (!operation) {
|
|
638
|
+
console.error("Unable to resolve operation.");
|
|
639
|
+
process.exit(1);
|
|
640
|
+
}
|
|
641
|
+
const pathParams = opts.pathParam ? parseKeyValuePairs(opts.pathParam) : {};
|
|
642
|
+
const queryParams = opts.queryParam ? parseKeyValuePairs(opts.queryParam) : {};
|
|
643
|
+
const headers = opts.header ? parseKeyValuePairs(opts.header) : {};
|
|
644
|
+
const body = opts.body ? loadJsonPayload(opts.body) : undefined;
|
|
645
|
+
const requestSpec = buildRequestSpec(operation, baseUrl, pathParams, queryParams, headers, token, body);
|
|
646
|
+
if (opts.dryRun) {
|
|
647
|
+
printJson({
|
|
648
|
+
dry_run: true,
|
|
649
|
+
operation_id: operation.operationId,
|
|
650
|
+
method: requestSpec.method,
|
|
651
|
+
url: requestSpec.url,
|
|
652
|
+
params: requestSpec.params,
|
|
653
|
+
headers: Object.fromEntries(Object.entries(requestSpec.headers).map(([k, v]) => k.toLowerCase() === "authorization" ? [k, "Bearer ***"] : [k, v])),
|
|
654
|
+
body: requestSpec.body ?? null,
|
|
655
|
+
});
|
|
656
|
+
return;
|
|
657
|
+
}
|
|
658
|
+
// Execute request
|
|
659
|
+
try {
|
|
660
|
+
const response = await fetch(requestSpec.url + (Object.keys(requestSpec.params).length > 0
|
|
661
|
+
? "?" + new URLSearchParams(requestSpec.params).toString()
|
|
662
|
+
: ""), {
|
|
663
|
+
method: requestSpec.method,
|
|
664
|
+
headers: requestSpec.headers,
|
|
665
|
+
body: requestSpec.body != null ? JSON.stringify(requestSpec.body) : undefined,
|
|
666
|
+
});
|
|
667
|
+
const text = await response.text();
|
|
668
|
+
let data;
|
|
669
|
+
try {
|
|
670
|
+
data = JSON.parse(text);
|
|
671
|
+
}
|
|
672
|
+
catch {
|
|
673
|
+
data = text;
|
|
674
|
+
}
|
|
675
|
+
printJson({ status: response.status, body: data });
|
|
676
|
+
if (!response.ok)
|
|
677
|
+
process.exitCode = 1;
|
|
678
|
+
}
|
|
679
|
+
catch (err) {
|
|
680
|
+
console.error(`Request failed: ${err instanceof Error ? err.message : err}`);
|
|
681
|
+
process.exit(1);
|
|
682
|
+
}
|
|
683
|
+
});
|
|
684
|
+
// ═════════════════════════════════════════════════════════════════
|
|
685
|
+
// workflow (SDK-based)
|
|
686
|
+
// ═════════════════════════════════════════════════════════════════
|
|
687
|
+
const workflowCmd = program
|
|
688
|
+
.command("workflow")
|
|
689
|
+
.description("Workflow management commands.");
|
|
690
|
+
workflowCmd
|
|
691
|
+
.command("list")
|
|
692
|
+
.description("List workflows.")
|
|
693
|
+
.option("--workspace-id <id>", "Workspace ID (overrides global)")
|
|
694
|
+
.option("--project-id <id>", "Project ID")
|
|
695
|
+
.option("--search <query>", "Search query")
|
|
696
|
+
.option("--limit <n>", "Limit results")
|
|
697
|
+
.option("--offset <n>", "Offset")
|
|
698
|
+
.action(async (opts) => {
|
|
699
|
+
const client = buildClient(program.opts());
|
|
700
|
+
await run(() => client.workflows.list({
|
|
701
|
+
workspaceId: opts.workspaceId,
|
|
702
|
+
projectId: opts.projectId,
|
|
703
|
+
searchQuery: opts.search,
|
|
704
|
+
limit: opts.limit ? parseInt(opts.limit) : undefined,
|
|
705
|
+
offset: opts.offset ? parseInt(opts.offset) : undefined,
|
|
706
|
+
}));
|
|
707
|
+
});
|
|
708
|
+
workflowCmd
|
|
709
|
+
.command("get")
|
|
710
|
+
.description("Get a workflow by ID.")
|
|
711
|
+
.requiredOption("--workflow-id <id>", "Workflow ID")
|
|
712
|
+
.action(async (opts) => {
|
|
713
|
+
const client = buildClient(program.opts());
|
|
714
|
+
const token = resolveToken(program.opts());
|
|
715
|
+
if (token) {
|
|
716
|
+
await run(() => client.workflows.get(opts.workflowId));
|
|
717
|
+
}
|
|
718
|
+
else {
|
|
719
|
+
await run(() => client.workflows.getAnonymous(opts.workflowId));
|
|
720
|
+
}
|
|
721
|
+
});
|
|
722
|
+
workflowCmd
|
|
723
|
+
.command("create")
|
|
724
|
+
.description("Create a new workflow.")
|
|
725
|
+
.option("--workspace-id <id>", "Workspace ID")
|
|
726
|
+
.requiredOption("--body <body>", "JSON body (inline or @file)")
|
|
727
|
+
.action(async (opts) => {
|
|
728
|
+
const client = buildClient(program.opts());
|
|
729
|
+
const body = loadJsonPayload(opts.body);
|
|
730
|
+
await run(() => client.workflows.create(body, opts.workspaceId));
|
|
731
|
+
});
|
|
732
|
+
workflowCmd
|
|
733
|
+
.command("update")
|
|
734
|
+
.description("Update a workflow.")
|
|
735
|
+
.option("--workspace-id <id>", "Workspace ID")
|
|
736
|
+
.requiredOption("--workflow-id <id>", "Workflow ID")
|
|
737
|
+
.requiredOption("--body <body>", "JSON body (inline or @file)")
|
|
738
|
+
.action(async (opts) => {
|
|
739
|
+
const client = buildClient(program.opts());
|
|
740
|
+
const body = loadJsonPayload(opts.body);
|
|
741
|
+
await run(() => client.workflows.update(opts.workflowId, body, opts.workspaceId));
|
|
742
|
+
});
|
|
743
|
+
workflowCmd
|
|
744
|
+
.command("delete")
|
|
745
|
+
.description("Delete a workflow.")
|
|
746
|
+
.option("--workspace-id <id>", "Workspace ID")
|
|
747
|
+
.requiredOption("--workflow-id <id>", "Workflow ID")
|
|
748
|
+
.action(async (opts) => {
|
|
749
|
+
const client = buildClient(program.opts());
|
|
750
|
+
await run(() => client.workflows.delete(opts.workflowId, opts.workspaceId));
|
|
751
|
+
});
|
|
752
|
+
workflowCmd
|
|
753
|
+
.command("run")
|
|
754
|
+
.description("Run a workflow.")
|
|
755
|
+
.requiredOption("--workflow-id <id>", "Workflow ID")
|
|
756
|
+
.option("--input <input>", "JSON input (inline or @file)")
|
|
757
|
+
.action(async (opts) => {
|
|
758
|
+
const client = buildClient(program.opts());
|
|
759
|
+
const token = resolveToken(program.opts());
|
|
760
|
+
const body = { workflow_id: opts.workflowId };
|
|
761
|
+
if (opts.input)
|
|
762
|
+
body["input"] = loadJsonPayload(opts.input);
|
|
763
|
+
if (token) {
|
|
764
|
+
await run(() => client.workflows.run(body));
|
|
765
|
+
}
|
|
766
|
+
else {
|
|
767
|
+
await run(() => client.workflows.runAnonymous(body));
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
workflowCmd
|
|
771
|
+
.command("run-status")
|
|
772
|
+
.description("Get workflow run status.")
|
|
773
|
+
.requiredOption("--workflow-run-id <id>", "Workflow run ID")
|
|
774
|
+
.action(async (opts) => {
|
|
775
|
+
const client = buildClient(program.opts());
|
|
776
|
+
const token = resolveToken(program.opts());
|
|
777
|
+
if (token) {
|
|
778
|
+
await run(() => client.workflows.getRun(opts.workflowRunId));
|
|
779
|
+
}
|
|
780
|
+
else {
|
|
781
|
+
await run(() => client.workflows.getRunAnonymous(opts.workflowRunId));
|
|
782
|
+
}
|
|
783
|
+
});
|
|
784
|
+
workflowCmd
|
|
785
|
+
.command("list-runs")
|
|
786
|
+
.description("List runs for a workflow.")
|
|
787
|
+
.requiredOption("--workflow-id <id>", "Workflow ID")
|
|
788
|
+
.option("--workspace-id <id>", "Workspace ID")
|
|
789
|
+
.option("--limit <n>", "Limit")
|
|
790
|
+
.option("--offset <n>", "Offset")
|
|
791
|
+
.option("--sort-order <order>", "Sort order (asc|desc)")
|
|
792
|
+
.action(async (opts) => {
|
|
793
|
+
const client = buildClient(program.opts());
|
|
794
|
+
await run(() => client.workflows.listRuns(opts.workflowId, {
|
|
795
|
+
workspaceId: opts.workspaceId,
|
|
796
|
+
limit: opts.limit ? parseInt(opts.limit) : undefined,
|
|
797
|
+
offset: opts.offset ? parseInt(opts.offset) : undefined,
|
|
798
|
+
sortOrder: opts.sortOrder,
|
|
799
|
+
}));
|
|
800
|
+
});
|
|
801
|
+
workflowCmd
|
|
802
|
+
.command("validate")
|
|
803
|
+
.description("Validate a workflow payload.")
|
|
804
|
+
.requiredOption("--body <body>", "JSON body (inline or @file)")
|
|
805
|
+
.action(async (opts) => {
|
|
806
|
+
const client = buildClient(program.opts());
|
|
807
|
+
const body = loadJsonPayload(opts.body);
|
|
808
|
+
await run(() => client.workflows.validate(body));
|
|
809
|
+
});
|
|
810
|
+
workflowCmd
|
|
811
|
+
.command("run-history")
|
|
812
|
+
.description("Get run history for a workflow.")
|
|
813
|
+
.requiredOption("--workflow-id <id>", "Workflow ID")
|
|
814
|
+
.option("--limit <n>", "Limit")
|
|
815
|
+
.option("--offset <n>", "Offset")
|
|
816
|
+
.action(async (opts) => {
|
|
817
|
+
const client = buildClient(program.opts());
|
|
818
|
+
await run(() => client.workflows.runHistory(opts.workflowId, {
|
|
819
|
+
limit: opts.limit ? parseInt(opts.limit) : undefined,
|
|
820
|
+
offset: opts.offset ? parseInt(opts.offset) : undefined,
|
|
821
|
+
}));
|
|
822
|
+
});
|
|
823
|
+
workflowCmd
|
|
824
|
+
.command("like")
|
|
825
|
+
.description("Like a workflow.")
|
|
826
|
+
.requiredOption("--workflow-id <id>", "Workflow ID")
|
|
827
|
+
.action(async (opts) => {
|
|
828
|
+
const client = buildClient(program.opts());
|
|
829
|
+
await run(() => client.workflows.like(opts.workflowId));
|
|
830
|
+
});
|
|
831
|
+
workflowCmd
|
|
832
|
+
.command("unlike")
|
|
833
|
+
.description("Unlike a workflow.")
|
|
834
|
+
.requiredOption("--workflow-id <id>", "Workflow ID")
|
|
835
|
+
.action(async (opts) => {
|
|
836
|
+
const client = buildClient(program.opts());
|
|
837
|
+
await run(() => client.workflows.unlike(opts.workflowId));
|
|
838
|
+
});
|
|
839
|
+
workflowCmd
|
|
840
|
+
.command("like-status")
|
|
841
|
+
.description("Get like status for a workflow.")
|
|
842
|
+
.requiredOption("--workflow-id <id>", "Workflow ID")
|
|
843
|
+
.action(async (opts) => {
|
|
844
|
+
const client = buildClient(program.opts());
|
|
845
|
+
await run(() => client.workflows.getLikeStatus(opts.workflowId));
|
|
846
|
+
});
|
|
847
|
+
workflowCmd
|
|
848
|
+
.command("reference-impact")
|
|
849
|
+
.description("Get reference impact analysis for a workflow.")
|
|
850
|
+
.requiredOption("--workflow-id <id>", "Workflow ID")
|
|
851
|
+
.action(async (opts) => {
|
|
852
|
+
const client = buildClient(program.opts());
|
|
853
|
+
await run(() => client.workflows.getReferenceImpact(opts.workflowId));
|
|
854
|
+
});
|
|
855
|
+
// ═════════════════════════════════════════════════════════════════
|
|
856
|
+
// agent (SDK-based)
|
|
857
|
+
// ═════════════════════════════════════════════════════════════════
|
|
858
|
+
const agentCmd = program
|
|
859
|
+
.command("agent")
|
|
860
|
+
.description("Agent management commands.");
|
|
861
|
+
agentCmd
|
|
862
|
+
.command("list")
|
|
863
|
+
.description("List agents.")
|
|
864
|
+
.option("--project-id <id>", "Project ID")
|
|
865
|
+
.option("--search <query>", "Search query")
|
|
866
|
+
.option("--limit <n>", "Limit results")
|
|
867
|
+
.option("--offset <n>", "Offset")
|
|
868
|
+
.action(async (opts) => {
|
|
869
|
+
const client = buildClient(program.opts());
|
|
870
|
+
await run(() => client.agents.list({
|
|
871
|
+
projectId: opts.projectId,
|
|
872
|
+
searchQuery: opts.search,
|
|
873
|
+
limit: opts.limit ? parseInt(opts.limit) : undefined,
|
|
874
|
+
offset: opts.offset ? parseInt(opts.offset) : undefined,
|
|
875
|
+
}));
|
|
876
|
+
});
|
|
877
|
+
agentCmd
|
|
878
|
+
.command("get")
|
|
879
|
+
.description("Get an agent by ID.")
|
|
880
|
+
.requiredOption("--agent-id <id>", "Agent ID")
|
|
881
|
+
.action(async (opts) => {
|
|
882
|
+
const client = buildClient(program.opts());
|
|
883
|
+
const token = resolveToken(program.opts());
|
|
884
|
+
if (token) {
|
|
885
|
+
await run(() => client.agents.get(opts.agentId));
|
|
886
|
+
}
|
|
887
|
+
else {
|
|
888
|
+
await run(() => client.agents.getAnonymous(opts.agentId));
|
|
889
|
+
}
|
|
890
|
+
});
|
|
891
|
+
agentCmd
|
|
892
|
+
.command("create")
|
|
893
|
+
.description("Create an agent.")
|
|
894
|
+
.requiredOption("--body <body>", "JSON body (inline or @file)")
|
|
895
|
+
.action(async (opts) => {
|
|
896
|
+
const client = buildClient(program.opts());
|
|
897
|
+
const body = loadJsonPayload(opts.body);
|
|
898
|
+
await run(() => client.agents.create(body));
|
|
899
|
+
});
|
|
900
|
+
agentCmd
|
|
901
|
+
.command("update")
|
|
902
|
+
.description("Update an agent.")
|
|
903
|
+
.requiredOption("--agent-id <id>", "Agent ID")
|
|
904
|
+
.requiredOption("--body <body>", "JSON body (inline or @file)")
|
|
905
|
+
.action(async (opts) => {
|
|
906
|
+
const client = buildClient(program.opts());
|
|
907
|
+
const body = loadJsonPayload(opts.body);
|
|
908
|
+
await run(() => client.agents.update(opts.agentId, body));
|
|
909
|
+
});
|
|
910
|
+
agentCmd
|
|
911
|
+
.command("delete")
|
|
912
|
+
.description("Delete an agent.")
|
|
913
|
+
.requiredOption("--agent-id <id>", "Agent ID")
|
|
914
|
+
.action(async (opts) => {
|
|
915
|
+
const client = buildClient(program.opts());
|
|
916
|
+
await run(() => client.agents.delete(opts.agentId));
|
|
917
|
+
});
|
|
918
|
+
agentCmd
|
|
919
|
+
.command("stream")
|
|
920
|
+
.description("Stream interaction with an agent.")
|
|
921
|
+
.requiredOption("--agent-id <id>", "Agent ID")
|
|
922
|
+
.requiredOption("--body <body>", "JSON body (inline or @file)")
|
|
923
|
+
.action(async (opts) => {
|
|
924
|
+
const client = buildClient(program.opts());
|
|
925
|
+
const token = resolveToken(program.opts());
|
|
926
|
+
const body = loadJsonPayload(opts.body);
|
|
927
|
+
if (token) {
|
|
928
|
+
await run(() => client.agents.stream(opts.agentId, body));
|
|
929
|
+
}
|
|
930
|
+
else {
|
|
931
|
+
await run(() => client.agents.streamAnonymous(opts.agentId, body));
|
|
932
|
+
}
|
|
933
|
+
});
|
|
934
|
+
agentCmd
|
|
935
|
+
.command("reference-impact")
|
|
936
|
+
.description("Get reference impact analysis for an agent.")
|
|
937
|
+
.requiredOption("--agent-id <id>", "Agent ID")
|
|
938
|
+
.action(async (opts) => {
|
|
939
|
+
const client = buildClient(program.opts());
|
|
940
|
+
await run(() => client.agents.getReferenceImpact(opts.agentId));
|
|
941
|
+
});
|
|
942
|
+
// ═════════════════════════════════════════════════════════════════
|
|
943
|
+
// node-types (SDK-based)
|
|
944
|
+
// ═════════════════════════════════════════════════════════════════
|
|
945
|
+
const nodeTypesCmd = program
|
|
946
|
+
.command("node-types")
|
|
947
|
+
.description("Node type discovery commands.");
|
|
948
|
+
nodeTypesCmd
|
|
949
|
+
.command("list")
|
|
950
|
+
.description("List available node types.")
|
|
951
|
+
.action(async () => {
|
|
952
|
+
const client = buildClient(program.opts());
|
|
953
|
+
await run(() => client.nodeTypes.list());
|
|
954
|
+
});
|
|
955
|
+
nodeTypesCmd
|
|
956
|
+
.command("get")
|
|
957
|
+
.description("Get a specific node type.")
|
|
958
|
+
.requiredOption("--name <name>", "Node type name")
|
|
959
|
+
.action(async (opts) => {
|
|
960
|
+
const client = buildClient(program.opts());
|
|
961
|
+
await run(() => client.nodeTypes.get(opts.name));
|
|
962
|
+
});
|
|
963
|
+
nodeTypesCmd
|
|
964
|
+
.command("search")
|
|
965
|
+
.description("Search node types.")
|
|
966
|
+
.requiredOption("--query <query>", "Search query")
|
|
967
|
+
.action(async (opts) => {
|
|
968
|
+
const client = buildClient(program.opts());
|
|
969
|
+
await run(() => client.nodeTypes.search(opts.query));
|
|
970
|
+
});
|
|
971
|
+
nodeTypesCmd
|
|
972
|
+
.command("dynamic-options")
|
|
973
|
+
.description("Get dynamic options for a node type field.")
|
|
974
|
+
.requiredOption("--name <name>", "Node type name")
|
|
975
|
+
.requiredOption("--field-name <field>", "Field name")
|
|
976
|
+
.option("--project-id <id>", "Project ID")
|
|
977
|
+
.option("--input-config <json>", "Input config JSON")
|
|
978
|
+
.option("--connection <name>", "Connection name")
|
|
979
|
+
.option("--search-term <term>", "Search term")
|
|
980
|
+
.action(async (opts) => {
|
|
981
|
+
const client = buildClient(program.opts());
|
|
982
|
+
await run(() => client.nodeTypes.dynamicOptions({
|
|
983
|
+
name: opts.name,
|
|
984
|
+
fieldName: opts.fieldName,
|
|
985
|
+
projectId: opts.projectId,
|
|
986
|
+
inputConfig: opts.inputConfig ? JSON.parse(opts.inputConfig) : undefined,
|
|
987
|
+
connection: opts.connection,
|
|
988
|
+
searchTerm: opts.searchTerm,
|
|
989
|
+
}));
|
|
990
|
+
});
|
|
991
|
+
// ═════════════════════════════════════════════════════════════════
|
|
992
|
+
// connections (SDK-based)
|
|
993
|
+
// ═════════════════════════════════════════════════════════════════
|
|
994
|
+
const connectionsCmd = program
|
|
995
|
+
.command("connections")
|
|
996
|
+
.description("App connection management.");
|
|
997
|
+
connectionsCmd
|
|
998
|
+
.command("list")
|
|
999
|
+
.description("List connections.")
|
|
1000
|
+
.option("--workspace-id <id>", "Workspace ID")
|
|
1001
|
+
.option("--project-id <id>", "Project ID")
|
|
1002
|
+
.option("--limit <n>", "Limit")
|
|
1003
|
+
.option("--offset <n>", "Offset")
|
|
1004
|
+
.action(async (opts) => {
|
|
1005
|
+
const client = buildClient(program.opts());
|
|
1006
|
+
await run(() => client.connections.list({
|
|
1007
|
+
workspaceId: opts.workspaceId,
|
|
1008
|
+
projectId: opts.projectId,
|
|
1009
|
+
limit: opts.limit ? parseInt(opts.limit) : undefined,
|
|
1010
|
+
offset: opts.offset ? parseInt(opts.offset) : undefined,
|
|
1011
|
+
}));
|
|
1012
|
+
});
|
|
1013
|
+
connectionsCmd
|
|
1014
|
+
.command("create")
|
|
1015
|
+
.description("Create a connection.")
|
|
1016
|
+
.option("--workspace-id <id>", "Workspace ID")
|
|
1017
|
+
.requiredOption("--body <body>", "JSON body (inline or @file)")
|
|
1018
|
+
.action(async (opts) => {
|
|
1019
|
+
const client = buildClient(program.opts());
|
|
1020
|
+
const body = loadJsonPayload(opts.body);
|
|
1021
|
+
await run(() => client.connections.create(body, opts.workspaceId));
|
|
1022
|
+
});
|
|
1023
|
+
connectionsCmd
|
|
1024
|
+
.command("get-default")
|
|
1025
|
+
.description("Get default connection for a category.")
|
|
1026
|
+
.requiredOption("--category <name>", "Category name")
|
|
1027
|
+
.option("--workspace-id <id>", "Workspace ID")
|
|
1028
|
+
.option("--project-id <id>", "Project ID")
|
|
1029
|
+
.action(async (opts) => {
|
|
1030
|
+
const client = buildClient(program.opts());
|
|
1031
|
+
await run(() => client.connections.getDefault({
|
|
1032
|
+
categoryName: opts.category,
|
|
1033
|
+
workspaceId: opts.workspaceId,
|
|
1034
|
+
projectId: opts.projectId,
|
|
1035
|
+
}));
|
|
1036
|
+
});
|
|
1037
|
+
connectionsCmd
|
|
1038
|
+
.command("update")
|
|
1039
|
+
.description("Update a connection.")
|
|
1040
|
+
.requiredOption("--connection-id <id>", "Connection ID")
|
|
1041
|
+
.requiredOption("--body <body>", "JSON body (inline or @file)")
|
|
1042
|
+
.option("--workspace-id <id>", "Workspace ID")
|
|
1043
|
+
.action(async (opts) => {
|
|
1044
|
+
const client = buildClient(program.opts());
|
|
1045
|
+
const body = loadJsonPayload(opts.body);
|
|
1046
|
+
await run(() => client.connections.update(opts.connectionId, body, opts.workspaceId));
|
|
1047
|
+
});
|
|
1048
|
+
connectionsCmd
|
|
1049
|
+
.command("delete")
|
|
1050
|
+
.description("Delete a connection.")
|
|
1051
|
+
.requiredOption("--connection-id <id>", "Connection ID")
|
|
1052
|
+
.option("--workspace-id <id>", "Workspace ID")
|
|
1053
|
+
.action(async (opts) => {
|
|
1054
|
+
const client = buildClient(program.opts());
|
|
1055
|
+
await run(() => client.connections.delete(opts.connectionId, opts.workspaceId));
|
|
1056
|
+
});
|
|
1057
|
+
connectionsCmd
|
|
1058
|
+
.command("categories")
|
|
1059
|
+
.description("List connection categories.")
|
|
1060
|
+
.option("--workspace-id <id>", "Workspace ID")
|
|
1061
|
+
.option("--limit <n>", "Limit")
|
|
1062
|
+
.option("--offset <n>", "Offset")
|
|
1063
|
+
.action(async (opts) => {
|
|
1064
|
+
const client = buildClient(program.opts());
|
|
1065
|
+
await run(() => client.connections.categories({
|
|
1066
|
+
workspaceId: opts.workspaceId,
|
|
1067
|
+
limit: opts.limit ? parseInt(opts.limit) : undefined,
|
|
1068
|
+
offset: opts.offset ? parseInt(opts.offset) : undefined,
|
|
1069
|
+
}));
|
|
1070
|
+
});
|
|
1071
|
+
// ═════════════════════════════════════════════════════════════════
|
|
1072
|
+
// uploads (SDK-based)
|
|
1073
|
+
// ═════════════════════════════════════════════════════════════════
|
|
1074
|
+
const uploadsCmd = program
|
|
1075
|
+
.command("uploads")
|
|
1076
|
+
.description("Upload session management.");
|
|
1077
|
+
uploadsCmd
|
|
1078
|
+
.command("create")
|
|
1079
|
+
.description("Create an upload session.")
|
|
1080
|
+
.requiredOption("--body <body>", "JSON body (inline or @file)")
|
|
1081
|
+
.action(async (opts) => {
|
|
1082
|
+
const client = buildClient(program.opts());
|
|
1083
|
+
const body = loadJsonPayload(opts.body);
|
|
1084
|
+
await run(() => client.uploads.inputCreate(body));
|
|
1085
|
+
});
|
|
1086
|
+
uploadsCmd
|
|
1087
|
+
.command("status")
|
|
1088
|
+
.description("Get upload session status.")
|
|
1089
|
+
.requiredOption("--session-id <id>", "Session ID")
|
|
1090
|
+
.action(async (opts) => {
|
|
1091
|
+
const client = buildClient(program.opts());
|
|
1092
|
+
await run(() => client.uploads.inputStatus(opts.sessionId));
|
|
1093
|
+
});
|
|
1094
|
+
return program;
|
|
1095
|
+
}
|
|
1096
|
+
export async function runCli(argv) {
|
|
1097
|
+
const program = createProgram();
|
|
1098
|
+
await program.parseAsync(argv ?? process.argv);
|
|
1099
|
+
}
|
|
1100
|
+
//# sourceMappingURL=main.js.map
|