@seclai/cli 1.0.6 → 1.1.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.
Files changed (4) hide show
  1. package/README.md +393 -59
  2. package/dist/cli.js +2076 -219
  3. package/dist/cli.js.map +1 -1
  4. package/package.json +24 -5
package/dist/cli.js CHANGED
@@ -2,10 +2,13 @@
2
2
 
3
3
  // src/cli.ts
4
4
  import { Command } from "commander";
5
- import { readFile } from "fs/promises";
6
- import { readFileSync, realpathSync } from "fs";
7
- import process from "process";
5
+ import { realpathSync } from "fs";
8
6
  import { fileURLToPath, pathToFileURL } from "url";
7
+
8
+ // src/helpers.ts
9
+ import { readFile } from "fs/promises";
10
+ import { readFileSync } from "fs";
11
+ import process2 from "process";
9
12
  import {
10
13
  Seclai,
11
14
  SeclaiAPIStatusError,
@@ -14,15 +17,15 @@ import {
14
17
  } from "@seclai/sdk";
15
18
  function defaultRuntime() {
16
19
  return {
17
- stdin: process.stdin,
20
+ stdin: process2.stdin,
18
21
  writeOut: (text) => {
19
- process.stdout.write(text);
22
+ process2.stdout.write(text);
20
23
  },
21
24
  writeErr: (text) => {
22
- process.stderr.write(text);
25
+ process2.stderr.write(text);
23
26
  },
24
27
  setExitCode: (code) => {
25
- process.exitCode = code;
28
+ process2.exitCode = code;
26
29
  }
27
30
  };
28
31
  }
@@ -69,12 +72,13 @@ function getCliVersion() {
69
72
  function createClient(opts) {
70
73
  const seclaiOpts = {};
71
74
  if (opts.apiKey !== void 0) seclaiOpts.apiKey = opts.apiKey;
72
- const envUrl = process.env.SECLAI_API_URL;
75
+ const envUrl = process2.env.SECLAI_API_URL;
73
76
  seclaiOpts.baseUrl = envUrl && envUrl.length > 0 ? envUrl : "https://api.seclai.com";
74
77
  return new Seclai(seclaiOpts);
75
78
  }
76
79
  function printJson(rt, value) {
77
- rt.writeOut(`${JSON.stringify(value, null, 2)}
80
+ const indent = rt.compact ? void 0 : 2;
81
+ rt.writeOut(`${JSON.stringify(value, null, indent)}
78
82
  `);
79
83
  }
80
84
  function printError(rt, err) {
@@ -103,6 +107,8 @@ function printError(rt, err) {
103
107
  }
104
108
  if (err instanceof SeclaiConfigurationError) {
105
109
  rt.writeErr(`${err.name}: ${err.message}
110
+ `);
111
+ rt.writeErr(`hint: Set the SECLAI_API_KEY environment variable or pass --api-key.
106
112
  `);
107
113
  return;
108
114
  }
@@ -122,250 +128,2101 @@ async function run(rt, main) {
122
128
  rt.setExitCode(1);
123
129
  }
124
130
  }
125
- function createProgram(rt = defaultRuntime()) {
126
- const program = new Command();
127
- const cliVersion = getCliVersion();
128
- program.name("seclai").description(
129
- `Seclai Command Line Interface (v${cliVersion})
130
-
131
- Use this CLI to interact with Seclai from scripts and CI: manage connected content sources, run agents, and inspect agent runs and indexed content.
132
-
133
- All commands return JSON to stdout by default, which makes it easy to pipe into tools like jq.`
134
- ).version(cliVersion, "-V, --version", "output the version").option(
135
- "--api-key <key>",
136
- "Seclai API key (defaults to SECLAI_API_KEY). You can create/manage keys in the Seclai dashboard (Settings \u2192 API Keys)."
137
- );
138
- program.addHelpText(
139
- "after",
140
- `
141
- Environment:
142
- SECLAI_API_KEY Default API key (alternative to --api-key)
143
- SECLAI_API_URL Override API base URL (default: https://api.seclai.com). Intended for dev/staging.
131
+ function withFileUploadOptions(cmd) {
132
+ return cmd.requiredOption("--file <path>", "Path to a local file to upload.").option("--title <title>", "Optional title.").option("--metadata <json>", "Metadata JSON object. Use '-' for stdin.").option("--metadata-file <path>", "Path to metadata JSON file. Use '-' for stdin.").option("--file-name <name>", "Override filename sent to API.").option("--mime-type <type>", "Explicit MIME type.");
133
+ }
134
+ async function buildUploadOpts(rt, opts) {
135
+ const bytes = new Uint8Array(await readFile(opts.file));
136
+ const result = { file: bytes };
137
+ if (opts.title !== void 0) result.title = opts.title;
138
+ if (opts.metadata !== void 0 || opts.metadataFile !== void 0) {
139
+ const jsonArg = opts.metadata !== void 0 ? { json: opts.metadata } : {};
140
+ const jsonFileArg = opts.metadataFile !== void 0 ? { jsonFile: opts.metadataFile } : {};
141
+ result.metadata = await readJsonObjectInput(rt, { ...jsonArg, ...jsonFileArg });
142
+ }
143
+ if (opts.fileName !== void 0) result.fileName = opts.fileName;
144
+ if (opts.mimeType !== void 0) result.mimeType = opts.mimeType;
145
+ return result;
146
+ }
147
+ function listOpts(opts) {
148
+ const o = {};
149
+ if (opts.page !== void 0) o.page = opts.page;
150
+ if (opts.limit !== void 0) o.limit = opts.limit;
151
+ if (opts.sort !== void 0) o.sort = opts.sort;
152
+ if (opts.order !== void 0) o.order = opts.order;
153
+ return o;
154
+ }
155
+ function withAiInputOptions(cmd) {
156
+ return cmd.option("--user-input <text>", `User input text (shorthand for --json '{"user_input":"..."}')`).option("--json <json>", "Full request body JSON.").option("--json-file <path>", "Request body JSON file.");
157
+ }
158
+ async function readAiInput(rt, opts) {
159
+ if (opts.userInput !== void 0) {
160
+ return { user_input: opts.userInput };
161
+ }
162
+ const jsonArg = opts.json !== void 0 ? { json: opts.json } : {};
163
+ const jsonFileArg = opts.jsonFile !== void 0 ? { jsonFile: opts.jsonFile } : {};
164
+ return readJsonInput(rt, { ...jsonArg, ...jsonFileArg });
165
+ }
144
166
 
145
- Examples:
146
- seclai sources list
147
- seclai sources upload <sourceConnectionId> --file ./document.pdf --metadata '{"category":"docs"}'
148
- seclai contents upload <sourceConnectionContentVersionId> --file ./updated.pdf
149
- seclai agents run <agentId> --json '{"input":"Hello"}'
150
- seclai agents run <agentId> --json-file - --stream --timeout-ms 60000 < run.json
151
- `
152
- );
153
- program.configureOutput({
154
- writeOut: (str) => rt.writeOut(str),
155
- writeErr: (str) => rt.writeErr(str)
167
+ // src/commands/agents.ts
168
+ function register(program, rt) {
169
+ const agents = program.command("agents").description("Manage agents, runs, definitions, and AI assistance.");
170
+ agents.command("list").description("List agents.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).action(async (opts) => {
171
+ await run(rt, async () => {
172
+ const client = createClient(program.opts());
173
+ printJson(rt, await client.listAgents(listOpts(opts)));
174
+ });
156
175
  });
157
- program.exitOverride();
158
- const sources = program.command("sources").alias("source").description(
159
- "Manage content sources connected to Seclai.\n\nSources are how Seclai ingests content (e.g., websites, RSS feeds, document uploads) into a knowledge base so agents can retrieve and cite it."
160
- );
161
- sources.command("list").description(
162
- "List sources available to your organization/account.\n\nUse this to discover source connections and their IDs before uploading documents or debugging indexing."
163
- ).option("--page <n>", "Page number for pagination (1-based).", (v) => Number(v)).option("--limit <n>", "Page size (number of items to return).", (v) => Number(v)).option("--sort <field>", "Sort field (API-defined; commonly created_at or updated_at).").option("--order <asc|desc>", "Sort direction: asc or desc.").option("--account-id <id>", "Filter results to a specific account/organization id.").action(async (opts) => {
164
- await run(rt, async () => {
165
- const global = program.opts();
166
- const client = createClient(global);
167
- const res = await client.listSources({
168
- page: opts.page,
169
- limit: opts.limit,
170
- sort: opts.sort,
171
- order: opts.order,
172
- accountId: opts.accountId
173
- });
174
- printJson(rt, res);
175
- });
176
- });
177
- sources.command("upload").description(
178
- "Upload a local file to an existing source connection.\n\nThis is commonly used for document-upload sources inside a knowledge base. The uploaded file becomes indexed content that agents can retrieve from.\n\nNote: file size limits and supported MIME types are defined by the Seclai API (see the API reference for the upload endpoint)."
179
- ).argument(
180
- "<sourceConnectionId>",
181
- "Source connection ID to upload into. You can find this in the Seclai dashboard or by listing sources."
182
- ).requiredOption("--file <path>", "Path to a local file to upload.").option("--title <title>", "Optional human-readable title to associate with the uploaded content.").option(
183
- "--metadata <json>",
184
- `Optional metadata JSON object to attach to the upload (e.g. '{"category":"docs"}'). Use '-' to read JSON from stdin.`
185
- ).option(
186
- "--metadata-file <path>",
187
- "Path to a JSON file containing a metadata object. Use '-' to read JSON from stdin."
188
- ).option(
189
- "--file-name <name>",
190
- "Override the filename sent to the API (defaults to the basename of --file). Useful when uploading from temp paths."
191
- ).option("--mime-type <type>", "Explicit MIME type (e.g., application/pdf, text/plain).").action(async (sourceConnectionId, opts) => {
192
- await run(rt, async () => {
193
- const global = program.opts();
194
- const client = createClient(global);
195
- const bytes = new Uint8Array(await readFile(opts.file));
196
- const uploadOpts = { file: bytes };
197
- if (opts.title !== void 0) uploadOpts.title = opts.title;
198
- if (opts.metadata !== void 0 || opts.metadataFile !== void 0) {
199
- uploadOpts.metadata = await readJsonObjectInput(rt, { json: opts.metadata, jsonFile: opts.metadataFile });
200
- }
201
- if (opts.fileName !== void 0) uploadOpts.fileName = opts.fileName;
202
- if (opts.mimeType !== void 0) uploadOpts.mimeType = opts.mimeType;
203
- const res = await client.uploadFileToSource(sourceConnectionId, uploadOpts);
204
- printJson(rt, res);
176
+ agents.command("create").description("Create a new agent.").option("--json <json>", "Inline JSON body. Use '-' for stdin.").option("--json-file <path>", "JSON file path. Use '-' for stdin.").action(async (opts) => {
177
+ await run(rt, async () => {
178
+ const client = createClient(program.opts());
179
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
180
+ printJson(rt, await client.createAgent(body));
205
181
  });
206
182
  });
207
- const agents = program.command("agents").description(
208
- "Run agents and manage agent runs.\n\nAgents are workflows/assistants backed by your configured knowledge base and model settings. Running an agent creates a run, which you can inspect later for status, outputs, and (optionally) step-level details."
209
- );
210
- agents.command("run").description(
211
- "Run an agent by ID and print the run result as JSON.\n\nThe request body is passed through to the Seclai API as-is (see the API docs for the specific agent/run schema).\n\nFor automation, prefer --json-file and pipe input via stdin (use '-' as the path)."
212
- ).argument("<agentId>", "Agent ID to run (from the Seclai dashboard).").option("--json <json>", "Inline JSON request body. Use '-' to read JSON from stdin.").option("--json-file <path>", "Path to a JSON file containing the request body. Use '-' to read from stdin.").option(
213
- "--stream",
214
- "Wait for completion using the streaming (SSE) endpoint. The CLI prints the final result when the run is done."
215
- ).option(
216
- "--timeout-ms <n>",
217
- "Client-side timeout (milliseconds) when using --stream. This controls how long the CLI waits; it does not change server-side execution limits.",
218
- (v) => Number(v)
219
- ).action(async (agentId, opts) => {
183
+ agents.command("get").description("Get an agent by ID.").argument("<agentId>", "Agent ID.").action(async (agentId) => {
184
+ await run(rt, async () => {
185
+ const client = createClient(program.opts());
186
+ printJson(rt, await client.getAgent(agentId));
187
+ });
188
+ });
189
+ agents.command("update").description("Update an agent.").argument("<agentId>", "Agent ID.").option("--json <json>", "Inline JSON body.").option("--json-file <path>", "JSON file path.").action(async (agentId, opts) => {
220
190
  await run(rt, async () => {
221
- const global = program.opts();
222
- const client = createClient(global);
191
+ const client = createClient(program.opts());
223
192
  const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
224
- let res;
225
- if (opts.stream) {
226
- res = await client.runStreamingAgentAndWait(
193
+ printJson(rt, await client.updateAgent(agentId, body));
194
+ });
195
+ });
196
+ agents.command("delete").description("Delete an agent.").argument("<agentId>", "Agent ID.").action(async (agentId) => {
197
+ await run(rt, async () => {
198
+ const client = createClient(program.opts());
199
+ await client.deleteAgent(agentId);
200
+ printJson(rt, { ok: true });
201
+ });
202
+ });
203
+ agents.command("run").description("Run an agent. Use --stream/--events/--poll for different modes.").argument("<agentId>", "Agent ID.").option("--json <json>", "Inline JSON body. Use '-' for stdin.").option("--json-file <path>", "JSON file path. Use '-' for stdin.").option("--stream", "Stream and print final result when done.").option("--events", "Stream SSE events as newline-delimited JSON.").option("--event-filter <types>", "Comma-separated event types to show (with --events).").option("--output <mode>", "Output mode: 'full' prints entire event, 'data' prints only the data field, 'status' prints a one-line summary.", "full").option("--poll", "Poll until completion instead of streaming.").option("--poll-interval-ms <n>", "Poll interval in ms (with --poll).", (v) => Number(v)).option("--timeout-ms <n>", "Client-side timeout in ms.", (v) => Number(v)).option("--include-step-outputs", "Include step outputs (with --poll).").action(async (agentId, opts) => {
204
+ await run(rt, async () => {
205
+ const client = createClient(program.opts());
206
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
207
+ if (opts.events) {
208
+ const filterSet = opts.eventFilter ? new Set(opts.eventFilter.split(",").map((s) => s.trim())) : void 0;
209
+ const stream = client.runStreamingAgent(
227
210
  agentId,
228
211
  body,
229
212
  opts.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : void 0
230
213
  );
231
- } else {
232
- res = await client.runAgent(agentId, body);
214
+ for await (const event of stream) {
215
+ if (filterSet && !filterSet.has(event.type ?? "")) continue;
216
+ if (opts.output === "data") {
217
+ rt.writeOut(JSON.stringify(event.data ?? event) + "\n");
218
+ } else if (opts.output === "status") {
219
+ const e = event;
220
+ rt.writeOut(`${e.type ?? "event"}: ${e.status ?? JSON.stringify(e.data ?? e)}
221
+ `);
222
+ } else {
223
+ rt.writeOut(JSON.stringify(event) + "\n");
224
+ }
225
+ }
226
+ return;
227
+ }
228
+ if (opts.poll) {
229
+ const pollOpts = {};
230
+ if (opts.pollIntervalMs !== void 0) pollOpts.pollIntervalMs = opts.pollIntervalMs;
231
+ if (opts.timeoutMs !== void 0) pollOpts.timeoutMs = opts.timeoutMs;
232
+ if (opts.includeStepOutputs) pollOpts.includeStepOutputs = true;
233
+ printJson(rt, await client.runAgentAndPoll(agentId, body, pollOpts));
234
+ return;
235
+ }
236
+ if (opts.stream) {
237
+ printJson(
238
+ rt,
239
+ await client.runStreamingAgentAndWait(
240
+ agentId,
241
+ body,
242
+ opts.timeoutMs !== void 0 ? { timeoutMs: opts.timeoutMs } : void 0
243
+ )
244
+ );
245
+ return;
233
246
  }
234
- printJson(rt, res);
247
+ printJson(rt, await client.runAgent(agentId, body));
235
248
  });
236
249
  });
237
- const agentRuns = agents.command("runs").description("Manage agent runs");
238
- agentRuns.command("list").description(
239
- "List runs for a specific agent.\n\nThis is useful for monitoring recent executions, checking statuses, and obtaining run IDs for follow-up commands."
240
- ).argument("<agentId>", "Agent ID whose runs you want to list.").option("--page <n>", "Page number for pagination (1-based).", (v) => Number(v)).option("--limit <n>", "Page size (number of runs to return).", (v) => Number(v)).action(async (agentId, opts) => {
250
+ const runs = agents.command("runs").description("Manage agent runs.");
251
+ runs.command("list").description("List runs for an agent.").argument("<agentId>", "Agent ID.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).option("--status <status>", "Filter by run status (e.g. queued, running, completed, failed, cancelled).").action(async (agentId, opts) => {
241
252
  await run(rt, async () => {
242
- const global = program.opts();
243
- const client = createClient(global);
244
- const res = await client.listAgentRuns(agentId, { page: opts.page, limit: opts.limit });
245
- printJson(rt, res);
253
+ const client = createClient(program.opts());
254
+ const o = listOpts(opts);
255
+ if (opts.status) o.status = opts.status;
256
+ printJson(rt, await client.listAgentRuns(agentId, o));
246
257
  });
247
258
  });
248
- agentRuns.command("get").description(
249
- "Fetch a specific agent run and print it as JSON.\n\nUse this to inspect status, timestamps, and outputs. Optionally include step outputs for deeper debugging (may be large)."
250
- ).argument("<runId>", "Run ID to retrieve.").option(
251
- "--include-step-outputs",
252
- "Include step-level outputs when available. This may increase response size and latency."
253
- ).action(async (agentId, runId, opts) => {
259
+ runs.command("get").description("Get a specific run.").argument("<runId>", "Run ID.").option("--include-step-outputs", "Include step-level outputs.").action(async (runId, opts) => {
254
260
  await run(rt, async () => {
255
- const global = program.opts();
256
- const client = createClient(global);
257
- const res = await client.getAgentRun(runId, opts.includeStepOutputs ? { includeStepOutputs: true } : void 0);
258
- printJson(rt, res);
261
+ const client = createClient(program.opts());
262
+ printJson(
263
+ rt,
264
+ await client.getAgentRun(runId, opts.includeStepOutputs ? { includeStepOutputs: true } : void 0)
265
+ );
259
266
  });
260
267
  });
261
- agentRuns.command("delete").description(
262
- "Cancel or delete a specific agent run by ID.\n\nIf a run is still in progress, this requests cancellation. If it has already completed, behavior depends on the API (it may delete or mark the run)."
263
- ).argument("<runId>", "Run ID to cancel/delete.").action(async (runId) => {
268
+ runs.command("delete").description("Delete a run.").argument("<runId>", "Run ID.").action(async (runId) => {
264
269
  await run(rt, async () => {
265
- const global = program.opts();
266
- const client = createClient(global);
267
- const res = await client.deleteAgentRun(runId);
268
- printJson(rt, res);
270
+ const client = createClient(program.opts());
271
+ await client.deleteAgentRun(runId);
272
+ printJson(rt, { ok: true });
269
273
  });
270
274
  });
271
- const runs = program.command("runs").alias("agent-runs").description(
272
- "Manage agent runs by run ID (globally unique)."
273
- );
274
- runs.command("get").description(
275
- "Fetch a specific agent run by run ID and print it as JSON.\n\nUse --include-step-outputs to include step-level details when available (may be large)."
276
- ).argument("<runId>", "Run ID to retrieve.").option(
277
- "--include-step-outputs",
278
- "Include step-level outputs when available. This may increase response size and latency."
279
- ).action(async (runId, opts) => {
275
+ runs.command("cancel").description("Cancel a running agent run.").argument("<runId>", "Run ID.").action(async (runId) => {
280
276
  await run(rt, async () => {
281
- const global = program.opts();
282
- const client = createClient(global);
283
- const res = await client.getAgentRun(runId, opts.includeStepOutputs ? { includeStepOutputs: true } : void 0);
284
- printJson(rt, res);
277
+ const client = createClient(program.opts());
278
+ printJson(rt, await client.cancelAgentRun(runId));
285
279
  });
286
280
  });
287
- runs.command("delete").description(
288
- "Cancel or delete a specific agent run by run ID.\n\nIf the run is in progress, this requests cancellation. If it is completed, behavior depends on the API (it may delete or mark the run)."
289
- ).argument("<runId>", "Run ID to cancel/delete.").action(async (runId) => {
281
+ runs.command("search").description("Search agent runs.").option("--json <json>", "Search body JSON.").option("--json-file <path>", "Search body JSON file.").action(async (opts) => {
290
282
  await run(rt, async () => {
291
- const global = program.opts();
292
- const client = createClient(global);
293
- const res = await client.deleteAgentRun(runId);
294
- printJson(rt, res);
283
+ const client = createClient(program.opts());
284
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
285
+ printJson(rt, await client.searchAgentRuns(body));
295
286
  });
296
287
  });
297
- const contents = program.command("contents").description(
298
- "Inspect indexed content and embeddings.\n\nWhen Seclai ingests data from sources into a knowledge base, it creates content versions and generates vector embeddings for retrieval. These commands help you debug what was indexed and what embeddings were produced."
299
- );
300
- contents.command("upload").alias("replace").description(
301
- "Upload a local file to replace the underlying data for an existing content version.\n\nThis calls the content replace upload endpoint (/contents/{source_connection_content_version}/upload).\n\nUse this when you want to keep the same content version ID but update the file contents (e.g., new revision of a PDF)."
302
- ).argument(
303
- "<sourceConnectionContentVersion>",
304
- "Content version ID to replace (from Seclai dashboard or API responses)."
305
- ).requiredOption("--file <path>", "Path to a local file to upload.").option("--title <title>", "Optional title to associate with the uploaded content.").option(
306
- "--metadata <json>",
307
- `Optional metadata JSON object to attach to the upload (e.g. '{"revision":2}'). Use '-' to read JSON from stdin.`
308
- ).option(
309
- "--metadata-file <path>",
310
- "Path to a JSON file containing a metadata object. Use '-' to read JSON from stdin."
311
- ).option(
312
- "--file-name <name>",
313
- "Override the filename sent to the API (defaults to the basename of --file). Useful when uploading from temp paths."
314
- ).option("--mime-type <type>", "Explicit MIME type (e.g., application/pdf, text/plain).").action(async (sourceConnectionContentVersion, opts) => {
315
- await run(rt, async () => {
316
- const global = program.opts();
317
- const client = createClient(global);
318
- const bytes = new Uint8Array(await readFile(opts.file));
319
- const uploadOpts = { file: bytes };
320
- if (opts.title !== void 0) uploadOpts.title = opts.title;
321
- if (opts.metadata !== void 0 || opts.metadataFile !== void 0) {
322
- uploadOpts.metadata = await readJsonObjectInput(rt, { json: opts.metadata, jsonFile: opts.metadataFile });
323
- }
324
- if (opts.fileName !== void 0) uploadOpts.fileName = opts.fileName;
325
- if (opts.mimeType !== void 0) uploadOpts.mimeType = opts.mimeType;
326
- const res = await client.uploadFileToContent(sourceConnectionContentVersion, uploadOpts);
327
- printJson(rt, res);
328
- });
329
- });
330
- contents.command("get").description(
331
- "Get details for a specific content version.\n\nThis typically includes extracted text/metadata produced during indexing. Use --start/--end to fetch a slice of the text for faster inspection."
332
- ).argument(
333
- "<sourceConnectionContentVersion>",
334
- "Content version ID to retrieve (from Seclai dashboard or API responses)."
335
- ).option("--start <n>", "Start offset for returned text (0-based).", (v) => Number(v)).option("--end <n>", "End offset for returned text (exclusive).", (v) => Number(v)).action(async (sourceConnectionContentVersion, opts) => {
336
- await run(rt, async () => {
337
- const global = program.opts();
338
- const client = createClient(global);
339
- const res = await client.getContentDetail(sourceConnectionContentVersion, {
340
- start: opts.start,
341
- end: opts.end
342
- });
343
- printJson(rt, res);
344
- });
345
- });
346
- contents.command("delete").description(
347
- "Delete a specific content version from Seclai.\n\nUse with care: removing a content version can affect retrieval results for agents that rely on the associated knowledge base."
348
- ).argument("<sourceConnectionContentVersion>", "Content version ID to delete.").action(async (sourceConnectionContentVersion) => {
349
- await run(rt, async () => {
350
- const global = program.opts();
351
- const client = createClient(global);
352
- await client.deleteContent(sourceConnectionContentVersion);
288
+ const def = agents.command("def").description("Agent definition (step workflow).");
289
+ def.command("get").description("Get agent definition.").argument("<agentId>", "Agent ID.").action(async (agentId) => {
290
+ await run(rt, async () => {
291
+ const client = createClient(program.opts());
292
+ printJson(rt, await client.getAgentDefinition(agentId));
293
+ });
294
+ });
295
+ def.command("update").description("Update agent definition.").argument("<agentId>", "Agent ID.").option("--json <json>", "Definition JSON body.").option("--json-file <path>", "Definition JSON file.").action(async (agentId, opts) => {
296
+ await run(rt, async () => {
297
+ const client = createClient(program.opts());
298
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
299
+ printJson(rt, await client.updateAgentDefinition(agentId, body));
300
+ });
301
+ });
302
+ agents.command("upload-input").description("Upload a file as agent input.").argument("<agentId>", "Agent ID.").requiredOption("--file <path>", "File to upload.").option("--file-name <name>", "Override filename.").option("--mime-type <type>", "MIME type.").action(async (agentId, opts) => {
303
+ await run(rt, async () => {
304
+ const client = createClient(program.opts());
305
+ const { readFile: readFile3 } = await import("fs/promises");
306
+ const bytes = new Uint8Array(await readFile3(opts.file));
307
+ const o = { file: bytes };
308
+ if (opts.fileName) o.fileName = opts.fileName;
309
+ if (opts.mimeType) o.mimeType = opts.mimeType;
310
+ printJson(rt, await client.uploadAgentInput(agentId, o));
311
+ });
312
+ });
313
+ agents.command("input-status").description("Check agent input upload status.").argument("<agentId>", "Agent ID.").argument("<uploadId>", "Upload ID.").action(async (agentId, uploadId) => {
314
+ await run(rt, async () => {
315
+ const client = createClient(program.opts());
316
+ printJson(rt, await client.getAgentInputUploadStatus(agentId, uploadId));
317
+ });
318
+ });
319
+ const ai = agents.command("ai").description("Agent AI assistant.");
320
+ withAiInputOptions(
321
+ ai.command("gen-steps").description("Generate agent steps via AI.").argument("<agentId>", "Agent ID.")
322
+ ).action(async (agentId, opts) => {
323
+ await run(rt, async () => {
324
+ const client = createClient(program.opts());
325
+ const body = await readAiInput(rt, opts);
326
+ printJson(rt, await client.generateAgentSteps(agentId, body));
327
+ });
328
+ });
329
+ withAiInputOptions(
330
+ ai.command("step-config").description("Generate step config via AI.").argument("<agentId>", "Agent ID.")
331
+ ).action(async (agentId, opts) => {
332
+ await run(rt, async () => {
333
+ const client = createClient(program.opts());
334
+ const body = await readAiInput(rt, opts);
335
+ printJson(rt, await client.generateStepConfig(agentId, body));
336
+ });
337
+ });
338
+ ai.command("history").description("Get agent AI conversation history.").argument("<agentId>", "Agent ID.").action(async (agentId) => {
339
+ await run(rt, async () => {
340
+ const client = createClient(program.opts());
341
+ printJson(rt, await client.getAgentAiConversationHistory(agentId));
342
+ });
343
+ });
344
+ ai.command("mark").description("Mark an AI suggestion (accept/reject).").argument("<agentId>", "Agent ID.").argument("<conversationId>", "Conversation ID.").option("--json <json>", "Mark body JSON.").option("--json-file <path>", "Mark body JSON file.").action(async (agentId, conversationId, opts) => {
345
+ await run(rt, async () => {
346
+ const client = createClient(program.opts());
347
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
348
+ await client.markAgentAiSuggestion(agentId, conversationId, body);
349
+ printJson(rt, { ok: true });
350
+ });
351
+ });
352
+ runs.command("eval-results").description("List evaluation results for a run.").argument("<agentId>", "Agent ID.").argument("<runId>", "Run ID.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).action(async (agentId, runId, opts) => {
353
+ await run(rt, async () => {
354
+ const client = createClient(program.opts());
355
+ printJson(rt, await client.listRunEvaluationResults(agentId, runId, listOpts(opts)));
356
+ });
357
+ });
358
+ }
359
+
360
+ // src/commands/sources.ts
361
+ function register2(program, rt) {
362
+ const sources = program.command("sources").alias("source").description("Manage content sources.");
363
+ sources.command("list").description("List sources.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).option("--sort <field>", "Sort field.").option("--order <asc|desc>", "Sort direction.").option("--account-id <id>", "Filter by account ID.").action(async (opts) => {
364
+ await run(rt, async () => {
365
+ const client = createClient(program.opts());
366
+ const o = listOpts(opts);
367
+ if (opts.accountId) o.accountId = opts.accountId;
368
+ printJson(rt, await client.listSources(o));
369
+ });
370
+ });
371
+ sources.command("create").description("Create a source.").option("--json <json>", "Source body JSON.").option("--json-file <path>", "Source body JSON file.").action(async (opts) => {
372
+ await run(rt, async () => {
373
+ const client = createClient(program.opts());
374
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
375
+ printJson(rt, await client.createSource(body));
376
+ });
377
+ });
378
+ sources.command("get").description("Get a source by ID.").argument("<sourceId>", "Source ID.").action(async (sourceId) => {
379
+ await run(rt, async () => {
380
+ const client = createClient(program.opts());
381
+ printJson(rt, await client.getSource(sourceId));
382
+ });
383
+ });
384
+ sources.command("update").description("Update a source.").argument("<sourceId>", "Source ID.").option("--json <json>", "Update body JSON.").option("--json-file <path>", "Update body JSON file.").action(async (sourceId, opts) => {
385
+ await run(rt, async () => {
386
+ const client = createClient(program.opts());
387
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
388
+ printJson(rt, await client.updateSource(sourceId, body));
389
+ });
390
+ });
391
+ sources.command("delete").description("Delete a source.").argument("<sourceId>", "Source ID.").action(async (sourceId) => {
392
+ await run(rt, async () => {
393
+ const client = createClient(program.opts());
394
+ await client.deleteSource(sourceId);
395
+ printJson(rt, { ok: true });
396
+ });
397
+ });
398
+ const uploadCmd = sources.command("upload").description("Upload a file to a source.");
399
+ withFileUploadOptions(uploadCmd).argument("<sourceId>", "Source ID.").action(async (sourceId, opts) => {
400
+ await run(rt, async () => {
401
+ const client = createClient(program.opts());
402
+ const uploadOpts = await buildUploadOpts(rt, opts);
403
+ printJson(rt, await client.uploadFileToSource(sourceId, uploadOpts));
404
+ });
405
+ });
406
+ sources.command("upload-text").description("Upload inline text to a source.").argument("<sourceId>", "Source ID.").option("--json <json>", "Inline text body JSON.").option("--json-file <path>", "Inline text body JSON file.").action(async (sourceId, opts) => {
407
+ await run(rt, async () => {
408
+ const client = createClient(program.opts());
409
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
410
+ printJson(rt, await client.uploadInlineTextToSource(sourceId, body));
411
+ });
412
+ });
413
+ const exports_ = sources.command("exports").description("Manage source exports.");
414
+ exports_.command("list").description("List exports for a source.").argument("<sourceId>", "Source ID.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).action(async (sourceId, opts) => {
415
+ await run(rt, async () => {
416
+ const client = createClient(program.opts());
417
+ printJson(rt, await client.listSourceExports(sourceId, listOpts(opts)));
418
+ });
419
+ });
420
+ exports_.command("create").description("Create an export.").argument("<sourceId>", "Source ID.").option("--json <json>", "Export body JSON.").option("--json-file <path>", "Export body JSON file.").action(async (sourceId, opts) => {
421
+ await run(rt, async () => {
422
+ const client = createClient(program.opts());
423
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
424
+ printJson(rt, await client.createSourceExport(sourceId, body));
425
+ });
426
+ });
427
+ exports_.command("get").description("Get an export.").argument("<sourceId>", "Source ID.").argument("<exportId>", "Export ID.").action(async (sourceId, exportId) => {
428
+ await run(rt, async () => {
429
+ const client = createClient(program.opts());
430
+ printJson(rt, await client.getSourceExport(sourceId, exportId));
431
+ });
432
+ });
433
+ exports_.command("cancel").description("Cancel an export.").argument("<sourceId>", "Source ID.").argument("<exportId>", "Export ID.").action(async (sourceId, exportId) => {
434
+ await run(rt, async () => {
435
+ const client = createClient(program.opts());
436
+ printJson(rt, await client.cancelSourceExport(sourceId, exportId));
437
+ });
438
+ });
439
+ exports_.command("delete").description("Delete an export.").argument("<sourceId>", "Source ID.").argument("<exportId>", "Export ID.").action(async (sourceId, exportId) => {
440
+ await run(rt, async () => {
441
+ const client = createClient(program.opts());
442
+ await client.deleteSourceExport(sourceId, exportId);
443
+ printJson(rt, { ok: true });
444
+ });
445
+ });
446
+ exports_.command("download").description("Download an export (prints raw response body).").argument("<sourceId>", "Source ID.").argument("<exportId>", "Export ID.").action(async (sourceId, exportId) => {
447
+ await run(rt, async () => {
448
+ const client = createClient(program.opts());
449
+ const res = await client.downloadSourceExport(sourceId, exportId);
450
+ rt.writeOut(await res.text());
451
+ });
452
+ });
453
+ exports_.command("estimate").description("Estimate an export.").argument("<sourceId>", "Source ID.").option("--json <json>", "Estimate body JSON.").option("--json-file <path>", "Estimate body JSON file.").action(async (sourceId, opts) => {
454
+ await run(rt, async () => {
455
+ const client = createClient(program.opts());
456
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
457
+ printJson(rt, await client.estimateSourceExport(sourceId, body));
458
+ });
459
+ });
460
+ const migration = sources.command("migration").description("Source embedding migrations.");
461
+ migration.command("get").description("Get migration status.").argument("<sourceId>", "Source ID.").action(async (sourceId) => {
462
+ await run(rt, async () => {
463
+ const client = createClient(program.opts());
464
+ printJson(rt, await client.getSourceEmbeddingMigration(sourceId));
465
+ });
466
+ });
467
+ migration.command("start").description("Start an embedding migration.").argument("<sourceId>", "Source ID.").option("--json <json>", "Migration config JSON.").option("--json-file <path>", "Migration config JSON file.").action(async (sourceId, opts) => {
468
+ await run(rt, async () => {
469
+ const client = createClient(program.opts());
470
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
471
+ printJson(rt, await client.startSourceEmbeddingMigration(sourceId, body));
472
+ });
473
+ });
474
+ migration.command("cancel").description("Cancel an embedding migration.").argument("<sourceId>", "Source ID.").action(async (sourceId) => {
475
+ await run(rt, async () => {
476
+ const client = createClient(program.opts());
477
+ printJson(rt, await client.cancelSourceEmbeddingMigration(sourceId));
478
+ });
479
+ });
480
+ }
481
+
482
+ // src/commands/contents.ts
483
+ function register3(program, rt) {
484
+ const contents = program.command("contents").description("Manage indexed content and embeddings.");
485
+ contents.command("get").description("Get content version details.").argument("<contentVersionId>", "Content version ID.").option("--start <n>", "Text start offset (0-based).", (v) => Number(v)).option("--end <n>", "Text end offset (exclusive).", (v) => Number(v)).action(async (contentVersionId, opts) => {
486
+ await run(rt, async () => {
487
+ const client = createClient(program.opts());
488
+ const o = {};
489
+ if (opts.start !== void 0) o.start = opts.start;
490
+ if (opts.end !== void 0) o.end = opts.end;
491
+ printJson(rt, await client.getContentDetail(contentVersionId, o));
492
+ });
493
+ });
494
+ contents.command("delete").description("Delete a content version.").argument("<contentVersionId>", "Content version ID.").action(async (contentVersionId) => {
495
+ await run(rt, async () => {
496
+ const client = createClient(program.opts());
497
+ await client.deleteContent(contentVersionId);
498
+ printJson(rt, { ok: true });
499
+ });
500
+ });
501
+ const uploadCmd = contents.command("upload").alias("replace").description("Upload/replace content file.");
502
+ withFileUploadOptions(uploadCmd).argument("<contentVersionId>", "Content version ID.").action(async (contentVersionId, opts) => {
503
+ await run(rt, async () => {
504
+ const client = createClient(program.opts());
505
+ const uploadOpts = await buildUploadOpts(rt, opts);
506
+ printJson(rt, await client.uploadFileToContent(contentVersionId, uploadOpts));
507
+ });
508
+ });
509
+ contents.command("replace-text").description("Replace content with inline text.").argument("<contentVersionId>", "Content version ID.").option("--json <json>", "Inline text body JSON.").option("--json-file <path>", "Inline text body JSON file.").action(async (contentVersionId, opts) => {
510
+ await run(rt, async () => {
511
+ const client = createClient(program.opts());
512
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
513
+ printJson(rt, await client.replaceContentWithInlineText(contentVersionId, body));
514
+ });
515
+ });
516
+ contents.command("embeddings").description("List embeddings for a content version.").argument("<contentVersionId>", "Content version ID.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).action(async (contentVersionId, opts) => {
517
+ await run(rt, async () => {
518
+ const client = createClient(program.opts());
519
+ printJson(rt, await client.listContentEmbeddings(contentVersionId, listOpts(opts)));
520
+ });
521
+ });
522
+ }
523
+
524
+ // src/commands/kb.ts
525
+ function register4(program, rt) {
526
+ const kb = program.command("kb").description("Manage knowledge bases.");
527
+ kb.command("list").description("List knowledge bases.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).option("--sort <field>", "Sort field.").option("--order <asc|desc>", "Sort direction.").action(async (opts) => {
528
+ await run(rt, async () => {
529
+ const client = createClient(program.opts());
530
+ printJson(rt, await client.listKnowledgeBases(listOpts(opts)));
531
+ });
532
+ });
533
+ kb.command("create").description("Create a knowledge base.").option("--json <json>", "Body JSON.").option("--json-file <path>", "Body JSON file.").action(async (opts) => {
534
+ await run(rt, async () => {
535
+ const client = createClient(program.opts());
536
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
537
+ printJson(rt, await client.createKnowledgeBase(body));
538
+ });
539
+ });
540
+ kb.command("get").description("Get a knowledge base.").argument("<kbId>", "Knowledge base ID.").action(async (kbId) => {
541
+ await run(rt, async () => {
542
+ const client = createClient(program.opts());
543
+ printJson(rt, await client.getKnowledgeBase(kbId));
544
+ });
545
+ });
546
+ kb.command("update").description("Update a knowledge base.").argument("<kbId>", "Knowledge base ID.").option("--json <json>", "Update body JSON.").option("--json-file <path>", "Update body JSON file.").action(async (kbId, opts) => {
547
+ await run(rt, async () => {
548
+ const client = createClient(program.opts());
549
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
550
+ printJson(rt, await client.updateKnowledgeBase(kbId, body));
551
+ });
552
+ });
553
+ kb.command("delete").description("Delete a knowledge base.").argument("<kbId>", "Knowledge base ID.").action(async (kbId) => {
554
+ await run(rt, async () => {
555
+ const client = createClient(program.opts());
556
+ await client.deleteKnowledgeBase(kbId);
557
+ printJson(rt, { ok: true });
558
+ });
559
+ });
560
+ }
561
+
562
+ // src/commands/memory.ts
563
+ function register5(program, rt) {
564
+ const memory = program.command("memory").description("Manage memory banks.");
565
+ memory.command("list").description("List memory banks.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).option("--sort <field>", "Sort field.").option("--order <asc|desc>", "Sort direction.").action(async (opts) => {
566
+ await run(rt, async () => {
567
+ const client = createClient(program.opts());
568
+ printJson(rt, await client.listMemoryBanks(listOpts(opts)));
569
+ });
570
+ });
571
+ memory.command("create").description("Create a memory bank.").option("--json <json>", "Body JSON.").option("--json-file <path>", "Body JSON file.").action(async (opts) => {
572
+ await run(rt, async () => {
573
+ const client = createClient(program.opts());
574
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
575
+ printJson(rt, await client.createMemoryBank(body));
576
+ });
577
+ });
578
+ memory.command("get").description("Get a memory bank.").argument("<memoryBankId>", "Memory bank ID.").action(async (memoryBankId) => {
579
+ await run(rt, async () => {
580
+ const client = createClient(program.opts());
581
+ printJson(rt, await client.getMemoryBank(memoryBankId));
582
+ });
583
+ });
584
+ memory.command("update").description("Update a memory bank.").argument("<memoryBankId>", "Memory bank ID.").option("--json <json>", "Update body JSON.").option("--json-file <path>", "Update body JSON file.").action(async (memoryBankId, opts) => {
585
+ await run(rt, async () => {
586
+ const client = createClient(program.opts());
587
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
588
+ printJson(rt, await client.updateMemoryBank(memoryBankId, body));
589
+ });
590
+ });
591
+ memory.command("delete").description("Delete a memory bank.").argument("<memoryBankId>", "Memory bank ID.").action(async (memoryBankId) => {
592
+ await run(rt, async () => {
593
+ const client = createClient(program.opts());
594
+ await client.deleteMemoryBank(memoryBankId);
595
+ printJson(rt, { ok: true });
596
+ });
597
+ });
598
+ memory.command("stats").description("Get memory bank statistics.").argument("<memoryBankId>", "Memory bank ID.").action(async (memoryBankId) => {
599
+ await run(rt, async () => {
600
+ const client = createClient(program.opts());
601
+ printJson(rt, await client.getMemoryBankStats(memoryBankId));
602
+ });
603
+ });
604
+ memory.command("agents").description("List agents using a memory bank.").argument("<memoryBankId>", "Memory bank ID.").action(async (memoryBankId) => {
605
+ await run(rt, async () => {
606
+ const client = createClient(program.opts());
607
+ printJson(rt, await client.getAgentsUsingMemoryBank(memoryBankId));
608
+ });
609
+ });
610
+ memory.command("compact").description("Compact a memory bank.").argument("<memoryBankId>", "Memory bank ID.").action(async (memoryBankId) => {
611
+ await run(rt, async () => {
612
+ const client = createClient(program.opts());
613
+ await client.compactMemoryBank(memoryBankId);
614
+ printJson(rt, { ok: true });
615
+ });
616
+ });
617
+ memory.command("delete-source").description("Delete a memory bank's source data.").argument("<memoryBankId>", "Memory bank ID.").action(async (memoryBankId) => {
618
+ await run(rt, async () => {
619
+ const client = createClient(program.opts());
620
+ await client.deleteMemoryBankSource(memoryBankId);
353
621
  printJson(rt, { ok: true });
354
622
  });
355
623
  });
356
- contents.command("embeddings").description(
357
- "List embeddings generated for a content version.\n\nEmbeddings power similarity search and retrieval for knowledge base agents. Listing them is useful for debugging indexing and verifying that content produced vectors."
358
- ).argument("<sourceConnectionContentVersion>", "Content version ID whose embeddings you want to list.").option("--page <n>", "Page number for pagination (1-based).", (v) => Number(v)).option("--limit <n>", "Page size (number of embeddings to return).", (v) => Number(v)).action(async (sourceConnectionContentVersion, opts) => {
624
+ memory.command("templates").description("List memory bank templates.").action(async () => {
625
+ await run(rt, async () => {
626
+ const client = createClient(program.opts());
627
+ printJson(rt, await client.listMemoryBankTemplates());
628
+ });
629
+ });
630
+ memory.command("test-compaction").description("Test compaction on a memory bank.").argument("<memoryBankId>", "Memory bank ID.").option("--json <json>", "Test config JSON.").option("--json-file <path>", "Test config JSON file.").action(async (memoryBankId, opts) => {
631
+ await run(rt, async () => {
632
+ const client = createClient(program.opts());
633
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
634
+ printJson(rt, await client.testMemoryBankCompaction(memoryBankId, body));
635
+ });
636
+ });
637
+ memory.command("test-compaction-standalone").description("Test compaction prompt standalone (no memory bank required).").option("--json <json>", "Test config JSON.").option("--json-file <path>", "Test config JSON file.").action(async (opts) => {
638
+ await run(rt, async () => {
639
+ const client = createClient(program.opts());
640
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
641
+ printJson(rt, await client.testCompactionPromptStandalone(body));
642
+ });
643
+ });
644
+ const ai = memory.command("ai").description("Memory bank AI assistant.");
645
+ withAiInputOptions(
646
+ ai.command("generate").description("Generate memory bank config via AI.")
647
+ ).action(async (opts) => {
648
+ await run(rt, async () => {
649
+ const client = createClient(program.opts());
650
+ const body = await readAiInput(rt, opts);
651
+ printJson(rt, await client.generateMemoryBankConfig(body));
652
+ });
653
+ });
654
+ ai.command("last").description("Get last memory bank AI conversation.").action(async () => {
359
655
  await run(rt, async () => {
360
- const global = program.opts();
361
- const client = createClient(global);
362
- const res = await client.listContentEmbeddings(sourceConnectionContentVersion, {
363
- page: opts.page,
364
- limit: opts.limit
365
- });
366
- printJson(rt, res);
656
+ const client = createClient(program.opts());
657
+ printJson(rt, await client.getMemoryBankAiLastConversation());
367
658
  });
368
659
  });
660
+ ai.command("accept").description("Accept a memory bank AI suggestion.").argument("<conversationId>", "Conversation ID.").option("--json <json>", "Accept body JSON.").option("--json-file <path>", "Accept body JSON file.").action(async (conversationId, opts) => {
661
+ await run(rt, async () => {
662
+ const client = createClient(program.opts());
663
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
664
+ printJson(rt, await client.acceptMemoryBankAiSuggestion(conversationId, body));
665
+ });
666
+ });
667
+ }
668
+
669
+ // src/commands/evals.ts
670
+ function register6(program, rt) {
671
+ const evals = program.command("evals").description("Manage evaluations.");
672
+ const criteria = evals.command("criteria").description("Evaluation criteria.");
673
+ criteria.command("list").description("List evaluation criteria for an agent.").argument("<agentId>", "Agent ID.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).action(async (agentId, opts) => {
674
+ await run(rt, async () => {
675
+ const client = createClient(program.opts());
676
+ printJson(rt, await client.listEvaluationCriteria(agentId, listOpts(opts)));
677
+ });
678
+ });
679
+ criteria.command("create").description("Create evaluation criteria.").argument("<agentId>", "Agent ID.").option("--json <json>", "Criteria body JSON.").option("--json-file <path>", "Criteria body JSON file.").action(async (agentId, opts) => {
680
+ await run(rt, async () => {
681
+ const client = createClient(program.opts());
682
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
683
+ printJson(rt, await client.createEvaluationCriteria(agentId, body));
684
+ });
685
+ });
686
+ criteria.command("get").description("Get evaluation criteria.").argument("<criteriaId>", "Criteria ID.").action(async (criteriaId) => {
687
+ await run(rt, async () => {
688
+ const client = createClient(program.opts());
689
+ printJson(rt, await client.getEvaluationCriteria(criteriaId));
690
+ });
691
+ });
692
+ criteria.command("update").description("Update evaluation criteria.").argument("<criteriaId>", "Criteria ID.").option("--json <json>", "Update body JSON.").option("--json-file <path>", "Update body JSON file.").action(async (criteriaId, opts) => {
693
+ await run(rt, async () => {
694
+ const client = createClient(program.opts());
695
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
696
+ printJson(rt, await client.updateEvaluationCriteria(criteriaId, body));
697
+ });
698
+ });
699
+ criteria.command("delete").description("Delete evaluation criteria.").argument("<criteriaId>", "Criteria ID.").action(async (criteriaId) => {
700
+ await run(rt, async () => {
701
+ const client = createClient(program.opts());
702
+ await client.deleteEvaluationCriteria(criteriaId);
703
+ printJson(rt, { ok: true });
704
+ });
705
+ });
706
+ criteria.command("summary").description("Get criteria evaluation summary.").argument("<criteriaId>", "Criteria ID.").action(async (criteriaId) => {
707
+ await run(rt, async () => {
708
+ const client = createClient(program.opts());
709
+ printJson(rt, await client.getEvaluationCriteriaSummary(criteriaId));
710
+ });
711
+ });
712
+ const results = evals.command("results").description("Evaluation results.");
713
+ results.command("list").description("List results for criteria.").argument("<criteriaId>", "Criteria ID.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).action(async (criteriaId, opts) => {
714
+ await run(rt, async () => {
715
+ const client = createClient(program.opts());
716
+ printJson(rt, await client.listEvaluationResults(criteriaId, listOpts(opts)));
717
+ });
718
+ });
719
+ results.command("create").description("Create an evaluation result.").argument("<criteriaId>", "Criteria ID.").option("--json <json>", "Result body JSON.").option("--json-file <path>", "Result body JSON file.").action(async (criteriaId, opts) => {
720
+ await run(rt, async () => {
721
+ const client = createClient(program.opts());
722
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
723
+ printJson(rt, await client.createEvaluationResult(criteriaId, body));
724
+ });
725
+ });
726
+ evals.command("compatible-runs").description("List runs compatible with criteria.").argument("<criteriaId>", "Criteria ID.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).action(async (criteriaId, opts) => {
727
+ await run(rt, async () => {
728
+ const client = createClient(program.opts());
729
+ printJson(rt, await client.listCompatibleRuns(criteriaId, listOpts(opts)));
730
+ });
731
+ });
732
+ evals.command("test-draft").description("Test a draft evaluation.").argument("<agentId>", "Agent ID.").option("--json <json>", "Test body JSON.").option("--json-file <path>", "Test body JSON file.").action(async (agentId, opts) => {
733
+ await run(rt, async () => {
734
+ const client = createClient(program.opts());
735
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
736
+ printJson(rt, await client.testDraftEvaluation(agentId, body));
737
+ });
738
+ });
739
+ evals.command("agent-results").description("List all evaluation results for an agent.").argument("<agentId>", "Agent ID.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).action(async (agentId, opts) => {
740
+ await run(rt, async () => {
741
+ const client = createClient(program.opts());
742
+ printJson(rt, await client.listAgentEvaluationResults(agentId, listOpts(opts)));
743
+ });
744
+ });
745
+ evals.command("agent-runs").description("List evaluation run summaries for an agent.").argument("<agentId>", "Agent ID.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).action(async (agentId, opts) => {
746
+ await run(rt, async () => {
747
+ const client = createClient(program.opts());
748
+ printJson(rt, await client.listEvaluationRuns(agentId, listOpts(opts)));
749
+ });
750
+ });
751
+ evals.command("non-manual-summary").description("Get non-manual evaluation summary for an agent.").argument("<agentId>", "Agent ID.").action(async (agentId) => {
752
+ await run(rt, async () => {
753
+ const client = createClient(program.opts());
754
+ printJson(rt, await client.getNonManualEvaluationSummary(agentId));
755
+ });
756
+ });
757
+ }
758
+
759
+ // src/commands/solutions.ts
760
+ function register7(program, rt) {
761
+ const solutions = program.command("solutions").description("Manage solutions.");
762
+ solutions.command("list").description("List solutions.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).option("--sort <field>", "Sort field.").option("--order <asc|desc>", "Sort direction.").action(async (opts) => {
763
+ await run(rt, async () => {
764
+ const client = createClient(program.opts());
765
+ printJson(rt, await client.listSolutions(listOpts(opts)));
766
+ });
767
+ });
768
+ solutions.command("create").description("Create a solution.").option("--json <json>", "Body JSON.").option("--json-file <path>", "Body JSON file.").action(async (opts) => {
769
+ await run(rt, async () => {
770
+ const client = createClient(program.opts());
771
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
772
+ printJson(rt, await client.createSolution(body));
773
+ });
774
+ });
775
+ solutions.command("get").description("Get a solution.").argument("<solutionId>", "Solution ID.").action(async (solutionId) => {
776
+ await run(rt, async () => {
777
+ const client = createClient(program.opts());
778
+ printJson(rt, await client.getSolution(solutionId));
779
+ });
780
+ });
781
+ solutions.command("update").description("Update a solution.").argument("<solutionId>", "Solution ID.").option("--json <json>", "Update body JSON.").option("--json-file <path>", "Update body JSON file.").action(async (solutionId, opts) => {
782
+ await run(rt, async () => {
783
+ const client = createClient(program.opts());
784
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
785
+ printJson(rt, await client.updateSolution(solutionId, body));
786
+ });
787
+ });
788
+ solutions.command("delete").description("Delete a solution.").argument("<solutionId>", "Solution ID.").action(async (solutionId) => {
789
+ await run(rt, async () => {
790
+ const client = createClient(program.opts());
791
+ await client.deleteSolution(solutionId);
792
+ printJson(rt, { ok: true });
793
+ });
794
+ });
795
+ solutions.command("link").description("Link resources to a solution. Use --agents, --kb, or --sources with JSON array of IDs.").argument("<solutionId>", "Solution ID.").option("--agents <json>", "Link agents (JSON body).").option("--kb <json>", "Link knowledge bases (JSON body).").option("--sources <json>", "Link sources (JSON body).").action(async (solutionId, opts) => {
796
+ await run(rt, async () => {
797
+ if (!opts.agents && !opts.kb && !opts.sources) {
798
+ rt.writeErr("Provide at least one of --agents, --kb, or --sources.\n");
799
+ rt.setExitCode(1);
800
+ return;
801
+ }
802
+ const client = createClient(program.opts());
803
+ const results = {};
804
+ if (opts.agents) {
805
+ results.agents = await client.linkAgentsToSolution(solutionId, JSON.parse(opts.agents));
806
+ }
807
+ if (opts.kb) {
808
+ results.knowledgeBases = await client.linkKnowledgeBasesToSolution(solutionId, JSON.parse(opts.kb));
809
+ }
810
+ if (opts.sources) {
811
+ results.sources = await client.linkSourceConnectionsToSolution(solutionId, JSON.parse(opts.sources));
812
+ }
813
+ printJson(rt, results);
814
+ });
815
+ });
816
+ solutions.command("unlink").description("Unlink resources from a solution. Use --agents, --kb, or --sources with JSON array of IDs.").argument("<solutionId>", "Solution ID.").option("--agents <json>", "Unlink agents (JSON body).").option("--kb <json>", "Unlink knowledge bases (JSON body).").option("--sources <json>", "Unlink sources (JSON body).").action(async (solutionId, opts) => {
817
+ await run(rt, async () => {
818
+ if (!opts.agents && !opts.kb && !opts.sources) {
819
+ rt.writeErr("Provide at least one of --agents, --kb, or --sources.\n");
820
+ rt.setExitCode(1);
821
+ return;
822
+ }
823
+ const client = createClient(program.opts());
824
+ const results = {};
825
+ if (opts.agents) {
826
+ results.agents = await client.unlinkAgentsFromSolution(solutionId, JSON.parse(opts.agents));
827
+ }
828
+ if (opts.kb) {
829
+ results.knowledgeBases = await client.unlinkKnowledgeBasesFromSolution(solutionId, JSON.parse(opts.kb));
830
+ }
831
+ if (opts.sources) {
832
+ results.sources = await client.unlinkSourceConnectionsFromSolution(solutionId, JSON.parse(opts.sources));
833
+ }
834
+ printJson(rt, results);
835
+ });
836
+ });
837
+ const convos = solutions.command("convos").description("Solution conversations.");
838
+ convos.command("list").description("List conversations for a solution.").argument("<solutionId>", "Solution ID.").action(async (solutionId) => {
839
+ await run(rt, async () => {
840
+ const client = createClient(program.opts());
841
+ printJson(rt, await client.listSolutionConversations(solutionId));
842
+ });
843
+ });
844
+ convos.command("add").description("Add a conversation turn.").argument("<solutionId>", "Solution ID.").option("--json <json>", "Turn body JSON.").option("--json-file <path>", "Turn body JSON file.").action(async (solutionId, opts) => {
845
+ await run(rt, async () => {
846
+ const client = createClient(program.opts());
847
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
848
+ printJson(rt, await client.addSolutionConversationTurn(solutionId, body));
849
+ });
850
+ });
851
+ convos.command("mark").description("Mark a conversation turn.").argument("<solutionId>", "Solution ID.").argument("<conversationId>", "Conversation ID.").option("--json <json>", "Mark body JSON.").option("--json-file <path>", "Mark body JSON file.").action(async (solutionId, conversationId, opts) => {
852
+ await run(rt, async () => {
853
+ const client = createClient(program.opts());
854
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
855
+ await client.markSolutionConversationTurn(solutionId, conversationId, body);
856
+ printJson(rt, { ok: true });
857
+ });
858
+ });
859
+ const ai = solutions.command("ai").description("Solution AI assistant.");
860
+ withAiInputOptions(
861
+ ai.command("generate").description("Generate a solution AI plan.").argument("<solutionId>", "Solution ID.")
862
+ ).action(async (solutionId, opts) => {
863
+ await run(rt, async () => {
864
+ const client = createClient(program.opts());
865
+ const body = await readAiInput(rt, opts);
866
+ printJson(rt, await client.generateSolutionAiPlan(solutionId, body));
867
+ });
868
+ });
869
+ withAiInputOptions(
870
+ ai.command("kb").description("Generate a KB plan via solution AI.").argument("<solutionId>", "Solution ID.")
871
+ ).action(async (solutionId, opts) => {
872
+ await run(rt, async () => {
873
+ const client = createClient(program.opts());
874
+ const body = await readAiInput(rt, opts);
875
+ printJson(rt, await client.generateSolutionAiKnowledgeBase(solutionId, body));
876
+ });
877
+ });
878
+ withAiInputOptions(
879
+ ai.command("source").description("Generate a source plan via solution AI.").argument("<solutionId>", "Solution ID.")
880
+ ).action(async (solutionId, opts) => {
881
+ await run(rt, async () => {
882
+ const client = createClient(program.opts());
883
+ const body = await readAiInput(rt, opts);
884
+ printJson(rt, await client.generateSolutionAiSource(solutionId, body));
885
+ });
886
+ });
887
+ ai.command("accept").description("Accept a solution AI plan.").argument("<solutionId>", "Solution ID.").argument("<conversationId>", "Conversation ID.").option("--json <json>", "Accept body JSON.").option("--json-file <path>", "Accept body JSON file.").action(async (solutionId, conversationId, opts) => {
888
+ await run(rt, async () => {
889
+ const client = createClient(program.opts());
890
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
891
+ printJson(rt, await client.acceptSolutionAiPlan(solutionId, conversationId, body));
892
+ });
893
+ });
894
+ ai.command("decline").description("Decline a solution AI plan.").argument("<solutionId>", "Solution ID.").argument("<conversationId>", "Conversation ID.").action(async (solutionId, conversationId) => {
895
+ await run(rt, async () => {
896
+ const client = createClient(program.opts());
897
+ await client.declineSolutionAiPlan(solutionId, conversationId);
898
+ printJson(rt, { ok: true });
899
+ });
900
+ });
901
+ }
902
+
903
+ // src/commands/governance.ts
904
+ function register8(program, rt) {
905
+ const governance = program.command("governance").description("Governance AI assistant.");
906
+ const ai = governance.command("ai").description("Governance AI operations.");
907
+ withAiInputOptions(
908
+ ai.command("generate").description("Generate a governance AI plan.")
909
+ ).action(async (opts) => {
910
+ await run(rt, async () => {
911
+ const client = createClient(program.opts());
912
+ const body = await readAiInput(rt, opts);
913
+ printJson(rt, await client.generateGovernanceAiPlan(body));
914
+ });
915
+ });
916
+ ai.command("list").description("List governance AI conversations.").action(async () => {
917
+ await run(rt, async () => {
918
+ const client = createClient(program.opts());
919
+ printJson(rt, await client.listGovernanceAiConversations());
920
+ });
921
+ });
922
+ ai.command("accept").description("Accept a governance AI plan.").argument("<conversationId>", "Conversation ID.").action(async (conversationId) => {
923
+ await run(rt, async () => {
924
+ const client = createClient(program.opts());
925
+ printJson(rt, await client.acceptGovernanceAiPlan(conversationId));
926
+ });
927
+ });
928
+ ai.command("decline").description("Decline a governance AI plan.").argument("<conversationId>", "Conversation ID.").action(async (conversationId) => {
929
+ await run(rt, async () => {
930
+ const client = createClient(program.opts());
931
+ await client.declineGovernanceAiPlan(conversationId);
932
+ printJson(rt, { ok: true });
933
+ });
934
+ });
935
+ }
936
+
937
+ // src/commands/alerts.ts
938
+ function register9(program, rt) {
939
+ const alerts = program.command("alerts").description("Manage alerts and alert configurations.");
940
+ alerts.command("list").description("List alerts.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).option("--status <status>", "Filter by status.").option("--severity <severity>", "Filter by severity.").action(async (opts) => {
941
+ await run(rt, async () => {
942
+ const client = createClient(program.opts());
943
+ const o = listOpts(opts);
944
+ if (opts.status) o.status = opts.status;
945
+ if (opts.severity) o.severity = opts.severity;
946
+ printJson(rt, await client.listAlerts(o));
947
+ });
948
+ });
949
+ alerts.command("get").description("Get an alert.").argument("<alertId>", "Alert ID.").action(async (alertId) => {
950
+ await run(rt, async () => {
951
+ const client = createClient(program.opts());
952
+ printJson(rt, await client.getAlert(alertId));
953
+ });
954
+ });
955
+ alerts.command("status").description("Change alert status.").argument("<alertId>", "Alert ID.").option("--json <json>", "Status body JSON.").option("--json-file <path>", "Status body JSON file.").action(async (alertId, opts) => {
956
+ await run(rt, async () => {
957
+ const client = createClient(program.opts());
958
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
959
+ printJson(rt, await client.changeAlertStatus(alertId, body));
960
+ });
961
+ });
962
+ alerts.command("comment").description("Add a comment to an alert.").argument("<alertId>", "Alert ID.").option("--json <json>", "Comment body JSON.").option("--json-file <path>", "Comment body JSON file.").action(async (alertId, opts) => {
963
+ await run(rt, async () => {
964
+ const client = createClient(program.opts());
965
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
966
+ printJson(rt, await client.addAlertComment(alertId, body));
967
+ });
968
+ });
969
+ alerts.command("subscribe").description("Subscribe to an alert.").argument("<alertId>", "Alert ID.").action(async (alertId) => {
970
+ await run(rt, async () => {
971
+ const client = createClient(program.opts());
972
+ printJson(rt, await client.subscribeToAlert(alertId));
973
+ });
974
+ });
975
+ alerts.command("unsubscribe").description("Unsubscribe from an alert.").argument("<alertId>", "Alert ID.").action(async (alertId) => {
976
+ await run(rt, async () => {
977
+ const client = createClient(program.opts());
978
+ printJson(rt, await client.unsubscribeFromAlert(alertId));
979
+ });
980
+ });
981
+ const configs = alerts.command("configs").description("Alert configurations.");
982
+ configs.command("list").description("List alert configurations.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).action(async (opts) => {
983
+ await run(rt, async () => {
984
+ const client = createClient(program.opts());
985
+ printJson(rt, await client.listAlertConfigs(listOpts(opts)));
986
+ });
987
+ });
988
+ configs.command("create").description("Create an alert configuration.").option("--json <json>", "Config body JSON.").option("--json-file <path>", "Config body JSON file.").action(async (opts) => {
989
+ await run(rt, async () => {
990
+ const client = createClient(program.opts());
991
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
992
+ printJson(rt, await client.createAlertConfig(body));
993
+ });
994
+ });
995
+ configs.command("get").description("Get an alert configuration.").argument("<configId>", "Config ID.").action(async (configId) => {
996
+ await run(rt, async () => {
997
+ const client = createClient(program.opts());
998
+ printJson(rt, await client.getAlertConfig(configId));
999
+ });
1000
+ });
1001
+ configs.command("update").description("Update an alert configuration.").argument("<configId>", "Config ID.").option("--json <json>", "Update body JSON.").option("--json-file <path>", "Update body JSON file.").action(async (configId, opts) => {
1002
+ await run(rt, async () => {
1003
+ const client = createClient(program.opts());
1004
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
1005
+ printJson(rt, await client.updateAlertConfig(configId, body));
1006
+ });
1007
+ });
1008
+ configs.command("delete").description("Delete an alert configuration.").argument("<configId>", "Config ID.").action(async (configId) => {
1009
+ await run(rt, async () => {
1010
+ const client = createClient(program.opts());
1011
+ await client.deleteAlertConfig(configId);
1012
+ printJson(rt, { ok: true });
1013
+ });
1014
+ });
1015
+ const prefs = alerts.command("prefs").description("Organization alert preferences.");
1016
+ prefs.command("list").description("List organization alert preferences.").action(async () => {
1017
+ await run(rt, async () => {
1018
+ const client = createClient(program.opts());
1019
+ printJson(rt, await client.listOrganizationAlertPreferences());
1020
+ });
1021
+ });
1022
+ prefs.command("update").description("Update an organization alert preference.").argument("<organizationId>", "Organization ID.").argument("<alertType>", "Alert type.").option("--json <json>", "Preference body JSON.").option("--json-file <path>", "Preference body JSON file.").action(async (organizationId, alertType, opts) => {
1023
+ await run(rt, async () => {
1024
+ const client = createClient(program.opts());
1025
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
1026
+ printJson(rt, await client.updateOrganizationAlertPreference(organizationId, alertType, body));
1027
+ });
1028
+ });
1029
+ }
1030
+
1031
+ // src/commands/models.ts
1032
+ function register10(program, rt) {
1033
+ const models = program.command("models").description("Model alerts and recommendations.");
1034
+ const alerts = models.command("alerts").description("Model alerts.");
1035
+ alerts.command("list").description("List model alerts.").option("--page <n>", "Page number.", (v) => Number(v)).option("--limit <n>", "Page size.", (v) => Number(v)).action(async (opts) => {
1036
+ await run(rt, async () => {
1037
+ const client = createClient(program.opts());
1038
+ printJson(rt, await client.listModelAlerts(listOpts(opts)));
1039
+ });
1040
+ });
1041
+ alerts.command("mark-read").description("Mark a model alert as read.").argument("<alertId>", "Alert ID.").action(async (alertId) => {
1042
+ await run(rt, async () => {
1043
+ const client = createClient(program.opts());
1044
+ await client.markModelAlertRead(alertId);
1045
+ printJson(rt, { ok: true });
1046
+ });
1047
+ });
1048
+ alerts.command("mark-all-read").description("Mark all model alerts as read.").action(async () => {
1049
+ await run(rt, async () => {
1050
+ const client = createClient(program.opts());
1051
+ await client.markAllModelAlertsRead();
1052
+ printJson(rt, { ok: true });
1053
+ });
1054
+ });
1055
+ alerts.command("unread-count").description("Get unread model alert count.").action(async () => {
1056
+ await run(rt, async () => {
1057
+ const client = createClient(program.opts());
1058
+ printJson(rt, await client.getUnreadModelAlertCount());
1059
+ });
1060
+ });
1061
+ models.command("recommendations").description("Get model recommendations.").argument("<modelId>", "Model ID.").action(async (modelId) => {
1062
+ await run(rt, async () => {
1063
+ const client = createClient(program.opts());
1064
+ printJson(rt, await client.getModelRecommendations(modelId));
1065
+ });
1066
+ });
1067
+ }
1068
+
1069
+ // src/commands/search.ts
1070
+ function register11(program, rt) {
1071
+ program.command("search").description("Search across Seclai resources.").requiredOption("--query <text>", "Search query text.").option("--limit <n>", "Max results.", (v) => Number(v)).option("--entity-type <type>", "Filter by entity type (e.g. agent, source, knowledge_base, memory_bank).").action(async (opts) => {
1072
+ await run(rt, async () => {
1073
+ const client = createClient(program.opts());
1074
+ const o = { query: opts.query };
1075
+ if (opts.limit !== void 0) o.limit = opts.limit;
1076
+ if (opts.entityType) o.entityType = opts.entityType;
1077
+ printJson(rt, await client.search(o));
1078
+ });
1079
+ });
1080
+ }
1081
+
1082
+ // src/commands/ai.ts
1083
+ function register12(program, rt) {
1084
+ const ai = program.command("ai").description("Top-level AI assistant.");
1085
+ ai.command("feedback").description("Submit AI feedback.").option("--json <json>", "Feedback body JSON.").option("--json-file <path>", "Feedback body JSON file.").action(async (opts) => {
1086
+ await run(rt, async () => {
1087
+ const client = createClient(program.opts());
1088
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
1089
+ printJson(rt, await client.submitAiFeedback(body));
1090
+ });
1091
+ });
1092
+ withAiInputOptions(
1093
+ ai.command("kb").description("AI assistant for knowledge bases.")
1094
+ ).action(async (opts) => {
1095
+ await run(rt, async () => {
1096
+ const client = createClient(program.opts());
1097
+ const body = await readAiInput(rt, opts);
1098
+ printJson(rt, await client.aiAssistantKnowledgeBase(body));
1099
+ });
1100
+ });
1101
+ withAiInputOptions(
1102
+ ai.command("source").description("AI assistant for sources.")
1103
+ ).action(async (opts) => {
1104
+ await run(rt, async () => {
1105
+ const client = createClient(program.opts());
1106
+ const body = await readAiInput(rt, opts);
1107
+ printJson(rt, await client.aiAssistantSource(body));
1108
+ });
1109
+ });
1110
+ withAiInputOptions(
1111
+ ai.command("solution").description("AI assistant for solutions.")
1112
+ ).action(async (opts) => {
1113
+ await run(rt, async () => {
1114
+ const client = createClient(program.opts());
1115
+ const body = await readAiInput(rt, opts);
1116
+ printJson(rt, await client.aiAssistantSolution(body));
1117
+ });
1118
+ });
1119
+ withAiInputOptions(
1120
+ ai.command("memory").description("AI assistant for memory banks.")
1121
+ ).action(async (opts) => {
1122
+ await run(rt, async () => {
1123
+ const client = createClient(program.opts());
1124
+ const body = await readAiInput(rt, opts);
1125
+ printJson(rt, await client.aiAssistantMemoryBank(body));
1126
+ });
1127
+ });
1128
+ ai.command("memory-history").description("Get AI assistant memory bank conversation history.").action(async () => {
1129
+ await run(rt, async () => {
1130
+ const client = createClient(program.opts());
1131
+ printJson(rt, await client.getAiAssistantMemoryBankHistory());
1132
+ });
1133
+ });
1134
+ ai.command("accept").description("Accept an AI assistant plan.").argument("<conversationId>", "Conversation ID.").option("--json <json>", "Accept body JSON.").option("--json-file <path>", "Accept body JSON file.").action(async (conversationId, opts) => {
1135
+ await run(rt, async () => {
1136
+ const client = createClient(program.opts());
1137
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
1138
+ printJson(rt, await client.acceptAiAssistantPlan(conversationId, body));
1139
+ });
1140
+ });
1141
+ ai.command("decline").description("Decline an AI assistant plan.").argument("<conversationId>", "Conversation ID.").action(async (conversationId) => {
1142
+ await run(rt, async () => {
1143
+ const client = createClient(program.opts());
1144
+ await client.declineAiAssistantPlan(conversationId);
1145
+ printJson(rt, { ok: true });
1146
+ });
1147
+ });
1148
+ ai.command("memory-accept").description("Accept an AI memory bank suggestion.").argument("<conversationId>", "Conversation ID.").option("--json <json>", "Accept body JSON.").option("--json-file <path>", "Accept body JSON file.").action(async (conversationId, opts) => {
1149
+ await run(rt, async () => {
1150
+ const client = createClient(program.opts());
1151
+ const body = await readJsonInput(rt, { json: opts.json, jsonFile: opts.jsonFile });
1152
+ printJson(rt, await client.acceptAiMemoryBankSuggestion(conversationId, body));
1153
+ });
1154
+ });
1155
+ }
1156
+
1157
+ // src/commands/skills.ts
1158
+ import { existsSync, statSync } from "fs";
1159
+ import { mkdir, writeFile } from "fs/promises";
1160
+ import { dirname, join } from "path";
1161
+ var SKILL_MD = `---
1162
+ name: seclai-cli
1163
+ description: >-
1164
+ Manage Seclai agents, knowledge bases, sources, memory banks, evaluations,
1165
+ solutions, governance, alerts, and more via the CLI. Use when working with
1166
+ the Seclai platform or when the user mentions Seclai CLI commands.
1167
+ ---
1168
+
1169
+ # Seclai CLI
1170
+
1171
+ The Seclai CLI (\`seclai\` / \`npx @seclai/cli\`) manages agents, knowledge bases, sources, memory banks, evaluations, solutions, governance, alerts, and more from the terminal.
1172
+
1173
+ All commands output JSON to stdout. Pipe into \`jq\` for filtering.
1174
+
1175
+ ## Quick start
1176
+
1177
+ \`\`\`bash
1178
+ # authenticate
1179
+ export SECLAI_API_KEY="sk-..."
1180
+
1181
+ # create an agent
1182
+ seclai agents create --json '{"name":"My Agent","description":"QA chatbot"}'
1183
+
1184
+ # configure steps via AI assistant
1185
+ seclai agents ai gen-steps <agentId> --user-input "Build a QA chatbot that uses a knowledge base"
1186
+
1187
+ # accept the generated plan
1188
+ seclai agents ai mark <agentId> <conversationId> --json '{"accepted":true}'
1189
+
1190
+ # run the agent
1191
+ seclai agents run <agentId> --json '{"input":"How do I reset my password?"}' --stream
1192
+
1193
+ # list runs
1194
+ seclai agents runs list <agentId>
1195
+ \`\`\`
1196
+
1197
+ ## Authentication
1198
+
1199
+ Set \`SECLAI_API_KEY\` env var or pass \`--api-key <key>\`.
1200
+ Override the API URL with \`SECLAI_API_URL\` (default: https://api.seclai.com).
1201
+
1202
+ ## Global options
1203
+
1204
+ \`\`\`bash
1205
+ --api-key <key> # Seclai API key (or set SECLAI_API_KEY)
1206
+ --compact # Output compact single-line JSON
1207
+ -V, --version # Print version
1208
+ \`\`\`
1209
+
1210
+ ## Common patterns
1211
+
1212
+ ### JSON input
1213
+ Most create/update commands accept \`--json '{"key":"value"}'\` or \`--json-file path.json\`.
1214
+ Use \`--json -\` or \`--json-file -\` to read from stdin.
1215
+
1216
+ ### AI assistant shorthand
1217
+ AI generation commands accept \`--user-input <text>\` as shorthand for \`--json '{"user_input":"<text>"}'\`.
1218
+
1219
+ ### Pagination
1220
+ List commands support \`--page <n>\` and \`--limit <n>\`. Some also support \`--sort <field>\` and \`--order asc|desc\`.
1221
+
1222
+ ### File uploads
1223
+ Upload commands accept \`--file <path>\` (required), plus optional \`--title\`, \`--metadata '{"k":"v"}'\`, \`--metadata-file path.json\`, \`--file-name\`, \`--mime-type\`.
1224
+
1225
+ ## Commands
1226
+
1227
+ ### Agents
1228
+
1229
+ \`\`\`bash
1230
+ seclai agents list [--page N] [--limit N]
1231
+ seclai agents create --json '{"name":"My Agent","description":"..."}'
1232
+ seclai agents get <agentId>
1233
+ seclai agents update <agentId> --json '{"name":"Renamed"}'
1234
+ seclai agents delete <agentId>
1235
+ \`\`\`
1236
+
1237
+ ### Running agents
1238
+
1239
+ \`\`\`bash
1240
+ # simple run \u2014 returns the final result
1241
+ seclai agents run <agentId> --json '{"input":"Hello"}'
1242
+
1243
+ # stream \u2014 wait for completion via SSE, print final result
1244
+ seclai agents run <agentId> --json '{"input":"Hello"}' --stream [--timeout-ms 60000]
1245
+
1246
+ # events \u2014 stream individual SSE events as NDJSON lines
1247
+ # --output: full (entire event), data (event data only), status (status events only)
1248
+ # --event-filter: comma-separated event types to include, e.g. "status,data"
1249
+ seclai agents run <agentId> --json '{"input":"Hello"}' --events [--output full|data|status] [--event-filter "status,data"]
1250
+
1251
+ # poll \u2014 poll for completion
1252
+ seclai agents run <agentId> --json '{"input":"Hello"}' --poll [--poll-interval-ms 2000] [--include-step-outputs]
1253
+ \`\`\`
1254
+
1255
+ ### Agent runs
1256
+
1257
+ \`\`\`bash
1258
+ seclai agents runs list <agentId> [--page N] [--limit N] [--status <status>]
1259
+ seclai agents runs get <runId> [--include-step-outputs]
1260
+ seclai agents runs delete <runId>
1261
+ seclai agents runs cancel <runId>
1262
+ seclai agents runs search --json '{"query":"..."}'
1263
+ seclai agents runs eval-results <agentId> <runId> [--page N] [--limit N]
1264
+ \`\`\`
1265
+
1266
+ ### Agent definitions
1267
+
1268
+ \`\`\`bash
1269
+ seclai agents def get <agentId>
1270
+ seclai agents def update <agentId> --json '{"steps":[{"step_type":"llm","config":{...}}]}'
1271
+ \`\`\`
1272
+
1273
+ ### Agent input uploads
1274
+
1275
+ \`\`\`bash
1276
+ seclai agents upload-input <agentId> --file ./input.pdf [--file-name name] [--mime-type type]
1277
+ seclai agents input-status <agentId> <uploadId>
1278
+ \`\`\`
1279
+
1280
+ ### Agent AI assistant
1281
+
1282
+ \`\`\`bash
1283
+ seclai agents ai gen-steps <agentId> --user-input "Build a QA chatbot"
1284
+ seclai agents ai step-config <agentId> --json '{"step_type":"llm","user_input":"Configure the LLM step"}'
1285
+ seclai agents ai history <agentId>
1286
+ seclai agents ai mark <agentId> <conversationId> --json '{"accepted":true}'
1287
+ \`\`\`
1288
+
1289
+ ### Sources
1290
+
1291
+ \`\`\`bash
1292
+ seclai sources list [--page N] [--limit N] [--sort field] [--order asc|desc] [--account-id id]
1293
+ seclai sources create --json '{"name":"Docs","description":"Product documentation"}'
1294
+ seclai sources get <sourceId>
1295
+ seclai sources update <sourceId> --json '{"name":"Updated Docs"}'
1296
+ seclai sources delete <sourceId>
1297
+ \`\`\`
1298
+
1299
+ ### Source uploads
1300
+
1301
+ \`\`\`bash
1302
+ seclai sources upload <sourceId> --file ./doc.pdf [--title "My Doc"] [--metadata '{"category":"docs"}'] [--file-name name] [--mime-type type]
1303
+ seclai sources upload-text <sourceId> --json '{"text":"Article content here...","title":"My Article"}'
1304
+ \`\`\`
1305
+
1306
+ ### Source exports
1307
+
1308
+ \`\`\`bash
1309
+ seclai sources exports list <sourceId> [--page N] [--limit N]
1310
+ seclai sources exports create <sourceId> --json '{"format":"jsonl"}'
1311
+ seclai sources exports get <sourceId> <exportId>
1312
+ seclai sources exports cancel <sourceId> <exportId>
1313
+ seclai sources exports delete <sourceId> <exportId>
1314
+ seclai sources exports download <sourceId> <exportId>
1315
+ seclai sources exports estimate <sourceId> --json '{"format":"jsonl"}'
1316
+ \`\`\`
1317
+
1318
+ ### Embedding migration
1319
+
1320
+ \`\`\`bash
1321
+ seclai sources migration get <sourceId>
1322
+ seclai sources migration start <sourceId> --json '{"target_model":"text-embedding-3-large"}'
1323
+ seclai sources migration cancel <sourceId>
1324
+ \`\`\`
1325
+
1326
+ ### Contents (indexed content)
1327
+
1328
+ \`\`\`bash
1329
+ seclai contents get <contentVersionId> [--start N] [--end N]
1330
+ seclai contents delete <contentVersionId>
1331
+ seclai contents upload <contentVersionId> --file ./updated.pdf [--title "Title"] [--file-name name] [--mime-type type]
1332
+ seclai contents replace-text <contentVersionId> --json '{"text":"Replacement text","title":"Updated"}'
1333
+ seclai contents embeddings <contentVersionId> [--page N] [--limit N]
1334
+ \`\`\`
1335
+
1336
+ ### Knowledge bases
1337
+
1338
+ \`\`\`bash
1339
+ seclai kb list [--page N] [--limit N] [--sort field] [--order asc|desc]
1340
+ seclai kb create --json '{"name":"Support KB","description":"Customer support articles"}'
1341
+ seclai kb get <kbId>
1342
+ seclai kb update <kbId> --json '{"name":"Updated KB"}'
1343
+ seclai kb delete <kbId>
1344
+ \`\`\`
1345
+
1346
+ ### Memory banks
1347
+
1348
+ \`\`\`bash
1349
+ seclai memory list [--page N] [--limit N] [--sort field] [--order asc|desc]
1350
+ # type: "conversation" (chat history) or "general" (structured facts)
1351
+ seclai memory create --json '{"name":"Chat Memory","type":"conversation"}'
1352
+ seclai memory get <memoryBankId>
1353
+ seclai memory update <memoryBankId> --json '{"name":"Renamed"}'
1354
+ seclai memory delete <memoryBankId>
1355
+ \`\`\`
1356
+
1357
+ ### Memory bank utilities
1358
+
1359
+ \`\`\`bash
1360
+ seclai memory stats <memoryBankId>
1361
+ seclai memory agents <memoryBankId>
1362
+ seclai memory compact <memoryBankId>
1363
+ seclai memory delete-source <memoryBankId>
1364
+ seclai memory templates
1365
+ seclai memory test-compaction <memoryBankId> --json '{"prompt":"Summarize the conversation"}'
1366
+ seclai memory test-compaction-standalone --json '{"prompt":"Summarize the conversation"}'
1367
+ \`\`\`
1368
+
1369
+ ### Memory bank AI
1370
+
1371
+ \`\`\`bash
1372
+ seclai memory ai generate --user-input "Configure compaction for chat memory"
1373
+ seclai memory ai last
1374
+ seclai memory ai accept <conversationId> --json '{"accepted":true}'
1375
+ \`\`\`
1376
+
1377
+ ### Evaluations \u2014 criteria
1378
+
1379
+ \`\`\`bash
1380
+ seclai evals criteria list <agentId> [--page N] [--limit N]
1381
+ seclai evals criteria create <agentId> --json '{"name":"Response Quality","description":"...","eval_type":"llm_judge"}'
1382
+ seclai evals criteria get <criteriaId>
1383
+ seclai evals criteria update <criteriaId> --json '{"name":"Updated Criteria"}'
1384
+ seclai evals criteria delete <criteriaId>
1385
+ seclai evals criteria summary <criteriaId>
1386
+ \`\`\`
1387
+
1388
+ ### Evaluations \u2014 results & runs
1389
+
1390
+ \`\`\`bash
1391
+ seclai evals results list <criteriaId> [--page N] [--limit N]
1392
+ seclai evals results create <criteriaId> --json '{"run_id":"...","score":0.9}'
1393
+ seclai evals compatible-runs <criteriaId> [--page N] [--limit N]
1394
+ seclai evals test-draft <agentId> --json '{"criteria":{"name":"Test","eval_type":"llm_judge"},"run_id":"..."}'
1395
+ seclai evals agent-results <agentId> [--page N] [--limit N]
1396
+ seclai evals agent-runs <agentId> [--page N] [--limit N]
1397
+ seclai evals non-manual-summary <agentId>
1398
+ \`\`\`
1399
+
1400
+ ### Solutions
1401
+
1402
+ \`\`\`bash
1403
+ seclai solutions list [--page N] [--limit N] [--sort field] [--order asc|desc]
1404
+ seclai solutions create --json '{"name":"Customer Support Solution"}'
1405
+ seclai solutions get <solutionId>
1406
+ seclai solutions update <solutionId> --json '{"name":"Updated"}'
1407
+ seclai solutions delete <solutionId>
1408
+ \`\`\`
1409
+
1410
+ ### Solution links
1411
+
1412
+ \`\`\`bash
1413
+ # link resources \u2014 each flag takes a JSON array of IDs
1414
+ seclai solutions link <solutionId> --agents '["agentId1"]' --kb '["kbId1"]' --sources '["sourceId1"]'
1415
+ seclai solutions unlink <solutionId> --agents '["agentId1"]'
1416
+ \`\`\`
1417
+
1418
+ ### Solution conversations & AI
1419
+
1420
+ \`\`\`bash
1421
+ seclai solutions convos list <solutionId>
1422
+ seclai solutions convos add <solutionId> --json '{"message":"How should I structure this?"}'
1423
+ seclai solutions convos mark <solutionId> <conversationId> --json '{"accepted":true}'
1424
+
1425
+ seclai solutions ai generate <solutionId> --user-input "Add an FAQ source"
1426
+ seclai solutions ai kb <solutionId> --user-input "Create a knowledge base for docs"
1427
+ seclai solutions ai source <solutionId> --user-input "Create a file source for PDFs"
1428
+ seclai solutions ai accept <solutionId> <conversationId> --json '{"accepted":true}'
1429
+ seclai solutions ai decline <solutionId> <conversationId>
1430
+ \`\`\`
1431
+
1432
+ ### Alerts
1433
+
1434
+ \`\`\`bash
1435
+ seclai alerts list [--page N] [--limit N] [--status <status>] [--severity <severity>]
1436
+ seclai alerts get <alertId>
1437
+ seclai alerts status <alertId> --json '{"status":"resolved"}'
1438
+ seclai alerts comment <alertId> --json '{"comment":"Fixed the issue"}'
1439
+ seclai alerts subscribe <alertId>
1440
+ seclai alerts unsubscribe <alertId>
1441
+ \`\`\`
1442
+
1443
+ ### Alert configurations
1444
+
1445
+ \`\`\`bash
1446
+ seclai alerts configs list [--page N] [--limit N]
1447
+ seclai alerts configs create --json '{"name":"Latency Alert","description":"...","threshold":5000}'
1448
+ seclai alerts configs get <configId>
1449
+ seclai alerts configs update <configId> --json '{"threshold":3000}'
1450
+ seclai alerts configs delete <configId>
1451
+ \`\`\`
1452
+
1453
+ ### Alert preferences
1454
+
1455
+ \`\`\`bash
1456
+ seclai alerts prefs list
1457
+ seclai alerts prefs update <organizationId> <alertType> --json '{"enabled":true}'
1458
+ \`\`\`
1459
+
1460
+ ### Governance AI
1461
+
1462
+ \`\`\`bash
1463
+ seclai governance ai generate --user-input "Create a content safety policy"
1464
+ seclai governance ai list
1465
+ seclai governance ai accept <conversationId>
1466
+ seclai governance ai decline <conversationId>
1467
+ \`\`\`
1468
+
1469
+ ### Model alerts
1470
+
1471
+ \`\`\`bash
1472
+ seclai models alerts list [--page N] [--limit N]
1473
+ seclai models alerts mark-read <alertId>
1474
+ seclai models alerts mark-all-read
1475
+ seclai models alerts unread-count
1476
+ seclai models recommendations <modelId>
1477
+ \`\`\`
1478
+
1479
+ ### Search
1480
+
1481
+ \`\`\`bash
1482
+ seclai search --query "deployment guide" [--limit N] [--entity-type <type>]
1483
+ \`\`\`
1484
+
1485
+ ### AI assistant (global)
1486
+
1487
+ \`\`\`bash
1488
+ seclai ai feedback --json '{"feedback":"The response was helpful"}'
1489
+ seclai ai kb --user-input "Create a support knowledge base"
1490
+ seclai ai source --user-input "Create a documentation source"
1491
+ seclai ai solution --user-input "Build a customer support solution"
1492
+ seclai ai memory --user-input "Create a conversation memory bank"
1493
+ seclai ai memory-history
1494
+ seclai ai accept <conversationId> --json '{"accepted":true}'
1495
+ seclai ai decline <conversationId>
1496
+ seclai ai memory-accept <conversationId> --json '{"accepted":true}'
1497
+ \`\`\`
1498
+
1499
+ ### Skills
1500
+
1501
+ \`\`\`bash
1502
+ # install skill files into AI coding tool directories (auto-detects or specify)
1503
+ seclai skills install [--tool copilot|claude|cursor|windsurf|codex|kiro|cline|roo|gemini|antigravity|all] [--dir .]
1504
+ \`\`\`
1505
+
1506
+ ### MCP server
1507
+
1508
+ \`\`\`bash
1509
+ # configure MCP server access in AI coding tool config files
1510
+ seclai mcp configure --key <apiKey> [--target claude-code|cursor|claude-desktop|windsurf|all] [--dir .]
1511
+
1512
+ # show the MCP config JSON snippet
1513
+ seclai mcp show [--key <apiKey>]
1514
+ \`\`\`
1515
+
1516
+ ## Example: Create a source and upload content
1517
+
1518
+ \`\`\`bash
1519
+ seclai sources create --json '{"name":"Product Docs","description":"Product documentation source"}'
1520
+ # note the id from the output
1521
+ seclai sources upload <sourceId> --file ./docs.pdf --title "Product Manual" --metadata '{"version":"2.0"}'
1522
+ seclai sources get <sourceId>
1523
+ \`\`\`
1524
+
1525
+ ## Example: Set up a knowledge base with an agent
1526
+
1527
+ \`\`\`bash
1528
+ seclai kb create --json '{"name":"Support KB","description":"Customer support articles"}'
1529
+ seclai agents create --json '{"name":"Support Bot","description":"Answers customer questions"}'
1530
+ seclai agents ai gen-steps <agentId> --user-input "Build a QA chatbot that searches the Support KB"
1531
+ seclai agents ai mark <agentId> <conversationId> --json '{"accepted":true}'
1532
+ seclai agents run <agentId> --json '{"input":"How do I reset my password?"}' --stream
1533
+ \`\`\`
1534
+
1535
+ ## Example: Evaluate agent quality
1536
+
1537
+ \`\`\`bash
1538
+ # create eval criteria
1539
+ seclai evals criteria create <agentId> --json '{"name":"Answer Accuracy","eval_type":"llm_judge","description":"Does the answer correctly address the question?"}'
1540
+ # find compatible runs
1541
+ seclai evals compatible-runs <criteriaId> --limit 5
1542
+ # test the criteria against a run without persisting
1543
+ seclai evals test-draft <agentId> --json '{"criteria":{"name":"Answer Accuracy","eval_type":"llm_judge"},"run_id":"<runId>"}'
1544
+ # create a persisted result
1545
+ seclai evals results create <criteriaId> --json '{"run_id":"<runId>","score":0.95}'
1546
+ # view summary
1547
+ seclai evals criteria summary <criteriaId>
1548
+ \`\`\`
1549
+
1550
+ ## Example: Solution with linked resources
1551
+
1552
+ \`\`\`bash
1553
+ seclai solutions create --json '{"name":"Customer Support"}'
1554
+ seclai solutions link <solutionId> --agents '["<agentId>"]' --kb '["<kbId>"]' --sources '["<sourceId>"]'
1555
+ seclai solutions get <solutionId>
1556
+ \`\`\`
1557
+
1558
+ ## Example: Memory-powered agent
1559
+
1560
+ \`\`\`bash
1561
+ seclai memory create --json '{"name":"User Preferences","type":"general"}'
1562
+ seclai agents create --json '{"name":"Personal Assistant","description":"Remembers user preferences"}'
1563
+ seclai agents ai gen-steps <agentId> --user-input "Build a chat agent that remembers user preferences. Use general memory bank <memoryBankId>"
1564
+ seclai agents ai mark <agentId> <conversationId> --json '{"accepted":true}'
1565
+ \`\`\`
1566
+
1567
+ ## Example: Governance policy setup
1568
+
1569
+ \`\`\`bash
1570
+ seclai governance ai generate --user-input "Create a content safety policy that blocks harmful outputs"
1571
+ seclai governance ai list
1572
+ seclai governance ai accept <conversationId>
1573
+ \`\`\`
1574
+
1575
+ ## Specific topics
1576
+
1577
+ * **Streaming & event modes** [references/streaming.md](references/streaming.md)
1578
+ * **File uploads & content management** [references/uploads.md](references/uploads.md)
1579
+ * **Evaluations workflow** [references/evaluations.md](references/evaluations.md)
1580
+ `;
1581
+ var STREAMING_REF = `# Streaming Agent Runs
1582
+
1583
+ ## Modes
1584
+
1585
+ ### --stream
1586
+ Wait for the agent run to complete via SSE. Prints the final result as a single JSON object.
1587
+ Useful when you want to block until done.
1588
+
1589
+ \`\`\`bash
1590
+ seclai agents run <agentId> --json '{"input":"Hello"}' --stream
1591
+ seclai agents run <agentId> --json '{"input":"Hello"}' --stream --timeout-ms 120000
1592
+ \`\`\`
1593
+
1594
+ ### --events
1595
+ Stream individual SSE events as NDJSON (one JSON object per line). Use for real-time processing.
1596
+
1597
+ \`\`\`bash
1598
+ # all events, full event objects
1599
+ seclai agents run <agentId> --json '{"input":"Hello"}' --events
1600
+
1601
+ # only data payloads (no event metadata)
1602
+ seclai agents run <agentId> --json '{"input":"Hello"}' --events --output data
1603
+
1604
+ # only status events
1605
+ seclai agents run <agentId> --json '{"input":"Hello"}' --events --output status
1606
+
1607
+ # filter specific event types
1608
+ seclai agents run <agentId> --json '{"input":"Hello"}' --events --event-filter "status,data"
1609
+ \`\`\`
1610
+
1611
+ Output modes for --events:
1612
+ - \`full\`: entire SSE event object (default)
1613
+ - \`data\`: only the data payload of each event
1614
+ - \`status\`: only events with status information
1615
+
1616
+ ### --poll
1617
+ Poll the API at intervals for run completion. Does not use SSE.
1618
+
1619
+ \`\`\`bash
1620
+ seclai agents run <agentId> --json '{"input":"Hello"}' --poll
1621
+ seclai agents run <agentId> --json '{"input":"Hello"}' --poll --poll-interval-ms 5000 --include-step-outputs
1622
+ \`\`\`
1623
+
1624
+ ### No flag
1625
+ Fire-and-forget: starts the run and immediately returns the run ID.
1626
+
1627
+ \`\`\`bash
1628
+ seclai agents run <agentId> --json '{"input":"Hello"}'
1629
+ # returns: {"id":"run_...","status":"queued",...}
1630
+ # check later:
1631
+ seclai agents runs get <runId>
1632
+ \`\`\`
1633
+ `;
1634
+ var UPLOADS_REF = `# File Uploads & Content Management
1635
+
1636
+ ## Upload to a source
1637
+ \`\`\`bash
1638
+ seclai sources upload <sourceId> --file ./doc.pdf
1639
+ seclai sources upload <sourceId> --file ./doc.pdf --title "My Doc" --metadata '{"category":"docs"}' --file-name "custom-name.pdf" --mime-type "application/pdf"
1640
+ seclai sources upload <sourceId> --file ./doc.pdf --metadata-file ./meta.json
1641
+ \`\`\`
1642
+
1643
+ ## Upload text directly
1644
+ \`\`\`bash
1645
+ seclai sources upload-text <sourceId> --json '{"text":"Article content here...","title":"My Article"}'
1646
+ \`\`\`
1647
+
1648
+ ## Upload input for agent runs
1649
+ \`\`\`bash
1650
+ seclai agents upload-input <agentId> --file ./input.pdf
1651
+ seclai agents upload-input <agentId> --file ./data.csv --file-name "report.csv" --mime-type "text/csv"
1652
+ seclai agents input-status <agentId> <uploadId>
1653
+ \`\`\`
1654
+
1655
+ ## Replace content
1656
+ \`\`\`bash
1657
+ # replace with file
1658
+ seclai contents upload <contentVersionId> --file ./updated.pdf
1659
+
1660
+ # replace with text
1661
+ seclai contents replace-text <contentVersionId> --json '{"text":"Updated content","title":"Revised Article"}'
1662
+ \`\`\`
1663
+
1664
+ ## Read content
1665
+ \`\`\`bash
1666
+ # full content
1667
+ seclai contents get <contentVersionId>
1668
+
1669
+ # text slice (0-based offsets)
1670
+ seclai contents get <contentVersionId> --start 0 --end 1000
1671
+
1672
+ # view embeddings
1673
+ seclai contents embeddings <contentVersionId> [--page N] [--limit N]
1674
+ \`\`\`
1675
+ `;
1676
+ var EVALUATIONS_REF = `# Evaluations Workflow
1677
+
1678
+ ## Step 1: Create evaluation criteria for an agent
1679
+ \`\`\`bash
1680
+ seclai evals criteria create <agentId> --json '{"name":"Answer Accuracy","description":"Does the answer correctly address the question?","eval_type":"llm_judge"}'
1681
+ \`\`\`
1682
+
1683
+ ## Step 2: Find runs to evaluate
1684
+ \`\`\`bash
1685
+ # list all runs for an agent
1686
+ seclai agents runs list <agentId> --limit 10
1687
+
1688
+ # or find runs compatible with specific criteria
1689
+ seclai evals compatible-runs <criteriaId> --limit 10
1690
+ \`\`\`
1691
+
1692
+ ## Step 3: Test criteria before committing
1693
+ \`\`\`bash
1694
+ seclai evals test-draft <agentId> --json '{"criteria":{"name":"Answer Accuracy","eval_type":"llm_judge","description":"..."},"run_id":"<runId>"}'
1695
+ \`\`\`
1696
+
1697
+ ## Step 4: Create evaluation results
1698
+ \`\`\`bash
1699
+ seclai evals results create <criteriaId> --json '{"run_id":"<runId>","score":0.95}'
1700
+ \`\`\`
1701
+
1702
+ ## Step 5: Review summaries
1703
+ \`\`\`bash
1704
+ seclai evals criteria summary <criteriaId>
1705
+ seclai evals agent-results <agentId>
1706
+ seclai evals agent-runs <agentId> --limit 20
1707
+ seclai evals non-manual-summary <agentId>
1708
+ \`\`\`
1709
+
1710
+ ## Managing criteria
1711
+ \`\`\`bash
1712
+ seclai evals criteria list <agentId>
1713
+ seclai evals criteria get <criteriaId>
1714
+ seclai evals criteria update <criteriaId> --json '{"name":"Updated Name"}'
1715
+ seclai evals criteria delete <criteriaId>
1716
+ \`\`\`
1717
+
1718
+ ## Viewing results
1719
+ \`\`\`bash
1720
+ seclai evals results list <criteriaId> [--page N] [--limit N]
1721
+ \`\`\`
1722
+ `;
1723
+ function getToolConfig(tool, destDir) {
1724
+ const skillFiles = [
1725
+ { name: "SKILL.md", content: SKILL_MD },
1726
+ { name: "references/streaming.md", content: STREAMING_REF },
1727
+ { name: "references/uploads.md", content: UPLOADS_REF },
1728
+ { name: "references/evaluations.md", content: EVALUATIONS_REF }
1729
+ ];
1730
+ switch (tool) {
1731
+ case "copilot":
1732
+ return { dir: join(destDir, ".github", "copilot", "seclai-cli"), files: skillFiles };
1733
+ case "claude":
1734
+ return { dir: join(destDir, ".claude", "skills", "seclai-cli"), files: skillFiles };
1735
+ case "cursor":
1736
+ return { dir: join(destDir, ".cursor", "skills", "seclai-cli"), files: skillFiles };
1737
+ case "windsurf":
1738
+ return { dir: join(destDir, ".windsurf", "skills", "seclai-cli"), files: skillFiles };
1739
+ case "codex":
1740
+ return { dir: join(destDir, ".codex", "skills", "seclai-cli"), files: skillFiles };
1741
+ case "kiro":
1742
+ return { dir: join(destDir, ".kiro", "steering", "seclai-cli"), files: skillFiles };
1743
+ case "cline":
1744
+ return { dir: join(destDir, ".clinerules", "seclai-cli"), files: skillFiles };
1745
+ case "roo":
1746
+ return { dir: join(destDir, ".roo", "rules", "seclai-cli"), files: skillFiles };
1747
+ case "gemini":
1748
+ return { dir: join(destDir, ".gemini", "seclai-cli"), files: skillFiles };
1749
+ case "antigravity":
1750
+ return { dir: join(destDir, ".antigravity", "seclai-cli"), files: skillFiles };
1751
+ default:
1752
+ throw new Error(`Unknown tool: ${tool}. Use copilot, claude, cursor, windsurf, codex, kiro, cline, roo, gemini, or antigravity.`);
1753
+ }
1754
+ }
1755
+ function detectTools(destDir) {
1756
+ const detected = [];
1757
+ if (existsSync(join(destDir, ".github", "copilot"))) detected.push("copilot");
1758
+ if (existsSync(join(destDir, ".claude")) || existsSync(join(destDir, "CLAUDE.md")))
1759
+ detected.push("claude");
1760
+ if (existsSync(join(destDir, ".cursor"))) detected.push("cursor");
1761
+ if (existsSync(join(destDir, ".windsurf"))) detected.push("windsurf");
1762
+ if (existsSync(join(destDir, ".codex"))) detected.push("codex");
1763
+ if (existsSync(join(destDir, ".kiro"))) detected.push("kiro");
1764
+ if (existsSync(join(destDir, ".clinerules")) && statSync(join(destDir, ".clinerules")).isDirectory()) detected.push("cline");
1765
+ if (existsSync(join(destDir, ".roo"))) detected.push("roo");
1766
+ if (existsSync(join(destDir, ".gemini")) || existsSync(join(destDir, "GEMINI.md")))
1767
+ detected.push("gemini");
1768
+ if (existsSync(join(destDir, ".antigravity"))) detected.push("antigravity");
1769
+ return detected;
1770
+ }
1771
+ function register13(program, rt) {
1772
+ const skills = program.command("skills").description("Install Seclai CLI skill files for AI coding tools.");
1773
+ skills.command("install").description(
1774
+ "Write Seclai CLI skill/instruction files into the current workspace.\n\nDetected tools: copilot, claude, cursor, windsurf, codex, kiro, cline, roo, gemini, antigravity.\nUse --tool to target a specific tool, or 'all' for all supported tools."
1775
+ ).option("--tool <name>", "Target tool (copilot|claude|cursor|windsurf|codex|kiro|cline|roo|gemini|antigravity|all). Auto-detects if omitted.").option("--dir <path>", "Target directory (default: current directory).", ".").action(async (opts) => {
1776
+ await run(rt, async () => {
1777
+ const destDir = opts.dir;
1778
+ let tools;
1779
+ if (opts.tool === "all") {
1780
+ tools = ["copilot", "claude", "cursor", "windsurf", "codex", "kiro", "cline", "roo", "gemini", "antigravity"];
1781
+ } else if (opts.tool) {
1782
+ tools = [opts.tool];
1783
+ } else {
1784
+ tools = detectTools(destDir);
1785
+ if (tools.length === 0) {
1786
+ tools = ["copilot"];
1787
+ rt.writeErr("No AI tool detected, defaulting to copilot.\n");
1788
+ }
1789
+ }
1790
+ let totalFiles = 0;
1791
+ for (const tool of tools) {
1792
+ const config = getToolConfig(tool, destDir);
1793
+ for (const file of config.files) {
1794
+ const filePath = join(config.dir, file.name);
1795
+ await mkdir(dirname(filePath), { recursive: true });
1796
+ await writeFile(filePath, file.content, "utf8");
1797
+ totalFiles++;
1798
+ }
1799
+ rt.writeErr(`Installed ${config.files.length} skill files for ${tool} \u2192 ${config.dir}
1800
+ `);
1801
+ }
1802
+ printJson(rt, { ok: true, tools, filesWritten: totalFiles });
1803
+ });
1804
+ });
1805
+ }
1806
+
1807
+ // src/commands/mcp.ts
1808
+ import { existsSync as existsSync2 } from "fs";
1809
+ import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from "fs/promises";
1810
+ import { dirname as dirname2, join as join2 } from "path";
1811
+ import { homedir, platform } from "os";
1812
+ var MCP_URL = "https://api.seclai.com/mcp";
1813
+ function buildMcpEntry(apiKey) {
1814
+ return {
1815
+ type: "streamable-http",
1816
+ url: MCP_URL,
1817
+ headers: { "X-API-Key": apiKey }
1818
+ };
1819
+ }
1820
+ function getTargets(destDir) {
1821
+ const home = homedir();
1822
+ const os = platform();
1823
+ const targets = [
1824
+ // Project-scoped configs
1825
+ { name: "claude-code", path: join2(destDir, ".mcp.json"), scope: "project" },
1826
+ { name: "cursor", path: join2(destDir, ".cursor", "mcp.json"), scope: "project" }
1827
+ ];
1828
+ if (os === "win32") {
1829
+ targets.push({
1830
+ name: "claude-desktop",
1831
+ path: join2(process.env["APPDATA"] ?? join2(home, "AppData", "Roaming"), "Claude", "claude_desktop_config.json"),
1832
+ scope: "global"
1833
+ });
1834
+ } else if (os === "darwin") {
1835
+ targets.push({
1836
+ name: "claude-desktop",
1837
+ path: join2(home, "Library", "Application Support", "Claude", "claude_desktop_config.json"),
1838
+ scope: "global"
1839
+ });
1840
+ }
1841
+ targets.push({ name: "windsurf", path: join2(home, ".codeium", "windsurf", "mcp_config.json"), scope: "global" });
1842
+ return targets;
1843
+ }
1844
+ async function mergeConfig(filePath, apiKey) {
1845
+ let existing = {};
1846
+ if (existsSync2(filePath)) {
1847
+ try {
1848
+ const parsed = JSON.parse(await readFile2(filePath, "utf8"));
1849
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) return false;
1850
+ existing = parsed;
1851
+ } catch {
1852
+ return false;
1853
+ }
1854
+ }
1855
+ const raw = existing["mcpServers"];
1856
+ const servers = typeof raw === "object" && raw !== null && !Array.isArray(raw) ? raw : {};
1857
+ servers["seclai"] = buildMcpEntry(apiKey);
1858
+ existing["mcpServers"] = servers;
1859
+ await mkdir2(dirname2(filePath), { recursive: true });
1860
+ await writeFile2(filePath, JSON.stringify(existing, null, 2) + "\n", "utf8");
1861
+ return true;
1862
+ }
1863
+ function detectTargets(destDir) {
1864
+ const all = getTargets(destDir);
1865
+ return all.filter((t) => {
1866
+ if (t.scope === "global") return existsSync2(dirname2(t.path));
1867
+ if (t.name === "claude-code") return existsSync2(join2(destDir, ".claude")) || existsSync2(join2(destDir, "CLAUDE.md"));
1868
+ if (t.name === "cursor") return existsSync2(join2(destDir, ".cursor"));
1869
+ return false;
1870
+ });
1871
+ }
1872
+ function register14(program, rt) {
1873
+ const mcp = program.command("mcp").description("Configure the Seclai MCP server for AI coding tools.");
1874
+ mcp.command("configure").description(
1875
+ "Add the Seclai MCP server to AI coding tool config files.\n\nTargets: claude-code, cursor, claude-desktop, windsurf.\nUse --target to pick a specific tool, or 'all' for all known targets."
1876
+ ).requiredOption("--key <key>", "Seclai API key to embed in the config.").option("--target <name>", "Target tool (claude-code|cursor|claude-desktop|windsurf|all). Auto-detects if omitted.").option("--dir <path>", "Project directory for project-scoped configs (default: current directory).", ".").action(async (opts) => {
1877
+ await run(rt, async () => {
1878
+ const destDir = opts.dir;
1879
+ const apiKey = opts.key;
1880
+ const allTargets = getTargets(destDir);
1881
+ let targets;
1882
+ if (opts.target === "all") {
1883
+ targets = allTargets;
1884
+ } else if (opts.target) {
1885
+ const found = allTargets.find((t) => t.name === opts.target);
1886
+ if (!found) {
1887
+ rt.writeErr(`Unknown target "${opts.target}". Use: claude-code, cursor, claude-desktop, windsurf, or all.
1888
+ `);
1889
+ rt.setExitCode(1);
1890
+ return;
1891
+ }
1892
+ targets = [found];
1893
+ } else {
1894
+ targets = detectTargets(destDir);
1895
+ if (targets.length === 0) {
1896
+ targets = [allTargets[0]];
1897
+ rt.writeErr("No MCP-compatible tool detected, defaulting to claude-code (.mcp.json).\n");
1898
+ }
1899
+ }
1900
+ let configured = 0;
1901
+ const failures = [];
1902
+ for (const target of targets) {
1903
+ const ok = await mergeConfig(target.path, apiKey);
1904
+ if (ok) {
1905
+ configured++;
1906
+ rt.writeErr(`Configured seclai MCP for ${target.name} \u2192 ${target.path}
1907
+ `);
1908
+ } else {
1909
+ failures.push(target.name);
1910
+ rt.writeErr(`Failed to parse existing config at ${target.path}, skipping.
1911
+ `);
1912
+ }
1913
+ }
1914
+ const allOk = failures.length === 0;
1915
+ printJson(rt, { ok: allOk, targets: targets.map((t) => t.name), filesWritten: configured, ...failures.length > 0 ? { failures } : {} });
1916
+ if (!allOk) rt.setExitCode(1);
1917
+ });
1918
+ });
1919
+ mcp.command("show").description("Show the Seclai MCP server JSON configuration snippet.").option("--key <key>", "API key to include (default: placeholder).").action(async (opts) => {
1920
+ await run(rt, async () => {
1921
+ const entry = buildMcpEntry(opts.key ?? "YOUR_API_KEY");
1922
+ printJson(rt, { mcpServers: { seclai: entry } });
1923
+ });
1924
+ });
1925
+ }
1926
+
1927
+ // src/commands/completion.ts
1928
+ var BASH = `#!/usr/bin/env bash
1929
+ # seclai bash completion \u2014 add to ~/.bashrc:
1930
+ # eval "$(seclai completion bash)"
1931
+
1932
+ _seclai_completions() {
1933
+ local cur prev commands
1934
+ cur="\${COMP_WORDS[COMP_CWORD]}"
1935
+ prev="\${COMP_WORDS[COMP_CWORD-1]}"
1936
+
1937
+ # Top-level commands
1938
+ commands="agents sources contents kb memory evals solutions governance alerts models search ai skills mcp completion help"
1939
+
1940
+ case "\${COMP_WORDS[1]}" in
1941
+ agents)
1942
+ case "\${COMP_WORDS[2]}" in
1943
+ runs) COMPREPLY=( $(compgen -W "list get delete cancel search eval-results" -- "$cur") ); return ;;
1944
+ def) COMPREPLY=( $(compgen -W "get update" -- "$cur") ); return ;;
1945
+ ai) COMPREPLY=( $(compgen -W "gen-steps step-config history mark" -- "$cur") ); return ;;
1946
+ *) COMPREPLY=( $(compgen -W "list create get update delete run runs def upload-input input-status ai" -- "$cur") ); return ;;
1947
+ esac ;;
1948
+ sources|source)
1949
+ case "\${COMP_WORDS[2]}" in
1950
+ exports) COMPREPLY=( $(compgen -W "list create get cancel delete download estimate" -- "$cur") ); return ;;
1951
+ migration) COMPREPLY=( $(compgen -W "get start cancel" -- "$cur") ); return ;;
1952
+ *) COMPREPLY=( $(compgen -W "list create get update delete upload upload-text exports migration" -- "$cur") ); return ;;
1953
+ esac ;;
1954
+ contents) COMPREPLY=( $(compgen -W "get delete upload replace replace-text embeddings" -- "$cur") ); return ;;
1955
+ kb) COMPREPLY=( $(compgen -W "list create get update delete" -- "$cur") ); return ;;
1956
+ memory)
1957
+ case "\${COMP_WORDS[2]}" in
1958
+ ai) COMPREPLY=( $(compgen -W "generate last accept" -- "$cur") ); return ;;
1959
+ *) COMPREPLY=( $(compgen -W "list create get update delete stats agents compact delete-source templates test-compaction test-compaction-standalone ai" -- "$cur") ); return ;;
1960
+ esac ;;
1961
+ evals)
1962
+ case "\${COMP_WORDS[2]}" in
1963
+ criteria) COMPREPLY=( $(compgen -W "list create get update delete summary" -- "$cur") ); return ;;
1964
+ results) COMPREPLY=( $(compgen -W "list create" -- "$cur") ); return ;;
1965
+ *) COMPREPLY=( $(compgen -W "criteria results compatible-runs test-draft agent-results agent-runs non-manual-summary" -- "$cur") ); return ;;
1966
+ esac ;;
1967
+ solutions)
1968
+ case "\${COMP_WORDS[2]}" in
1969
+ convos) COMPREPLY=( $(compgen -W "list add mark" -- "$cur") ); return ;;
1970
+ ai) COMPREPLY=( $(compgen -W "generate kb source accept decline" -- "$cur") ); return ;;
1971
+ *) COMPREPLY=( $(compgen -W "list create get update delete link unlink convos ai" -- "$cur") ); return ;;
1972
+ esac ;;
1973
+ governance)
1974
+ case "\${COMP_WORDS[2]}" in
1975
+ ai) COMPREPLY=( $(compgen -W "generate list accept decline" -- "$cur") ); return ;;
1976
+ *) COMPREPLY=( $(compgen -W "ai" -- "$cur") ); return ;;
1977
+ esac ;;
1978
+ alerts)
1979
+ case "\${COMP_WORDS[2]}" in
1980
+ configs) COMPREPLY=( $(compgen -W "list create get update delete" -- "$cur") ); return ;;
1981
+ prefs) COMPREPLY=( $(compgen -W "list update" -- "$cur") ); return ;;
1982
+ *) COMPREPLY=( $(compgen -W "list get status comment subscribe unsubscribe configs prefs" -- "$cur") ); return ;;
1983
+ esac ;;
1984
+ models)
1985
+ case "\${COMP_WORDS[2]}" in
1986
+ alerts) COMPREPLY=( $(compgen -W "list mark-read mark-all-read unread-count" -- "$cur") ); return ;;
1987
+ *) COMPREPLY=( $(compgen -W "alerts recommendations" -- "$cur") ); return ;;
1988
+ esac ;;
1989
+ ai) COMPREPLY=( $(compgen -W "feedback kb source solution memory memory-history accept decline memory-accept" -- "$cur") ); return ;;
1990
+ skills) COMPREPLY=( $(compgen -W "install" -- "$cur") ); return ;;
1991
+ mcp) COMPREPLY=( $(compgen -W "configure show" -- "$cur") ); return ;;
1992
+ completion) COMPREPLY=( $(compgen -W "bash zsh fish" -- "$cur") ); return ;;
1993
+ esac
1994
+
1995
+ COMPREPLY=( $(compgen -W "$commands" -- "$cur") )
1996
+ }
1997
+
1998
+ complete -F _seclai_completions seclai
1999
+ `;
2000
+ var ZSH = `#compdef seclai
2001
+ # seclai zsh completion \u2014 add to ~/.zshrc:
2002
+ # eval "$(seclai completion zsh)"
2003
+
2004
+ _seclai() {
2005
+ local -a commands
2006
+ commands=(
2007
+ 'agents:Manage agents, runs, definitions, and AI assistance'
2008
+ 'sources:Manage content sources'
2009
+ 'contents:Manage indexed content and embeddings'
2010
+ 'kb:Manage knowledge bases'
2011
+ 'memory:Manage memory banks'
2012
+ 'evals:Manage evaluations'
2013
+ 'solutions:Manage solutions'
2014
+ 'governance:Governance AI assistant'
2015
+ 'alerts:Manage alerts and alert configurations'
2016
+ 'models:Model alerts and recommendations'
2017
+ 'search:Search across Seclai resources'
2018
+ 'ai:Top-level AI assistant'
2019
+ 'skills:Install skill files for AI coding tools'
2020
+ 'mcp:Configure the Seclai MCP server'
2021
+ 'completion:Generate shell completion scripts'
2022
+ 'help:Display help for command'
2023
+ )
2024
+
2025
+ _arguments -C \\
2026
+ '--api-key[Seclai API key]:key' \\
2027
+ '--compact[Output compact JSON]' \\
2028
+ '-V[Output version]' \\
2029
+ '-h[Display help]' \\
2030
+ '1:command:->cmd' \\
2031
+ '*::arg:->args'
2032
+
2033
+ case $state in
2034
+ cmd) _describe 'command' commands ;;
2035
+ args)
2036
+ case \${words[1]} in
2037
+ agents)
2038
+ local -a sub=(list create get update delete run runs def upload-input input-status ai)
2039
+ _describe 'subcommand' sub ;;
2040
+ sources|source)
2041
+ local -a sub=(list create get update delete upload upload-text exports migration)
2042
+ _describe 'subcommand' sub ;;
2043
+ contents)
2044
+ local -a sub=(get delete upload replace replace-text embeddings)
2045
+ _describe 'subcommand' sub ;;
2046
+ kb)
2047
+ local -a sub=(list create get update delete)
2048
+ _describe 'subcommand' sub ;;
2049
+ memory)
2050
+ local -a sub=(list create get update delete stats agents compact delete-source templates test-compaction test-compaction-standalone ai)
2051
+ _describe 'subcommand' sub ;;
2052
+ evals)
2053
+ local -a sub=(criteria results compatible-runs test-draft agent-results agent-runs non-manual-summary)
2054
+ _describe 'subcommand' sub ;;
2055
+ solutions)
2056
+ local -a sub=(list create get update delete link unlink convos ai)
2057
+ _describe 'subcommand' sub ;;
2058
+ governance)
2059
+ local -a sub=(ai)
2060
+ _describe 'subcommand' sub ;;
2061
+ alerts)
2062
+ local -a sub=(list get status comment subscribe unsubscribe configs prefs)
2063
+ _describe 'subcommand' sub ;;
2064
+ models)
2065
+ local -a sub=(alerts recommendations)
2066
+ _describe 'subcommand' sub ;;
2067
+ ai)
2068
+ local -a sub=(feedback kb source solution memory memory-history accept decline memory-accept)
2069
+ _describe 'subcommand' sub ;;
2070
+ skills)
2071
+ local -a sub=(install)
2072
+ _describe 'subcommand' sub ;;
2073
+ mcp)
2074
+ local -a sub=(configure show)
2075
+ _describe 'subcommand' sub ;;
2076
+ completion)
2077
+ local -a sub=(bash zsh fish)
2078
+ _describe 'shell' sub ;;
2079
+ esac ;;
2080
+ esac
2081
+ }
2082
+
2083
+ _seclai "$@"
2084
+ `;
2085
+ var FISH = `# seclai fish completion \u2014 save to ~/.config/fish/completions/seclai.fish
2086
+ # seclai completion fish > ~/.config/fish/completions/seclai.fish
2087
+
2088
+ set -l top agents sources contents kb memory evals solutions governance alerts models search ai skills mcp completion help
2089
+
2090
+ # Top-level
2091
+ complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "agents" -d "Manage agents"
2092
+ complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "sources" -d "Manage sources"
2093
+ complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "contents" -d "Manage content"
2094
+ complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "kb" -d "Knowledge bases"
2095
+ complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "memory" -d "Memory banks"
2096
+ complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "evals" -d "Evaluations"
2097
+ complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "solutions" -d "Solutions"
2098
+ complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "governance" -d "Governance AI"
2099
+ complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "alerts" -d "Alerts"
2100
+ complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "models" -d "Model alerts"
2101
+ complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "search" -d "Search resources"
2102
+ complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "ai" -d "AI assistant"
2103
+ complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "skills" -d "Skill files"
2104
+ complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "mcp" -d "MCP server config"
2105
+ complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "completion" -d "Shell completions"
2106
+
2107
+ # agents
2108
+ complete -c seclai -n "__fish_seen_subcommand_from agents; and not __fish_seen_subcommand_from list create get update delete run runs def upload-input input-status ai" -f -a "list create get update delete run runs def upload-input input-status ai"
2109
+
2110
+ # sources
2111
+ complete -c seclai -n "__fish_seen_subcommand_from sources; and not __fish_seen_subcommand_from list create get update delete upload upload-text exports migration" -f -a "list create get update delete upload upload-text exports migration"
2112
+
2113
+ # contents
2114
+ complete -c seclai -n "__fish_seen_subcommand_from contents; and not __fish_seen_subcommand_from get delete upload replace replace-text embeddings" -f -a "get delete upload replace replace-text embeddings"
2115
+
2116
+ # kb
2117
+ complete -c seclai -n "__fish_seen_subcommand_from kb; and not __fish_seen_subcommand_from list create get update delete" -f -a "list create get update delete"
2118
+
2119
+ # memory
2120
+ complete -c seclai -n "__fish_seen_subcommand_from memory; and not __fish_seen_subcommand_from list create get update delete stats agents compact delete-source templates test-compaction test-compaction-standalone ai" -f -a "list create get update delete stats agents compact delete-source templates test-compaction test-compaction-standalone ai"
2121
+
2122
+ # evals
2123
+ complete -c seclai -n "__fish_seen_subcommand_from evals; and not __fish_seen_subcommand_from criteria results compatible-runs test-draft agent-results agent-runs non-manual-summary" -f -a "criteria results compatible-runs test-draft agent-results agent-runs non-manual-summary"
2124
+
2125
+ # solutions
2126
+ complete -c seclai -n "__fish_seen_subcommand_from solutions; and not __fish_seen_subcommand_from list create get update delete link unlink convos ai" -f -a "list create get update delete link unlink convos ai"
2127
+
2128
+ # governance
2129
+ complete -c seclai -n "__fish_seen_subcommand_from governance; and not __fish_seen_subcommand_from ai" -f -a "ai"
2130
+
2131
+ # alerts
2132
+ complete -c seclai -n "__fish_seen_subcommand_from alerts; and not __fish_seen_subcommand_from list get status comment subscribe unsubscribe configs prefs" -f -a "list get status comment subscribe unsubscribe configs prefs"
2133
+
2134
+ # models
2135
+ complete -c seclai -n "__fish_seen_subcommand_from models; and not __fish_seen_subcommand_from alerts recommendations" -f -a "alerts recommendations"
2136
+
2137
+ # ai
2138
+ complete -c seclai -n "__fish_seen_subcommand_from ai; and not __fish_seen_subcommand_from feedback kb source solution memory memory-history accept decline memory-accept" -f -a "feedback kb source solution memory memory-history accept decline memory-accept"
2139
+
2140
+ # skills
2141
+ complete -c seclai -n "__fish_seen_subcommand_from skills; and not __fish_seen_subcommand_from install" -f -a "install"
2142
+
2143
+ # mcp
2144
+ complete -c seclai -n "__fish_seen_subcommand_from mcp; and not __fish_seen_subcommand_from configure show" -f -a "configure show"
2145
+
2146
+ # completion
2147
+ complete -c seclai -n "__fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from bash zsh fish" -f -a "bash zsh fish"
2148
+
2149
+ # Global options
2150
+ complete -c seclai -l api-key -d "Seclai API key"
2151
+ complete -c seclai -l compact -d "Output compact JSON"
2152
+ complete -c seclai -s V -l version -d "Output version"
2153
+ `;
2154
+ var SCRIPTS = { bash: BASH, zsh: ZSH, fish: FISH };
2155
+ function register15(program, rt) {
2156
+ const completion = program.command("completion").description("Generate shell completion scripts.").argument("<shell>", "Shell type: bash, zsh, or fish.").action(async (shell) => {
2157
+ const script = SCRIPTS[shell];
2158
+ if (!script) {
2159
+ rt.writeErr(`Unknown shell "${shell}". Use: bash, zsh, or fish.
2160
+ `);
2161
+ rt.setExitCode(1);
2162
+ return;
2163
+ }
2164
+ rt.writeOut(script);
2165
+ });
2166
+ }
2167
+
2168
+ // src/cli.ts
2169
+ function createProgram(rt = defaultRuntime()) {
2170
+ const program = new Command();
2171
+ const cliVersion = getCliVersion();
2172
+ program.name("seclai").description(
2173
+ `Seclai Command Line Interface (v${cliVersion})
2174
+
2175
+ Manage agents, knowledge bases, sources, memory banks, evaluations, and more from the terminal.
2176
+
2177
+ All commands return JSON to stdout, making it easy to pipe into jq or other tools.`
2178
+ ).version(cliVersion, "-V, --version", "output the version").option(
2179
+ "--api-key <key>",
2180
+ "Seclai API key (defaults to SECLAI_API_KEY)."
2181
+ ).option(
2182
+ "--compact",
2183
+ "Output compact JSON (no indentation)."
2184
+ );
2185
+ program.addHelpText(
2186
+ "after",
2187
+ `
2188
+ Environment:
2189
+ SECLAI_API_KEY Default API key (alternative to --api-key)
2190
+ SECLAI_API_URL Override API base URL (default: https://api.seclai.com)
2191
+
2192
+ Examples:
2193
+ seclai agents list
2194
+ seclai agents run <agentId> --json '{"input":"Hello"}'
2195
+ seclai agents run <agentId> --json '{"input":"Hi"}' --events
2196
+ seclai sources list
2197
+ seclai kb list
2198
+ seclai search --query "deployment guide"
2199
+ npx @seclai/cli agents list
2200
+ `
2201
+ );
2202
+ program.configureOutput({
2203
+ writeOut: (str) => rt.writeOut(str),
2204
+ writeErr: (str) => rt.writeErr(str)
2205
+ });
2206
+ program.exitOverride();
2207
+ program.hook("preAction", (thisCommand) => {
2208
+ const globalOpts = thisCommand.opts();
2209
+ rt.compact = Boolean(globalOpts.compact);
2210
+ });
2211
+ register(program, rt);
2212
+ register2(program, rt);
2213
+ register3(program, rt);
2214
+ register4(program, rt);
2215
+ register5(program, rt);
2216
+ register6(program, rt);
2217
+ register7(program, rt);
2218
+ register8(program, rt);
2219
+ register9(program, rt);
2220
+ register10(program, rt);
2221
+ register11(program, rt);
2222
+ register12(program, rt);
2223
+ register13(program, rt);
2224
+ register14(program, rt);
2225
+ register15(program, rt);
369
2226
  return program;
370
2227
  }
371
2228
  async function runCli(argv, rt = defaultRuntime()) {