@seclai/cli 1.5.0 → 1.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/cli.js CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/cli.ts
4
- import { Command as Command3 } from "commander";
4
+ import { Command as Command4 } from "commander";
5
5
  import { realpathSync } from "fs";
6
6
  import { fileURLToPath, pathToFileURL } from "url";
7
7
 
@@ -75,12 +75,25 @@ function getCliVersion() {
75
75
  }
76
76
  function createClient(opts) {
77
77
  const seclaiOpts = {};
78
+ const identityFlags = [
79
+ ["apiKey", "--api-key", "Pass a key, or omit the flag to use SECLAI_API_KEY or SSO."],
80
+ ["profile", "--profile", "Pass a profile name, or omit the flag to use the default profile."],
81
+ ["accountId", "--account-id", "Pass an account ID, or omit the flag to use the default org."],
82
+ ["configDir", "--config-dir", "Pass a directory, or omit the flag to use ~/.seclai."]
83
+ ];
84
+ for (const [key, flag, hint] of identityFlags) {
85
+ const value = opts[key];
86
+ if (typeof value === "string" && value.trim().length === 0) {
87
+ throw new Error(`${flag} was given an empty value. ${hint}`);
88
+ }
89
+ }
78
90
  if (opts.apiKey !== void 0) seclaiOpts.apiKey = opts.apiKey;
79
91
  if (opts.profile !== void 0) seclaiOpts.profile = opts.profile;
80
92
  if (opts.configDir !== void 0) seclaiOpts.configDir = opts.configDir;
81
93
  if (opts.accountId !== void 0) seclaiOpts.accountId = opts.accountId;
82
94
  const envVersion = process2.env.SECLAI_API_VERSION;
83
- const version = opts.apiVersion ?? (envVersion && envVersion.length > 0 ? envVersion : void 0);
95
+ const blank = (v) => v === void 0 || v.trim().length === 0;
96
+ const version = blank(opts.apiVersion) ? opts.apiVersion !== void 0 ? void 0 : blank(envVersion) ? void 0 : envVersion : opts.apiVersion;
84
97
  if (version !== void 0) seclaiOpts.apiVersion = version;
85
98
  if (opts.allowUnknownApiVersion) seclaiOpts.allowUnknownApiVersion = true;
86
99
  const envUrl = process2.env.SECLAI_API_URL;
@@ -92,8 +105,9 @@ function printJson(rt, value) {
92
105
  rt.writeOut(`${JSON.stringify(value, null, indent)}
93
106
  `);
94
107
  }
95
- function warnDeprecated(rt, message) {
96
- rt.writeErr(`warning: ${message} This will be rejected in a future release.
108
+ function warnDeprecated(rt, message, fate = "rejected") {
109
+ const suffix = fate === "kept" ? "" : fate === "removed" ? " This will be removed in a future release." : " This will be rejected in a future release.";
110
+ rt.writeErr(`warning: ${message}${suffix}
97
111
  `);
98
112
  }
99
113
  function printError(rt, err) {
@@ -123,8 +137,13 @@ function printError(rt, err) {
123
137
  if (err instanceof SeclaiConfigurationError) {
124
138
  rt.writeErr(`${err.name}: ${err.message}
125
139
  `);
126
- rt.writeErr(`hint: Set the SECLAI_API_KEY environment variable or pass --api-key.
140
+ if (/api version/i.test(err.message)) {
141
+ rt.writeErr(`hint: Pass --allow-unknown-api-version to send it anyway.
142
+ `);
143
+ } else {
144
+ rt.writeErr(`hint: Set the SECLAI_API_KEY environment variable or pass --api-key.
127
145
  `);
146
+ }
128
147
  return;
129
148
  }
130
149
  if (err instanceof Error) {
@@ -144,18 +163,30 @@ async function run(rt, main) {
144
163
  }
145
164
  }
146
165
  function parseNumber(value) {
147
- const parsed = value.trim() === "" ? Number.NaN : Number(value);
148
- if (!Number.isFinite(parsed)) {
149
- throw new InvalidArgumentError("Expected a number.");
166
+ if (!/^\d+$/.test(value.trim())) {
167
+ throw new InvalidArgumentError("Expected a non-negative whole number.");
150
168
  }
151
- return parsed;
169
+ return Number(value.trim());
152
170
  }
153
- function withLimitOption(cmd) {
154
- return cmd.option("--limit <n>", "Page size.", parseNumber);
171
+ function withLimitOption(cmd, description = "Page size.") {
172
+ return cmd.option("--limit <n>", description, parseNumber);
155
173
  }
156
174
  function withOffsetListOptions(cmd) {
157
175
  return withLimitOption(cmd).option("--offset <n>", "Number of items to skip.", parseNumber);
158
176
  }
177
+ function toPagedEnvelope(res, ...legacyKeys) {
178
+ if (Array.isArray(res)) return { data: res };
179
+ if (res === null || typeof res !== "object") return res;
180
+ const obj = res;
181
+ if (Array.isArray(obj.data)) return obj;
182
+ for (const key of legacyKeys) {
183
+ if (Array.isArray(obj[key])) {
184
+ const { [key]: rows, ...rest } = obj;
185
+ return { data: rows, ...rest };
186
+ }
187
+ }
188
+ return res;
189
+ }
159
190
  function offsetListOpts(opts) {
160
191
  const o = {};
161
192
  if (opts.limit !== void 0) o.limit = opts.limit;
@@ -339,7 +370,10 @@ function register(program, rt) {
339
370
  await run(rt, async () => {
340
371
  warnDeprecated(
341
372
  rt,
342
- `'agents runs delete' is deprecated and cancels the run rather than deleting it \u2014 the API has no delete-a-run operation. Use 'agents runs cancel', which also prints the cancelled run instead of {"ok": true}.`
373
+ `'agents runs delete' is deprecated and cancels the run rather than deleting it \u2014 the API has no delete-a-run operation. Use 'agents runs cancel', which also prints the cancelled run instead of {"ok": true}.`,
374
+ // Kept, not scheduled for removal — the whole point of the alias is
375
+ // that existing scripts keep working.
376
+ "kept"
343
377
  );
344
378
  const client = createClient(program.opts());
345
379
  await client.cancelAgentRun(runId);
@@ -487,10 +521,14 @@ function register(program, rt) {
487
521
  printJson(rt, { ok: true });
488
522
  });
489
523
  });
490
- runs.command("eval-results").description("List evaluation results for a run.").argument("<agentId>", "Agent ID.").argument("<runId>", "Run ID.").option("--page <n>", "Page number.", parseNumber).option("--limit <n>", "Page size.", parseNumber).action(async (agentId, runId, opts) => {
524
+ runs.command("eval-results").description("List evaluation results for a run.").argument("<agentId>", "Agent ID.").argument("<runId>", "Run ID.").option("--page <n>", "Page number.", parseNumber).option("--limit <n>", "Page size.", parseNumber).option(
525
+ "--paged",
526
+ "Wrap the results in {data: [...]}, the shape this endpoint moves to from --api-version 2026-07-27."
527
+ ).action(async (agentId, runId, opts) => {
491
528
  await run(rt, async () => {
492
529
  const client = createClient(program.opts());
493
- printJson(rt, await client.listRunEvaluationResults(agentId, runId, listOpts(opts)));
530
+ const res = await client.listRunEvaluationResults(agentId, runId, listOpts(opts));
531
+ printJson(rt, opts.paged ? toPagedEnvelope(res) : res);
494
532
  });
495
533
  });
496
534
  }
@@ -498,7 +536,7 @@ function register(program, rt) {
498
536
  // src/commands/sources.ts
499
537
  function register2(program, rt) {
500
538
  const sources = program.command("sources").alias("source").description("Manage content sources.");
501
- 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) => {
539
+ sources.command("list").description("List sources.").option("--page <n>", "Page number.", parseNumber).option("--limit <n>", "Page size.", parseNumber).option("--sort <field>", "Sort field.").option("--order <asc|desc>", "Sort direction.").option("--account-id <id>", "Filter by account ID.").action(async (opts) => {
502
540
  await run(rt, async () => {
503
541
  const globalOpts = program.opts();
504
542
  const client = createClient(globalOpts);
@@ -551,7 +589,7 @@ function register2(program, rt) {
551
589
  });
552
590
  });
553
591
  const exports_ = sources.command("exports").description("Manage source exports.");
554
- 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) => {
592
+ exports_.command("list").description("List exports for a source.").argument("<sourceId>", "Source ID.").option("--page <n>", "Page number.", parseNumber).option("--limit <n>", "Page size.", parseNumber).action(async (sourceId, opts) => {
555
593
  await run(rt, async () => {
556
594
  const client = createClient(program.opts());
557
595
  printJson(rt, await client.listSourceExports(sourceId, listOpts(opts)));
@@ -622,7 +660,7 @@ function register2(program, rt) {
622
660
  // src/commands/contents.ts
623
661
  function register3(program, rt) {
624
662
  const contents = program.command("contents").description("Manage indexed content and embeddings.");
625
- 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) => {
663
+ contents.command("get").description("Get content version details.").argument("<contentVersionId>", "Content version ID.").option("--start <n>", "Text start offset (0-based).", parseNumber).option("--end <n>", "Text end offset (exclusive).", parseNumber).action(async (contentVersionId, opts) => {
626
664
  await run(rt, async () => {
627
665
  const client = createClient(program.opts());
628
666
  const o = {};
@@ -653,7 +691,7 @@ function register3(program, rt) {
653
691
  printJson(rt, await client.replaceContentWithInlineText(contentVersionId, body));
654
692
  });
655
693
  });
656
- 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) => {
694
+ contents.command("embeddings").description("List embeddings for a content version.").argument("<contentVersionId>", "Content version ID.").option("--page <n>", "Page number.", parseNumber).option("--limit <n>", "Page size.", parseNumber).action(async (contentVersionId, opts) => {
657
695
  await run(rt, async () => {
658
696
  const client = createClient(program.opts());
659
697
  printJson(rt, await client.listContentEmbeddings(contentVersionId, listOpts(opts)));
@@ -664,7 +702,7 @@ function register3(program, rt) {
664
702
  // src/commands/kb.ts
665
703
  function register4(program, rt) {
666
704
  const kb = program.command("kb").description("Manage knowledge bases.");
667
- 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) => {
705
+ kb.command("list").description("List knowledge bases.").option("--page <n>", "Page number.", parseNumber).option("--limit <n>", "Page size.", parseNumber).option("--sort <field>", "Sort field.").option("--order <asc|desc>", "Sort direction.").action(async (opts) => {
668
706
  await run(rt, async () => {
669
707
  const client = createClient(program.opts());
670
708
  printJson(rt, await client.listKnowledgeBases(listOpts(opts)));
@@ -702,7 +740,7 @@ function register4(program, rt) {
702
740
  // src/commands/memory.ts
703
741
  function register5(program, rt) {
704
742
  const memory = program.command("memory").description("Manage memory banks.");
705
- 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) => {
743
+ memory.command("list").description("List memory banks.").option("--page <n>", "Page number.", parseNumber).option("--limit <n>", "Page size.", parseNumber).option("--sort <field>", "Sort field.").option("--order <asc|desc>", "Sort direction.").action(async (opts) => {
706
744
  await run(rt, async () => {
707
745
  const client = createClient(program.opts());
708
746
  printJson(rt, await client.listMemoryBanks(listOpts(opts)));
@@ -905,7 +943,7 @@ function register6(program, rt) {
905
943
  // src/commands/solutions.ts
906
944
  function register7(program, rt) {
907
945
  const solutions = program.command("solutions").description("Manage solutions.");
908
- 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) => {
946
+ solutions.command("list").description("List solutions.").option("--page <n>", "Page number.", parseNumber).option("--limit <n>", "Page size.", parseNumber).option("--sort <field>", "Sort field.").option("--order <asc|desc>", "Sort direction.").action(async (opts) => {
909
947
  await run(rt, async () => {
910
948
  const client = createClient(program.opts());
911
949
  printJson(rt, await client.listSolutions(listOpts(opts)));
@@ -1083,20 +1121,11 @@ function register8(program, rt) {
1083
1121
  // src/commands/alerts.ts
1084
1122
  function register9(program, rt) {
1085
1123
  const alerts = program.command("alerts").description("Manage alerts and alert configurations.");
1086
- alerts.command("list").description("List alerts.").option("--page <n>", "Page number.", parseNumber).option("--limit <n>", "Page size.", parseNumber).option("--status <status>", "Filter by status.").option(
1087
- "--severity <severity>",
1088
- "Deprecated and ignored \u2014 GET /alerts declares no severity filter. Filter with jq instead."
1089
- ).action(async (opts) => {
1124
+ alerts.command("list").description("List alerts.").option("--page <n>", "Page number.", parseNumber).option("--limit <n>", "Page size.", parseNumber).option("--status <status>", "Filter by status.").action(async (opts) => {
1090
1125
  await run(rt, async () => {
1091
1126
  const client = createClient(program.opts());
1092
1127
  const o = listOpts(opts);
1093
1128
  if (opts.status) o.status = opts.status;
1094
- if (opts.severity !== void 0) {
1095
- warnDeprecated(
1096
- rt,
1097
- `'alerts list --severity' is ignored \u2014 the API has no severity filter, so it never filtered anything. Filter client-side, e.g. | jq '[.data[] | select(.severity == "high")]'.`
1098
- );
1099
- }
1100
1129
  printJson(rt, await client.listAlerts(o));
1101
1130
  });
1102
1131
  });
@@ -1133,10 +1162,14 @@ function register9(program, rt) {
1133
1162
  });
1134
1163
  });
1135
1164
  const configs = alerts.command("configs").description("Alert configurations.");
1136
- configs.command("list").description("List alert configurations.").option("--page <n>", "Page number.", parseNumber).option("--limit <n>", "Page size.", parseNumber).action(async (opts) => {
1165
+ configs.command("list").description("List alert configurations.").option("--page <n>", "Page number.", parseNumber).option("--limit <n>", "Page size.", parseNumber).option(
1166
+ "--paged",
1167
+ "Wrap the results in {data: [...]}, the shape this endpoint moves to from --api-version 2026-07-27."
1168
+ ).action(async (opts) => {
1137
1169
  await run(rt, async () => {
1138
1170
  const client = createClient(program.opts());
1139
- printJson(rt, await client.listAlertConfigs(listOpts(opts)));
1171
+ const res = await client.listAlertConfigs(listOpts(opts));
1172
+ printJson(rt, opts.paged ? toPagedEnvelope(res, "configs") : res);
1140
1173
  });
1141
1174
  });
1142
1175
  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) => {
@@ -1183,6 +1216,7 @@ function register9(program, rt) {
1183
1216
  }
1184
1217
 
1185
1218
  // src/commands/email.ts
1219
+ import { Argument, Option } from "commander";
1186
1220
  function register10(program, rt) {
1187
1221
  const email = program.command("email").description("Agent email: sending domains, inbound blocklist, inbound health, and opt-outs.");
1188
1222
  const domains = email.command("domains").description("Agent-email sending domains.");
@@ -1192,7 +1226,9 @@ function register10(program, rt) {
1192
1226
  printJson(rt, await client.listEmailDomains());
1193
1227
  });
1194
1228
  });
1195
- domains.command("add").description("Add and provision a new agent-email domain. Returns the DNS records to publish.").requiredOption("--kind <kind>", "'vanity' (a subdomain of seclai.com) or 'custom' (your own domain).").requiredOption("--value <domain>", "The domain to add.").option("--delegated", "The domain's DNS is delegated to Seclai, so records are published automatically.").action(async (opts) => {
1229
+ domains.command("add").description("Add and provision a new agent-email domain. Returns the DNS records to publish.").addOption(
1230
+ new Option("--kind <kind>", "'vanity' (a subdomain of seclai.com) or 'custom' (your own domain).").choices(["vanity", "custom"]).makeOptionMandatory()
1231
+ ).requiredOption("--value <domain>", "The domain to add.").option("--delegated", "The domain's DNS is delegated to Seclai, so records are published automatically.").action(async (opts) => {
1196
1232
  await run(rt, async () => {
1197
1233
  const client = createClient(program.opts());
1198
1234
  const body = {
@@ -1252,7 +1288,9 @@ function register10(program, rt) {
1252
1288
  printJson(rt, await client.listBlockedEmailSenders(offsetListOpts(opts)));
1253
1289
  });
1254
1290
  });
1255
- blocked.command("add").description("Block an inbound sender address or domain.").requiredOption("--sender-email <email>", "Sender address, or the domain when --match-type is 'domain'.").option("--match-type <type>", "'address' or 'domain'.", "address").option("--note <text>", "Why the sender was blocked.").action(async (opts) => {
1291
+ blocked.command("add").description("Block an inbound sender address or domain.").requiredOption("--sender-email <email>", "Sender address, or the domain when --match-type is 'domain'.").addOption(
1292
+ new Option("--match-type <type>", "'address' or 'domain'.").choices(["address", "domain"]).default("address")
1293
+ ).option("--note <text>", "Why the sender was blocked.").action(async (opts) => {
1256
1294
  await run(rt, async () => {
1257
1295
  const client = createClient(program.opts());
1258
1296
  const body = {
@@ -1270,7 +1308,15 @@ function register10(program, rt) {
1270
1308
  printJson(rt, { ok: true });
1271
1309
  });
1272
1310
  });
1273
- blocked.command("auto-block-mode").description("Set whether a governance BLOCK on an authenticated sender auto-adds them to the blocklist.").argument("<mode>", "One of 'disabled', 'input', or 'input_and_output'.").action(async (mode) => {
1311
+ blocked.command("auto-block-mode").description("Set whether a governance BLOCK on an authenticated sender auto-adds them to the blocklist.").addArgument(
1312
+ // A closed set the API will only ever 422 on. Failing the parse names the
1313
+ // accepted values; the server names nothing.
1314
+ new Argument("<mode>", "How governance BLOCK verdicts feed the blocklist.").choices([
1315
+ "disabled",
1316
+ "input",
1317
+ "input_and_output"
1318
+ ])
1319
+ ).action(async (mode) => {
1274
1320
  await run(rt, async () => {
1275
1321
  const client = createClient(program.opts());
1276
1322
  printJson(rt, await client.setAutoBlockMode({ mode }));
@@ -1325,6 +1371,7 @@ function register10(program, rt) {
1325
1371
  }
1326
1372
 
1327
1373
  // src/commands/account.ts
1374
+ import { SeclaiApiVersion } from "@seclai/sdk";
1328
1375
  function register11(program, rt) {
1329
1376
  program.command("me").description("Show the authenticated user's account ID and organization memberships.").action(async () => {
1330
1377
  await run(rt, async () => {
@@ -1343,8 +1390,11 @@ function register11(program, rt) {
1343
1390
  });
1344
1391
  version.command("set").description("Pin the account to a dated API version. Affects every client, not just this CLI.").argument("<date>", "API version as YYYY-MM-DD.").action(async (date) => {
1345
1392
  await run(rt, async () => {
1346
- if (!/^\d{4}-\d{2}-\d{2}$/.test(date)) {
1347
- throw new Error(`Expected an API version as YYYY-MM-DD, got "${date}".`);
1393
+ const known = Object.values(SeclaiApiVersion);
1394
+ if (!known.includes(date) && !program.opts().allowUnknownApiVersion) {
1395
+ throw new Error(
1396
+ `Unknown API version "${date}". This release knows ${[...new Set(known)].sort().join(", ")}. Pass --allow-unknown-api-version to pin it anyway.`
1397
+ );
1348
1398
  }
1349
1399
  const client = createClient(program.opts());
1350
1400
  printJson(rt, await client.updateApiVersion(date));
@@ -1386,10 +1436,14 @@ function register12(program, rt) {
1386
1436
  });
1387
1437
  });
1388
1438
  const alerts = models.command("alerts").description("Model alerts.");
1389
- alerts.command("list").description("List model alerts.").option("--page <n>", "Page number.", parseNumber).option("--limit <n>", "Page size.", parseNumber).action(async (opts) => {
1439
+ alerts.command("list").description("List model alerts.").option("--page <n>", "Page number.", parseNumber).option("--limit <n>", "Page size.", parseNumber).option(
1440
+ "--paged",
1441
+ "Wrap the results in {data: [...]}, the shape this endpoint moves to from --api-version 2026-07-27."
1442
+ ).action(async (opts) => {
1390
1443
  await run(rt, async () => {
1391
1444
  const client = createClient(program.opts());
1392
- printJson(rt, await client.listModelAlerts(listOpts(opts)));
1445
+ const res = await client.listModelAlerts(listOpts(opts));
1446
+ printJson(rt, opts.paged ? toPagedEnvelope(res, "alerts") : res);
1393
1447
  });
1394
1448
  });
1395
1449
  alerts.command("mark-read").description("Mark a model alert as read.").argument("<alertId>", "Alert ID.").action(async (alertId) => {
@@ -1460,19 +1514,19 @@ function register12(program, rt) {
1460
1514
  }
1461
1515
 
1462
1516
  // src/commands/search.ts
1463
- import { Option } from "commander";
1517
+ import { Option as Option2 } from "commander";
1464
1518
  function register13(program, rt) {
1465
1519
  program.command("search").description("Search across Seclai resources.").requiredOption("--query <text>", "Search query text.").option("--limit <n>", "Max results.", parseNumber).option("--entity-type <type>", "Filter by entity type (e.g. agent, source, knowledge_base, memory_bank).").action(async (opts) => {
1466
1520
  await run(rt, async () => {
1467
1521
  const client = createClient(program.opts());
1468
1522
  const o = { query: opts.query };
1469
1523
  if (opts.limit !== void 0) o.limit = opts.limit;
1470
- if (opts.entityType) o.entityType = opts.entityType;
1524
+ if (opts.entityType !== void 0) o.entityType = opts.entityType;
1471
1525
  printJson(rt, await client.search(o));
1472
1526
  });
1473
1527
  });
1474
1528
  const docs = program.command("docs").description("Seclai documentation.");
1475
- docs.command("search").description("Search the Seclai documentation.").requiredOption("--query <text>", "Search query text.").addOption(new Option("--mode <mode>", "Search mode.").choices(["keyword", "semantic"])).option("--limit <n>", "Max results.", parseNumber).action(async (opts) => {
1529
+ docs.command("search").description("Search the Seclai documentation.").requiredOption("--query <text>", "Search query text.").addOption(new Option2("--mode <mode>", "Search mode.").choices(["keyword", "semantic"])).option("--limit <n>", "Max results.", parseNumber).action(async (opts) => {
1476
1530
  await run(rt, async () => {
1477
1531
  const client = createClient(program.opts());
1478
1532
  const o = { query: opts.query };
@@ -1608,6 +1662,7 @@ seclai agents runs list <agentId>
1608
1662
  | \`models\` | Model catalog, generation tiers, model alerts, recommendations, playground experiments | [references/models.md](references/models.md) |
1609
1663
  | \`auth\` \`configure\` \`api-version\` \`mcp\` \`skills\` \`completion\` | Authentication, profiles, API version pinning, editor integration | [references/setup.md](references/setup.md) |
1610
1664
  | \`ai\` | Top-level AI assistant for knowledge bases, sources, solutions and memory | [references/ai-assistant.md](references/ai-assistant.md) |
1665
+ | \`search\` \`docs\` \`me\` | Search across resources, search the documentation, show the authenticated account | below, under [Search and account](#search-and-account) |
1611
1666
 
1612
1667
  Cross-cutting topics: [streaming and event modes](references/streaming.md),
1613
1668
  [file uploads](references/uploads.md).
@@ -1878,9 +1933,9 @@ seclai alerts subscribe <alertId>
1878
1933
  seclai alerts unsubscribe <alertId>
1879
1934
  \`\`\`
1880
1935
 
1881
- \`GET /alerts\` declares no severity filter. \`--severity\` still parses, but it is
1882
- ignored with a warning and will be removed \u2014 it never filtered anything. Filter
1883
- client-side instead:
1936
+ \`GET /alerts\` declares no severity filter, so there is no \`--severity\` \u2014 it
1937
+ never filtered anything, and returned unfiltered rows that looked filtered.
1938
+ Filter client-side instead:
1884
1939
 
1885
1940
  \`\`\`bash
1886
1941
  seclai alerts list | jq '[.data[] | select(.severity == "high")]'
@@ -2635,302 +2690,156 @@ function register16(program, rt) {
2635
2690
  }
2636
2691
 
2637
2692
  // src/commands/completion.ts
2638
- var BASH = `#!/usr/bin/env bash
2693
+ function collectTree(program) {
2694
+ const tree = /* @__PURE__ */ new Map();
2695
+ const walk = (cmd, prefix) => {
2696
+ const children = [];
2697
+ for (const sub of cmd.commands) {
2698
+ const name = sub.name();
2699
+ if (name === "help") continue;
2700
+ children.push({ name, description: sub.description().replace(/\s+/g, " ").trim() });
2701
+ walk(sub, [...prefix, name]);
2702
+ }
2703
+ if (children.length > 0) tree.set(prefix.join(" "), children);
2704
+ };
2705
+ walk(program, []);
2706
+ return tree;
2707
+ }
2708
+ function globalOptions(program) {
2709
+ return program.options.filter((o) => o.long && o.long !== "--help").map((o) => ({
2710
+ flag: o.long,
2711
+ description: o.description.replace(/\s+/g, " ").trim()
2712
+ }));
2713
+ }
2714
+ var names = (children) => children.map((c) => c.name).join(" ");
2715
+ function renderBash(tree, options) {
2716
+ const cases = [...tree.entries()].map(([prefix, children]) => ` ${JSON.stringify(prefix)}) __seclai_reply "${names(children)}" ;;`).join("\n");
2717
+ return `#!/usr/bin/env bash
2639
2718
  # seclai bash completion \u2014 add to ~/.bashrc:
2640
2719
  # eval "$(seclai completion bash)"
2720
+ #
2721
+ # Generated from the command tree by \`seclai completion bash\`. Do not edit.
2722
+
2723
+ __seclai_reply() {
2724
+ COMPREPLY=( $(compgen -W "$1" -- "$__seclai_cur") )
2725
+ }
2641
2726
 
2642
2727
  _seclai_completions() {
2643
- local cur prev commands
2644
- cur="\${COMP_WORDS[COMP_CWORD]}"
2645
- prev="\${COMP_WORDS[COMP_CWORD-1]}"
2646
-
2647
- # Top-level commands
2648
- commands="agents sources contents kb memory evals solutions governance alerts email models search docs me api-version ai skills mcp completion auth configure help"
2649
-
2650
- case "\${COMP_WORDS[1]}" in
2651
- agents)
2652
- case "\${COMP_WORDS[2]}" in
2653
- runs) COMPREPLY=( $(compgen -W "list get delete cancel search eval-results download-attachment" -- "$cur") ); return ;;
2654
- def) COMPREPLY=( $(compgen -W "get update" -- "$cur") ); return ;;
2655
- ai) COMPREPLY=( $(compgen -W "gen-steps step-config history mark" -- "$cur") ); return ;;
2656
- triggers) COMPREPLY=( $(compgen -W "email-config" -- "$cur") ); return ;;
2657
- *) COMPREPLY=( $(compgen -W "list create get update delete disable enable callers triggers run runs def export preview-import upload-input input-status attachment-references ai" -- "$cur") ); return ;;
2658
- esac ;;
2659
- sources|source)
2660
- case "\${COMP_WORDS[2]}" in
2661
- exports) COMPREPLY=( $(compgen -W "list create get cancel delete download estimate" -- "$cur") ); return ;;
2662
- migration) COMPREPLY=( $(compgen -W "get start cancel" -- "$cur") ); return ;;
2663
- *) COMPREPLY=( $(compgen -W "list create get update delete upload upload-text exports migration" -- "$cur") ); return ;;
2664
- esac ;;
2665
- contents) COMPREPLY=( $(compgen -W "get delete upload replace replace-text embeddings" -- "$cur") ); return ;;
2666
- kb) COMPREPLY=( $(compgen -W "list create get update delete" -- "$cur") ); return ;;
2667
- memory)
2668
- case "\${COMP_WORDS[2]}" in
2669
- ai) COMPREPLY=( $(compgen -W "generate last accept" -- "$cur") ); return ;;
2670
- *) COMPREPLY=( $(compgen -W "list create get update delete stats agents compact delete-source templates test-compaction test-compaction-standalone ai" -- "$cur") ); return ;;
2671
- esac ;;
2672
- evals)
2673
- case "\${COMP_WORDS[2]}" in
2674
- criteria) COMPREPLY=( $(compgen -W "list create get update delete summary" -- "$cur") ); return ;;
2675
- results) COMPREPLY=( $(compgen -W "list create" -- "$cur") ); return ;;
2676
- *) COMPREPLY=( $(compgen -W "criteria results compatible-runs test-draft agent-results agent-runs non-manual-summary" -- "$cur") ); return ;;
2677
- esac ;;
2678
- solutions)
2679
- case "\${COMP_WORDS[2]}" in
2680
- convos) COMPREPLY=( $(compgen -W "list add mark" -- "$cur") ); return ;;
2681
- ai) COMPREPLY=( $(compgen -W "generate kb source accept decline" -- "$cur") ); return ;;
2682
- *) COMPREPLY=( $(compgen -W "list create get update delete link unlink convos ai" -- "$cur") ); return ;;
2683
- esac ;;
2684
- governance)
2685
- case "\${COMP_WORDS[2]}" in
2686
- ai) COMPREPLY=( $(compgen -W "generate list accept decline" -- "$cur") ); return ;;
2687
- *) COMPREPLY=( $(compgen -W "ai" -- "$cur") ); return ;;
2688
- esac ;;
2689
- alerts)
2690
- case "\${COMP_WORDS[2]}" in
2691
- configs) COMPREPLY=( $(compgen -W "list create get update delete" -- "$cur") ); return ;;
2692
- prefs) COMPREPLY=( $(compgen -W "list update" -- "$cur") ); return ;;
2693
- *) COMPREPLY=( $(compgen -W "list get status comment subscribe unsubscribe configs prefs" -- "$cur") ); return ;;
2694
- esac ;;
2695
- email)
2696
- case "\${COMP_WORDS[2]}" in
2697
- domains) COMPREPLY=( $(compgen -W "list add remove verify set-primary use-shared test-email dmarc" -- "$cur") ); return ;;
2698
- blocked) COMPREPLY=( $(compgen -W "list add remove auto-block-mode" -- "$cur") ); return ;;
2699
- inbound) COMPREPLY=( $(compgen -W "status rejections cancel-queued resume" -- "$cur") ); return ;;
2700
- optouts) COMPREPLY=( $(compgen -W "list remove" -- "$cur") ); return ;;
2701
- *) COMPREPLY=( $(compgen -W "domains blocked inbound optouts" -- "$cur") ); return ;;
2702
- esac ;;
2703
- models)
2704
- case "\${COMP_WORDS[2]}" in
2705
- alerts) COMPREPLY=( $(compgen -W "list mark-read mark-all-read unread-count" -- "$cur") ); return ;;
2706
- experiments) COMPREPLY=( $(compgen -W "list create get cancel delete" -- "$cur") ); return ;;
2707
- *) COMPREPLY=( $(compgen -W "list get tiers alerts recommendations experiments" -- "$cur") ); return ;;
2708
- esac ;;
2709
- docs) COMPREPLY=( $(compgen -W "search" -- "$cur") ); return ;;
2710
- api-version) COMPREPLY=( $(compgen -W "get set clear" -- "$cur") ); return ;;
2711
- auth) COMPREPLY=( $(compgen -W "login logout status refresh" -- "$cur") ); return ;;
2712
- configure) COMPREPLY=( $(compgen -W "sso list" -- "$cur") ); return ;;
2713
- ai) COMPREPLY=( $(compgen -W "feedback kb source solution memory memory-history accept decline memory-accept" -- "$cur") ); return ;;
2714
- skills) COMPREPLY=( $(compgen -W "install" -- "$cur") ); return ;;
2715
- mcp) COMPREPLY=( $(compgen -W "configure show" -- "$cur") ); return ;;
2716
- completion) COMPREPLY=( $(compgen -W "bash zsh fish" -- "$cur") ); return ;;
2728
+ local __seclai_cur prefix i
2729
+ __seclai_cur="\${COMP_WORDS[COMP_CWORD]}"
2730
+
2731
+ # Everything typed so far except the program name and the word being
2732
+ # completed, with flags dropped, joined by spaces.
2733
+ prefix=""
2734
+ for ((i = 1; i < COMP_CWORD; i++)); do
2735
+ case "\${COMP_WORDS[i]}" in
2736
+ -*) continue ;;
2737
+ esac
2738
+ if [ -z "$prefix" ]; then
2739
+ prefix="\${COMP_WORDS[i]}"
2740
+ else
2741
+ prefix="$prefix \${COMP_WORDS[i]}"
2742
+ fi
2743
+ done
2744
+
2745
+ case "$__seclai_cur" in
2746
+ -*) __seclai_reply "${options.map((o) => o.flag).join(" ")}"; return ;;
2717
2747
  esac
2718
2748
 
2719
- COMPREPLY=( $(compgen -W "$commands" -- "$cur") )
2749
+ case "$prefix" in
2750
+ ${cases}
2751
+ *) COMPREPLY=() ;;
2752
+ esac
2720
2753
  }
2721
2754
 
2722
2755
  complete -F _seclai_completions seclai
2723
2756
  `;
2724
- var ZSH = `#compdef seclai
2757
+ }
2758
+ function renderZsh(tree, options) {
2759
+ const cases = [...tree.entries()].map(([prefix, children]) => {
2760
+ const described = children.map((c) => `'${c.name}:${c.description.replace(/['`$]/g, "")}'`).join(" ");
2761
+ return ` ${JSON.stringify(prefix)}) sub=(${described}) ;;`;
2762
+ }).join("\n");
2763
+ const opts = options.map((o) => `'${o.flag}[${o.description.replace(/['\]`$]/g, "")}]'`).join(" ");
2764
+ return `#compdef seclai
2725
2765
  # seclai zsh completion \u2014 add to ~/.zshrc:
2726
2766
  # eval "$(seclai completion zsh)"
2767
+ #
2768
+ # Generated from the command tree by \`seclai completion zsh\`. Do not edit.
2727
2769
 
2728
2770
  _seclai() {
2729
- local -a commands
2730
- commands=(
2731
- 'agents:Manage agents, runs, definitions, and AI assistance'
2732
- 'sources:Manage content sources'
2733
- 'contents:Manage indexed content and embeddings'
2734
- 'kb:Manage knowledge bases'
2735
- 'memory:Manage memory banks'
2736
- 'evals:Manage evaluations'
2737
- 'solutions:Manage solutions'
2738
- 'governance:Governance AI assistant'
2739
- 'alerts:Manage alerts and alert configurations'
2740
- 'email:Agent email domains, blocklist, inbound health, opt-outs'
2741
- 'models:Models, model alerts, recommendations, experiments'
2742
- 'search:Search across Seclai resources'
2743
- 'docs:Search the Seclai documentation'
2744
- 'me:Show the authenticated user and organizations'
2745
- 'api-version:Read or pin the dated API version'
2746
- 'ai:Top-level AI assistant'
2747
- 'skills:Install skill files for AI coding tools'
2748
- 'mcp:Configure the Seclai MCP server'
2749
- 'completion:Generate shell completion scripts'
2750
- 'auth:SSO authentication'
2751
- 'configure:Manage SSO profiles'
2752
- 'help:Display help for command'
2753
- )
2754
-
2755
- _arguments -C \\
2756
- '--api-key[Seclai API key]:key' \\
2757
- '--profile[SSO profile name]:name' \\
2758
- '--account-id[Account ID (X-Account-Id header)]:id' \\
2759
- '--config-dir[Config directory]:path' \\
2760
- '--api-version[Dated API version (YYYY-MM-DD)]:date' \\
2761
- '--allow-unknown-api-version[Permit an unrecognized --api-version]' \\
2762
- '--compact[Output compact JSON]' \\
2763
- '-V[Output version]' \\
2764
- '-h[Display help]' \\
2765
- '1:command:->cmd' \\
2766
- '*::arg:->args'
2767
-
2768
- case $state in
2769
- cmd) _describe 'command' commands ;;
2770
- args)
2771
- case \${words[1]} in
2772
- agents)
2773
- local -a sub=(list create get update delete disable enable callers triggers run runs def export preview-import upload-input input-status attachment-references ai)
2774
- _describe 'subcommand' sub ;;
2775
- sources|source)
2776
- local -a sub=(list create get update delete upload upload-text exports migration)
2777
- _describe 'subcommand' sub ;;
2778
- contents)
2779
- local -a sub=(get delete upload replace replace-text embeddings)
2780
- _describe 'subcommand' sub ;;
2781
- kb)
2782
- local -a sub=(list create get update delete)
2783
- _describe 'subcommand' sub ;;
2784
- memory)
2785
- local -a sub=(list create get update delete stats agents compact delete-source templates test-compaction test-compaction-standalone ai)
2786
- _describe 'subcommand' sub ;;
2787
- evals)
2788
- local -a sub=(criteria results compatible-runs test-draft agent-results agent-runs non-manual-summary)
2789
- _describe 'subcommand' sub ;;
2790
- solutions)
2791
- local -a sub=(list create get update delete link unlink convos ai)
2792
- _describe 'subcommand' sub ;;
2793
- governance)
2794
- local -a sub=(ai)
2795
- _describe 'subcommand' sub ;;
2796
- alerts)
2797
- local -a sub=(list get status comment subscribe unsubscribe configs prefs)
2798
- _describe 'subcommand' sub ;;
2799
- email)
2800
- local -a sub=(domains blocked inbound optouts)
2801
- _describe 'subcommand' sub ;;
2802
- models)
2803
- local -a sub=(list get tiers alerts recommendations experiments)
2804
- _describe 'subcommand' sub ;;
2805
- docs)
2806
- local -a sub=(search)
2807
- _describe 'subcommand' sub ;;
2808
- api-version)
2809
- local -a sub=(get set clear)
2810
- _describe 'subcommand' sub ;;
2811
- auth)
2812
- local -a sub=(login logout status refresh)
2813
- _describe 'subcommand' sub ;;
2814
- configure)
2815
- local -a sub=(sso list)
2816
- _describe 'subcommand' sub ;;
2817
- ai)
2818
- local -a sub=(feedback kb source solution memory memory-history accept decline memory-accept)
2819
- _describe 'subcommand' sub ;;
2820
- skills)
2821
- local -a sub=(install)
2822
- _describe 'subcommand' sub ;;
2823
- mcp)
2824
- local -a sub=(configure show)
2825
- _describe 'subcommand' sub ;;
2826
- completion)
2827
- local -a sub=(bash zsh fish)
2828
- _describe 'shell' sub ;;
2829
- esac ;;
2771
+ local prefix cur
2772
+ local -a sub opts
2773
+ cur="\${words[CURRENT]}"
2774
+
2775
+ opts=(${opts})
2776
+ if [[ "$cur" == -* ]]; then
2777
+ _describe 'option' opts
2778
+ return
2779
+ fi
2780
+
2781
+ # Words typed so far, minus the program name, the word being completed, and
2782
+ # any flags.
2783
+ prefix="\${(j: :)\${(M)words[2,CURRENT-1]:#[^-]*}}"
2784
+
2785
+ case "$prefix" in
2786
+ ${cases}
2787
+ *) return ;;
2830
2788
  esac
2789
+
2790
+ _describe 'command' sub
2831
2791
  }
2832
2792
 
2833
- _seclai "$@"
2793
+ compdef _seclai seclai
2834
2794
  `;
2835
- var FISH = `# seclai fish completion \u2014 save to ~/.config/fish/completions/seclai.fish
2795
+ }
2796
+ function renderFish(tree, options) {
2797
+ const lines = [...tree.entries()].map(
2798
+ ([prefix, children]) => children.map(
2799
+ (c) => `complete -c seclai -f -n "__seclai_at '${prefix}'" -a "${c.name}" -d "${c.description.replace(/["$`]/g, "")}"`
2800
+ ).join("\n")
2801
+ ).join("\n");
2802
+ const opts = options.map(
2803
+ (o) => `complete -c seclai -l ${o.flag.replace(/^--/, "")} -d "${o.description.replace(/["$`]/g, "")}"`
2804
+ ).join("\n");
2805
+ return `# seclai fish completion \u2014 save to your completions directory:
2836
2806
  # seclai completion fish > ~/.config/fish/completions/seclai.fish
2837
-
2838
- set -l top agents sources contents kb memory evals solutions governance alerts email models search docs me api-version ai skills mcp completion auth configure help
2839
-
2840
- # Top-level
2841
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "agents" -d "Manage agents"
2842
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "sources" -d "Manage sources"
2843
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "contents" -d "Manage content"
2844
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "kb" -d "Knowledge bases"
2845
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "memory" -d "Memory banks"
2846
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "evals" -d "Evaluations"
2847
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "solutions" -d "Solutions"
2848
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "governance" -d "Governance AI"
2849
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "alerts" -d "Alerts"
2850
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "email" -d "Agent email"
2851
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "models" -d "Models and model alerts"
2852
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "search" -d "Search resources"
2853
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "docs" -d "Search documentation"
2854
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "me" -d "Authenticated user"
2855
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "api-version" -d "Dated API version"
2856
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "ai" -d "AI assistant"
2857
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "skills" -d "Skill files"
2858
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "mcp" -d "MCP server config"
2859
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "completion" -d "Shell completions"
2860
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "auth" -d "SSO authentication"
2861
- complete -c seclai -n "not __fish_seen_subcommand_from $top" -f -a "configure" -d "Manage SSO profiles"
2862
-
2863
- # agents
2864
- complete -c seclai -n "__fish_seen_subcommand_from agents; and not __fish_seen_subcommand_from list create get update delete disable enable callers triggers run runs def export preview-import upload-input input-status attachment-references ai" -f -a "list create get update delete disable enable callers triggers run runs def export preview-import upload-input input-status attachment-references ai"
2865
-
2866
- # sources
2867
- 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"
2868
-
2869
- # contents
2870
- 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"
2871
-
2872
- # kb
2873
- 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"
2874
-
2875
- # memory
2876
- 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"
2877
-
2878
- # evals
2879
- 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"
2880
-
2881
- # solutions
2882
- 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"
2883
-
2884
- # governance
2885
- complete -c seclai -n "__fish_seen_subcommand_from governance; and not __fish_seen_subcommand_from ai" -f -a "ai"
2886
-
2887
- # alerts
2888
- 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"
2889
-
2890
- # email
2891
- complete -c seclai -n "__fish_seen_subcommand_from email; and not __fish_seen_subcommand_from domains blocked inbound optouts" -f -a "domains blocked inbound optouts"
2892
-
2893
- # models
2894
- complete -c seclai -n "__fish_seen_subcommand_from models; and not __fish_seen_subcommand_from list get tiers alerts recommendations experiments" -f -a "list get tiers alerts recommendations experiments"
2895
-
2896
- # docs
2897
- complete -c seclai -n "__fish_seen_subcommand_from docs; and not __fish_seen_subcommand_from search" -f -a "search"
2898
-
2899
- # api-version
2900
- complete -c seclai -n "__fish_seen_subcommand_from api-version; and not __fish_seen_subcommand_from get set clear" -f -a "get set clear"
2901
-
2902
- # auth
2903
- complete -c seclai -n "__fish_seen_subcommand_from auth; and not __fish_seen_subcommand_from login logout status refresh" -f -a "login logout status refresh"
2904
-
2905
- # configure
2906
- complete -c seclai -n "__fish_seen_subcommand_from configure; and not __fish_seen_subcommand_from sso list" -f -a "sso list"
2907
-
2908
- # ai
2909
- 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"
2910
-
2911
- # skills
2912
- complete -c seclai -n "__fish_seen_subcommand_from skills; and not __fish_seen_subcommand_from install" -f -a "install"
2913
-
2914
- # mcp
2915
- complete -c seclai -n "__fish_seen_subcommand_from mcp; and not __fish_seen_subcommand_from configure show" -f -a "configure show"
2916
-
2917
- # completion
2918
- complete -c seclai -n "__fish_seen_subcommand_from completion; and not __fish_seen_subcommand_from bash zsh fish" -f -a "bash zsh fish"
2807
+ #
2808
+ # Generated from the command tree by \`seclai completion fish\`. Do not edit.
2809
+
2810
+ function __seclai_prefix
2811
+ set -l toks (commandline -opc)
2812
+ set -e toks[1]
2813
+ set -l out
2814
+ for t in $toks
2815
+ if not string match -q -- '-*' $t
2816
+ set -a out $t
2817
+ end
2818
+ end
2819
+ string join ' ' $out
2820
+ end
2821
+
2822
+ function __seclai_at
2823
+ test (__seclai_prefix) = "$argv[1]"
2824
+ end
2825
+
2826
+ ${lines}
2919
2827
 
2920
2828
  # Global options
2921
- complete -c seclai -l api-key -d "Seclai API key"
2922
- complete -c seclai -l profile -d "SSO profile name"
2923
- complete -c seclai -l account-id -d "Account ID (X-Account-Id header)"
2924
- complete -c seclai -l config-dir -d "Config directory"
2925
- complete -c seclai -l api-version -d "Dated API version (YYYY-MM-DD)"
2926
- complete -c seclai -l allow-unknown-api-version -d "Permit an unrecognized --api-version"
2927
- complete -c seclai -l compact -d "Output compact JSON"
2928
- complete -c seclai -s V -l version -d "Output version"
2829
+ ${opts}
2929
2830
  `;
2930
- var SCRIPTS = { bash: BASH, zsh: ZSH, fish: FISH };
2831
+ }
2832
+ function renderCompletion(shell, program) {
2833
+ const tree = collectTree(program);
2834
+ const options = globalOptions(program);
2835
+ if (shell === "bash") return renderBash(tree, options);
2836
+ if (shell === "zsh") return renderZsh(tree, options);
2837
+ if (shell === "fish") return renderFish(tree, options);
2838
+ return void 0;
2839
+ }
2931
2840
  function register17(program, rt) {
2932
- const completion = program.command("completion").description("Generate shell completion scripts.").argument("<shell>", "Shell type: bash, zsh, or fish.").action(async (shell) => {
2933
- const script = SCRIPTS[shell];
2841
+ program.command("completion").description("Generate shell completion scripts.").argument("<shell>", "Shell type: bash, zsh, or fish.").action((shell) => {
2842
+ const script = renderCompletion(shell, program);
2934
2843
  if (!script) {
2935
2844
  rt.writeErr(`Unknown shell "${shell}". Use: bash, zsh, or fish.
2936
2845
  `);
@@ -3389,15 +3298,8 @@ function escapeRegExp(s) {
3389
3298
  }
3390
3299
 
3391
3300
  // src/cli.ts
3392
- var VALUED_GLOBAL_OPTIONS = [
3393
- ["apiKey", "--api-key", "reject", "Pass a key, or omit the flag to use SECLAI_API_KEY or SSO."],
3394
- ["profile", "--profile", "reject", "Pass a profile name, or omit the flag to use the default profile."],
3395
- ["accountId", "--account-id", "reject", "Pass an account ID, or omit the flag to use the default org."],
3396
- ["configDir", "--config-dir", "reject", "Pass a directory, or omit the flag to use ~/.seclai."],
3397
- ["apiVersion", "--api-version", "warn", "Pass a YYYY-MM-DD date, or omit the flag to use the account default."]
3398
- ];
3399
3301
  function createProgram(rt = defaultRuntime()) {
3400
- const program = new Command3();
3302
+ const program = new Command4();
3401
3303
  const cliVersion = getCliVersion();
3402
3304
  program.name("seclai").description(
3403
3305
  `Seclai Command Line Interface (v${cliVersion})
@@ -3455,14 +3357,12 @@ Examples:
3455
3357
  program.exitOverride();
3456
3358
  program.hook("preAction", (thisCommand) => {
3457
3359
  const globalOpts = thisCommand.opts();
3458
- for (const [key, flag, policy, hint] of VALUED_GLOBAL_OPTIONS) {
3459
- const value = globalOpts[key];
3460
- if (typeof value !== "string" || value.length > 0) continue;
3461
- if (policy === "reject") {
3462
- throw new Error(`${flag} was given an empty value. ${hint}`);
3463
- }
3464
- delete globalOpts[key];
3465
- warnDeprecated(rt, `${flag} was given an empty value and is being ignored. ${hint}`);
3360
+ if (typeof globalOpts.apiVersion === "string" && globalOpts.apiVersion.trim().length === 0) {
3361
+ warnDeprecated(
3362
+ rt,
3363
+ "--api-version was given an empty value and is being ignored. Pass a YYYY-MM-DD date, or omit the flag to use the account default.",
3364
+ "rejected"
3365
+ );
3466
3366
  }
3467
3367
  rt.compact = Boolean(globalOpts.compact);
3468
3368
  });
@@ -3531,4 +3431,3 @@ export {
3531
3431
  createProgram,
3532
3432
  runCli
3533
3433
  };
3534
- //# sourceMappingURL=cli.js.map