@robinmordasiewicz/f5xc-xcsh 6.37.0 → 6.38.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/index.js CHANGED
@@ -45354,8 +45354,8 @@ function getLogoModeFromEnv(envPrefix) {
45354
45354
  var CLI_NAME = "xcsh";
45355
45355
  var CLI_FULL_NAME = "F5 Distributed Cloud Shell";
45356
45356
  function getVersion() {
45357
- if ("6.37.0") {
45358
- return "6.37.0";
45357
+ if ("6.38.0") {
45358
+ return "6.38.0";
45359
45359
  }
45360
45360
  if (process.env.XCSH_VERSION) {
45361
45361
  return process.env.XCSH_VERSION;
@@ -46024,6 +46024,728 @@ var APIClient = class {
46024
46024
  }
46025
46025
  };
46026
46026
 
46027
+ // src/output/formatter.ts
46028
+ var import_yaml2 = __toESM(require_dist(), 1);
46029
+
46030
+ // src/output/types.ts
46031
+ var DEFAULT_TABLE_STYLE = {
46032
+ unicode: true,
46033
+ coloredBorders: true,
46034
+ headerStyle: "bold"
46035
+ };
46036
+ var PLAIN_TABLE_STYLE = {
46037
+ unicode: false,
46038
+ coloredBorders: false,
46039
+ headerStyle: "normal"
46040
+ };
46041
+ function isValidOutputFormat(format) {
46042
+ return ["json", "yaml", "table", "text", "tsv", "none", "spec"].includes(
46043
+ format.toLowerCase()
46044
+ );
46045
+ }
46046
+
46047
+ // src/output/resolver.ts
46048
+ var OUTPUT_FORMAT_ENV_VAR = `${ENV_PREFIX}_OUTPUT_FORMAT`;
46049
+ function getOutputFormatFromEnv() {
46050
+ const envValue = process.env[OUTPUT_FORMAT_ENV_VAR]?.toLowerCase().trim();
46051
+ if (envValue && isValidOutputFormat(envValue)) {
46052
+ return envValue;
46053
+ }
46054
+ return void 0;
46055
+ }
46056
+ function shouldUseColors(isTTY = process.stdout.isTTY ?? false, noColorFlag = false) {
46057
+ if (noColorFlag) {
46058
+ return false;
46059
+ }
46060
+ if (process.env.NO_COLOR !== void 0) {
46061
+ return false;
46062
+ }
46063
+ if (process.env.FORCE_COLOR !== void 0) {
46064
+ return true;
46065
+ }
46066
+ return isTTY;
46067
+ }
46068
+
46069
+ // src/output/table.ts
46070
+ var UNICODE_BOX = {
46071
+ topLeft: "\u256D",
46072
+ // ╭
46073
+ topRight: "\u256E",
46074
+ // ╮
46075
+ bottomLeft: "\u2570",
46076
+ // ╰
46077
+ bottomRight: "\u256F",
46078
+ // ╯
46079
+ horizontal: "\u2500",
46080
+ // ─
46081
+ vertical: "\u2502",
46082
+ // │
46083
+ leftT: "\u251C",
46084
+ // ├
46085
+ rightT: "\u2524",
46086
+ // ┤
46087
+ topT: "\u252C",
46088
+ // ┬
46089
+ bottomT: "\u2534",
46090
+ // ┴
46091
+ cross: "\u253C"
46092
+ // ┼
46093
+ };
46094
+ var ASCII_BOX = {
46095
+ topLeft: "+",
46096
+ topRight: "+",
46097
+ bottomLeft: "+",
46098
+ bottomRight: "+",
46099
+ horizontal: "-",
46100
+ vertical: "|",
46101
+ leftT: "+",
46102
+ rightT: "+",
46103
+ topT: "+",
46104
+ bottomT: "+",
46105
+ cross: "+"
46106
+ };
46107
+ function getBoxCharacters(style) {
46108
+ return style.unicode ? UNICODE_BOX : ASCII_BOX;
46109
+ }
46110
+ function applyColor(text, color, useColors) {
46111
+ if (!useColors) {
46112
+ return text;
46113
+ }
46114
+ return `${color}${text}${colors.reset}`;
46115
+ }
46116
+ function wrapText2(text, maxWidth) {
46117
+ if (text.length <= maxWidth) {
46118
+ return [text];
46119
+ }
46120
+ const lines = [];
46121
+ let remaining = text;
46122
+ while (remaining.length > 0) {
46123
+ if (remaining.length <= maxWidth) {
46124
+ lines.push(remaining);
46125
+ break;
46126
+ }
46127
+ let breakPoint = maxWidth;
46128
+ for (let i = maxWidth - 1; i > 0; i--) {
46129
+ if (remaining[i] === " ") {
46130
+ breakPoint = i;
46131
+ break;
46132
+ }
46133
+ }
46134
+ lines.push(remaining.slice(0, breakPoint));
46135
+ remaining = remaining.slice(breakPoint).trimStart();
46136
+ }
46137
+ return lines;
46138
+ }
46139
+ function getValue(row, accessor) {
46140
+ if (typeof accessor === "function") {
46141
+ return accessor(row);
46142
+ }
46143
+ const value = row[accessor];
46144
+ if (value === null || value === void 0) {
46145
+ return "";
46146
+ }
46147
+ if (typeof value === "object") {
46148
+ if (accessor === "labels") {
46149
+ return formatLabelsValue(value);
46150
+ }
46151
+ return JSON.stringify(value);
46152
+ }
46153
+ return String(value);
46154
+ }
46155
+ function formatLabelsValue(labels) {
46156
+ const entries = Object.entries(labels).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}:${v}`);
46157
+ if (entries.length === 0) {
46158
+ return "";
46159
+ }
46160
+ return `map[${entries.join(" ")}]`;
46161
+ }
46162
+ function calculateColumnWidths(columns, rows, maxTableWidth) {
46163
+ const widths = columns.map((col) => {
46164
+ let width = col.header.length;
46165
+ for (const row of rows) {
46166
+ const value = getValue(row, col.accessor);
46167
+ width = Math.max(width, value.length);
46168
+ }
46169
+ if (col.minWidth) {
46170
+ width = Math.max(width, col.minWidth);
46171
+ }
46172
+ if (col.maxWidth) {
46173
+ width = Math.min(width, col.maxWidth);
46174
+ }
46175
+ if (col.width) {
46176
+ width = col.width;
46177
+ }
46178
+ return width;
46179
+ });
46180
+ if (maxTableWidth) {
46181
+ const totalWidth = widths.reduce((a, b) => a + b, 0) + columns.length * 3 + 1;
46182
+ if (totalWidth > maxTableWidth) {
46183
+ const ratio = (maxTableWidth - columns.length * 3 - 1) / totalWidth;
46184
+ for (let i = 0; i < widths.length; i++) {
46185
+ widths[i] = Math.max(5, Math.floor(widths[i] * ratio));
46186
+ }
46187
+ }
46188
+ }
46189
+ return widths;
46190
+ }
46191
+ function formatBeautifulTable(data, config, noColor = false) {
46192
+ if (data.length === 0) {
46193
+ return "";
46194
+ }
46195
+ const useColors = shouldUseColors(void 0, noColor);
46196
+ const style = useColors ? config.style ?? DEFAULT_TABLE_STYLE : PLAIN_TABLE_STYLE;
46197
+ const box = getBoxCharacters(style);
46198
+ const borderColor = style.borderColor ?? colors.red;
46199
+ const widths = calculateColumnWidths(config.columns, data, config.maxWidth);
46200
+ const lines = [];
46201
+ const colorBorder = (text) => applyColor(text, borderColor, useColors && style.coloredBorders);
46202
+ const buildHorizontalLine = (left, mid, right, fill) => {
46203
+ const segments = widths.map((w) => fill.repeat(w + 2));
46204
+ return colorBorder(left + segments.join(mid) + right);
46205
+ };
46206
+ if (config.title) {
46207
+ const title = ` ${config.title} `;
46208
+ const totalWidth = widths.reduce((a, b) => a + b, 0) + widths.length * 3 - 1;
46209
+ const remainingWidth = totalWidth - title.length;
46210
+ const leftDashes = 1;
46211
+ const rightDashes = Math.max(0, remainingWidth - leftDashes);
46212
+ lines.push(
46213
+ colorBorder(box.topLeft + box.horizontal.repeat(leftDashes)) + title + colorBorder(box.horizontal.repeat(rightDashes) + box.topRight)
46214
+ );
46215
+ } else {
46216
+ lines.push(
46217
+ buildHorizontalLine(
46218
+ box.topLeft,
46219
+ box.topT,
46220
+ box.topRight,
46221
+ box.horizontal
46222
+ )
46223
+ );
46224
+ }
46225
+ const headerCells = config.columns.map((col, i) => {
46226
+ const padding = widths[i] - col.header.length;
46227
+ const leftPad = Math.floor(padding / 2);
46228
+ const rightPad = padding - leftPad;
46229
+ const content = " ".repeat(leftPad) + col.header + " ".repeat(rightPad);
46230
+ return ` ${content} `;
46231
+ });
46232
+ lines.push(
46233
+ colorBorder(box.vertical) + headerCells.join(colorBorder(box.vertical)) + colorBorder(box.vertical)
46234
+ );
46235
+ lines.push(
46236
+ buildHorizontalLine(box.leftT, box.cross, box.rightT, box.horizontal)
46237
+ );
46238
+ for (let rowIndex = 0; rowIndex < data.length; rowIndex++) {
46239
+ const row = data[rowIndex];
46240
+ const cellValues = config.columns.map((col, i) => {
46241
+ const value = getValue(row, col.accessor) || "<None>";
46242
+ return config.wrapText !== false ? wrapText2(value, widths[i]) : [value.slice(0, widths[i])];
46243
+ });
46244
+ const maxLines = Math.max(...cellValues.map((c) => c.length));
46245
+ for (let lineIndex = 0; lineIndex < maxLines; lineIndex++) {
46246
+ const cells = cellValues.map((cellLines, i) => {
46247
+ const text = cellLines[lineIndex] ?? "";
46248
+ const padding = widths[i] - text.length;
46249
+ const align = config.columns[i]?.align ?? "left";
46250
+ let content;
46251
+ if (align === "center") {
46252
+ const leftPad = Math.floor(padding / 2);
46253
+ const rightPad = padding - leftPad;
46254
+ content = " ".repeat(leftPad) + text + " ".repeat(rightPad);
46255
+ } else if (align === "right") {
46256
+ content = " ".repeat(padding) + text;
46257
+ } else {
46258
+ content = text + " ".repeat(padding);
46259
+ }
46260
+ return ` ${content} `;
46261
+ });
46262
+ lines.push(
46263
+ colorBorder(box.vertical) + cells.join(colorBorder(box.vertical)) + colorBorder(box.vertical)
46264
+ );
46265
+ }
46266
+ if (rowIndex < data.length - 1 && config.rowSeparators) {
46267
+ lines.push(
46268
+ buildHorizontalLine(
46269
+ box.leftT,
46270
+ box.cross,
46271
+ box.rightT,
46272
+ box.horizontal
46273
+ )
46274
+ );
46275
+ }
46276
+ }
46277
+ lines.push(
46278
+ buildHorizontalLine(
46279
+ box.bottomLeft,
46280
+ box.bottomT,
46281
+ box.bottomRight,
46282
+ box.horizontal
46283
+ )
46284
+ );
46285
+ return lines.join("\n");
46286
+ }
46287
+ var DEFAULT_RESOURCE_COLUMNS = [
46288
+ { header: "NAMESPACE", accessor: "namespace", minWidth: 9 },
46289
+ { header: "NAME", accessor: "name", minWidth: 10, maxWidth: 40 },
46290
+ { header: "LABELS", accessor: "labels", minWidth: 10, maxWidth: 35 }
46291
+ ];
46292
+ function formatResourceTable(data, noColor = false) {
46293
+ const items = extractItems(data);
46294
+ if (items.length === 0) {
46295
+ return "";
46296
+ }
46297
+ return formatBeautifulTable(
46298
+ items,
46299
+ {
46300
+ columns: DEFAULT_RESOURCE_COLUMNS,
46301
+ wrapText: true
46302
+ },
46303
+ noColor
46304
+ );
46305
+ }
46306
+ function extractItems(data) {
46307
+ if (data && typeof data === "object" && "items" in data) {
46308
+ const items = data.items;
46309
+ if (Array.isArray(items)) {
46310
+ return items.filter(
46311
+ (item) => item !== null && typeof item === "object"
46312
+ );
46313
+ }
46314
+ }
46315
+ if (Array.isArray(data)) {
46316
+ return data.filter(
46317
+ (item) => item !== null && typeof item === "object"
46318
+ );
46319
+ }
46320
+ if (data && typeof data === "object") {
46321
+ return [data];
46322
+ }
46323
+ return [];
46324
+ }
46325
+
46326
+ // src/output/formatter.ts
46327
+ function formatOutput(data, format = "table", noColor = false) {
46328
+ if (format === "none") {
46329
+ return "";
46330
+ }
46331
+ const useNoColor = noColor || !shouldUseColors();
46332
+ switch (format) {
46333
+ case "json":
46334
+ return formatJSON(data);
46335
+ case "yaml":
46336
+ return formatYAML(data);
46337
+ case "table":
46338
+ case "text":
46339
+ return formatTable(data, useNoColor);
46340
+ case "tsv":
46341
+ return formatTSV(data);
46342
+ case "spec":
46343
+ return formatJSON(data);
46344
+ default:
46345
+ return formatTable(data, useNoColor);
46346
+ }
46347
+ }
46348
+ function formatJSON(data) {
46349
+ return JSON.stringify(data, null, 2);
46350
+ }
46351
+ function formatYAML(data) {
46352
+ return import_yaml2.default.stringify(data, { indent: 2 });
46353
+ }
46354
+ function extractItems2(data) {
46355
+ if (data && typeof data === "object" && "items" in data) {
46356
+ const items = data.items;
46357
+ if (Array.isArray(items)) {
46358
+ return items.filter(
46359
+ (item) => item !== null && typeof item === "object"
46360
+ );
46361
+ }
46362
+ }
46363
+ if (Array.isArray(data)) {
46364
+ return data.filter(
46365
+ (item) => item !== null && typeof item === "object"
46366
+ );
46367
+ }
46368
+ if (data && typeof data === "object") {
46369
+ return [data];
46370
+ }
46371
+ return [];
46372
+ }
46373
+ function formatTable(data, noColor = false) {
46374
+ return formatResourceTable(data, noColor);
46375
+ }
46376
+ function formatTSV(data) {
46377
+ const items = extractItems2(data);
46378
+ if (items.length === 0) {
46379
+ return "";
46380
+ }
46381
+ const allKeys = /* @__PURE__ */ new Set();
46382
+ for (const item of items) {
46383
+ Object.keys(item).forEach((k) => allKeys.add(k));
46384
+ }
46385
+ const priority = ["name", "namespace", "status", "created", "modified"];
46386
+ const headers = [
46387
+ ...priority.filter((p) => allKeys.has(p)),
46388
+ ...[...allKeys].filter((k) => !priority.includes(k)).sort()
46389
+ ];
46390
+ const lines = [];
46391
+ for (const item of items) {
46392
+ const values = headers.map((h) => {
46393
+ const val = item[h];
46394
+ if (val === null || val === void 0) return "";
46395
+ if (typeof val === "object") return JSON.stringify(val);
46396
+ return String(val);
46397
+ });
46398
+ lines.push(values.join(" "));
46399
+ }
46400
+ return lines.join("\n");
46401
+ }
46402
+ function parseOutputFormat(format) {
46403
+ switch (format.toLowerCase()) {
46404
+ case "json":
46405
+ return "json";
46406
+ case "yaml":
46407
+ return "yaml";
46408
+ case "table":
46409
+ case "text":
46410
+ case "":
46411
+ return "table";
46412
+ case "tsv":
46413
+ return "tsv";
46414
+ case "none":
46415
+ return "none";
46416
+ default:
46417
+ return "table";
46418
+ }
46419
+ }
46420
+ function formatAPIError(statusCode, body, operation) {
46421
+ const lines = [];
46422
+ lines.push(`ERROR: ${operation} failed (HTTP ${statusCode})`);
46423
+ if (body && typeof body === "object") {
46424
+ const errResp = body;
46425
+ if (errResp.message) {
46426
+ lines.push(` Message: ${errResp.message}`);
46427
+ }
46428
+ if (errResp.code) {
46429
+ lines.push(` Code: ${errResp.code}`);
46430
+ }
46431
+ if (errResp.details) {
46432
+ lines.push(` Details: ${errResp.details}`);
46433
+ }
46434
+ }
46435
+ switch (statusCode) {
46436
+ case 401:
46437
+ lines.push(
46438
+ "\nHint: Authentication failed. Check your credentials with 'login profile show'"
46439
+ );
46440
+ break;
46441
+ case 403:
46442
+ lines.push(
46443
+ "\nHint: Permission denied. You may not have access to this resource."
46444
+ );
46445
+ break;
46446
+ case 404:
46447
+ lines.push(
46448
+ "\nHint: Resource not found. Verify the name and namespace are correct."
46449
+ );
46450
+ break;
46451
+ case 409:
46452
+ lines.push(
46453
+ "\nHint: Conflict - resource may already exist or be in a conflicting state."
46454
+ );
46455
+ break;
46456
+ case 429:
46457
+ lines.push("\nHint: Rate limited. Please wait and try again.");
46458
+ break;
46459
+ case 500:
46460
+ case 502:
46461
+ case 503:
46462
+ lines.push(
46463
+ "\nHint: Server error. Please try again later or contact support."
46464
+ );
46465
+ break;
46466
+ }
46467
+ return lines.join("\n");
46468
+ }
46469
+
46470
+ // src/output/spec.ts
46471
+ function buildCommandSpec(options) {
46472
+ const spec = {
46473
+ command: options.command,
46474
+ description: options.description,
46475
+ usage: options.usage ?? `xcsh ${options.command} [options]`,
46476
+ flags: options.flags ?? [],
46477
+ examples: options.examples ?? [],
46478
+ outputFormats: options.outputFormats ?? ["table", "json", "yaml"]
46479
+ };
46480
+ if (options.related !== void 0) {
46481
+ spec.related = options.related;
46482
+ }
46483
+ if (options.category !== void 0) {
46484
+ spec.category = options.category;
46485
+ }
46486
+ return spec;
46487
+ }
46488
+ function formatSpec(spec) {
46489
+ return JSON.stringify(spec, null, 2);
46490
+ }
46491
+ function buildCloudstatusSpecs() {
46492
+ return {
46493
+ status: buildCommandSpec({
46494
+ command: "cloudstatus status",
46495
+ description: "Get the overall health indicator for F5 Distributed Cloud services. Returns status level (operational, degraded, major outage) with description.",
46496
+ usage: "xcsh cloudstatus status [--quiet]",
46497
+ flags: [
46498
+ {
46499
+ name: "--quiet",
46500
+ alias: "-q",
46501
+ description: "Return exit code only (0=operational, 1=degraded, 2=outage)",
46502
+ type: "boolean"
46503
+ }
46504
+ ],
46505
+ examples: [
46506
+ {
46507
+ command: "xcsh cloudstatus status",
46508
+ description: "Check current F5 XC service status"
46509
+ },
46510
+ {
46511
+ command: "xcsh cloudstatus status --quiet && echo 'All systems operational'",
46512
+ description: "Use in scripts for health checks"
46513
+ },
46514
+ {
46515
+ command: "xcsh cloudstatus status --output json",
46516
+ description: "Get status as JSON for automation"
46517
+ }
46518
+ ],
46519
+ category: "cloudstatus",
46520
+ related: [
46521
+ "cloudstatus summary",
46522
+ "cloudstatus components",
46523
+ "cloudstatus incidents"
46524
+ ]
46525
+ }),
46526
+ summary: buildCommandSpec({
46527
+ command: "cloudstatus summary",
46528
+ description: "Get complete status summary including overall health, component status, and active incidents.",
46529
+ usage: "xcsh cloudstatus summary",
46530
+ examples: [
46531
+ {
46532
+ command: "xcsh cloudstatus summary",
46533
+ description: "View full infrastructure health overview"
46534
+ },
46535
+ {
46536
+ command: "xcsh cloudstatus summary --output json",
46537
+ description: "Get complete summary as JSON"
46538
+ }
46539
+ ],
46540
+ category: "cloudstatus",
46541
+ related: ["cloudstatus status", "cloudstatus components"]
46542
+ }),
46543
+ components: buildCommandSpec({
46544
+ command: "cloudstatus components",
46545
+ description: "List all infrastructure components and their current operational status.",
46546
+ usage: "xcsh cloudstatus components",
46547
+ examples: [
46548
+ {
46549
+ command: "xcsh cloudstatus components",
46550
+ description: "List all components with status"
46551
+ },
46552
+ {
46553
+ command: "xcsh cloudstatus components --output json",
46554
+ description: "Get components as JSON for monitoring integration"
46555
+ }
46556
+ ],
46557
+ category: "cloudstatus",
46558
+ related: ["cloudstatus status", "cloudstatus summary"]
46559
+ }),
46560
+ incidents: buildCommandSpec({
46561
+ command: "cloudstatus incidents",
46562
+ description: "List active and recent incidents affecting F5 Distributed Cloud services.",
46563
+ usage: "xcsh cloudstatus incidents",
46564
+ examples: [
46565
+ {
46566
+ command: "xcsh cloudstatus incidents",
46567
+ description: "View active incidents"
46568
+ },
46569
+ {
46570
+ command: "xcsh cloudstatus incidents --output json",
46571
+ description: "Get incidents as JSON for alerting systems"
46572
+ }
46573
+ ],
46574
+ category: "cloudstatus",
46575
+ related: ["cloudstatus status", "cloudstatus maintenance"]
46576
+ }),
46577
+ maintenance: buildCommandSpec({
46578
+ command: "cloudstatus maintenance",
46579
+ description: "List scheduled maintenance windows for F5 Distributed Cloud services.",
46580
+ usage: "xcsh cloudstatus maintenance",
46581
+ examples: [
46582
+ {
46583
+ command: "xcsh cloudstatus maintenance",
46584
+ description: "View upcoming maintenance windows"
46585
+ },
46586
+ {
46587
+ command: "xcsh cloudstatus maintenance --output json",
46588
+ description: "Get maintenance schedule as JSON"
46589
+ }
46590
+ ],
46591
+ category: "cloudstatus",
46592
+ related: ["cloudstatus status", "cloudstatus incidents"]
46593
+ })
46594
+ };
46595
+ }
46596
+ function buildLoginSpecs() {
46597
+ return {
46598
+ banner: buildCommandSpec({
46599
+ command: "login banner",
46600
+ description: "Display xcsh banner with logo and connection information.",
46601
+ usage: "xcsh login banner",
46602
+ examples: [
46603
+ {
46604
+ command: "xcsh login banner",
46605
+ description: "Show the xcsh welcome banner"
46606
+ }
46607
+ ],
46608
+ category: "login",
46609
+ related: ["login profile show"]
46610
+ }),
46611
+ "profile list": buildCommandSpec({
46612
+ command: "login profile list",
46613
+ description: "List all saved connection profiles.",
46614
+ usage: "xcsh login profile list",
46615
+ examples: [
46616
+ {
46617
+ command: "xcsh login profile list",
46618
+ description: "List saved profiles"
46619
+ },
46620
+ {
46621
+ command: "xcsh login profile list --output json",
46622
+ description: "Get profiles as JSON"
46623
+ }
46624
+ ],
46625
+ category: "login",
46626
+ related: [
46627
+ "login profile show",
46628
+ "login profile create",
46629
+ "login profile use"
46630
+ ]
46631
+ }),
46632
+ "profile show": buildCommandSpec({
46633
+ command: "login profile show",
46634
+ description: "Show current connection profile and authentication status.",
46635
+ usage: "xcsh login profile show [name]",
46636
+ flags: [
46637
+ {
46638
+ name: "name",
46639
+ description: "Profile name to show (optional, defaults to active)",
46640
+ type: "string"
46641
+ }
46642
+ ],
46643
+ examples: [
46644
+ {
46645
+ command: "xcsh login profile show",
46646
+ description: "Show active profile"
46647
+ },
46648
+ {
46649
+ command: "xcsh login profile show production",
46650
+ description: "Show specific profile"
46651
+ }
46652
+ ],
46653
+ category: "login",
46654
+ related: ["login profile list", "login profile use"]
46655
+ }),
46656
+ "profile create": buildCommandSpec({
46657
+ command: "login profile create",
46658
+ description: "Create a new connection profile with URL and credentials.",
46659
+ usage: "xcsh login profile create <name>",
46660
+ flags: [
46661
+ {
46662
+ name: "name",
46663
+ description: "Profile name",
46664
+ type: "string",
46665
+ required: true
46666
+ }
46667
+ ],
46668
+ examples: [
46669
+ {
46670
+ command: "xcsh login profile create production",
46671
+ description: "Create a new profile named 'production'"
46672
+ }
46673
+ ],
46674
+ category: "login",
46675
+ related: ["login profile list", "login profile use"]
46676
+ }),
46677
+ "profile use": buildCommandSpec({
46678
+ command: "login profile use",
46679
+ description: "Switch to a different connection profile.",
46680
+ usage: "xcsh login profile use <name>",
46681
+ flags: [
46682
+ {
46683
+ name: "name",
46684
+ description: "Profile name to activate",
46685
+ type: "string",
46686
+ required: true
46687
+ }
46688
+ ],
46689
+ examples: [
46690
+ {
46691
+ command: "xcsh login profile use staging",
46692
+ description: "Switch to staging profile"
46693
+ }
46694
+ ],
46695
+ category: "login",
46696
+ related: ["login profile list", "login profile show"]
46697
+ }),
46698
+ "context show": buildCommandSpec({
46699
+ command: "login context show",
46700
+ description: "Show the current default namespace context.",
46701
+ usage: "xcsh login context show",
46702
+ examples: [
46703
+ {
46704
+ command: "xcsh login context show",
46705
+ description: "Display current namespace"
46706
+ }
46707
+ ],
46708
+ category: "login",
46709
+ related: ["login context set", "login context list"]
46710
+ }),
46711
+ "context set": buildCommandSpec({
46712
+ command: "login context set",
46713
+ description: "Set the default namespace for subsequent operations.",
46714
+ usage: "xcsh login context set <namespace>",
46715
+ flags: [
46716
+ {
46717
+ name: "namespace",
46718
+ description: "Namespace to set as default",
46719
+ type: "string",
46720
+ required: true
46721
+ }
46722
+ ],
46723
+ examples: [
46724
+ {
46725
+ command: "xcsh login context set production",
46726
+ description: "Set production as default namespace"
46727
+ }
46728
+ ],
46729
+ category: "login",
46730
+ related: ["login context show", "login context list"]
46731
+ })
46732
+ };
46733
+ }
46734
+ function getCommandSpec(commandPath) {
46735
+ const cloudstatusSpecs = buildCloudstatusSpecs();
46736
+ const loginSpecs = buildLoginSpecs();
46737
+ const normalized = commandPath.toLowerCase().trim();
46738
+ if (normalized.startsWith("cloudstatus ")) {
46739
+ const subcommand = normalized.replace("cloudstatus ", "");
46740
+ return cloudstatusSpecs[subcommand];
46741
+ }
46742
+ if (normalized.startsWith("login ")) {
46743
+ const subcommand = normalized.replace("login ", "");
46744
+ return loginSpecs[subcommand];
46745
+ }
46746
+ return void 0;
46747
+ }
46748
+
46027
46749
  // src/repl/session.ts
46028
46750
  var NAMESPACE_CACHE_TTL = 5 * 60 * 1e3;
46029
46751
  var REPLSession = class {
@@ -46037,7 +46759,7 @@ var REPLSession = class {
46037
46759
  _serverUrl = "";
46038
46760
  _apiToken = "";
46039
46761
  _apiClient = null;
46040
- _outputFormat = "yaml";
46762
+ _outputFormat = "table";
46041
46763
  _debug = false;
46042
46764
  _profileManager;
46043
46765
  _activeProfile = null;
@@ -46051,7 +46773,7 @@ var REPLSession = class {
46051
46773
  this._profileManager = getProfileManager();
46052
46774
  this._serverUrl = config.serverUrl ?? process.env[`${ENV_PREFIX}_API_URL`] ?? "";
46053
46775
  this._apiToken = config.apiToken ?? process.env[`${ENV_PREFIX}_API_TOKEN`] ?? "";
46054
- this._outputFormat = config.outputFormat ?? "yaml";
46776
+ this._outputFormat = config.outputFormat ?? getOutputFormatFromEnv() ?? "table";
46055
46777
  this._debug = config.debug ?? process.env[`${ENV_PREFIX}_DEBUG`] === "true";
46056
46778
  if (this._serverUrl) {
46057
46779
  this._tenant = this.extractTenant(this._serverUrl);
@@ -46900,7 +47622,7 @@ function formatConfigSection() {
46900
47622
  }
46901
47623
 
46902
47624
  // src/repl/help.ts
46903
- function wrapText2(text, width, indent) {
47625
+ function wrapText3(text, width, indent) {
46904
47626
  const prefix = " ".repeat(indent);
46905
47627
  const words = text.split(/\s+/);
46906
47628
  const lines = [];
@@ -46924,7 +47646,7 @@ function formatRootHelp() {
46924
47646
  colorBoldWhite(`${CLI_NAME} - ${CLI_FULL_NAME} v${CLI_VERSION}`),
46925
47647
  "",
46926
47648
  "DESCRIPTION",
46927
- ...wrapText2(CLI_DESCRIPTION_LONG, 80, 2),
47649
+ ...wrapText3(CLI_DESCRIPTION_LONG, 80, 2),
46928
47650
  "",
46929
47651
  "USAGE",
46930
47652
  ` ${CLI_NAME} Enter interactive REPL mode`,
@@ -46968,7 +47690,8 @@ function formatGlobalFlags() {
46968
47690
  " -h, --help Show this help",
46969
47691
  " --no-color Disable color output",
46970
47692
  " -o, --output <fmt> Output format (json, yaml, table)",
46971
- " -ns, --namespace <ns> Target namespace"
47693
+ " -ns, --namespace <ns> Target namespace",
47694
+ " --spec Output command specification as JSON (for AI)"
46972
47695
  ];
46973
47696
  }
46974
47697
  function formatEnvironmentVariables() {
@@ -47233,7 +47956,7 @@ function formatDomainsSection() {
47233
47956
  function formatCustomDomainHelp(domain) {
47234
47957
  const output = ["", colorBoldWhite(domain.name), ""];
47235
47958
  output.push("DESCRIPTION");
47236
- output.push(...wrapText2(domain.description, 80, 2));
47959
+ output.push(...wrapText3(domain.description, 80, 2));
47237
47960
  output.push("");
47238
47961
  output.push("USAGE");
47239
47962
  output.push(` ${CLI_NAME} ${domain.name} <command> [options]`);
@@ -47263,7 +47986,7 @@ function formatSubcommandHelp(domainName, subcommand) {
47263
47986
  ""
47264
47987
  ];
47265
47988
  output.push("DESCRIPTION");
47266
- output.push(...wrapText2(subcommand.description, 80, 2));
47989
+ output.push(...wrapText3(subcommand.description, 80, 2));
47267
47990
  output.push("");
47268
47991
  output.push("USAGE");
47269
47992
  output.push(
@@ -47982,7 +48705,7 @@ var contextSubcommands = {
47982
48705
  };
47983
48706
 
47984
48707
  // src/config/settings.ts
47985
- var import_yaml2 = __toESM(require_dist(), 1);
48708
+ var import_yaml3 = __toESM(require_dist(), 1);
47986
48709
  import { homedir as homedir3 } from "os";
47987
48710
  import { join as join3 } from "path";
47988
48711
  var LOGO_MODES = [
@@ -48013,7 +48736,7 @@ function loadSettingsSync() {
48013
48736
  configPath,
48014
48737
  "utf-8"
48015
48738
  );
48016
- const parsed = import_yaml2.default.parse(content);
48739
+ const parsed = import_yaml3.default.parse(content);
48017
48740
  return {
48018
48741
  ...DEFAULT_SETTINGS,
48019
48742
  ...validateSettings(parsed)
@@ -48880,6 +49603,34 @@ function calculateRegionalStatus(components) {
48880
49603
  }
48881
49604
 
48882
49605
  // src/domains/cloudstatus/index.ts
49606
+ function parseOutputArgs(args, session) {
49607
+ let format;
49608
+ let spec = false;
49609
+ const filteredArgs = [];
49610
+ for (let i = 0; i < args.length; i++) {
49611
+ const arg = args[i] ?? "";
49612
+ const nextArg = args[i + 1];
49613
+ if (arg === "--output" || arg === "-o") {
49614
+ if (nextArg) {
49615
+ format = parseOutputFormat(nextArg);
49616
+ i++;
49617
+ }
49618
+ } else if (arg === "--spec") {
49619
+ spec = true;
49620
+ } else if (arg.startsWith("--output=")) {
49621
+ format = parseOutputFormat(arg.split("=")[1] ?? "table");
49622
+ } else if (arg.startsWith("-o=")) {
49623
+ format = parseOutputFormat(arg.split("=")[1] ?? "table");
49624
+ } else {
49625
+ filteredArgs.push(arg);
49626
+ }
49627
+ }
49628
+ return {
49629
+ format: format ?? session.getOutputFormat(),
49630
+ spec,
49631
+ filteredArgs
49632
+ };
49633
+ }
48883
49634
  var cloudstatusClient = null;
48884
49635
  function getClient() {
48885
49636
  if (!cloudstatusClient) {
@@ -48895,8 +49646,14 @@ var statusCommand = {
48895
49646
  usage: "[--quiet]",
48896
49647
  aliases: ["st"],
48897
49648
  async execute(args, session) {
48898
- const quiet = args.includes("--quiet") || args.includes("-q");
48899
- const format = session.getOutputFormat();
49649
+ const { format, spec, filteredArgs } = parseOutputArgs(args, session);
49650
+ const quiet = filteredArgs.includes("--quiet") || filteredArgs.includes("-q");
49651
+ if (spec) {
49652
+ const cmdSpec = getCommandSpec("cloudstatus status");
49653
+ if (cmdSpec) {
49654
+ return successResult([formatSpec(cmdSpec)]);
49655
+ }
49656
+ }
48900
49657
  try {
48901
49658
  const client = getClient();
48902
49659
  const response = await client.getStatus();
@@ -48946,8 +49703,14 @@ var summaryCommand = {
48946
49703
  usage: "[--brief]",
48947
49704
  aliases: ["sum"],
48948
49705
  async execute(args, session) {
48949
- const brief = args.includes("--brief") || args.includes("-b");
48950
- const format = session.getOutputFormat();
49706
+ const { format, spec, filteredArgs } = parseOutputArgs(args, session);
49707
+ const brief = filteredArgs.includes("--brief") || filteredArgs.includes("-b");
49708
+ if (spec) {
49709
+ const cmdSpec = getCommandSpec("cloudstatus summary");
49710
+ if (cmdSpec) {
49711
+ return successResult([formatSpec(cmdSpec)]);
49712
+ }
49713
+ }
48951
49714
  try {
48952
49715
  const client = getClient();
48953
49716
  const response = await client.getSummary();
@@ -48975,8 +49738,14 @@ var componentsCommand = {
48975
49738
  usage: "[--degraded-only]",
48976
49739
  aliases: ["comp"],
48977
49740
  async execute(args, session) {
48978
- const degradedOnly = args.includes("--degraded-only") || args.includes("-d");
48979
- const format = session.getOutputFormat();
49741
+ const { format, spec, filteredArgs } = parseOutputArgs(args, session);
49742
+ const degradedOnly = filteredArgs.includes("--degraded-only") || filteredArgs.includes("-d");
49743
+ if (spec) {
49744
+ const cmdSpec = getCommandSpec("cloudstatus components");
49745
+ if (cmdSpec) {
49746
+ return successResult([formatSpec(cmdSpec)]);
49747
+ }
49748
+ }
48980
49749
  try {
48981
49750
  const client = getClient();
48982
49751
  const response = await client.getComponents();
@@ -49018,8 +49787,14 @@ var incidentsCommand = {
49018
49787
  usage: "[--active-only]",
49019
49788
  aliases: ["inc"],
49020
49789
  async execute(args, session) {
49021
- const activeOnly = args.includes("--active-only") || args.includes("-a");
49022
- const format = session.getOutputFormat();
49790
+ const { format, spec, filteredArgs } = parseOutputArgs(args, session);
49791
+ const activeOnly = filteredArgs.includes("--active-only") || filteredArgs.includes("-a");
49792
+ if (spec) {
49793
+ const cmdSpec = getCommandSpec("cloudstatus incidents");
49794
+ if (cmdSpec) {
49795
+ return successResult([formatSpec(cmdSpec)]);
49796
+ }
49797
+ }
49023
49798
  try {
49024
49799
  const client = getClient();
49025
49800
  const response = activeOnly ? await client.getUnresolvedIncidents() : await client.getIncidents();
@@ -49059,8 +49834,14 @@ var maintenanceCommand = {
49059
49834
  usage: "[--upcoming]",
49060
49835
  aliases: ["maint"],
49061
49836
  async execute(args, session) {
49062
- const upcomingOnly = args.includes("--upcoming") || args.includes("-u");
49063
- const format = session.getOutputFormat();
49837
+ const { format, spec, filteredArgs } = parseOutputArgs(args, session);
49838
+ const upcomingOnly = filteredArgs.includes("--upcoming") || filteredArgs.includes("-u");
49839
+ if (spec) {
49840
+ const cmdSpec = getCommandSpec("cloudstatus maintenance");
49841
+ if (cmdSpec) {
49842
+ return successResult([formatSpec(cmdSpec)]);
49843
+ }
49844
+ }
49064
49845
  try {
49065
49846
  const client = getClient();
49066
49847
  const response = upcomingOnly ? await client.getUpcomingMaintenances() : await client.getMaintenances();
@@ -49532,7 +50313,7 @@ _xcsh_completions() {
49532
50313
  local commands="${domainNames} ${allAliases.join(" ")} help quit exit clear history"
49533
50314
  local actions="${actions}"
49534
50315
  local builtins="help quit exit clear history context ctx"
49535
- local global_flags="--help -h --version -v --no-color --output -o --namespace -ns"
50316
+ local global_flags="--help -h --version -v --no-color --output -o --namespace -ns --spec"
49536
50317
 
49537
50318
  # Handle completion based on position
49538
50319
  case \${cword} in
@@ -49563,7 +50344,7 @@ ${customDomainCompletions.join("\n")}
49563
50344
  *)
49564
50345
  # Third+ word: flags
49565
50346
  if [[ "\${cur}" == -* ]]; then
49566
- local action_flags="--name -n --namespace -ns --output -o --json --yaml --limit --label"
50347
+ local action_flags="--name -n --namespace -ns --output -o --json --yaml --limit --label --spec"
49567
50348
  COMPREPLY=($(compgen -W "\${action_flags}" -- "\${cur}"))
49568
50349
  fi
49569
50350
  return 0
@@ -49617,6 +50398,7 @@ _xcsh() {
49617
50398
  '--no-color[Disable color output]'
49618
50399
  '(-o --output)'{-o,--output}'[Output format]:format:(json yaml table)'
49619
50400
  '(-ns --namespace)'{-ns,--namespace}'[Namespace]:namespace:_xcsh_namespaces'
50401
+ '--spec[Output command specification as JSON for AI assistants]'
49620
50402
  )
49621
50403
 
49622
50404
  _arguments -C \\
@@ -49667,6 +50449,7 @@ ${customDomainCompletions.join("\n")}
49667
50449
  '--limit[Maximum results]:limit:'
49668
50450
  '--label[Filter by label]:label:'
49669
50451
  '(-f --file)'{-f,--file}'[Configuration file]:file:_files'
50452
+ '--spec[Output command specification as JSON for AI assistants]'
49670
50453
  )
49671
50454
  _arguments "\${action_opts[@]}"
49672
50455
  ;;
@@ -49730,6 +50513,7 @@ complete -c xcsh -s v -l version -d 'Show version number'
49730
50513
  complete -c xcsh -l no-color -d 'Disable color output'
49731
50514
  complete -c xcsh -s o -l output -d 'Output format' -xa 'json yaml table'
49732
50515
  complete -c xcsh -l namespace -s ns -d 'Namespace' -xa 'default system shared'
50516
+ complete -c xcsh -l spec -d 'Output command specification as JSON for AI assistants'
49733
50517
 
49734
50518
  # Builtin commands
49735
50519
  complete -c xcsh -n "__fish_use_subcommand" -a "help" -d 'Show help information'
@@ -49759,6 +50543,7 @@ complete -c xcsh -l label -d 'Filter by label'
49759
50543
  complete -c xcsh -s f -l file -d 'Configuration file' -r
49760
50544
  complete -c xcsh -l force -d 'Force deletion'
49761
50545
  complete -c xcsh -l cascade -d 'Cascade delete'
50546
+ complete -c xcsh -l spec -d 'Output command specification as JSON for AI assistants'
49762
50547
  `;
49763
50548
  }
49764
50549
 
@@ -50925,219 +51710,6 @@ function useCompletion(options) {
50925
51710
  };
50926
51711
  }
50927
51712
 
50928
- // src/output/formatter.ts
50929
- var import_yaml3 = __toESM(require_dist(), 1);
50930
- function formatOutput(data, format = "yaml") {
50931
- if (format === "none") {
50932
- return "";
50933
- }
50934
- switch (format) {
50935
- case "json":
50936
- return formatJSON(data);
50937
- case "yaml":
50938
- return formatYAML(data);
50939
- case "table":
50940
- case "text":
50941
- return formatTable(data);
50942
- case "tsv":
50943
- return formatTSV(data);
50944
- default:
50945
- return formatYAML(data);
50946
- }
50947
- }
50948
- function formatJSON(data) {
50949
- return JSON.stringify(data, null, 2);
50950
- }
50951
- function formatYAML(data) {
50952
- return import_yaml3.default.stringify(data, { indent: 2 });
50953
- }
50954
- function extractItems(data) {
50955
- if (data && typeof data === "object" && "items" in data) {
50956
- const items = data.items;
50957
- if (Array.isArray(items)) {
50958
- return items.filter(
50959
- (item) => item !== null && typeof item === "object"
50960
- );
50961
- }
50962
- }
50963
- if (Array.isArray(data)) {
50964
- return data.filter(
50965
- (item) => item !== null && typeof item === "object"
50966
- );
50967
- }
50968
- if (data && typeof data === "object") {
50969
- return [data];
50970
- }
50971
- return [];
50972
- }
50973
- function getStringField(obj, key) {
50974
- const value = obj[key];
50975
- if (typeof value === "string") {
50976
- return value;
50977
- }
50978
- if (value !== null && value !== void 0) {
50979
- return String(value);
50980
- }
50981
- return "";
50982
- }
50983
- function formatLabels(obj) {
50984
- const labels = obj["labels"];
50985
- if (!labels || typeof labels !== "object") {
50986
- return "";
50987
- }
50988
- const labelMap = labels;
50989
- const entries = Object.entries(labelMap).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}:${v}`);
50990
- if (entries.length === 0) {
50991
- return "";
50992
- }
50993
- return `map[${entries.join(" ")}]`;
50994
- }
50995
- function wrapText3(text, maxWidth) {
50996
- if (text.length <= maxWidth) {
50997
- return [text];
50998
- }
50999
- const lines = [];
51000
- let remaining = text;
51001
- while (remaining.length > 0) {
51002
- if (remaining.length <= maxWidth) {
51003
- lines.push(remaining);
51004
- break;
51005
- }
51006
- let breakPoint = maxWidth;
51007
- for (let i = maxWidth - 1; i > 0; i--) {
51008
- if (remaining[i] === " ") {
51009
- breakPoint = i;
51010
- break;
51011
- }
51012
- }
51013
- lines.push(remaining.slice(0, breakPoint));
51014
- remaining = remaining.slice(breakPoint).trimStart();
51015
- }
51016
- return lines;
51017
- }
51018
- function formatTable(data) {
51019
- const items = extractItems(data);
51020
- if (items.length === 0) {
51021
- return "";
51022
- }
51023
- const headers = ["NAMESPACE", "NAME", "LABELS"];
51024
- const widths = [9, 27, 30];
51025
- const rows = [];
51026
- for (const item of items) {
51027
- const row = [
51028
- getStringField(item, "namespace") || "<None>",
51029
- getStringField(item, "name") || "<None>",
51030
- formatLabels(item) || "<None>"
51031
- ];
51032
- const wrappedCells = row.map((cell, i) => wrapText3(cell, widths[i]));
51033
- const maxLines = Math.max(...wrappedCells.map((c) => c.length));
51034
- const wrappedRows = [];
51035
- for (let line = 0; line < maxLines; line++) {
51036
- wrappedRows.push(wrappedCells.map((c) => c[line] ?? ""));
51037
- }
51038
- rows.push(wrappedRows);
51039
- }
51040
- const lines = [];
51041
- const boxLine = "+" + widths.map((w) => "-".repeat(w + 2)).join("+") + "+";
51042
- lines.push(boxLine);
51043
- lines.push(
51044
- "|" + headers.map((h, i) => {
51045
- const padding = widths[i] - h.length;
51046
- const leftPad = Math.floor(padding / 2);
51047
- const rightPad = padding - leftPad;
51048
- return " " + " ".repeat(leftPad) + h + " ".repeat(rightPad) + " ";
51049
- }).join("|") + "|"
51050
- );
51051
- lines.push(boxLine);
51052
- for (const wrappedRows of rows) {
51053
- for (const row of wrappedRows) {
51054
- lines.push(
51055
- "|" + row.map((cell, i) => {
51056
- const padding = widths[i] - cell.length;
51057
- return " " + cell + " ".repeat(padding) + " ";
51058
- }).join("|") + "|"
51059
- );
51060
- }
51061
- lines.push(boxLine);
51062
- }
51063
- return lines.join("\n");
51064
- }
51065
- function formatTSV(data) {
51066
- const items = extractItems(data);
51067
- if (items.length === 0) {
51068
- return "";
51069
- }
51070
- const allKeys = /* @__PURE__ */ new Set();
51071
- for (const item of items) {
51072
- Object.keys(item).forEach((k) => allKeys.add(k));
51073
- }
51074
- const priority = ["name", "namespace", "status", "created", "modified"];
51075
- const headers = [
51076
- ...priority.filter((p) => allKeys.has(p)),
51077
- ...[...allKeys].filter((k) => !priority.includes(k)).sort()
51078
- ];
51079
- const lines = [];
51080
- for (const item of items) {
51081
- const values = headers.map((h) => {
51082
- const val = item[h];
51083
- if (val === null || val === void 0) return "";
51084
- if (typeof val === "object") return JSON.stringify(val);
51085
- return String(val);
51086
- });
51087
- lines.push(values.join(" "));
51088
- }
51089
- return lines.join("\n");
51090
- }
51091
- function formatAPIError(statusCode, body, operation) {
51092
- const lines = [];
51093
- lines.push(`ERROR: ${operation} failed (HTTP ${statusCode})`);
51094
- if (body && typeof body === "object") {
51095
- const errResp = body;
51096
- if (errResp.message) {
51097
- lines.push(` Message: ${errResp.message}`);
51098
- }
51099
- if (errResp.code) {
51100
- lines.push(` Code: ${errResp.code}`);
51101
- }
51102
- if (errResp.details) {
51103
- lines.push(` Details: ${errResp.details}`);
51104
- }
51105
- }
51106
- switch (statusCode) {
51107
- case 401:
51108
- lines.push(
51109
- "\nHint: Authentication failed. Check your credentials with 'login profile show'"
51110
- );
51111
- break;
51112
- case 403:
51113
- lines.push(
51114
- "\nHint: Permission denied. You may not have access to this resource."
51115
- );
51116
- break;
51117
- case 404:
51118
- lines.push(
51119
- "\nHint: Resource not found. Verify the name and namespace are correct."
51120
- );
51121
- break;
51122
- case 409:
51123
- lines.push(
51124
- "\nHint: Conflict - resource may already exist or be in a conflicting state."
51125
- );
51126
- break;
51127
- case 429:
51128
- lines.push("\nHint: Rate limited. Please wait and try again.");
51129
- break;
51130
- case 500:
51131
- case 502:
51132
- case 503:
51133
- lines.push(
51134
- "\nHint: Server error. Please try again later or contact support."
51135
- );
51136
- break;
51137
- }
51138
- return lines.join("\n");
51139
- }
51140
-
51141
51713
  // src/repl/executor.ts
51142
51714
  var BUILTIN_COMMANDS = /* @__PURE__ */ new Set([
51143
51715
  "help",
@@ -51687,34 +52259,66 @@ function domainToResourcePath(domain) {
51687
52259
  function parseCommandArgs(args) {
51688
52260
  let name;
51689
52261
  let namespace;
52262
+ let outputFormat;
52263
+ let spec = false;
52264
+ let noColor = false;
51690
52265
  for (let i = 0; i < args.length; i++) {
51691
52266
  const arg = args[i] ?? "";
51692
52267
  if (arg.startsWith("--")) {
51693
- const flagName = arg.slice(2);
52268
+ const flagName = arg.slice(2).toLowerCase();
51694
52269
  const nextArg = args[i + 1];
51695
- if (flagName === "namespace" || flagName === "ns") {
51696
- namespace = nextArg;
51697
- i++;
51698
- } else if (flagName === "name") {
51699
- name = nextArg;
51700
- i++;
51701
- } else if (nextArg && !nextArg.startsWith("--")) {
51702
- i++;
52270
+ switch (flagName) {
52271
+ case "namespace":
52272
+ case "ns":
52273
+ namespace = nextArg;
52274
+ i++;
52275
+ break;
52276
+ case "name":
52277
+ name = nextArg;
52278
+ i++;
52279
+ break;
52280
+ case "output":
52281
+ if (nextArg) {
52282
+ outputFormat = parseOutputFormat(nextArg);
52283
+ i++;
52284
+ }
52285
+ break;
52286
+ case "spec":
52287
+ spec = true;
52288
+ break;
52289
+ case "no-color":
52290
+ noColor = true;
52291
+ break;
52292
+ default:
52293
+ if (nextArg && !nextArg.startsWith("--")) {
52294
+ i++;
52295
+ }
51703
52296
  }
51704
52297
  } else if (arg.startsWith("-")) {
51705
52298
  const flagName = arg.slice(1);
51706
52299
  const nextArg = args[i + 1];
51707
- if (flagName === "n") {
51708
- namespace = nextArg;
51709
- i++;
51710
- } else if (nextArg && !nextArg.startsWith("-")) {
51711
- i++;
52300
+ switch (flagName) {
52301
+ case "n":
52302
+ case "ns":
52303
+ namespace = nextArg;
52304
+ i++;
52305
+ break;
52306
+ case "o":
52307
+ if (nextArg) {
52308
+ outputFormat = parseOutputFormat(nextArg);
52309
+ i++;
52310
+ }
52311
+ break;
52312
+ default:
52313
+ if (nextArg && !nextArg.startsWith("-")) {
52314
+ i++;
52315
+ }
51712
52316
  }
51713
52317
  } else if (!name) {
51714
52318
  name = arg;
51715
52319
  }
51716
52320
  }
51717
- return { name, namespace };
52321
+ return { name, namespace, outputFormat, spec, noColor };
51718
52322
  }
51719
52323
  async function executeAPICommand(session, ctx, cmd) {
51720
52324
  const client = session.getAPIClient();
@@ -51763,8 +52367,51 @@ async function executeAPICommand(session, ctx, cmd) {
51763
52367
  }
51764
52368
  }
51765
52369
  const canonicalDomain = resolveDomain(domain) ?? domain;
51766
- const { name, namespace } = parseCommandArgs(args);
52370
+ const { name, namespace, outputFormat, spec, noColor } = parseCommandArgs(args);
51767
52371
  const effectiveNamespace = namespace ?? session.getNamespace();
52372
+ if (spec) {
52373
+ const commandPath = `${canonicalDomain} ${action}`;
52374
+ const cmdSpec = getCommandSpec(commandPath);
52375
+ if (cmdSpec) {
52376
+ return {
52377
+ output: [formatSpec(cmdSpec)],
52378
+ shouldExit: false,
52379
+ shouldClear: false,
52380
+ contextChanged: false
52381
+ };
52382
+ }
52383
+ const basicSpec = {
52384
+ command: `${CLI_NAME} ${canonicalDomain} ${action}`,
52385
+ description: `Execute ${action} on ${canonicalDomain} resources`,
52386
+ usage: `${CLI_NAME} ${canonicalDomain} ${action} [name] [options]`,
52387
+ flags: [
52388
+ {
52389
+ name: "--namespace",
52390
+ alias: "-ns",
52391
+ type: "string",
52392
+ description: "Target namespace"
52393
+ },
52394
+ {
52395
+ name: "--output",
52396
+ alias: "-o",
52397
+ type: "string",
52398
+ description: "Output format (json, yaml, table)"
52399
+ },
52400
+ {
52401
+ name: "--name",
52402
+ type: "string",
52403
+ description: "Resource name"
52404
+ }
52405
+ ],
52406
+ outputFormats: ["table", "json", "yaml"]
52407
+ };
52408
+ return {
52409
+ output: [JSON.stringify(basicSpec, null, 2)],
52410
+ shouldExit: false,
52411
+ shouldClear: false,
52412
+ contextChanged: false
52413
+ };
52414
+ }
51768
52415
  const resourcePath = domainToResourcePath(canonicalDomain);
51769
52416
  let apiPath = `/api/config/namespaces/${effectiveNamespace}/${resourcePath}`;
51770
52417
  try {
@@ -51849,8 +52496,8 @@ async function executeAPICommand(session, ctx, cmd) {
51849
52496
  };
51850
52497
  }
51851
52498
  }
51852
- const outputFormat = session.getOutputFormat();
51853
- const formatted = formatOutput(result, outputFormat);
52499
+ const effectiveFormat = outputFormat ?? session.getOutputFormat();
52500
+ const formatted = formatOutput(result, effectiveFormat, noColor);
51854
52501
  return {
51855
52502
  output: formatted ? [formatted] : ["(no output)"],
51856
52503
  shouldExit: false,
@@ -52241,7 +52888,7 @@ var program2 = new Command();
52241
52888
  program2.configureHelp({
52242
52889
  formatHelp: () => formatRootHelp().join("\n")
52243
52890
  });
52244
- program2.name(CLI_NAME).description("F5 Distributed Cloud Shell - Interactive CLI for F5 XC").version(CLI_VERSION, "-v, --version", "Show version number").option("--no-color", "Disable color output").option("--logo <mode>", "Logo display mode: image, ascii, none").option("-h, --help", "Show help").argument("[command...]", "Command to execute non-interactively").allowUnknownOption(true).helpOption(false).action(
52891
+ program2.name(CLI_NAME).description("F5 Distributed Cloud Shell - Interactive CLI for F5 XC").version(CLI_VERSION, "-v, --version", "Show version number").option("--no-color", "Disable color output").option("--logo <mode>", "Logo display mode: image, ascii, none").option("-o, --output <format>", "Output format (json, yaml, table)").option("--spec", "Output command specification as JSON (for AI)").option("-h, --help", "Show help").argument("[command...]", "Command to execute non-interactively").allowUnknownOption(true).helpOption(false).action(
52245
52892
  async (commandArgs, options) => {
52246
52893
  if (options.help && commandArgs.length === 0) {
52247
52894
  formatRootHelp().forEach((line) => console.log(line));
@@ -52253,6 +52900,12 @@ program2.name(CLI_NAME).description("F5 Distributed Cloud Shell - Interactive CL
52253
52900
  if (options.logo && commandArgs.length > 0) {
52254
52901
  commandArgs.push("--logo", options.logo);
52255
52902
  }
52903
+ if (options.output && commandArgs.length > 0) {
52904
+ commandArgs.push("--output", options.output);
52905
+ }
52906
+ if (options.spec && commandArgs.length > 0) {
52907
+ commandArgs.push("--spec");
52908
+ }
52256
52909
  if (commandArgs.length === 0) {
52257
52910
  if (!process.stdin.isTTY) {
52258
52911
  console.error(