@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.
- package/README.md +141 -29
- package/bin/{components/animate/animate.js → libs/animate/animate-mod.js} +1 -4
- package/bin/{components → libs}/anykey/anykey-mod.js +2 -2
- package/bin/libs/confirm/confirm-alias.d.ts +1 -0
- package/bin/libs/confirm/confirm-alias.js +2 -0
- package/bin/{components/confirm/confirm-prompt.js → libs/confirm/confirm-mod.js} +1 -1
- package/bin/{components → libs}/editor/editor-mod.js +8 -8
- package/bin/{components → libs}/figures/figures-mod.d.ts +2 -3
- package/bin/{components → libs}/figures/figures-mod.js +1 -2
- package/bin/libs/input/input-alias.d.ts +4 -0
- package/bin/libs/input/input-alias.js +4 -0
- package/bin/{components/input/input-prompt.js → libs/input/input-mod.js} +2 -2
- package/bin/libs/intro/intro-alias.d.ts +2 -0
- package/bin/libs/intro/intro-alias.js +3 -0
- package/bin/{components/intro/intro-start.js → libs/intro/intro-mod.js} +3 -3
- package/bin/libs/launcher/launcher-alias.d.ts +2 -0
- package/bin/libs/launcher/launcher-alias.js +2 -0
- package/bin/libs/launcher/launcher-mod.d.ts +114 -0
- package/bin/{components → libs}/launcher/launcher-mod.js +355 -191
- package/bin/{components → libs}/launcher/launcher-types.d.ts +1 -1
- package/bin/libs/launcher/trpc-orpc-support/completions.d.ts +4 -0
- package/bin/libs/launcher/trpc-orpc-support/completions.js +45 -0
- package/bin/libs/launcher/trpc-orpc-support/errors.d.ts +11 -0
- package/bin/libs/launcher/trpc-orpc-support/errors.js +10 -0
- package/bin/libs/launcher/trpc-orpc-support/index.d.ts +34 -0
- package/bin/libs/launcher/trpc-orpc-support/index.js +641 -0
- package/bin/libs/launcher/trpc-orpc-support/json-schema.d.ts +17 -0
- package/bin/libs/launcher/trpc-orpc-support/json-schema.js +168 -0
- package/bin/libs/launcher/trpc-orpc-support/json.d.ts +44 -0
- package/bin/libs/launcher/trpc-orpc-support/json.js +41 -0
- package/bin/libs/launcher/trpc-orpc-support/logging.d.ts +11 -0
- package/bin/libs/launcher/trpc-orpc-support/logging.js +26 -0
- package/bin/libs/launcher/trpc-orpc-support/parse-procedure.d.ts +2 -0
- package/bin/libs/launcher/trpc-orpc-support/parse-procedure.js +486 -0
- package/bin/libs/launcher/trpc-orpc-support/prompts.d.ts +18 -0
- package/bin/libs/launcher/trpc-orpc-support/prompts.js +534 -0
- package/bin/libs/launcher/trpc-orpc-support/standard-schema/contract.d.ts +53 -0
- package/bin/libs/launcher/trpc-orpc-support/standard-schema/contract.js +0 -0
- package/bin/libs/launcher/trpc-orpc-support/standard-schema/errors.d.ts +9 -0
- package/bin/libs/launcher/trpc-orpc-support/standard-schema/errors.js +47 -0
- package/bin/libs/launcher/trpc-orpc-support/standard-schema/utils.d.ts +3 -0
- package/bin/libs/launcher/trpc-orpc-support/standard-schema/utils.js +6 -0
- package/bin/libs/launcher/trpc-orpc-support/trpc-compat.d.ts +71 -0
- package/bin/libs/launcher/trpc-orpc-support/trpc-compat.js +11 -0
- package/bin/libs/launcher/trpc-orpc-support/types.d.ts +276 -0
- package/bin/libs/launcher/trpc-orpc-support/types.js +0 -0
- package/bin/libs/launcher/trpc-orpc-support/util.d.ts +9 -0
- package/bin/libs/launcher/trpc-orpc-support/util.js +9 -0
- package/bin/{components → libs}/msg-fmt/logger.js +1 -1
- package/bin/libs/multiselect/multiselect-alias.d.ts +1 -0
- package/bin/libs/multiselect/multiselect-alias.js +2 -0
- package/bin/{components/select → libs/multiselect}/multiselect-prompt.js +1 -1
- package/bin/{components → libs}/number/number-mod.js +1 -4
- package/bin/libs/outro/outro-alias.d.ts +2 -0
- package/bin/libs/outro/outro-alias.js +3 -0
- package/bin/{components/outro/outro-end.js → libs/outro/outro-mod.js} +2 -2
- package/bin/libs/select/aliases-alias.d.ts +1 -0
- package/bin/libs/select/aliases-alias.js +2 -0
- package/bin/{components → libs}/select/select-prompt.js +2 -2
- package/bin/{components → libs}/select/toggle-prompt.js +1 -1
- package/bin/libs/spinner/spinner-alias.d.ts +1 -0
- package/bin/libs/spinner/spinner-alias.js +2 -0
- package/bin/{components → libs}/spinner/spinner-mod.js +3 -1
- package/bin/{components → libs}/task/task-spin.js +1 -1
- package/bin/{utils → libs/utils}/colorize.d.ts +1 -1
- package/bin/{utils → libs/utils}/prevent.d.ts +1 -1
- package/bin/{utils → libs/utils}/prevent.js +2 -2
- package/bin/{utils → libs/utils}/prompt-end.d.ts +1 -1
- package/bin/{utils → libs/utils}/prompt-end.js +2 -2
- package/bin/{utils → libs/utils}/stream-text.d.ts +1 -1
- package/bin/{utils → libs/utils}/stream-text.js +2 -2
- package/bin/mod.d.ts +66 -41
- package/bin/mod.js +102 -66
- package/package.json +17 -2
- package/bin/components/aliases/aliases-mod.d.ts +0 -11
- package/bin/components/aliases/aliases-mod.js +0 -16
- package/bin/components/launcher/launcher-mod.d.ts +0 -52
- /package/bin/{components/animate/animate.d.ts → libs/animate/animate-mod.d.ts} +0 -0
- /package/bin/{components → libs}/anykey/anykey-mod.d.ts +0 -0
- /package/bin/{components → libs}/cancel/cancel.d.ts +0 -0
- /package/bin/{components → libs}/cancel/cancel.js +0 -0
- /package/bin/{components/confirm/confirm-prompt.d.ts → libs/confirm/confirm-mod.d.ts} +0 -0
- /package/bin/{components → libs}/date/date.d.ts +0 -0
- /package/bin/{components → libs}/date/date.js +0 -0
- /package/bin/{components → libs}/editor/editor-mod.d.ts +0 -0
- /package/bin/{components/input/input-prompt.d.ts → libs/input/input-mod.d.ts} +0 -0
- /package/bin/{components/intro/intro-start.d.ts → libs/intro/intro-mod.d.ts} +0 -0
- /package/bin/{components → libs}/launcher/launcher-types.js +0 -0
- /package/bin/{components → libs}/launcher/run-command.d.ts +0 -0
- /package/bin/{components → libs}/launcher/run-command.js +0 -0
- /package/bin/{components/log/log.d.ts → libs/log/log-alias.d.ts} +0 -0
- /package/bin/{components/log/log.js → libs/log/log-alias.js} +0 -0
- /package/bin/{components → libs}/msg-fmt/colors.d.ts +0 -0
- /package/bin/{components → libs}/msg-fmt/colors.js +0 -0
- /package/bin/{components → libs}/msg-fmt/logger.d.ts +0 -0
- /package/bin/{components → libs}/msg-fmt/mapping.d.ts +0 -0
- /package/bin/{components → libs}/msg-fmt/mapping.js +0 -0
- /package/bin/{components → libs}/msg-fmt/messages.d.ts +0 -0
- /package/bin/{components → libs}/msg-fmt/messages.js +0 -0
- /package/bin/{components → libs}/msg-fmt/terminal.d.ts +0 -0
- /package/bin/{components → libs}/msg-fmt/terminal.js +0 -0
- /package/bin/{components → libs}/msg-fmt/variants.d.ts +0 -0
- /package/bin/{components → libs}/msg-fmt/variants.js +0 -0
- /package/bin/{components/select → libs/multiselect}/multiselect-prompt.d.ts +0 -0
- /package/bin/{components → libs}/next-steps/next-steps.d.ts +0 -0
- /package/bin/{components → libs}/next-steps/next-steps.js +0 -0
- /package/bin/{components → libs}/number/number-mod.d.ts +0 -0
- /package/bin/{components/outro/outro-end.d.ts → libs/outro/outro-mod.d.ts} +0 -0
- /package/bin/{components → libs}/results/results.d.ts +0 -0
- /package/bin/{components → libs}/results/results.js +0 -0
- /package/bin/{components → libs}/select/nummultiselect-prompt.d.ts +0 -0
- /package/bin/{components → libs}/select/nummultiselect-prompt.js +0 -0
- /package/bin/{components → libs}/select/numselect-prompt.d.ts +0 -0
- /package/bin/{components → libs}/select/numselect-prompt.js +0 -0
- /package/bin/{components → libs}/select/select-prompt.d.ts +0 -0
- /package/bin/{components → libs}/select/toggle-prompt.d.ts +0 -0
- /package/bin/{components → libs}/spinner/spinner-mod.d.ts +0 -0
- /package/bin/{components → libs}/task/progress.d.ts +0 -0
- /package/bin/{components → libs}/task/progress.js +0 -0
- /package/bin/{components → libs}/task/task-spin.d.ts +0 -0
- /package/bin/{utils → libs/utils}/colorize.js +0 -0
- /package/bin/{utils → libs/utils}/errors.d.ts +0 -0
- /package/bin/{utils → libs/utils}/errors.js +0 -0
- /package/bin/{utils → libs/utils}/system.d.ts +0 -0
- /package/bin/{utils → libs/utils}/system.js +0 -0
- /package/bin/{utils → libs/utils}/validate.d.ts +0 -0
- /package/bin/{utils → libs/utils}/validate.js +0 -0
- /package/bin/{components/ascii-art/ascii-art.d.ts → libs/visual/visual-mod.d.ts} +0 -0
- /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]
|
|
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]
|
|
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.
|
|
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
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
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)
|
|
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
|
|
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
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
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
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
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
|
-
|
|
331
|
-
|
|
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 (
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
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
|
-
|
|
361
|
-
if (fileBasedEnabled && rawArgv.length > 0 && !isFlag(rawArgv[0])) {
|
|
362
|
-
const [subName, ...subCmdArgv] = rawArgv;
|
|
430
|
+
if (typeof command.onLauncherInit === "function") {
|
|
363
431
|
try {
|
|
364
|
-
|
|
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
|
|
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
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
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
|
-
|
|
403
|
-
|
|
404
|
-
|
|
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
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
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
|
|
420
|
-
|
|
496
|
+
await runFileBasedSubCmd(
|
|
497
|
+
subName,
|
|
421
498
|
subCmdArgv,
|
|
422
|
-
|
|
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
|
|
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
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
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
|
-
|
|
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
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
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
|
-
|
|
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(
|
|
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]
|
|
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]
|
|
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
|
-
|
|
785
|
+
if (!key || !command.args) continue;
|
|
786
|
+
const def = command.args[key];
|
|
619
787
|
const val = leftoverPositionals[i];
|
|
620
|
-
|
|
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]
|
|
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.
|
|
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]
|
|
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]
|
|
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]
|
|
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
|
-
|
|
990
|
+
if (!key || !command.args) continue;
|
|
991
|
+
const def = command.args[key];
|
|
828
992
|
const val = leftoverPositionals[i];
|
|
829
|
-
|
|
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]
|
|
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]
|
|
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]
|
|
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
|
-
|
|
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
|
|
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]
|
|
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;
|