@reliverse/rempts 1.7.29 → 1.7.31

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 (129) hide show
  1. package/README.md +141 -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/libs/launcher/launcher-mod.d.ts +114 -0
  19. package/bin/{components → libs}/launcher/launcher-mod.js +355 -191
  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 +17 -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/launcher/launcher-mod.d.ts +0 -52
  78. /package/bin/{components/animate/animate.d.ts → libs/animate/animate-mod.d.ts} +0 -0
  79. /package/bin/{components → libs}/anykey/anykey-mod.d.ts +0 -0
  80. /package/bin/{components → libs}/cancel/cancel.d.ts +0 -0
  81. /package/bin/{components → libs}/cancel/cancel.js +0 -0
  82. /package/bin/{components/confirm/confirm-prompt.d.ts → libs/confirm/confirm-mod.d.ts} +0 -0
  83. /package/bin/{components → libs}/date/date.d.ts +0 -0
  84. /package/bin/{components → libs}/date/date.js +0 -0
  85. /package/bin/{components → libs}/editor/editor-mod.d.ts +0 -0
  86. /package/bin/{components/input/input-prompt.d.ts → libs/input/input-mod.d.ts} +0 -0
  87. /package/bin/{components/intro/intro-start.d.ts → libs/intro/intro-mod.d.ts} +0 -0
  88. /package/bin/{components → libs}/launcher/launcher-types.js +0 -0
  89. /package/bin/{components → libs}/launcher/run-command.d.ts +0 -0
  90. /package/bin/{components → libs}/launcher/run-command.js +0 -0
  91. /package/bin/{components/log/log.d.ts → libs/log/log-alias.d.ts} +0 -0
  92. /package/bin/{components/log/log.js → libs/log/log-alias.js} +0 -0
  93. /package/bin/{components → libs}/msg-fmt/colors.d.ts +0 -0
  94. /package/bin/{components → libs}/msg-fmt/colors.js +0 -0
  95. /package/bin/{components → libs}/msg-fmt/logger.d.ts +0 -0
  96. /package/bin/{components → libs}/msg-fmt/mapping.d.ts +0 -0
  97. /package/bin/{components → libs}/msg-fmt/mapping.js +0 -0
  98. /package/bin/{components → libs}/msg-fmt/messages.d.ts +0 -0
  99. /package/bin/{components → libs}/msg-fmt/messages.js +0 -0
  100. /package/bin/{components → libs}/msg-fmt/terminal.d.ts +0 -0
  101. /package/bin/{components → libs}/msg-fmt/terminal.js +0 -0
  102. /package/bin/{components → libs}/msg-fmt/variants.d.ts +0 -0
  103. /package/bin/{components → libs}/msg-fmt/variants.js +0 -0
  104. /package/bin/{components/select → libs/multiselect}/multiselect-prompt.d.ts +0 -0
  105. /package/bin/{components → libs}/next-steps/next-steps.d.ts +0 -0
  106. /package/bin/{components → libs}/next-steps/next-steps.js +0 -0
  107. /package/bin/{components → libs}/number/number-mod.d.ts +0 -0
  108. /package/bin/{components/outro/outro-end.d.ts → libs/outro/outro-mod.d.ts} +0 -0
  109. /package/bin/{components → libs}/results/results.d.ts +0 -0
  110. /package/bin/{components → libs}/results/results.js +0 -0
  111. /package/bin/{components → libs}/select/nummultiselect-prompt.d.ts +0 -0
  112. /package/bin/{components → libs}/select/nummultiselect-prompt.js +0 -0
  113. /package/bin/{components → libs}/select/numselect-prompt.d.ts +0 -0
  114. /package/bin/{components → libs}/select/numselect-prompt.js +0 -0
  115. /package/bin/{components → libs}/select/select-prompt.d.ts +0 -0
  116. /package/bin/{components → libs}/select/toggle-prompt.d.ts +0 -0
  117. /package/bin/{components → libs}/spinner/spinner-mod.d.ts +0 -0
  118. /package/bin/{components → libs}/task/progress.d.ts +0 -0
  119. /package/bin/{components → libs}/task/progress.js +0 -0
  120. /package/bin/{components → libs}/task/task-spin.d.ts +0 -0
  121. /package/bin/{utils → libs/utils}/colorize.js +0 -0
  122. /package/bin/{utils → libs/utils}/errors.d.ts +0 -0
  123. /package/bin/{utils → libs/utils}/errors.js +0 -0
  124. /package/bin/{utils → libs/utils}/system.d.ts +0 -0
  125. /package/bin/{utils → libs/utils}/system.js +0 -0
  126. /package/bin/{utils → libs/utils}/validate.d.ts +0 -0
  127. /package/bin/{utils → libs/utils}/validate.js +0 -0
  128. /package/bin/{components/ascii-art/ascii-art.d.ts → libs/visual/visual-mod.d.ts} +0 -0
  129. /package/bin/{components/ascii-art/ascii-art.js → libs/visual/visual-mod.js} +0 -0
@@ -5,23 +5,24 @@ import fs from "@reliverse/relifso";
5
5
  import { relinka, relinkaConfig, relinkaShutdown } from "@reliverse/relinka";
6
6
  import process from "node:process";
7
7
  import { readPackageJSON } from "pkg-types";
8
+ import { createRpcCli } from "./trpc-orpc-support/index.js";
8
9
  function buildExampleArgs(args) {
9
10
  const parts = [];
10
- const positionalKeys = Object.keys(args).filter(
11
- (k) => args[k].type === "positional"
11
+ const positionalKeys = Object.keys(args || {}).filter(
12
+ (k) => args?.[k]?.type === "positional"
12
13
  );
13
14
  positionalKeys.forEach((key) => {
14
- const def = args[key];
15
- if (def.required || Math.random() > 0.5) {
15
+ const def = args?.[key];
16
+ if (def && (def.required || Math.random() > 0.5)) {
16
17
  parts.push(String(def.default ?? `<${key}>`));
17
18
  }
18
19
  });
19
- const otherKeys = Object.keys(args).filter(
20
- (k) => args[k].type !== "positional"
20
+ const otherKeys = Object.keys(args || {}).filter(
21
+ (k) => args?.[k]?.type !== "positional"
21
22
  );
22
23
  for (const key of otherKeys) {
23
- const def = args[key];
24
- if (def.required || Math.random() > 0.7) {
24
+ const def = args?.[key];
25
+ if (def && (def.required || Math.random() > 0.7)) {
25
26
  switch (def.type) {
26
27
  case "boolean":
27
28
  if (def.default === true) {
@@ -145,13 +146,13 @@ function formatTableRow(text, desc, padding) {
145
146
  const spaces = " ".repeat(Math.max(0, padding - text.length));
146
147
  return `${text}${spaces}| ${desc || ""}`;
147
148
  }
148
- export async function showUsage(command, parserOptions = {}) {
149
+ export async function showUsage(command, parserOptions = {}, globalCliMeta) {
149
150
  const { name: fallbackName, version: fallbackVersion } = await getDefaultCliNameAndVersion();
150
- const cliName = command.meta?.name || fallbackName;
151
- const cliVersion = command.meta?.version || fallbackVersion;
151
+ const cliName = globalCliMeta?.name || command.meta?.name || fallbackName;
152
+ const cliVersion = globalCliMeta?.version || command.meta?.version || fallbackVersion;
152
153
  relinka("info", `${cliName}${cliVersion ? ` v${cliVersion}` : ""}`);
153
154
  if (parserOptions.metaSettings?.showDescriptionOnMain) {
154
- let description = command.meta?.description;
155
+ let description = globalCliMeta?.description || command.meta?.description;
155
156
  if (!description) {
156
157
  try {
157
158
  const pkg = await readPackageJSON();
@@ -164,7 +165,7 @@ export async function showUsage(command, parserOptions = {}) {
164
165
  }
165
166
  }
166
167
  const { name: pkgName } = await getDefaultCliNameAndVersion();
167
- const fileCmds = parserOptions.fileBasedCmds;
168
+ const fileCmds = parserOptions.fileBased;
168
169
  if (fileCmds?.enable) {
169
170
  const commandsDir = path.resolve(fileCmds.cmdsRootPath);
170
171
  const pathSegments = parserOptions._fileBasedPathSegments || [];
@@ -184,16 +185,19 @@ export async function showUsage(command, parserOptions = {}) {
184
185
  if (pos) usageLine += ` ${pos}`;
185
186
  }
186
187
  relinka("log", re.cyan(`Usage: ${usageLine}`));
187
- if (directCommands.length > 0) {
188
+ if (directCommands.length > 0 && allCommands.length > 0) {
188
189
  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
- );
190
+ const exampleCmd = allCommands[randomIdx];
191
+ if (exampleCmd) {
192
+ const { path: path2, def: exampleDef } = exampleCmd;
193
+ const exampleArgs = buildExampleArgs(exampleDef.args || {});
194
+ relinka(
195
+ "log",
196
+ re.cyan(
197
+ `Example: ${pkgName} ${path2.join(" ")}${exampleArgs ? ` ${exampleArgs}` : ""}`
198
+ )
199
+ );
200
+ }
197
201
  }
198
202
  if (allCommands.length > 0) {
199
203
  relinka("info", "Available commands (run with `help` to see more):");
@@ -203,7 +207,10 @@ export async function showUsage(command, parserOptions = {}) {
203
207
  if (!commandsByPath.has(parentPath)) {
204
208
  commandsByPath.set(parentPath, []);
205
209
  }
206
- commandsByPath.get(parentPath).push(cmd);
210
+ const group = commandsByPath.get(parentPath);
211
+ if (group) {
212
+ group.push(cmd);
213
+ }
207
214
  }
208
215
  const groupPaddings = /* @__PURE__ */ new Map();
209
216
  for (const [parentPath, cmds] of commandsByPath) {
@@ -217,7 +224,7 @@ export async function showUsage(command, parserOptions = {}) {
217
224
  if (parentPath !== "/") {
218
225
  relinka("log", re.cyanPastel(`Sub-commands in ${parentPath}:`));
219
226
  }
220
- const padding = groupPaddings.get(parentPath);
227
+ const padding = groupPaddings.get(parentPath) || 0;
221
228
  for (const { def, path: path2 } of cmds) {
222
229
  const desc = def?.meta?.description ?? "";
223
230
  const indent = parentPath === "/" ? "" : " ";
@@ -235,7 +242,7 @@ export async function showUsage(command, parserOptions = {}) {
235
242
  try {
236
243
  const cmd = await loadSubCommand(spec);
237
244
  if (!cmd?.meta?.hidden) {
238
- const aliasDisplay = cmd.meta.aliases ? ` (aliases: ${cmd.meta.aliases.join(", ")})` : "";
245
+ const aliasDisplay = cmd.meta?.aliases ? ` (aliases: ${cmd.meta.aliases.join(", ")})` : "";
239
246
  subCommandNames.push(`${name}${aliasDisplay}`);
240
247
  subCommandDefs.push({ name, def: cmd });
241
248
  }
@@ -256,14 +263,17 @@ export async function showUsage(command, parserOptions = {}) {
256
263
  relinka("log", re.cyan(`Usage: ${usageLine}`));
257
264
  if (subCommandDefs.length > 0) {
258
265
  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
- );
266
+ const exampleCmd = subCommandDefs[randomIdx];
267
+ if (exampleCmd) {
268
+ const { name: exampleCmdName, def: exampleDef } = exampleCmd;
269
+ const exampleArgs = buildExampleArgs(exampleDef.args || {});
270
+ relinka(
271
+ "log",
272
+ re.cyan(
273
+ `Example: ${pkgName}${parserOptions._isSubcommand ? ` ${cliName}` : ""} ${exampleCmdName}${exampleArgs ? ` ${exampleArgs}` : ""}`
274
+ )
275
+ );
276
+ }
267
277
  }
268
278
  if (subCommandNames.length > 0) {
269
279
  relinka("info", "Available commands (run with `help` to see more):");
@@ -306,158 +316,310 @@ export async function showUsage(command, parserOptions = {}) {
306
316
  relinka("log", formatTableRow(text, desc, optionsPadding));
307
317
  }
308
318
  }
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;
317
- }
319
+ export function createCli(options, legacyParserOptions) {
320
+ let command;
321
+ let parserOptions;
322
+ let globalCliMeta = {};
323
+ if (typeof options === "object" && !("run" in options) && !("meta" in options) && !("args" in options) && !("commands" in options)) {
324
+ command = options;
325
+ parserOptions = legacyParserOptions || {};
326
+ } else if ("mainCommand" in options) {
327
+ command = options.mainCommand;
328
+ parserOptions = {
329
+ fileBased: options.fileBased,
330
+ autoExit: options.autoExit,
331
+ metaSettings: options.metaSettings
332
+ };
333
+ globalCliMeta = {
334
+ name: options.name,
335
+ version: options.version,
336
+ description: options.description
337
+ };
338
+ } else {
339
+ const inlineOptions = options;
340
+ const {
341
+ name,
342
+ version,
343
+ description,
344
+ fileBased,
345
+ autoExit,
346
+ metaSettings,
347
+ mainCommand,
348
+ ...commandOptions
349
+ } = inlineOptions;
350
+ command = {
351
+ meta: commandOptions.meta,
352
+ args: commandOptions.args,
353
+ run: commandOptions.run,
354
+ commands: commandOptions.commands,
355
+ onCmdInit: commandOptions.onCmdInit,
356
+ onCmdExit: commandOptions.onCmdExit,
357
+ onLauncherInit: commandOptions.onLauncherInit,
358
+ onLauncherExit: commandOptions.onLauncherExit
359
+ };
360
+ parserOptions = {
361
+ fileBased,
362
+ autoExit,
363
+ metaSettings
364
+ };
365
+ globalCliMeta = { name, version, description };
318
366
  }
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
- };
367
+ if (command.run && (globalCliMeta.name || globalCliMeta.version || globalCliMeta.description)) {
368
+ const mergedMeta = { ...command.meta };
369
+ if (globalCliMeta.name && !command.meta?.name) {
370
+ mergedMeta.name = globalCliMeta.name;
329
371
  }
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)) {
333
- 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."
336
- );
337
- process.exit(1);
372
+ if (globalCliMeta.version && !command.meta?.version) {
373
+ mergedMeta.version = globalCliMeta.version;
338
374
  }
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;
357
- }
375
+ if (globalCliMeta.description && !command.meta?.description) {
376
+ mergedMeta.description = globalCliMeta.description;
377
+ }
378
+ command = {
379
+ ...command,
380
+ meta: mergedMeta
381
+ };
382
+ }
383
+ const execute = async (_ctx) => {
384
+ if (options && typeof options === "object" && "rpc" in options && options.rpc) {
385
+ const rpcOptions = options.rpc;
386
+ const rpcRunParams = options.rpcRunParams || {};
387
+ debugLog("RPC integration detected, creating RPC CLI...");
388
+ try {
389
+ require("tsx/cjs");
390
+ await import("tsx/esm");
391
+ debugLog("tsx loaded successfully for TypeScript support");
392
+ } catch {
393
+ debugLog("tsx not available, continuing without TypeScript support");
358
394
  }
395
+ const getRouterMeta = (router) => {
396
+ if ("_def" in router && router._def && "meta" in router._def) {
397
+ return router._def.meta;
398
+ }
399
+ return void 0;
400
+ };
401
+ const routerMeta = getRouterMeta(rpcOptions.router);
402
+ const rpcCli = createRpcCli({
403
+ router: rpcOptions.router,
404
+ name: globalCliMeta.name || routerMeta?.name,
405
+ version: globalCliMeta.version || routerMeta?.version,
406
+ description: globalCliMeta.description || routerMeta?.description,
407
+ usage: rpcOptions.usage,
408
+ context: rpcOptions.context,
409
+ trpcServer: rpcOptions.trpcServer,
410
+ "@valibot/to-json-schema": rpcOptions["@valibot/to-json-schema"],
411
+ effect: rpcOptions.effect
412
+ });
413
+ debugLog(
414
+ "RPC CLI created, running with argv:",
415
+ rpcRunParams.argv || process.argv.slice(2)
416
+ );
417
+ await rpcCli.run({
418
+ argv: rpcRunParams.argv || process.argv.slice(2),
419
+ logger: rpcRunParams.logger || {
420
+ info: console.log,
421
+ error: console.error
422
+ },
423
+ completion: rpcRunParams.completion,
424
+ prompts: rpcRunParams.prompts,
425
+ formatError: rpcRunParams.formatError,
426
+ process: rpcRunParams.process
427
+ });
428
+ return;
359
429
  }
360
- const fileBasedEnabled = parserOptions.fileBasedCmds?.enable;
361
- if (fileBasedEnabled && rawArgv.length > 0 && !isFlag(rawArgv[0])) {
362
- const [subName, ...subCmdArgv] = rawArgv;
430
+ if (typeof command.onLauncherInit === "function") {
363
431
  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;
432
+ await command.onLauncherInit();
378
433
  } catch (err) {
379
- relinka("error", "Error loading file-based subcommand:", err.message);
380
- if (autoExit) process.exit(1);
434
+ relinka("error", "Error in onLauncherInit:", err);
435
+ if (parserOptions.autoExit !== false) process.exit(1);
381
436
  throw err;
382
437
  }
383
438
  }
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;
391
- }
392
- try {
393
- const cmd = await loadSubCommand(spec);
394
- if (cmd.meta.aliases?.includes(maybeSub)) {
395
- subSpec = spec;
396
- break;
397
- }
398
- } catch (err) {
399
- debugLog(`Error checking alias for command ${key}:`, err);
400
- }
439
+ try {
440
+ if (!parserOptions.fileBased && !command.commands) {
441
+ const mainEntry = process.argv[1] ? path.dirname(path.resolve(process.argv[1])) : process.cwd();
442
+ const defaultCmdsRoot = path.join(mainEntry, "src", "app");
443
+ const exists = await fs.pathExists(defaultCmdsRoot);
444
+ const finalCmdsRoot = exists ? defaultCmdsRoot : path.join(mainEntry, "app");
445
+ parserOptions.fileBased = {
446
+ enable: true,
447
+ cmdsRootPath: finalCmdsRoot
448
+ };
401
449
  }
402
- if (subSpec) {
403
- const helpIdx = subCmdArgv.findIndex(
404
- (arg) => arg === "help" || arg === "--help" || arg === "-h"
450
+ const rawArgv = process.argv.slice(2);
451
+ const autoExit = parserOptions.autoExit !== false;
452
+ if (!(parserOptions.fileBased?.enable || command.commands && Object.keys(command.commands).length > 0 || command.run)) {
453
+ relinka(
454
+ "error",
455
+ "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."
405
456
  );
406
- if (helpIdx !== -1) {
407
- const subCommandDef = await loadSubCommand(subSpec);
408
- await showUsage(subCommandDef, {
409
- ...parserOptions,
410
- _isSubcommand: true
411
- });
412
- if (autoExit) process.exit(0);
413
- return;
457
+ process.exit(1);
458
+ }
459
+ if (parserOptions.fileBased?.enable && rawArgv.length > 0) {
460
+ const commandsDir = path.resolve(parserOptions.fileBased.cmdsRootPath);
461
+ const resolved = await resolveFileBasedCommandPath(
462
+ commandsDir,
463
+ rawArgv
464
+ );
465
+ if (resolved) {
466
+ const {
467
+ def: subCommand,
468
+ leftoverArgv,
469
+ path: pathSegments
470
+ } = resolved;
471
+ const helpIdx = leftoverArgv.findIndex(
472
+ (arg) => arg === "help" || arg === "--help" || arg === "-h"
473
+ );
474
+ if (helpIdx !== -1) {
475
+ await showUsage(
476
+ subCommand,
477
+ {
478
+ ...parserOptions,
479
+ _fileBasedCurrentDir: pathSegments.length ? path.join(commandsDir, ...pathSegments) : commandsDir,
480
+ _fileBasedPathSegments: pathSegments
481
+ },
482
+ globalCliMeta
483
+ );
484
+ if (autoExit) process.exit(0);
485
+ return;
486
+ }
414
487
  }
488
+ }
489
+ const fileBasedEnabled = parserOptions.fileBased?.enable;
490
+ if (fileBasedEnabled && rawArgv.length > 0 && rawArgv[0] && !isFlag(rawArgv[0])) {
491
+ const [subName, ...subCmdArgv] = rawArgv;
415
492
  try {
416
493
  const ctx = getParsedContext(command, rawArgv, parserOptions);
417
494
  if (typeof command.onCmdInit === "function")
418
495
  await command.onCmdInit(ctx);
419
- await runSubCommand(
420
- subSpec,
496
+ await runFileBasedSubCmd(
497
+ subName,
421
498
  subCmdArgv,
422
- { ...parserOptions, _isSubcommand: true },
499
+ parserOptions.fileBased,
500
+ parserOptions,
423
501
  command.onCmdExit ? async (_subCtx) => {
424
502
  await command.onCmdExit?.(ctx);
425
- } : void 0
503
+ } : void 0,
504
+ globalCliMeta
426
505
  );
427
506
  if (autoExit) process.exit(0);
428
507
  return;
429
508
  } catch (err) {
430
- relinka("error", "Error running subcommand:", err.message);
509
+ relinka("error", "Error loading file-based subcommand:", err.message);
431
510
  if (autoExit) process.exit(1);
432
511
  throw err;
433
512
  }
434
513
  }
435
- }
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}` : ""}`
514
+ if (!fileBasedEnabled && command.commands && rawArgv.length > 0 && rawArgv[0] && !isFlag(rawArgv[0])) {
515
+ const [maybeSub, ...subCmdArgv] = rawArgv;
516
+ let subSpec;
517
+ for (const [key, spec] of Object.entries(command.commands)) {
518
+ if (key === maybeSub) {
519
+ subSpec = spec;
520
+ break;
521
+ }
522
+ try {
523
+ const cmd = await loadSubCommand(spec);
524
+ if (cmd.meta?.aliases?.includes(maybeSub)) {
525
+ subSpec = spec;
526
+ break;
527
+ }
528
+ } catch (err) {
529
+ debugLog(`Error checking alias for command ${key}:`, err);
530
+ }
531
+ }
532
+ if (subSpec) {
533
+ const helpIdx = subCmdArgv.findIndex(
534
+ (arg) => arg === "help" || arg === "--help" || arg === "-h"
535
+ );
536
+ if (helpIdx !== -1) {
537
+ const subCommandDef = await loadSubCommand(subSpec);
538
+ await showUsage(
539
+ subCommandDef,
540
+ {
541
+ ...parserOptions,
542
+ _isSubcommand: true
543
+ },
544
+ globalCliMeta
545
+ );
546
+ if (autoExit) process.exit(0);
547
+ return;
548
+ }
549
+ try {
550
+ const ctx = getParsedContext(command, rawArgv, parserOptions);
551
+ if (typeof command.onCmdInit === "function")
552
+ await command.onCmdInit(ctx);
553
+ await runSubCommand(
554
+ subSpec,
555
+ subCmdArgv,
556
+ { ...parserOptions, _isSubcommand: true },
557
+ command.onCmdExit ? async (_subCtx) => {
558
+ await command.onCmdExit?.(ctx);
559
+ } : void 0,
560
+ globalCliMeta
561
+ );
562
+ if (autoExit) process.exit(0);
563
+ return;
564
+ } catch (err) {
565
+ relinka("error", "Error running subcommand:", err.message);
566
+ if (autoExit) process.exit(1);
567
+ throw err;
568
+ }
569
+ }
570
+ }
571
+ await relinkaConfig;
572
+ if (rawArgv[0] === "help" || checkHelp(rawArgv)) {
573
+ await showUsage(command, parserOptions, globalCliMeta);
574
+ if (autoExit) process.exit(0);
575
+ return;
576
+ }
577
+ if (checkVersion(rawArgv)) {
578
+ if (command.meta?.name) {
579
+ relinka(
580
+ "info",
581
+ `${command.meta?.name} ${command.meta?.version ? `v${command.meta?.version}` : ""}`
582
+ );
583
+ }
584
+ if (autoExit) process.exit(0);
585
+ return;
586
+ }
587
+ try {
588
+ await runCommandWithArgs(
589
+ command,
590
+ rawArgv,
591
+ parserOptions,
592
+ globalCliMeta
447
593
  );
594
+ } finally {
448
595
  }
449
- if (autoExit) process.exit(0);
450
- return;
451
- }
452
- try {
453
- await runCommandWithArgs(command, rawArgv, parserOptions);
596
+ await relinkaShutdown();
454
597
  } finally {
598
+ if (typeof command.onLauncherExit === "function")
599
+ await command.onLauncherExit();
455
600
  }
456
- await relinkaShutdown();
457
- } finally {
458
- if (typeof command.onLauncherExit === "function")
459
- await command.onLauncherExit();
460
- }
601
+ };
602
+ const promise = execute();
603
+ const cli = Object.assign(promise, {
604
+ /**
605
+ * @deprecated Use createCli() directly instead. This method will be removed in a future version.
606
+ * @example
607
+ * // Instead of:
608
+ * createCli({...}).run()
609
+ * // Use:
610
+ * await createCli({...})
611
+ */
612
+ async run(_ctx) {
613
+ relinka(
614
+ "warn",
615
+ "\u26A0\uFE0F Deprecated: .run() method is deprecated. Use createCli() directly instead."
616
+ );
617
+ relinka("warn", " Instead of: createCli({...}).run()");
618
+ relinka("warn", " Use: await createCli({...})");
619
+ return execute(_ctx);
620
+ }
621
+ });
622
+ return cli;
461
623
  }
462
624
  function checkHelp(argv) {
463
625
  return argv.includes("--help") || argv.includes("-h");
@@ -482,9 +644,9 @@ async function loadSubCommand(spec) {
482
644
  }
483
645
  throw new Error("Subcommand import did not return a valid command");
484
646
  }
485
- async function runFileBasedSubCmd(subName, argv, fileCmdOpts, parserOptions, parentFinish) {
647
+ async function runFileBasedSubCmd(subName, argv, fileCmdOpts, parserOptions, parentFinish, globalCliMeta) {
486
648
  async function resolveCmdPath(baseDir, args) {
487
- if (args.length === 0 || isFlag(args[0])) {
649
+ if (args.length === 0 || args[0] && isFlag(args[0])) {
488
650
  const possibleFiles2 = [
489
651
  path.join(baseDir, "cmd.js"),
490
652
  path.join(baseDir, "cmd.ts")
@@ -500,7 +662,7 @@ Unknown command or arguments: ${args.join(" ")}
500
662
  Info for this CLI's developer: No valid command file found in ${baseDir}`
501
663
  );
502
664
  }
503
- const nextDir = path.join(baseDir, args[0]);
665
+ const nextDir = path.join(baseDir, args[0] || "");
504
666
  if (await fs.pathExists(nextDir) && (await fs.stat(nextDir)).isDirectory()) {
505
667
  return resolveCmdPath(nextDir, args.slice(1));
506
668
  }
@@ -533,7 +695,7 @@ Info for this CLI's developer: No valid command file found in ${baseDir}`
533
695
  let closestMatch = "";
534
696
  let minDistance = Number.POSITIVE_INFINITY;
535
697
  for (const cmd of commandNames) {
536
- const distance = levenshteinDistance(subName, cmd.split(" ")[0]);
698
+ const distance = levenshteinDistance(subName, cmd.split(" ")[0] || "");
537
699
  if (distance < minDistance) {
538
700
  minDistance = distance;
539
701
  closestMatch = cmd;
@@ -559,21 +721,25 @@ Info for this CLI's developer: No valid command directory found, expected: ${exp
559
721
  subCommand,
560
722
  leftoverArgv,
561
723
  parserOptions,
562
- true
724
+ globalCliMeta
563
725
  );
564
726
  if (typeof parentFinish === "function" && subCtx)
565
727
  await parentFinish(subCtx);
566
728
  } finally {
567
729
  }
568
730
  }
569
- async function runSubCommand(spec, argv, parserOptions, parentFinish) {
731
+ async function runSubCommand(spec, argv, parserOptions, parentFinish, globalCliMeta) {
570
732
  const subCommand = await loadSubCommand(spec);
571
733
  try {
572
734
  const helpIdx = argv.findIndex(
573
735
  (arg) => arg === "help" || arg === "--help" || arg === "-h"
574
736
  );
575
737
  if (helpIdx !== -1) {
576
- await showUsage(subCommand, { ...parserOptions, _isSubcommand: true });
738
+ await showUsage(
739
+ subCommand,
740
+ { ...parserOptions, _isSubcommand: true },
741
+ globalCliMeta
742
+ );
577
743
  if (parserOptions.autoExit !== false) process.exit(0);
578
744
  return;
579
745
  }
@@ -581,6 +747,7 @@ async function runSubCommand(spec, argv, parserOptions, parentFinish) {
581
747
  subCommand,
582
748
  argv,
583
749
  parserOptions,
750
+ globalCliMeta,
584
751
  true
585
752
  );
586
753
  if (typeof parentFinish === "function" && subCtx)
@@ -588,10 +755,10 @@ async function runSubCommand(spec, argv, parserOptions, parentFinish) {
588
755
  } finally {
589
756
  }
590
757
  }
591
- async function runCommandWithArgs(command, argv, parserOptions, returnCtx) {
758
+ async function runCommandWithArgs(command, argv, parserOptions, globalCliMeta, returnCtx) {
592
759
  const autoExit = parserOptions.autoExit !== false;
593
760
  const booleanKeys = Object.keys(command.args || {}).filter(
594
- (k) => command.args[k].type === "boolean"
761
+ (k) => command.args?.[k]?.type === "boolean"
595
762
  );
596
763
  const defaultMap = {};
597
764
  for (const [argKey, def] of Object.entries(command.args || {})) {
@@ -610,26 +777,22 @@ async function runCommandWithArgs(command, argv, parserOptions, returnCtx) {
610
777
  debugLog("Parsed arguments:", parsed);
611
778
  const finalArgs = {};
612
779
  const positionalKeys = Object.keys(command.args || {}).filter(
613
- (k) => command.args[k].type === "positional"
780
+ (k) => command.args?.[k]?.type === "positional"
614
781
  );
615
782
  const leftoverPositionals = [...parsed._ || []];
616
783
  for (let i = 0; i < positionalKeys.length; i++) {
617
784
  const key = positionalKeys[i];
618
- const def = command.args?.[key];
785
+ if (!key || !command.args) continue;
786
+ const def = command.args[key];
619
787
  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;
788
+ finalArgs[key] = val != null && def ? castArgValue(def, val, key) : def?.default;
627
789
  }
628
790
  const otherKeys = Object.keys(command.args || {}).filter(
629
- (k) => command.args[k].type !== "positional"
791
+ (k) => command.args?.[k]?.type !== "positional"
630
792
  );
631
793
  for (const key of otherKeys) {
632
794
  const def = command.args?.[key];
795
+ if (!def) continue;
633
796
  let rawVal = parsed[key];
634
797
  if (def.type === "array" && rawVal !== void 0 && !Array.isArray(rawVal)) {
635
798
  rawVal = [rawVal];
@@ -637,7 +800,7 @@ async function runCommandWithArgs(command, argv, parserOptions, returnCtx) {
637
800
  const casted = rawVal !== void 0 ? castArgValue(def, rawVal, key) : def.default;
638
801
  const argUsed = rawVal !== void 0 && (def.type === "boolean" ? casted === true : true);
639
802
  if (casted == null && def.required) {
640
- await showUsage(command, parserOptions);
803
+ await showUsage(command, parserOptions, globalCliMeta);
641
804
  relinka("error", `Missing required argument: --${key}`);
642
805
  if (autoExit) process.exit(1);
643
806
  else throw new Error(`Missing required argument: --${key}`);
@@ -664,17 +827,17 @@ async function runCommandWithArgs(command, argv, parserOptions, returnCtx) {
664
827
  if (command.run) {
665
828
  await command.run(ctx);
666
829
  } else {
667
- const isDispatcher = parserOptions.fileBasedCmds?.enable || command.commands && Object.keys(command.commands).length > 0;
830
+ const isDispatcher = parserOptions.fileBased?.enable || command.commands && Object.keys(command.commands).length > 0;
668
831
  const noSubcommandArgInCurrentCall = !argv.some((arg) => !isFlag(arg));
669
832
  if (isDispatcher && noSubcommandArgInCurrentCall) {
670
833
  relinka("warn", "Please specify a command");
671
- await showUsage(command, parserOptions);
834
+ await showUsage(command, parserOptions, globalCliMeta);
672
835
  if (autoExit) process.exit(0);
673
836
  return;
674
837
  }
675
838
  const cmdName = command.meta?.name || "unknown";
676
839
  const attempted = argv.length > 0 ? argv.join(" ") : "(no arguments)";
677
- await showUsage(command, parserOptions);
840
+ await showUsage(command, parserOptions, globalCliMeta);
678
841
  relinka("error", `Unknown command or arguments: ${attempted}`);
679
842
  if (autoExit) {
680
843
  process.exit(1);
@@ -791,7 +954,7 @@ function castArgValue(def, rawVal, argName) {
791
954
  }
792
955
  function renderPositional(args) {
793
956
  const positionalKeys = Object.keys(args || {}).filter(
794
- (k) => args[k].type === "positional"
957
+ (k) => args?.[k]?.type === "positional"
795
958
  );
796
959
  return positionalKeys.map((k) => `<${k}>`).join(" ");
797
960
  }
@@ -800,7 +963,7 @@ export function defineArgs(args) {
800
963
  }
801
964
  export async function runCmd(command, argv = [], parserOptions = {}) {
802
965
  const booleanKeys = Object.keys(command.args || {}).filter(
803
- (k) => command.args[k].type === "boolean"
966
+ (k) => command.args?.[k]?.type === "boolean"
804
967
  );
805
968
  const defaultMap = {};
806
969
  for (const [argKey, def] of Object.entries(command.args || {})) {
@@ -819,23 +982,22 @@ export async function runCmd(command, argv = [], parserOptions = {}) {
819
982
  debugLog("Parsed arguments (runCmd):", parsed);
820
983
  const finalArgs = {};
821
984
  const positionalKeys = Object.keys(command.args || {}).filter(
822
- (k) => command.args[k].type === "positional"
985
+ (k) => command.args?.[k]?.type === "positional"
823
986
  );
824
987
  const leftoverPositionals = [...parsed._ || []];
825
988
  for (let i = 0; i < positionalKeys.length; i++) {
826
989
  const key = positionalKeys[i];
827
- const def = command.args?.[key];
990
+ if (!key || !command.args) continue;
991
+ const def = command.args[key];
828
992
  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;
993
+ finalArgs[key] = val != null && def ? castArgValue(def, val, key) : def?.default;
833
994
  }
834
995
  const otherKeys = Object.keys(command.args || {}).filter(
835
- (k) => command.args[k].type !== "positional"
996
+ (k) => command.args?.[k]?.type !== "positional"
836
997
  );
837
998
  for (const key of otherKeys) {
838
999
  const def = command.args?.[key];
1000
+ if (!def) continue;
839
1001
  let rawVal = parsed[key];
840
1002
  if (def.type === "array" && rawVal !== void 0 && !Array.isArray(rawVal)) {
841
1003
  rawVal = [rawVal];
@@ -871,7 +1033,7 @@ export async function runCmd(command, argv = [], parserOptions = {}) {
871
1033
  }
872
1034
  function getParsedContext(command, argv, parserOptions) {
873
1035
  const booleanKeys = Object.keys(command.args || {}).filter(
874
- (k) => command.args[k].type === "boolean"
1036
+ (k) => command.args?.[k]?.type === "boolean"
875
1037
  );
876
1038
  const defaultMap = {};
877
1039
  for (const [argKey, def] of Object.entries(command.args || {})) {
@@ -889,20 +1051,22 @@ function getParsedContext(command, argv, parserOptions) {
889
1051
  const parsed = reliArgParser(argv, mergedParserOptions);
890
1052
  const finalArgs = {};
891
1053
  const positionalKeys = Object.keys(command.args || {}).filter(
892
- (k) => command.args[k].type === "positional"
1054
+ (k) => command.args?.[k]?.type === "positional"
893
1055
  );
894
1056
  const leftoverPositionals = [...parsed._ || []];
895
1057
  for (let i = 0; i < positionalKeys.length; i++) {
896
1058
  const key = positionalKeys[i];
897
- const def = command.args?.[key];
1059
+ if (!key || !command.args) continue;
1060
+ const def = command.args[key];
898
1061
  const val = leftoverPositionals[i];
899
- finalArgs[key] = val != null ? castArgValue(def, val, key) : def.default;
1062
+ finalArgs[key] = val != null && def ? castArgValue(def, val, key) : def?.default;
900
1063
  }
901
1064
  const otherKeys = Object.keys(command.args || {}).filter(
902
- (k) => command.args[k].type !== "positional"
1065
+ (k) => command.args?.[k]?.type !== "positional"
903
1066
  );
904
1067
  for (const key of otherKeys) {
905
1068
  const def = command.args?.[key];
1069
+ if (!def) continue;
906
1070
  let rawVal = parsed[key];
907
1071
  if (def.type === "array" && rawVal !== void 0 && !Array.isArray(rawVal)) {
908
1072
  rawVal = [rawVal];
@@ -919,7 +1083,7 @@ async function resolveFileBasedCommandPath(cmdsRoot, argv) {
919
1083
  let currentDir = cmdsRoot;
920
1084
  const pathSegments = [];
921
1085
  let leftover = [...argv];
922
- while (leftover.length > 0 && !isFlag(leftover[0])) {
1086
+ while (leftover.length > 0 && leftover[0] && !isFlag(leftover[0])) {
923
1087
  const nextDir = path.join(currentDir, leftover[0]);
924
1088
  if (await fs.pathExists(nextDir) && (await fs.stat(nextDir)).isDirectory()) {
925
1089
  currentDir = nextDir;