@reliverse/rempts 1.7.43 → 1.7.45

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 (134) hide show
  1. package/README.md +1 -1
  2. package/dist-npm/bin/mod.d.mts +2333 -0
  3. package/dist-npm/bin/mod.mjs +8236 -0
  4. package/package.json +84 -42
  5. package/bin/libs/animate/animate-mod.d.ts +0 -14
  6. package/bin/libs/animate/animate-mod.js +0 -62
  7. package/bin/libs/anykey/anykey-mod.d.ts +0 -12
  8. package/bin/libs/anykey/anykey-mod.js +0 -125
  9. package/bin/libs/cancel/cancel.d.ts +0 -45
  10. package/bin/libs/cancel/cancel.js +0 -72
  11. package/bin/libs/confirm/confirm-alias.d.ts +0 -2
  12. package/bin/libs/confirm/confirm-alias.js +0 -2
  13. package/bin/libs/confirm/confirm-mod.d.ts +0 -5
  14. package/bin/libs/confirm/confirm-mod.js +0 -179
  15. package/bin/libs/date/date.d.ts +0 -2
  16. package/bin/libs/date/date.js +0 -236
  17. package/bin/libs/editor/editor-mod.d.ts +0 -25
  18. package/bin/libs/editor/editor-mod.js +0 -897
  19. package/bin/libs/figures/figures-mod.d.ts +0 -461
  20. package/bin/libs/figures/figures-mod.js +0 -285
  21. package/bin/libs/group/group-mod.d.ts +0 -33
  22. package/bin/libs/group/group-mod.js +0 -93
  23. package/bin/libs/input/input-alias.d.ts +0 -5
  24. package/bin/libs/input/input-alias.js +0 -4
  25. package/bin/libs/input/input-mod.d.ts +0 -16
  26. package/bin/libs/input/input-mod.js +0 -372
  27. package/bin/libs/intro/intro-alias.d.ts +0 -2
  28. package/bin/libs/intro/intro-alias.js +0 -3
  29. package/bin/libs/intro/intro-mod.d.ts +0 -20
  30. package/bin/libs/intro/intro-mod.js +0 -81
  31. package/bin/libs/launcher/command-runner.d.ts +0 -18
  32. package/bin/libs/launcher/command-runner.js +0 -76
  33. package/bin/libs/launcher/command-typed.d.ts +0 -16
  34. package/bin/libs/launcher/command-typed.js +0 -60
  35. package/bin/libs/launcher/launcher-alias.d.ts +0 -2
  36. package/bin/libs/launcher/launcher-alias.js +0 -2
  37. package/bin/libs/launcher/launcher-mod.d.ts +0 -162
  38. package/bin/libs/launcher/launcher-mod.js +0 -1222
  39. package/bin/libs/launcher/launcher-types.d.ts +0 -159
  40. package/bin/libs/launcher/launcher-types.js +0 -0
  41. package/bin/libs/launcher/trpc-orpc-support/completions.d.ts +0 -4
  42. package/bin/libs/launcher/trpc-orpc-support/completions.js +0 -45
  43. package/bin/libs/launcher/trpc-orpc-support/errors.d.ts +0 -11
  44. package/bin/libs/launcher/trpc-orpc-support/errors.js +0 -10
  45. package/bin/libs/launcher/trpc-orpc-support/index.d.ts +0 -34
  46. package/bin/libs/launcher/trpc-orpc-support/index.js +0 -641
  47. package/bin/libs/launcher/trpc-orpc-support/json-schema.d.ts +0 -17
  48. package/bin/libs/launcher/trpc-orpc-support/json-schema.js +0 -168
  49. package/bin/libs/launcher/trpc-orpc-support/json.d.ts +0 -44
  50. package/bin/libs/launcher/trpc-orpc-support/json.js +0 -41
  51. package/bin/libs/launcher/trpc-orpc-support/logging.d.ts +0 -11
  52. package/bin/libs/launcher/trpc-orpc-support/logging.js +0 -26
  53. package/bin/libs/launcher/trpc-orpc-support/parse-procedure.d.ts +0 -2
  54. package/bin/libs/launcher/trpc-orpc-support/parse-procedure.js +0 -486
  55. package/bin/libs/launcher/trpc-orpc-support/prompts.d.ts +0 -18
  56. package/bin/libs/launcher/trpc-orpc-support/prompts.js +0 -534
  57. package/bin/libs/launcher/trpc-orpc-support/standard-schema/contract.d.ts +0 -53
  58. package/bin/libs/launcher/trpc-orpc-support/standard-schema/contract.js +0 -0
  59. package/bin/libs/launcher/trpc-orpc-support/standard-schema/errors.d.ts +0 -9
  60. package/bin/libs/launcher/trpc-orpc-support/standard-schema/errors.js +0 -47
  61. package/bin/libs/launcher/trpc-orpc-support/standard-schema/utils.d.ts +0 -3
  62. package/bin/libs/launcher/trpc-orpc-support/standard-schema/utils.js +0 -6
  63. package/bin/libs/launcher/trpc-orpc-support/trpc-compat.d.ts +0 -71
  64. package/bin/libs/launcher/trpc-orpc-support/trpc-compat.js +0 -11
  65. package/bin/libs/launcher/trpc-orpc-support/types.d.ts +0 -276
  66. package/bin/libs/launcher/trpc-orpc-support/types.js +0 -0
  67. package/bin/libs/launcher/trpc-orpc-support/util.d.ts +0 -9
  68. package/bin/libs/launcher/trpc-orpc-support/util.js +0 -9
  69. package/bin/libs/log/log-alias.d.ts +0 -1
  70. package/bin/libs/log/log-alias.js +0 -2
  71. package/bin/libs/msg-fmt/colors.d.ts +0 -30
  72. package/bin/libs/msg-fmt/colors.js +0 -42
  73. package/bin/libs/msg-fmt/logger.d.ts +0 -17
  74. package/bin/libs/msg-fmt/logger.js +0 -103
  75. package/bin/libs/msg-fmt/mapping.d.ts +0 -3
  76. package/bin/libs/msg-fmt/mapping.js +0 -49
  77. package/bin/libs/msg-fmt/messages.d.ts +0 -35
  78. package/bin/libs/msg-fmt/messages.js +0 -319
  79. package/bin/libs/msg-fmt/terminal.d.ts +0 -15
  80. package/bin/libs/msg-fmt/terminal.js +0 -60
  81. package/bin/libs/msg-fmt/variants.d.ts +0 -11
  82. package/bin/libs/msg-fmt/variants.js +0 -52
  83. package/bin/libs/multiselect/multiselect-alias.d.ts +0 -2
  84. package/bin/libs/multiselect/multiselect-alias.js +0 -2
  85. package/bin/libs/multiselect/multiselect-prompt.d.ts +0 -2
  86. package/bin/libs/multiselect/multiselect-prompt.js +0 -348
  87. package/bin/libs/next-steps/next-steps.d.ts +0 -14
  88. package/bin/libs/next-steps/next-steps.js +0 -24
  89. package/bin/libs/number/number-mod.d.ts +0 -28
  90. package/bin/libs/number/number-mod.js +0 -194
  91. package/bin/libs/outro/outro-alias.d.ts +0 -2
  92. package/bin/libs/outro/outro-alias.js +0 -3
  93. package/bin/libs/outro/outro-mod.d.ts +0 -8
  94. package/bin/libs/outro/outro-mod.js +0 -55
  95. package/bin/libs/results/results.d.ts +0 -7
  96. package/bin/libs/results/results.js +0 -27
  97. package/bin/libs/select/nummultiselect-prompt.d.ts +0 -6
  98. package/bin/libs/select/nummultiselect-prompt.js +0 -105
  99. package/bin/libs/select/numselect-prompt.d.ts +0 -7
  100. package/bin/libs/select/numselect-prompt.js +0 -115
  101. package/bin/libs/select/select-alias.d.ts +0 -9
  102. package/bin/libs/select/select-alias.js +0 -9
  103. package/bin/libs/select/select-prompt.d.ts +0 -5
  104. package/bin/libs/select/select-prompt.js +0 -314
  105. package/bin/libs/select/toggle-prompt.d.ts +0 -5
  106. package/bin/libs/select/toggle-prompt.js +0 -209
  107. package/bin/libs/spinner/spinner-alias.d.ts +0 -1
  108. package/bin/libs/spinner/spinner-alias.js +0 -2
  109. package/bin/libs/spinner/spinner-mod.d.ts +0 -106
  110. package/bin/libs/spinner/spinner-mod.js +0 -265
  111. package/bin/libs/task/progress.d.ts +0 -2
  112. package/bin/libs/task/progress.js +0 -57
  113. package/bin/libs/task/task-spin.d.ts +0 -15
  114. package/bin/libs/task/task-spin.js +0 -110
  115. package/bin/libs/utils/colorize.d.ts +0 -2
  116. package/bin/libs/utils/colorize.js +0 -135
  117. package/bin/libs/utils/errors.d.ts +0 -1
  118. package/bin/libs/utils/errors.js +0 -17
  119. package/bin/libs/utils/prevent.d.ts +0 -8
  120. package/bin/libs/utils/prevent.js +0 -65
  121. package/bin/libs/utils/prompt-end.d.ts +0 -8
  122. package/bin/libs/utils/prompt-end.js +0 -34
  123. package/bin/libs/utils/stream-text.d.ts +0 -18
  124. package/bin/libs/utils/stream-text.js +0 -136
  125. package/bin/libs/utils/system.d.ts +0 -6
  126. package/bin/libs/utils/system.js +0 -7
  127. package/bin/libs/utils/validate.d.ts +0 -21
  128. package/bin/libs/utils/validate.js +0 -17
  129. package/bin/libs/visual/visual-mod.d.ts +0 -6
  130. package/bin/libs/visual/visual-mod.js +0 -13
  131. package/bin/mod.d.ts +0 -69
  132. package/bin/mod.js +0 -159
  133. package/bin/types.d.ts +0 -371
  134. package/bin/types.js +0 -0
@@ -1,1222 +0,0 @@
1
- import path from "@reliverse/pathkit";
2
- import { reliArgParser } from "@reliverse/reliarg";
3
- import { re } from "@reliverse/relico";
4
- import fs from "@reliverse/relifso";
5
- import { relinka, relinkaConfig, relinkaShutdown } from "@reliverse/relinka";
6
- import process from "node:process";
7
- import { readPackageJSON } from "pkg-types";
8
- import { createRpcCli } from "./trpc-orpc-support/index.js";
9
- function buildExampleArgs(args) {
10
- const parts = [];
11
- const positionalKeys = Object.keys(args || {}).filter(
12
- (k) => args?.[k]?.type === "positional"
13
- );
14
- positionalKeys.forEach((key) => {
15
- const def = args?.[key];
16
- if (def && (def.required || Math.random() > 0.5)) {
17
- parts.push(String(def.default ?? `<${key}>`));
18
- }
19
- });
20
- const otherKeys = Object.keys(args || {}).filter(
21
- (k) => args?.[k]?.type !== "positional"
22
- );
23
- for (const key of otherKeys) {
24
- const def = args?.[key];
25
- if (def && (def.required || Math.random() > 0.7)) {
26
- switch (def.type) {
27
- case "boolean":
28
- if (def.default === true) {
29
- if (Math.random() > 0.5) parts.push(`--no-${key}`);
30
- } else {
31
- parts.push(`--${key}`);
32
- }
33
- break;
34
- case "string":
35
- parts.push(`--${key}=${String(def.default ?? key)}`);
36
- break;
37
- case "number":
38
- parts.push(`--${key}=${String(def.default ?? 42)}`);
39
- break;
40
- case "array":
41
- parts.push(`--${key}=${String(def.default ?? key)}`);
42
- break;
43
- }
44
- }
45
- }
46
- return parts.join(" ");
47
- }
48
- const isDebugMode = process.argv.includes("--debug");
49
- function debugLog(...args) {
50
- if (isDebugMode) {
51
- relinka("log", "[DEBUG]", ...args);
52
- }
53
- }
54
- function isFlag(str) {
55
- return str.startsWith("-");
56
- }
57
- export function defineCommand(options) {
58
- const onCmdInit = options.onCmdInit || options.setup;
59
- const onCmdExit = options.onCmdExit || options.cleanup;
60
- const onLauncherInit = options.onLauncherInit;
61
- const onLauncherExit = options.onLauncherExit;
62
- let commands = options.commands;
63
- if (!commands) {
64
- commands = options.subCommands;
65
- }
66
- const cmdObj = {
67
- meta: options.meta,
68
- args: options.args || {},
69
- run: options.run,
70
- commands,
71
- onCmdInit,
72
- onCmdExit,
73
- onLauncherInit,
74
- onLauncherExit,
75
- router: options.router,
76
- // Backward-compatible aliases
77
- setup: onCmdInit,
78
- cleanup: onCmdExit
79
- };
80
- Object.defineProperty(cmdObj, "subCommands", {
81
- get() {
82
- return this.commands;
83
- },
84
- enumerable: false,
85
- configurable: true
86
- });
87
- return cmdObj;
88
- }
89
- let _cachedDefaultCliName;
90
- let _cachedDefaultCliVersion;
91
- async function getDefaultCliNameAndVersion() {
92
- if (_cachedDefaultCliName)
93
- return { name: _cachedDefaultCliName, version: _cachedDefaultCliVersion };
94
- try {
95
- const pkg = await readPackageJSON();
96
- let name = pkg.name || "cli";
97
- if (name.startsWith("@")) {
98
- name = name.split("/").pop() || name;
99
- }
100
- _cachedDefaultCliName = name;
101
- _cachedDefaultCliVersion = pkg.version;
102
- return { name, version: pkg.version };
103
- } catch (_e) {
104
- return { name: "cli", version: void 0 };
105
- }
106
- }
107
- async function findRecursiveFileBasedCommands(baseDir, currentPath = []) {
108
- const results = [];
109
- const items = await fs.readdir(path.join(baseDir, ...currentPath), {
110
- withFileTypes: true
111
- });
112
- for (const dirent of items) {
113
- if (dirent.isDirectory()) {
114
- const newPath = [...currentPath, dirent.name];
115
- for (const fname of ["cmd.ts", "cmd.js"]) {
116
- const fpath = path.join(baseDir, ...newPath, fname);
117
- if (await fs.pathExists(fpath)) {
118
- try {
119
- const imported = await import(path.resolve(fpath));
120
- if (imported.default && !imported.default.meta?.hidden) {
121
- results.push({
122
- name: dirent.name,
123
- def: imported.default,
124
- path: newPath
125
- });
126
- }
127
- } catch (err) {
128
- debugLog(`Skipping file-based command in ${fpath}:`, err);
129
- }
130
- break;
131
- }
132
- }
133
- const subResults = await findRecursiveFileBasedCommands(baseDir, newPath);
134
- results.push(...subResults);
135
- }
136
- }
137
- return results;
138
- }
139
- function calculatePadding(items, minPad = 2) {
140
- const maxLength = items.reduce(
141
- (max, item) => Math.max(max, item.text.length),
142
- 0
143
- );
144
- return maxLength + minPad;
145
- }
146
- function formatTableRow(text, desc, padding) {
147
- const spaces = " ".repeat(Math.max(0, padding - text.length));
148
- return `${text}${spaces}| ${desc || ""}`;
149
- }
150
- export async function showUsage(command, parserOptions = {}, globalCliMeta) {
151
- const { name: fallbackName, version: fallbackVersion } = await getDefaultCliNameAndVersion();
152
- const cliName = globalCliMeta?.name || command.meta?.name || fallbackName;
153
- const cliVersion = globalCliMeta?.version || command.meta?.version || fallbackVersion;
154
- relinka("info", `${cliName}${cliVersion ? ` v${cliVersion}` : ""}`);
155
- if (parserOptions.metaSettings?.showDescriptionOnMain) {
156
- let description = globalCliMeta?.description || command.meta?.description;
157
- if (!description) {
158
- try {
159
- const pkg = await readPackageJSON();
160
- if (pkg.description) description = pkg.description;
161
- } catch (_e) {
162
- }
163
- }
164
- if (description) {
165
- relinka("log", description);
166
- }
167
- }
168
- const { name: pkgName } = await getDefaultCliNameAndVersion();
169
- const fileCmds = parserOptions.fileBased;
170
- if (fileCmds?.enable) {
171
- const commandsDir = path.resolve(fileCmds.cmdsRootPath);
172
- const pathSegments = parserOptions._fileBasedPathSegments || [];
173
- let usageLine = [pkgName, ...pathSegments].join(" ");
174
- const allCommands = await findRecursiveFileBasedCommands(
175
- commandsDir,
176
- pathSegments
177
- );
178
- const directCommands = allCommands.filter(
179
- (cmd) => cmd.path.length === pathSegments.length + 1
180
- );
181
- if (directCommands.length > 0) {
182
- usageLine += " <command> [command's options]";
183
- } else {
184
- usageLine += " [command's options]";
185
- const pos = renderPositional(command.args);
186
- if (pos) usageLine += ` ${pos}`;
187
- }
188
- relinka("log", re.cyan(`Usage: ${usageLine}`));
189
- if (directCommands.length > 0 && allCommands.length > 0) {
190
- const randomIdx = Math.floor(Math.random() * allCommands.length);
191
- const exampleCmd = allCommands[randomIdx];
192
- if (exampleCmd) {
193
- const { path: path2, def: exampleDef } = exampleCmd;
194
- const exampleArgs = buildExampleArgs(exampleDef.args || {});
195
- relinka(
196
- "log",
197
- re.cyan(
198
- `Example: ${pkgName} ${path2.join(" ")}${exampleArgs ? ` ${exampleArgs}` : ""}`
199
- )
200
- );
201
- }
202
- }
203
- if (allCommands.length > 0) {
204
- relinka("info", "Available commands (run with `help` to see more):");
205
- const commandsByPath = /* @__PURE__ */ new Map();
206
- for (const cmd of allCommands) {
207
- const parentPath = cmd.path.slice(0, -1).join("/") || "/";
208
- if (!commandsByPath.has(parentPath)) {
209
- commandsByPath.set(parentPath, []);
210
- }
211
- const group = commandsByPath.get(parentPath);
212
- if (group) {
213
- group.push(cmd);
214
- }
215
- }
216
- const groupPaddings = /* @__PURE__ */ new Map();
217
- for (const [parentPath, cmds] of commandsByPath) {
218
- const items = cmds.map(({ path: path2, def }) => ({
219
- text: `${parentPath === "/" ? "" : " "}\u2022 ${path2.join(" ")}`,
220
- desc: def?.meta?.description
221
- }));
222
- groupPaddings.set(parentPath, calculatePadding(items));
223
- }
224
- for (const [parentPath, cmds] of commandsByPath) {
225
- if (parentPath !== "/") {
226
- relinka("log", re.cyanPastel(`Sub-commands in ${parentPath}:`));
227
- }
228
- const padding = groupPaddings.get(parentPath) || 0;
229
- for (const { def, path: path2 } of cmds) {
230
- const desc = def?.meta?.description ?? "";
231
- const indent = parentPath === "/" ? "" : " ";
232
- const text = `${indent}\u2022 ${path2.join(" ")}`;
233
- relinka("log", formatTableRow(text, desc, padding));
234
- }
235
- }
236
- }
237
- } else {
238
- const subCommandNames = [];
239
- const subCommandDefs = [];
240
- const objectCommands = command.commands;
241
- if (objectCommands) {
242
- for (const [name, spec] of Object.entries(objectCommands)) {
243
- try {
244
- const cmd = await loadSubCommand(spec);
245
- if (!cmd?.meta?.hidden) {
246
- const aliasDisplay = cmd.meta?.aliases ? ` (aliases: ${cmd.meta.aliases.join(", ")})` : "";
247
- subCommandNames.push(`${name}${aliasDisplay}`);
248
- subCommandDefs.push({ name, def: cmd });
249
- }
250
- } catch (err) {
251
- debugLog(`Error loading command ${name}:`, err);
252
- }
253
- }
254
- }
255
- let usageLine = pkgName;
256
- if (parserOptions._isSubcommand) {
257
- usageLine += ` ${cliName}`;
258
- }
259
- if (subCommandNames.length > 0) {
260
- usageLine += " <command> [command's options]";
261
- } else {
262
- usageLine += ` [command's options] ${renderPositional(command.args)}`;
263
- }
264
- relinka("log", re.cyan(`Usage: ${usageLine}`));
265
- if (subCommandDefs.length > 0) {
266
- const randomIdx = Math.floor(Math.random() * subCommandDefs.length);
267
- const exampleCmd = subCommandDefs[randomIdx];
268
- if (exampleCmd) {
269
- const { name: exampleCmdName, def: exampleDef } = exampleCmd;
270
- const exampleArgs = buildExampleArgs(exampleDef.args || {});
271
- relinka(
272
- "log",
273
- re.cyan(
274
- `Example: ${pkgName}${parserOptions._isSubcommand ? ` ${cliName}` : ""} ${exampleCmdName}${exampleArgs ? ` ${exampleArgs}` : ""}`
275
- )
276
- );
277
- }
278
- }
279
- if (subCommandNames.length > 0) {
280
- relinka("info", "Available commands (run with `help` to see more):");
281
- const commandItems = subCommandDefs.map(({ name, def }) => ({
282
- text: `\u2022 ${name}`,
283
- desc: def?.meta?.description
284
- }));
285
- const padding = calculatePadding(commandItems);
286
- for (const { text, desc } of commandItems) {
287
- relinka("log", formatTableRow(text, desc, padding));
288
- }
289
- }
290
- }
291
- relinka("info", "Available options:");
292
- const optionItems = [
293
- { text: "\u2022 -h, --help", desc: "Show help" },
294
- { text: "\u2022 -v, --version", desc: "Show version" },
295
- { text: "\u2022 --debug", desc: "Enable debug mode" }
296
- ];
297
- for (const [key, def] of Object.entries(command.args || {})) {
298
- if (def.type === "positional") {
299
- optionItems.push({
300
- text: `\u2022 <${key}>`,
301
- desc: `${def.description ?? ""}${def.required ? " | required" : ""}`
302
- });
303
- } else {
304
- const text = `\u2022 --${key}${"alias" in def && def.alias ? `, -${def.alias}` : ""}`;
305
- const parts = [
306
- def.description ?? "",
307
- `type=${def.type}`,
308
- def.default !== void 0 ? `default=${JSON.stringify(def.default)}` : null,
309
- def.required ? "required" : null,
310
- def.dependencies ? `depends on: ${def.dependencies.map((r) => `--${r}`).join(", ")}` : null
311
- ].filter(Boolean);
312
- optionItems.push({ text, desc: parts.join(" | ") });
313
- }
314
- }
315
- const optionsPadding = calculatePadding(optionItems);
316
- for (const { text, desc } of optionItems) {
317
- relinka("log", formatTableRow(text, desc, optionsPadding));
318
- }
319
- }
320
- export function createCli(options, legacyParserOptions) {
321
- let command;
322
- let parserOptions;
323
- let globalCliMeta = {};
324
- if (typeof options === "object" && !("run" in options) && !("meta" in options) && !("args" in options) && !("commands" in options)) {
325
- command = options;
326
- parserOptions = legacyParserOptions || {};
327
- } else if ("mainCommand" in options) {
328
- command = options.mainCommand;
329
- parserOptions = {
330
- fileBased: options.fileBased,
331
- autoExit: options.autoExit,
332
- metaSettings: options.metaSettings
333
- };
334
- globalCliMeta = {
335
- name: options.name,
336
- version: options.version,
337
- description: options.description
338
- };
339
- } else {
340
- const inlineOptions = options;
341
- const {
342
- name,
343
- version,
344
- description,
345
- fileBased,
346
- autoExit,
347
- metaSettings,
348
- mainCommand,
349
- ...commandOptions
350
- } = inlineOptions;
351
- command = {
352
- meta: commandOptions.meta,
353
- args: commandOptions.args,
354
- run: commandOptions.run,
355
- commands: commandOptions.commands,
356
- onCmdInit: commandOptions.onCmdInit,
357
- onCmdExit: commandOptions.onCmdExit,
358
- onLauncherInit: commandOptions.onLauncherInit,
359
- onLauncherExit: commandOptions.onLauncherExit
360
- };
361
- parserOptions = {
362
- fileBased,
363
- autoExit,
364
- metaSettings
365
- };
366
- globalCliMeta = { name, version, description };
367
- }
368
- if (command.run && (globalCliMeta.name || globalCliMeta.version || globalCliMeta.description)) {
369
- const mergedMeta = { ...command.meta };
370
- if (globalCliMeta.name && !command.meta?.name) {
371
- mergedMeta.name = globalCliMeta.name;
372
- }
373
- if (globalCliMeta.version && !command.meta?.version) {
374
- mergedMeta.version = globalCliMeta.version;
375
- }
376
- if (globalCliMeta.description && !command.meta?.description) {
377
- mergedMeta.description = globalCliMeta.description;
378
- }
379
- command = {
380
- ...command,
381
- meta: mergedMeta
382
- };
383
- }
384
- const execute = async (_ctx) => {
385
- if (options && typeof options === "object" && "rpc" in options && options.rpc) {
386
- const rpcOptions = options.rpc;
387
- const rpcRunParams = options.rpcRunParams || {};
388
- debugLog("RPC integration detected, creating RPC CLI...");
389
- try {
390
- require("tsx/cjs");
391
- await import("tsx/esm");
392
- debugLog("tsx loaded successfully for TypeScript support");
393
- } catch {
394
- debugLog("tsx not available, continuing without TypeScript support");
395
- }
396
- const getRouterMeta = (router) => {
397
- if ("_def" in router && router._def && "meta" in router._def) {
398
- return router._def.meta;
399
- }
400
- return void 0;
401
- };
402
- const routerMeta = getRouterMeta(rpcOptions.router);
403
- const rpcCli = createRpcCli({
404
- router: rpcOptions.router,
405
- name: globalCliMeta.name || routerMeta?.name,
406
- version: globalCliMeta.version || routerMeta?.version,
407
- description: globalCliMeta.description || routerMeta?.description,
408
- usage: rpcOptions.usage,
409
- context: rpcOptions.context,
410
- trpcServer: rpcOptions.trpcServer,
411
- "@valibot/to-json-schema": rpcOptions["@valibot/to-json-schema"],
412
- effect: rpcOptions.effect
413
- });
414
- debugLog(
415
- "RPC CLI created, running with argv:",
416
- rpcRunParams.argv || process.argv.slice(2)
417
- );
418
- await rpcCli.run({
419
- argv: rpcRunParams.argv || process.argv.slice(2),
420
- logger: rpcRunParams.logger || {
421
- info: console.log,
422
- error: console.error
423
- },
424
- completion: rpcRunParams.completion,
425
- prompts: rpcRunParams.prompts,
426
- formatError: rpcRunParams.formatError,
427
- process: rpcRunParams.process
428
- });
429
- return;
430
- }
431
- if (command.router) {
432
- debugLog(
433
- "Router detected in command, automatically enabling RPC mode..."
434
- );
435
- try {
436
- require("tsx/cjs");
437
- await import("tsx/esm");
438
- debugLog("tsx loaded successfully for TypeScript support");
439
- } catch {
440
- debugLog("tsx not available, continuing without TypeScript support");
441
- }
442
- const getRouterMeta = (router) => {
443
- if ("_def" in router && router._def && "meta" in router._def) {
444
- return router._def.meta;
445
- }
446
- return void 0;
447
- };
448
- const routerMeta = getRouterMeta(command.router);
449
- const rpcCli = createRpcCli({
450
- router: command.router,
451
- name: globalCliMeta.name || command.meta?.name || routerMeta?.name,
452
- version: globalCliMeta.version || command.meta?.version || routerMeta?.version,
453
- description: globalCliMeta.description || command.meta?.description || routerMeta?.description
454
- });
455
- debugLog(
456
- "RPC CLI created from command router, running with argv:",
457
- process.argv.slice(2)
458
- );
459
- await rpcCli.run({
460
- argv: process.argv.slice(2),
461
- logger: {
462
- info: console.log,
463
- error: console.error
464
- },
465
- process: {
466
- exit: process.exit
467
- }
468
- });
469
- return;
470
- }
471
- if (typeof command.onLauncherInit === "function") {
472
- try {
473
- await command.onLauncherInit();
474
- } catch (err) {
475
- relinka("error", "Error in onLauncherInit:", err);
476
- if (parserOptions.autoExit !== false) process.exit(1);
477
- throw err;
478
- }
479
- }
480
- try {
481
- if (!parserOptions.fileBased && !command.commands) {
482
- const mainEntry = process.argv[1] ? path.dirname(path.resolve(process.argv[1])) : process.cwd();
483
- const defaultCmdsRoot = path.join(mainEntry, "src", "app");
484
- const exists = await fs.pathExists(defaultCmdsRoot);
485
- const finalCmdsRoot = exists ? defaultCmdsRoot : path.join(mainEntry, "app");
486
- parserOptions.fileBased = {
487
- enable: true,
488
- cmdsRootPath: finalCmdsRoot
489
- };
490
- }
491
- const rawArgv = process.argv.slice(2);
492
- const autoExit = parserOptions.autoExit !== false;
493
- if (!(parserOptions.fileBased?.enable || command.commands && Object.keys(command.commands).length > 0 || command.run || command.router)) {
494
- relinka(
495
- "error",
496
- "Invalid CLI configuration: No file-based commands, subCommands, run() handler, or router are defined. This CLI will not do anything.\n\u2502 To fix: add file-based commands (./app), or provide at least one subCommand, a run() handler, or a router."
497
- );
498
- process.exit(1);
499
- }
500
- if (parserOptions.fileBased?.enable && rawArgv.length > 0) {
501
- const commandsDir = path.resolve(parserOptions.fileBased.cmdsRootPath);
502
- const resolved = await resolveFileBasedCommandPath(
503
- commandsDir,
504
- rawArgv
505
- );
506
- if (resolved) {
507
- const {
508
- def: subCommand,
509
- leftoverArgv,
510
- path: pathSegments
511
- } = resolved;
512
- const helpIdx = leftoverArgv.findIndex(
513
- (arg) => arg === "help" || arg === "--help" || arg === "-h"
514
- );
515
- if (helpIdx !== -1) {
516
- await showUsage(
517
- subCommand,
518
- {
519
- ...parserOptions,
520
- _fileBasedCurrentDir: pathSegments.length ? path.join(commandsDir, ...pathSegments) : commandsDir,
521
- _fileBasedPathSegments: pathSegments
522
- },
523
- globalCliMeta
524
- );
525
- if (autoExit) process.exit(0);
526
- return;
527
- }
528
- }
529
- }
530
- const fileBasedEnabled = parserOptions.fileBased?.enable;
531
- if (fileBasedEnabled && rawArgv.length > 0 && rawArgv[0] && !isFlag(rawArgv[0])) {
532
- const [subName, ...subCmdArgv] = rawArgv;
533
- try {
534
- const ctx = getParsedContext(command, rawArgv, parserOptions);
535
- if (typeof command.onCmdInit === "function")
536
- await command.onCmdInit(ctx);
537
- await runFileBasedSubCmd(
538
- subName,
539
- subCmdArgv,
540
- parserOptions.fileBased,
541
- parserOptions,
542
- command.onCmdExit ? async (_subCtx) => {
543
- await command.onCmdExit?.(ctx);
544
- } : void 0,
545
- globalCliMeta
546
- );
547
- if (autoExit) process.exit(0);
548
- return;
549
- } catch (err) {
550
- relinka("error", "Error loading file-based subcommand:", err.message);
551
- if (autoExit) process.exit(1);
552
- throw err;
553
- }
554
- }
555
- if (!fileBasedEnabled && command.commands && rawArgv.length > 0 && rawArgv[0] && !isFlag(rawArgv[0])) {
556
- const [maybeSub, ...subCmdArgv] = rawArgv;
557
- let subSpec;
558
- for (const [key, spec] of Object.entries(command.commands)) {
559
- if (key === maybeSub) {
560
- subSpec = spec;
561
- break;
562
- }
563
- try {
564
- const cmd = await loadSubCommand(spec);
565
- if (cmd.meta?.aliases?.includes(maybeSub)) {
566
- subSpec = spec;
567
- break;
568
- }
569
- } catch (err) {
570
- debugLog(`Error checking alias for command ${key}:`, err);
571
- }
572
- }
573
- if (subSpec) {
574
- const helpIdx = subCmdArgv.findIndex(
575
- (arg) => arg === "help" || arg === "--help" || arg === "-h"
576
- );
577
- if (helpIdx !== -1) {
578
- const subCommandDef = await loadSubCommand(subSpec);
579
- await showUsage(
580
- subCommandDef,
581
- {
582
- ...parserOptions,
583
- _isSubcommand: true
584
- },
585
- globalCliMeta
586
- );
587
- if (autoExit) process.exit(0);
588
- return;
589
- }
590
- try {
591
- const ctx = getParsedContext(command, rawArgv, parserOptions);
592
- if (typeof command.onCmdInit === "function")
593
- await command.onCmdInit(ctx);
594
- await runSubCommand(
595
- subSpec,
596
- subCmdArgv,
597
- { ...parserOptions, _isSubcommand: true },
598
- command.onCmdExit ? async (_subCtx) => {
599
- await command.onCmdExit?.(ctx);
600
- } : void 0,
601
- globalCliMeta
602
- );
603
- if (autoExit) process.exit(0);
604
- return;
605
- } catch (err) {
606
- relinka("error", "Error running subcommand:", err.message);
607
- if (autoExit) process.exit(1);
608
- throw err;
609
- }
610
- }
611
- }
612
- await relinkaConfig();
613
- if (rawArgv[0] === "help" || checkHelp(rawArgv)) {
614
- await showUsage(command, parserOptions, globalCliMeta);
615
- if (autoExit) process.exit(0);
616
- return;
617
- }
618
- if (checkVersion(rawArgv)) {
619
- if (command.meta?.name) {
620
- relinka(
621
- "info",
622
- `${command.meta?.name} ${command.meta?.version ? `v${command.meta?.version}` : ""}`
623
- );
624
- }
625
- if (autoExit) process.exit(0);
626
- return;
627
- }
628
- try {
629
- await runCommandWithArgs(
630
- command,
631
- rawArgv,
632
- parserOptions,
633
- globalCliMeta
634
- );
635
- } finally {
636
- }
637
- await relinkaShutdown();
638
- } finally {
639
- if (typeof command.onLauncherExit === "function")
640
- await command.onLauncherExit();
641
- }
642
- };
643
- const promise = execute();
644
- const cli = Object.assign(promise, {
645
- /**
646
- * @deprecated Use createCli() directly instead. This method will be removed in a future version.
647
- * @example
648
- * // Instead of:
649
- * createCli({...}).run()
650
- * // Use:
651
- * await createCli({...})
652
- */
653
- async run(_ctx) {
654
- relinka(
655
- "warn",
656
- "\u26A0\uFE0F Deprecated: .run() method is deprecated. Use createCli() directly instead."
657
- );
658
- relinka("warn", " Instead of: createCli({...}).run()");
659
- relinka("warn", " Use: await createCli({...})");
660
- return execute(_ctx);
661
- }
662
- });
663
- return cli;
664
- }
665
- function checkHelp(argv) {
666
- return argv.includes("--help") || argv.includes("-h");
667
- }
668
- function checkVersion(argv) {
669
- return argv.includes("--version") || argv.includes("-v");
670
- }
671
- async function loadSubCommand(spec) {
672
- if (typeof spec === "string") {
673
- const mod = await import(spec);
674
- if (!mod.default) {
675
- throw new Error(`Subcommand module "${spec}" has no default export`);
676
- }
677
- return mod.default;
678
- }
679
- const imported = await spec();
680
- if ("default" in imported && imported.default) {
681
- return imported.default;
682
- }
683
- if (imported) {
684
- return imported;
685
- }
686
- throw new Error("Subcommand import did not return a valid command");
687
- }
688
- async function runFileBasedSubCmd(subName, argv, fileCmdOpts, parserOptions, parentFinish, globalCliMeta) {
689
- async function resolveCmdPath(baseDir, args) {
690
- if (args.length === 0 || args[0] && isFlag(args[0])) {
691
- const possibleFiles2 = [
692
- path.join(baseDir, "cmd.js"),
693
- path.join(baseDir, "cmd.ts")
694
- ];
695
- for (const file of possibleFiles2) {
696
- if (await fs.pathExists(file)) {
697
- return { importPath: file, leftoverArgv: args };
698
- }
699
- }
700
- throw new Error(
701
- `
702
- Unknown command or arguments: ${args.join(" ")}
703
- Info for this CLI's developer: No valid command file found in ${baseDir}`
704
- );
705
- }
706
- const nextDir = path.join(baseDir, args[0] || "");
707
- if (await fs.pathExists(nextDir) && (await fs.stat(nextDir)).isDirectory()) {
708
- return resolveCmdPath(nextDir, args.slice(1));
709
- }
710
- const possibleFiles = [
711
- path.join(baseDir, "cmd.js"),
712
- path.join(baseDir, "cmd.ts")
713
- ];
714
- for (const file of possibleFiles) {
715
- if (await fs.pathExists(file)) {
716
- return { importPath: file, leftoverArgv: args };
717
- }
718
- }
719
- throw new Error(
720
- `
721
- Unknown command or arguments: ${args.join(" ")}
722
- Info for this CLI's developer: No valid command file found in ${baseDir}`
723
- );
724
- }
725
- const startDir = path.join(fileCmdOpts.cmdsRootPath, subName);
726
- if (!await fs.pathExists(startDir) || !(await fs.stat(startDir)).isDirectory()) {
727
- const attempted = [subName, ...argv].join(" ");
728
- const expectedPath = path.relative(
729
- process.cwd(),
730
- path.join(fileCmdOpts.cmdsRootPath, subName, "cmd.{ts,js}")
731
- );
732
- const allCommands = await findRecursiveFileBasedCommands(
733
- fileCmdOpts.cmdsRootPath
734
- );
735
- const commandNames = allCommands.map((cmd) => cmd.path.join(" "));
736
- let closestMatch = "";
737
- let minDistance = Number.POSITIVE_INFINITY;
738
- for (const cmd of commandNames) {
739
- const distance = levenshteinDistance(subName, cmd.split(" ")[0] || "");
740
- if (distance < minDistance) {
741
- minDistance = distance;
742
- closestMatch = cmd;
743
- }
744
- }
745
- const suggestion = minDistance <= 3 ? ` (Did you mean: \`${closestMatch}\`?)` : "";
746
- throw new Error(
747
- `
748
- Unknown command or arguments: ${attempted}${suggestion}
749
- Info for this CLI's developer: No valid command directory found, expected: ${expectedPath}`
750
- );
751
- }
752
- const { importPath, leftoverArgv } = await resolveCmdPath(startDir, argv);
753
- const imported = await import(path.resolve(importPath));
754
- const subCommand = imported.default;
755
- if (!subCommand) {
756
- throw new Error(
757
- `File-based subcommand has no default export or is invalid: ${importPath}`
758
- );
759
- }
760
- try {
761
- const subCtx = await runCommandWithArgs(
762
- subCommand,
763
- leftoverArgv,
764
- parserOptions,
765
- globalCliMeta
766
- );
767
- if (typeof parentFinish === "function" && subCtx)
768
- await parentFinish(subCtx);
769
- } finally {
770
- }
771
- }
772
- async function runSubCommand(spec, argv, parserOptions, parentFinish, globalCliMeta) {
773
- const subCommand = await loadSubCommand(spec);
774
- try {
775
- const helpIdx = argv.findIndex(
776
- (arg) => arg === "help" || arg === "--help" || arg === "-h"
777
- );
778
- if (helpIdx !== -1) {
779
- await showUsage(
780
- subCommand,
781
- { ...parserOptions, _isSubcommand: true },
782
- globalCliMeta
783
- );
784
- if (parserOptions.autoExit !== false) process.exit(0);
785
- return;
786
- }
787
- const subCtx = await runCommandWithArgs(
788
- subCommand,
789
- argv,
790
- parserOptions,
791
- globalCliMeta,
792
- true
793
- );
794
- if (typeof parentFinish === "function" && subCtx)
795
- await parentFinish(subCtx);
796
- } finally {
797
- }
798
- }
799
- async function runCommandWithArgs(command, argv, parserOptions, globalCliMeta, returnCtx) {
800
- const autoExit = parserOptions.autoExit !== false;
801
- const booleanKeys = Object.keys(command.args || {}).filter(
802
- (k) => command.args?.[k]?.type === "boolean"
803
- );
804
- const defaultMap = {};
805
- for (const [argKey, def] of Object.entries(command.args || {})) {
806
- if (def.type === "boolean") {
807
- defaultMap[argKey] = def.default !== void 0 ? def.default : false;
808
- } else if (def.default !== void 0) {
809
- defaultMap[argKey] = def.type === "array" && typeof def.default === "string" ? [def.default] : def.default;
810
- }
811
- }
812
- const mergedParserOptions = {
813
- ...parserOptions,
814
- boolean: [...parserOptions.boolean || [], ...booleanKeys],
815
- defaults: { ...defaultMap, ...parserOptions.defaults || {} }
816
- };
817
- const parsed = reliArgParser(argv, mergedParserOptions);
818
- debugLog("Parsed arguments:", parsed);
819
- const finalArgs = {};
820
- const positionalKeys = Object.keys(command.args || {}).filter(
821
- (k) => command.args?.[k]?.type === "positional"
822
- );
823
- const leftoverPositionals = [...parsed._ || []];
824
- for (let i = 0; i < positionalKeys.length; i++) {
825
- const key = positionalKeys[i];
826
- if (!key || !command.args) continue;
827
- const def = command.args[key];
828
- const val = leftoverPositionals[i];
829
- finalArgs[key] = val != null && def ? castArgValue(def, val, key) : def?.default;
830
- }
831
- const otherKeys = Object.keys(command.args || {}).filter(
832
- (k) => command.args?.[k]?.type !== "positional"
833
- );
834
- for (const key of otherKeys) {
835
- const def = command.args?.[key];
836
- if (!def) continue;
837
- let rawVal = parsed[key];
838
- if (def.type === "array" && rawVal !== void 0 && !Array.isArray(rawVal)) {
839
- rawVal = [rawVal];
840
- }
841
- const casted = rawVal !== void 0 ? castArgValue(def, rawVal, key) : def.default;
842
- const argUsed = rawVal !== void 0 && (def.type === "boolean" ? casted === true : true);
843
- if (casted == null && def.required) {
844
- await showUsage(command, parserOptions, globalCliMeta);
845
- relinka("error", `Missing required argument: --${key}`);
846
- if (autoExit) process.exit(1);
847
- else throw new Error(`Missing required argument: --${key}`);
848
- }
849
- if (argUsed && def.dependencies?.length) {
850
- const missingDeps = def.dependencies.filter((d) => {
851
- const depVal = parsed[d] ?? defaultMap[d];
852
- return !depVal;
853
- });
854
- if (missingDeps.length > 0) {
855
- const depsList = missingDeps.map((d) => `--${d}`).join(", ");
856
- throw new Error(
857
- `Argument --${key} can only be used when ${depsList} ${missingDeps.length === 1 ? "is" : "are"} set`
858
- );
859
- }
860
- }
861
- finalArgs[key] = def.type === "boolean" ? Boolean(casted) : casted;
862
- }
863
- const ctx = {
864
- args: finalArgs,
865
- raw: argv
866
- };
867
- try {
868
- if (command.run) {
869
- await command.run(ctx);
870
- } else {
871
- const isDispatcher = parserOptions.fileBased?.enable || command.commands && Object.keys(command.commands).length > 0 || command.router;
872
- const noSubcommandArgInCurrentCall = !argv.some((arg) => !isFlag(arg));
873
- if (isDispatcher && noSubcommandArgInCurrentCall) {
874
- relinka("warn", "Please specify a command");
875
- await showUsage(command, parserOptions, globalCliMeta);
876
- if (autoExit) process.exit(0);
877
- return;
878
- }
879
- const cmdName = command.meta?.name || "unknown";
880
- const attempted = argv.length > 0 ? argv.join(" ") : "(no arguments)";
881
- await showUsage(command, parserOptions, globalCliMeta);
882
- relinka("error", `Unknown command or arguments: ${attempted}`);
883
- if (autoExit) {
884
- process.exit(1);
885
- } else {
886
- throw new Error(`Command "${cmdName}" is not runnable.`);
887
- }
888
- }
889
- } catch (err) {
890
- relinka("error", `Error while executing command:
891
- ${String(err)}`);
892
- if (autoExit) process.exit(1);
893
- else throw err;
894
- }
895
- if (returnCtx) return ctx;
896
- return void 0;
897
- }
898
- function castArgValue(def, rawVal, argName) {
899
- if (rawVal == null) {
900
- if (def.type === "array" && typeof def.default === "string") {
901
- return [def.default];
902
- }
903
- return def.default ?? void 0;
904
- }
905
- let castedValue;
906
- switch (def.type) {
907
- case "boolean":
908
- if (typeof rawVal === "string") {
909
- const lower = rawVal.toLowerCase();
910
- if (lower === "true") castedValue = true;
911
- else if (lower === "false") castedValue = false;
912
- else castedValue = Boolean(rawVal);
913
- } else {
914
- castedValue = Boolean(rawVal);
915
- }
916
- if (def.allowed && !def.allowed.includes(castedValue)) {
917
- throw new Error(
918
- `Invalid value for --${argName}: ${rawVal}. Allowed values are: ${def.allowed.join(", ")}`
919
- );
920
- }
921
- return castedValue;
922
- case "string":
923
- castedValue = typeof rawVal === "string" ? rawVal : String(rawVal);
924
- if (def.allowed && !def.allowed.includes(castedValue)) {
925
- throw new Error(
926
- `Invalid value for --${argName}: ${rawVal}. Allowed values are: ${def.allowed.join(", ")}`
927
- );
928
- }
929
- return castedValue;
930
- case "number": {
931
- const n = Number(rawVal);
932
- if (Number.isNaN(n)) {
933
- throw new Error(`Invalid number provided for --${argName}: ${rawVal}`);
934
- }
935
- if (def.allowed && !def.allowed.includes(n)) {
936
- throw new Error(
937
- `Invalid value for --${argName}: ${rawVal}. Allowed values are: ${def.allowed.join(", ")}`
938
- );
939
- }
940
- return n;
941
- }
942
- case "positional":
943
- castedValue = String(rawVal);
944
- if (def.allowed && !def.allowed.includes(castedValue)) {
945
- throw new Error(
946
- `Invalid value for <${argName}>: ${rawVal}. Allowed values are: ${def.allowed.join(", ")}`
947
- );
948
- }
949
- return castedValue;
950
- case "array": {
951
- const arrVal = Array.isArray(rawVal) ? rawVal : [String(rawVal)];
952
- const result = [];
953
- const arrValStr = arrVal.map(String);
954
- let warned = false;
955
- for (let v of arrValStr) {
956
- if (!warned && (v.startsWith("[") && !v.endsWith("]") || !v.startsWith("[") && v.endsWith("]"))) {
957
- relinka("error", `Don't use quotes around array elements.`);
958
- relinka(
959
- "error",
960
- `Also \u2014 don't use spaces \u2014 unless you wrap the whole array in quotes.`
961
- );
962
- relinka(
963
- "warn",
964
- `Array argument --${argName}: Detected possible shell splitting of bracketed value ('${v}').`
965
- );
966
- relinka(
967
- "warn",
968
- `If you intended to pass a bracketed list, quote the whole value like: --${argName} "[a, b, c]"`
969
- );
970
- }
971
- warned = true;
972
- if (v.startsWith("[") && v.endsWith("]")) {
973
- v = v.slice(1, -1);
974
- }
975
- const parts = v.split(/\s*,\s*/).filter(Boolean);
976
- parts.forEach((p) => {
977
- if (p.startsWith('"') && p.endsWith('"') || p.startsWith("'") && p.endsWith("'")) {
978
- throw new Error(
979
- `Array argument --${argName}: Quoted values are not supported due to shell parsing limitations. Please avoid using single or double quotes around array elements.`
980
- );
981
- }
982
- if (def.allowed && !def.allowed.includes(p)) {
983
- throw new Error(
984
- `Invalid value in array --${argName}: ${p}. Allowed values are: ${def.allowed.join(", ")}`
985
- );
986
- }
987
- });
988
- result.push(...parts);
989
- }
990
- return result;
991
- }
992
- default:
993
- return rawVal;
994
- }
995
- }
996
- function renderPositional(args) {
997
- const positionalKeys = Object.keys(args || {}).filter(
998
- (k) => args?.[k]?.type === "positional"
999
- );
1000
- return positionalKeys.map((k) => `<${k}>`).join(" ");
1001
- }
1002
- export function defineArgs(args) {
1003
- return args;
1004
- }
1005
- function normalizeArgv(argv) {
1006
- const normalized = [];
1007
- for (const arg of argv) {
1008
- const parts = arg.split(/\s+/).filter((part) => part.length > 0);
1009
- normalized.push(...parts);
1010
- }
1011
- return normalized;
1012
- }
1013
- export async function runCmdWithSubcommands(command, argv = [], parserOptions = {}) {
1014
- const normalizedArgv = normalizeArgv(argv);
1015
- let currentCommand = command;
1016
- let currentArgv = normalizedArgv;
1017
- while (currentCommand.commands && currentArgv.length > 0 && currentArgv[0] && !isFlag(currentArgv[0])) {
1018
- const [maybeSub, ...restArgv] = currentArgv;
1019
- let subSpec;
1020
- for (const [key, spec] of Object.entries(currentCommand.commands)) {
1021
- if (key === maybeSub) {
1022
- subSpec = spec;
1023
- break;
1024
- }
1025
- try {
1026
- const cmd = await loadSubCommand(spec);
1027
- if (cmd.meta?.aliases?.includes(maybeSub)) {
1028
- subSpec = spec;
1029
- break;
1030
- }
1031
- } catch (err) {
1032
- debugLog(`Error checking alias for command ${key}:`, err);
1033
- }
1034
- }
1035
- if (!subSpec) break;
1036
- const loaded = await loadSubCommand(subSpec);
1037
- currentCommand = loaded;
1038
- currentArgv = restArgv;
1039
- }
1040
- return await runCommandWithArgs(currentCommand, currentArgv, {
1041
- ...parserOptions,
1042
- autoExit: false
1043
- // Don't exit process in programmatic usage
1044
- });
1045
- }
1046
- export async function runCmd(command, argv = [], parserOptions = {}) {
1047
- const normalizedArgv = normalizeArgv(argv);
1048
- const booleanKeys = Object.keys(command.args || {}).filter(
1049
- (k) => command.args?.[k]?.type === "boolean"
1050
- );
1051
- const defaultMap = {};
1052
- for (const [argKey, def] of Object.entries(command.args || {})) {
1053
- if (def.type === "boolean") {
1054
- defaultMap[argKey] = def.default !== void 0 ? def.default : false;
1055
- } else if (def.default !== void 0) {
1056
- defaultMap[argKey] = def.type === "array" && typeof def.default === "string" ? [def.default] : def.default;
1057
- }
1058
- }
1059
- const mergedParserOptions = {
1060
- ...parserOptions,
1061
- boolean: [...parserOptions.boolean || [], ...booleanKeys],
1062
- defaults: { ...defaultMap, ...parserOptions.defaults || {} }
1063
- };
1064
- const parsed = reliArgParser(normalizedArgv, mergedParserOptions);
1065
- debugLog("Parsed arguments (runCmd):", parsed);
1066
- const finalArgs = {};
1067
- const positionalKeys = Object.keys(command.args || {}).filter(
1068
- (k) => command.args?.[k]?.type === "positional"
1069
- );
1070
- const leftoverPositionals = [...parsed._ || []];
1071
- for (let i = 0; i < positionalKeys.length; i++) {
1072
- const key = positionalKeys[i];
1073
- if (!key || !command.args) continue;
1074
- const def = command.args[key];
1075
- const val = leftoverPositionals[i];
1076
- finalArgs[key] = val != null && def ? castArgValue(def, val, key) : def?.default;
1077
- }
1078
- const otherKeys = Object.keys(command.args || {}).filter(
1079
- (k) => command.args?.[k]?.type !== "positional"
1080
- );
1081
- for (const key of otherKeys) {
1082
- const def = command.args?.[key];
1083
- if (!def) continue;
1084
- let rawVal = parsed[key];
1085
- if (def.type === "array" && rawVal !== void 0 && !Array.isArray(rawVal)) {
1086
- rawVal = [rawVal];
1087
- }
1088
- const casted = rawVal !== void 0 ? castArgValue(def, rawVal, key) : def.default;
1089
- const argUsed = rawVal !== void 0 && (def.type === "boolean" ? casted === true : true);
1090
- if (casted == null && def.required) {
1091
- throw new Error(`Missing required argument: --${key}`);
1092
- }
1093
- if (argUsed && def.dependencies?.length) {
1094
- const missingDeps = def.dependencies.filter((d) => {
1095
- const depVal = parsed[d] ?? defaultMap[d];
1096
- return !depVal;
1097
- });
1098
- if (missingDeps.length) {
1099
- const depsList = missingDeps.map((d) => `--${d}`).join(", ");
1100
- throw new Error(
1101
- `Argument --${key} can only be used when ${depsList} ${missingDeps.length === 1 ? "is" : "are"} set`
1102
- );
1103
- }
1104
- }
1105
- finalArgs[key] = def.type === "boolean" ? Boolean(casted) : casted;
1106
- }
1107
- const ctx = {
1108
- args: finalArgs,
1109
- raw: argv
1110
- };
1111
- if (typeof command.run === "function") {
1112
- await command.run(ctx);
1113
- } else {
1114
- throw new Error("Command has no run() handler.");
1115
- }
1116
- }
1117
- function getParsedContext(command, argv, parserOptions) {
1118
- const normalizedArgv = normalizeArgv(argv);
1119
- const booleanKeys = Object.keys(command.args || {}).filter(
1120
- (k) => command.args?.[k]?.type === "boolean"
1121
- );
1122
- const defaultMap = {};
1123
- for (const [argKey, def] of Object.entries(command.args || {})) {
1124
- if (def.type === "boolean") {
1125
- defaultMap[argKey] = def.default !== void 0 ? def.default : false;
1126
- } else if (def.default !== void 0) {
1127
- defaultMap[argKey] = def.type === "array" && typeof def.default === "string" ? [def.default] : def.default;
1128
- }
1129
- }
1130
- const mergedParserOptions = {
1131
- ...parserOptions,
1132
- boolean: [...parserOptions.boolean || [], ...booleanKeys],
1133
- defaults: { ...defaultMap, ...parserOptions.defaults || {} }
1134
- };
1135
- const parsed = reliArgParser(normalizedArgv, mergedParserOptions);
1136
- const finalArgs = {};
1137
- const positionalKeys = Object.keys(command.args || {}).filter(
1138
- (k) => command.args?.[k]?.type === "positional"
1139
- );
1140
- const leftoverPositionals = [...parsed._ || []];
1141
- for (let i = 0; i < positionalKeys.length; i++) {
1142
- const key = positionalKeys[i];
1143
- if (!key || !command.args) continue;
1144
- const def = command.args[key];
1145
- const val = leftoverPositionals[i];
1146
- finalArgs[key] = val != null && def ? castArgValue(def, val, key) : def?.default;
1147
- }
1148
- const otherKeys = Object.keys(command.args || {}).filter(
1149
- (k) => command.args?.[k]?.type !== "positional"
1150
- );
1151
- for (const key of otherKeys) {
1152
- const def = command.args?.[key];
1153
- if (!def) continue;
1154
- let rawVal = parsed[key];
1155
- if (def.type === "array" && rawVal !== void 0 && !Array.isArray(rawVal)) {
1156
- rawVal = [rawVal];
1157
- }
1158
- if (def.type === "boolean") {
1159
- finalArgs[key] = rawVal !== void 0 ? castArgValue(def, rawVal, key) : false;
1160
- } else {
1161
- finalArgs[key] = castArgValue(def, rawVal, key);
1162
- }
1163
- }
1164
- return { args: finalArgs, raw: argv };
1165
- }
1166
- async function resolveFileBasedCommandPath(cmdsRoot, argv) {
1167
- let currentDir = cmdsRoot;
1168
- const pathSegments = [];
1169
- let leftover = [...argv];
1170
- while (leftover.length > 0 && leftover[0] && !isFlag(leftover[0])) {
1171
- const nextDir = path.join(currentDir, leftover[0]);
1172
- if (await fs.pathExists(nextDir) && (await fs.stat(nextDir)).isDirectory()) {
1173
- currentDir = nextDir;
1174
- pathSegments.push(leftover[0]);
1175
- leftover = leftover.slice(1);
1176
- } else {
1177
- break;
1178
- }
1179
- }
1180
- for (const fname of ["cmd.ts", "cmd.js"]) {
1181
- const fpath = path.join(currentDir, fname);
1182
- if (await fs.pathExists(fpath)) {
1183
- const imported = await import(path.resolve(fpath));
1184
- if (imported.default) {
1185
- return {
1186
- def: imported.default,
1187
- path: pathSegments,
1188
- leftoverArgv: leftover
1189
- };
1190
- }
1191
- }
1192
- }
1193
- return null;
1194
- }
1195
- function levenshteinDistance(a, b) {
1196
- if (a.length === 0) return b.length;
1197
- if (b.length === 0) return a.length;
1198
- const matrix = [];
1199
- for (let i = 0; i <= b.length; i++) {
1200
- matrix[i] = [i];
1201
- }
1202
- for (let j = 0; j <= a.length; j++) {
1203
- matrix[0][j] = j;
1204
- }
1205
- for (let i = 1; i <= b.length; i++) {
1206
- for (let j = 1; j <= a.length; j++) {
1207
- if (b.charAt(i - 1) === a.charAt(j - 1)) {
1208
- matrix[i][j] = matrix[i - 1][j - 1];
1209
- } else {
1210
- matrix[i][j] = Math.min(
1211
- matrix[i - 1][j - 1] + 1,
1212
- // substitution
1213
- matrix[i][j - 1] + 1,
1214
- // insertion
1215
- matrix[i - 1][j] + 1
1216
- // deletion
1217
- );
1218
- }
1219
- }
1220
- }
1221
- return matrix[b.length][a.length];
1222
- }