@reliverse/rempts 1.7.29 → 1.7.30

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 (128) hide show
  1. package/README.md +92 -29
  2. package/bin/{components/animate/animate.js → libs/animate/animate-mod.js} +1 -4
  3. package/bin/{components → libs}/anykey/anykey-mod.js +2 -2
  4. package/bin/libs/confirm/confirm-alias.d.ts +1 -0
  5. package/bin/libs/confirm/confirm-alias.js +2 -0
  6. package/bin/{components/confirm/confirm-prompt.js → libs/confirm/confirm-mod.js} +1 -1
  7. package/bin/{components → libs}/editor/editor-mod.js +8 -8
  8. package/bin/{components → libs}/figures/figures-mod.d.ts +2 -3
  9. package/bin/{components → libs}/figures/figures-mod.js +1 -2
  10. package/bin/libs/input/input-alias.d.ts +4 -0
  11. package/bin/libs/input/input-alias.js +4 -0
  12. package/bin/{components/input/input-prompt.js → libs/input/input-mod.js} +2 -2
  13. package/bin/libs/intro/intro-alias.d.ts +2 -0
  14. package/bin/libs/intro/intro-alias.js +3 -0
  15. package/bin/{components/intro/intro-start.js → libs/intro/intro-mod.js} +3 -3
  16. package/bin/libs/launcher/launcher-alias.d.ts +2 -0
  17. package/bin/libs/launcher/launcher-alias.js +2 -0
  18. package/bin/{components → libs}/launcher/launcher-mod.d.ts +37 -5
  19. package/bin/{components → libs}/launcher/launcher-mod.js +326 -205
  20. package/bin/{components → libs}/launcher/launcher-types.d.ts +1 -1
  21. package/bin/libs/launcher/trpc-orpc-support/completions.d.ts +4 -0
  22. package/bin/libs/launcher/trpc-orpc-support/completions.js +45 -0
  23. package/bin/libs/launcher/trpc-orpc-support/errors.d.ts +11 -0
  24. package/bin/libs/launcher/trpc-orpc-support/errors.js +10 -0
  25. package/bin/libs/launcher/trpc-orpc-support/index.d.ts +34 -0
  26. package/bin/libs/launcher/trpc-orpc-support/index.js +641 -0
  27. package/bin/libs/launcher/trpc-orpc-support/json-schema.d.ts +17 -0
  28. package/bin/libs/launcher/trpc-orpc-support/json-schema.js +168 -0
  29. package/bin/libs/launcher/trpc-orpc-support/json.d.ts +44 -0
  30. package/bin/libs/launcher/trpc-orpc-support/json.js +41 -0
  31. package/bin/libs/launcher/trpc-orpc-support/logging.d.ts +11 -0
  32. package/bin/libs/launcher/trpc-orpc-support/logging.js +26 -0
  33. package/bin/libs/launcher/trpc-orpc-support/parse-procedure.d.ts +2 -0
  34. package/bin/libs/launcher/trpc-orpc-support/parse-procedure.js +486 -0
  35. package/bin/libs/launcher/trpc-orpc-support/prompts.d.ts +18 -0
  36. package/bin/libs/launcher/trpc-orpc-support/prompts.js +534 -0
  37. package/bin/libs/launcher/trpc-orpc-support/standard-schema/contract.d.ts +53 -0
  38. package/bin/libs/launcher/trpc-orpc-support/standard-schema/contract.js +0 -0
  39. package/bin/libs/launcher/trpc-orpc-support/standard-schema/errors.d.ts +9 -0
  40. package/bin/libs/launcher/trpc-orpc-support/standard-schema/errors.js +47 -0
  41. package/bin/libs/launcher/trpc-orpc-support/standard-schema/utils.d.ts +3 -0
  42. package/bin/libs/launcher/trpc-orpc-support/standard-schema/utils.js +6 -0
  43. package/bin/libs/launcher/trpc-orpc-support/trpc-compat.d.ts +71 -0
  44. package/bin/libs/launcher/trpc-orpc-support/trpc-compat.js +11 -0
  45. package/bin/libs/launcher/trpc-orpc-support/types.d.ts +276 -0
  46. package/bin/libs/launcher/trpc-orpc-support/types.js +0 -0
  47. package/bin/libs/launcher/trpc-orpc-support/util.d.ts +9 -0
  48. package/bin/libs/launcher/trpc-orpc-support/util.js +9 -0
  49. package/bin/{components → libs}/msg-fmt/logger.js +1 -1
  50. package/bin/libs/multiselect/multiselect-alias.d.ts +1 -0
  51. package/bin/libs/multiselect/multiselect-alias.js +2 -0
  52. package/bin/{components/select → libs/multiselect}/multiselect-prompt.js +1 -1
  53. package/bin/{components → libs}/number/number-mod.js +1 -4
  54. package/bin/libs/outro/outro-alias.d.ts +2 -0
  55. package/bin/libs/outro/outro-alias.js +3 -0
  56. package/bin/{components/outro/outro-end.js → libs/outro/outro-mod.js} +2 -2
  57. package/bin/libs/select/aliases-alias.d.ts +1 -0
  58. package/bin/libs/select/aliases-alias.js +2 -0
  59. package/bin/{components → libs}/select/select-prompt.js +2 -2
  60. package/bin/{components → libs}/select/toggle-prompt.js +1 -1
  61. package/bin/libs/spinner/spinner-alias.d.ts +1 -0
  62. package/bin/libs/spinner/spinner-alias.js +2 -0
  63. package/bin/{components → libs}/spinner/spinner-mod.js +3 -1
  64. package/bin/{components → libs}/task/task-spin.js +1 -1
  65. package/bin/{utils → libs/utils}/colorize.d.ts +1 -1
  66. package/bin/{utils → libs/utils}/prevent.d.ts +1 -1
  67. package/bin/{utils → libs/utils}/prevent.js +2 -2
  68. package/bin/{utils → libs/utils}/prompt-end.d.ts +1 -1
  69. package/bin/{utils → libs/utils}/prompt-end.js +2 -2
  70. package/bin/{utils → libs/utils}/stream-text.d.ts +1 -1
  71. package/bin/{utils → libs/utils}/stream-text.js +2 -2
  72. package/bin/mod.d.ts +66 -41
  73. package/bin/mod.js +102 -66
  74. package/package.json +16 -2
  75. package/bin/components/aliases/aliases-mod.d.ts +0 -11
  76. package/bin/components/aliases/aliases-mod.js +0 -16
  77. /package/bin/{components/animate/animate.d.ts → libs/animate/animate-mod.d.ts} +0 -0
  78. /package/bin/{components → libs}/anykey/anykey-mod.d.ts +0 -0
  79. /package/bin/{components → libs}/cancel/cancel.d.ts +0 -0
  80. /package/bin/{components → libs}/cancel/cancel.js +0 -0
  81. /package/bin/{components/confirm/confirm-prompt.d.ts → libs/confirm/confirm-mod.d.ts} +0 -0
  82. /package/bin/{components → libs}/date/date.d.ts +0 -0
  83. /package/bin/{components → libs}/date/date.js +0 -0
  84. /package/bin/{components → libs}/editor/editor-mod.d.ts +0 -0
  85. /package/bin/{components/input/input-prompt.d.ts → libs/input/input-mod.d.ts} +0 -0
  86. /package/bin/{components/intro/intro-start.d.ts → libs/intro/intro-mod.d.ts} +0 -0
  87. /package/bin/{components → libs}/launcher/launcher-types.js +0 -0
  88. /package/bin/{components → libs}/launcher/run-command.d.ts +0 -0
  89. /package/bin/{components → libs}/launcher/run-command.js +0 -0
  90. /package/bin/{components/log/log.d.ts → libs/log/log-alias.d.ts} +0 -0
  91. /package/bin/{components/log/log.js → libs/log/log-alias.js} +0 -0
  92. /package/bin/{components → libs}/msg-fmt/colors.d.ts +0 -0
  93. /package/bin/{components → libs}/msg-fmt/colors.js +0 -0
  94. /package/bin/{components → libs}/msg-fmt/logger.d.ts +0 -0
  95. /package/bin/{components → libs}/msg-fmt/mapping.d.ts +0 -0
  96. /package/bin/{components → libs}/msg-fmt/mapping.js +0 -0
  97. /package/bin/{components → libs}/msg-fmt/messages.d.ts +0 -0
  98. /package/bin/{components → libs}/msg-fmt/messages.js +0 -0
  99. /package/bin/{components → libs}/msg-fmt/terminal.d.ts +0 -0
  100. /package/bin/{components → libs}/msg-fmt/terminal.js +0 -0
  101. /package/bin/{components → libs}/msg-fmt/variants.d.ts +0 -0
  102. /package/bin/{components → libs}/msg-fmt/variants.js +0 -0
  103. /package/bin/{components/select → libs/multiselect}/multiselect-prompt.d.ts +0 -0
  104. /package/bin/{components → libs}/next-steps/next-steps.d.ts +0 -0
  105. /package/bin/{components → libs}/next-steps/next-steps.js +0 -0
  106. /package/bin/{components → libs}/number/number-mod.d.ts +0 -0
  107. /package/bin/{components/outro/outro-end.d.ts → libs/outro/outro-mod.d.ts} +0 -0
  108. /package/bin/{components → libs}/results/results.d.ts +0 -0
  109. /package/bin/{components → libs}/results/results.js +0 -0
  110. /package/bin/{components → libs}/select/nummultiselect-prompt.d.ts +0 -0
  111. /package/bin/{components → libs}/select/nummultiselect-prompt.js +0 -0
  112. /package/bin/{components → libs}/select/numselect-prompt.d.ts +0 -0
  113. /package/bin/{components → libs}/select/numselect-prompt.js +0 -0
  114. /package/bin/{components → libs}/select/select-prompt.d.ts +0 -0
  115. /package/bin/{components → libs}/select/toggle-prompt.d.ts +0 -0
  116. /package/bin/{components → libs}/spinner/spinner-mod.d.ts +0 -0
  117. /package/bin/{components → libs}/task/progress.d.ts +0 -0
  118. /package/bin/{components → libs}/task/progress.js +0 -0
  119. /package/bin/{components → libs}/task/task-spin.d.ts +0 -0
  120. /package/bin/{utils → libs/utils}/colorize.js +0 -0
  121. /package/bin/{utils → libs/utils}/errors.d.ts +0 -0
  122. /package/bin/{utils → libs/utils}/errors.js +0 -0
  123. /package/bin/{utils → libs/utils}/system.d.ts +0 -0
  124. /package/bin/{utils → libs/utils}/system.js +0 -0
  125. /package/bin/{utils → libs/utils}/validate.d.ts +0 -0
  126. /package/bin/{utils → libs/utils}/validate.js +0 -0
  127. /package/bin/{components/ascii-art/ascii-art.d.ts → libs/visual/visual-mod.d.ts} +0 -0
  128. /package/bin/{components/ascii-art/ascii-art.js → libs/visual/visual-mod.js} +0 -0
@@ -7,21 +7,21 @@ import process from "node:process";
7
7
  import { readPackageJSON } from "pkg-types";
8
8
  function buildExampleArgs(args) {
9
9
  const parts = [];
10
- const positionalKeys = Object.keys(args).filter(
11
- (k) => args[k].type === "positional"
10
+ const positionalKeys = Object.keys(args || {}).filter(
11
+ (k) => args?.[k]?.type === "positional"
12
12
  );
13
13
  positionalKeys.forEach((key) => {
14
- const def = args[key];
15
- if (def.required || Math.random() > 0.5) {
14
+ const def = args?.[key];
15
+ if (def && (def.required || Math.random() > 0.5)) {
16
16
  parts.push(String(def.default ?? `<${key}>`));
17
17
  }
18
18
  });
19
- const otherKeys = Object.keys(args).filter(
20
- (k) => args[k].type !== "positional"
19
+ const otherKeys = Object.keys(args || {}).filter(
20
+ (k) => args?.[k]?.type !== "positional"
21
21
  );
22
22
  for (const key of otherKeys) {
23
- const def = args[key];
24
- if (def.required || Math.random() > 0.7) {
23
+ const def = args?.[key];
24
+ if (def && (def.required || Math.random() > 0.7)) {
25
25
  switch (def.type) {
26
26
  case "boolean":
27
27
  if (def.default === true) {
@@ -145,13 +145,13 @@ function formatTableRow(text, desc, padding) {
145
145
  const spaces = " ".repeat(Math.max(0, padding - text.length));
146
146
  return `${text}${spaces}| ${desc || ""}`;
147
147
  }
148
- export async function showUsage(command, parserOptions = {}) {
148
+ export async function showUsage(command, parserOptions = {}, globalCliMeta) {
149
149
  const { name: fallbackName, version: fallbackVersion } = await getDefaultCliNameAndVersion();
150
- const cliName = command.meta?.name || fallbackName;
151
- const cliVersion = command.meta?.version || fallbackVersion;
150
+ const cliName = globalCliMeta?.name || command.meta?.name || fallbackName;
151
+ const cliVersion = globalCliMeta?.version || command.meta?.version || fallbackVersion;
152
152
  relinka("info", `${cliName}${cliVersion ? ` v${cliVersion}` : ""}`);
153
153
  if (parserOptions.metaSettings?.showDescriptionOnMain) {
154
- let description = command.meta?.description;
154
+ let description = globalCliMeta?.description || command.meta?.description;
155
155
  if (!description) {
156
156
  try {
157
157
  const pkg = await readPackageJSON();
@@ -164,7 +164,7 @@ export async function showUsage(command, parserOptions = {}) {
164
164
  }
165
165
  }
166
166
  const { name: pkgName } = await getDefaultCliNameAndVersion();
167
- const fileCmds = parserOptions.fileBasedCmds;
167
+ const fileCmds = parserOptions.fileBased;
168
168
  if (fileCmds?.enable) {
169
169
  const commandsDir = path.resolve(fileCmds.cmdsRootPath);
170
170
  const pathSegments = parserOptions._fileBasedPathSegments || [];
@@ -184,16 +184,19 @@ export async function showUsage(command, parserOptions = {}) {
184
184
  if (pos) usageLine += ` ${pos}`;
185
185
  }
186
186
  relinka("log", re.cyan(`Usage: ${usageLine}`));
187
- if (directCommands.length > 0) {
187
+ if (directCommands.length > 0 && allCommands.length > 0) {
188
188
  const randomIdx = Math.floor(Math.random() * allCommands.length);
189
- const { path: path2, def: exampleDef } = allCommands[randomIdx];
190
- const exampleArgs = buildExampleArgs(exampleDef.args || {});
191
- relinka(
192
- "log",
193
- re.cyan(
194
- `Example: ${pkgName} ${path2.join(" ")}${exampleArgs ? ` ${exampleArgs}` : ""}`
195
- )
196
- );
189
+ const exampleCmd = allCommands[randomIdx];
190
+ if (exampleCmd) {
191
+ const { path: path2, def: exampleDef } = exampleCmd;
192
+ const exampleArgs = buildExampleArgs(exampleDef.args || {});
193
+ relinka(
194
+ "log",
195
+ re.cyan(
196
+ `Example: ${pkgName} ${path2.join(" ")}${exampleArgs ? ` ${exampleArgs}` : ""}`
197
+ )
198
+ );
199
+ }
197
200
  }
198
201
  if (allCommands.length > 0) {
199
202
  relinka("info", "Available commands (run with `help` to see more):");
@@ -203,7 +206,10 @@ export async function showUsage(command, parserOptions = {}) {
203
206
  if (!commandsByPath.has(parentPath)) {
204
207
  commandsByPath.set(parentPath, []);
205
208
  }
206
- commandsByPath.get(parentPath).push(cmd);
209
+ const group = commandsByPath.get(parentPath);
210
+ if (group) {
211
+ group.push(cmd);
212
+ }
207
213
  }
208
214
  const groupPaddings = /* @__PURE__ */ new Map();
209
215
  for (const [parentPath, cmds] of commandsByPath) {
@@ -217,7 +223,7 @@ export async function showUsage(command, parserOptions = {}) {
217
223
  if (parentPath !== "/") {
218
224
  relinka("log", re.cyanPastel(`Sub-commands in ${parentPath}:`));
219
225
  }
220
- const padding = groupPaddings.get(parentPath);
226
+ const padding = groupPaddings.get(parentPath) || 0;
221
227
  for (const { def, path: path2 } of cmds) {
222
228
  const desc = def?.meta?.description ?? "";
223
229
  const indent = parentPath === "/" ? "" : " ";
@@ -235,7 +241,7 @@ export async function showUsage(command, parserOptions = {}) {
235
241
  try {
236
242
  const cmd = await loadSubCommand(spec);
237
243
  if (!cmd?.meta?.hidden) {
238
- const aliasDisplay = cmd.meta.aliases ? ` (aliases: ${cmd.meta.aliases.join(", ")})` : "";
244
+ const aliasDisplay = cmd.meta?.aliases ? ` (aliases: ${cmd.meta.aliases.join(", ")})` : "";
239
245
  subCommandNames.push(`${name}${aliasDisplay}`);
240
246
  subCommandDefs.push({ name, def: cmd });
241
247
  }
@@ -256,14 +262,17 @@ export async function showUsage(command, parserOptions = {}) {
256
262
  relinka("log", re.cyan(`Usage: ${usageLine}`));
257
263
  if (subCommandDefs.length > 0) {
258
264
  const randomIdx = Math.floor(Math.random() * subCommandDefs.length);
259
- const { name: exampleCmd, def: exampleDef } = subCommandDefs[randomIdx];
260
- const exampleArgs = buildExampleArgs(exampleDef.args || {});
261
- relinka(
262
- "log",
263
- re.cyan(
264
- `Example: ${pkgName}${parserOptions._isSubcommand ? ` ${cliName}` : ""} ${exampleCmd}${exampleArgs ? ` ${exampleArgs}` : ""}`
265
- )
266
- );
265
+ const exampleCmd = subCommandDefs[randomIdx];
266
+ if (exampleCmd) {
267
+ const { name: exampleCmdName, def: exampleDef } = exampleCmd;
268
+ const exampleArgs = buildExampleArgs(exampleDef.args || {});
269
+ relinka(
270
+ "log",
271
+ re.cyan(
272
+ `Example: ${pkgName}${parserOptions._isSubcommand ? ` ${cliName}` : ""} ${exampleCmdName}${exampleArgs ? ` ${exampleArgs}` : ""}`
273
+ )
274
+ );
275
+ }
267
276
  }
268
277
  if (subCommandNames.length > 0) {
269
278
  relinka("info", "Available commands (run with `help` to see more):");
@@ -306,158 +315,268 @@ export async function showUsage(command, parserOptions = {}) {
306
315
  relinka("log", formatTableRow(text, desc, optionsPadding));
307
316
  }
308
317
  }
309
- export async function runMain(command, parserOptions = {}) {
310
- if (typeof command.onLauncherInit === "function") {
311
- try {
312
- await command.onLauncherInit();
313
- } catch (err) {
314
- relinka("error", "Error in onLauncherInit:", err);
315
- if (parserOptions.autoExit !== false) process.exit(1);
316
- throw err;
318
+ export function createCli(options, legacyParserOptions) {
319
+ let command;
320
+ let parserOptions;
321
+ let globalCliMeta = {};
322
+ if (typeof options === "object" && !("run" in options) && !("meta" in options) && !("args" in options) && !("commands" in options)) {
323
+ command = options;
324
+ parserOptions = legacyParserOptions || {};
325
+ } else if ("mainCommand" in options) {
326
+ command = options.mainCommand;
327
+ parserOptions = {
328
+ fileBased: options.fileBased,
329
+ autoExit: options.autoExit,
330
+ metaSettings: options.metaSettings
331
+ };
332
+ globalCliMeta = {
333
+ name: options.name,
334
+ version: options.version,
335
+ description: options.description
336
+ };
337
+ } else {
338
+ const inlineOptions = options;
339
+ const {
340
+ name,
341
+ version,
342
+ description,
343
+ fileBased,
344
+ autoExit,
345
+ metaSettings,
346
+ mainCommand,
347
+ ...commandOptions
348
+ } = inlineOptions;
349
+ command = {
350
+ meta: commandOptions.meta,
351
+ args: commandOptions.args,
352
+ run: commandOptions.run,
353
+ commands: commandOptions.commands,
354
+ onCmdInit: commandOptions.onCmdInit,
355
+ onCmdExit: commandOptions.onCmdExit,
356
+ onLauncherInit: commandOptions.onLauncherInit,
357
+ onLauncherExit: commandOptions.onLauncherExit
358
+ };
359
+ parserOptions = {
360
+ fileBased,
361
+ autoExit,
362
+ metaSettings
363
+ };
364
+ globalCliMeta = { name, version, description };
365
+ }
366
+ if (command.run && (globalCliMeta.name || globalCliMeta.version || globalCliMeta.description)) {
367
+ const mergedMeta = { ...command.meta };
368
+ if (globalCliMeta.name && !command.meta?.name) {
369
+ mergedMeta.name = globalCliMeta.name;
317
370
  }
371
+ if (globalCliMeta.version && !command.meta?.version) {
372
+ mergedMeta.version = globalCliMeta.version;
373
+ }
374
+ if (globalCliMeta.description && !command.meta?.description) {
375
+ mergedMeta.description = globalCliMeta.description;
376
+ }
377
+ command = {
378
+ ...command,
379
+ meta: mergedMeta
380
+ };
318
381
  }
319
- try {
320
- if (!parserOptions.fileBasedCmds && !command.commands) {
321
- const mainEntry = process.argv[1] ? path.dirname(path.resolve(process.argv[1])) : process.cwd();
322
- const defaultCmdsRoot = path.join(mainEntry, "src", "app");
323
- const exists = await fs.pathExists(defaultCmdsRoot);
324
- const finalCmdsRoot = exists ? defaultCmdsRoot : path.join(mainEntry, "app");
325
- parserOptions.fileBasedCmds = {
326
- enable: true,
327
- cmdsRootPath: finalCmdsRoot
328
- };
329
- }
330
- const rawArgv = process.argv.slice(2);
331
- const autoExit = parserOptions.autoExit !== false;
332
- if (!(parserOptions.fileBasedCmds?.enable || command.commands && Object.keys(command.commands).length > 0 || command.run)) {
382
+ return {
383
+ /**
384
+ * @deprecated Use createCli() directly instead. This method will be removed in a future version.
385
+ * @example
386
+ * // Instead of:
387
+ * createCli({...}).run()
388
+ * // Use:
389
+ * await createCli({...})
390
+ */
391
+ async run(_ctx) {
333
392
  relinka(
334
- "error",
335
- "Invalid CLI configuration: No file-based commands, subCommands, or run() handler are defined. This CLI will not do anything.\n\u2502 To fix: add file-based commands (./app), or provide at least one subCommand or a run() handler."
393
+ "warn",
394
+ "\u26A0\uFE0F Deprecated: .run() method is deprecated. Use createCli() directly instead."
336
395
  );
337
- process.exit(1);
338
- }
339
- if (parserOptions.fileBasedCmds?.enable && rawArgv.length > 0) {
340
- const commandsDir = path.resolve(
341
- parserOptions.fileBasedCmds.cmdsRootPath
342
- );
343
- const resolved = await resolveFileBasedCommandPath(commandsDir, rawArgv);
344
- if (resolved) {
345
- const { def: subCommand, leftoverArgv, path: pathSegments } = resolved;
346
- const helpIdx = leftoverArgv.findIndex(
347
- (arg) => arg === "help" || arg === "--help" || arg === "-h"
348
- );
349
- if (helpIdx !== -1) {
350
- await showUsage(subCommand, {
351
- ...parserOptions,
352
- _fileBasedCurrentDir: pathSegments.length ? path.join(commandsDir, ...pathSegments) : commandsDir,
353
- _fileBasedPathSegments: pathSegments
354
- });
355
- if (autoExit) process.exit(0);
356
- return;
396
+ relinka("warn", " Instead of: createCli({...}).run()");
397
+ relinka("warn", " Use: await createCli({...})");
398
+ if (typeof command.onLauncherInit === "function") {
399
+ try {
400
+ await command.onLauncherInit();
401
+ } catch (err) {
402
+ relinka("error", "Error in onLauncherInit:", err);
403
+ if (parserOptions.autoExit !== false) process.exit(1);
404
+ throw err;
357
405
  }
358
406
  }
359
- }
360
- const fileBasedEnabled = parserOptions.fileBasedCmds?.enable;
361
- if (fileBasedEnabled && rawArgv.length > 0 && !isFlag(rawArgv[0])) {
362
- const [subName, ...subCmdArgv] = rawArgv;
363
407
  try {
364
- const ctx = getParsedContext(command, rawArgv, parserOptions);
365
- if (typeof command.onCmdInit === "function")
366
- await command.onCmdInit(ctx);
367
- await runFileBasedSubCmd(
368
- subName,
369
- subCmdArgv,
370
- parserOptions.fileBasedCmds,
371
- parserOptions,
372
- command.onCmdExit ? async (_subCtx) => {
373
- await command.onCmdExit?.(ctx);
374
- } : void 0
375
- );
376
- if (autoExit) process.exit(0);
377
- return;
378
- } catch (err) {
379
- relinka("error", "Error loading file-based subcommand:", err.message);
380
- if (autoExit) process.exit(1);
381
- throw err;
382
- }
383
- }
384
- if (!fileBasedEnabled && command.commands && rawArgv.length > 0 && !isFlag(rawArgv[0])) {
385
- const [maybeSub, ...subCmdArgv] = rawArgv;
386
- let subSpec;
387
- for (const [key, spec] of Object.entries(command.commands)) {
388
- if (key === maybeSub) {
389
- subSpec = spec;
390
- break;
408
+ if (!parserOptions.fileBased && !command.commands) {
409
+ const mainEntry = process.argv[1] ? path.dirname(path.resolve(process.argv[1])) : process.cwd();
410
+ const defaultCmdsRoot = path.join(mainEntry, "src", "app");
411
+ const exists = await fs.pathExists(defaultCmdsRoot);
412
+ const finalCmdsRoot = exists ? defaultCmdsRoot : path.join(mainEntry, "app");
413
+ parserOptions.fileBased = {
414
+ enable: true,
415
+ cmdsRootPath: finalCmdsRoot
416
+ };
391
417
  }
392
- try {
393
- const cmd = await loadSubCommand(spec);
394
- if (cmd.meta.aliases?.includes(maybeSub)) {
395
- subSpec = spec;
396
- break;
418
+ const rawArgv = process.argv.slice(2);
419
+ const autoExit = parserOptions.autoExit !== false;
420
+ if (!(parserOptions.fileBased?.enable || command.commands && Object.keys(command.commands).length > 0 || command.run)) {
421
+ relinka(
422
+ "error",
423
+ "Invalid CLI configuration: No file-based commands, subCommands, or run() handler are defined. This CLI will not do anything.\n\u2502 To fix: add file-based commands (./app), or provide at least one subCommand or a run() handler."
424
+ );
425
+ process.exit(1);
426
+ }
427
+ if (parserOptions.fileBased?.enable && rawArgv.length > 0) {
428
+ const commandsDir = path.resolve(
429
+ parserOptions.fileBased.cmdsRootPath
430
+ );
431
+ const resolved = await resolveFileBasedCommandPath(
432
+ commandsDir,
433
+ rawArgv
434
+ );
435
+ if (resolved) {
436
+ const {
437
+ def: subCommand,
438
+ leftoverArgv,
439
+ path: pathSegments
440
+ } = resolved;
441
+ const helpIdx = leftoverArgv.findIndex(
442
+ (arg) => arg === "help" || arg === "--help" || arg === "-h"
443
+ );
444
+ if (helpIdx !== -1) {
445
+ await showUsage(
446
+ subCommand,
447
+ {
448
+ ...parserOptions,
449
+ _fileBasedCurrentDir: pathSegments.length ? path.join(commandsDir, ...pathSegments) : commandsDir,
450
+ _fileBasedPathSegments: pathSegments
451
+ },
452
+ globalCliMeta
453
+ );
454
+ if (autoExit) process.exit(0);
455
+ return;
456
+ }
397
457
  }
398
- } catch (err) {
399
- debugLog(`Error checking alias for command ${key}:`, err);
400
458
  }
401
- }
402
- if (subSpec) {
403
- const helpIdx = subCmdArgv.findIndex(
404
- (arg) => arg === "help" || arg === "--help" || arg === "-h"
405
- );
406
- if (helpIdx !== -1) {
407
- const subCommandDef = await loadSubCommand(subSpec);
408
- await showUsage(subCommandDef, {
409
- ...parserOptions,
410
- _isSubcommand: true
411
- });
459
+ const fileBasedEnabled = parserOptions.fileBased?.enable;
460
+ if (fileBasedEnabled && rawArgv.length > 0 && rawArgv[0] && !isFlag(rawArgv[0])) {
461
+ const [subName, ...subCmdArgv] = rawArgv;
462
+ try {
463
+ const ctx = getParsedContext(command, rawArgv, parserOptions);
464
+ if (typeof command.onCmdInit === "function")
465
+ await command.onCmdInit(ctx);
466
+ await runFileBasedSubCmd(
467
+ subName,
468
+ subCmdArgv,
469
+ parserOptions.fileBased,
470
+ parserOptions,
471
+ command.onCmdExit ? async (_subCtx) => {
472
+ await command.onCmdExit?.(ctx);
473
+ } : void 0,
474
+ globalCliMeta
475
+ );
476
+ if (autoExit) process.exit(0);
477
+ return;
478
+ } catch (err) {
479
+ relinka(
480
+ "error",
481
+ "Error loading file-based subcommand:",
482
+ err.message
483
+ );
484
+ if (autoExit) process.exit(1);
485
+ throw err;
486
+ }
487
+ }
488
+ if (!fileBasedEnabled && command.commands && rawArgv.length > 0 && rawArgv[0] && !isFlag(rawArgv[0])) {
489
+ const [maybeSub, ...subCmdArgv] = rawArgv;
490
+ let subSpec;
491
+ for (const [key, spec] of Object.entries(command.commands)) {
492
+ if (key === maybeSub) {
493
+ subSpec = spec;
494
+ break;
495
+ }
496
+ try {
497
+ const cmd = await loadSubCommand(spec);
498
+ if (cmd.meta?.aliases?.includes(maybeSub)) {
499
+ subSpec = spec;
500
+ break;
501
+ }
502
+ } catch (err) {
503
+ debugLog(`Error checking alias for command ${key}:`, err);
504
+ }
505
+ }
506
+ if (subSpec) {
507
+ const helpIdx = subCmdArgv.findIndex(
508
+ (arg) => arg === "help" || arg === "--help" || arg === "-h"
509
+ );
510
+ if (helpIdx !== -1) {
511
+ const subCommandDef = await loadSubCommand(subSpec);
512
+ await showUsage(
513
+ subCommandDef,
514
+ {
515
+ ...parserOptions,
516
+ _isSubcommand: true
517
+ },
518
+ globalCliMeta
519
+ );
520
+ if (autoExit) process.exit(0);
521
+ return;
522
+ }
523
+ try {
524
+ const ctx = getParsedContext(command, rawArgv, parserOptions);
525
+ if (typeof command.onCmdInit === "function")
526
+ await command.onCmdInit(ctx);
527
+ await runSubCommand(
528
+ subSpec,
529
+ subCmdArgv,
530
+ { ...parserOptions, _isSubcommand: true },
531
+ command.onCmdExit ? async (_subCtx) => {
532
+ await command.onCmdExit?.(ctx);
533
+ } : void 0,
534
+ globalCliMeta
535
+ );
536
+ if (autoExit) process.exit(0);
537
+ return;
538
+ } catch (err) {
539
+ relinka("error", "Error running subcommand:", err.message);
540
+ if (autoExit) process.exit(1);
541
+ throw err;
542
+ }
543
+ }
544
+ }
545
+ await relinkaConfig;
546
+ if (rawArgv[0] === "help" || checkHelp(rawArgv)) {
547
+ await showUsage(command, parserOptions, globalCliMeta);
412
548
  if (autoExit) process.exit(0);
413
549
  return;
414
550
  }
415
- try {
416
- const ctx = getParsedContext(command, rawArgv, parserOptions);
417
- if (typeof command.onCmdInit === "function")
418
- await command.onCmdInit(ctx);
419
- await runSubCommand(
420
- subSpec,
421
- subCmdArgv,
422
- { ...parserOptions, _isSubcommand: true },
423
- command.onCmdExit ? async (_subCtx) => {
424
- await command.onCmdExit?.(ctx);
425
- } : void 0
426
- );
551
+ if (checkVersion(rawArgv)) {
552
+ if (command.meta?.name) {
553
+ relinka(
554
+ "info",
555
+ `${command.meta?.name} ${command.meta?.version ? `v${command.meta?.version}` : ""}`
556
+ );
557
+ }
427
558
  if (autoExit) process.exit(0);
428
559
  return;
429
- } catch (err) {
430
- relinka("error", "Error running subcommand:", err.message);
431
- if (autoExit) process.exit(1);
432
- throw err;
433
560
  }
561
+ try {
562
+ await runCommandWithArgs(
563
+ command,
564
+ rawArgv,
565
+ parserOptions,
566
+ globalCliMeta
567
+ );
568
+ } finally {
569
+ }
570
+ await relinkaShutdown();
571
+ } finally {
572
+ if (typeof command.onLauncherExit === "function")
573
+ await command.onLauncherExit();
434
574
  }
575
+ throw new Error(
576
+ "\u26A0\uFE0F Deprecated: .run() method is deprecated. Use createCli() directly instead.\n Instead of: createCli({...}).run()\n Use: await createCli({...})"
577
+ );
435
578
  }
436
- await relinkaConfig;
437
- if (rawArgv[0] === "help" || checkHelp(rawArgv)) {
438
- await showUsage(command, parserOptions);
439
- if (autoExit) process.exit(0);
440
- return;
441
- }
442
- if (checkVersion(rawArgv)) {
443
- if (command.meta?.name) {
444
- relinka(
445
- "info",
446
- `${command.meta?.name} ${command.meta?.version ? `v${command.meta?.version}` : ""}`
447
- );
448
- }
449
- if (autoExit) process.exit(0);
450
- return;
451
- }
452
- try {
453
- await runCommandWithArgs(command, rawArgv, parserOptions);
454
- } finally {
455
- }
456
- await relinkaShutdown();
457
- } finally {
458
- if (typeof command.onLauncherExit === "function")
459
- await command.onLauncherExit();
460
- }
579
+ };
461
580
  }
462
581
  function checkHelp(argv) {
463
582
  return argv.includes("--help") || argv.includes("-h");
@@ -482,9 +601,9 @@ async function loadSubCommand(spec) {
482
601
  }
483
602
  throw new Error("Subcommand import did not return a valid command");
484
603
  }
485
- async function runFileBasedSubCmd(subName, argv, fileCmdOpts, parserOptions, parentFinish) {
604
+ async function runFileBasedSubCmd(subName, argv, fileCmdOpts, parserOptions, parentFinish, globalCliMeta) {
486
605
  async function resolveCmdPath(baseDir, args) {
487
- if (args.length === 0 || isFlag(args[0])) {
606
+ if (args.length === 0 || args[0] && isFlag(args[0])) {
488
607
  const possibleFiles2 = [
489
608
  path.join(baseDir, "cmd.js"),
490
609
  path.join(baseDir, "cmd.ts")
@@ -500,7 +619,7 @@ Unknown command or arguments: ${args.join(" ")}
500
619
  Info for this CLI's developer: No valid command file found in ${baseDir}`
501
620
  );
502
621
  }
503
- const nextDir = path.join(baseDir, args[0]);
622
+ const nextDir = path.join(baseDir, args[0] || "");
504
623
  if (await fs.pathExists(nextDir) && (await fs.stat(nextDir)).isDirectory()) {
505
624
  return resolveCmdPath(nextDir, args.slice(1));
506
625
  }
@@ -533,7 +652,7 @@ Info for this CLI's developer: No valid command file found in ${baseDir}`
533
652
  let closestMatch = "";
534
653
  let minDistance = Number.POSITIVE_INFINITY;
535
654
  for (const cmd of commandNames) {
536
- const distance = levenshteinDistance(subName, cmd.split(" ")[0]);
655
+ const distance = levenshteinDistance(subName, cmd.split(" ")[0] || "");
537
656
  if (distance < minDistance) {
538
657
  minDistance = distance;
539
658
  closestMatch = cmd;
@@ -559,21 +678,25 @@ Info for this CLI's developer: No valid command directory found, expected: ${exp
559
678
  subCommand,
560
679
  leftoverArgv,
561
680
  parserOptions,
562
- true
681
+ globalCliMeta
563
682
  );
564
683
  if (typeof parentFinish === "function" && subCtx)
565
684
  await parentFinish(subCtx);
566
685
  } finally {
567
686
  }
568
687
  }
569
- async function runSubCommand(spec, argv, parserOptions, parentFinish) {
688
+ async function runSubCommand(spec, argv, parserOptions, parentFinish, globalCliMeta) {
570
689
  const subCommand = await loadSubCommand(spec);
571
690
  try {
572
691
  const helpIdx = argv.findIndex(
573
692
  (arg) => arg === "help" || arg === "--help" || arg === "-h"
574
693
  );
575
694
  if (helpIdx !== -1) {
576
- await showUsage(subCommand, { ...parserOptions, _isSubcommand: true });
695
+ await showUsage(
696
+ subCommand,
697
+ { ...parserOptions, _isSubcommand: true },
698
+ globalCliMeta
699
+ );
577
700
  if (parserOptions.autoExit !== false) process.exit(0);
578
701
  return;
579
702
  }
@@ -581,6 +704,7 @@ async function runSubCommand(spec, argv, parserOptions, parentFinish) {
581
704
  subCommand,
582
705
  argv,
583
706
  parserOptions,
707
+ globalCliMeta,
584
708
  true
585
709
  );
586
710
  if (typeof parentFinish === "function" && subCtx)
@@ -588,10 +712,10 @@ async function runSubCommand(spec, argv, parserOptions, parentFinish) {
588
712
  } finally {
589
713
  }
590
714
  }
591
- async function runCommandWithArgs(command, argv, parserOptions, returnCtx) {
715
+ async function runCommandWithArgs(command, argv, parserOptions, globalCliMeta, returnCtx) {
592
716
  const autoExit = parserOptions.autoExit !== false;
593
717
  const booleanKeys = Object.keys(command.args || {}).filter(
594
- (k) => command.args[k].type === "boolean"
718
+ (k) => command.args?.[k]?.type === "boolean"
595
719
  );
596
720
  const defaultMap = {};
597
721
  for (const [argKey, def] of Object.entries(command.args || {})) {
@@ -610,26 +734,22 @@ async function runCommandWithArgs(command, argv, parserOptions, returnCtx) {
610
734
  debugLog("Parsed arguments:", parsed);
611
735
  const finalArgs = {};
612
736
  const positionalKeys = Object.keys(command.args || {}).filter(
613
- (k) => command.args[k].type === "positional"
737
+ (k) => command.args?.[k]?.type === "positional"
614
738
  );
615
739
  const leftoverPositionals = [...parsed._ || []];
616
740
  for (let i = 0; i < positionalKeys.length; i++) {
617
741
  const key = positionalKeys[i];
618
- const def = command.args?.[key];
742
+ if (!key || !command.args) continue;
743
+ const def = command.args[key];
619
744
  const val = leftoverPositionals[i];
620
- if (val == null && def.required) {
621
- await showUsage(command, parserOptions);
622
- relinka("error", `Missing required positional argument: <${key}>`);
623
- if (autoExit) process.exit(1);
624
- else throw new Error(`Missing required positional argument: <${key}>`);
625
- }
626
- finalArgs[key] = val != null ? castArgValue(def, val, key) : def.default;
745
+ finalArgs[key] = val != null && def ? castArgValue(def, val, key) : def?.default;
627
746
  }
628
747
  const otherKeys = Object.keys(command.args || {}).filter(
629
- (k) => command.args[k].type !== "positional"
748
+ (k) => command.args?.[k]?.type !== "positional"
630
749
  );
631
750
  for (const key of otherKeys) {
632
751
  const def = command.args?.[key];
752
+ if (!def) continue;
633
753
  let rawVal = parsed[key];
634
754
  if (def.type === "array" && rawVal !== void 0 && !Array.isArray(rawVal)) {
635
755
  rawVal = [rawVal];
@@ -637,7 +757,7 @@ async function runCommandWithArgs(command, argv, parserOptions, returnCtx) {
637
757
  const casted = rawVal !== void 0 ? castArgValue(def, rawVal, key) : def.default;
638
758
  const argUsed = rawVal !== void 0 && (def.type === "boolean" ? casted === true : true);
639
759
  if (casted == null && def.required) {
640
- await showUsage(command, parserOptions);
760
+ await showUsage(command, parserOptions, globalCliMeta);
641
761
  relinka("error", `Missing required argument: --${key}`);
642
762
  if (autoExit) process.exit(1);
643
763
  else throw new Error(`Missing required argument: --${key}`);
@@ -664,17 +784,17 @@ async function runCommandWithArgs(command, argv, parserOptions, returnCtx) {
664
784
  if (command.run) {
665
785
  await command.run(ctx);
666
786
  } else {
667
- const isDispatcher = parserOptions.fileBasedCmds?.enable || command.commands && Object.keys(command.commands).length > 0;
787
+ const isDispatcher = parserOptions.fileBased?.enable || command.commands && Object.keys(command.commands).length > 0;
668
788
  const noSubcommandArgInCurrentCall = !argv.some((arg) => !isFlag(arg));
669
789
  if (isDispatcher && noSubcommandArgInCurrentCall) {
670
790
  relinka("warn", "Please specify a command");
671
- await showUsage(command, parserOptions);
791
+ await showUsage(command, parserOptions, globalCliMeta);
672
792
  if (autoExit) process.exit(0);
673
793
  return;
674
794
  }
675
795
  const cmdName = command.meta?.name || "unknown";
676
796
  const attempted = argv.length > 0 ? argv.join(" ") : "(no arguments)";
677
- await showUsage(command, parserOptions);
797
+ await showUsage(command, parserOptions, globalCliMeta);
678
798
  relinka("error", `Unknown command or arguments: ${attempted}`);
679
799
  if (autoExit) {
680
800
  process.exit(1);
@@ -791,7 +911,7 @@ function castArgValue(def, rawVal, argName) {
791
911
  }
792
912
  function renderPositional(args) {
793
913
  const positionalKeys = Object.keys(args || {}).filter(
794
- (k) => args[k].type === "positional"
914
+ (k) => args?.[k]?.type === "positional"
795
915
  );
796
916
  return positionalKeys.map((k) => `<${k}>`).join(" ");
797
917
  }
@@ -800,7 +920,7 @@ export function defineArgs(args) {
800
920
  }
801
921
  export async function runCmd(command, argv = [], parserOptions = {}) {
802
922
  const booleanKeys = Object.keys(command.args || {}).filter(
803
- (k) => command.args[k].type === "boolean"
923
+ (k) => command.args?.[k]?.type === "boolean"
804
924
  );
805
925
  const defaultMap = {};
806
926
  for (const [argKey, def] of Object.entries(command.args || {})) {
@@ -819,23 +939,22 @@ export async function runCmd(command, argv = [], parserOptions = {}) {
819
939
  debugLog("Parsed arguments (runCmd):", parsed);
820
940
  const finalArgs = {};
821
941
  const positionalKeys = Object.keys(command.args || {}).filter(
822
- (k) => command.args[k].type === "positional"
942
+ (k) => command.args?.[k]?.type === "positional"
823
943
  );
824
944
  const leftoverPositionals = [...parsed._ || []];
825
945
  for (let i = 0; i < positionalKeys.length; i++) {
826
946
  const key = positionalKeys[i];
827
- const def = command.args?.[key];
947
+ if (!key || !command.args) continue;
948
+ const def = command.args[key];
828
949
  const val = leftoverPositionals[i];
829
- if (val == null && def.required) {
830
- throw new Error(`Missing required positional argument: <${key}>`);
831
- }
832
- finalArgs[key] = val != null ? castArgValue(def, val, key) : def.default;
950
+ finalArgs[key] = val != null && def ? castArgValue(def, val, key) : def?.default;
833
951
  }
834
952
  const otherKeys = Object.keys(command.args || {}).filter(
835
- (k) => command.args[k].type !== "positional"
953
+ (k) => command.args?.[k]?.type !== "positional"
836
954
  );
837
955
  for (const key of otherKeys) {
838
956
  const def = command.args?.[key];
957
+ if (!def) continue;
839
958
  let rawVal = parsed[key];
840
959
  if (def.type === "array" && rawVal !== void 0 && !Array.isArray(rawVal)) {
841
960
  rawVal = [rawVal];
@@ -871,7 +990,7 @@ export async function runCmd(command, argv = [], parserOptions = {}) {
871
990
  }
872
991
  function getParsedContext(command, argv, parserOptions) {
873
992
  const booleanKeys = Object.keys(command.args || {}).filter(
874
- (k) => command.args[k].type === "boolean"
993
+ (k) => command.args?.[k]?.type === "boolean"
875
994
  );
876
995
  const defaultMap = {};
877
996
  for (const [argKey, def] of Object.entries(command.args || {})) {
@@ -889,20 +1008,22 @@ function getParsedContext(command, argv, parserOptions) {
889
1008
  const parsed = reliArgParser(argv, mergedParserOptions);
890
1009
  const finalArgs = {};
891
1010
  const positionalKeys = Object.keys(command.args || {}).filter(
892
- (k) => command.args[k].type === "positional"
1011
+ (k) => command.args?.[k]?.type === "positional"
893
1012
  );
894
1013
  const leftoverPositionals = [...parsed._ || []];
895
1014
  for (let i = 0; i < positionalKeys.length; i++) {
896
1015
  const key = positionalKeys[i];
897
- const def = command.args?.[key];
1016
+ if (!key || !command.args) continue;
1017
+ const def = command.args[key];
898
1018
  const val = leftoverPositionals[i];
899
- finalArgs[key] = val != null ? castArgValue(def, val, key) : def.default;
1019
+ finalArgs[key] = val != null && def ? castArgValue(def, val, key) : def?.default;
900
1020
  }
901
1021
  const otherKeys = Object.keys(command.args || {}).filter(
902
- (k) => command.args[k].type !== "positional"
1022
+ (k) => command.args?.[k]?.type !== "positional"
903
1023
  );
904
1024
  for (const key of otherKeys) {
905
1025
  const def = command.args?.[key];
1026
+ if (!def) continue;
906
1027
  let rawVal = parsed[key];
907
1028
  if (def.type === "array" && rawVal !== void 0 && !Array.isArray(rawVal)) {
908
1029
  rawVal = [rawVal];
@@ -919,7 +1040,7 @@ async function resolveFileBasedCommandPath(cmdsRoot, argv) {
919
1040
  let currentDir = cmdsRoot;
920
1041
  const pathSegments = [];
921
1042
  let leftover = [...argv];
922
- while (leftover.length > 0 && !isFlag(leftover[0])) {
1043
+ while (leftover.length > 0 && leftover[0] && !isFlag(leftover[0])) {
923
1044
  const nextDir = path.join(currentDir, leftover[0]);
924
1045
  if (await fs.pathExists(nextDir) && (await fs.stat(nextDir)).isDirectory()) {
925
1046
  currentDir = nextDir;