@robinmordasiewicz/xcsh 6.19.0 → 6.20.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 +777 -256
  2. package/package.json +2 -1
package/dist/index.js CHANGED
@@ -7936,7 +7936,7 @@ var require_react_reconciler_development = __commonJS({
7936
7936
  var HostPortal = 4;
7937
7937
  var HostComponent = 5;
7938
7938
  var HostText = 6;
7939
- var Fragment = 7;
7939
+ var Fragment2 = 7;
7940
7940
  var Mode = 8;
7941
7941
  var ContextConsumer = 9;
7942
7942
  var ContextProvider = 10;
@@ -8076,7 +8076,7 @@ var require_react_reconciler_development = __commonJS({
8076
8076
  return "DehydratedFragment";
8077
8077
  case ForwardRef:
8078
8078
  return getWrappedName$1(type, type.render, "ForwardRef");
8079
- case Fragment:
8079
+ case Fragment2:
8080
8080
  return "Fragment";
8081
8081
  case HostComponent:
8082
8082
  return type;
@@ -11210,7 +11210,7 @@ var require_react_reconciler_development = __commonJS({
11210
11210
  }
11211
11211
  }
11212
11212
  function updateFragment2(returnFiber, current2, fragment, lanes, key) {
11213
- if (current2 === null || current2.tag !== Fragment) {
11213
+ if (current2 === null || current2.tag !== Fragment2) {
11214
11214
  var created = createFiberFromFragment(fragment, returnFiber.mode, lanes, key);
11215
11215
  created.return = returnFiber;
11216
11216
  return created;
@@ -11613,7 +11613,7 @@ var require_react_reconciler_development = __commonJS({
11613
11613
  if (child.key === key) {
11614
11614
  var elementType = element.type;
11615
11615
  if (elementType === REACT_FRAGMENT_TYPE) {
11616
- if (child.tag === Fragment) {
11616
+ if (child.tag === Fragment2) {
11617
11617
  deleteRemainingChildren(returnFiber, child.sibling);
11618
11618
  var existing = useFiber(child, element.props.children);
11619
11619
  existing.return = returnFiber;
@@ -17104,7 +17104,7 @@ var require_react_reconciler_development = __commonJS({
17104
17104
  var _resolvedProps2 = workInProgress2.elementType === type ? _unresolvedProps2 : resolveDefaultProps(type, _unresolvedProps2);
17105
17105
  return updateForwardRef(current2, workInProgress2, type, _resolvedProps2, renderLanes2);
17106
17106
  }
17107
- case Fragment:
17107
+ case Fragment2:
17108
17108
  return updateFragment(current2, workInProgress2, renderLanes2);
17109
17109
  case Mode:
17110
17110
  return updateMode(current2, workInProgress2, renderLanes2);
@@ -17541,7 +17541,7 @@ var require_react_reconciler_development = __commonJS({
17541
17541
  case SimpleMemoComponent:
17542
17542
  case FunctionComponent:
17543
17543
  case ForwardRef:
17544
- case Fragment:
17544
+ case Fragment2:
17545
17545
  case Mode:
17546
17546
  case Profiler:
17547
17547
  case ContextConsumer:
@@ -22309,7 +22309,7 @@ var require_react_reconciler_development = __commonJS({
22309
22309
  return fiber;
22310
22310
  }
22311
22311
  function createFiberFromFragment(elements, mode, lanes, key) {
22312
- var fiber = createFiber(Fragment, elements, key, mode);
22312
+ var fiber = createFiber(Fragment2, elements, key, mode);
22313
22313
  fiber.lanes = lanes;
22314
22314
  return fiber;
22315
22315
  }
@@ -38537,6 +38537,46 @@ function throttle(func, throttleMs = 0, options = {}) {
38537
38537
  });
38538
38538
  }
38539
38539
 
38540
+ // node_modules/ansi-escapes/index.js
38541
+ var ansi_escapes_exports = {};
38542
+ __export(ansi_escapes_exports, {
38543
+ ConEmu: () => ConEmu,
38544
+ beep: () => beep,
38545
+ clearScreen: () => clearScreen,
38546
+ clearTerminal: () => clearTerminal,
38547
+ clearViewport: () => clearViewport,
38548
+ cursorBackward: () => cursorBackward,
38549
+ cursorDown: () => cursorDown,
38550
+ cursorForward: () => cursorForward,
38551
+ cursorGetPosition: () => cursorGetPosition,
38552
+ cursorHide: () => cursorHide,
38553
+ cursorLeft: () => cursorLeft,
38554
+ cursorMove: () => cursorMove,
38555
+ cursorNextLine: () => cursorNextLine,
38556
+ cursorPrevLine: () => cursorPrevLine,
38557
+ cursorRestorePosition: () => cursorRestorePosition,
38558
+ cursorSavePosition: () => cursorSavePosition,
38559
+ cursorShow: () => cursorShow,
38560
+ cursorTo: () => cursorTo,
38561
+ cursorUp: () => cursorUp,
38562
+ default: () => base_exports,
38563
+ enterAlternativeScreen: () => enterAlternativeScreen,
38564
+ eraseDown: () => eraseDown,
38565
+ eraseEndLine: () => eraseEndLine,
38566
+ eraseLine: () => eraseLine,
38567
+ eraseLines: () => eraseLines,
38568
+ eraseScreen: () => eraseScreen,
38569
+ eraseStartLine: () => eraseStartLine,
38570
+ eraseUp: () => eraseUp,
38571
+ exitAlternativeScreen: () => exitAlternativeScreen,
38572
+ iTerm: () => iTerm,
38573
+ image: () => image,
38574
+ link: () => link,
38575
+ scrollDown: () => scrollDown,
38576
+ scrollUp: () => scrollUp,
38577
+ setCwd: () => setCwd
38578
+ });
38579
+
38540
38580
  // node_modules/ansi-escapes/base.js
38541
38581
  var base_exports = {};
38542
38582
  __export(base_exports, {
@@ -38733,6 +38773,51 @@ var ConEmu = {
38733
38773
  };
38734
38774
  var setCwd = (cwd2 = cwdFunction()) => iTerm.setCwd(cwd2) + ConEmu.setCwd(cwd2);
38735
38775
 
38776
+ // src/stubs/ansi-escapes.ts
38777
+ var ESC2 = "\x1B[";
38778
+ var eraseScreen2 = `${ESC2}2J`;
38779
+ var cursorHome = `${ESC2}H`;
38780
+ var patchedClearTerminal = `${eraseScreen2}${cursorHome}`;
38781
+ var {
38782
+ beep: beep2,
38783
+ clearScreen: clearScreen2,
38784
+ clearViewport: clearViewport2,
38785
+ cursorBackward: cursorBackward2,
38786
+ cursorDown: cursorDown2,
38787
+ cursorForward: cursorForward2,
38788
+ cursorGetPosition: cursorGetPosition2,
38789
+ cursorHide: cursorHide2,
38790
+ cursorLeft: cursorLeft2,
38791
+ cursorMove: cursorMove2,
38792
+ cursorNextLine: cursorNextLine2,
38793
+ cursorPrevLine: cursorPrevLine2,
38794
+ cursorRestorePosition: cursorRestorePosition2,
38795
+ cursorSavePosition: cursorSavePosition2,
38796
+ cursorShow: cursorShow2,
38797
+ cursorTo: cursorTo2,
38798
+ cursorUp: cursorUp2,
38799
+ enterAlternativeScreen: enterAlternativeScreen2,
38800
+ eraseDown: eraseDown2,
38801
+ eraseEndLine: eraseEndLine2,
38802
+ eraseLine: eraseLine2,
38803
+ eraseLines: eraseLines2,
38804
+ eraseScreen: eraseScreenOriginal,
38805
+ eraseStartLine: eraseStartLine2,
38806
+ eraseUp: eraseUp2,
38807
+ exitAlternativeScreen: exitAlternativeScreen2,
38808
+ image: image2,
38809
+ link: link2,
38810
+ scrollDown: scrollDown2,
38811
+ scrollUp: scrollUp2,
38812
+ setCwd: setCwd2,
38813
+ iTerm: iTerm2,
38814
+ ConEmu: ConEmu2
38815
+ } = ansi_escapes_exports;
38816
+ var ansi_escapes_default = {
38817
+ ...base_exports,
38818
+ clearTerminal: patchedClearTerminal
38819
+ };
38820
+
38736
38821
  // node_modules/is-in-ci/index.js
38737
38822
  import { env } from "process";
38738
38823
  var isInCi = env.CI !== "0" && env.CI !== "false" && ("CI" in env || "CONTINUOUS_INTEGRATION" in env || Object.keys(env).some((key) => key.startsWith("CI_")));
@@ -42856,11 +42941,11 @@ var create = (stream, { showCursor = false } = {}) => {
42856
42941
  return;
42857
42942
  }
42858
42943
  previousOutput = output;
42859
- stream.write(base_exports.eraseLines(previousLineCount) + output);
42944
+ stream.write(ansi_escapes_default.eraseLines(previousLineCount) + output);
42860
42945
  previousLineCount = output.split("\n").length;
42861
42946
  };
42862
42947
  render2.clear = () => {
42863
- stream.write(base_exports.eraseLines(previousLineCount));
42948
+ stream.write(ansi_escapes_default.eraseLines(previousLineCount));
42864
42949
  previousOutput = "";
42865
42950
  previousLineCount = 0;
42866
42951
  };
@@ -43535,7 +43620,7 @@ var Ink = class {
43535
43620
  this.fullStaticOutput += staticOutput;
43536
43621
  }
43537
43622
  if (outputHeight >= this.options.stdout.rows) {
43538
- this.options.stdout.write(base_exports.clearTerminal + this.fullStaticOutput + output);
43623
+ this.options.stdout.write(ansi_escapes_default.clearTerminal + this.fullStaticOutput + output);
43539
43624
  this.lastOutput = output;
43540
43625
  return;
43541
43626
  }
@@ -43688,6 +43773,25 @@ var getInstance = (stdout, createInstance) => {
43688
43773
 
43689
43774
  // node_modules/ink/build/components/Static.js
43690
43775
  var import_react11 = __toESM(require_react(), 1);
43776
+ function Static(props) {
43777
+ const { items, children: render2, style: customStyle } = props;
43778
+ const [index, setIndex] = (0, import_react11.useState)(0);
43779
+ const itemsToRender = (0, import_react11.useMemo)(() => {
43780
+ return items.slice(index);
43781
+ }, [items, index]);
43782
+ (0, import_react11.useLayoutEffect)(() => {
43783
+ setIndex(items.length);
43784
+ }, [items.length]);
43785
+ const children = itemsToRender.map((item, itemIndex) => {
43786
+ return render2(item, index + itemIndex);
43787
+ });
43788
+ const style = (0, import_react11.useMemo)(() => ({
43789
+ position: "absolute",
43790
+ flexDirection: "column",
43791
+ ...customStyle
43792
+ }), [customStyle]);
43793
+ return import_react11.default.createElement("ink-box", { internal_static: true, style }, children);
43794
+ }
43691
43795
 
43692
43796
  // node_modules/ink/build/components/Transform.js
43693
43797
  var import_react12 = __toESM(require_react(), 1);
@@ -44678,6 +44782,13 @@ function initializeAliasRegistry() {
44678
44782
  function resolveDomain(nameOrAlias) {
44679
44783
  return aliasRegistry.get(nameOrAlias);
44680
44784
  }
44785
+ function getDomainInfo(nameOrAlias) {
44786
+ const canonical = resolveDomain(nameOrAlias);
44787
+ if (!canonical) {
44788
+ return void 0;
44789
+ }
44790
+ return domainRegistry.get(canonical);
44791
+ }
44681
44792
  function allDomains() {
44682
44793
  return Array.from(domainRegistry.keys()).sort();
44683
44794
  }
@@ -44983,8 +45094,8 @@ var HistoryManager = class _HistoryManager {
44983
45094
  var CLI_NAME = "xcsh";
44984
45095
  var CLI_FULL_NAME = "F5 Distributed Cloud Shell";
44985
45096
  function getVersion() {
44986
- if ("6.19.0") {
44987
- return "6.19.0";
45097
+ if ("6.20.0") {
45098
+ return "6.20.0";
44988
45099
  }
44989
45100
  if (process.env.XCSH_VERSION) {
44990
45101
  return process.env.XCSH_VERSION;
@@ -44992,6 +45103,7 @@ function getVersion() {
44992
45103
  return "dev";
44993
45104
  }
44994
45105
  var CLI_VERSION = getVersion();
45106
+ var CONFIG_FILE_NAME = ".xcshconfig";
44995
45107
  var ENV_PREFIX = "F5XC";
44996
45108
  var F5_LOGO = ` ________
44997
45109
  (\u2592\u2592\u2592\u2592\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2593\u2592\u2592\u2592\u2592)
@@ -45034,6 +45146,15 @@ var REPO_OWNER = "robinmordasiewicz";
45034
45146
  var REPO_NAME = CLI_NAME;
45035
45147
  var REPO_URL = `https://github.com/${REPO_OWNER}/${REPO_NAME}`;
45036
45148
  var DOCS_URL = `https://${REPO_OWNER}.github.io/${REPO_NAME}/`;
45149
+ function colorRed(text) {
45150
+ return `${colors.red}${text}${colors.reset}`;
45151
+ }
45152
+ function colorBoldWhite(text) {
45153
+ return `${colors.boldWhite}${text}${colors.reset}`;
45154
+ }
45155
+ function colorDim(text) {
45156
+ return `${colors.dim}${text}${colors.reset}`;
45157
+ }
45037
45158
 
45038
45159
  // src/profile/manager.ts
45039
45160
  var import_yaml = __toESM(require_dist(), 1);
@@ -46482,22 +46603,8 @@ var REPLSession = class {
46482
46603
  };
46483
46604
 
46484
46605
  // src/repl/prompt.ts
46485
- function buildPlainPrompt(session) {
46486
- const parts = [];
46487
- const profileName = session.getActiveProfileName();
46488
- if (profileName) {
46489
- parts.push(`${profileName}@xc`);
46490
- } else {
46491
- parts.push("xc");
46492
- }
46493
- const ctx = session.getContextPath();
46494
- if (ctx.domain !== "") {
46495
- parts.push(ctx.domain);
46496
- if (ctx.action !== "") {
46497
- parts.push(ctx.action);
46498
- }
46499
- }
46500
- return `<${parts.join(".")}> `;
46606
+ function buildPlainPrompt(_session) {
46607
+ return "> ";
46501
46608
  }
46502
46609
 
46503
46610
  // src/repl/App.tsx
@@ -46778,151 +46885,10 @@ function toDisplayTier(tier) {
46778
46885
 
46779
46886
  // src/repl/components/Banner.tsx
46780
46887
  var import_jsx_runtime3 = __toESM(require_jsx_runtime(), 1);
46781
- var BOX = {
46782
- topLeft: "\u256D",
46783
- topRight: "\u256E",
46784
- bottomLeft: "\u2570",
46785
- bottomRight: "\u256F",
46786
- horizontal: "\u2500",
46787
- vertical: "\u2502",
46788
- leftT: "\u251C",
46789
- rightT: "\u2524"
46790
- };
46791
46888
  var TOTAL_WIDTH = 80;
46792
46889
  var INNER_WIDTH = TOTAL_WIDTH - 2;
46793
46890
  var logoLines = F5_LOGO.split("\n");
46794
46891
  var LOGO_WIDTH = Math.max(...logoLines.map((l) => stringWidth(l)));
46795
- var HELP_LINES = [
46796
- "Type 'help' for commands",
46797
- "Run 'namespace <ns>' to set",
46798
- "Press Ctrl+C twice to exit"
46799
- ];
46800
- var HELP_START_ROW = 8;
46801
- function padToWidth(str, targetWidth) {
46802
- const currentWidth = stringWidth(str);
46803
- if (currentWidth >= targetWidth) return str;
46804
- return str + " ".repeat(targetWidth - currentWidth);
46805
- }
46806
- function colorizeLogoLine(line) {
46807
- const elements = [];
46808
- let currentColor = null;
46809
- let buffer = "";
46810
- let keyIndex = 0;
46811
- const flush = () => {
46812
- if (buffer) {
46813
- if (currentColor) {
46814
- elements.push(
46815
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: currentColor, children: buffer }, keyIndex++)
46816
- );
46817
- } else {
46818
- elements.push(/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: buffer }, keyIndex++));
46819
- }
46820
- buffer = "";
46821
- }
46822
- };
46823
- for (const char of line) {
46824
- let newColor;
46825
- switch (char) {
46826
- case "\u2593":
46827
- // Dark shade - red
46828
- case "\u2592":
46829
- // Medium shade - red
46830
- case "(":
46831
- case ")":
46832
- case "|":
46833
- case "_":
46834
- newColor = "#E4002B";
46835
- break;
46836
- case "\u2588":
46837
- newColor = "#ffffff";
46838
- break;
46839
- default:
46840
- newColor = null;
46841
- }
46842
- if (newColor !== currentColor) {
46843
- flush();
46844
- currentColor = newColor;
46845
- }
46846
- buffer += char === "\u2593" ? "\u2588" : char;
46847
- }
46848
- flush();
46849
- return elements;
46850
- }
46851
- function buildContentRow(logoLine, helpText, innerWidth) {
46852
- const paddedLogo = padToWidth(logoLine, LOGO_WIDTH);
46853
- const helpColumnWidth = innerWidth - LOGO_WIDTH - 1;
46854
- const paddedHelp = padToWidth(helpText, helpColumnWidth);
46855
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { children: [
46856
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: "#E4002B", children: BOX.vertical }),
46857
- colorizeLogoLine(paddedLogo),
46858
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { children: " " }),
46859
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { bold: true, color: "#ffffff", children: paddedHelp }),
46860
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: "#E4002B", children: BOX.vertical })
46861
- ] });
46862
- }
46863
- function Banner({
46864
- version,
46865
- connectionInfo
46866
- }) {
46867
- const title = ` ${CLI_FULL_NAME} v${version} `;
46868
- const titleWidth = stringWidth(title);
46869
- const leftDashes = 3;
46870
- const rightDashes = TOTAL_WIDTH - 1 - leftDashes - titleWidth - 1;
46871
- const connectionLines = [];
46872
- if (!connectionInfo.isConnected) {
46873
- connectionLines.push("Not connected - run: export F5XC_API_URL=...");
46874
- } else {
46875
- if (connectionInfo.tenant) {
46876
- connectionLines.push(`Tenant: ${connectionInfo.tenant}`);
46877
- }
46878
- if (connectionInfo.username) {
46879
- connectionLines.push(`User: ${connectionInfo.username}`);
46880
- }
46881
- if (connectionInfo.tier) {
46882
- const displayTier = toDisplayTier(connectionInfo.tier);
46883
- if (displayTier) {
46884
- connectionLines.push(`Tier: ${displayTier}`);
46885
- }
46886
- }
46887
- }
46888
- connectionLines.push(`Namespace: ${connectionInfo.namespace}`);
46889
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Box_default, { flexDirection: "column", marginY: 1, children: [
46890
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { children: [
46891
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { color: "#E4002B", children: [
46892
- BOX.topLeft,
46893
- BOX.horizontal.repeat(leftDashes)
46894
- ] }),
46895
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { bold: true, color: "#ffffff", children: title }),
46896
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { color: "#E4002B", children: [
46897
- BOX.horizontal.repeat(Math.max(0, rightDashes)),
46898
- BOX.topRight
46899
- ] })
46900
- ] }),
46901
- logoLines.map((logoLine, index) => {
46902
- const helpIndex = index - HELP_START_ROW;
46903
- const helpText = helpIndex >= 0 && helpIndex < HELP_LINES.length ? HELP_LINES[helpIndex] : "";
46904
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Box_default, { children: buildContentRow(logoLine, helpText ?? "", INNER_WIDTH) }, index);
46905
- }),
46906
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { color: "#E4002B", children: [
46907
- BOX.leftT,
46908
- BOX.horizontal.repeat(INNER_WIDTH),
46909
- BOX.rightT
46910
- ] }),
46911
- connectionLines.map((line, index) => {
46912
- const paddedLine = padToWidth(` ${line}`, INNER_WIDTH);
46913
- return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { children: [
46914
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: "#E4002B", children: BOX.vertical }),
46915
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { bold: true, color: "#ffffff", children: paddedLine }),
46916
- /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(Text, { color: "#E4002B", children: BOX.vertical })
46917
- ] }, index);
46918
- }),
46919
- /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(Text, { color: "#E4002B", children: [
46920
- BOX.bottomLeft,
46921
- BOX.horizontal.repeat(INNER_WIDTH),
46922
- BOX.bottomRight
46923
- ] })
46924
- ] });
46925
- }
46926
46892
 
46927
46893
  // src/repl/components/Suggestions.tsx
46928
46894
  var import_react24 = __toESM(require_react(), 1);
@@ -47199,6 +47165,9 @@ var DomainRegistry = class {
47199
47165
  }
47200
47166
  const firstArg = args[0]?.toLowerCase() ?? "";
47201
47167
  const restArgs = args.slice(1);
47168
+ if (firstArg === "--help" || firstArg === "-h" || firstArg === "help") {
47169
+ return this.showDomainHelp(domain);
47170
+ }
47202
47171
  const subgroup = domain.subcommands.get(firstArg);
47203
47172
  if (subgroup) {
47204
47173
  if (restArgs.length === 0) {
@@ -47856,7 +47825,7 @@ function formatWhoamiBox(info, options) {
47856
47825
  const lines = [];
47857
47826
  const red = colors.red;
47858
47827
  const reset = colors.reset;
47859
- const BOX2 = {
47828
+ const BOX = {
47860
47829
  topLeft: "\u256D",
47861
47830
  topRight: "\u256E",
47862
47831
  bottomLeft: "\u2570",
@@ -47922,12 +47891,12 @@ function formatWhoamiBox(info, options) {
47922
47891
  const leftDashes = 1;
47923
47892
  const rightDashes = Math.max(0, remainingWidth - leftDashes);
47924
47893
  lines.push(
47925
- `${red}${BOX2.topLeft}${BOX2.horizontal.repeat(leftDashes)}${reset}${title}${red}${BOX2.horizontal.repeat(rightDashes)}${BOX2.topRight}${reset}`
47894
+ `${red}${BOX.topLeft}${BOX.horizontal.repeat(leftDashes)}${reset}${title}${red}${BOX.horizontal.repeat(rightDashes)}${BOX.topRight}${reset}`
47926
47895
  );
47927
47896
  for (const text of formattedContent) {
47928
47897
  const padding = innerWidth - text.length;
47929
47898
  lines.push(
47930
- `${red}${BOX2.vertical}${reset} ${text}${" ".repeat(Math.max(0, padding - 1))}${red}${BOX2.vertical}${reset}`
47899
+ `${red}${BOX.vertical}${reset} ${text}${" ".repeat(Math.max(0, padding - 1))}${red}${BOX.vertical}${reset}`
47931
47900
  );
47932
47901
  }
47933
47902
  if (quotaLines.length > 0) {
@@ -47936,12 +47905,12 @@ function formatWhoamiBox(info, options) {
47936
47905
  const quotaLeft = 1;
47937
47906
  const quotaRight = Math.max(0, quotaRemaining - quotaLeft);
47938
47907
  lines.push(
47939
- `${red}${BOX2.leftT}${BOX2.horizontal.repeat(quotaLeft)}${reset}${quotaTitle}${red}${BOX2.horizontal.repeat(quotaRight)}${BOX2.rightT}${reset}`
47908
+ `${red}${BOX.leftT}${BOX.horizontal.repeat(quotaLeft)}${reset}${quotaTitle}${red}${BOX.horizontal.repeat(quotaRight)}${BOX.rightT}${reset}`
47940
47909
  );
47941
47910
  for (const text of quotaLines) {
47942
47911
  const padding = innerWidth - text.length;
47943
47912
  lines.push(
47944
- `${red}${BOX2.vertical}${reset} ${text}${" ".repeat(Math.max(0, padding - 1))}${red}${BOX2.vertical}${reset}`
47913
+ `${red}${BOX.vertical}${reset} ${text}${" ".repeat(Math.max(0, padding - 1))}${red}${BOX.vertical}${reset}`
47945
47914
  );
47946
47915
  }
47947
47916
  }
@@ -47951,17 +47920,17 @@ function formatWhoamiBox(info, options) {
47951
47920
  const addonLeft = 1;
47952
47921
  const addonRight = Math.max(0, addonRemaining - addonLeft);
47953
47922
  lines.push(
47954
- `${red}${BOX2.leftT}${BOX2.horizontal.repeat(addonLeft)}${reset}${addonTitle}${red}${BOX2.horizontal.repeat(addonRight)}${BOX2.rightT}${reset}`
47923
+ `${red}${BOX.leftT}${BOX.horizontal.repeat(addonLeft)}${reset}${addonTitle}${red}${BOX.horizontal.repeat(addonRight)}${BOX.rightT}${reset}`
47955
47924
  );
47956
47925
  for (const text of addonLines) {
47957
47926
  const padding = innerWidth - text.length;
47958
47927
  lines.push(
47959
- `${red}${BOX2.vertical}${reset} ${text}${" ".repeat(Math.max(0, padding - 1))}${red}${BOX2.vertical}${reset}`
47928
+ `${red}${BOX.vertical}${reset} ${text}${" ".repeat(Math.max(0, padding - 1))}${red}${BOX.vertical}${reset}`
47960
47929
  );
47961
47930
  }
47962
47931
  }
47963
47932
  lines.push(
47964
- `${red}${BOX2.bottomLeft}${BOX2.horizontal.repeat(innerWidth)}${BOX2.bottomRight}${reset}`
47933
+ `${red}${BOX.bottomLeft}${BOX.horizontal.repeat(innerWidth)}${BOX.bottomRight}${reset}`
47965
47934
  );
47966
47935
  return lines;
47967
47936
  }
@@ -50807,9 +50776,380 @@ function formatAPIError(statusCode, body, operation) {
50807
50776
  return lines.join("\n");
50808
50777
  }
50809
50778
 
50779
+ // src/config/envvars.ts
50780
+ var EnvVarRegistry = [
50781
+ {
50782
+ name: `${ENV_PREFIX}_API_URL`,
50783
+ description: "API endpoint URL",
50784
+ relatedFlag: "",
50785
+ required: true
50786
+ },
50787
+ {
50788
+ name: `${ENV_PREFIX}_API_TOKEN`,
50789
+ description: "API authentication token",
50790
+ relatedFlag: "",
50791
+ required: true
50792
+ },
50793
+ {
50794
+ name: `${ENV_PREFIX}_NAMESPACE`,
50795
+ description: "Default namespace",
50796
+ relatedFlag: "-ns"
50797
+ },
50798
+ {
50799
+ name: `${ENV_PREFIX}_OUTPUT_FORMAT`,
50800
+ description: "Output format (json, yaml, table)",
50801
+ relatedFlag: "-o"
50802
+ },
50803
+ {
50804
+ name: `${ENV_PREFIX}_SUBSCRIPTION_TIER`,
50805
+ description: "Subscription tier for feature validation",
50806
+ relatedFlag: ""
50807
+ },
50808
+ {
50809
+ name: "NO_COLOR",
50810
+ description: "Disable color output",
50811
+ relatedFlag: "--no-color"
50812
+ }
50813
+ ];
50814
+ function formatEnvVarsSection() {
50815
+ const maxLen = Math.max(...EnvVarRegistry.map((e) => e.name.length));
50816
+ const lines = ["ENVIRONMENT VARIABLES"];
50817
+ for (const env3 of EnvVarRegistry) {
50818
+ const padding = " ".repeat(maxLen - env3.name.length + 3);
50819
+ const flagNote = env3.relatedFlag ? ` [${env3.relatedFlag}]` : "";
50820
+ lines.push(` ${env3.name}${padding}${env3.description}${flagNote}`);
50821
+ }
50822
+ return lines;
50823
+ }
50824
+ function formatConfigSection() {
50825
+ return [
50826
+ "CONFIGURATION",
50827
+ ` Config file: ~/${CONFIG_FILE_NAME}`,
50828
+ " Priority: CLI flags > environment variables > config file > defaults",
50829
+ "",
50830
+ "DOCUMENTATION",
50831
+ ` ${DOCS_URL}`
50832
+ ];
50833
+ }
50834
+
50835
+ // src/repl/help.ts
50836
+ function formatRootHelp() {
50837
+ return [
50838
+ "",
50839
+ colorBoldWhite(`${CLI_NAME} - ${CLI_FULL_NAME} v${CLI_VERSION}`),
50840
+ "",
50841
+ "DESCRIPTION",
50842
+ ` Interactive CLI for F5 Distributed Cloud services.`,
50843
+ "",
50844
+ "USAGE",
50845
+ ` ${CLI_NAME} Enter interactive REPL mode`,
50846
+ ` ${CLI_NAME} <domain> <action> Execute command non-interactively`,
50847
+ ` ${CLI_NAME} help [topic] Show help for a topic`,
50848
+ "",
50849
+ "EXAMPLES",
50850
+ ` ${CLI_NAME} tenant_and_identity list namespace List all namespaces`,
50851
+ ` ${CLI_NAME} virtual get http_loadbalancer Get a specific load balancer`,
50852
+ ` ${CLI_NAME} dns list List DNS zones`,
50853
+ ` ${CLI_NAME} waf list -ns prod List WAF policies in prod`,
50854
+ ` ${CLI_NAME} --interactive Force interactive REPL mode`,
50855
+ "",
50856
+ ...formatDomainsSection(),
50857
+ "",
50858
+ ...formatGlobalFlags(),
50859
+ "",
50860
+ ...formatEnvVarsSection(),
50861
+ "",
50862
+ ...formatConfigSection(),
50863
+ "",
50864
+ "NAVIGATION (Interactive Mode)",
50865
+ " <domain> Navigate into a domain (e.g., 'dns', 'lb')",
50866
+ " /domain Navigate directly to domain from anywhere",
50867
+ " .. Go up one level",
50868
+ " / Return to root",
50869
+ " context Show current navigation context",
50870
+ "",
50871
+ "BUILTINS",
50872
+ " help Show this help",
50873
+ " domains List all available domains",
50874
+ " clear Clear the screen",
50875
+ " history Show command history",
50876
+ " quit, exit Exit the shell",
50877
+ ""
50878
+ ];
50879
+ }
50880
+ function formatGlobalFlags() {
50881
+ return [
50882
+ "GLOBAL FLAGS",
50883
+ " -v, --version Show version number",
50884
+ " -h, --help Show this help",
50885
+ " -i, --interactive Force interactive mode",
50886
+ " --no-color Disable color output",
50887
+ " -o, --output <fmt> Output format (json, yaml, table)",
50888
+ " -ns, --namespace <ns> Target namespace"
50889
+ ];
50890
+ }
50891
+ function formatEnvironmentVariables() {
50892
+ return formatEnvVarsSection();
50893
+ }
50894
+ function formatDomainHelp(domain) {
50895
+ const output = ["", colorBoldWhite(`${domain.displayName}`), ""];
50896
+ output.push(` ${domain.description}`);
50897
+ output.push("");
50898
+ if (domain.category || domain.complexity) {
50899
+ const meta = [];
50900
+ if (domain.category) meta.push(`Category: ${domain.category}`);
50901
+ if (domain.complexity) meta.push(`Complexity: ${domain.complexity}`);
50902
+ output.push(colorDim(` ${meta.join(" | ")}`));
50903
+ output.push("");
50904
+ }
50905
+ output.push("USAGE");
50906
+ output.push(` ${CLI_NAME} ${domain.name} <action> [options]`);
50907
+ output.push("");
50908
+ output.push("ACTIONS");
50909
+ const actionDescriptions = {
50910
+ list: "List resources",
50911
+ get: "Get a specific resource by name",
50912
+ create: "Create a new resource",
50913
+ delete: "Delete a resource",
50914
+ replace: "Replace a resource configuration",
50915
+ apply: "Apply configuration from file",
50916
+ status: "Get resource status",
50917
+ patch: "Patch a resource",
50918
+ "add-labels": "Add labels to a resource",
50919
+ "remove-labels": "Remove labels from a resource"
50920
+ };
50921
+ for (const action of validActions) {
50922
+ const desc = actionDescriptions[action] ?? action;
50923
+ output.push(` ${action.padEnd(16)} ${desc}`);
50924
+ }
50925
+ output.push("");
50926
+ output.push("EXAMPLES");
50927
+ output.push(` ${CLI_NAME} ${domain.name} list`);
50928
+ output.push(` ${CLI_NAME} ${domain.name} get my-resource`);
50929
+ output.push(
50930
+ ` ${CLI_NAME} ${domain.name} create my-resource -f config.yaml`
50931
+ );
50932
+ output.push(` ${CLI_NAME} ${domain.name} delete my-resource`);
50933
+ output.push("");
50934
+ if (domain.useCases && domain.useCases.length > 0) {
50935
+ output.push("USE CASES");
50936
+ for (const useCase of domain.useCases.slice(0, 5)) {
50937
+ output.push(` - ${useCase}`);
50938
+ }
50939
+ output.push("");
50940
+ }
50941
+ if (domain.relatedDomains && domain.relatedDomains.length > 0) {
50942
+ output.push("RELATED DOMAINS");
50943
+ output.push(` ${domain.relatedDomains.join(", ")}`);
50944
+ output.push("");
50945
+ }
50946
+ if (domain.aliases && domain.aliases.length > 0) {
50947
+ output.push("ALIASES");
50948
+ output.push(` ${domain.aliases.join(", ")}`);
50949
+ output.push("");
50950
+ }
50951
+ output.push(colorDim(`For global options, run: ${CLI_NAME} --help`));
50952
+ output.push("");
50953
+ return output;
50954
+ }
50955
+ function formatActionHelp(domainName, action) {
50956
+ const domain = getDomainInfo(domainName);
50957
+ const displayDomain = domain?.displayName ?? domainName;
50958
+ const actionDescriptions = {
50959
+ list: {
50960
+ desc: "List all resources in the namespace",
50961
+ usage: `${CLI_NAME} ${domainName} list [--limit N] [--label key=value]`
50962
+ },
50963
+ get: {
50964
+ desc: "Get a specific resource by name",
50965
+ usage: `${CLI_NAME} ${domainName} get <name> [-o json|yaml|table]`
50966
+ },
50967
+ create: {
50968
+ desc: "Create a new resource",
50969
+ usage: `${CLI_NAME} ${domainName} create <name> -f <file.yaml>`
50970
+ },
50971
+ delete: {
50972
+ desc: "Delete a resource by name",
50973
+ usage: `${CLI_NAME} ${domainName} delete <name>`
50974
+ },
50975
+ replace: {
50976
+ desc: "Replace an existing resource configuration",
50977
+ usage: `${CLI_NAME} ${domainName} replace <name> -f <file.yaml>`
50978
+ },
50979
+ apply: {
50980
+ desc: "Apply configuration from a file (create or update)",
50981
+ usage: `${CLI_NAME} ${domainName} apply -f <file.yaml>`
50982
+ },
50983
+ status: {
50984
+ desc: "Get the current status of a resource",
50985
+ usage: `${CLI_NAME} ${domainName} status <name>`
50986
+ },
50987
+ patch: {
50988
+ desc: "Patch specific fields of a resource",
50989
+ usage: `${CLI_NAME} ${domainName} patch <name> -f <patch.yaml>`
50990
+ },
50991
+ "add-labels": {
50992
+ desc: "Add labels to a resource",
50993
+ usage: `${CLI_NAME} ${domainName} add-labels <name> key=value`
50994
+ },
50995
+ "remove-labels": {
50996
+ desc: "Remove labels from a resource",
50997
+ usage: `${CLI_NAME} ${domainName} remove-labels <name> key`
50998
+ }
50999
+ };
51000
+ const actionInfo = actionDescriptions[action] ?? {
51001
+ desc: `Execute ${action} operation`,
51002
+ usage: `${CLI_NAME} ${domainName} ${action} [options]`
51003
+ };
51004
+ return [
51005
+ "",
51006
+ colorBoldWhite(`${displayDomain} - ${action}`),
51007
+ "",
51008
+ ` ${actionInfo.desc}`,
51009
+ "",
51010
+ "USAGE",
51011
+ ` ${actionInfo.usage}`,
51012
+ "",
51013
+ "OPTIONS",
51014
+ " -n, --name <name> Resource name",
51015
+ " -ns, --namespace <ns> Target namespace",
51016
+ " -o, --output <fmt> Output format (json, yaml, table)",
51017
+ " -f, --file <path> Configuration file",
51018
+ "",
51019
+ colorDim(`For domain help, run: ${CLI_NAME} ${domainName} --help`),
51020
+ ""
51021
+ ];
51022
+ }
51023
+ function formatTopicHelp(topic) {
51024
+ const lowerTopic = topic.toLowerCase();
51025
+ const domainInfo = getDomainInfo(lowerTopic);
51026
+ if (domainInfo) {
51027
+ return formatDomainHelp(domainInfo);
51028
+ }
51029
+ switch (lowerTopic) {
51030
+ case "domains":
51031
+ return formatDomainsHelp();
51032
+ case "actions":
51033
+ return formatActionsHelp();
51034
+ case "navigation":
51035
+ case "nav":
51036
+ return formatNavigationHelp();
51037
+ case "env":
51038
+ case "environment":
51039
+ return ["", ...formatEnvironmentVariables(), ""];
51040
+ case "flags":
51041
+ return ["", ...formatGlobalFlags(), ""];
51042
+ default:
51043
+ return [
51044
+ "",
51045
+ `Unknown help topic: ${topic}`,
51046
+ "",
51047
+ "Available topics:",
51048
+ " domains List all available domains",
51049
+ " actions List available actions",
51050
+ " navigation Navigation commands",
51051
+ " env Environment variables",
51052
+ " flags Global flags",
51053
+ " <domain> Help for a specific domain (e.g., 'help dns')",
51054
+ ""
51055
+ ];
51056
+ }
51057
+ }
51058
+ function formatDomainsHelp() {
51059
+ const output = ["", colorBoldWhite("Available Domains"), ""];
51060
+ const categories = /* @__PURE__ */ new Map();
51061
+ for (const domain of domainRegistry.values()) {
51062
+ const category = domain.category ?? "Other";
51063
+ if (!categories.has(category)) {
51064
+ categories.set(category, []);
51065
+ }
51066
+ categories.get(category)?.push(domain);
51067
+ }
51068
+ const sortedCategories = Array.from(categories.keys()).sort();
51069
+ for (const category of sortedCategories) {
51070
+ const domains = categories.get(category) ?? [];
51071
+ output.push(colorBoldWhite(` ${category}`));
51072
+ for (const domain of domains.sort(
51073
+ (a, b) => a.name.localeCompare(b.name)
51074
+ )) {
51075
+ const aliases = domain.aliases.length > 0 ? ` (${domain.aliases.join(", ")})` : "";
51076
+ output.push(
51077
+ ` ${domain.name.padEnd(24)} ${domain.displayName}${aliases}`
51078
+ );
51079
+ }
51080
+ output.push("");
51081
+ }
51082
+ return output;
51083
+ }
51084
+ function formatActionsHelp() {
51085
+ return [
51086
+ "",
51087
+ colorBoldWhite("Available Actions"),
51088
+ "",
51089
+ " list List all resources in the namespace",
51090
+ " get Get a specific resource by name",
51091
+ " create Create a new resource from a file",
51092
+ " delete Delete a resource by name",
51093
+ " replace Replace a resource configuration",
51094
+ " apply Apply configuration (create or update)",
51095
+ " status Get resource status",
51096
+ " patch Patch specific fields of a resource",
51097
+ " add-labels Add labels to a resource",
51098
+ " remove-labels Remove labels from a resource",
51099
+ "",
51100
+ "USAGE",
51101
+ ` ${CLI_NAME} <domain> <action> [options]`,
51102
+ "",
51103
+ "EXAMPLES",
51104
+ ` ${CLI_NAME} dns list`,
51105
+ ` ${CLI_NAME} lb get my-loadbalancer`,
51106
+ ` ${CLI_NAME} waf create my-policy -f policy.yaml`,
51107
+ ""
51108
+ ];
51109
+ }
51110
+ function formatNavigationHelp() {
51111
+ return [
51112
+ "",
51113
+ colorBoldWhite("Navigation Commands"),
51114
+ "",
51115
+ " <domain> Navigate into a domain context",
51116
+ " /<domain> Navigate directly to domain from anywhere",
51117
+ " .. Go up one level in context",
51118
+ " / Return to root context",
51119
+ " back Go up one level (same as ..)",
51120
+ " root Return to root (same as /)",
51121
+ "",
51122
+ "CONTEXT DISPLAY",
51123
+ " context Show current navigation context",
51124
+ " ctx Alias for context",
51125
+ "",
51126
+ "EXAMPLES",
51127
+ " xcsh> dns # Enter dns domain",
51128
+ " dns> list # Execute list in dns context",
51129
+ " dns> .. # Return to root",
51130
+ " xcsh> /waf # Jump directly to waf",
51131
+ " waf> /dns # Jump from waf to dns",
51132
+ ""
51133
+ ];
51134
+ }
51135
+ function formatDomainsSection() {
51136
+ const output = ["DOMAINS"];
51137
+ const domains = Array.from(domainRegistry.values()).sort(
51138
+ (a, b) => a.name.localeCompare(b.name)
51139
+ );
51140
+ const maxNameLen = Math.max(...domains.map((d) => d.name.length));
51141
+ for (const domain of domains) {
51142
+ const padding = " ".repeat(maxNameLen - domain.name.length + 2);
51143
+ output.push(` ${domain.name}${padding}${domain.description}`);
51144
+ }
51145
+ return output;
51146
+ }
51147
+
50810
51148
  // src/repl/executor.ts
50811
51149
  var BUILTIN_COMMANDS = /* @__PURE__ */ new Set([
50812
51150
  "help",
51151
+ "--help",
51152
+ "-h",
50813
51153
  "clear",
50814
51154
  "quit",
50815
51155
  "exit",
@@ -50858,9 +51198,11 @@ function parseCommand(input) {
50858
51198
  };
50859
51199
  }
50860
51200
  const firstWord = trimmed.split(/\s+/)[0]?.toLowerCase() ?? "";
50861
- if (BUILTIN_COMMANDS.has(firstWord)) {
51201
+ const normalizedFirst = firstWord.startsWith("/") ? firstWord.slice(1) : firstWord;
51202
+ if (BUILTIN_COMMANDS.has(firstWord) || BUILTIN_COMMANDS.has(normalizedFirst)) {
51203
+ const effectiveCommand = normalizedFirst === "--help" || normalizedFirst === "-h" ? "help" : normalizedFirst;
50862
51204
  return {
50863
- raw: trimmed,
51205
+ raw: effectiveCommand,
50864
51206
  isDirectNavigation: false,
50865
51207
  isBuiltin: true,
50866
51208
  args: trimmed.split(/\s+/).slice(1)
@@ -51027,32 +51369,57 @@ function executeBuiltin(cmd, session, ctx) {
51027
51369
  }));
51028
51370
  }
51029
51371
  if (command === "help" || command.startsWith("help ")) {
51372
+ const topic = cmd.args[0]?.trim() ?? "";
51373
+ if (topic) {
51374
+ return {
51375
+ output: formatTopicHelp(topic),
51376
+ shouldExit: false,
51377
+ shouldClear: false,
51378
+ contextChanged: false
51379
+ };
51380
+ }
51381
+ if (ctx.isRoot()) {
51382
+ return {
51383
+ output: formatRootHelp(),
51384
+ shouldExit: false,
51385
+ shouldClear: false,
51386
+ contextChanged: false
51387
+ };
51388
+ }
51389
+ if (ctx.isDomain()) {
51390
+ const domain = ctx.domain ?? "";
51391
+ const domainInfo = getDomainInfo(domain);
51392
+ if (domainInfo) {
51393
+ return {
51394
+ output: formatDomainHelp(domainInfo),
51395
+ shouldExit: false,
51396
+ shouldClear: false,
51397
+ contextChanged: false
51398
+ };
51399
+ }
51400
+ return {
51401
+ output: [
51402
+ `Help for domain: ${domain}`,
51403
+ "",
51404
+ "Use 'help' at root for full help."
51405
+ ],
51406
+ shouldExit: false,
51407
+ shouldClear: false,
51408
+ contextChanged: false
51409
+ };
51410
+ }
51411
+ if (ctx.isAction()) {
51412
+ const domain = ctx.domain ?? "";
51413
+ const action = ctx.action ?? "";
51414
+ return {
51415
+ output: formatActionHelp(domain, action),
51416
+ shouldExit: false,
51417
+ shouldClear: false,
51418
+ contextChanged: false
51419
+ };
51420
+ }
51030
51421
  return {
51031
- output: [
51032
- "xcsh - F5 Distributed Cloud Shell",
51033
- "",
51034
- "Navigation:",
51035
- " /domain Navigate directly to domain",
51036
- " exit, back, .. Navigate up one level (exits at root)",
51037
- " /, root Navigate to root context",
51038
- " context, ctx Show current context",
51039
- "",
51040
- "Built-in commands:",
51041
- " help Show this help",
51042
- " clear Clear the screen",
51043
- " quit Exit the shell",
51044
- " history Show command history",
51045
- " domains List available domains",
51046
- " whoami Show current user and connection (-q/--quota, -a/--addons, -v/--verbose, --json)",
51047
- " version Show version info",
51048
- "",
51049
- "Keyboard shortcuts:",
51050
- " Tab Trigger/cycle completions",
51051
- " Up/Down Navigate history or suggestions",
51052
- " Ctrl+C twice Exit (within 500ms)",
51053
- " Ctrl+D Exit immediately",
51054
- " Escape Cancel suggestions"
51055
- ],
51422
+ output: formatRootHelp(),
51056
51423
  shouldExit: false,
51057
51424
  shouldClear: false,
51058
51425
  contextChanged: false
@@ -51083,6 +51450,27 @@ async function handleDirectNavigation(cmd, ctx, session) {
51083
51450
  );
51084
51451
  return customDomains.execute(canonicalDomain, allArgs, session);
51085
51452
  }
51453
+ if (cmd.targetAction === "--help" || cmd.targetAction === "-h" || cmd.targetAction === "help") {
51454
+ const domainInfo = getDomainInfo(cmd.targetDomain);
51455
+ if (domainInfo) {
51456
+ return {
51457
+ output: formatDomainHelp(domainInfo),
51458
+ shouldExit: false,
51459
+ shouldClear: false,
51460
+ contextChanged: false
51461
+ };
51462
+ }
51463
+ return {
51464
+ output: [
51465
+ `${cmd.targetDomain} - Run '${cmd.targetDomain}' for available commands.`,
51466
+ "",
51467
+ `For global options, run: help`
51468
+ ],
51469
+ shouldExit: false,
51470
+ shouldClear: false,
51471
+ contextChanged: false
51472
+ };
51473
+ }
51086
51474
  const extensionDomain = aliasRegistry.get(cmd.targetDomain) ?? cmd.targetDomain;
51087
51475
  const merged = extensionRegistry.getMergedDomain(extensionDomain);
51088
51476
  if (merged?.hasExtension && cmd.targetAction) {
@@ -51166,6 +51554,28 @@ async function handleDomainNavigation(domain, args, ctx, session) {
51166
51554
  const canonicalDomain = resolveDomainAlias(domain);
51167
51555
  return customDomains.execute(canonicalDomain, args, session);
51168
51556
  }
51557
+ const firstArg = args[0]?.toLowerCase() ?? "";
51558
+ if (firstArg === "--help" || firstArg === "-h" || firstArg === "help") {
51559
+ const domainInfo = getDomainInfo(domain);
51560
+ if (domainInfo) {
51561
+ return {
51562
+ output: formatDomainHelp(domainInfo),
51563
+ shouldExit: false,
51564
+ shouldClear: false,
51565
+ contextChanged: false
51566
+ };
51567
+ }
51568
+ return {
51569
+ output: [
51570
+ `${domain} - Run '${domain}' for available commands.`,
51571
+ "",
51572
+ `For global options, run: help`
51573
+ ],
51574
+ shouldExit: false,
51575
+ shouldClear: false,
51576
+ contextChanged: false
51577
+ };
51578
+ }
51169
51579
  const merged = extensionRegistry.getMergedDomain(domain);
51170
51580
  if (merged?.hasExtension) {
51171
51581
  if (args.length > 0) {
@@ -51508,9 +51918,9 @@ function App2() {
51508
51918
  },
51509
51919
  []
51510
51920
  );
51511
- const [output, setOutput] = (0, import_react28.useState)([]);
51512
- const [showBanner, setShowBanner] = (0, import_react28.useState)(true);
51513
- const [prompt, setPrompt] = (0, import_react28.useState)("<xc> ");
51921
+ const [outputItems, setOutputItems] = (0, import_react28.useState)([]);
51922
+ const outputIdRef = (0, import_react28.useRef)(0);
51923
+ const [prompt, setPrompt] = (0, import_react28.useState)("> ");
51514
51924
  const [width, setWidth] = (0, import_react28.useState)(stdout?.columns ?? 80);
51515
51925
  const [gitInfo, setGitInfo] = (0, import_react28.useState)(void 0);
51516
51926
  const [statusHint, setStatusHint] = (0, import_react28.useState)("Ctrl+C twice to exit");
@@ -51558,12 +51968,17 @@ function App2() {
51558
51968
  };
51559
51969
  }, [stdout]);
51560
51970
  const addOutput = (0, import_react28.useCallback)((line) => {
51561
- setOutput((prev) => {
51562
- const newLines = [...prev, ...line.split("\n")];
51563
- if (newLines.length > 1e3) {
51564
- return newLines.slice(newLines.length - 1e3);
51971
+ const lines = line.split("\n");
51972
+ const newItems = lines.map((content) => ({
51973
+ id: outputIdRef.current++,
51974
+ content
51975
+ }));
51976
+ setOutputItems((prev) => {
51977
+ const combined = [...prev, ...newItems];
51978
+ if (combined.length > 1e3) {
51979
+ return combined.slice(combined.length - 1e3);
51565
51980
  }
51566
- return newLines;
51981
+ return combined;
51567
51982
  });
51568
51983
  }, []);
51569
51984
  const applyCompletion = (0, import_react28.useCallback)(
@@ -51605,10 +52020,9 @@ function App2() {
51605
52020
  const trimmed = cmd.trim();
51606
52021
  if (!trimmed) return;
51607
52022
  addOutput(prompt + trimmed);
51608
- setShowBanner(false);
51609
52023
  const result = await executeCommand(trimmed, session);
51610
52024
  if (result.shouldClear) {
51611
- setOutput([]);
52025
+ setOutputItems([]);
51612
52026
  } else {
51613
52027
  result.output.forEach((line) => addOutput(line));
51614
52028
  }
@@ -51672,10 +52086,17 @@ function App2() {
51672
52086
  if (key.tab) {
51673
52087
  const currentInput = inputRef.current;
51674
52088
  if (completion.isShowing) {
51675
- if (key.shift) {
51676
- completion.navigateUp();
51677
- } else {
51678
- completion.navigateDown();
52089
+ const selected = completion.suggestions.at(
52090
+ completion.selectedIndex
52091
+ );
52092
+ if (selected) {
52093
+ applyCompletion({
52094
+ label: selected.text,
52095
+ value: selected.text,
52096
+ description: selected.description,
52097
+ category: selected.category ?? "builtin"
52098
+ });
52099
+ completion.hide();
51679
52100
  }
51680
52101
  } else {
51681
52102
  completion.triggerCompletion(currentInput).then((suggestion) => {
@@ -51742,52 +52163,151 @@ function App2() {
51742
52163
  },
51743
52164
  [applyCompletion, completion]
51744
52165
  );
51745
- if (!isInitialized) {
51746
- return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { children: "Initializing..." }) });
51747
- }
51748
- const maxOutputLines = Math.max(5, 20);
51749
- const connectionInfo = {
51750
- tenant: session.getTenant() || void 0,
51751
- username: session.getUsername() || void 0,
51752
- tier: session.getTier() || void 0,
51753
- namespace: session.getNamespace(),
51754
- isConnected: session.isConnected()
51755
- };
51756
52166
  return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Box_default, { flexDirection: "column", width, children: [
51757
- showBanner && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Banner, { version: CLI_VERSION, connectionInfo }),
51758
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Box_default, { flexDirection: "column", children: output.slice(-maxOutputLines).map((line, i) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { children: line }, i)) }),
51759
- /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
51760
- InputBox,
51761
- {
51762
- prompt,
51763
- value: input,
51764
- onChange: handleInputChange,
51765
- onSubmit: handleSubmit,
51766
- width,
51767
- isActive: true,
51768
- inputKey
51769
- }
51770
- ),
51771
- completion.isShowing && completion.suggestions.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
51772
- Suggestions,
51773
- {
51774
- suggestions: toUISuggestions(completion.suggestions),
51775
- selectedIndex: completion.selectedIndex,
51776
- onSelect: handleSuggestionSelect,
51777
- onNavigate: handleSuggestionNavigate,
51778
- onCancel: completion.hide,
51779
- maxVisible: 10,
51780
- isActive: false
51781
- }
51782
- ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(StatusBar, { gitInfo, width, hint: statusHint })
52167
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Static, { items: outputItems, children: (item) => /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { children: item.content }, item.id) }),
52168
+ isInitialized ? /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(import_jsx_runtime5.Fragment, { children: [
52169
+ /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
52170
+ InputBox,
52171
+ {
52172
+ prompt,
52173
+ value: input,
52174
+ onChange: handleInputChange,
52175
+ onSubmit: handleSubmit,
52176
+ width,
52177
+ isActive: true,
52178
+ inputKey
52179
+ }
52180
+ ),
52181
+ completion.isShowing && completion.suggestions.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
52182
+ Suggestions,
52183
+ {
52184
+ suggestions: toUISuggestions(
52185
+ completion.suggestions
52186
+ ),
52187
+ selectedIndex: completion.selectedIndex,
52188
+ onSelect: handleSuggestionSelect,
52189
+ onNavigate: handleSuggestionNavigate,
52190
+ onCancel: completion.hide,
52191
+ maxVisible: 10,
52192
+ isActive: false
52193
+ }
52194
+ ) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
52195
+ StatusBar,
52196
+ {
52197
+ gitInfo,
52198
+ width,
52199
+ hint: statusHint
52200
+ }
52201
+ )
52202
+ ] }) : /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Text, { children: "Initializing..." })
51783
52203
  ] });
51784
52204
  }
51785
52205
 
51786
52206
  // src/index.tsx
51787
52207
  var import_jsx_runtime6 = __toESM(require_jsx_runtime(), 1);
52208
+ function colorizeLogoLine(line) {
52209
+ let result = "";
52210
+ let currentColor = "none";
52211
+ for (const char of line) {
52212
+ let newColor;
52213
+ switch (char) {
52214
+ case "\u2593":
52215
+ // Dark shade - red (rendered as solid block)
52216
+ case "\u2592":
52217
+ // Medium shade - red
52218
+ case "(":
52219
+ case ")":
52220
+ case "|":
52221
+ case "_":
52222
+ newColor = "red";
52223
+ break;
52224
+ case "\u2588":
52225
+ newColor = "white";
52226
+ break;
52227
+ default:
52228
+ newColor = "none";
52229
+ }
52230
+ if (newColor !== currentColor) {
52231
+ if (currentColor !== "none") {
52232
+ result += colors.reset;
52233
+ }
52234
+ if (newColor === "red") {
52235
+ result += colors.red;
52236
+ } else if (newColor === "white") {
52237
+ result += colors.boldWhite;
52238
+ }
52239
+ currentColor = newColor;
52240
+ }
52241
+ result += char === "\u2593" ? "\u2588" : char;
52242
+ }
52243
+ if (currentColor !== "none") {
52244
+ result += colors.reset;
52245
+ }
52246
+ return result;
52247
+ }
52248
+ function printBannerToScrollback() {
52249
+ const BOX = {
52250
+ topLeft: "\u256D",
52251
+ topRight: "\u256E",
52252
+ bottomLeft: "\u2570",
52253
+ bottomRight: "\u256F",
52254
+ horizontal: "\u2500",
52255
+ vertical: "\u2502",
52256
+ leftT: "\u251C",
52257
+ rightT: "\u2524"
52258
+ };
52259
+ const logoLines2 = F5_LOGO.split("\n");
52260
+ const logoWidth = Math.max(...logoLines2.map((l) => [...l].length));
52261
+ const TOTAL_WIDTH2 = Math.max(80, logoWidth + 4);
52262
+ const INNER_WIDTH2 = TOTAL_WIDTH2 - 2;
52263
+ const HELP_LINES = [
52264
+ "Type 'help' for commands",
52265
+ "Run 'namespace <ns>' to set",
52266
+ "Press Ctrl+C twice to exit"
52267
+ ];
52268
+ const HELP_START_ROW = 8;
52269
+ const title = ` ${CLI_FULL_NAME} v${CLI_VERSION} `;
52270
+ const leftDashes = 3;
52271
+ const rightDashes = TOTAL_WIDTH2 - 1 - leftDashes - title.length - 1;
52272
+ const output = [];
52273
+ output.push(
52274
+ colorRed(BOX.topLeft + BOX.horizontal.repeat(leftDashes)) + colorBoldWhite(title) + colorRed(
52275
+ BOX.horizontal.repeat(Math.max(0, rightDashes)) + BOX.topRight
52276
+ )
52277
+ );
52278
+ for (let i = 0; i < logoLines2.length; i++) {
52279
+ const logoLine = logoLines2[i] ?? "";
52280
+ const helpIndex = i - HELP_START_ROW;
52281
+ const helpText = helpIndex >= 0 && helpIndex < HELP_LINES.length ? HELP_LINES[helpIndex] ?? "" : "";
52282
+ const paddedLogo = logoLine.padEnd(logoWidth);
52283
+ const coloredLogo = colorizeLogoLine(paddedLogo);
52284
+ const helpColumnWidth = INNER_WIDTH2 - logoWidth - 1;
52285
+ const paddedHelp = helpText.padEnd(helpColumnWidth);
52286
+ output.push(
52287
+ colorRed(BOX.vertical) + coloredLogo + " " + colorBoldWhite(paddedHelp) + colorRed(BOX.vertical)
52288
+ );
52289
+ }
52290
+ output.push(
52291
+ colorRed(
52292
+ BOX.bottomLeft + BOX.horizontal.repeat(INNER_WIDTH2) + BOX.bottomRight
52293
+ )
52294
+ );
52295
+ output.push("");
52296
+ process.stdout.write(output.join("\n") + "\n");
52297
+ }
51788
52298
  var program2 = new Command();
51789
- program2.name(CLI_NAME).description("F5 Distributed Cloud Shell - Interactive CLI for F5 XC").version(CLI_VERSION, "-v, --version", "Show version number").option("-i, --interactive", "Force interactive mode").option("--no-color", "Disable color output").argument("[command...]", "Command to execute non-interactively").allowUnknownOption(true).action(
52299
+ program2.configureHelp({
52300
+ formatHelp: () => formatRootHelp().join("\n")
52301
+ });
52302
+ program2.name(CLI_NAME).description("F5 Distributed Cloud Shell - Interactive CLI for F5 XC").version(CLI_VERSION, "-v, --version", "Show version number").option("-i, --interactive", "Force interactive mode").option("--no-color", "Disable color output").option("-h, --help", "Show help").argument("[command...]", "Command to execute non-interactively").allowUnknownOption(true).helpOption(false).action(
51790
52303
  async (commandArgs, options) => {
52304
+ if (options.help && commandArgs.length === 0) {
52305
+ formatRootHelp().forEach((line) => console.log(line));
52306
+ process.exit(0);
52307
+ }
52308
+ if (options.help && commandArgs.length > 0) {
52309
+ commandArgs.push("--help");
52310
+ }
51791
52311
  if (commandArgs.length === 0 || options.interactive) {
51792
52312
  if (!process.stdin.isTTY && !options.interactive) {
51793
52313
  console.error(
@@ -51798,6 +52318,7 @@ program2.name(CLI_NAME).description("F5 Distributed Cloud Shell - Interactive CL
51798
52318
  );
51799
52319
  process.exit(1);
51800
52320
  }
52321
+ printBannerToScrollback();
51801
52322
  process.stdin.resume();
51802
52323
  render_default(/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(App2, {}));
51803
52324
  return;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@robinmordasiewicz/xcsh",
3
- "version": "6.19.0",
3
+ "version": "6.20.0",
4
4
  "description": "F5 Distributed Cloud Shell - Interactive CLI for F5 XC",
5
5
  "type": "module",
6
6
  "bin": {
@@ -25,6 +25,7 @@
25
25
  "build:binaries": "./scripts/build-binaries.sh",
26
26
  "build:release": "npm run build && npm run build:binaries",
27
27
  "dev": "tsx src/index.tsx",
28
+ "build:dev": "npm run build && ${HOME}/.bun/bin/bun build dist/index.js --compile --outfile ./xcsh",
28
29
  "start": "node dist/index.js",
29
30
  "test": "vitest",
30
31
  "test:coverage": "vitest --coverage",