@cdot65/prisma-airs-cli 3.3.0 → 4.0.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/index.js CHANGED
@@ -20,7 +20,7 @@ import {
20
20
  sanitizeFilename,
21
21
  validateTopic,
22
22
  writeBackupFile
23
- } from "../chunk-2VIUZRPB.js";
23
+ } from "../chunk-W5YDJS7H.js";
24
24
 
25
25
  // src/cli/index.ts
26
26
  import "dotenv/config";
@@ -187,9 +187,15 @@ var SdkAiGatewayService = class {
187
187
  workspaceSlug,
188
188
  days,
189
189
  totalCents: raw.data.total,
190
+ totalUsd: raw.data.total / 100,
190
191
  avgCents: raw.data.avg,
192
+ avgUsd: raw.data.avg / 100,
191
193
  quotaExceeded: raw.data.isQuotaExceeded,
192
- records: raw.data.records.map((r) => ({ date: r.x, costCents: r.y }))
194
+ records: raw.data.records.map((r) => ({
195
+ date: r.x,
196
+ costCents: r.y,
197
+ costUsd: r.y / 100
198
+ }))
193
199
  };
194
200
  }
195
201
  /** Re-read after a write, falling back to the (partial) write response if the get fails. */
@@ -249,7 +255,11 @@ import { dump as yamlDump } from "js-yaml";
249
255
 
250
256
  // src/cli/renderer/common.ts
251
257
  import chalk2 from "chalk";
258
+ import { dump } from "js-yaml";
259
+ var CliUsageError = class extends Error {
260
+ };
252
261
  function fail(err) {
262
+ if (err instanceof CliUsageError) usageError(err.message);
253
263
  const message = err instanceof Error ? err.message : String(err);
254
264
  const status = err?.status ?? err?.statusCode;
255
265
  console.error(chalk2.red(`
@@ -267,44 +277,81 @@ function usageError(message) {
267
277
  `));
268
278
  process.exit(2);
269
279
  }
270
- var OUTPUT_FORMATS = ["pretty", "table", "csv", "json", "yaml"];
280
+ var OUTPUT_FORMATS = [
281
+ "pretty",
282
+ "table",
283
+ "markdown",
284
+ "csv",
285
+ "json",
286
+ "yaml"
287
+ ];
288
+ async function resolveOutput(command, opts, resolution = {}) {
289
+ const localIsExplicit = command.getOptionValueSource?.("output") === "cli";
290
+ const root = command.parent ? command.optsWithGlobals() : command.opts();
291
+ let configured;
292
+ try {
293
+ configured = (await loadConfig()).defaultOutput;
294
+ } catch (error) {
295
+ if (process.env.PANW_CLI_OUTPUT !== void 0) configured = process.env.PANW_CLI_OUTPUT;
296
+ else throw error;
297
+ }
298
+ const candidate = String(localIsExplicit ? opts.output : root.output ?? configured ?? "pretty");
299
+ if (!OUTPUT_FORMATS.includes(candidate))
300
+ throw new CliUsageError(
301
+ `Invalid output format '${candidate}'. Expected: ${OUTPUT_FORMATS.join(", ")}`
302
+ );
303
+ const format = candidate;
304
+ const allowed = resolution.allowed ?? OUTPUT_FORMATS;
305
+ if (!allowed.includes(format))
306
+ throw new CliUsageError(
307
+ `Output format '${format}' is not supported here. Expected: ${allowed.join(", ")}`
308
+ );
309
+ return format;
310
+ }
311
+ function displayValue(value) {
312
+ if (value == null) return "";
313
+ return typeof value === "object" ? JSON.stringify(value) : String(value);
314
+ }
315
+ function csvCell(value) {
316
+ const text = displayValue(value);
317
+ return /[",\r\n]/.test(text) ? `"${text.replace(/"/g, '""')}"` : text;
318
+ }
319
+ function markdownCell(value) {
320
+ return displayValue(value).replace(/\\/g, "\\\\").replace(/\|/g, "\\|").replace(/\r?\n/g, "<br>");
321
+ }
271
322
  function formatOutput(rows, columns, format) {
272
- if (rows.length === 0) return "";
273
- const vals = (row, key) => String(row[key] ?? "");
323
+ if (rows.length === 0) return format === "json" ? "[]" : "";
324
+ const projected = rows.map((row) => columns.map((column) => row[column.key]));
274
325
  switch (format) {
275
326
  case "json":
276
- return JSON.stringify(
277
- rows.map((r) => {
278
- const obj = {};
279
- for (const c of columns) obj[c.key] = r[c.key];
280
- return obj;
281
- }),
282
- null,
283
- 2
284
- );
285
- case "csv": {
286
- const header = columns.map((c) => c.label).join(",");
287
- const lines = rows.map(
288
- (r) => columns.map((c) => {
289
- const v = vals(r, c.key);
290
- return v.includes(",") || v.includes('"') ? `"${v.replace(/"/g, '""')}"` : v;
291
- }).join(",")
292
- );
293
- return [header, ...lines].join("\n");
294
- }
295
- case "yaml": {
296
- return rows.map((r) => columns.map((c) => `${c.key}: ${vals(r, c.key)}`).join("\n")).join("\n---\n");
327
+ return JSON.stringify(rows, null, 2);
328
+ case "yaml":
329
+ return dump(rows, { noRefs: true, lineWidth: -1 }).trimEnd();
330
+ case "csv":
331
+ return [
332
+ columns.map((column) => csvCell(column.label)).join(","),
333
+ ...projected.map((values) => values.map(csvCell).join(","))
334
+ ].join("\n");
335
+ case "markdown": {
336
+ const header = `| ${columns.map((column) => markdownCell(column.label)).join(" | ")} |`;
337
+ const divider = `| ${columns.map(() => "---").join(" | ")} |`;
338
+ return [
339
+ header,
340
+ divider,
341
+ ...projected.map((values) => `| ${values.map(markdownCell).join(" | ")} |`)
342
+ ].join("\n");
297
343
  }
298
344
  case "table": {
345
+ const values = projected.map((row) => row.map(displayValue));
299
346
  const widths = columns.map(
300
- (c) => Math.max(c.label.length, ...rows.map((r) => vals(r, c.key).length))
347
+ (column, index) => Math.max(column.label.length, ...values.map((row) => row[index].length))
301
348
  );
302
- const sep = widths.map((w) => "\u2500".repeat(w + 2)).join("\u253C");
303
- const header = columns.map((c, i) => ` ${c.label.padEnd(widths[i])} `).join("\u2502");
304
- const body = rows.map(
305
- (r) => columns.map((c, i) => ` ${vals(r, c.key).padEnd(widths[i])} `).join("\u2502")
349
+ const separator = widths.map((width) => "\u2500".repeat(width + 2)).join("\u253C");
350
+ const header = columns.map((column, index) => ` ${column.label.padEnd(widths[index])} `).join("\u2502");
351
+ const body = values.map(
352
+ (row) => row.map((value, index) => ` ${value.padEnd(widths[index])} `).join("\u2502")
306
353
  );
307
- return [header, sep, ...body].join("\n");
354
+ return [header, separator, ...body].join("\n");
308
355
  }
309
356
  default:
310
357
  return "";
@@ -403,6 +450,65 @@ ${INDENT}${chalk3.bold(label)}
403
450
  }
404
451
  };
405
452
 
453
+ // src/cli/renderer/view.ts
454
+ import { dump as dump2 } from "js-yaml";
455
+ function asRecord(item) {
456
+ return item;
457
+ }
458
+ function project(view, item) {
459
+ const source = asRecord(item);
460
+ return Object.fromEntries(
461
+ view.columns.map((column) => [column.key, column.get ? column.get(item) : source[column.key]])
462
+ );
463
+ }
464
+ function renderPageStatus(page) {
465
+ if (!page) return;
466
+ if (page.all) ui.status(`Showing all ${page.total ?? page.returned}`);
467
+ else if (page.total !== void 0)
468
+ ui.status(
469
+ `Showing ${page.returned} of ${page.total}${page.next !== void 0 ? ` (next --offset ${page.next})` : ""}`
470
+ );
471
+ else if (page.next !== void 0) ui.status(`Showing ${page.returned} (more available)`);
472
+ else ui.status(`Showing ${page.returned}`);
473
+ }
474
+ function emitList(view, items, format, opts = {}) {
475
+ if (format === "pretty") {
476
+ if (items.length === 0) ui.emptyList(view.name);
477
+ else view.pretty.list(items);
478
+ } else {
479
+ const rows = format === "json" || format === "yaml" ? items.map((item) => view.structured?.(item) ?? asRecord(item)) : items.map((item) => project(view, item));
480
+ const rendered = formatOutput(rows, view.columns, format);
481
+ if (rendered) console.log(rendered);
482
+ }
483
+ renderPageStatus(opts.page);
484
+ }
485
+ function emitDetail(view, item, format) {
486
+ if (format === "pretty") {
487
+ view.pretty.detail(item);
488
+ return;
489
+ }
490
+ const structured = view.structured?.(item) ?? asRecord(item);
491
+ if (format === "json") console.log(JSON.stringify(structured, null, 2));
492
+ else if (format === "yaml")
493
+ console.log(dump2(structured, { noRefs: true, lineWidth: -1 }).trimEnd());
494
+ else {
495
+ const rows = Object.entries(structured).map(([key, value]) => ({
496
+ key,
497
+ value: value != null && typeof value === "object" ? JSON.stringify(value) : value
498
+ }));
499
+ console.log(
500
+ formatOutput(
501
+ rows,
502
+ [
503
+ { key: "key", label: "Key" },
504
+ { key: "value", label: "Value" }
505
+ ],
506
+ format
507
+ )
508
+ );
509
+ }
510
+ }
511
+
406
512
  // src/cli/renderer/aigateway.ts
407
513
  function renderAiGatewayHeader() {
408
514
  ui.header("Prisma AIRS \u2014 AI Gateway", "Gateway workspace operations");
@@ -498,7 +604,17 @@ function renderWorkspaceDetail(workspace, format = "pretty") {
498
604
  }
499
605
  function renderCostReport(report, format = "pretty") {
500
606
  if (format !== "pretty") {
501
- console.log(format === "json" ? JSON.stringify(report, null, 2) : yamlDump(report));
607
+ emitDetail(
608
+ {
609
+ name: "cost report",
610
+ columns: [],
611
+ pretty: { list() {
612
+ }, detail() {
613
+ } }
614
+ },
615
+ report,
616
+ format
617
+ );
502
618
  return;
503
619
  }
504
620
  const dollars = (cents) => `$${(cents / 100).toFixed(2)}`;
@@ -597,60 +713,67 @@ function pageMeta(page, returned) {
597
713
  returned
598
714
  };
599
715
  }
600
- function emitList(page, fmt, header, toRow, columns, prettyLine) {
601
- const content = Array.isArray(page?.content) ? page.content : [];
602
- const rows = content.map(toRow);
603
- if (fmt === "json" || fmt === "yaml") {
604
- emitStructured({ items: rows, page: pageMeta(page, content.length) }, fmt);
605
- return;
606
- }
607
- if (content.length === 0) {
608
- ui.emptyList(header.toLowerCase());
609
- return;
610
- }
611
- if (fmt === "pretty") {
612
- ui.section(`${header}:`);
613
- for (const item of content) console.log(prettyLine(item));
614
- const meta = pageMeta(page, content.length);
615
- console.log();
616
- ui.dim(
617
- `page=${meta.number} size=${meta.size} returned=${meta.returned} total=${meta.total ?? "?"}`
618
- );
619
- console.log();
620
- return;
621
- }
622
- console.log(formatOutput(rows, columns, fmt));
716
+ function camelKey(key) {
717
+ return key.replace(/[_-]([a-z0-9])/g, (_, char) => char.toUpperCase());
623
718
  }
624
- function fieldsToObject(fields) {
625
- const obj = {};
626
- for (const f of fields) {
627
- if (f.value === void 0 || f.value === null || f.value === "") continue;
628
- obj[toKey(f.label)] = f.value;
719
+ function camelize(value) {
720
+ if (Array.isArray(value)) return value.map(camelize);
721
+ if (value && typeof value === "object") {
722
+ return Object.fromEntries(
723
+ Object.entries(value).map(([key, child]) => [
724
+ camelKey(key),
725
+ camelize(child)
726
+ ])
727
+ );
629
728
  }
630
- return obj;
631
- }
632
- function toKey(label) {
633
- return label.toLowerCase().replace(/[^a-z0-9]+/g, "_").replace(/^_+|_+$/g, "");
729
+ return value;
634
730
  }
635
- function emitDetail(_item, fmt, fields, title) {
636
- if (fmt === "json" || fmt === "yaml") {
637
- emitStructured(fieldsToObject(fields), fmt);
638
- return;
639
- }
640
- if (fmt === "pretty") {
641
- ui.section(`${title}:`);
642
- const pairs = [];
643
- for (const f of fields) {
644
- if (f.value === void 0 || f.value === null || f.value === "") continue;
645
- pairs.push([f.label, f.value]);
731
+ function emitList2(page, fmt, header, toRow, columns, prettyLine) {
732
+ const content = Array.isArray(page?.content) ? page.content : [];
733
+ const meta = pageMeta(page, content.length);
734
+ const view = {
735
+ name: header.toLowerCase(),
736
+ columns: columns.map((column) => ({
737
+ ...column,
738
+ get: (item) => toRow(item)[column.key]
739
+ })),
740
+ structured: (item) => camelize(item),
741
+ pretty: {
742
+ list(items) {
743
+ ui.section(`${header}:`);
744
+ for (const item of items) console.log(prettyLine(item));
745
+ console.log();
746
+ },
747
+ detail() {
748
+ }
646
749
  }
647
- ui.keyValue(pairs);
648
- console.log();
649
- return;
650
- }
651
- const rows = [Object.fromEntries(fields.map((f) => [f.label, f.value ?? ""]))];
652
- const columns = fields.map((f) => ({ key: f.label, label: f.label }));
653
- console.log(formatOutput(rows, columns, fmt));
750
+ };
751
+ const total = typeof meta.total === "number" ? meta.total : void 0;
752
+ const number = Number(meta.number ?? 0);
753
+ const size = Number(meta.size ?? content.length);
754
+ const next = total !== void 0 && (number + 1) * size < total ? (number + 1) * size : void 0;
755
+ emitList(view, content, fmt, { page: { returned: content.length, total, next } });
756
+ }
757
+ function emitDetail2(item, fmt, fields, title) {
758
+ const view = {
759
+ name: title.toLowerCase(),
760
+ columns: [],
761
+ structured: (value) => camelize(value),
762
+ pretty: {
763
+ list() {
764
+ },
765
+ detail() {
766
+ ui.section(`${title}:`);
767
+ ui.keyValue(
768
+ fields.filter(
769
+ (field) => field.value !== void 0 && field.value !== null && field.value !== ""
770
+ ).map((field) => [field.label, field.value])
771
+ );
772
+ console.log();
773
+ }
774
+ }
775
+ };
776
+ emitDetail(view, item, fmt);
654
777
  }
655
778
  function ackObject(verb, item) {
656
779
  const out = { action: verb };
@@ -681,7 +804,7 @@ function emitIdAck(verb, id) {
681
804
  }
682
805
  var dlpFilteringProfiles = {
683
806
  renderList(page, fmt) {
684
- emitList(
807
+ emitList2(
685
808
  page,
686
809
  fmt,
687
810
  "Data Filtering Profiles",
@@ -711,7 +834,7 @@ var dlpFilteringProfiles = {
711
834
  );
712
835
  },
713
836
  renderGet(item, fmt) {
714
- emitDetail(
837
+ emitDetail2(
715
838
  item,
716
839
  fmt,
717
840
  [
@@ -740,7 +863,7 @@ var dlpFilteringProfiles = {
740
863
  };
741
864
  var dlpPatterns = {
742
865
  renderList(page, fmt) {
743
- emitList(
866
+ emitList2(
744
867
  page,
745
868
  fmt,
746
869
  "Data Patterns",
@@ -769,7 +892,7 @@ var dlpPatterns = {
769
892
  );
770
893
  },
771
894
  renderGet(item, fmt) {
772
- emitDetail(
895
+ emitDetail2(
773
896
  item,
774
897
  fmt,
775
898
  [
@@ -808,7 +931,7 @@ var dlpPatterns = {
808
931
  };
809
932
  var dlpProfiles = {
810
933
  renderList(page, fmt) {
811
- emitList(
934
+ emitList2(
812
935
  page,
813
936
  fmt,
814
937
  "Data Profiles",
@@ -837,7 +960,7 @@ var dlpProfiles = {
837
960
  );
838
961
  },
839
962
  renderGet(item, fmt) {
840
- emitDetail(
963
+ emitDetail2(
841
964
  item,
842
965
  fmt,
843
966
  [
@@ -865,7 +988,7 @@ var dlpProfiles = {
865
988
  };
866
989
  var dlpDictionaries = {
867
990
  renderList(page, fmt) {
868
- emitList(
991
+ emitList2(
869
992
  page,
870
993
  fmt,
871
994
  "Data Dictionaries",
@@ -894,7 +1017,7 @@ var dlpDictionaries = {
894
1017
  );
895
1018
  },
896
1019
  renderGet(item, fmt) {
897
- emitDetail(
1020
+ emitDetail2(
898
1021
  item,
899
1022
  fmt,
900
1023
  [
@@ -989,7 +1112,15 @@ function renderEvalTerminal(output) {
989
1112
 
990
1113
  // src/cli/renderer/modelsecurity.ts
991
1114
  import chalk7 from "chalk";
992
- import { dump as yamlDump3 } from "js-yaml";
1115
+ function resourceView(name, columns, pretty) {
1116
+ return { name, columns, pretty };
1117
+ }
1118
+ function structuredList(name, items, columns, format, pretty) {
1119
+ emitList(resourceView(name, columns, { list: pretty, detail: () => void 0 }), items, format);
1120
+ }
1121
+ function structuredDetail(name, item, format, pretty) {
1122
+ emitDetail(resourceView(name, [], { list: () => void 0, detail: pretty }), item, format);
1123
+ }
993
1124
  function renderModelSecurityHeader() {
994
1125
  ui.header("Prisma AIRS \u2014 Model Security", "ML model supply chain security");
995
1126
  }
@@ -1012,31 +1143,25 @@ function stateColor(state) {
1012
1143
  }
1013
1144
  }
1014
1145
  function renderGroupList(groups, format = "pretty") {
1015
- if (groups.length === 0) {
1016
- ui.emptyList("security groups");
1017
- return;
1018
- }
1019
1146
  if (format !== "pretty") {
1020
- const rows = groups.map((g) => ({
1021
- id: g.uuid,
1022
- name: g.name,
1023
- state: g.state,
1024
- sourceType: g.sourceType
1025
- }));
1026
- console.log(
1027
- formatOutput(
1028
- rows,
1029
- [
1030
- { key: "id", label: "ID" },
1031
- { key: "name", label: "Name" },
1032
- { key: "state", label: "State" },
1033
- { key: "sourceType", label: "Source Type" }
1034
- ],
1035
- format
1036
- )
1147
+ structuredList(
1148
+ "security groups",
1149
+ groups,
1150
+ [
1151
+ { key: "uuid", label: "ID" },
1152
+ { key: "name", label: "Name" },
1153
+ { key: "state", label: "State" },
1154
+ { key: "sourceType", label: "Source Type" }
1155
+ ],
1156
+ format,
1157
+ () => void 0
1037
1158
  );
1038
1159
  return;
1039
1160
  }
1161
+ if (groups.length === 0) {
1162
+ ui.emptyList("security groups");
1163
+ return;
1164
+ }
1040
1165
  ui.section("Security Groups:");
1041
1166
  for (const g of groups) {
1042
1167
  ui.dim(g.uuid);
@@ -1046,12 +1171,8 @@ function renderGroupList(groups, format = "pretty") {
1046
1171
  console.log();
1047
1172
  }
1048
1173
  function renderGroupDetail(group, format = "pretty") {
1049
- if (format === "json") {
1050
- console.log(JSON.stringify(group, null, 2));
1051
- return;
1052
- }
1053
- if (format === "yaml") {
1054
- console.log(yamlDump3(group));
1174
+ if (format !== "pretty") {
1175
+ structuredDetail("security group", group, format, () => void 0);
1055
1176
  return;
1056
1177
  }
1057
1178
  ui.section("Security Group Detail:");
@@ -1068,33 +1189,30 @@ function renderGroupDetail(group, format = "pretty") {
1068
1189
  console.log();
1069
1190
  }
1070
1191
  function renderRuleList(rules, format = "pretty") {
1071
- if (rules.length === 0) {
1072
- ui.emptyList("security rules");
1073
- return;
1074
- }
1075
1192
  if (format !== "pretty") {
1076
- const rows = rules.map((r) => ({
1077
- id: r.uuid,
1078
- name: r.name,
1079
- type: r.ruleType,
1080
- defaultState: r.defaultState,
1081
- sources: r.compatibleSources.join(", ")
1082
- }));
1083
- console.log(
1084
- formatOutput(
1085
- rows,
1086
- [
1087
- { key: "id", label: "ID" },
1088
- { key: "name", label: "Name" },
1089
- { key: "type", label: "Type" },
1090
- { key: "defaultState", label: "Default State" },
1091
- { key: "sources", label: "Sources" }
1092
- ],
1093
- format
1094
- )
1193
+ structuredList(
1194
+ "security rules",
1195
+ rules,
1196
+ [
1197
+ { key: "uuid", label: "ID" },
1198
+ { key: "name", label: "Name" },
1199
+ { key: "ruleType", label: "Type" },
1200
+ { key: "defaultState", label: "Default State" },
1201
+ {
1202
+ key: "compatibleSources",
1203
+ label: "Sources",
1204
+ get: (rule) => rule.compatibleSources.join(", ")
1205
+ }
1206
+ ],
1207
+ format,
1208
+ () => void 0
1095
1209
  );
1096
1210
  return;
1097
1211
  }
1212
+ if (rules.length === 0) {
1213
+ ui.emptyList("security rules");
1214
+ return;
1215
+ }
1098
1216
  ui.section("Security Rules:");
1099
1217
  for (const r of rules) {
1100
1218
  ui.dim(r.uuid);
@@ -1106,7 +1224,11 @@ function renderRuleList(rules, format = "pretty") {
1106
1224
  }
1107
1225
  console.log();
1108
1226
  }
1109
- function renderRuleDetail(rule) {
1227
+ function renderRuleDetail(rule, format = "pretty") {
1228
+ if (format !== "pretty") {
1229
+ structuredDetail("security rule", rule, format, () => void 0);
1230
+ return;
1231
+ }
1110
1232
  ui.section("Security Rule Detail:");
1111
1233
  ui.keyValue([
1112
1234
  ["UUID", rule.uuid],
@@ -1137,7 +1259,21 @@ function renderRuleDetail(rule) {
1137
1259
  }
1138
1260
  console.log();
1139
1261
  }
1140
- function renderRuleInstanceList(instances) {
1262
+ function renderRuleInstanceList(instances, format = "pretty") {
1263
+ if (format !== "pretty") {
1264
+ structuredList(
1265
+ "rule instances",
1266
+ instances,
1267
+ [
1268
+ { key: "uuid", label: "ID" },
1269
+ { key: "securityRuleUuid", label: "Rule ID" },
1270
+ { key: "state", label: "State" }
1271
+ ],
1272
+ format,
1273
+ () => void 0
1274
+ );
1275
+ return;
1276
+ }
1141
1277
  if (instances.length === 0) {
1142
1278
  ui.emptyList("rule instances");
1143
1279
  return;
@@ -1150,7 +1286,11 @@ function renderRuleInstanceList(instances) {
1150
1286
  }
1151
1287
  console.log();
1152
1288
  }
1153
- function renderRuleInstanceDetail(instance) {
1289
+ function renderRuleInstanceDetail(instance, format = "pretty") {
1290
+ if (format !== "pretty") {
1291
+ structuredDetail("rule instance", instance, format, () => void 0);
1292
+ return;
1293
+ }
1154
1294
  ui.section("Rule Instance Detail:");
1155
1295
  const pairs = [
1156
1296
  ["UUID", instance.uuid],
@@ -1175,37 +1315,26 @@ function renderRuleInstanceDetail(instance) {
1175
1315
  console.log();
1176
1316
  }
1177
1317
  function renderMsScanList(scans, format = "pretty") {
1178
- if (scans.length === 0) {
1179
- ui.emptyList("scans");
1180
- return;
1181
- }
1182
1318
  if (format !== "pretty") {
1183
- const rows = scans.map((s) => ({
1184
- id: s.uuid,
1185
- outcome: s.evalOutcome,
1186
- origin: s.scanOrigin,
1187
- modelUri: s.modelUri ?? "",
1188
- createdAt: s.createdAt,
1189
- passed: s.evalSummary?.rulesPassed ?? "",
1190
- failed: s.evalSummary?.rulesFailed ?? ""
1191
- }));
1192
- console.log(
1193
- formatOutput(
1194
- rows,
1195
- [
1196
- { key: "id", label: "ID" },
1197
- { key: "outcome", label: "Outcome" },
1198
- { key: "origin", label: "Origin" },
1199
- { key: "modelUri", label: "Model URI" },
1200
- { key: "passed", label: "Passed" },
1201
- { key: "failed", label: "Failed" },
1202
- { key: "createdAt", label: "Created" }
1203
- ],
1204
- format
1205
- )
1319
+ structuredList(
1320
+ "scans",
1321
+ scans,
1322
+ [
1323
+ { key: "uuid", label: "ID" },
1324
+ { key: "evalOutcome", label: "Outcome" },
1325
+ { key: "scanOrigin", label: "Origin" },
1326
+ { key: "modelUri", label: "Model URI" },
1327
+ { key: "createdAt", label: "Created" }
1328
+ ],
1329
+ format,
1330
+ () => void 0
1206
1331
  );
1207
1332
  return;
1208
1333
  }
1334
+ if (scans.length === 0) {
1335
+ ui.emptyList("scans");
1336
+ return;
1337
+ }
1209
1338
  ui.section("Model Security Scans:");
1210
1339
  for (const s of scans) {
1211
1340
  ui.dim(s.uuid);
@@ -1222,7 +1351,11 @@ function renderMsScanList(scans, format = "pretty") {
1222
1351
  }
1223
1352
  console.log();
1224
1353
  }
1225
- function renderMsScanDetail(scan) {
1354
+ function renderMsScanDetail(scan, format = "pretty") {
1355
+ if (format !== "pretty") {
1356
+ structuredDetail("scan", scan, format, () => void 0);
1357
+ return;
1358
+ }
1226
1359
  ui.section("Scan Detail:");
1227
1360
  const pairs = [
1228
1361
  ["UUID", scan.uuid],
@@ -1248,7 +1381,22 @@ function renderMsScanDetail(scan) {
1248
1381
  }
1249
1382
  console.log();
1250
1383
  }
1251
- function renderEvaluationList(evaluations) {
1384
+ function renderEvaluationList(evaluations, format = "pretty") {
1385
+ if (format !== "pretty") {
1386
+ structuredList(
1387
+ "evaluations",
1388
+ evaluations,
1389
+ [
1390
+ { key: "uuid", label: "ID" },
1391
+ { key: "ruleName", label: "Rule" },
1392
+ { key: "result", label: "Result" },
1393
+ { key: "ruleInstanceState", label: "State" }
1394
+ ],
1395
+ format,
1396
+ () => void 0
1397
+ );
1398
+ return;
1399
+ }
1252
1400
  if (evaluations.length === 0) {
1253
1401
  ui.emptyList("evaluations");
1254
1402
  return;
@@ -1262,7 +1410,11 @@ function renderEvaluationList(evaluations) {
1262
1410
  }
1263
1411
  console.log();
1264
1412
  }
1265
- function renderEvaluationDetail(evaluation) {
1413
+ function renderEvaluationDetail(evaluation, format = "pretty") {
1414
+ if (format !== "pretty") {
1415
+ structuredDetail("evaluation", evaluation, format, () => void 0);
1416
+ return;
1417
+ }
1266
1418
  ui.section("Evaluation Detail:");
1267
1419
  ui.keyValue([
1268
1420
  ["UUID", evaluation.uuid],
@@ -1275,7 +1427,22 @@ function renderEvaluationDetail(evaluation) {
1275
1427
  ]);
1276
1428
  console.log();
1277
1429
  }
1278
- function renderViolationList(violations) {
1430
+ function renderViolationList(violations, format = "pretty") {
1431
+ if (format !== "pretty") {
1432
+ structuredList(
1433
+ "violations",
1434
+ violations,
1435
+ [
1436
+ { key: "uuid", label: "ID" },
1437
+ { key: "ruleName", label: "Rule" },
1438
+ { key: "file", label: "File" },
1439
+ { key: "threat", label: "Threat" }
1440
+ ],
1441
+ format,
1442
+ () => void 0
1443
+ );
1444
+ return;
1445
+ }
1279
1446
  if (violations.length === 0) {
1280
1447
  ui.emptyList("violations");
1281
1448
  return;
@@ -1289,7 +1456,11 @@ function renderViolationList(violations) {
1289
1456
  }
1290
1457
  console.log();
1291
1458
  }
1292
- function renderViolationDetail(violation) {
1459
+ function renderViolationDetail(violation, format = "pretty") {
1460
+ if (format !== "pretty") {
1461
+ structuredDetail("violation", violation, format, () => void 0);
1462
+ return;
1463
+ }
1293
1464
  ui.section("Violation Detail:");
1294
1465
  ui.keyValue([
1295
1466
  ["UUID", violation.uuid],
@@ -1302,7 +1473,22 @@ function renderViolationDetail(violation) {
1302
1473
  ]);
1303
1474
  console.log();
1304
1475
  }
1305
- function renderFileList(files) {
1476
+ function renderFileList(files, format = "pretty") {
1477
+ if (format !== "pretty") {
1478
+ structuredList(
1479
+ "files",
1480
+ files,
1481
+ [
1482
+ { key: "uuid", label: "ID" },
1483
+ { key: "path", label: "Path" },
1484
+ { key: "type", label: "Type" },
1485
+ { key: "result", label: "Result" }
1486
+ ],
1487
+ format,
1488
+ () => void 0
1489
+ );
1490
+ return;
1491
+ }
1306
1492
  if (files.length === 0) {
1307
1493
  ui.emptyList("files");
1308
1494
  return;
@@ -1338,33 +1524,30 @@ function renderLabelValues(key, values) {
1338
1524
  console.log();
1339
1525
  }
1340
1526
  function renderModelList(models, format = "pretty") {
1341
- if (models.length === 0) {
1342
- ui.emptyList("models");
1343
- return;
1344
- }
1345
1527
  if (format !== "pretty") {
1346
- const rows = models.map((m) => ({
1347
- id: m.uuid,
1348
- name: m.name,
1349
- outcome: m.latestVersionOutcome ?? "",
1350
- formats: (m.latestVersionFormats ?? []).join(", "),
1351
- scanned: m.latestVersionScanTime ?? ""
1352
- }));
1353
- console.log(
1354
- formatOutput(
1355
- rows,
1356
- [
1357
- { key: "id", label: "ID" },
1358
- { key: "name", label: "Name" },
1359
- { key: "outcome", label: "Outcome" },
1360
- { key: "formats", label: "Formats" },
1361
- { key: "scanned", label: "Last Scan" }
1362
- ],
1363
- format
1364
- )
1528
+ structuredList(
1529
+ "models",
1530
+ models,
1531
+ [
1532
+ { key: "uuid", label: "ID" },
1533
+ { key: "name", label: "Name" },
1534
+ { key: "latestVersionOutcome", label: "Outcome" },
1535
+ {
1536
+ key: "latestVersionFormats",
1537
+ label: "Formats",
1538
+ get: (model) => (model.latestVersionFormats ?? []).join(", ")
1539
+ },
1540
+ { key: "latestVersionScanTime", label: "Last Scan" }
1541
+ ],
1542
+ format,
1543
+ () => void 0
1365
1544
  );
1366
1545
  return;
1367
1546
  }
1547
+ if (models.length === 0) {
1548
+ ui.emptyList("models");
1549
+ return;
1550
+ }
1368
1551
  ui.section("Models:");
1369
1552
  for (const m of models) {
1370
1553
  ui.dim(m.uuid);
@@ -1376,7 +1559,7 @@ function renderModelList(models, format = "pretty") {
1376
1559
  }
1377
1560
  function renderModelDetail(model, format = "pretty") {
1378
1561
  if (format !== "pretty") {
1379
- console.log(format === "json" ? JSON.stringify(model, null, 2) : yamlDump3(model));
1562
+ structuredDetail("model", model, format, () => void 0);
1380
1563
  return;
1381
1564
  }
1382
1565
  ui.section("Model Detail:");
@@ -1403,33 +1586,26 @@ function renderModelDetail(model, format = "pretty") {
1403
1586
  console.log();
1404
1587
  }
1405
1588
  function renderModelVersionList(versions, format = "pretty") {
1406
- if (versions.length === 0) {
1407
- ui.emptyList("versions");
1408
- return;
1409
- }
1410
1589
  if (format !== "pretty") {
1411
- const rows = versions.map((v) => ({
1412
- id: v.uuid,
1413
- revision: v.revision,
1414
- files: v.fileCount ?? "",
1415
- outcome: v.lastEvalOutcome ?? "",
1416
- scanned: v.latestScanTime ?? ""
1417
- }));
1418
- console.log(
1419
- formatOutput(
1420
- rows,
1421
- [
1422
- { key: "id", label: "ID" },
1423
- { key: "revision", label: "Revision" },
1424
- { key: "files", label: "Files" },
1425
- { key: "outcome", label: "Outcome" },
1426
- { key: "scanned", label: "Last Scan" }
1427
- ],
1428
- format
1429
- )
1590
+ structuredList(
1591
+ "versions",
1592
+ versions,
1593
+ [
1594
+ { key: "uuid", label: "ID" },
1595
+ { key: "revision", label: "Revision" },
1596
+ { key: "fileCount", label: "Files" },
1597
+ { key: "lastEvalOutcome", label: "Outcome" },
1598
+ { key: "latestScanTime", label: "Last Scan" }
1599
+ ],
1600
+ format,
1601
+ () => void 0
1430
1602
  );
1431
1603
  return;
1432
1604
  }
1605
+ if (versions.length === 0) {
1606
+ ui.emptyList("versions");
1607
+ return;
1608
+ }
1433
1609
  ui.section("Model Versions:");
1434
1610
  for (const v of versions) {
1435
1611
  ui.dim(v.uuid);
@@ -1441,7 +1617,7 @@ function renderModelVersionList(versions, format = "pretty") {
1441
1617
  }
1442
1618
  function renderModelVersionDetail(version, format = "pretty") {
1443
1619
  if (format !== "pretty") {
1444
- console.log(format === "json" ? JSON.stringify(version, null, 2) : yamlDump3(version));
1620
+ structuredDetail("model version", version, format, () => void 0);
1445
1621
  return;
1446
1622
  }
1447
1623
  ui.section("Model Version Detail:");
@@ -1473,31 +1649,12 @@ function renderModelVersionDetail(version, format = "pretty") {
1473
1649
  console.log();
1474
1650
  }
1475
1651
  function renderModelFileList(files, format = "pretty") {
1476
- if (files.length === 0) {
1477
- ui.emptyList("files");
1652
+ if (format !== "pretty") {
1653
+ renderFileList(files, format);
1478
1654
  return;
1479
1655
  }
1480
- if (format !== "pretty") {
1481
- const rows = files.map((f) => ({
1482
- id: f.uuid,
1483
- path: f.path,
1484
- type: f.type,
1485
- formats: f.formats.join(", "),
1486
- result: f.result
1487
- }));
1488
- console.log(
1489
- formatOutput(
1490
- rows,
1491
- [
1492
- { key: "id", label: "ID" },
1493
- { key: "path", label: "Path" },
1494
- { key: "type", label: "Type" },
1495
- { key: "formats", label: "Formats" },
1496
- { key: "result", label: "Result" }
1497
- ],
1498
- format
1499
- )
1500
- );
1656
+ if (files.length === 0) {
1657
+ ui.emptyList("files");
1501
1658
  return;
1502
1659
  }
1503
1660
  renderFileList(files);
@@ -1505,7 +1662,7 @@ function renderModelFileList(files, format = "pretty") {
1505
1662
 
1506
1663
  // src/cli/renderer/redteam.ts
1507
1664
  import chalk8 from "chalk";
1508
- import { dump as yamlDump4 } from "js-yaml";
1665
+ import { dump as yamlDump3 } from "js-yaml";
1509
1666
  function renderRedteamHeader() {
1510
1667
  ui.header("Prisma AIRS \u2014 AI Red Team", "Adversarial scan operations");
1511
1668
  }
@@ -1825,7 +1982,7 @@ function renderTargetDetail(target, format = "pretty") {
1825
1982
  if (format === "json") {
1826
1983
  console.log(JSON.stringify(target, null, 2));
1827
1984
  } else if (format === "yaml") {
1828
- console.log(yamlDump4(target));
1985
+ console.log(yamlDump3(target));
1829
1986
  }
1830
1987
  return;
1831
1988
  }
@@ -1857,7 +2014,7 @@ function renderPromptSetDetail(ps, format = "pretty", info) {
1857
2014
  if (format === "json") {
1858
2015
  console.log(JSON.stringify(payload, null, 2));
1859
2016
  } else if (format === "yaml") {
1860
- console.log(yamlDump4(payload));
2017
+ console.log(yamlDump3(payload));
1861
2018
  }
1862
2019
  return;
1863
2020
  }
@@ -1894,7 +2051,7 @@ function renderPromptList(prompts, format = "pretty") {
1894
2051
  if (format === "json") {
1895
2052
  console.log(JSON.stringify(prompts, null, 2));
1896
2053
  } else if (format === "yaml") {
1897
- console.log(yamlDump4(prompts));
2054
+ console.log(yamlDump3(prompts));
1898
2055
  }
1899
2056
  return;
1900
2057
  }
@@ -1917,7 +2074,7 @@ function renderPromptDetail(p, format = "pretty") {
1917
2074
  if (format === "json") {
1918
2075
  console.log(JSON.stringify(p, null, 2));
1919
2076
  } else if (format === "yaml") {
1920
- console.log(yamlDump4(p));
2077
+ console.log(yamlDump3(p));
1921
2078
  }
1922
2079
  return;
1923
2080
  }
@@ -1937,7 +2094,7 @@ function renderPropertyNames(names, format = "pretty") {
1937
2094
  if (format === "json") {
1938
2095
  console.log(JSON.stringify(names, null, 2));
1939
2096
  } else if (format === "yaml") {
1940
- console.log(yamlDump4(names));
2097
+ console.log(yamlDump3(names));
1941
2098
  } else {
1942
2099
  const rows = names.map((n) => ({ name: n }));
1943
2100
  console.log(formatOutput(rows, [{ key: "name", label: "Name" }], format));
@@ -1992,7 +2149,7 @@ function renderPropertyValues(payload, format = "pretty") {
1992
2149
  if (format === "json") {
1993
2150
  console.log(JSON.stringify(payload, null, 2));
1994
2151
  } else if (format === "yaml") {
1995
- console.log(yamlDump4(payload));
2152
+ console.log(yamlDump3(payload));
1996
2153
  }
1997
2154
  return;
1998
2155
  }
@@ -2023,7 +2180,7 @@ function renderInstanceDetail(inst, format = "pretty") {
2023
2180
  if (format === "json") {
2024
2181
  console.log(JSON.stringify(inst, null, 2));
2025
2182
  } else if (format === "yaml") {
2026
- console.log(yamlDump4(inst));
2183
+ console.log(yamlDump3(inst));
2027
2184
  }
2028
2185
  return;
2029
2186
  }
@@ -2041,7 +2198,7 @@ function renderRegistryCredentials(creds, format = "pretty") {
2041
2198
  if (format === "json") {
2042
2199
  console.log(JSON.stringify(creds, null, 2));
2043
2200
  } else if (format === "yaml") {
2044
- console.log(yamlDump4(creds));
2201
+ console.log(yamlDump3(creds));
2045
2202
  }
2046
2203
  return;
2047
2204
  }
@@ -2103,7 +2260,7 @@ function renderChannelList(channels, format = "pretty") {
2103
2260
  }
2104
2261
  function renderChannelDetail(channel, format = "pretty") {
2105
2262
  if (format !== "pretty") {
2106
- console.log(format === "json" ? JSON.stringify(channel, null, 2) : yamlDump4(channel));
2263
+ console.log(format === "json" ? JSON.stringify(channel, null, 2) : yamlDump3(channel));
2107
2264
  return;
2108
2265
  }
2109
2266
  ui.section("Channel Detail:");
@@ -2129,7 +2286,7 @@ function renderChannelDetail(channel, format = "pretty") {
2129
2286
  }
2130
2287
  function renderChannelStats(stats, format = "pretty") {
2131
2288
  if (format !== "pretty") {
2132
- console.log(format === "json" ? JSON.stringify(stats, null, 2) : yamlDump4(stats));
2289
+ console.log(format === "json" ? JSON.stringify(stats, null, 2) : yamlDump3(stats));
2133
2290
  return;
2134
2291
  }
2135
2292
  ui.section("Network Broker Stats:");
@@ -2147,7 +2304,7 @@ function renderChannelStats(stats, format = "pretty") {
2147
2304
  function renderLanguages(data, format = "pretty") {
2148
2305
  if (format !== "pretty") {
2149
2306
  if (format === "json" || format === "yaml") {
2150
- console.log(format === "json" ? JSON.stringify(data, null, 2) : yamlDump4(data));
2307
+ console.log(format === "json" ? JSON.stringify(data, null, 2) : yamlDump3(data));
2151
2308
  return;
2152
2309
  }
2153
2310
  console.log(
@@ -2256,7 +2413,7 @@ function renderAdapterList(adapters, format = "pretty", totalItems) {
2256
2413
  }
2257
2414
  function renderAdapterDetail(adapter, format = "pretty") {
2258
2415
  if (format !== "pretty") {
2259
- console.log(format === "json" ? JSON.stringify(adapter, null, 2) : yamlDump4(adapter));
2416
+ console.log(format === "json" ? JSON.stringify(adapter, null, 2) : yamlDump3(adapter));
2260
2417
  return;
2261
2418
  }
2262
2419
  ui.section("Adapter Detail:");
@@ -2289,7 +2446,7 @@ function renderAdapterDetail(adapter, format = "pretty") {
2289
2446
  }
2290
2447
  function renderAdapterValidation(result, format = "pretty") {
2291
2448
  if (format !== "pretty") {
2292
- console.log(format === "json" ? JSON.stringify(result, null, 2) : yamlDump4(result));
2449
+ console.log(format === "json" ? JSON.stringify(result, null, 2) : yamlDump3(result));
2293
2450
  return;
2294
2451
  }
2295
2452
  if (result.validated) {
@@ -2980,9 +3137,9 @@ function registerAiGatewayCommand(program) {
2980
3137
  }
2981
3138
  });
2982
3139
  const telemetry = aigateway.command("telemetry").description("AI Gateway runtime telemetry (data plane)");
2983
- telemetry.command("cost").description(
3140
+ const cost = telemetry.command("cost").description(
2984
3141
  "Total and per-day spend for a workspace (API reports cents; pretty output shows dollars)"
2985
- ).requiredOption("--workspace <slug>", "Workspace slug (not UUID), e.g. ws-main-a-349e0e").option("--days <n>", "Rolling window in days, counted back from now", "7").option("--output <format>", "Output format: pretty, json, yaml", "pretty").addHelpText(
3142
+ ).requiredOption("--workspace <slug>", "Workspace slug (not UUID), e.g. ws-main-a-349e0e").option("--days <n>", "Rolling window in days, counted back from now", "7").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").addHelpText(
2986
3143
  "after",
2987
3144
  examples(
2988
3145
  "airs aigateway telemetry cost --workspace ws-main-a-349e0e",
@@ -2990,7 +3147,7 @@ function registerAiGatewayCommand(program) {
2990
3147
  )
2991
3148
  ).action(async (opts) => {
2992
3149
  try {
2993
- const fmt = opts.output;
3150
+ const fmt = await resolveOutput(cost, opts);
2994
3151
  if (fmt === "pretty") renderAiGatewayHeader();
2995
3152
  const days = Number.parseInt(opts.days, 10);
2996
3153
  if (!Number.isFinite(days) || days <= 0) {
@@ -3194,13 +3351,6 @@ function assertKnownKey(key) {
3194
3351
  usageError(`Unknown config key '${key}'. Valid keys: ${CONFIG_KEYS.join(", ")}`);
3195
3352
  }
3196
3353
  }
3197
- var LIST_FORMATS = ["pretty", "json", "yaml"];
3198
- function parseListFormat(value) {
3199
- if (!LIST_FORMATS.includes(value)) {
3200
- usageError(`Invalid --output '${value}'. Valid formats: ${LIST_FORMATS.join(", ")}`);
3201
- }
3202
- return value;
3203
- }
3204
3354
  var COLUMNS = [
3205
3355
  { key: "key", label: "Key" },
3206
3356
  { key: "value", label: "Value" },
@@ -3215,9 +3365,9 @@ function registerConfigCommand(program) {
3215
3365
  "airs config get mgmtTsgId"
3216
3366
  )
3217
3367
  );
3218
- config.command("list").description("Show effective configuration with per-key source (env/file/default)").option("--output <format>", "Output format: pretty, json, or yaml", "pretty").option("--reveal", "Show secret values in full").action(async (opts) => {
3368
+ const configList = config.command("list").description("Show effective configuration with per-key source (env/file/default)").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").option("--reveal", "Show secret values in full").action(async (opts) => {
3219
3369
  try {
3220
- const fmt = parseListFormat(opts.output);
3370
+ const fmt = await resolveOutput(configList, opts);
3221
3371
  const filePath = resolveConfigFilePath();
3222
3372
  const rows = buildConfigRows(await inspectConfig(), Boolean(opts.reveal));
3223
3373
  if (fmt === "pretty") {
@@ -3232,12 +3382,18 @@ function registerConfigCommand(program) {
3232
3382
  fail(err);
3233
3383
  }
3234
3384
  });
3235
- config.command("get <key>").description("Print a single effective config value").option("--reveal", "Show the real value of a secret key").action(async (key, opts) => {
3385
+ const configGet = config.command("get <key>").description("Print a single effective config value").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").option("--reveal", "Show the real value of a secret key").action(async (key, opts) => {
3236
3386
  try {
3237
3387
  assertKnownKey(key);
3238
3388
  const inspected = await inspectConfig();
3239
3389
  const entry = inspected[key];
3240
3390
  const raw = entry.value == null ? "" : String(entry.value);
3391
+ const fmt = await resolveOutput(configGet, opts);
3392
+ const value = raw !== "" && isSecretKey(key) && !opts.reveal ? maskSecret(raw) : raw;
3393
+ if (fmt !== "pretty") {
3394
+ console.log(formatOutput([{ key, value, source: entry.source }], COLUMNS, fmt));
3395
+ return;
3396
+ }
3241
3397
  if (raw !== "" && isSecretKey(key)) {
3242
3398
  if (opts.reveal) {
3243
3399
  ui.status(`Warning: printing secret value for '${key}'`);
@@ -3590,20 +3746,6 @@ var STATUS_KIND = {
3590
3746
  warn: "warn",
3591
3747
  fail: "error"
3592
3748
  };
3593
- var DOCTOR_FORMATS = ["pretty", "json", "yaml"];
3594
- function parseDoctorFormat(value) {
3595
- if (!DOCTOR_FORMATS.includes(value)) {
3596
- usageError(`Invalid --output '${value}'. Valid formats: ${DOCTOR_FORMATS.join(", ")}`);
3597
- }
3598
- return value;
3599
- }
3600
- function toYaml(checks) {
3601
- return checks.map((c) => {
3602
- const lines = [`name: ${c.name}`, `status: ${c.status}`, `detail: ${c.detail}`];
3603
- if (c.hint) lines.push(`hint: ${c.hint}`);
3604
- return lines.join("\n");
3605
- }).join("\n---\n");
3606
- }
3607
3749
  function renderPretty(checks) {
3608
3750
  ui.header("Doctor", "Prisma AIRS CLI preflight checks");
3609
3751
  for (const check of checks) {
@@ -3623,18 +3765,27 @@ function renderPretty(checks) {
3623
3765
  console.log("");
3624
3766
  }
3625
3767
  function registerDoctorCommand(program) {
3626
- program.command("doctor").description("Check credentials, config, and API connectivity (preflight)").option("--output <format>", "Output format: pretty, json, or yaml", "pretty").addHelpText(
3768
+ const doctor = program.command("doctor").description("Check credentials, config, and API connectivity (preflight)").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").addHelpText(
3627
3769
  "after",
3628
3770
  examples("airs doctor", `airs doctor --output json | jq '.[] | select(.status != "pass")'`)
3629
3771
  ).action(async (opts) => {
3630
- const fmt = parseDoctorFormat(opts.output);
3772
+ const fmt = await resolveOutput(doctor, opts);
3631
3773
  const checks = await runDoctor();
3632
- if (fmt === "json") {
3633
- console.log(JSON.stringify(checks, null, 2));
3634
- } else if (fmt === "yaml") {
3635
- console.log(toYaml(checks));
3636
- } else {
3774
+ if (fmt === "pretty") {
3637
3775
  renderPretty(checks);
3776
+ } else {
3777
+ console.log(
3778
+ formatOutput(
3779
+ checks.map((check) => ({ ...check })),
3780
+ [
3781
+ { key: "name", label: "Name" },
3782
+ { key: "status", label: "Status" },
3783
+ { key: "detail", label: "Detail" },
3784
+ { key: "hint", label: "Hint" }
3785
+ ],
3786
+ fmt
3787
+ )
3788
+ );
3638
3789
  }
3639
3790
  process.exit(hasFailure(checks) ? 1 : 0);
3640
3791
  });
@@ -3674,15 +3825,17 @@ function registerModelSecurityCommand(program) {
3674
3825
  const fmt = opts.output;
3675
3826
  if (fmt === "pretty") renderModelSecurityHeader();
3676
3827
  const service = await createService2();
3677
- const result = await service.listGroups({
3828
+ const listOptions = {
3678
3829
  sourceTypes: opts.sourceTypes ? opts.sourceTypes.split(",").map((s) => s.trim()) : void 0,
3679
3830
  searchQuery: opts.search,
3680
3831
  sortField: opts.sortField,
3681
3832
  sortDir: opts.sortDir,
3682
3833
  enabledRules: opts.enabledRules ? opts.enabledRules.split(",").map((s) => s.trim()) : void 0,
3683
- limit: Number.parseInt(opts.limit, 10)
3684
- });
3685
- renderGroupList(result.groups, fmt);
3834
+ limit: Number.parseInt(opts.limit, 10),
3835
+ skip: Number(opts.offset ?? 0)
3836
+ };
3837
+ const rows = opts.all ? await service.listAllGroups({ ...listOptions, max: Number(opts.max) }) : (await service.listGroups(listOptions)).groups;
3838
+ renderGroupList(rows, fmt);
3686
3839
  } catch (err) {
3687
3840
  fail(err);
3688
3841
  }
@@ -3877,24 +4030,26 @@ function registerModelSecurityCommand(program) {
3877
4030
  const ruleInstances = ms.command("rule-instances").description("Manage rule instances in groups");
3878
4031
  ruleInstances.command("list <groupUuid>").description("List rule instances in a security group").option("--security-rule-uuid <uuid>", "Filter by security rule UUID").option("--state <state>", "Filter by state (DISABLED, ALLOWING, BLOCKING)").option("--limit <n>", "Max results", "20").action(async (groupUuid, opts) => {
3879
4032
  try {
3880
- renderModelSecurityHeader();
4033
+ const fmt = opts.output;
4034
+ if (fmt === "pretty") renderModelSecurityHeader();
3881
4035
  const service = await createService2();
3882
4036
  const result = await service.listRuleInstances(groupUuid, {
3883
4037
  securityRuleUuid: opts.securityRuleUuid,
3884
4038
  state: opts.state,
3885
4039
  limit: Number.parseInt(opts.limit, 10)
3886
4040
  });
3887
- renderRuleInstanceList(result.ruleInstances);
4041
+ renderRuleInstanceList(result.ruleInstances, fmt);
3888
4042
  } catch (err) {
3889
4043
  fail(err);
3890
4044
  }
3891
4045
  });
3892
- ruleInstances.command("get <groupUuid> <instanceUuid>").description("Get rule instance details").action(async (groupUuid, instanceUuid) => {
4046
+ ruleInstances.command("get <groupUuid> <instanceUuid>").description("Get rule instance details").action(async (groupUuid, instanceUuid, opts) => {
3893
4047
  try {
3894
- renderModelSecurityHeader();
4048
+ const fmt = opts.output;
4049
+ if (fmt === "pretty") renderModelSecurityHeader();
3895
4050
  const service = await createService2();
3896
4051
  const instance = await service.getRuleInstance(groupUuid, instanceUuid);
3897
- renderRuleInstanceDetail(instance);
4052
+ renderRuleInstanceDetail(instance, fmt);
3898
4053
  } catch (err) {
3899
4054
  fail(err);
3900
4055
  }
@@ -3920,22 +4075,25 @@ function registerModelSecurityCommand(program) {
3920
4075
  const fmt = opts.output;
3921
4076
  if (fmt === "pretty") renderModelSecurityHeader();
3922
4077
  const service = await createService2();
3923
- const result = await service.listRules({
4078
+ const listOptions = {
3924
4079
  sourceType: opts.sourceType,
3925
4080
  searchQuery: opts.search,
3926
- limit: Number.parseInt(opts.limit, 10)
3927
- });
3928
- renderRuleList(result.rules, fmt);
4081
+ limit: Number.parseInt(opts.limit, 10),
4082
+ skip: Number(opts.offset ?? 0)
4083
+ };
4084
+ const rows = opts.all ? await service.listAllRules({ ...listOptions, max: Number(opts.max) }) : (await service.listRules(listOptions)).rules;
4085
+ renderRuleList(rows, fmt);
3929
4086
  } catch (err) {
3930
4087
  fail(err);
3931
4088
  }
3932
4089
  });
3933
- rules.command("get <uuid>").description("Get security rule details").action(async (uuid) => {
4090
+ rules.command("get <uuid>").description("Get security rule details").action(async (uuid, opts) => {
3934
4091
  try {
3935
- renderModelSecurityHeader();
4092
+ const fmt = opts.output;
4093
+ if (fmt === "pretty") renderModelSecurityHeader();
3936
4094
  const service = await createService2();
3937
4095
  const rule = await service.getRule(uuid);
3938
- renderRuleDetail(rule);
4096
+ renderRuleDetail(rule, fmt);
3939
4097
  } catch (err) {
3940
4098
  fail(err);
3941
4099
  }
@@ -3953,24 +4111,27 @@ function registerModelSecurityCommand(program) {
3953
4111
  const fmt = opts.output;
3954
4112
  if (fmt === "pretty") renderModelSecurityHeader();
3955
4113
  const service = await createService2();
3956
- const result = await service.listScans({
4114
+ const listOptions = {
3957
4115
  evalOutcome: opts.evalOutcome,
3958
4116
  sourceType: opts.sourceType,
3959
4117
  scanOrigin: opts.scanOrigin,
3960
4118
  search: opts.search,
3961
- limit: Number.parseInt(opts.limit, 10)
3962
- });
3963
- renderMsScanList(result.scans, fmt);
4119
+ limit: Number.parseInt(opts.limit, 10),
4120
+ skip: Number(opts.offset ?? 0)
4121
+ };
4122
+ const rows = opts.all ? await service.listAllScans({ ...listOptions, max: Number(opts.max) }) : (await service.listScans(listOptions)).scans;
4123
+ renderMsScanList(rows, fmt);
3964
4124
  } catch (err) {
3965
4125
  fail(err);
3966
4126
  }
3967
4127
  });
3968
- scans.command("get <uuid>").description("Get scan details").action(async (uuid) => {
4128
+ scans.command("get <uuid>").description("Get scan details").action(async (uuid, opts) => {
3969
4129
  try {
3970
- renderModelSecurityHeader();
4130
+ const fmt = opts.output;
4131
+ if (fmt === "pretty") renderModelSecurityHeader();
3971
4132
  const service = await createService2();
3972
4133
  const scan = await service.getScan(uuid);
3973
- renderMsScanDetail(scan);
4134
+ renderMsScanDetail(scan, fmt);
3974
4135
  } catch (err) {
3975
4136
  fail(err);
3976
4137
  }
@@ -4051,15 +4212,16 @@ function registerModelSecurityCommand(program) {
4051
4212
  const fmt = opts.output;
4052
4213
  if (fmt === "pretty") renderModelSecurityHeader();
4053
4214
  const service = await createService2();
4054
- const result = await service.listModels({
4215
+ const listOptions = {
4055
4216
  search: opts.search,
4056
4217
  searchQuery: opts.searchQuery,
4057
4218
  sortField: opts.sortField,
4058
4219
  sortOrder: opts.sortOrder,
4059
4220
  limit: opts.limit ? Number.parseInt(opts.limit, 10) : void 0,
4060
4221
  skip: opts.offset ? Number.parseInt(opts.offset, 10) : void 0
4061
- });
4062
- renderModelList(result.models, fmt);
4222
+ };
4223
+ const rows = opts.all ? await service.listAllModels({ ...listOptions, max: Number(opts.max) }) : (await service.listModels(listOptions)).models;
4224
+ renderModelList(rows, fmt);
4063
4225
  } catch (err) {
4064
4226
  fail(err);
4065
4227
  }
@@ -4352,8 +4514,12 @@ function parseAttackGoals(input) {
4352
4514
  return parsed;
4353
4515
  }
4354
4516
  function sliceClientSide(items, opts) {
4355
- const offset = opts.offset !== void 0 ? Number.parseInt(opts.offset, 10) : 0;
4356
- const limit = opts.limit !== void 0 ? Number.parseInt(opts.limit, 10) : void 0;
4517
+ if (opts.all) {
4518
+ const max = opts.max === void 0 ? 1e4 : Number(opts.max);
4519
+ return max === 0 ? items : items.slice(0, max);
4520
+ }
4521
+ const offset = opts.offset !== void 0 ? Number.parseInt(String(opts.offset), 10) : 0;
4522
+ const limit = opts.limit !== void 0 ? Number.parseInt(String(opts.limit), 10) : void 0;
4357
4523
  return items.slice(offset, limit === void 0 ? void 0 : offset + limit);
4358
4524
  }
4359
4525
  function parsePositiveInt(input, flag) {
@@ -4634,12 +4800,14 @@ function registerRedteamCommand(program) {
4634
4800
  const fmt = opts.output;
4635
4801
  if (fmt === "pretty") renderRedteamHeader();
4636
4802
  const service = await createService3();
4637
- const scans = await service.listScans({
4803
+ const listOptions = {
4638
4804
  status: opts.status,
4639
4805
  jobType: opts.type,
4640
4806
  targetId: opts.target,
4641
- limit: Number.parseInt(opts.limit, 10)
4642
- });
4807
+ limit: Number.parseInt(opts.limit, 10),
4808
+ offset: Number(opts.offset ?? 0)
4809
+ };
4810
+ const scans = opts.all ? await service.listAllScans({ ...listOptions, max: Number(opts.max) }) : await service.listScans(listOptions);
4643
4811
  renderScanList(scans, fmt);
4644
4812
  } catch (err) {
4645
4813
  fail(err);
@@ -5142,12 +5310,18 @@ function registerRedteamCommand(program) {
5142
5310
  fail(err);
5143
5311
  }
5144
5312
  });
5145
- const targetsBackup = targets.command("backup").description("Backup red team targets to local JSON/YAML files").option("--output-dir <path>", "Output directory").option("--output <format>", "Output format: json or yaml", "json").option("--name <targetName>", "Backup a single target by name");
5313
+ const targetsBackup = targets.command("backup").description("Backup red team targets to local JSON/YAML files").option("--output-dir <path>", "Output directory").option("--file-format <format>", "Backup file format: json or yaml", "json").option("--name <targetName>", "Backup a single target by name");
5314
+ registerDeprecatedAlias(targetsBackup, {
5315
+ oldFlag: "--output <format>",
5316
+ oldKey: "output",
5317
+ canonicalFlag: "--file-format",
5318
+ canonicalKey: "fileFormat"
5319
+ });
5146
5320
  registerDeprecatedAlias(targetsBackup, {
5147
5321
  oldFlag: "--format <format>",
5148
5322
  oldKey: "format",
5149
- canonicalFlag: "--output",
5150
- canonicalKey: "output"
5323
+ canonicalFlag: "--file-format",
5324
+ canonicalKey: "fileFormat"
5151
5325
  });
5152
5326
  targetsBackup.action(async (opts) => {
5153
5327
  resolveDeprecatedAliases(targetsBackup, opts);
@@ -5156,7 +5330,7 @@ function registerRedteamCommand(program) {
5156
5330
  const outputDir = resolveOutputDir(opts.outputDir, "targets");
5157
5331
  const results = await backupTargets({
5158
5332
  outputDir,
5159
- format: opts.output ?? "json",
5333
+ format: opts.fileFormat ?? "json",
5160
5334
  name: opts.name
5161
5335
  });
5162
5336
  renderBackupSummary(results, outputDir);
@@ -5221,11 +5395,13 @@ function registerRedteamCommand(program) {
5221
5395
  const fmt = opts.output;
5222
5396
  if (fmt === "pretty") renderRedteamHeader();
5223
5397
  const service = await createService3();
5224
- const { adapters, totalItems } = await service.listAdapters({
5398
+ const listOptions = {
5225
5399
  limit: opts.limit ? parsePositiveInt(opts.limit, "--limit") : void 0,
5226
5400
  offset: opts.offset ? Number.parseInt(opts.offset, 10) : void 0,
5227
5401
  search: opts.search
5228
- });
5402
+ };
5403
+ const result = opts.all ? { adapters: await service.listAllAdapters({ ...listOptions, max: Number(opts.max) }) } : await service.listAdapters(listOptions);
5404
+ const { adapters, totalItems } = result;
5229
5405
  renderAdapterList(adapters, fmt, totalItems);
5230
5406
  } catch (err) {
5231
5407
  fail(err);
@@ -5367,12 +5543,13 @@ function registerRedteamCommand(program) {
5367
5543
  const fmt = opts.output;
5368
5544
  if (fmt === "pretty") renderRedteamHeader();
5369
5545
  const service = await createService3();
5370
- const { channels: list } = await service.listChannels({
5546
+ const listOptions = {
5371
5547
  limit: opts.limit ? parsePositiveInt(opts.limit, "--limit") : void 0,
5372
5548
  offset: opts.offset ? Number.parseInt(opts.offset, 10) : void 0,
5373
5549
  search: opts.search,
5374
5550
  status: opts.status
5375
- });
5551
+ };
5552
+ const list = opts.all ? await service.listAllChannels({ ...listOptions, max: Number(opts.max) }) : (await service.listChannels(listOptions)).channels;
5376
5553
  renderChannelList(list, fmt);
5377
5554
  } catch (err) {
5378
5555
  fail(err);
@@ -5914,6 +6091,31 @@ async function loadBulkScanState(filePath) {
5914
6091
 
5915
6092
  // src/cli/pagination.ts
5916
6093
  var DEFAULT_PAGE_SIZE = 50;
6094
+ var DEFAULT_OFFSET_LIMIT = 100;
6095
+ var DEFAULT_MAX_ITEMS = 1e4;
6096
+ function registerListFlags(command, options) {
6097
+ const defaultLimit = options.dialect === "offset" ? DEFAULT_OFFSET_LIMIT : DEFAULT_PAGE_SIZE;
6098
+ return command.option("--limit <n>", `Items per page (default: ${defaultLimit})`, Number, defaultLimit).option("--offset <n>", "Item offset (default: 0)", Number, 0).option("--all", "Walk all pages").option("--max <n>", "Maximum items with --all; 0 removes the cap", Number, DEFAULT_MAX_ITEMS);
6099
+ }
6100
+ function integerFlag(name, value, minimum) {
6101
+ const parsed = Number(value);
6102
+ if (!Number.isSafeInteger(parsed) || parsed < minimum) {
6103
+ const qualifier = minimum === 1 ? "a positive integer" : "a non-negative integer";
6104
+ throw new CliUsageError(`${name} must be ${qualifier}`);
6105
+ }
6106
+ return parsed;
6107
+ }
6108
+ function resolveListParams(command, opts, options) {
6109
+ const defaultLimit = options.dialect === "offset" ? DEFAULT_OFFSET_LIMIT : DEFAULT_PAGE_SIZE;
6110
+ const limit = integerFlag("--limit", opts.limit ?? defaultLimit, 1);
6111
+ const offset = integerFlag("--offset", opts.offset ?? 0, 0);
6112
+ const max = integerFlag("--max", opts.max ?? DEFAULT_MAX_ITEMS, 0);
6113
+ const all = Boolean(opts.all);
6114
+ if (all && command.getOptionValueSource?.("offset") === "cli") {
6115
+ throw new CliUsageError("--all cannot be combined with --offset");
6116
+ }
6117
+ return { limit, offset, all, max };
6118
+ }
5917
6119
  function registerPageAliases(cmd, opts) {
5918
6120
  registerDeprecatedAlias(cmd, {
5919
6121
  oldFlag: `${opts.sizeFlag} <n>`,
@@ -6035,6 +6237,71 @@ function parseQuotedField(content, start, len) {
6035
6237
  return { value, nextIndex: i };
6036
6238
  }
6037
6239
 
6240
+ // src/cli/renderer/views/runtime.ts
6241
+ var profilesView = {
6242
+ name: "profiles",
6243
+ columns: [
6244
+ { key: "profileId", label: "ID" },
6245
+ { key: "profileName", label: "Name" },
6246
+ { key: "active", label: "Active" },
6247
+ { key: "revision", label: "Revision" }
6248
+ ],
6249
+ pretty: {
6250
+ list: (items) => renderProfileList(items, "pretty"),
6251
+ detail: renderProfileDetail
6252
+ }
6253
+ };
6254
+ var apiKeysView = {
6255
+ name: "API keys",
6256
+ columns: [
6257
+ { key: "id", label: "ID" },
6258
+ { key: "name", label: "Name" },
6259
+ { key: "last8", label: "Last 8" },
6260
+ { key: "expiresAt", label: "Expires" }
6261
+ ],
6262
+ pretty: {
6263
+ list: (items) => renderApiKeyList(items, "pretty"),
6264
+ detail: renderApiKeyDetail
6265
+ }
6266
+ };
6267
+ var customerAppsView = {
6268
+ name: "customer apps",
6269
+ columns: [
6270
+ { key: "id", label: "ID" },
6271
+ { key: "name", label: "Name" },
6272
+ { key: "description", label: "Description" }
6273
+ ],
6274
+ pretty: {
6275
+ list: (items) => renderCustomerAppList(items, "pretty"),
6276
+ detail: renderCustomerAppDetail
6277
+ }
6278
+ };
6279
+ var topicsView = {
6280
+ name: "topics",
6281
+ columns: [
6282
+ { key: "topic_id", label: "ID" },
6283
+ { key: "topic_name", label: "Name" },
6284
+ { key: "revision", label: "Revision" },
6285
+ { key: "description", label: "Description" }
6286
+ ],
6287
+ structured: (topic) => ({
6288
+ topicId: topic.topic_id,
6289
+ topicName: topic.topic_name,
6290
+ revision: topic.revision,
6291
+ active: topic.active,
6292
+ description: topic.description,
6293
+ examples: topic.examples,
6294
+ createdBy: topic.created_by,
6295
+ updatedBy: topic.updated_by,
6296
+ lastModifiedTs: topic.last_modified_ts,
6297
+ createdTs: topic.created_ts
6298
+ }),
6299
+ pretty: {
6300
+ list: (items) => renderTopicList(items, "pretty"),
6301
+ detail: renderTopicDetail
6302
+ }
6303
+ };
6304
+
6038
6305
  // src/cli/commands/dlp/dictionaries.ts
6039
6306
  import { readFile as readFile6 } from "fs/promises";
6040
6307
  import { basename as basename2 } from "path";
@@ -6048,6 +6315,9 @@ var SdkDictionariesService = class {
6048
6315
  async list(params) {
6049
6316
  return this.client.list(params);
6050
6317
  }
6318
+ async listAll(params) {
6319
+ return this.client.listAll(params);
6320
+ }
6051
6321
  async create(params) {
6052
6322
  return this.client.create(params);
6053
6323
  }
@@ -6155,20 +6425,22 @@ function register(dlp) {
6155
6425
  "--offset <n>",
6156
6426
  "Starting offset \u2014 rounds down to a page boundary",
6157
6427
  (v) => Number.parseInt(v, 10)
6158
- ).option("--sort <field,dir>", "(repeatable)", (v, p = []) => [...p, v]).option("--keywords", "Include keyword list in response").option("--include-keywords", "Alias for --keywords").option("--output <fmt>", "Output format", "pretty");
6428
+ ).option("--sort <field,dir>", "(repeatable)", (v, p = []) => [...p, v]).option("--keywords", "Include keyword list in response").option("--include-keywords", "Alias for --keywords").option("--output <fmt>", "Output format: pretty, table, markdown, csv, json, yaml");
6159
6429
  registerPageAliases(listCmd, { sizeFlag: "--size", sizeKey: "size" });
6160
6430
  listCmd.action(async (opts) => {
6161
6431
  try {
6162
6432
  const { page, size } = resolvePageParams(listCmd, opts);
6163
6433
  const includeKeywords = opts.keywords || opts.includeKeywords;
6434
+ const svc = new SdkDictionariesService();
6435
+ const params = {
6436
+ size,
6437
+ sort: opts.sort,
6438
+ keywords: includeKeywords ? true : void 0
6439
+ };
6440
+ const all = opts.all ? await svc.listAll({ ...params, max: Number(opts.max) }) : void 0;
6164
6441
  dlpDictionaries.renderList(
6165
- await new SdkDictionariesService().list({
6166
- page,
6167
- size,
6168
- sort: opts.sort,
6169
- keywords: includeKeywords ? true : void 0
6170
- }),
6171
- opts.output
6442
+ all ? { content: all, totalElements: all.length } : await svc.list({ ...params, page }),
6443
+ await resolveOutput(listCmd, opts)
6172
6444
  );
6173
6445
  } catch (err) {
6174
6446
  fail(err);
@@ -6189,12 +6461,12 @@ function register(dlp) {
6189
6461
  usageError(err instanceof Error ? err.message : String(err));
6190
6462
  }
6191
6463
  });
6192
- group.command("get <id>").option("--keywords", "").option("--include-keywords", "Alias for --keywords").option("--output <fmt>", "Output format", "pretty").action(async (id, opts) => {
6464
+ const getCmd = group.command("get <id>").option("--keywords", "").option("--include-keywords", "Alias for --keywords").option("--output <fmt>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (id, opts) => {
6193
6465
  try {
6194
6466
  const includeKeywords = opts.keywords || opts.includeKeywords;
6195
6467
  dlpDictionaries.renderGet(
6196
6468
  await new SdkDictionariesService().get(id, { includeKeywords }),
6197
- opts.output
6469
+ await resolveOutput(getCmd, opts)
6198
6470
  );
6199
6471
  } catch (err) {
6200
6472
  fail(err);
@@ -6255,6 +6527,9 @@ var SdkDataFilteringProfilesService = class {
6255
6527
  async list(params) {
6256
6528
  return this.client.list(params);
6257
6529
  }
6530
+ async listAll(params) {
6531
+ return this.client.listAll(params);
6532
+ }
6258
6533
  async get(id) {
6259
6534
  return this.client.get(id);
6260
6535
  }
@@ -6388,7 +6663,7 @@ function listFlags(cmd) {
6388
6663
  "--offset <n>",
6389
6664
  "Starting offset \u2014 rounds down to a page boundary",
6390
6665
  (v) => Number.parseInt(v, 10)
6391
- ).option("--sort <field,dir>", "Sort criteria (repeatable)", repeatable).option("--output <fmt>", "Output format", "pretty");
6666
+ ).option("--sort <field,dir>", "Sort criteria (repeatable)", repeatable).option("--output <fmt>", "Output format: pretty, table, markdown, csv, json, yaml");
6392
6667
  registerPageAliases(cmd, { sizeFlag: "--size", sizeKey: "size" });
6393
6668
  return cmd;
6394
6669
  }
@@ -6409,16 +6684,17 @@ function register2(dlp) {
6409
6684
  try {
6410
6685
  const { page, size } = resolvePageParams(listCmd, opts);
6411
6686
  const svc = new SdkDataFilteringProfilesService();
6412
- const r = await svc.list({ page, size, sort: opts.sort });
6413
- dlpFilteringProfiles.renderList(r, opts.output);
6687
+ const all = opts.all ? await svc.listAll({ size, sort: opts.sort, max: Number(opts.max) }) : void 0;
6688
+ const r = all ? { content: all, totalElements: all.length } : await svc.list({ page, size, sort: opts.sort });
6689
+ dlpFilteringProfiles.renderList(r, await resolveOutput(listCmd, opts));
6414
6690
  } catch (err) {
6415
6691
  fail(err);
6416
6692
  }
6417
6693
  });
6418
- group.command("get <id>").description("Get a filtering profile by id").option("--output <fmt>", "Output format", "pretty").action(async (id, opts) => {
6694
+ const getCmd = group.command("get <id>").description("Get a filtering profile by id").option("--output <fmt>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (id, opts) => {
6419
6695
  try {
6420
6696
  const svc = new SdkDataFilteringProfilesService();
6421
- dlpFilteringProfiles.renderGet(await svc.get(id), opts.output);
6697
+ dlpFilteringProfiles.renderGet(await svc.get(id), await resolveOutput(getCmd, opts));
6422
6698
  } catch (err) {
6423
6699
  fail(err);
6424
6700
  }
@@ -6514,6 +6790,9 @@ var SdkDataPatternsService = class {
6514
6790
  async list(params) {
6515
6791
  return this.client.list(params);
6516
6792
  }
6793
+ async listAll(params) {
6794
+ return this.client.listAll(params);
6795
+ }
6517
6796
  async create(body) {
6518
6797
  return this.client.create(body);
6519
6798
  }
@@ -6537,7 +6816,7 @@ function listFlags2(cmd) {
6537
6816
  "--offset <n>",
6538
6817
  "Starting offset \u2014 rounds down to a page boundary",
6539
6818
  (v) => Number.parseInt(v, 10)
6540
- ).option("--sort <field,dir>", "Sort criteria (repeatable)", repeatable).option("--output <fmt>", "Output format", "pretty");
6819
+ ).option("--sort <field,dir>", "Sort criteria (repeatable)", repeatable).option("--output <fmt>", "Output format: pretty, table, markdown, csv, json, yaml");
6541
6820
  registerPageAliases(cmd, { sizeFlag: "--size", sizeKey: "size" });
6542
6821
  return cmd;
6543
6822
  }
@@ -6559,9 +6838,10 @@ function register4(dlp) {
6559
6838
  try {
6560
6839
  const { page, size } = resolvePageParams(listCmd, opts);
6561
6840
  const svc = new SdkDataPatternsService();
6841
+ const result = opts.all ? await svc.listAll({ size, sort: opts.sort, max: Number(opts.max) }) : void 0;
6562
6842
  dlpPatterns.renderList(
6563
- await svc.list({ page, size, sort: opts.sort }),
6564
- opts.output
6843
+ result ? { content: result, totalElements: result.length } : await svc.list({ page, size, sort: opts.sort }),
6844
+ await resolveOutput(listCmd, opts)
6565
6845
  );
6566
6846
  } catch (err) {
6567
6847
  fail(err);
@@ -6579,11 +6859,11 @@ function register4(dlp) {
6579
6859
  usageError(err instanceof Error ? err.message : String(err));
6580
6860
  }
6581
6861
  });
6582
- group.command("get <id>").description("Get a data pattern by id").option("--output <fmt>", "Output format", "pretty").action(async (id, opts) => {
6862
+ const getCmd = group.command("get <id>").description("Get a data pattern by id").option("--output <fmt>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (id, opts) => {
6583
6863
  try {
6584
6864
  dlpPatterns.renderGet(
6585
6865
  await new SdkDataPatternsService().get(id),
6586
- opts.output
6866
+ await resolveOutput(getCmd, opts)
6587
6867
  );
6588
6868
  } catch (err) {
6589
6869
  fail(err);
@@ -6639,6 +6919,9 @@ var SdkDataProfilesService = class {
6639
6919
  async list(params) {
6640
6920
  return this.client.list(params);
6641
6921
  }
6922
+ async listAll(params) {
6923
+ return this.client.listAll(params);
6924
+ }
6642
6925
  async create(body) {
6643
6926
  return this.client.create(body);
6644
6927
  }
@@ -6659,7 +6942,7 @@ function listFlags3(cmd) {
6659
6942
  "--offset <n>",
6660
6943
  "Starting offset \u2014 rounds down to a page boundary",
6661
6944
  (v) => Number.parseInt(v, 10)
6662
- ).option("--sort <field,dir>", "Sort criteria (repeatable)", repeatable).option("--output <fmt>", "Output format", "pretty");
6945
+ ).option("--sort <field,dir>", "Sort criteria (repeatable)", repeatable).option("--output <fmt>", "Output format: pretty, table, markdown, csv, json, yaml");
6663
6946
  registerPageAliases(cmd, { sizeFlag: "--size", sizeKey: "size" });
6664
6947
  return cmd;
6665
6948
  }
@@ -6693,9 +6976,10 @@ function register5(dlp) {
6693
6976
  try {
6694
6977
  const { page, size } = resolvePageParams(listCmd, opts);
6695
6978
  const svc = new SdkDataProfilesService();
6979
+ const result = opts.all ? await svc.listAll({ size, sort: opts.sort, max: Number(opts.max) }) : void 0;
6696
6980
  dlpProfiles.renderList(
6697
- await svc.list({ page, size, sort: opts.sort }),
6698
- opts.output
6981
+ result ? { content: result, totalElements: result.length } : await svc.list({ page, size, sort: opts.sort }),
6982
+ await resolveOutput(listCmd, opts)
6699
6983
  );
6700
6984
  } catch (err) {
6701
6985
  fail(err);
@@ -6713,11 +6997,11 @@ function register5(dlp) {
6713
6997
  usageError(err instanceof Error ? err.message : String(err));
6714
6998
  }
6715
6999
  });
6716
- group.command("get <id>").description("Get a data profile by id").option("--output <fmt>", "Output format", "pretty").action(async (id, opts) => {
7000
+ const getCmd = group.command("get <id>").description("Get a data profile by id").option("--output <fmt>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (id, opts) => {
6717
7001
  try {
6718
7002
  dlpProfiles.renderGet(
6719
7003
  await new SdkDataProfilesService().get(id),
6720
- opts.output
7004
+ await resolveOutput(getCmd, opts)
6721
7005
  );
6722
7006
  } catch (err) {
6723
7007
  fail(err);
@@ -7365,15 +7649,26 @@ async function createMgmtService() {
7365
7649
  function registerRuntimeCommand(program) {
7366
7650
  const runtime = program.command("runtime").description("Runtime prompt scanning against AIRS profiles");
7367
7651
  const apiKeys = runtime.command("api-keys").description("Manage AIRS API keys");
7368
- apiKeys.command("list").description("List API keys").option("--limit <n>", "Max results", "100").option("--output <format>", "Output format: pretty, table, csv, json, yaml", "pretty").action(async (opts) => {
7652
+ const apiKeysList = registerListFlags(apiKeys.command("list"), { dialect: "offset" }).description("List API keys").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (opts) => {
7369
7653
  try {
7370
- const fmt = opts.output;
7654
+ const fmt = await resolveOutput(apiKeysList, opts);
7655
+ const page = resolveListParams(apiKeysList, opts, { dialect: "offset" });
7371
7656
  if (fmt === "pretty") renderRuntimeConfigHeader();
7372
7657
  const service = await createMgmtService();
7658
+ if (page.all) {
7659
+ const items = await service.listAllApiKeys({ limit: page.limit, max: page.max });
7660
+ emitList(apiKeysView, items, fmt, {
7661
+ page: { returned: items.length, total: items.length, all: true }
7662
+ });
7663
+ return;
7664
+ }
7373
7665
  const result = await service.listApiKeys({
7374
- limit: Number.parseInt(opts.limit, 10)
7666
+ limit: page.limit,
7667
+ offset: page.offset
7668
+ });
7669
+ emitList(apiKeysView, result.apiKeys, fmt, {
7670
+ page: { returned: result.apiKeys.length, next: result.nextOffset }
7375
7671
  });
7376
- renderApiKeyList(result.apiKeys, fmt);
7377
7672
  } catch (err) {
7378
7673
  fail(err);
7379
7674
  }
@@ -7560,25 +7855,37 @@ function registerRuntimeCommand(program) {
7560
7855
  }
7561
7856
  });
7562
7857
  const customerApps = runtime.command("customer-apps").description("Manage AIRS customer apps");
7563
- customerApps.command("list").description("List customer apps").option("--limit <n>", "Max results", "100").option("--output <format>", "Output format: pretty, table, csv, json, yaml", "pretty").action(async (opts) => {
7858
+ const customerAppsList = registerListFlags(customerApps.command("list"), { dialect: "offset" }).description("List customer apps").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (opts) => {
7564
7859
  try {
7565
- const fmt = opts.output;
7860
+ const fmt = await resolveOutput(customerAppsList, opts);
7861
+ const page = resolveListParams(customerAppsList, opts, { dialect: "offset" });
7566
7862
  if (fmt === "pretty") renderRuntimeConfigHeader();
7567
7863
  const service = await createMgmtService();
7864
+ if (page.all) {
7865
+ const items = await service.listAllCustomerApps({ limit: page.limit, max: page.max });
7866
+ emitList(customerAppsView, items, fmt, {
7867
+ page: { returned: items.length, total: items.length, all: true }
7868
+ });
7869
+ return;
7870
+ }
7568
7871
  const result = await service.listCustomerApps({
7569
- limit: Number.parseInt(opts.limit, 10)
7872
+ limit: page.limit,
7873
+ offset: page.offset
7874
+ });
7875
+ emitList(customerAppsView, result.apps, fmt, {
7876
+ page: { returned: result.apps.length, next: result.nextOffset }
7570
7877
  });
7571
- renderCustomerAppList(result.apps, fmt);
7572
7878
  } catch (err) {
7573
7879
  fail(err);
7574
7880
  }
7575
7881
  });
7576
- customerApps.command("get <appName>").description("Get customer app details").action(async (appName) => {
7882
+ const customerAppsGet = customerApps.command("get <appName>").description("Get customer app details").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (appName, opts) => {
7577
7883
  try {
7578
- renderRuntimeConfigHeader();
7884
+ const fmt = await resolveOutput(customerAppsGet, opts);
7885
+ if (fmt === "pretty") renderRuntimeConfigHeader();
7579
7886
  const service = await createMgmtService();
7580
7887
  const app = await service.getCustomerApp(appName);
7581
- renderCustomerAppDetail(app);
7888
+ emitDetail(customerAppsView, app, fmt);
7582
7889
  } catch (err) {
7583
7890
  fail(err);
7584
7891
  }
@@ -7660,7 +7967,7 @@ function registerRuntimeCommand(program) {
7660
7967
  }
7661
7968
  });
7662
7969
  const profiles = runtime.command("profiles").description("Manage AIRS security profiles");
7663
- profiles.command("list").description("List security profiles").option("--limit <n>", "Max results", "100").option("--offset <n>", "Starting offset", "0").option("--output <format>", "Output format: pretty, table, csv, json, yaml", "pretty").addHelpText(
7970
+ const profilesList = registerListFlags(profiles.command("list"), { dialect: "offset" }).description("List security profiles").option("--all-versions", "Include every profile revision").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").addHelpText(
7664
7971
  "after",
7665
7972
  examples(
7666
7973
  "airs runtime profiles list",
@@ -7669,49 +7976,55 @@ function registerRuntimeCommand(program) {
7669
7976
  )
7670
7977
  ).action(async (opts) => {
7671
7978
  try {
7672
- const fmt = opts.output;
7673
- if (!OUTPUT_FORMATS.includes(fmt)) {
7674
- usageError(`Invalid output format "${fmt}". Valid: ${OUTPUT_FORMATS.join(", ")}`);
7675
- }
7979
+ const fmt = await resolveOutput(profilesList, opts);
7980
+ const page = resolveListParams(profilesList, opts, { dialect: "offset" });
7676
7981
  if (fmt === "pretty") renderRuntimeConfigHeader();
7677
7982
  const service = await createMgmtService();
7983
+ if (page.all) {
7984
+ const items = await service.listAllProfiles({
7985
+ limit: page.limit,
7986
+ latest: !opts.allVersions,
7987
+ max: page.max
7988
+ });
7989
+ emitList(profilesView, items, fmt, {
7990
+ page: { returned: items.length, total: items.length, all: true }
7991
+ });
7992
+ return;
7993
+ }
7678
7994
  const result = await service.listProfiles({
7679
- limit: Number.parseInt(opts.limit, 10),
7680
- offset: Number.parseInt(opts.offset, 10)
7995
+ limit: page.limit,
7996
+ offset: page.offset,
7997
+ latest: !opts.allVersions
7998
+ });
7999
+ emitList(profilesView, result.profiles, fmt, {
8000
+ page: {
8001
+ returned: result.profiles.length,
8002
+ next: result.nextOffset
8003
+ }
7681
8004
  });
7682
- renderProfileList(result.profiles, fmt);
7683
- if (fmt === "pretty" && result.nextOffset != null) {
7684
- ui.dim(`Next offset: ${result.nextOffset}`);
7685
- }
7686
8005
  } catch (err) {
7687
8006
  fail(err);
7688
8007
  }
7689
8008
  });
7690
- profiles.command("get <nameOrId>").description("Get a security profile by name or UUID").option("--output <format>", "Output format: pretty, json, yaml", "pretty").action(async (nameOrId, opts) => {
8009
+ const profilesGet = profiles.command("get <nameOrId>").description("Get a security profile by name or UUID").option("--revision <n>", "Select an exact revision", Number).option("--all-versions", "Return every matching revision").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (nameOrId, opts) => {
7691
8010
  try {
7692
- const fmt = opts.output;
7693
- if (fmt !== "pretty" && fmt !== "json" && fmt !== "yaml") {
7694
- usageError(`Invalid output format "${fmt}". Valid: pretty, json, yaml`);
7695
- }
8011
+ const fmt = await resolveOutput(profilesGet, opts);
7696
8012
  if (fmt === "pretty") renderRuntimeConfigHeader();
7697
8013
  const service = await createMgmtService();
7698
8014
  const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
7699
8015
  nameOrId
7700
8016
  );
7701
- const profile = isUuid ? await service.getProfile(nameOrId) : await service.getProfileByName(nameOrId);
7702
- if (fmt === "json") {
7703
- console.log(JSON.stringify(profile, null, 2));
7704
- } else if (fmt === "yaml") {
7705
- const lines = [`profileId: ${profile.profileId}`, `profileName: ${profile.profileName}`];
7706
- if (profile.revision != null) lines.push(`revision: ${profile.revision}`);
7707
- if (profile.active != null) lines.push(`active: ${profile.active}`);
7708
- if (profile.createdBy) lines.push(`createdBy: ${profile.createdBy}`);
7709
- if (profile.updatedBy) lines.push(`updatedBy: ${profile.updatedBy}`);
7710
- if (profile.lastModifiedTs) lines.push(`lastModifiedTs: ${profile.lastModifiedTs}`);
7711
- if (profile.policy) lines.push(`policy: ${JSON.stringify(profile.policy, null, 2)}`);
7712
- console.log(lines.join("\n"));
8017
+ if (opts.revision !== void 0 || opts.allVersions) {
8018
+ const profiles2 = (await service.listAllProfiles({ latest: false })).filter(
8019
+ (profile) => isUuid ? profile.profileId === nameOrId : profile.profileName === nameOrId
8020
+ );
8021
+ const selected = opts.revision === void 0 ? profiles2 : profiles2.filter((profile) => profile.revision === opts.revision);
8022
+ if (selected.length === 0) throw new Error(`Profile ${nameOrId} not found`);
8023
+ if (opts.allVersions) emitList(profilesView, selected, fmt);
8024
+ else emitDetail(profilesView, selected[0], fmt);
7713
8025
  } else {
7714
- renderProfileDetail(profile);
8026
+ const profile = isUuid ? await service.getProfile(nameOrId) : await service.getProfileByName(nameOrId);
8027
+ emitDetail(profilesView, profile, fmt);
7715
8028
  }
7716
8029
  } catch (err) {
7717
8030
  fail(err);
@@ -8036,52 +8349,47 @@ function registerRuntimeCommand(program) {
8036
8349
  }
8037
8350
  });
8038
8351
  registerEvalCommand(topics);
8039
- topics.command("get <nameOrId>").description("Get a custom topic by name or UUID").option("--output <format>", "Output format: pretty, json, yaml", "pretty").action(async (nameOrId, opts) => {
8352
+ const topicsGet = topics.command("get <nameOrId>").description("Get a custom topic by name or UUID").option("--revision <n>", "Select an exact revision", Number).option("--all-versions", "Return every matching revision").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (nameOrId, opts) => {
8040
8353
  try {
8041
- const fmt = opts.output;
8042
- if (fmt !== "pretty" && fmt !== "json" && fmt !== "yaml") {
8043
- usageError(`Invalid output format "${fmt}". Valid: pretty, json, yaml`);
8044
- }
8354
+ const fmt = await resolveOutput(topicsGet, opts);
8045
8355
  if (fmt === "pretty") renderRuntimeConfigHeader();
8046
8356
  const service = await createMgmtService();
8047
8357
  const isUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
8048
8358
  nameOrId
8049
8359
  );
8050
- const topic = isUuid ? await service.getTopic(nameOrId) : await service.getTopicByName(nameOrId);
8051
- if (fmt === "json") {
8052
- console.log(JSON.stringify(topic, null, 2));
8053
- } else if (fmt === "yaml") {
8054
- const lines = [`topic_id: ${topic.topic_id}`, `topic_name: ${topic.topic_name}`];
8055
- if (topic.revision != null) lines.push(`revision: ${topic.revision}`);
8056
- if (topic.description) lines.push(`description: ${topic.description}`);
8057
- if (topic.examples?.length) {
8058
- lines.push("examples:");
8059
- for (const ex of topic.examples) lines.push(` - ${ex}`);
8060
- }
8061
- if (topic.created_by) lines.push(`created_by: ${topic.created_by}`);
8062
- if (topic.updated_by) lines.push(`updated_by: ${topic.updated_by}`);
8063
- if (topic.last_modified_ts) lines.push(`last_modified_ts: ${topic.last_modified_ts}`);
8064
- console.log(lines.join("\n"));
8360
+ if (opts.revision !== void 0 || opts.allVersions) {
8361
+ const topics2 = (await service.listTopics()).filter(
8362
+ (topic) => isUuid ? topic.topic_id === nameOrId : topic.topic_name === nameOrId
8363
+ );
8364
+ const selected = opts.revision === void 0 ? topics2 : topics2.filter((topic) => topic.revision === opts.revision);
8365
+ if (selected.length === 0) throw new Error(`Topic ${nameOrId} not found`);
8366
+ if (opts.allVersions) emitList(topicsView, selected, fmt);
8367
+ else emitDetail(topicsView, selected[0], fmt);
8065
8368
  } else {
8066
- renderTopicDetail(topic);
8369
+ const topic = isUuid ? await service.getTopic(nameOrId) : await service.getTopicByName(nameOrId);
8370
+ emitDetail(topicsView, topic, fmt);
8067
8371
  }
8068
8372
  } catch (err) {
8069
8373
  fail(err);
8070
8374
  }
8071
8375
  });
8072
- topics.command("list").description("List custom topics").option("--limit <n>", "Max results", "100").option("--offset <n>", "Starting offset", "0").option("--output <format>", "Output format: pretty, table, csv, json, yaml", "pretty").action(async (opts) => {
8376
+ const topicsList = registerListFlags(topics.command("list"), { dialect: "offset" }).description("List custom topics").option("--all-versions", "Include every topic revision").option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml").action(async (opts) => {
8073
8377
  try {
8074
- const fmt = opts.output;
8378
+ const fmt = await resolveOutput(topicsList, opts);
8379
+ const params = resolveListParams(topicsList, opts, { dialect: "offset" });
8075
8380
  if (fmt === "pretty") renderRuntimeConfigHeader();
8076
8381
  const service = await createMgmtService();
8077
- const allTopics = await service.listTopics();
8078
- const offset = Number.parseInt(opts.offset, 10);
8079
- const limit = Number.parseInt(opts.limit, 10);
8080
- const page = allTopics.slice(offset, offset + limit);
8081
- renderTopicList(page, fmt);
8082
- if (fmt === "pretty" && offset + limit < allTopics.length) {
8083
- ui.dim(`Showing ${page.length} of ${allTopics.length} topics`);
8084
- }
8382
+ const allTopics = opts.allVersions ? await service.listTopics() : await service.listLatestTopics(
8383
+ params.all ? { offset: 0, limit: params.max === 0 ? 1e4 : params.max } : { offset: params.offset, limit: params.limit }
8384
+ );
8385
+ const page = opts.allVersions && !params.all ? allTopics.slice(params.offset, params.offset + params.limit) : allTopics;
8386
+ emitList(topicsView, page, fmt, {
8387
+ page: params.all ? { returned: page.length, total: page.length, all: true } : {
8388
+ returned: page.length,
8389
+ total: opts.allVersions ? allTopics.length : void 0,
8390
+ next: opts.allVersions && params.offset + params.limit < allTopics.length ? params.offset + params.limit : void 0
8391
+ }
8392
+ });
8085
8393
  } catch (err) {
8086
8394
  fail(err);
8087
8395
  }
@@ -8290,16 +8598,45 @@ function applyListDeleteAliases(cmd) {
8290
8598
  applyListDeleteAliases(sub);
8291
8599
  }
8292
8600
  }
8601
+ function applyReadContractFlags(cmd) {
8602
+ for (const sub of cmd.commands) {
8603
+ const flags = () => sub.options.map((option) => option.long);
8604
+ if ((sub.name() === "list" || sub.name() === "get") && !flags().includes("--output")) {
8605
+ sub.option("--output <format>", "Output format: pretty, table, markdown, csv, json, yaml");
8606
+ }
8607
+ if (sub.name() === "list" && (flags().includes("--limit") || flags().includes("--offset"))) {
8608
+ if (!flags().includes("--limit")) sub.option("--limit <n>", "Items per page", Number, 50);
8609
+ if (!flags().includes("--offset")) sub.option("--offset <n>", "Item offset", Number, 0);
8610
+ if (!flags().includes("--all")) sub.option("--all", "Walk all pages");
8611
+ if (!flags().includes("--max")) {
8612
+ sub.option("--max <n>", "Maximum items with --all; 0 removes the cap", Number, 1e4);
8613
+ }
8614
+ }
8615
+ applyReadContractFlags(sub);
8616
+ }
8617
+ }
8618
+ function applySortedHelp(cmd) {
8619
+ cmd.configureHelp({ sortOptions: true, sortSubcommands: true });
8620
+ for (const sub of cmd.commands) applySortedHelp(sub);
8621
+ }
8293
8622
  function buildProgram() {
8294
8623
  const here = dirname4(fileURLToPath(import.meta.url));
8295
8624
  const pkg = JSON.parse(readFileSync4(join4(here, "../../package.json"), "utf-8"));
8296
8625
  const program = new Command();
8297
8626
  program.name("airs").description(
8298
8627
  "CLI and library for Palo Alto Prisma AIRS \u2014 guardrail refinement, AI red teaming, model security scanning, profile audits"
8299
- ).version(pkg.version).option("--debug", "Log all AIRS/SCM API requests and responses to a JSONL file").option("--quiet", "Suppress status and decorative output (data and errors still print)");
8300
- program.hook("preAction", (_thisCommand, actionCommand) => {
8628
+ ).version(pkg.version).option("--debug", "Log all AIRS/SCM API requests and responses to a JSONL file").option("--output <format>", "Default output format for read commands").option("--quiet", "Suppress status and decorative output (data and errors still print)");
8629
+ program.hook("preAction", async (_thisCommand, actionCommand) => {
8301
8630
  const root = actionCommand.optsWithGlobals?.() ?? _thisCommand.opts();
8302
8631
  setQuiet(Boolean(root.quiet));
8632
+ if ((actionCommand.name() === "list" || actionCommand.name() === "get") && actionCommand.options.some((option) => option.long === "--output")) {
8633
+ try {
8634
+ const format = await resolveOutput(actionCommand, actionCommand.opts());
8635
+ actionCommand.setOptionValueWithSource("output", format, "implied");
8636
+ } catch (error) {
8637
+ fail(error);
8638
+ }
8639
+ }
8303
8640
  if (root.debug) {
8304
8641
  const logPath = join4(homedir(), ".prisma-airs", `debug-api-${Date.now()}.jsonl`);
8305
8642
  installDebugLogger(logPath);
@@ -8314,6 +8651,8 @@ function buildProgram() {
8314
8651
  registerDoctorCommand(program);
8315
8652
  registerCompletionCommand(program);
8316
8653
  applyListDeleteAliases(program);
8654
+ applyReadContractFlags(program);
8655
+ applySortedHelp(program);
8317
8656
  return program;
8318
8657
  }
8319
8658