@rockcarver/frodo-cli 4.0.0-24 → 4.0.0-26

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -7,6 +7,10 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [4.0.0-25] - 2026-03-23
11
+
12
+ ## [4.0.0-24] - 2026-03-21
13
+
10
14
  ## [4.0.0-23] - 2026-03-21
11
15
 
12
16
  ## [4.0.0-22] - 2026-03-20
@@ -2209,7 +2213,9 @@ Frodo CLI 2.x automatically refreshes session and access tokens before they expi
2209
2213
  - Fixed problem with adding connection profiles
2210
2214
  - Miscellaneous bug fixes
2211
2215
 
2212
- [unreleased]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-23...HEAD
2216
+ [unreleased]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-25...HEAD
2217
+ [4.0.0-25]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-24...v4.0.0-25
2218
+ [4.0.0-24]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-23...v4.0.0-24
2213
2219
  [4.0.0-23]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-22...v4.0.0-23
2214
2220
  [4.0.0-22]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-21...v4.0.0-22
2215
2221
  [4.0.0-21]: https://github.com/rockcarver/frodo-cli/compare/v4.0.0-20...v4.0.0-21
package/dist/app.cjs CHANGED
@@ -238576,16 +238576,183 @@ var _repl = require('repl'); var _repl2 = _interopRequireDefault2(_repl);
238576
238576
 
238577
238577
  var _vm = require('vm'); var _vm2 = _interopRequireDefault2(_vm);
238578
238578
 
238579
+ // src/ops/ShellAutoCompleteOps.ts
238580
+ _chunkI43EENNMcjs.init_cjs_shims.call(void 0, );
238581
+ var CYAN = "\x1B[36m";
238582
+ var DIM = "\x1B[2m";
238583
+ var RESET = "\x1B[0m";
238584
+ function getHelpMetadataFromInstance(frodoInstance) {
238585
+ const candidate = frodoInstance["utils"];
238586
+ if (!candidate || typeof candidate !== "object") return [];
238587
+ const getHelpMetadata2 = candidate["getHelpMetadata"];
238588
+ if (typeof getHelpMetadata2 !== "function") return [];
238589
+ const result = getHelpMetadata2();
238590
+ return Array.isArray(result) ? result : [];
238591
+ }
238592
+ function getValueAtPath(root4, pathSegments) {
238593
+ let current = root4;
238594
+ for (const segment of pathSegments) {
238595
+ if (!current || typeof current !== "object") return void 0;
238596
+ current = current[segment];
238597
+ }
238598
+ return current;
238599
+ }
238600
+ function normalizeName(value) {
238601
+ return value.toLowerCase().replace(/[^a-z0-9]/g, "");
238602
+ }
238603
+ function findBestDoc(methodName, moduleSegments, docsByMethod) {
238604
+ const docs = _nullishCoalesce(docsByMethod.get(methodName), () => ( []));
238605
+ if (docs.length === 0) return void 0;
238606
+ const normalizedModuleSegments = moduleSegments.map(normalizeName);
238607
+ const exactMatch = docs.find(
238608
+ (d3) => normalizedModuleSegments.includes(normalizeName(d3.typeName))
238609
+ );
238610
+ return _nullishCoalesce(exactMatch, () => ( docs[0]));
238611
+ }
238612
+ function buildMethodScaffold(moduleSegments, methodName, docsByMethod) {
238613
+ const doc = findBestDoc(methodName, moduleSegments, docsByMethod);
238614
+ if (!doc) return "()";
238615
+ const paramNames = (_nullishCoalesce(doc.params, () => ( []))).map((p) => p.name.trim()).filter((name) => name.length > 0);
238616
+ if (paramNames.length === 0) return "()";
238617
+ return `(${paramNames.join(", ")})`;
238618
+ }
238619
+ function abbrevType(type) {
238620
+ const t = type.trim();
238621
+ if (!t) return t;
238622
+ if (t.includes("=>") || t.startsWith("(")) return "fn";
238623
+ if (t.endsWith("[]")) return abbrevType(t.slice(0, -2)) + "[]";
238624
+ switch (t) {
238625
+ case "string":
238626
+ return "str";
238627
+ case "boolean":
238628
+ return "bool";
238629
+ case "number":
238630
+ return "num";
238631
+ default:
238632
+ return t;
238633
+ }
238634
+ }
238635
+ function buildHintLine(fullPath, doc) {
238636
+ const params = (_nullishCoalesce(doc.params, () => ( []))).map((p) => {
238637
+ const name = p.name.trim();
238638
+ const type = abbrevType(p.type);
238639
+ return name && type ? `${name}: ${type}` : name;
238640
+ }).filter((s4) => s4.length > 0).join(", ");
238641
+ return `\u25B8 ${CYAN}${fullPath}${RESET}(${DIM}${params}${RESET})`;
238642
+ }
238643
+ function createFrodoCompleter(rootBindings, docsByMethod, onMethodHint) {
238644
+ return (line) => {
238645
+ const invocationMatch = line.match(
238646
+ /([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)+)\(\s*$/
238647
+ );
238648
+ if (invocationMatch) {
238649
+ const fullPath = invocationMatch[1];
238650
+ const parts = fullPath.split(".");
238651
+ const rootName2 = parts[0];
238652
+ const root5 = rootBindings[rootName2];
238653
+ if (!root5) return [[], line];
238654
+ const methodName = parts[parts.length - 1];
238655
+ const parentSegments2 = parts.slice(1, -1);
238656
+ const completion = `${fullPath}${buildMethodScaffold(
238657
+ parentSegments2,
238658
+ methodName,
238659
+ docsByMethod
238660
+ )}`;
238661
+ if (onMethodHint) {
238662
+ const doc = findBestDoc(methodName, parentSegments2, docsByMethod);
238663
+ if (doc) {
238664
+ setImmediate(() => onMethodHint(buildHintLine(fullPath, doc)));
238665
+ }
238666
+ }
238667
+ return [[completion], `${fullPath}(`];
238668
+ }
238669
+ const tokenMatch = line.match(
238670
+ /([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)*\.?)$/
238671
+ );
238672
+ const token2 = _nullishCoalesce(_optionalChain([tokenMatch, 'optionalAccess', _580 => _580[1]]), () => ( ""));
238673
+ if (!token2) return [[], line];
238674
+ const rootCandidates = Object.keys(rootBindings).filter(
238675
+ (rootName2) => rootName2.startsWith(token2)
238676
+ );
238677
+ if (!token2.includes(".")) {
238678
+ const rootCompletions = rootCandidates.sort((a, b) => a.localeCompare(b));
238679
+ return [rootCompletions, token2];
238680
+ }
238681
+ const segments = token2.split(".");
238682
+ const rootName = segments[0];
238683
+ const root4 = rootBindings[rootName];
238684
+ if (!root4) return [[], token2];
238685
+ const hasTrailingDot = token2.endsWith(".");
238686
+ const parentSegments = hasTrailingDot ? segments.slice(1, -1) : segments.slice(1, -1);
238687
+ const partial = hasTrailingDot ? "" : segments[segments.length - 1];
238688
+ const targetObj = getValueAtPath(root4, parentSegments);
238689
+ if (!targetObj || typeof targetObj !== "object") return [[], token2];
238690
+ const completions = Object.keys(targetObj).filter((k2) => k2.startsWith(partial)).sort((a, b) => a.localeCompare(b)).map((k2) => {
238691
+ const value = targetObj[k2];
238692
+ const prefix = `${rootName}.${[...parentSegments, k2].join(".")}`;
238693
+ if (typeof value !== "function") return prefix;
238694
+ return `${prefix}${buildMethodScaffold(parentSegments, k2, docsByMethod)}`;
238695
+ });
238696
+ if (onMethodHint && completions.length === 1) {
238697
+ const completion = completions[0];
238698
+ const parenIdx = completion.indexOf("(");
238699
+ if (parenIdx !== -1) {
238700
+ const dotIdx = completion.lastIndexOf(".", parenIdx);
238701
+ const resolvedMethodName = completion.slice(dotIdx + 1, parenIdx);
238702
+ const doc = findBestDoc(
238703
+ resolvedMethodName,
238704
+ parentSegments,
238705
+ docsByMethod
238706
+ );
238707
+ if (doc) {
238708
+ const fullPath = completion.slice(0, parenIdx);
238709
+ setImmediate(() => onMethodHint(buildHintLine(fullPath, doc)));
238710
+ }
238711
+ }
238712
+ }
238713
+ return [completions, token2];
238714
+ };
238715
+ }
238716
+ function buildDocsByMethod(frodoInstance) {
238717
+ const helpDocs = getHelpMetadataFromInstance(frodoInstance);
238718
+ const docsByMethod = /* @__PURE__ */ new Map();
238719
+ for (const doc of helpDocs) {
238720
+ if (!docsByMethod.has(doc.methodName)) docsByMethod.set(doc.methodName, []);
238721
+ docsByMethod.get(doc.methodName).push(doc);
238722
+ }
238723
+ return docsByMethod;
238724
+ }
238725
+ function registerOpenParenHint(replServer, rootBindings, docsByMethod, onHint) {
238726
+ process.stdin.on("keypress", (_char, key) => {
238727
+ const char = typeof _char === "string" ? _char : "";
238728
+ const sequence = _nullishCoalesce(_optionalChain([key, 'optionalAccess', _581 => _581.sequence]), () => ( ""));
238729
+ if (sequence !== "(" && char !== "(") return;
238730
+ const currentLine = _nullishCoalesce(replServer["line"], () => ( ""));
238731
+ const match2 = currentLine.match(
238732
+ /([A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)+)\s*$/
238733
+ );
238734
+ if (!match2) return;
238735
+ const parts = match2[1].split(".");
238736
+ if (!rootBindings[parts[0]]) return;
238737
+ const methodName = parts[parts.length - 1];
238738
+ const parentSegments = parts.slice(1, -1);
238739
+ const doc = findBestDoc(methodName, parentSegments, docsByMethod);
238740
+ if (doc) {
238741
+ setImmediate(() => onHint(buildHintLine(match2[1], doc)));
238742
+ }
238743
+ });
238744
+ }
238745
+
238579
238746
  // src/ops/ShellHelpOps.ts
238580
238747
  _chunkI43EENNMcjs.init_cjs_shims.call(void 0, );
238581
238748
  var BOLD = "\x1B[1m";
238582
- var RESET = "\x1B[0m";
238583
- var CYAN = "\x1B[36m";
238749
+ var RESET2 = "\x1B[0m";
238750
+ var CYAN2 = "\x1B[36m";
238584
238751
  var YELLOW = "\x1B[33m";
238585
238752
  var GREEN = "\x1B[32m";
238586
- var DIM = "\x1B[2m";
238753
+ var DIM2 = "\x1B[2m";
238587
238754
  var cachedIndex = null;
238588
- function getHelpMetadataFromInstance(frodoInstance) {
238755
+ function getHelpMetadataFromInstance2(frodoInstance) {
238589
238756
  const candidate = frodoInstance["utils"];
238590
238757
  if (!candidate || typeof candidate !== "object") return [];
238591
238758
  const getHelpMetadata2 = candidate["getHelpMetadata"];
@@ -238604,22 +238771,22 @@ function getMethodIndex(helpDocs) {
238604
238771
  }
238605
238772
  function formatMethodDoc(doc, verbose) {
238606
238773
  const lines = [];
238607
- lines.push(`${YELLOW}${doc.typeName}.${doc.methodName}${RESET}`);
238608
- lines.push(` ${CYAN}Signature :${RESET} ${doc.signature}`);
238774
+ lines.push(`${YELLOW}${doc.typeName}.${doc.methodName}${RESET2}`);
238775
+ lines.push(` ${CYAN2}Signature :${RESET2} ${doc.signature}`);
238609
238776
  if (doc.description) {
238610
- lines.push(` ${CYAN}Description:${RESET} ${doc.description}`);
238777
+ lines.push(` ${CYAN2}Description:${RESET2} ${doc.description}`);
238611
238778
  }
238612
238779
  if (verbose) {
238613
238780
  if (doc.params.length > 0) {
238614
- lines.push(` ${CYAN}Parameters :${RESET}`);
238781
+ lines.push(` ${CYAN2}Parameters :${RESET2}`);
238615
238782
  for (const p of doc.params) {
238616
238783
  const typePart = p.type ? `{${p.type}} ` : "";
238617
238784
  const desc = p.description ? `: ${p.description}` : "";
238618
- lines.push(` ${typePart}${GREEN}${p.name}${RESET}${desc}`);
238785
+ lines.push(` ${typePart}${GREEN}${p.name}${RESET2}${desc}`);
238619
238786
  }
238620
238787
  }
238621
238788
  if (doc.returns) {
238622
- lines.push(` ${CYAN}Returns :${RESET} ${doc.returns}`);
238789
+ lines.push(` ${CYAN2}Returns :${RESET2} ${doc.returns}`);
238623
238790
  }
238624
238791
  }
238625
238792
  return lines.join("\n");
@@ -238637,13 +238804,37 @@ function findModulePath(root4, target, prefix = "frodo") {
238637
238804
  }
238638
238805
  function createHelpContext(frodoInstance) {
238639
238806
  const alphaSort = (a, b) => a.localeCompare(b);
238640
- const metadata = getHelpMetadataFromInstance(frodoInstance);
238807
+ const metadata = getHelpMetadataFromInstance2(frodoInstance);
238641
238808
  cachedIndex = null;
238642
238809
  function getMethodNames(obj) {
238643
238810
  return Object.keys(obj).filter(
238644
238811
  (k2) => typeof obj[k2] === "function"
238645
238812
  );
238646
238813
  }
238814
+ function getSubModuleNames(obj) {
238815
+ return Object.keys(obj).filter((k2) => {
238816
+ const value = obj[k2];
238817
+ return typeof value === "object" && value !== null;
238818
+ });
238819
+ }
238820
+ function getCountParts(methodCount, subModuleCount) {
238821
+ const parts = [];
238822
+ if (methodCount > 0)
238823
+ parts.push(`${methodCount} ${methodCount === 1 ? "method" : "methods"}`);
238824
+ if (subModuleCount > 0)
238825
+ parts.push(
238826
+ `${subModuleCount} ${subModuleCount === 1 ? "module" : "modules"}`
238827
+ );
238828
+ return parts;
238829
+ }
238830
+ function formatCountSuffix(methodCount, subModuleCount) {
238831
+ const parts = getCountParts(methodCount, subModuleCount);
238832
+ return parts.length > 0 ? ` (${parts.join(", ")})` : "";
238833
+ }
238834
+ function formatCountLabel(methodCount, subModuleCount) {
238835
+ const parts = getCountParts(methodCount, subModuleCount);
238836
+ return parts.length > 0 ? ` - ${parts.join(", ")}` : "";
238837
+ }
238647
238838
  function help(target) {
238648
238839
  const idx = getMethodIndex(metadata);
238649
238840
  if (target === void 0) {
@@ -238656,42 +238847,39 @@ function createHelpContext(frodoInstance) {
238656
238847
  );
238657
238848
  const sortedFns = [...fns].sort(alphaSort);
238658
238849
  const sortedMods = [...mods].sort(alphaSort);
238659
- console.log(`${BOLD}${CYAN}Frodo Shell - Help System${RESET}`);
238850
+ console.log(`${BOLD}${CYAN2}Frodo Shell - Help System${RESET2}`);
238660
238851
  console.log("");
238852
+ console.log(` ${GREEN}help()${RESET2} ${DIM2}this overview${RESET2}`);
238661
238853
  console.log(
238662
- ` ${GREEN}help()${RESET} -> this overview`
238663
- );
238664
- console.log(
238665
- ` ${GREEN}help(frodo.<sub-module>)${RESET} -> list all methods in <sub-module>`
238854
+ ` ${GREEN}help(frodo.<module>)${RESET2} ${DIM2}list all methods and modules in <module>${RESET2}`
238666
238855
  );
238667
238856
  console.log(
238668
- ` ${GREEN}help(frodo.<sub-module>.<method name>)${RESET} -> full signature + docs for a method`
238857
+ ` ${GREEN}help(frodo.<module>.<method>)${RESET2} ${DIM2}full signature + docs for a method${RESET2}`
238669
238858
  );
238670
238859
  console.log(
238671
- ` ${GREEN}help("methodName")${RESET} -> search for a method across all modules`
238860
+ ` ${GREEN}help("methodName")${RESET2} ${DIM2}search for a method across all modules${RESET2}`
238672
238861
  );
238673
238862
  console.log("");
238674
- console.log(`${BOLD}Modules:${RESET}`);
238863
+ const modulesCountLabel = sortedMods.length > 0 ? ` (${sortedMods.length} ${sortedMods.length === 1 ? "module" : "modules"})` : "";
238864
+ console.log(`${BOLD}Modules${modulesCountLabel}:${RESET2}`);
238675
238865
  for (const k2 of sortedMods) {
238676
238866
  const val = frodoInstance[k2];
238677
238867
  if (typeof val === "object" && val !== null) {
238678
- const count = getMethodNames(val).length;
238679
- if (count > 0) {
238680
- console.log(
238681
- ` frodo.${GREEN}${k2}${RESET} ${DIM}(${count} methods)${RESET}`
238682
- );
238683
- } else {
238684
- console.log(` frodo.${GREEN}${k2}${RESET}`);
238685
- }
238868
+ const methodCount = getMethodNames(val).length;
238869
+ const subModuleCount = getSubModuleNames(val).length;
238870
+ const countSuffix = formatCountSuffix(methodCount, subModuleCount);
238871
+ console.log(
238872
+ ` frodo.${GREEN}${k2}${RESET2}${countSuffix ? ` ${DIM2}${countSuffix}${RESET2}` : ""}`
238873
+ );
238686
238874
  }
238687
238875
  }
238688
238876
  if (sortedFns.length > 0) {
238689
238877
  console.log("");
238690
- console.log(`${BOLD}Factory helpers:${RESET}`);
238878
+ console.log(`${BOLD}Factory helpers:${RESET2}`);
238691
238879
  for (const fn of sortedFns) {
238692
238880
  const docs = idx.get(fn);
238693
- const sigHint = _optionalChain([docs, 'optionalAccess', _580 => _580.length]) ? ` ${DIM}${docs[0].signature}${RESET}` : "";
238694
- console.log(` frodo.${GREEN}${fn}${RESET}${sigHint}`);
238881
+ const sigHint = _optionalChain([docs, 'optionalAccess', _582 => _582.length]) ? ` ${DIM2}${docs[0].signature}${RESET2}` : "";
238882
+ console.log(` frodo.${GREEN}${fn}${RESET2}${sigHint}`);
238695
238883
  }
238696
238884
  }
238697
238885
  return;
@@ -238702,7 +238890,7 @@ function createHelpContext(frodoInstance) {
238702
238890
  const matches = idx.get(methodName);
238703
238891
  if (!matches || matches.length === 0) {
238704
238892
  console.log(
238705
- `${YELLOW}No documentation found for "${methodName}".${RESET}`
238893
+ `${YELLOW}No documentation found for "${methodName}".${RESET2}`
238706
238894
  );
238707
238895
  return;
238708
238896
  }
@@ -238716,20 +238904,20 @@ function createHelpContext(frodoInstance) {
238716
238904
  const fnName = target.name;
238717
238905
  if (!fnName) {
238718
238906
  console.log(
238719
- `${YELLOW}Cannot determine function name from this reference.${RESET}`
238907
+ `${YELLOW}Cannot determine function name from this reference.${RESET2}`
238720
238908
  );
238721
238909
  return;
238722
238910
  }
238723
238911
  const matches = idx.get(fnName);
238724
238912
  if (!matches || matches.length === 0) {
238725
- console.log(`${YELLOW}No documentation found for "${fnName}".${RESET}`);
238913
+ console.log(`${YELLOW}No documentation found for "${fnName}".${RESET2}`);
238726
238914
  return;
238727
238915
  }
238728
238916
  if (matches.length === 1) {
238729
238917
  console.log(formatMethodDoc(matches[0], true));
238730
238918
  } else {
238731
238919
  console.log(
238732
- `${YELLOW}Found "${fnName}" in ${matches.length} module types:${RESET}`
238920
+ `${YELLOW}Found "${fnName}" in ${matches.length} module types:${RESET2}`
238733
238921
  );
238734
238922
  for (const doc of matches) {
238735
238923
  console.log("");
@@ -238740,24 +238928,39 @@ function createHelpContext(frodoInstance) {
238740
238928
  }
238741
238929
  if (typeof target === "object" && target !== null) {
238742
238930
  const methods = getMethodNames(target);
238743
- const subMods = Object.keys(target).filter((k2) => {
238744
- const v = target[k2];
238745
- return typeof v === "object" && v !== null;
238746
- });
238931
+ const subMods = getSubModuleNames(target);
238747
238932
  const sortedMethods = [...methods].sort(alphaSort);
238748
238933
  const sortedSubMods = [...subMods].sort(alphaSort);
238934
+ const methodCount = sortedMethods.length;
238935
+ const subModuleCount = sortedSubMods.length;
238936
+ const moduleType = _optionalChain([findModulePath, 'call', _583 => _583(frodoInstance, target), 'optionalAccess', _584 => _584.replace, 'call', _585 => _585(
238937
+ /^frodo\./,
238938
+ ""
238939
+ )]) || "Module";
238940
+ console.log(
238941
+ `${BOLD}${CYAN2}${moduleType}${formatCountLabel(methodCount, subModuleCount)}${RESET2}`
238942
+ );
238943
+ console.log("");
238749
238944
  if (sortedMethods.length === 0) {
238750
238945
  if (sortedSubMods.length > 0) {
238751
- console.log(`${BOLD}Sub-modules:${RESET}`);
238946
+ console.log(
238947
+ `${BOLD}Modules (${subModuleCount} ${subModuleCount === 1 ? "module" : "modules"}):${RESET2}`
238948
+ );
238752
238949
  for (const subModule of sortedSubMods) {
238753
- console.log(` ${GREEN}${subModule}${RESET}`);
238950
+ const subModuleObj = target[subModule];
238951
+ const subMethods = typeof subModuleObj === "object" && subModuleObj !== null ? getMethodNames(subModuleObj).length : 0;
238952
+ const nestedSubMods = typeof subModuleObj === "object" && subModuleObj !== null ? getSubModuleNames(subModuleObj).length : 0;
238953
+ const countSuffix = formatCountSuffix(subMethods, nestedSubMods);
238954
+ console.log(
238955
+ ` ${GREEN}${subModule}${RESET2}${countSuffix ? ` ${DIM2}${countSuffix}${RESET2}` : ""}`
238956
+ );
238754
238957
  }
238755
238958
  const subModPath = _nullishCoalesce(findModulePath(frodoInstance, target), () => ( "frodo.X"));
238756
238959
  console.log(
238757
- `Use ${GREEN}help(${subModPath}.<sub-module>)${RESET} to explore further.`
238960
+ `Use ${GREEN}help(${subModPath}.<module>)${RESET2} to explore further.`
238758
238961
  );
238759
238962
  } else {
238760
- console.log(`${YELLOW}No methods found on this object.${RESET}`);
238963
+ console.log(`${YELLOW}No methods found on this object.${RESET2}`);
238761
238964
  }
238762
238965
  return;
238763
238966
  }
@@ -238776,39 +238979,47 @@ function createHelpContext(frodoInstance) {
238776
238979
  }
238777
238980
  }
238778
238981
  if (sortedSubMods.length > 0) {
238779
- console.log(`${BOLD}Sub-modules:${RESET}`);
238982
+ console.log(
238983
+ `${BOLD}Modules (${subModuleCount} ${subModuleCount === 1 ? "module" : "modules"}):${RESET2}`
238984
+ );
238780
238985
  for (const subModule of sortedSubMods) {
238781
- console.log(` ${GREEN}${subModule}${RESET}`);
238986
+ const subModuleObj = target[subModule];
238987
+ const subMethods = typeof subModuleObj === "object" && subModuleObj !== null ? getMethodNames(subModuleObj).length : 0;
238988
+ const nestedSubMods = typeof subModuleObj === "object" && subModuleObj !== null ? getSubModuleNames(subModuleObj).length : 0;
238989
+ const countSuffix = formatCountSuffix(subMethods, nestedSubMods);
238990
+ console.log(
238991
+ ` ${GREEN}${subModule}${RESET2}${countSuffix ? ` ${DIM2}${countSuffix}${RESET2}` : ""}`
238992
+ );
238782
238993
  }
238783
238994
  console.log("");
238784
238995
  }
238785
238996
  console.log(
238786
- `${BOLD}${CYAN}${bestType || "Module"} - ${sortedMethods.length} method(s):${RESET}`
238997
+ `${BOLD}${CYAN2}${bestType || moduleType}${formatCountLabel(methodCount, subModuleCount)}:${RESET2}`
238787
238998
  );
238788
238999
  console.log("");
238789
239000
  for (const methodName of sortedMethods) {
238790
239001
  const docs = idx.get(methodName);
238791
- const doc = _nullishCoalesce(_optionalChain([docs, 'optionalAccess', _581 => _581.find, 'call', _582 => _582((d3) => d3.typeName === bestType)]), () => ( _optionalChain([docs, 'optionalAccess', _583 => _583[0]])));
239002
+ const doc = _nullishCoalesce(_optionalChain([docs, 'optionalAccess', _586 => _586.find, 'call', _587 => _587((d3) => d3.typeName === bestType)]), () => ( _optionalChain([docs, 'optionalAccess', _588 => _588[0]])));
238792
239003
  if (doc) {
238793
239004
  const sig = doc.signature.length > 100 ? doc.signature.slice(0, 97) + "..." : doc.signature;
238794
- console.log(` ${YELLOW}${sig}${RESET}`);
239005
+ console.log(` ${YELLOW}${sig}${RESET2}`);
238795
239006
  if (doc.description) {
238796
239007
  const desc = doc.description.length > 110 ? doc.description.slice(0, 107) + "..." : doc.description;
238797
- console.log(` ${DIM}${desc}${RESET}`);
239008
+ console.log(` ${DIM2}${desc}${RESET2}`);
238798
239009
  }
238799
239010
  } else {
238800
- console.log(` ${YELLOW}${methodName}(...)${RESET}`);
239011
+ console.log(` ${YELLOW}${methodName}(...)${RESET2}`);
238801
239012
  }
238802
239013
  console.log("");
238803
239014
  }
238804
239015
  const modPath = _nullishCoalesce(findModulePath(frodoInstance, target), () => ( "frodo.X"));
238805
239016
  console.log(
238806
- `Tip: ${GREEN}help(${modPath}.<method name>)${RESET} shows full parameter documentation.`
239017
+ `Tip: ${GREEN}help(${modPath}.<method name>)${RESET2} shows full parameter documentation.`
238807
239018
  );
238808
239019
  return;
238809
239020
  }
238810
239021
  console.log(
238811
- `${YELLOW}Usage: help() | help(frodo.<sub-module>) | help(frodo.<sub-module>.<method name>) | help("methodName")${RESET}`
239022
+ `${YELLOW}Usage: help() | help(frodo.<module>) | help(frodo.<module>.<method name>) | help("methodName")${RESET2}`
238812
239023
  );
238813
239024
  }
238814
239025
  return { help };
@@ -238896,12 +239107,36 @@ var ShellHistory = class {
238896
239107
  };
238897
239108
 
238898
239109
  // src/cli/shell/shell.ts
239110
+ function printHintAbovePrompt(replServer, hint) {
239111
+ if (!replServer) return;
239112
+ setImmediate(() => {
239113
+ process.stdout.write(`
239114
+ ${hint}
239115
+ `);
239116
+ const refreshLine = replServer._refreshLine;
239117
+ if (typeof refreshLine === "function") {
239118
+ refreshLine.call(replServer);
239119
+ return;
239120
+ }
239121
+ replServer.displayPrompt(true);
239122
+ });
239123
+ }
238899
239124
  async function startRepl(allowAwait = false, host) {
239125
+ const docsByMethod = buildDocsByMethod(frodo);
239126
+ const rootBindings = {
239127
+ frodo,
239128
+ frodoLib: frodo
239129
+ };
239130
+ let _replServer;
239131
+ const completer = createFrodoCompleter(rootBindings, docsByMethod, (hint) => {
239132
+ printHintAbovePrompt(_replServer, hint);
239133
+ });
238900
239134
  const baseConfig = {
238901
239135
  prompt: "> ",
238902
239136
  ignoreUndefined: true,
238903
239137
  useGlobal: true,
238904
239138
  useColors: true,
239139
+ completer,
238905
239140
  writer: function(output) {
238906
239141
  if (typeof output === "object" && output !== null) {
238907
239142
  return _util2.default.inspect(output, {
@@ -238919,11 +239154,15 @@ async function startRepl(allowAwait = false, host) {
238919
239154
  callback(null, await _vm2.default.runInNewContext(cmd, context));
238920
239155
  }
238921
239156
  };
238922
- const replServer = _repl2.default.start(allowAwait ? baseConfig : configWithoutAwait);
239157
+ _replServer = _repl2.default.start(allowAwait ? baseConfig : configWithoutAwait);
239158
+ const replServer = _replServer;
238923
239159
  replServer.context.frodoLib = frodo;
238924
239160
  replServer.context.frodo = frodo;
238925
239161
  const { help } = createHelpContext(frodo);
238926
239162
  replServer.context.help = help;
239163
+ registerOpenParenHint(replServer, rootBindings, docsByMethod, (hint) => {
239164
+ printHintAbovePrompt(replServer, hint);
239165
+ });
238927
239166
  const shellHistory = new ShellHistory(host);
238928
239167
  replServer.history = shellHistory.getLines();
238929
239168
  replServer.defineCommand("history", {
@@ -238965,46 +239204,74 @@ async function startRepl(allowAwait = false, host) {
238965
239204
  help: "Show this help (frodo context + dot-commands)",
238966
239205
  action() {
238967
239206
  const BOLD2 = "\x1B[1m";
238968
- const RESET2 = "\x1B[0m";
238969
- const CYAN2 = "\x1B[36m";
239207
+ const RESET3 = "\x1B[0m";
239208
+ const CYAN3 = "\x1B[36m";
238970
239209
  const GREEN2 = "\x1B[32m";
238971
- const DIM2 = "\x1B[2m";
238972
- console.log(`${BOLD2}${CYAN2}Frodo Interactive Shell${RESET2}`);
239210
+ const DIM3 = "\x1B[2m";
239211
+ console.log(`${BOLD2}${CYAN3}Frodo Interactive Shell${RESET3}`);
238973
239212
  console.log("");
238974
- console.log(`${BOLD2}Explore the Frodo API:${RESET2}`);
239213
+ console.log(`${BOLD2}Explore the Frodo API:${RESET3}`);
238975
239214
  console.log(
238976
- ` ${GREEN2}help()${RESET2} ${DIM2}browse all modules and methods${RESET2}`
239215
+ ` ${GREEN2}help()${RESET3} ${DIM3}browse all modules and methods${RESET3}`
238977
239216
  );
238978
239217
  console.log(
238979
- ` ${GREEN2}help(frodo.X)${RESET2} ${DIM2}list all methods in module X${RESET2}`
239218
+ ` ${GREEN2}help(frodo.<module>)${RESET3} ${DIM3}list all methods in module X${RESET3}`
238980
239219
  );
238981
239220
  console.log(
238982
- ` ${GREEN2}help(frodo.X.method)${RESET2} ${DIM2}show full signature and docs${RESET2}`
239221
+ ` ${GREEN2}help(frodo.<module>.<method>)${RESET3} ${DIM3}show full signature and docs${RESET3}`
238983
239222
  );
238984
239223
  console.log(
238985
- ` ${GREEN2}help("methodName")${RESET2} ${DIM2}search for a method across all modules${RESET2}`
239224
+ ` ${GREEN2}help("methodName")${RESET3} ${DIM3}search for a method across all modules${RESET3}`
238986
239225
  );
238987
239226
  console.log("");
238988
- console.log(`${BOLD2}Sample commands:${RESET2}`);
239227
+ console.log(`${BOLD2}Sample commands:${RESET3}`);
238989
239228
  console.log(
238990
- ` ${GREEN2}frodo.info.getInfo()${RESET2} ${DIM2}print info about the connected environment${RESET2}`
239229
+ ` ${GREEN2}frodo.info.getInfo()${RESET3} ${DIM3}print info about the connected environment${RESET3}`
238991
239230
  );
238992
239231
  console.log(
238993
- ` ${GREEN2}frodo.login.getTokens()${RESET2} ${DIM2}get fresh or cached tokens${RESET2}`
239232
+ ` ${GREEN2}frodo.login.getTokens()${RESET3} ${DIM3}get fresh or cached tokens${RESET3}`
238994
239233
  );
238995
239234
  console.log(
238996
- ` ${GREEN2}frodo${RESET2} ${DIM2}show a hierarchy of all Frodo Library commands${RESET2}`
239235
+ ` ${GREEN2}frodo${RESET3} ${DIM3}show a hierarchy of all Frodo Library commands${RESET3}`
238997
239236
  );
238998
239237
  console.log("");
238999
- console.log(`${BOLD2}Shell dot-commands:${RESET2}`);
239238
+ console.log(`${BOLD2}Shell dot-commands:${RESET3}`);
239000
239239
  const commands = replServer.commands;
239001
239240
  for (const name of Object.keys(commands).sort()) {
239002
- const helpText = _nullishCoalesce(_optionalChain([commands, 'access', _584 => _584[name], 'optionalAccess', _585 => _585.help]), () => ( ""));
239003
- console.log(` ${GREEN2}.${name}${RESET2} ${DIM2}${helpText}${RESET2}`);
239241
+ const helpText = _nullishCoalesce(_optionalChain([commands, 'access', _589 => _589[name], 'optionalAccess', _590 => _590.help]), () => ( ""));
239242
+ console.log(` ${GREEN2}.${name}${RESET3} ${DIM3}${helpText}${RESET3}`);
239004
239243
  }
239005
239244
  this.displayPrompt();
239006
239245
  }
239007
239246
  });
239247
+ let historyNavigationActive = false;
239248
+ process.stdin.on("keypress", (_char, key) => {
239249
+ const rl = replServer;
239250
+ const currentHistIdx = _nullishCoalesce(rl["_historyIndex"], () => ( -1));
239251
+ if (_optionalChain([key, 'optionalAccess', _591 => _591.name]) === "down" && !historyNavigationActive && currentHistIdx === -1) {
239252
+ const currentLine = _nullishCoalesce(replServer.line, () => ( ""));
239253
+ if (currentLine.trim().length > 0) {
239254
+ const replHistory = _nullishCoalesce(rl["history"], () => ( []));
239255
+ if (replHistory[0] !== currentLine) {
239256
+ replHistory.unshift(currentLine);
239257
+ shellHistory.addLine(currentLine);
239258
+ }
239259
+ replServer.write(null, { ctrl: true, name: "e" });
239260
+ replServer.write(null, { ctrl: true, name: "u" });
239261
+ }
239262
+ }
239263
+ if (_optionalChain([key, 'optionalAccess', _592 => _592.name]) === "up" || _optionalChain([key, 'optionalAccess', _593 => _593.name]) === "down") {
239264
+ historyNavigationActive = true;
239265
+ return;
239266
+ }
239267
+ if (_optionalChain([key, 'optionalAccess', _594 => _594.name]) === "return" || _optionalChain([key, 'optionalAccess', _595 => _595.name]) === "enter") {
239268
+ historyNavigationActive = false;
239269
+ return;
239270
+ }
239271
+ if (_optionalChain([key, 'optionalAccess', _596 => _596.ctrl]) || _optionalChain([key, 'optionalAccess', _597 => _597.meta]) || typeof _optionalChain([key, 'optionalAccess', _598 => _598.name]) === "string") {
239272
+ historyNavigationActive = false;
239273
+ }
239274
+ });
239008
239275
  replServer.on("line", (line) => {
239009
239276
  shellHistory.addLine(line);
239010
239277
  });
@@ -239407,7 +239674,7 @@ var compareVersions = (v12, v2) => {
239407
239674
  // package.json
239408
239675
  var package_default2 = {
239409
239676
  name: "@rockcarver/frodo-cli",
239410
- version: "4.0.0-24",
239677
+ version: "4.0.0-26",
239411
239678
  type: "module",
239412
239679
  description: "A command line interface to manage ForgeRock Identity Cloud tenants, ForgeOps deployments, and classic deployments.",
239413
239680
  keywords: [