@seclai/cli 1.3.0 → 1.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -42,7 +42,7 @@ npx add-mcp https://api.seclai.com/mcp --header "X-API-Key: $SECLAI_API_KEY" --n
42
42
 
43
43
  ## Documentation
44
44
 
45
- Command reference (latest): https://seclai.github.io/seclai-cli/1.3.0/
45
+ Command reference (latest): https://seclai.github.io/seclai-cli/1.4.0/
46
46
 
47
47
  ## Authentication
48
48
 
@@ -162,6 +162,9 @@ seclai agents runs delete <runId>
162
162
  seclai agents runs cancel <runId>
163
163
  seclai agents runs search [--page N] [--limit N] [--json '...']
164
164
  seclai agents runs eval-results <agentId> <runId> [--page N] [--limit N]
165
+ # Download a file attachment emitted by a run step. attachmentId is the
166
+ # URL-safe-base64 storage_key from run output manifests / webhooks.
167
+ seclai agents runs download-attachment <runId> <attachmentId> [--download-name <name>] [--output <path>]
165
168
  ```
166
169
 
167
170
  #### Agent Definition
@@ -190,6 +193,8 @@ seclai agents export <agentId> \
190
193
  #### Agent Input Upload
191
194
 
192
195
  ```bash
196
+ # Discover which files (if any) the agent expects before staging uploads.
197
+ seclai agents attachment-references <agentId>
193
198
  seclai agents upload-input <agentId> --file ./data.csv [--file-name data.csv] [--mime-type text/csv]
194
199
  seclai agents input-status <agentId> <uploadId>
195
200
  ```
@@ -412,6 +417,16 @@ seclai models alerts unread-count
412
417
  seclai models recommendations <modelId>
413
418
  ```
414
419
 
420
+ #### Model Playground Experiments
421
+
422
+ ```bash
423
+ seclai models experiments list [--days N] [--start-date <date>] [--end-date <date>] [--limit N] [--offset N]
424
+ seclai models experiments create --json '{"model_ids":["gpt-4o"],"prompt":"Compare responses"}'
425
+ seclai models experiments get <experimentId>
426
+ seclai models experiments cancel <experimentId>
427
+ seclai models experiments delete <experimentId> # soft-delete, preserves audit history
428
+ ```
429
+
415
430
  ### Search
416
431
 
417
432
  ```bash
package/dist/cli.js CHANGED
@@ -21,6 +21,9 @@ function defaultRuntime() {
21
21
  writeOut: (text) => {
22
22
  process2.stdout.write(text);
23
23
  },
24
+ writeOutBytes: (bytes) => {
25
+ process2.stdout.write(bytes);
26
+ },
24
27
  writeErr: (text) => {
25
28
  process2.stderr.write(text);
26
29
  },
@@ -291,6 +294,37 @@ function register(program, rt) {
291
294
  printJson(rt, await client.searchAgentRuns(body));
292
295
  });
293
296
  });
297
+ runs.command("download-attachment").description(
298
+ "Download a file attachment emitted by a step in an agent run. The attachmentId is the URL-safe-base64 storage_key from run output manifests / webhooks."
299
+ ).argument("<runId>", "Run ID.").argument("<attachmentId>", "Attachment ID (storage_key).").option("--download-name <name>", "Filename hint for the download disposition.").option("--output <path>", "Write the attachment bytes to this file. If omitted, raw bytes are written to stdout.").action(async (runId, attachmentId, opts) => {
300
+ await run(rt, async () => {
301
+ const client = createClient(program.opts());
302
+ const res = await client.downloadAgentRunAttachment(
303
+ runId,
304
+ attachmentId,
305
+ opts.downloadName ? { downloadName: opts.downloadName } : {}
306
+ );
307
+ if (opts.output) {
308
+ const { createWriteStream } = await import("fs");
309
+ const { stat } = await import("fs/promises");
310
+ if (res.body) {
311
+ const { Readable } = await import("stream");
312
+ const { pipeline } = await import("stream/promises");
313
+ await pipeline(
314
+ Readable.fromWeb(res.body),
315
+ createWriteStream(opts.output)
316
+ );
317
+ } else {
318
+ const { writeFile: writeFile5 } = await import("fs/promises");
319
+ await writeFile5(opts.output, Buffer.from(await res.arrayBuffer()));
320
+ }
321
+ const { size } = await stat(opts.output);
322
+ printJson(rt, { saved: opts.output, bytes: size });
323
+ } else {
324
+ rt.writeOutBytes(new Uint8Array(await res.arrayBuffer()));
325
+ }
326
+ });
327
+ });
294
328
  const def = agents.command("def").description("Agent definition (step workflow).");
295
329
  def.command("get").description("Get agent definition.").argument("<agentId>", "Agent ID.").action(async (agentId) => {
296
330
  await run(rt, async () => {
@@ -337,6 +371,14 @@ function register(program, rt) {
337
371
  printJson(rt, await client.getAgentInputUploadStatus(agentId, uploadId));
338
372
  });
339
373
  });
374
+ agents.command("attachment-references").description(
375
+ "Show which files (if any) an agent's templates expect on a run. Call before staging uploads: requires_uploads reports whether the agent accepts files, and the agent block lists the exact names / indexes / patterns a run-time batch must satisfy."
376
+ ).argument("<agentId>", "Agent ID.").action(async (agentId) => {
377
+ await run(rt, async () => {
378
+ const client = createClient(program.opts());
379
+ printJson(rt, await client.getAgentAttachmentReferences(agentId));
380
+ });
381
+ });
340
382
  const ai = agents.command("ai").description("Agent AI assistant.");
341
383
  withAiInputOptions(
342
384
  ai.command("gen-steps").description("Generate agent steps via AI.").argument("<agentId>", "Agent ID.")
@@ -1135,6 +1177,13 @@ function register10(program, rt) {
1135
1177
  printJson(rt, await client.cancelExperiment(experimentId));
1136
1178
  });
1137
1179
  });
1180
+ experiments.command("delete").description("Soft-delete a model playground experiment (preserves audit history).").argument("<experimentId>", "Experiment ID.").action(async (experimentId) => {
1181
+ await run(rt, async () => {
1182
+ const client = createClient(program.opts());
1183
+ await client.deleteExperiment(experimentId);
1184
+ printJson(rt, { ok: true });
1185
+ });
1186
+ });
1138
1187
  }
1139
1188
 
1140
1189
  // src/commands/search.ts
@@ -2011,10 +2060,10 @@ _seclai_completions() {
2011
2060
  case "\${COMP_WORDS[1]}" in
2012
2061
  agents)
2013
2062
  case "\${COMP_WORDS[2]}" in
2014
- runs) COMPREPLY=( $(compgen -W "list get delete cancel search eval-results" -- "$cur") ); return ;;
2063
+ runs) COMPREPLY=( $(compgen -W "list get delete cancel search eval-results download-attachment" -- "$cur") ); return ;;
2015
2064
  def) COMPREPLY=( $(compgen -W "get update" -- "$cur") ); return ;;
2016
2065
  ai) COMPREPLY=( $(compgen -W "gen-steps step-config history mark" -- "$cur") ); return ;;
2017
- *) COMPREPLY=( $(compgen -W "list create get update delete run runs def export upload-input input-status ai" -- "$cur") ); return ;;
2066
+ *) COMPREPLY=( $(compgen -W "list create get update delete run runs def export preview-import upload-input input-status attachment-references ai" -- "$cur") ); return ;;
2018
2067
  esac ;;
2019
2068
  sources|source)
2020
2069
  case "\${COMP_WORDS[2]}" in
@@ -2054,8 +2103,9 @@ _seclai_completions() {
2054
2103
  esac ;;
2055
2104
  models)
2056
2105
  case "\${COMP_WORDS[2]}" in
2057
- alerts) COMPREPLY=( $(compgen -W "list mark-read mark-all-read unread-count" -- "$cur") ); return ;;
2058
- *) COMPREPLY=( $(compgen -W "alerts recommendations" -- "$cur") ); return ;;
2106
+ alerts) COMPREPLY=( $(compgen -W "list mark-read mark-all-read unread-count" -- "$cur") ); return ;;
2107
+ experiments) COMPREPLY=( $(compgen -W "list create get cancel delete" -- "$cur") ); return ;;
2108
+ *) COMPREPLY=( $(compgen -W "alerts recommendations experiments" -- "$cur") ); return ;;
2059
2109
  esac ;;
2060
2110
  ai) COMPREPLY=( $(compgen -W "feedback kb source solution memory memory-history accept decline memory-accept" -- "$cur") ); return ;;
2061
2111
  skills) COMPREPLY=( $(compgen -W "install" -- "$cur") ); return ;;
@@ -2106,7 +2156,7 @@ _seclai() {
2106
2156
  args)
2107
2157
  case \${words[1]} in
2108
2158
  agents)
2109
- local -a sub=(list create get update delete run runs def export upload-input input-status ai)
2159
+ local -a sub=(list create get update delete run runs def export preview-import upload-input input-status attachment-references ai)
2110
2160
  _describe 'subcommand' sub ;;
2111
2161
  sources|source)
2112
2162
  local -a sub=(list create get update delete upload upload-text exports migration)
@@ -2133,7 +2183,7 @@ _seclai() {
2133
2183
  local -a sub=(list get status comment subscribe unsubscribe configs prefs)
2134
2184
  _describe 'subcommand' sub ;;
2135
2185
  models)
2136
- local -a sub=(alerts recommendations)
2186
+ local -a sub=(alerts recommendations experiments)
2137
2187
  _describe 'subcommand' sub ;;
2138
2188
  ai)
2139
2189
  local -a sub=(feedback kb source solution memory memory-history accept decline memory-accept)
@@ -2176,7 +2226,7 @@ complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "mcp" -d "MCP
2176
2226
  complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "completion" -d "Shell completions"
2177
2227
 
2178
2228
  # agents
2179
- complete -c seclai -n "__fish_seen_subcommand_from agents; and not __fish_seen_subcommand_from list create get update delete run runs def export upload-input input-status ai" -f -a "list create get update delete run runs def export upload-input input-status ai"
2229
+ complete -c seclai -n "__fish_seen_subcommand_from agents; and not __fish_seen_subcommand_from list create get update delete run runs def export preview-import upload-input input-status attachment-references ai" -f -a "list create get update delete run runs def export preview-import upload-input input-status attachment-references ai"
2180
2230
 
2181
2231
  # sources
2182
2232
  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"
@@ -2203,7 +2253,7 @@ complete -c seclai -n "__fish_seen_subcommand_from governance; and not __fish_se
2203
2253
  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"
2204
2254
 
2205
2255
  # models
2206
- complete -c seclai -n "__fish_seen_subcommand_from models; and not __fish_seen_subcommand_from alerts recommendations" -f -a "alerts recommendations"
2256
+ complete -c seclai -n "__fish_seen_subcommand_from models; and not __fish_seen_subcommand_from alerts recommendations experiments" -f -a "alerts recommendations experiments"
2207
2257
 
2208
2258
  # ai
2209
2259
  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"