@robinmordasiewicz/f5xc-xcsh 6.35.0 → 6.36.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.
Files changed (2) hide show
  1. package/dist/index.js +675 -640
  2. package/package.json +1 -1
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.35.0") {
45358
- return "6.35.0";
45357
+ if ("6.36.0") {
45358
+ return "6.36.0";
45359
45359
  }
45360
45360
  if (process.env.XCSH_VERSION) {
45361
45361
  return process.env.XCSH_VERSION;
@@ -46843,6 +46843,452 @@ function useHistory(options) {
46843
46843
  // src/repl/hooks/useCompletion.ts
46844
46844
  var import_react27 = __toESM(require_react(), 1);
46845
46845
 
46846
+ // src/config/envvars.ts
46847
+ var EnvVarRegistry = [
46848
+ {
46849
+ name: `${ENV_PREFIX}_API_URL`,
46850
+ description: "API endpoint URL",
46851
+ relatedFlag: "",
46852
+ required: true
46853
+ },
46854
+ {
46855
+ name: `${ENV_PREFIX}_API_TOKEN`,
46856
+ description: "API authentication token",
46857
+ relatedFlag: "",
46858
+ required: true
46859
+ },
46860
+ {
46861
+ name: `${ENV_PREFIX}_NAMESPACE`,
46862
+ description: "Default namespace",
46863
+ relatedFlag: "-ns"
46864
+ },
46865
+ {
46866
+ name: `${ENV_PREFIX}_OUTPUT_FORMAT`,
46867
+ description: "Output format (json, yaml, table)",
46868
+ relatedFlag: "-o"
46869
+ },
46870
+ {
46871
+ name: `${ENV_PREFIX}_LOGO`,
46872
+ description: "Logo display mode (auto, image, ascii, both, none)",
46873
+ relatedFlag: "--logo"
46874
+ },
46875
+ {
46876
+ name: "NO_COLOR",
46877
+ description: "Disable color output",
46878
+ relatedFlag: "--no-color"
46879
+ }
46880
+ ];
46881
+ function formatEnvVarsSection() {
46882
+ const maxLen = Math.max(...EnvVarRegistry.map((e) => e.name.length));
46883
+ const lines = ["ENVIRONMENT VARIABLES"];
46884
+ for (const env3 of EnvVarRegistry) {
46885
+ const padding = " ".repeat(maxLen - env3.name.length + 3);
46886
+ const flagNote = env3.relatedFlag ? ` [${env3.relatedFlag}]` : "";
46887
+ lines.push(` ${env3.name}${padding}${env3.description}${flagNote}`);
46888
+ }
46889
+ return lines;
46890
+ }
46891
+ function formatConfigSection() {
46892
+ return [
46893
+ "CONFIGURATION",
46894
+ ` Config file: ~/${CONFIG_FILE_NAME}`,
46895
+ " Priority: CLI flags > environment variables > config file > defaults",
46896
+ "",
46897
+ "DOCUMENTATION",
46898
+ ` ${DOCS_URL}`
46899
+ ];
46900
+ }
46901
+
46902
+ // src/repl/help.ts
46903
+ function wrapText2(text, width, indent) {
46904
+ const prefix = " ".repeat(indent);
46905
+ const words = text.split(/\s+/);
46906
+ const lines = [];
46907
+ let currentLine = prefix;
46908
+ for (const word of words) {
46909
+ if (currentLine.length + word.length + 1 > width && currentLine !== prefix) {
46910
+ lines.push(currentLine);
46911
+ currentLine = prefix + word;
46912
+ } else {
46913
+ currentLine += (currentLine === prefix ? "" : " ") + word;
46914
+ }
46915
+ }
46916
+ if (currentLine.trim()) {
46917
+ lines.push(currentLine);
46918
+ }
46919
+ return lines;
46920
+ }
46921
+ function formatRootHelp() {
46922
+ return [
46923
+ "",
46924
+ colorBoldWhite(`${CLI_NAME} - ${CLI_FULL_NAME} v${CLI_VERSION}`),
46925
+ "",
46926
+ "DESCRIPTION",
46927
+ ...wrapText2(CLI_DESCRIPTION_LONG, 80, 2),
46928
+ "",
46929
+ "USAGE",
46930
+ ` ${CLI_NAME} Enter interactive REPL mode`,
46931
+ ` ${CLI_NAME} <domain> <action> Execute command non-interactively`,
46932
+ ` ${CLI_NAME} help [topic] Show help for a topic`,
46933
+ "",
46934
+ "EXAMPLES",
46935
+ ` ${CLI_NAME} tenant_and_identity list namespace List all namespaces`,
46936
+ ` ${CLI_NAME} virtual get http_loadbalancer Get a specific load balancer`,
46937
+ ` ${CLI_NAME} dns list List DNS zones`,
46938
+ ` ${CLI_NAME} waf list -ns prod List WAF policies in prod`,
46939
+ ` ${CLI_NAME} --interactive Force interactive REPL mode`,
46940
+ "",
46941
+ ...formatDomainsSection(),
46942
+ "",
46943
+ ...formatGlobalFlags(),
46944
+ "",
46945
+ ...formatEnvVarsSection(),
46946
+ "",
46947
+ ...formatConfigSection(),
46948
+ "",
46949
+ "NAVIGATION (Interactive Mode)",
46950
+ " <domain> Navigate into a domain (e.g., 'dns', 'lb')",
46951
+ " /domain Navigate directly to domain from anywhere",
46952
+ " .. Go up one level",
46953
+ " / Return to root",
46954
+ " context Show current navigation context",
46955
+ "",
46956
+ "BUILTINS",
46957
+ " help Show this help",
46958
+ " domains List all available domains",
46959
+ " clear Clear the screen",
46960
+ " history Show command history",
46961
+ " quit, exit Exit the shell",
46962
+ ""
46963
+ ];
46964
+ }
46965
+ function formatGlobalFlags() {
46966
+ return [
46967
+ "GLOBAL FLAGS",
46968
+ " -v, --version Show version number",
46969
+ " -h, --help Show this help",
46970
+ " -i, --interactive Force interactive mode",
46971
+ " --no-color Disable color output",
46972
+ " -o, --output <fmt> Output format (json, yaml, table)",
46973
+ " -ns, --namespace <ns> Target namespace"
46974
+ ];
46975
+ }
46976
+ function formatEnvironmentVariables() {
46977
+ return formatEnvVarsSection();
46978
+ }
46979
+ function formatDomainHelp(domain) {
46980
+ const output = ["", colorBoldWhite(`${domain.displayName}`), ""];
46981
+ output.push(` ${domain.description}`);
46982
+ output.push("");
46983
+ if (domain.category || domain.complexity) {
46984
+ const meta = [];
46985
+ if (domain.category) meta.push(`Category: ${domain.category}`);
46986
+ if (domain.complexity) meta.push(`Complexity: ${domain.complexity}`);
46987
+ output.push(colorDim(` ${meta.join(" | ")}`));
46988
+ output.push("");
46989
+ }
46990
+ output.push("USAGE");
46991
+ output.push(` ${CLI_NAME} ${domain.name} <action> [options]`);
46992
+ output.push("");
46993
+ output.push("ACTIONS");
46994
+ const actionDescriptions2 = {
46995
+ list: "List resources",
46996
+ get: "Get a specific resource by name",
46997
+ create: "Create a new resource",
46998
+ delete: "Delete a resource",
46999
+ replace: "Replace a resource configuration",
47000
+ apply: "Apply configuration from file",
47001
+ status: "Get resource status",
47002
+ patch: "Patch a resource",
47003
+ "add-labels": "Add labels to a resource",
47004
+ "remove-labels": "Remove labels from a resource"
47005
+ };
47006
+ for (const action of validActions) {
47007
+ const desc = actionDescriptions2[action] ?? action;
47008
+ output.push(` ${action.padEnd(16)} ${desc}`);
47009
+ }
47010
+ output.push("");
47011
+ output.push("EXAMPLES");
47012
+ output.push(` ${CLI_NAME} ${domain.name} list`);
47013
+ output.push(` ${CLI_NAME} ${domain.name} get my-resource`);
47014
+ output.push(
47015
+ ` ${CLI_NAME} ${domain.name} create my-resource -f config.yaml`
47016
+ );
47017
+ output.push(` ${CLI_NAME} ${domain.name} delete my-resource`);
47018
+ output.push("");
47019
+ if (domain.useCases && domain.useCases.length > 0) {
47020
+ output.push("USE CASES");
47021
+ for (const useCase of domain.useCases.slice(0, 5)) {
47022
+ output.push(` - ${useCase}`);
47023
+ }
47024
+ output.push("");
47025
+ }
47026
+ if (domain.relatedDomains && domain.relatedDomains.length > 0) {
47027
+ output.push("RELATED DOMAINS");
47028
+ output.push(` ${domain.relatedDomains.join(", ")}`);
47029
+ output.push("");
47030
+ }
47031
+ if (domain.aliases && domain.aliases.length > 0) {
47032
+ output.push("ALIASES");
47033
+ output.push(` ${domain.aliases.join(", ")}`);
47034
+ output.push("");
47035
+ }
47036
+ output.push(colorDim(`For global options, run: ${CLI_NAME} --help`));
47037
+ output.push("");
47038
+ return output;
47039
+ }
47040
+ function formatActionHelp(domainName, action) {
47041
+ const domain = getDomainInfo(domainName);
47042
+ const displayDomain = domain?.displayName ?? domainName;
47043
+ const actionDescriptions2 = {
47044
+ list: {
47045
+ desc: "List all resources in the namespace",
47046
+ usage: `${CLI_NAME} ${domainName} list [--limit N] [--label key=value]`
47047
+ },
47048
+ get: {
47049
+ desc: "Get a specific resource by name",
47050
+ usage: `${CLI_NAME} ${domainName} get <name> [-o json|yaml|table]`
47051
+ },
47052
+ create: {
47053
+ desc: "Create a new resource",
47054
+ usage: `${CLI_NAME} ${domainName} create <name> -f <file.yaml>`
47055
+ },
47056
+ delete: {
47057
+ desc: "Delete a resource by name",
47058
+ usage: `${CLI_NAME} ${domainName} delete <name>`
47059
+ },
47060
+ replace: {
47061
+ desc: "Replace an existing resource configuration",
47062
+ usage: `${CLI_NAME} ${domainName} replace <name> -f <file.yaml>`
47063
+ },
47064
+ apply: {
47065
+ desc: "Apply configuration from a file (create or update)",
47066
+ usage: `${CLI_NAME} ${domainName} apply -f <file.yaml>`
47067
+ },
47068
+ status: {
47069
+ desc: "Get the current status of a resource",
47070
+ usage: `${CLI_NAME} ${domainName} status <name>`
47071
+ },
47072
+ patch: {
47073
+ desc: "Patch specific fields of a resource",
47074
+ usage: `${CLI_NAME} ${domainName} patch <name> -f <patch.yaml>`
47075
+ },
47076
+ "add-labels": {
47077
+ desc: "Add labels to a resource",
47078
+ usage: `${CLI_NAME} ${domainName} add-labels <name> key=value`
47079
+ },
47080
+ "remove-labels": {
47081
+ desc: "Remove labels from a resource",
47082
+ usage: `${CLI_NAME} ${domainName} remove-labels <name> key`
47083
+ }
47084
+ };
47085
+ const actionInfo = actionDescriptions2[action] ?? {
47086
+ desc: `Execute ${action} operation`,
47087
+ usage: `${CLI_NAME} ${domainName} ${action} [options]`
47088
+ };
47089
+ return [
47090
+ "",
47091
+ colorBoldWhite(`${displayDomain} - ${action}`),
47092
+ "",
47093
+ ` ${actionInfo.desc}`,
47094
+ "",
47095
+ "USAGE",
47096
+ ` ${actionInfo.usage}`,
47097
+ "",
47098
+ "OPTIONS",
47099
+ " -n, --name <name> Resource name",
47100
+ " -ns, --namespace <ns> Target namespace",
47101
+ " -o, --output <fmt> Output format (json, yaml, table)",
47102
+ " -f, --file <path> Configuration file",
47103
+ "",
47104
+ colorDim(`For domain help, run: ${CLI_NAME} ${domainName} --help`),
47105
+ ""
47106
+ ];
47107
+ }
47108
+ function formatTopicHelp(topic) {
47109
+ const lowerTopic = topic.toLowerCase();
47110
+ const domainInfo = getDomainInfo(lowerTopic);
47111
+ if (domainInfo) {
47112
+ return formatDomainHelp(domainInfo);
47113
+ }
47114
+ switch (lowerTopic) {
47115
+ case "domains":
47116
+ return formatDomainsHelp();
47117
+ case "actions":
47118
+ return formatActionsHelp();
47119
+ case "navigation":
47120
+ case "nav":
47121
+ return formatNavigationHelp();
47122
+ case "env":
47123
+ case "environment":
47124
+ return ["", ...formatEnvironmentVariables(), ""];
47125
+ case "flags":
47126
+ return ["", ...formatGlobalFlags(), ""];
47127
+ default:
47128
+ return [
47129
+ "",
47130
+ `Unknown help topic: ${topic}`,
47131
+ "",
47132
+ "Available topics:",
47133
+ " domains List all available domains",
47134
+ " actions List available actions",
47135
+ " navigation Navigation commands",
47136
+ " env Environment variables",
47137
+ " flags Global flags",
47138
+ " <domain> Help for a specific domain (e.g., 'help dns')",
47139
+ ""
47140
+ ];
47141
+ }
47142
+ }
47143
+ function formatDomainsHelp() {
47144
+ const output = ["", colorBoldWhite("Available Domains"), ""];
47145
+ const categories = /* @__PURE__ */ new Map();
47146
+ for (const domain of domainRegistry.values()) {
47147
+ const category = domain.category ?? "Other";
47148
+ if (!categories.has(category)) {
47149
+ categories.set(category, []);
47150
+ }
47151
+ categories.get(category)?.push(domain);
47152
+ }
47153
+ const sortedCategories = Array.from(categories.keys()).sort();
47154
+ for (const category of sortedCategories) {
47155
+ const domains = categories.get(category) ?? [];
47156
+ output.push(colorBoldWhite(` ${category}`));
47157
+ for (const domain of domains.sort(
47158
+ (a, b) => a.name.localeCompare(b.name)
47159
+ )) {
47160
+ const aliases = domain.aliases.length > 0 ? colorDim(` (${domain.aliases.join(", ")})`) : "";
47161
+ output.push(
47162
+ ` ${domain.name.padEnd(24)} ${domain.descriptionShort}`
47163
+ );
47164
+ if (aliases) {
47165
+ output.push(` ${"".padEnd(24)} Aliases:${aliases}`);
47166
+ }
47167
+ }
47168
+ output.push("");
47169
+ }
47170
+ return output;
47171
+ }
47172
+ function formatActionsHelp() {
47173
+ return [
47174
+ "",
47175
+ colorBoldWhite("Available Actions"),
47176
+ "",
47177
+ " list List all resources in the namespace",
47178
+ " get Get a specific resource by name",
47179
+ " create Create a new resource from a file",
47180
+ " delete Delete a resource by name",
47181
+ " replace Replace a resource configuration",
47182
+ " apply Apply configuration (create or update)",
47183
+ " status Get resource status",
47184
+ " patch Patch specific fields of a resource",
47185
+ " add-labels Add labels to a resource",
47186
+ " remove-labels Remove labels from a resource",
47187
+ "",
47188
+ "USAGE",
47189
+ ` ${CLI_NAME} <domain> <action> [options]`,
47190
+ "",
47191
+ "EXAMPLES",
47192
+ ` ${CLI_NAME} dns list`,
47193
+ ` ${CLI_NAME} lb get my-loadbalancer`,
47194
+ ` ${CLI_NAME} waf create my-policy -f policy.yaml`,
47195
+ ""
47196
+ ];
47197
+ }
47198
+ function formatNavigationHelp() {
47199
+ return [
47200
+ "",
47201
+ colorBoldWhite("Navigation Commands"),
47202
+ "",
47203
+ " <domain> Navigate into a domain context",
47204
+ " /<domain> Navigate directly to domain from anywhere",
47205
+ " .. Go up one level in context",
47206
+ " / Return to root context",
47207
+ " back Go up one level (same as ..)",
47208
+ " root Return to root (same as /)",
47209
+ "",
47210
+ "CONTEXT DISPLAY",
47211
+ " context Show current navigation context",
47212
+ " ctx Alias for context",
47213
+ "",
47214
+ "EXAMPLES",
47215
+ " xcsh> dns # Enter dns domain",
47216
+ " dns> list # Execute list in dns context",
47217
+ " dns> .. # Return to root",
47218
+ " xcsh> /waf # Jump directly to waf",
47219
+ " waf> /dns # Jump from waf to dns",
47220
+ ""
47221
+ ];
47222
+ }
47223
+ function formatDomainsSection() {
47224
+ const output = ["DOMAINS"];
47225
+ const domains = Array.from(domainRegistry.values()).sort(
47226
+ (a, b) => a.name.localeCompare(b.name)
47227
+ );
47228
+ const maxNameLen = Math.max(...domains.map((d) => d.name.length));
47229
+ for (const domain of domains) {
47230
+ const padding = " ".repeat(maxNameLen - domain.name.length + 2);
47231
+ output.push(` ${domain.name}${padding}${domain.descriptionShort}`);
47232
+ }
47233
+ return output;
47234
+ }
47235
+ function formatCustomDomainHelp(domain) {
47236
+ const output = ["", colorBoldWhite(domain.name), ""];
47237
+ output.push("DESCRIPTION");
47238
+ output.push(...wrapText2(domain.description, 80, 2));
47239
+ output.push("");
47240
+ output.push("USAGE");
47241
+ output.push(` ${CLI_NAME} ${domain.name} <command> [options]`);
47242
+ output.push("");
47243
+ if (domain.subcommands.size > 0) {
47244
+ output.push("SUBCOMMANDS");
47245
+ for (const [name, group] of domain.subcommands) {
47246
+ output.push(` ${name.padEnd(16)} ${group.descriptionShort}`);
47247
+ }
47248
+ output.push("");
47249
+ }
47250
+ if (domain.commands.size > 0) {
47251
+ output.push("COMMANDS");
47252
+ for (const [name, cmd] of domain.commands) {
47253
+ output.push(` ${name.padEnd(16)} ${cmd.descriptionShort}`);
47254
+ }
47255
+ output.push("");
47256
+ }
47257
+ output.push(colorDim(`For global options, run: ${CLI_NAME} --help`));
47258
+ output.push("");
47259
+ return output;
47260
+ }
47261
+ function formatSubcommandHelp(domainName, subcommand) {
47262
+ const output = [
47263
+ "",
47264
+ colorBoldWhite(`${domainName} ${subcommand.name}`),
47265
+ ""
47266
+ ];
47267
+ output.push("DESCRIPTION");
47268
+ output.push(...wrapText2(subcommand.description, 80, 2));
47269
+ output.push("");
47270
+ output.push("USAGE");
47271
+ output.push(
47272
+ ` ${CLI_NAME} ${domainName} ${subcommand.name} <command> [options]`
47273
+ );
47274
+ output.push("");
47275
+ if (subcommand.commands.size > 0) {
47276
+ output.push("COMMANDS");
47277
+ for (const [name, cmd] of subcommand.commands) {
47278
+ const usage = cmd.usage ? ` ${cmd.usage}` : "";
47279
+ output.push(
47280
+ ` ${name}${usage.padEnd(16 - name.length)} ${cmd.descriptionShort}`
47281
+ );
47282
+ }
47283
+ output.push("");
47284
+ }
47285
+ output.push(
47286
+ colorDim(`For domain help, run: ${CLI_NAME} ${domainName} --help`)
47287
+ );
47288
+ output.push("");
47289
+ return output;
47290
+ }
47291
+
46846
47292
  // src/domains/registry.ts
46847
47293
  var DomainRegistry = class {
46848
47294
  domains = /* @__PURE__ */ new Map();
@@ -47024,45 +47470,24 @@ var DomainRegistry = class {
47024
47470
  return suggestions;
47025
47471
  }
47026
47472
  /**
47027
- * Show help for a domain
47473
+ * Show help for a domain using the unified help formatter.
47474
+ * This ensures consistent professional formatting across all domains.
47028
47475
  */
47029
47476
  showDomainHelp(domain) {
47030
- const output = [`${domain.name} - ${domain.description}`, ``];
47031
- if (domain.subcommands.size > 0) {
47032
- output.push(`Subcommands:`);
47033
- for (const [name, group] of domain.subcommands) {
47034
- output.push(` ${name} ${group.description}`);
47035
- }
47036
- output.push(``);
47037
- }
47038
- if (domain.commands.size > 0) {
47039
- output.push(`Commands:`);
47040
- for (const [name, cmd] of domain.commands) {
47041
- output.push(` ${name} ${cmd.description}`);
47042
- }
47043
- }
47044
47477
  return {
47045
- output,
47478
+ output: formatCustomDomainHelp(domain),
47046
47479
  shouldExit: false,
47047
47480
  shouldClear: false,
47048
47481
  contextChanged: false
47049
47482
  };
47050
47483
  }
47051
47484
  /**
47052
- * Show help for a subcommand group
47485
+ * Show help for a subcommand group using the unified help formatter.
47486
+ * This ensures consistent professional formatting across all subcommands.
47053
47487
  */
47054
47488
  showSubcommandHelp(domain, subgroup) {
47055
- const output = [
47056
- `${domain.name} ${subgroup.name} - ${subgroup.description}`,
47057
- ``,
47058
- `Commands:`
47059
- ];
47060
- for (const [name, cmd] of subgroup.commands) {
47061
- const usage = cmd.usage ? ` ${cmd.usage}` : "";
47062
- output.push(` ${name}${usage} ${cmd.description}`);
47063
- }
47064
47489
  return {
47065
- output,
47490
+ output: formatSubcommandHelp(domain.name, subgroup),
47066
47491
  shouldExit: false,
47067
47492
  shouldClear: false,
47068
47493
  contextChanged: false
@@ -47542,77 +47967,21 @@ var listCommand2 = {
47542
47967
  return successResult(lines);
47543
47968
  } catch (error) {
47544
47969
  const message = error instanceof Error ? error.message : String(error);
47545
- return errorResult(`Failed to list namespaces: ${message}`);
47546
- }
47547
- }
47548
- };
47549
- var contextSubcommands = {
47550
- name: "context",
47551
- description: "Manage default namespace context for scoping operations. Set, display, and list namespaces to control which namespace is used when no explicit namespace is specified in commands.",
47552
- descriptionShort: "Manage default namespace context",
47553
- descriptionMedium: "Set, display, and list namespaces for scoping operations without explicit namespace flags.",
47554
- commands: /* @__PURE__ */ new Map([
47555
- ["show", showCommand2],
47556
- ["set", setCommand],
47557
- ["list", listCommand2]
47558
- ])
47559
- };
47560
-
47561
- // src/config/envvars.ts
47562
- var EnvVarRegistry = [
47563
- {
47564
- name: `${ENV_PREFIX}_API_URL`,
47565
- description: "API endpoint URL",
47566
- relatedFlag: "",
47567
- required: true
47568
- },
47569
- {
47570
- name: `${ENV_PREFIX}_API_TOKEN`,
47571
- description: "API authentication token",
47572
- relatedFlag: "",
47573
- required: true
47574
- },
47575
- {
47576
- name: `${ENV_PREFIX}_NAMESPACE`,
47577
- description: "Default namespace",
47578
- relatedFlag: "-ns"
47579
- },
47580
- {
47581
- name: `${ENV_PREFIX}_OUTPUT_FORMAT`,
47582
- description: "Output format (json, yaml, table)",
47583
- relatedFlag: "-o"
47584
- },
47585
- {
47586
- name: `${ENV_PREFIX}_LOGO`,
47587
- description: "Logo display mode (auto, image, ascii, both, none)",
47588
- relatedFlag: "--logo"
47589
- },
47590
- {
47591
- name: "NO_COLOR",
47592
- description: "Disable color output",
47593
- relatedFlag: "--no-color"
47594
- }
47595
- ];
47596
- function formatEnvVarsSection() {
47597
- const maxLen = Math.max(...EnvVarRegistry.map((e) => e.name.length));
47598
- const lines = ["ENVIRONMENT VARIABLES"];
47599
- for (const env3 of EnvVarRegistry) {
47600
- const padding = " ".repeat(maxLen - env3.name.length + 3);
47601
- const flagNote = env3.relatedFlag ? ` [${env3.relatedFlag}]` : "";
47602
- lines.push(` ${env3.name}${padding}${env3.description}${flagNote}`);
47970
+ return errorResult(`Failed to list namespaces: ${message}`);
47971
+ }
47603
47972
  }
47604
- return lines;
47605
- }
47606
- function formatConfigSection() {
47607
- return [
47608
- "CONFIGURATION",
47609
- ` Config file: ~/${CONFIG_FILE_NAME}`,
47610
- " Priority: CLI flags > environment variables > config file > defaults",
47611
- "",
47612
- "DOCUMENTATION",
47613
- ` ${DOCS_URL}`
47614
- ];
47615
- }
47973
+ };
47974
+ var contextSubcommands = {
47975
+ name: "context",
47976
+ description: "Manage default namespace context for scoping operations. Set, display, and list namespaces to control which namespace is used when no explicit namespace is specified in commands.",
47977
+ descriptionShort: "Manage default namespace context",
47978
+ descriptionMedium: "Set, display, and list namespaces for scoping operations without explicit namespace flags.",
47979
+ commands: /* @__PURE__ */ new Map([
47980
+ ["show", showCommand2],
47981
+ ["set", setCommand],
47982
+ ["list", listCommand2]
47983
+ ])
47984
+ };
47616
47985
 
47617
47986
  // src/config/settings.ts
47618
47987
  var import_yaml2 = __toESM(require_dist(), 1);
@@ -50539,572 +50908,238 @@ function useCompletion(options) {
50539
50908
  if (!isShowing || suggestions.length === 0) return;
50540
50909
  setSelectedIndex(
50541
50910
  (current) => current < suggestions.length - 1 ? current + 1 : 0
50542
- );
50543
- }, [isShowing, suggestions.length]);
50544
- const selectCurrent = (0, import_react27.useCallback)(() => {
50545
- if (!isShowing || suggestions.length === 0) return null;
50546
- const selected = suggestions.at(selectedIndex);
50547
- hide();
50548
- return selected ?? null;
50549
- }, [isShowing, suggestions, selectedIndex, hide]);
50550
- return {
50551
- suggestions,
50552
- selectedIndex,
50553
- isShowing,
50554
- triggerCompletion,
50555
- navigateUp,
50556
- navigateDown,
50557
- selectCurrent,
50558
- hide,
50559
- filterSuggestions
50560
- };
50561
- }
50562
-
50563
- // src/output/formatter.ts
50564
- var import_yaml3 = __toESM(require_dist(), 1);
50565
- function formatOutput(data, format = "yaml") {
50566
- if (format === "none") {
50567
- return "";
50568
- }
50569
- switch (format) {
50570
- case "json":
50571
- return formatJSON(data);
50572
- case "yaml":
50573
- return formatYAML(data);
50574
- case "table":
50575
- case "text":
50576
- return formatTable(data);
50577
- case "tsv":
50578
- return formatTSV(data);
50579
- default:
50580
- return formatYAML(data);
50581
- }
50582
- }
50583
- function formatJSON(data) {
50584
- return JSON.stringify(data, null, 2);
50585
- }
50586
- function formatYAML(data) {
50587
- return import_yaml3.default.stringify(data, { indent: 2 });
50588
- }
50589
- function extractItems(data) {
50590
- if (data && typeof data === "object" && "items" in data) {
50591
- const items = data.items;
50592
- if (Array.isArray(items)) {
50593
- return items.filter(
50594
- (item) => item !== null && typeof item === "object"
50595
- );
50596
- }
50597
- }
50598
- if (Array.isArray(data)) {
50599
- return data.filter(
50600
- (item) => item !== null && typeof item === "object"
50601
- );
50602
- }
50603
- if (data && typeof data === "object") {
50604
- return [data];
50605
- }
50606
- return [];
50607
- }
50608
- function getStringField(obj, key) {
50609
- const value = obj[key];
50610
- if (typeof value === "string") {
50611
- return value;
50612
- }
50613
- if (value !== null && value !== void 0) {
50614
- return String(value);
50615
- }
50616
- return "";
50617
- }
50618
- function formatLabels(obj) {
50619
- const labels = obj["labels"];
50620
- if (!labels || typeof labels !== "object") {
50621
- return "";
50622
- }
50623
- const labelMap = labels;
50624
- const entries = Object.entries(labelMap).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}:${v}`);
50625
- if (entries.length === 0) {
50626
- return "";
50627
- }
50628
- return `map[${entries.join(" ")}]`;
50629
- }
50630
- function wrapText2(text, maxWidth) {
50631
- if (text.length <= maxWidth) {
50632
- return [text];
50633
- }
50634
- const lines = [];
50635
- let remaining = text;
50636
- while (remaining.length > 0) {
50637
- if (remaining.length <= maxWidth) {
50638
- lines.push(remaining);
50639
- break;
50640
- }
50641
- let breakPoint = maxWidth;
50642
- for (let i = maxWidth - 1; i > 0; i--) {
50643
- if (remaining[i] === " ") {
50644
- breakPoint = i;
50645
- break;
50646
- }
50647
- }
50648
- lines.push(remaining.slice(0, breakPoint));
50649
- remaining = remaining.slice(breakPoint).trimStart();
50650
- }
50651
- return lines;
50652
- }
50653
- function formatTable(data) {
50654
- const items = extractItems(data);
50655
- if (items.length === 0) {
50656
- return "";
50657
- }
50658
- const headers = ["NAMESPACE", "NAME", "LABELS"];
50659
- const widths = [9, 27, 30];
50660
- const rows = [];
50661
- for (const item of items) {
50662
- const row = [
50663
- getStringField(item, "namespace") || "<None>",
50664
- getStringField(item, "name") || "<None>",
50665
- formatLabels(item) || "<None>"
50666
- ];
50667
- const wrappedCells = row.map((cell, i) => wrapText2(cell, widths[i]));
50668
- const maxLines = Math.max(...wrappedCells.map((c) => c.length));
50669
- const wrappedRows = [];
50670
- for (let line = 0; line < maxLines; line++) {
50671
- wrappedRows.push(wrappedCells.map((c) => c[line] ?? ""));
50672
- }
50673
- rows.push(wrappedRows);
50674
- }
50675
- const lines = [];
50676
- const boxLine = "+" + widths.map((w) => "-".repeat(w + 2)).join("+") + "+";
50677
- lines.push(boxLine);
50678
- lines.push(
50679
- "|" + headers.map((h, i) => {
50680
- const padding = widths[i] - h.length;
50681
- const leftPad = Math.floor(padding / 2);
50682
- const rightPad = padding - leftPad;
50683
- return " " + " ".repeat(leftPad) + h + " ".repeat(rightPad) + " ";
50684
- }).join("|") + "|"
50685
- );
50686
- lines.push(boxLine);
50687
- for (const wrappedRows of rows) {
50688
- for (const row of wrappedRows) {
50689
- lines.push(
50690
- "|" + row.map((cell, i) => {
50691
- const padding = widths[i] - cell.length;
50692
- return " " + cell + " ".repeat(padding) + " ";
50693
- }).join("|") + "|"
50694
- );
50695
- }
50696
- lines.push(boxLine);
50697
- }
50698
- return lines.join("\n");
50699
- }
50700
- function formatTSV(data) {
50701
- const items = extractItems(data);
50702
- if (items.length === 0) {
50703
- return "";
50704
- }
50705
- const allKeys = /* @__PURE__ */ new Set();
50706
- for (const item of items) {
50707
- Object.keys(item).forEach((k) => allKeys.add(k));
50708
- }
50709
- const priority = ["name", "namespace", "status", "created", "modified"];
50710
- const headers = [
50711
- ...priority.filter((p) => allKeys.has(p)),
50712
- ...[...allKeys].filter((k) => !priority.includes(k)).sort()
50713
- ];
50714
- const lines = [];
50715
- for (const item of items) {
50716
- const values = headers.map((h) => {
50717
- const val = item[h];
50718
- if (val === null || val === void 0) return "";
50719
- if (typeof val === "object") return JSON.stringify(val);
50720
- return String(val);
50721
- });
50722
- lines.push(values.join(" "));
50723
- }
50724
- return lines.join("\n");
50725
- }
50726
- function formatAPIError(statusCode, body, operation) {
50727
- const lines = [];
50728
- lines.push(`ERROR: ${operation} failed (HTTP ${statusCode})`);
50729
- if (body && typeof body === "object") {
50730
- const errResp = body;
50731
- if (errResp.message) {
50732
- lines.push(` Message: ${errResp.message}`);
50733
- }
50734
- if (errResp.code) {
50735
- lines.push(` Code: ${errResp.code}`);
50736
- }
50737
- if (errResp.details) {
50738
- lines.push(` Details: ${errResp.details}`);
50739
- }
50740
- }
50741
- switch (statusCode) {
50742
- case 401:
50743
- lines.push(
50744
- "\nHint: Authentication failed. Check your credentials with 'login profile show'"
50745
- );
50746
- break;
50747
- case 403:
50748
- lines.push(
50749
- "\nHint: Permission denied. You may not have access to this resource."
50750
- );
50751
- break;
50752
- case 404:
50753
- lines.push(
50754
- "\nHint: Resource not found. Verify the name and namespace are correct."
50755
- );
50756
- break;
50757
- case 409:
50758
- lines.push(
50759
- "\nHint: Conflict - resource may already exist or be in a conflicting state."
50760
- );
50761
- break;
50762
- case 429:
50763
- lines.push("\nHint: Rate limited. Please wait and try again.");
50764
- break;
50765
- case 500:
50766
- case 502:
50767
- case 503:
50768
- lines.push(
50769
- "\nHint: Server error. Please try again later or contact support."
50770
- );
50771
- break;
50772
- }
50773
- return lines.join("\n");
50911
+ );
50912
+ }, [isShowing, suggestions.length]);
50913
+ const selectCurrent = (0, import_react27.useCallback)(() => {
50914
+ if (!isShowing || suggestions.length === 0) return null;
50915
+ const selected = suggestions.at(selectedIndex);
50916
+ hide();
50917
+ return selected ?? null;
50918
+ }, [isShowing, suggestions, selectedIndex, hide]);
50919
+ return {
50920
+ suggestions,
50921
+ selectedIndex,
50922
+ isShowing,
50923
+ triggerCompletion,
50924
+ navigateUp,
50925
+ navigateDown,
50926
+ selectCurrent,
50927
+ hide,
50928
+ filterSuggestions
50929
+ };
50774
50930
  }
50775
50931
 
50776
- // src/repl/help.ts
50777
- function wrapText3(text, width, indent) {
50778
- const prefix = " ".repeat(indent);
50779
- const words = text.split(/\s+/);
50780
- const lines = [];
50781
- let currentLine = prefix;
50782
- for (const word of words) {
50783
- if (currentLine.length + word.length + 1 > width && currentLine !== prefix) {
50784
- lines.push(currentLine);
50785
- currentLine = prefix + word;
50786
- } else {
50787
- currentLine += (currentLine === prefix ? "" : " ") + word;
50788
- }
50932
+ // src/output/formatter.ts
50933
+ var import_yaml3 = __toESM(require_dist(), 1);
50934
+ function formatOutput(data, format = "yaml") {
50935
+ if (format === "none") {
50936
+ return "";
50789
50937
  }
50790
- if (currentLine.trim()) {
50791
- lines.push(currentLine);
50938
+ switch (format) {
50939
+ case "json":
50940
+ return formatJSON(data);
50941
+ case "yaml":
50942
+ return formatYAML(data);
50943
+ case "table":
50944
+ case "text":
50945
+ return formatTable(data);
50946
+ case "tsv":
50947
+ return formatTSV(data);
50948
+ default:
50949
+ return formatYAML(data);
50792
50950
  }
50793
- return lines;
50794
- }
50795
- function formatRootHelp() {
50796
- return [
50797
- "",
50798
- colorBoldWhite(`${CLI_NAME} - ${CLI_FULL_NAME} v${CLI_VERSION}`),
50799
- "",
50800
- "DESCRIPTION",
50801
- ...wrapText3(CLI_DESCRIPTION_LONG, 80, 2),
50802
- "",
50803
- "USAGE",
50804
- ` ${CLI_NAME} Enter interactive REPL mode`,
50805
- ` ${CLI_NAME} <domain> <action> Execute command non-interactively`,
50806
- ` ${CLI_NAME} help [topic] Show help for a topic`,
50807
- "",
50808
- "EXAMPLES",
50809
- ` ${CLI_NAME} tenant_and_identity list namespace List all namespaces`,
50810
- ` ${CLI_NAME} virtual get http_loadbalancer Get a specific load balancer`,
50811
- ` ${CLI_NAME} dns list List DNS zones`,
50812
- ` ${CLI_NAME} waf list -ns prod List WAF policies in prod`,
50813
- ` ${CLI_NAME} --interactive Force interactive REPL mode`,
50814
- "",
50815
- ...formatDomainsSection(),
50816
- "",
50817
- ...formatGlobalFlags(),
50818
- "",
50819
- ...formatEnvVarsSection(),
50820
- "",
50821
- ...formatConfigSection(),
50822
- "",
50823
- "NAVIGATION (Interactive Mode)",
50824
- " <domain> Navigate into a domain (e.g., 'dns', 'lb')",
50825
- " /domain Navigate directly to domain from anywhere",
50826
- " .. Go up one level",
50827
- " / Return to root",
50828
- " context Show current navigation context",
50829
- "",
50830
- "BUILTINS",
50831
- " help Show this help",
50832
- " domains List all available domains",
50833
- " clear Clear the screen",
50834
- " history Show command history",
50835
- " quit, exit Exit the shell",
50836
- ""
50837
- ];
50838
50951
  }
50839
- function formatGlobalFlags() {
50840
- return [
50841
- "GLOBAL FLAGS",
50842
- " -v, --version Show version number",
50843
- " -h, --help Show this help",
50844
- " -i, --interactive Force interactive mode",
50845
- " --no-color Disable color output",
50846
- " -o, --output <fmt> Output format (json, yaml, table)",
50847
- " -ns, --namespace <ns> Target namespace"
50848
- ];
50952
+ function formatJSON(data) {
50953
+ return JSON.stringify(data, null, 2);
50849
50954
  }
50850
- function formatEnvironmentVariables() {
50851
- return formatEnvVarsSection();
50955
+ function formatYAML(data) {
50956
+ return import_yaml3.default.stringify(data, { indent: 2 });
50852
50957
  }
50853
- function formatDomainHelp(domain) {
50854
- const output = ["", colorBoldWhite(`${domain.displayName}`), ""];
50855
- output.push(` ${domain.description}`);
50856
- output.push("");
50857
- if (domain.category || domain.complexity) {
50858
- const meta = [];
50859
- if (domain.category) meta.push(`Category: ${domain.category}`);
50860
- if (domain.complexity) meta.push(`Complexity: ${domain.complexity}`);
50861
- output.push(colorDim(` ${meta.join(" | ")}`));
50862
- output.push("");
50863
- }
50864
- output.push("USAGE");
50865
- output.push(` ${CLI_NAME} ${domain.name} <action> [options]`);
50866
- output.push("");
50867
- output.push("ACTIONS");
50868
- const actionDescriptions2 = {
50869
- list: "List resources",
50870
- get: "Get a specific resource by name",
50871
- create: "Create a new resource",
50872
- delete: "Delete a resource",
50873
- replace: "Replace a resource configuration",
50874
- apply: "Apply configuration from file",
50875
- status: "Get resource status",
50876
- patch: "Patch a resource",
50877
- "add-labels": "Add labels to a resource",
50878
- "remove-labels": "Remove labels from a resource"
50879
- };
50880
- for (const action of validActions) {
50881
- const desc = actionDescriptions2[action] ?? action;
50882
- output.push(` ${action.padEnd(16)} ${desc}`);
50883
- }
50884
- output.push("");
50885
- output.push("EXAMPLES");
50886
- output.push(` ${CLI_NAME} ${domain.name} list`);
50887
- output.push(` ${CLI_NAME} ${domain.name} get my-resource`);
50888
- output.push(
50889
- ` ${CLI_NAME} ${domain.name} create my-resource -f config.yaml`
50890
- );
50891
- output.push(` ${CLI_NAME} ${domain.name} delete my-resource`);
50892
- output.push("");
50893
- if (domain.useCases && domain.useCases.length > 0) {
50894
- output.push("USE CASES");
50895
- for (const useCase of domain.useCases.slice(0, 5)) {
50896
- output.push(` - ${useCase}`);
50958
+ function extractItems(data) {
50959
+ if (data && typeof data === "object" && "items" in data) {
50960
+ const items = data.items;
50961
+ if (Array.isArray(items)) {
50962
+ return items.filter(
50963
+ (item) => item !== null && typeof item === "object"
50964
+ );
50897
50965
  }
50898
- output.push("");
50899
50966
  }
50900
- if (domain.relatedDomains && domain.relatedDomains.length > 0) {
50901
- output.push("RELATED DOMAINS");
50902
- output.push(` ${domain.relatedDomains.join(", ")}`);
50903
- output.push("");
50967
+ if (Array.isArray(data)) {
50968
+ return data.filter(
50969
+ (item) => item !== null && typeof item === "object"
50970
+ );
50904
50971
  }
50905
- if (domain.aliases && domain.aliases.length > 0) {
50906
- output.push("ALIASES");
50907
- output.push(` ${domain.aliases.join(", ")}`);
50908
- output.push("");
50972
+ if (data && typeof data === "object") {
50973
+ return [data];
50909
50974
  }
50910
- output.push(colorDim(`For global options, run: ${CLI_NAME} --help`));
50911
- output.push("");
50912
- return output;
50975
+ return [];
50913
50976
  }
50914
- function formatActionHelp(domainName, action) {
50915
- const domain = getDomainInfo(domainName);
50916
- const displayDomain = domain?.displayName ?? domainName;
50917
- const actionDescriptions2 = {
50918
- list: {
50919
- desc: "List all resources in the namespace",
50920
- usage: `${CLI_NAME} ${domainName} list [--limit N] [--label key=value]`
50921
- },
50922
- get: {
50923
- desc: "Get a specific resource by name",
50924
- usage: `${CLI_NAME} ${domainName} get <name> [-o json|yaml|table]`
50925
- },
50926
- create: {
50927
- desc: "Create a new resource",
50928
- usage: `${CLI_NAME} ${domainName} create <name> -f <file.yaml>`
50929
- },
50930
- delete: {
50931
- desc: "Delete a resource by name",
50932
- usage: `${CLI_NAME} ${domainName} delete <name>`
50933
- },
50934
- replace: {
50935
- desc: "Replace an existing resource configuration",
50936
- usage: `${CLI_NAME} ${domainName} replace <name> -f <file.yaml>`
50937
- },
50938
- apply: {
50939
- desc: "Apply configuration from a file (create or update)",
50940
- usage: `${CLI_NAME} ${domainName} apply -f <file.yaml>`
50941
- },
50942
- status: {
50943
- desc: "Get the current status of a resource",
50944
- usage: `${CLI_NAME} ${domainName} status <name>`
50945
- },
50946
- patch: {
50947
- desc: "Patch specific fields of a resource",
50948
- usage: `${CLI_NAME} ${domainName} patch <name> -f <patch.yaml>`
50949
- },
50950
- "add-labels": {
50951
- desc: "Add labels to a resource",
50952
- usage: `${CLI_NAME} ${domainName} add-labels <name> key=value`
50953
- },
50954
- "remove-labels": {
50955
- desc: "Remove labels from a resource",
50956
- usage: `${CLI_NAME} ${domainName} remove-labels <name> key`
50957
- }
50958
- };
50959
- const actionInfo = actionDescriptions2[action] ?? {
50960
- desc: `Execute ${action} operation`,
50961
- usage: `${CLI_NAME} ${domainName} ${action} [options]`
50962
- };
50963
- return [
50964
- "",
50965
- colorBoldWhite(`${displayDomain} - ${action}`),
50966
- "",
50967
- ` ${actionInfo.desc}`,
50968
- "",
50969
- "USAGE",
50970
- ` ${actionInfo.usage}`,
50971
- "",
50972
- "OPTIONS",
50973
- " -n, --name <name> Resource name",
50974
- " -ns, --namespace <ns> Target namespace",
50975
- " -o, --output <fmt> Output format (json, yaml, table)",
50976
- " -f, --file <path> Configuration file",
50977
- "",
50978
- colorDim(`For domain help, run: ${CLI_NAME} ${domainName} --help`),
50979
- ""
50980
- ];
50977
+ function getStringField(obj, key) {
50978
+ const value = obj[key];
50979
+ if (typeof value === "string") {
50980
+ return value;
50981
+ }
50982
+ if (value !== null && value !== void 0) {
50983
+ return String(value);
50984
+ }
50985
+ return "";
50981
50986
  }
50982
- function formatTopicHelp(topic) {
50983
- const lowerTopic = topic.toLowerCase();
50984
- const domainInfo = getDomainInfo(lowerTopic);
50985
- if (domainInfo) {
50986
- return formatDomainHelp(domainInfo);
50987
+ function formatLabels(obj) {
50988
+ const labels = obj["labels"];
50989
+ if (!labels || typeof labels !== "object") {
50990
+ return "";
50987
50991
  }
50988
- switch (lowerTopic) {
50989
- case "domains":
50990
- return formatDomainsHelp();
50991
- case "actions":
50992
- return formatActionsHelp();
50993
- case "navigation":
50994
- case "nav":
50995
- return formatNavigationHelp();
50996
- case "env":
50997
- case "environment":
50998
- return ["", ...formatEnvironmentVariables(), ""];
50999
- case "flags":
51000
- return ["", ...formatGlobalFlags(), ""];
51001
- default:
51002
- return [
51003
- "",
51004
- `Unknown help topic: ${topic}`,
51005
- "",
51006
- "Available topics:",
51007
- " domains List all available domains",
51008
- " actions List available actions",
51009
- " navigation Navigation commands",
51010
- " env Environment variables",
51011
- " flags Global flags",
51012
- " <domain> Help for a specific domain (e.g., 'help dns')",
51013
- ""
51014
- ];
50992
+ const labelMap = labels;
50993
+ const entries = Object.entries(labelMap).sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => `${k}:${v}`);
50994
+ if (entries.length === 0) {
50995
+ return "";
51015
50996
  }
50997
+ return `map[${entries.join(" ")}]`;
51016
50998
  }
51017
- function formatDomainsHelp() {
51018
- const output = ["", colorBoldWhite("Available Domains"), ""];
51019
- const categories = /* @__PURE__ */ new Map();
51020
- for (const domain of domainRegistry.values()) {
51021
- const category = domain.category ?? "Other";
51022
- if (!categories.has(category)) {
51023
- categories.set(category, []);
51024
- }
51025
- categories.get(category)?.push(domain);
50999
+ function wrapText3(text, maxWidth) {
51000
+ if (text.length <= maxWidth) {
51001
+ return [text];
51026
51002
  }
51027
- const sortedCategories = Array.from(categories.keys()).sort();
51028
- for (const category of sortedCategories) {
51029
- const domains = categories.get(category) ?? [];
51030
- output.push(colorBoldWhite(` ${category}`));
51031
- for (const domain of domains.sort(
51032
- (a, b) => a.name.localeCompare(b.name)
51033
- )) {
51034
- const aliases = domain.aliases.length > 0 ? colorDim(` (${domain.aliases.join(", ")})`) : "";
51035
- output.push(
51036
- ` ${domain.name.padEnd(24)} ${domain.descriptionShort}`
51037
- );
51038
- if (aliases) {
51039
- output.push(` ${"".padEnd(24)} Aliases:${aliases}`);
51003
+ const lines = [];
51004
+ let remaining = text;
51005
+ while (remaining.length > 0) {
51006
+ if (remaining.length <= maxWidth) {
51007
+ lines.push(remaining);
51008
+ break;
51009
+ }
51010
+ let breakPoint = maxWidth;
51011
+ for (let i = maxWidth - 1; i > 0; i--) {
51012
+ if (remaining[i] === " ") {
51013
+ breakPoint = i;
51014
+ break;
51040
51015
  }
51041
51016
  }
51042
- output.push("");
51017
+ lines.push(remaining.slice(0, breakPoint));
51018
+ remaining = remaining.slice(breakPoint).trimStart();
51043
51019
  }
51044
- return output;
51020
+ return lines;
51045
51021
  }
51046
- function formatActionsHelp() {
51047
- return [
51048
- "",
51049
- colorBoldWhite("Available Actions"),
51050
- "",
51051
- " list List all resources in the namespace",
51052
- " get Get a specific resource by name",
51053
- " create Create a new resource from a file",
51054
- " delete Delete a resource by name",
51055
- " replace Replace a resource configuration",
51056
- " apply Apply configuration (create or update)",
51057
- " status Get resource status",
51058
- " patch Patch specific fields of a resource",
51059
- " add-labels Add labels to a resource",
51060
- " remove-labels Remove labels from a resource",
51061
- "",
51062
- "USAGE",
51063
- ` ${CLI_NAME} <domain> <action> [options]`,
51064
- "",
51065
- "EXAMPLES",
51066
- ` ${CLI_NAME} dns list`,
51067
- ` ${CLI_NAME} lb get my-loadbalancer`,
51068
- ` ${CLI_NAME} waf create my-policy -f policy.yaml`,
51069
- ""
51070
- ];
51022
+ function formatTable(data) {
51023
+ const items = extractItems(data);
51024
+ if (items.length === 0) {
51025
+ return "";
51026
+ }
51027
+ const headers = ["NAMESPACE", "NAME", "LABELS"];
51028
+ const widths = [9, 27, 30];
51029
+ const rows = [];
51030
+ for (const item of items) {
51031
+ const row = [
51032
+ getStringField(item, "namespace") || "<None>",
51033
+ getStringField(item, "name") || "<None>",
51034
+ formatLabels(item) || "<None>"
51035
+ ];
51036
+ const wrappedCells = row.map((cell, i) => wrapText3(cell, widths[i]));
51037
+ const maxLines = Math.max(...wrappedCells.map((c) => c.length));
51038
+ const wrappedRows = [];
51039
+ for (let line = 0; line < maxLines; line++) {
51040
+ wrappedRows.push(wrappedCells.map((c) => c[line] ?? ""));
51041
+ }
51042
+ rows.push(wrappedRows);
51043
+ }
51044
+ const lines = [];
51045
+ const boxLine = "+" + widths.map((w) => "-".repeat(w + 2)).join("+") + "+";
51046
+ lines.push(boxLine);
51047
+ lines.push(
51048
+ "|" + headers.map((h, i) => {
51049
+ const padding = widths[i] - h.length;
51050
+ const leftPad = Math.floor(padding / 2);
51051
+ const rightPad = padding - leftPad;
51052
+ return " " + " ".repeat(leftPad) + h + " ".repeat(rightPad) + " ";
51053
+ }).join("|") + "|"
51054
+ );
51055
+ lines.push(boxLine);
51056
+ for (const wrappedRows of rows) {
51057
+ for (const row of wrappedRows) {
51058
+ lines.push(
51059
+ "|" + row.map((cell, i) => {
51060
+ const padding = widths[i] - cell.length;
51061
+ return " " + cell + " ".repeat(padding) + " ";
51062
+ }).join("|") + "|"
51063
+ );
51064
+ }
51065
+ lines.push(boxLine);
51066
+ }
51067
+ return lines.join("\n");
51071
51068
  }
51072
- function formatNavigationHelp() {
51073
- return [
51074
- "",
51075
- colorBoldWhite("Navigation Commands"),
51076
- "",
51077
- " <domain> Navigate into a domain context",
51078
- " /<domain> Navigate directly to domain from anywhere",
51079
- " .. Go up one level in context",
51080
- " / Return to root context",
51081
- " back Go up one level (same as ..)",
51082
- " root Return to root (same as /)",
51083
- "",
51084
- "CONTEXT DISPLAY",
51085
- " context Show current navigation context",
51086
- " ctx Alias for context",
51087
- "",
51088
- "EXAMPLES",
51089
- " xcsh> dns # Enter dns domain",
51090
- " dns> list # Execute list in dns context",
51091
- " dns> .. # Return to root",
51092
- " xcsh> /waf # Jump directly to waf",
51093
- " waf> /dns # Jump from waf to dns",
51094
- ""
51069
+ function formatTSV(data) {
51070
+ const items = extractItems(data);
51071
+ if (items.length === 0) {
51072
+ return "";
51073
+ }
51074
+ const allKeys = /* @__PURE__ */ new Set();
51075
+ for (const item of items) {
51076
+ Object.keys(item).forEach((k) => allKeys.add(k));
51077
+ }
51078
+ const priority = ["name", "namespace", "status", "created", "modified"];
51079
+ const headers = [
51080
+ ...priority.filter((p) => allKeys.has(p)),
51081
+ ...[...allKeys].filter((k) => !priority.includes(k)).sort()
51095
51082
  ];
51083
+ const lines = [];
51084
+ for (const item of items) {
51085
+ const values = headers.map((h) => {
51086
+ const val = item[h];
51087
+ if (val === null || val === void 0) return "";
51088
+ if (typeof val === "object") return JSON.stringify(val);
51089
+ return String(val);
51090
+ });
51091
+ lines.push(values.join(" "));
51092
+ }
51093
+ return lines.join("\n");
51096
51094
  }
51097
- function formatDomainsSection() {
51098
- const output = ["DOMAINS"];
51099
- const domains = Array.from(domainRegistry.values()).sort(
51100
- (a, b) => a.name.localeCompare(b.name)
51101
- );
51102
- const maxNameLen = Math.max(...domains.map((d) => d.name.length));
51103
- for (const domain of domains) {
51104
- const padding = " ".repeat(maxNameLen - domain.name.length + 2);
51105
- output.push(` ${domain.name}${padding}${domain.descriptionShort}`);
51095
+ function formatAPIError(statusCode, body, operation) {
51096
+ const lines = [];
51097
+ lines.push(`ERROR: ${operation} failed (HTTP ${statusCode})`);
51098
+ if (body && typeof body === "object") {
51099
+ const errResp = body;
51100
+ if (errResp.message) {
51101
+ lines.push(` Message: ${errResp.message}`);
51102
+ }
51103
+ if (errResp.code) {
51104
+ lines.push(` Code: ${errResp.code}`);
51105
+ }
51106
+ if (errResp.details) {
51107
+ lines.push(` Details: ${errResp.details}`);
51108
+ }
51106
51109
  }
51107
- return output;
51110
+ switch (statusCode) {
51111
+ case 401:
51112
+ lines.push(
51113
+ "\nHint: Authentication failed. Check your credentials with 'login profile show'"
51114
+ );
51115
+ break;
51116
+ case 403:
51117
+ lines.push(
51118
+ "\nHint: Permission denied. You may not have access to this resource."
51119
+ );
51120
+ break;
51121
+ case 404:
51122
+ lines.push(
51123
+ "\nHint: Resource not found. Verify the name and namespace are correct."
51124
+ );
51125
+ break;
51126
+ case 409:
51127
+ lines.push(
51128
+ "\nHint: Conflict - resource may already exist or be in a conflicting state."
51129
+ );
51130
+ break;
51131
+ case 429:
51132
+ lines.push("\nHint: Rate limited. Please wait and try again.");
51133
+ break;
51134
+ case 500:
51135
+ case 502:
51136
+ case 503:
51137
+ lines.push(
51138
+ "\nHint: Server error. Please try again later or contact support."
51139
+ );
51140
+ break;
51141
+ }
51142
+ return lines.join("\n");
51108
51143
  }
51109
51144
 
51110
51145
  // src/repl/executor.ts