@backstage/cli-node 0.3.5-next.0 → 0.3.5-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +9 -0
- package/dist/cli-module/runCli.cjs.js +92 -16
- package/dist/cli-module/runCli.cjs.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
# @backstage/cli-node
|
|
2
2
|
|
|
3
|
+
## 0.3.5-next.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 7c6ab3d: Commands run through `runCli` now wait for `stdout` and `stderr` to be flushed before exiting, so large command output is no longer truncated on platforms where writes to `stdout` and `stderr` are asynchronous.
|
|
8
|
+
- 6dc6bc6: Fixed CLIs created with `runCli` silently exiting when the root or a command group is invoked without a subcommand. They now display help for that level and complete successfully.
|
|
9
|
+
|
|
10
|
+
Help output now lists groups and commands in separate, alphabetically sorted sections. Group previews adapt to the terminal width, using 80 columns when unavailable. Nested groups expand breadth-first when space permits; unexpanded groups retain a trailing slash and truncated previews end in an ellipsis.
|
|
11
|
+
|
|
3
12
|
## 0.3.5-next.0
|
|
4
13
|
|
|
5
14
|
### Patch Changes
|
|
@@ -22,6 +22,13 @@ ${chalk__default.default.red(message)}
|
|
|
22
22
|
`);
|
|
23
23
|
process.exit(code);
|
|
24
24
|
}
|
|
25
|
+
async function flushStdio() {
|
|
26
|
+
await Promise.all(
|
|
27
|
+
[process.stdout, process.stderr].map(
|
|
28
|
+
(stream) => new Promise((resolve) => stream.write("", () => resolve()))
|
|
29
|
+
)
|
|
30
|
+
);
|
|
31
|
+
}
|
|
25
32
|
function exitWithError(error) {
|
|
26
33
|
if (!errors.isError(error)) {
|
|
27
34
|
return exit(errors.stringifyError(error));
|
|
@@ -70,30 +77,97 @@ function getNodeName(node) {
|
|
|
70
77
|
}
|
|
71
78
|
return InternalCommandNode.OpaqueCommandLeafNode.toInternal(node).name;
|
|
72
79
|
}
|
|
73
|
-
function
|
|
74
|
-
|
|
75
|
-
|
|
80
|
+
function createGroupPreview(children, width) {
|
|
81
|
+
const entries = children.filter((node) => !InternalCommandNode.isCommandNodeHidden(node)).sort((a, b) => getNodeName(a).localeCompare(getNodeName(b), "en")).map((node) => ({ node, path: getNodeName(node) }));
|
|
82
|
+
const format = (items) => items.map(
|
|
83
|
+
({ node, path }) => path + (InternalCommandNode.OpaqueCommandTreeNode.isType(node) ? "/" : "")
|
|
84
|
+
).join(", ");
|
|
85
|
+
if (format(entries).length > width) {
|
|
86
|
+
while (entries.length > 0) {
|
|
87
|
+
entries.pop();
|
|
88
|
+
const preview = format(entries);
|
|
89
|
+
if (preview.length + 3 <= width) {
|
|
90
|
+
return preview ? `${preview}, \u2026` : "\u2026";
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return "\u2026";
|
|
94
|
+
}
|
|
95
|
+
const queue = [...entries];
|
|
96
|
+
for (const entry of queue) {
|
|
97
|
+
if (!InternalCommandNode.OpaqueCommandTreeNode.isType(entry.node)) {
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
const expanded = InternalCommandNode.OpaqueCommandTreeNode.toInternal(entry.node).children.filter((node) => !InternalCommandNode.isCommandNodeHidden(node)).sort((a, b) => getNodeName(a).localeCompare(getNodeName(b), "en")).map((node) => ({ node, path: `${entry.path} ${getNodeName(node)}` }));
|
|
101
|
+
const index = entries.indexOf(entry);
|
|
102
|
+
const candidate = [...entries];
|
|
103
|
+
candidate.splice(index, 1, ...expanded);
|
|
104
|
+
if (format(candidate).length <= width) {
|
|
105
|
+
entries.splice(index, 1, ...expanded);
|
|
106
|
+
queue.push(...expanded);
|
|
107
|
+
}
|
|
76
108
|
}
|
|
77
|
-
return
|
|
109
|
+
return format(entries);
|
|
78
110
|
}
|
|
79
111
|
function createHelpOptions(options) {
|
|
80
112
|
const { nodes, includeHelpCommand, version } = options;
|
|
81
113
|
const visibleNodes = nodes.filter((node) => !InternalCommandNode.isCommandNodeHidden(node));
|
|
114
|
+
const groups = visibleNodes.filter(InternalCommandNode.OpaqueCommandTreeNode.isType);
|
|
115
|
+
const previewWidth = Math.max(
|
|
116
|
+
1,
|
|
117
|
+
(process.stdout.columns || 80) - Math.max(0, ...groups.map((node) => getNodeName(node).length)) - 10
|
|
118
|
+
);
|
|
119
|
+
const groupRows = [];
|
|
120
|
+
const commandRows = [];
|
|
121
|
+
for (const node of visibleNodes) {
|
|
122
|
+
if (InternalCommandNode.OpaqueCommandTreeNode.isType(node)) {
|
|
123
|
+
const { name, children } = InternalCommandNode.OpaqueCommandTreeNode.toInternal(node);
|
|
124
|
+
groupRows.push([name, createGroupPreview(children, previewWidth)]);
|
|
125
|
+
} else {
|
|
126
|
+
const { name, command: cmd } = InternalCommandNode.OpaqueCommandLeafNode.toInternal(node);
|
|
127
|
+
commandRows.push([name, cmd.description]);
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
if (includeHelpCommand) {
|
|
131
|
+
commandRows.push(["help", "Display help for command"]);
|
|
132
|
+
}
|
|
133
|
+
for (const rows of [groupRows, commandRows]) {
|
|
134
|
+
rows.sort(([a], [b]) => a.localeCompare(b, "en"));
|
|
135
|
+
}
|
|
82
136
|
return {
|
|
83
137
|
version,
|
|
84
138
|
render(nodesToRender, renderers) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
139
|
+
return renderers.render(
|
|
140
|
+
nodesToRender.flatMap((node) => {
|
|
141
|
+
if (node.id !== "commands") {
|
|
142
|
+
return [node];
|
|
143
|
+
}
|
|
144
|
+
return [
|
|
145
|
+
{ title: "Groups:", rows: groupRows },
|
|
146
|
+
{ title: "Commands:", rows: commandRows }
|
|
147
|
+
].filter((section) => section.rows.length > 0).map(
|
|
148
|
+
({ title, rows }) => ({
|
|
149
|
+
type: "section",
|
|
150
|
+
data: {
|
|
151
|
+
title,
|
|
152
|
+
indentBody: 0,
|
|
153
|
+
body: {
|
|
154
|
+
type: "table",
|
|
155
|
+
data: {
|
|
156
|
+
tableData: rows,
|
|
157
|
+
tableOptions: [
|
|
158
|
+
{
|
|
159
|
+
width: "content-width",
|
|
160
|
+
paddingLeft: 2,
|
|
161
|
+
paddingRight: 8
|
|
162
|
+
}
|
|
163
|
+
]
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
})
|
|
168
|
+
);
|
|
169
|
+
})
|
|
170
|
+
);
|
|
97
171
|
}
|
|
98
172
|
};
|
|
99
173
|
}
|
|
@@ -139,6 +213,7 @@ async function runCommandLevel(options) {
|
|
|
139
213
|
commandArgs,
|
|
140
214
|
programName
|
|
141
215
|
);
|
|
216
|
+
await flushStdio();
|
|
142
217
|
process.exit(0);
|
|
143
218
|
}
|
|
144
219
|
} catch (error) {
|
|
@@ -192,6 +267,7 @@ async function runCommandLevel(options) {
|
|
|
192
267
|
return;
|
|
193
268
|
}
|
|
194
269
|
if (argv.length === 0) {
|
|
270
|
+
parsed.showHelp();
|
|
195
271
|
return;
|
|
196
272
|
}
|
|
197
273
|
console.log();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runCli.cjs.js","sources":["../../src/cli-module/runCli.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n OpaqueCliModule,\n OpaqueCommandLeafNode,\n OpaqueCommandTreeNode,\n isCommandNodeHidden,\n} from '@internal/cli';\nimport type { CommandNode } from '@internal/cli';\nimport { ForwardedError, isError, stringifyError } from '@backstage/errors';\nimport chalk from 'chalk';\nimport { cli, command } from 'cleye';\nimport type { Renderers } from 'cleye';\nimport { CommandGraph } from './CommandGraph';\nimport type { CliCommand, CliModule } from './types';\n\ninterface HelpNode {\n id?: string;\n type: keyof Renderers;\n data: unknown;\n}\n\ninterface CommandsHelpData {\n body: {\n data: {\n tableData: string[][];\n };\n };\n}\n\nfunction exit(message: string, code: number = 1): never {\n process.stderr.write(`\\n${chalk.red(message)}\\n\\n`);\n process.exit(code);\n}\n\nfunction exitWithError(error: unknown): never {\n if (!isError(error)) {\n return exit(stringifyError(error));\n }\n\n switch (error.name) {\n case 'InputError':\n return exit(error.message, 74 /* input/output error */);\n case 'NotFoundError':\n return exit(error.message, 127 /* command not found */);\n case 'NotImplementedError':\n return exit(error.message, 64 /* command line usage error */);\n case 'AuthenticationError':\n case 'NotAllowedError':\n return exit(error.message, 77 /* permission denied */);\n case 'ExitCodeError':\n return exit(\n error.message,\n 'code' in error && typeof error.code === 'number' ? error.code : 1,\n );\n default:\n return exit(\n stringifyError(error),\n 'code' in error && typeof error.code === 'number' ? error.code : 1,\n );\n }\n}\n\nfunction getNodeName(node: CommandNode): string {\n if (OpaqueCommandTreeNode.isType(node)) {\n return OpaqueCommandTreeNode.toInternal(node).name;\n }\n return OpaqueCommandLeafNode.toInternal(node).name;\n}\n\nfunction getNodeDescription(node: CommandNode): string {\n if (OpaqueCommandTreeNode.isType(node)) {\n return OpaqueCommandTreeNode.toInternal(node).name;\n }\n return OpaqueCommandLeafNode.toInternal(node).command.description;\n}\n\nfunction createHelpOptions(options: {\n nodes: ReadonlyArray<CommandNode>;\n includeHelpCommand: boolean;\n version?: string;\n}) {\n const { nodes, includeHelpCommand, version } = options;\n const visibleNodes = nodes.filter(node => !isCommandNodeHidden(node));\n\n return {\n version,\n render(nodesToRender: HelpNode[], renderers: Renderers) {\n const commandsNode = nodesToRender.find(node => node.id === 'commands');\n if (commandsNode) {\n const commandRows = visibleNodes.map(node => [\n getNodeName(node),\n getNodeDescription(node),\n ]);\n if (includeHelpCommand) {\n commandRows.push(['help', 'Display help for command']);\n }\n (commandsNode.data as CommandsHelpData).body.data.tableData =\n commandRows;\n }\n return renderers.render(nodesToRender);\n },\n };\n}\n\nasync function executeCommand(\n commandToExecute: CliCommand,\n args: string[],\n programName: string,\n): Promise<void> {\n const context = {\n args,\n info: {\n usage: [programName, ...commandToExecute.path].join(' '),\n name: commandToExecute.path.join(' '),\n },\n };\n\n if (typeof commandToExecute.execute === 'function') {\n await commandToExecute.execute(context);\n } else {\n const mod = await commandToExecute.execute.loader();\n const fn =\n typeof mod.default === 'function'\n ? mod.default\n : (mod.default as any).default;\n await fn(context);\n }\n}\n\nasync function runCommandLevel(options: {\n nodes: ReadonlyArray<CommandNode>;\n argv: string[];\n programName: string;\n commandPath?: string[];\n version?: string;\n}): Promise<void> {\n const { nodes, argv, programName, commandPath = [], version } = options;\n const name = [programName, ...commandPath].join(' ');\n const commandArgs = argv.slice(1);\n const commands = nodes.map(node =>\n command(\n {\n name: getNodeName(node),\n help: false,\n },\n async () => {\n try {\n if (OpaqueCommandTreeNode.isType(node)) {\n await runCommandLevel({\n nodes: OpaqueCommandTreeNode.toInternal(node).children,\n argv: commandArgs,\n programName,\n commandPath: [...commandPath, getNodeName(node)],\n version,\n });\n } else {\n await executeCommand(\n OpaqueCommandLeafNode.toInternal(node).command,\n commandArgs,\n programName,\n );\n process.exit(0);\n }\n } catch (error: unknown) {\n exitWithError(error);\n }\n },\n ),\n );\n const includeHelpCommand = !nodes.some(node => getNodeName(node) === 'help');\n if (includeHelpCommand && nodes.length > 0) {\n commands.push(\n command(\n {\n name: 'help',\n parameters: ['[command...]'],\n help: false,\n },\n async () => {\n await runCommandLevel({\n nodes,\n argv: [...commandArgs, '--help'],\n programName,\n commandPath,\n version,\n });\n },\n ),\n );\n }\n\n await cli(\n {\n name,\n flags: version\n ? {\n version: {\n type: Boolean,\n alias: 'V',\n description: 'Show version',\n },\n }\n : undefined,\n commands,\n help: createHelpOptions({\n nodes,\n includeHelpCommand: includeHelpCommand && nodes.length > 0,\n version,\n }),\n },\n parsed => {\n if (version && parsed.flags.version) {\n console.log(version);\n process.exit(0);\n return;\n }\n\n if (argv.length === 0) {\n return;\n }\n\n console.log();\n console.log(\n chalk.red(`Invalid command: ${[...commandPath, ...argv].join(' ')}`),\n );\n console.log();\n parsed.showHelp();\n process.exit(1);\n },\n [...argv],\n );\n}\n\nfunction handleUnhandledRejection(rejection: unknown): void {\n exitWithError(new ForwardedError('Unhandled rejection', rejection));\n}\n\nfunction hasVersionFlag(args: string[]): boolean {\n const separatorIndex = args.indexOf('--');\n const options = separatorIndex === -1 ? args : args.slice(0, separatorIndex);\n return options.includes('-V') || options.includes('--version');\n}\n\n/**\n * Runs a collection of CLI modules as an executable program.\n *\n * This is intended for creating custom CLI packages from a fixed set of\n * directly imported modules. Module discovery and override behavior are left\n * to the caller.\n *\n * @example\n * ```ts\n * import { runCli } from '@backstage/cli-node';\n * import buildModule from '@backstage/cli-module-build';\n * import testModule from '@backstage/cli-module-test-jest';\n * import packageJson from '../package.json';\n *\n * runCli({\n * modules: [buildModule, testModule],\n * name: packageJson.name,\n * version: packageJson.version,\n * });\n * ```\n *\n * @public\n */\nexport async function runCli(options: {\n /** The CLI modules whose commands are included in the program. */\n modules: ReadonlyArray<CliModule>;\n /** The program name shown in help output and usage strings. */\n name: string;\n /** The version string shown when `--version` is passed. */\n version?: string;\n}): Promise<void> {\n const { modules, name, version } = options;\n const graph = new CommandGraph();\n\n for (const module of modules) {\n if (!OpaqueCliModule.isType(module)) {\n throw new Error(\n `Invalid CLI module: expected a module created with createCliModule`,\n );\n }\n\n for (const commandToAdd of await OpaqueCliModule.toInternal(module)\n .commands) {\n graph.add(commandToAdd, module);\n }\n }\n\n if (\n !process.listeners('unhandledRejection').includes(handleUnhandledRejection)\n ) {\n process.on('unhandledRejection', handleUnhandledRejection);\n }\n\n const args = process.argv.slice(2);\n if (version && hasVersionFlag(args)) {\n console.log(version);\n process.exit(0);\n return;\n }\n\n await runCommandLevel({\n nodes: graph.roots,\n argv: args,\n programName: name,\n version,\n });\n}\n"],"names":["chalk","isError","stringifyError","OpaqueCommandTreeNode","OpaqueCommandLeafNode","isCommandNodeHidden","command","cli","ForwardedError","CommandGraph","OpaqueCliModule"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"runCli.cjs.js","sources":["../../src/cli-module/runCli.ts"],"sourcesContent":["/*\n * Copyright 2026 The Backstage Authors\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport {\n OpaqueCliModule,\n OpaqueCommandLeafNode,\n OpaqueCommandTreeNode,\n isCommandNodeHidden,\n} from '@internal/cli';\nimport type { CommandNode } from '@internal/cli';\nimport { ForwardedError, isError, stringifyError } from '@backstage/errors';\nimport chalk from 'chalk';\nimport { cli, command } from 'cleye';\nimport type { Renderers } from 'cleye';\nimport { CommandGraph } from './CommandGraph';\nimport type { CliCommand, CliModule } from './types';\n\ninterface HelpNode {\n id?: string;\n type: keyof Renderers;\n data: unknown;\n}\n\nfunction exit(message: string, code: number = 1): never {\n process.stderr.write(`\\n${chalk.red(message)}\\n\\n`);\n process.exit(code);\n}\n\n/**\n * Waits for any output queued on stdout and stderr to be handed off to the OS.\n * Depending on the platform and stream type (e.g. pipes on macOS), these writes\n * can be asynchronous, so exiting immediately after a large write can truncate\n * the output.\n */\nasync function flushStdio(): Promise<void> {\n await Promise.all(\n [process.stdout, process.stderr].map(\n stream => new Promise<void>(resolve => stream.write('', () => resolve())),\n ),\n );\n}\n\nfunction exitWithError(error: unknown): never {\n if (!isError(error)) {\n return exit(stringifyError(error));\n }\n\n switch (error.name) {\n case 'InputError':\n return exit(error.message, 74 /* input/output error */);\n case 'NotFoundError':\n return exit(error.message, 127 /* command not found */);\n case 'NotImplementedError':\n return exit(error.message, 64 /* command line usage error */);\n case 'AuthenticationError':\n case 'NotAllowedError':\n return exit(error.message, 77 /* permission denied */);\n case 'ExitCodeError':\n return exit(\n error.message,\n 'code' in error && typeof error.code === 'number' ? error.code : 1,\n );\n default:\n return exit(\n stringifyError(error),\n 'code' in error && typeof error.code === 'number' ? error.code : 1,\n );\n }\n}\n\nfunction getNodeName(node: CommandNode): string {\n if (OpaqueCommandTreeNode.isType(node)) {\n return OpaqueCommandTreeNode.toInternal(node).name;\n }\n return OpaqueCommandLeafNode.toInternal(node).name;\n}\n\nfunction createGroupPreview(\n children: ReadonlyArray<CommandNode>,\n width: number,\n): string {\n const entries = children\n .filter(node => !isCommandNodeHidden(node))\n .sort((a, b) => getNodeName(a).localeCompare(getNodeName(b), 'en'))\n .map(node => ({ node, path: getNodeName(node) }));\n const format = (items: typeof entries) =>\n items\n .map(\n ({ node, path }) =>\n path + (OpaqueCommandTreeNode.isType(node) ? '/' : ''),\n )\n .join(', ');\n\n if (format(entries).length > width) {\n while (entries.length > 0) {\n entries.pop();\n const preview = format(entries);\n if (preview.length + 3 <= width) {\n return preview ? `${preview}, …` : '…';\n }\n }\n return '…';\n }\n\n // Expand breadth-first, preserving every sibling before adding more detail.\n const queue = [...entries];\n for (const entry of queue) {\n if (!OpaqueCommandTreeNode.isType(entry.node)) {\n continue;\n }\n const expanded = OpaqueCommandTreeNode.toInternal(entry.node)\n .children.filter(node => !isCommandNodeHidden(node))\n .sort((a, b) => getNodeName(a).localeCompare(getNodeName(b), 'en'))\n .map(node => ({ node, path: `${entry.path} ${getNodeName(node)}` }));\n const index = entries.indexOf(entry);\n const candidate = [...entries];\n candidate.splice(index, 1, ...expanded);\n if (format(candidate).length <= width) {\n entries.splice(index, 1, ...expanded);\n queue.push(...expanded);\n }\n }\n return format(entries);\n}\n\nfunction createHelpOptions(options: {\n nodes: ReadonlyArray<CommandNode>;\n includeHelpCommand: boolean;\n version?: string;\n}) {\n const { nodes, includeHelpCommand, version } = options;\n const visibleNodes = nodes.filter(node => !isCommandNodeHidden(node));\n const groups = visibleNodes.filter(OpaqueCommandTreeNode.isType);\n // Match the table's name column and padding, with 80 columns for piped output.\n const previewWidth = Math.max(\n 1,\n (process.stdout.columns || 80) -\n Math.max(0, ...groups.map(node => getNodeName(node).length)) -\n 10,\n );\n const groupRows: string[][] = [];\n const commandRows: string[][] = [];\n\n for (const node of visibleNodes) {\n if (OpaqueCommandTreeNode.isType(node)) {\n const { name, children } = OpaqueCommandTreeNode.toInternal(node);\n groupRows.push([name, createGroupPreview(children, previewWidth)]);\n } else {\n const { name, command: cmd } = OpaqueCommandLeafNode.toInternal(node);\n commandRows.push([name, cmd.description]);\n }\n }\n if (includeHelpCommand) {\n commandRows.push(['help', 'Display help for command']);\n }\n for (const rows of [groupRows, commandRows]) {\n rows.sort(([a], [b]) => a.localeCompare(b, 'en'));\n }\n\n return {\n version,\n render(nodesToRender: HelpNode[], renderers: Renderers) {\n return renderers.render(\n nodesToRender.flatMap(node => {\n if (node.id !== 'commands') {\n return [node];\n }\n return [\n { title: 'Groups:', rows: groupRows },\n { title: 'Commands:', rows: commandRows },\n ]\n .filter(section => section.rows.length > 0)\n .map(\n ({ title, rows }): HelpNode => ({\n type: 'section',\n data: {\n title,\n indentBody: 0,\n body: {\n type: 'table',\n data: {\n tableData: rows,\n tableOptions: [\n {\n width: 'content-width',\n paddingLeft: 2,\n paddingRight: 8,\n },\n ],\n },\n },\n },\n }),\n );\n }),\n );\n },\n };\n}\n\nasync function executeCommand(\n commandToExecute: CliCommand,\n args: string[],\n programName: string,\n): Promise<void> {\n const context = {\n args,\n info: {\n usage: [programName, ...commandToExecute.path].join(' '),\n name: commandToExecute.path.join(' '),\n },\n };\n\n if (typeof commandToExecute.execute === 'function') {\n await commandToExecute.execute(context);\n } else {\n const mod = await commandToExecute.execute.loader();\n const fn =\n typeof mod.default === 'function'\n ? mod.default\n : (mod.default as any).default;\n await fn(context);\n }\n}\n\nasync function runCommandLevel(options: {\n nodes: ReadonlyArray<CommandNode>;\n argv: string[];\n programName: string;\n commandPath?: string[];\n version?: string;\n}): Promise<void> {\n const { nodes, argv, programName, commandPath = [], version } = options;\n const name = [programName, ...commandPath].join(' ');\n const commandArgs = argv.slice(1);\n const commands = nodes.map(node =>\n command(\n {\n name: getNodeName(node),\n help: false,\n },\n async () => {\n try {\n if (OpaqueCommandTreeNode.isType(node)) {\n await runCommandLevel({\n nodes: OpaqueCommandTreeNode.toInternal(node).children,\n argv: commandArgs,\n programName,\n commandPath: [...commandPath, getNodeName(node)],\n version,\n });\n } else {\n await executeCommand(\n OpaqueCommandLeafNode.toInternal(node).command,\n commandArgs,\n programName,\n );\n await flushStdio();\n process.exit(0);\n }\n } catch (error: unknown) {\n exitWithError(error);\n }\n },\n ),\n );\n const includeHelpCommand = !nodes.some(node => getNodeName(node) === 'help');\n if (includeHelpCommand && nodes.length > 0) {\n commands.push(\n command(\n {\n name: 'help',\n parameters: ['[command...]'],\n help: false,\n },\n async () => {\n await runCommandLevel({\n nodes,\n argv: [...commandArgs, '--help'],\n programName,\n commandPath,\n version,\n });\n },\n ),\n );\n }\n\n await cli(\n {\n name,\n flags: version\n ? {\n version: {\n type: Boolean,\n alias: 'V',\n description: 'Show version',\n },\n }\n : undefined,\n commands,\n help: createHelpOptions({\n nodes,\n includeHelpCommand: includeHelpCommand && nodes.length > 0,\n version,\n }),\n },\n parsed => {\n if (version && parsed.flags.version) {\n console.log(version);\n process.exit(0);\n return;\n }\n\n if (argv.length === 0) {\n parsed.showHelp();\n return;\n }\n\n console.log();\n console.log(\n chalk.red(`Invalid command: ${[...commandPath, ...argv].join(' ')}`),\n );\n console.log();\n parsed.showHelp();\n process.exit(1);\n },\n [...argv],\n );\n}\n\nfunction handleUnhandledRejection(rejection: unknown): void {\n exitWithError(new ForwardedError('Unhandled rejection', rejection));\n}\n\nfunction hasVersionFlag(args: string[]): boolean {\n const separatorIndex = args.indexOf('--');\n const options = separatorIndex === -1 ? args : args.slice(0, separatorIndex);\n return options.includes('-V') || options.includes('--version');\n}\n\n/**\n * Runs a collection of CLI modules as an executable program.\n *\n * This is intended for creating custom CLI packages from a fixed set of\n * directly imported modules. Module discovery and override behavior are left\n * to the caller.\n *\n * Invoking the program or a command group without a subcommand displays\n * help for that level and completes successfully. Command groups and commands\n * are listed separately in alphabetical order. Group previews fit the terminal width\n * (80 columns when unavailable), expanding nested groups breadth-first when space\n * permits. Unexpanded groups have a trailing slash; truncated previews end in an ellipsis.\n *\n * @example\n * ```ts\n * import { runCli } from '@backstage/cli-node';\n * import buildModule from '@backstage/cli-module-build';\n * import testModule from '@backstage/cli-module-test-jest';\n * import packageJson from '../package.json';\n *\n * runCli({\n * modules: [buildModule, testModule],\n * name: packageJson.name,\n * version: packageJson.version,\n * });\n * ```\n *\n * @public\n */\nexport async function runCli(options: {\n /** The CLI modules whose commands are included in the program. */\n modules: ReadonlyArray<CliModule>;\n /** The program name shown in help output and usage strings. */\n name: string;\n /** The version string shown when `--version` is passed. */\n version?: string;\n}): Promise<void> {\n const { modules, name, version } = options;\n const graph = new CommandGraph();\n\n for (const module of modules) {\n if (!OpaqueCliModule.isType(module)) {\n throw new Error(\n `Invalid CLI module: expected a module created with createCliModule`,\n );\n }\n\n for (const commandToAdd of await OpaqueCliModule.toInternal(module)\n .commands) {\n graph.add(commandToAdd, module);\n }\n }\n\n if (\n !process.listeners('unhandledRejection').includes(handleUnhandledRejection)\n ) {\n process.on('unhandledRejection', handleUnhandledRejection);\n }\n\n const args = process.argv.slice(2);\n if (version && hasVersionFlag(args)) {\n console.log(version);\n process.exit(0);\n return;\n }\n\n await runCommandLevel({\n nodes: graph.roots,\n argv: args,\n programName: name,\n version,\n });\n}\n"],"names":["chalk","isError","stringifyError","OpaqueCommandTreeNode","OpaqueCommandLeafNode","isCommandNodeHidden","command","cli","ForwardedError","CommandGraph","OpaqueCliModule"],"mappings":";;;;;;;;;;;;;;;;;AAoCA,SAAS,IAAA,CAAK,OAAA,EAAiB,IAAA,GAAe,CAAA,EAAU;AACtD,EAAA,OAAA,CAAQ,OAAO,KAAA,CAAM;AAAA,EAAKA,sBAAA,CAAM,GAAA,CAAI,OAAO,CAAC;;AAAA,CAAM,CAAA;AAClD,EAAA,OAAA,CAAQ,KAAK,IAAI,CAAA;AACnB;AAQA,eAAe,UAAA,GAA4B;AACzC,EAAA,MAAM,OAAA,CAAQ,GAAA;AAAA,IACZ,CAAC,OAAA,CAAQ,MAAA,EAAQ,OAAA,CAAQ,MAAM,CAAA,CAAE,GAAA;AAAA,MAC/B,CAAA,MAAA,KAAU,IAAI,OAAA,CAAc,CAAA,OAAA,KAAW,MAAA,CAAO,MAAM,EAAA,EAAI,MAAM,OAAA,EAAS,CAAC;AAAA;AAC1E,GACF;AACF;AAEA,SAAS,cAAc,KAAA,EAAuB;AAC5C,EAAA,IAAI,CAACC,cAAA,CAAQ,KAAK,CAAA,EAAG;AACnB,IAAA,OAAO,IAAA,CAAKC,qBAAA,CAAe,KAAK,CAAC,CAAA;AAAA,EACnC;AAEA,EAAA,QAAQ,MAAM,IAAA;AAAM,IAClB,KAAK,YAAA;AACH,MAAA,OAAO,IAAA;AAAA,QAAK,KAAA,CAAM,OAAA;AAAA,QAAS;AAAA;AAAA,OAA2B;AAAA,IACxD,KAAK,eAAA;AACH,MAAA,OAAO,IAAA;AAAA,QAAK,KAAA,CAAM,OAAA;AAAA,QAAS;AAAA;AAAA,OAA2B;AAAA,IACxD,KAAK,qBAAA;AACH,MAAA,OAAO,IAAA;AAAA,QAAK,KAAA,CAAM,OAAA;AAAA,QAAS;AAAA;AAAA,OAAiC;AAAA,IAC9D,KAAK,qBAAA;AAAA,IACL,KAAK,iBAAA;AACH,MAAA,OAAO,IAAA;AAAA,QAAK,KAAA,CAAM,OAAA;AAAA,QAAS;AAAA;AAAA,OAA0B;AAAA,IACvD,KAAK,eAAA;AACH,MAAA,OAAO,IAAA;AAAA,QACL,KAAA,CAAM,OAAA;AAAA,QACN,UAAU,KAAA,IAAS,OAAO,MAAM,IAAA,KAAS,QAAA,GAAW,MAAM,IAAA,GAAO;AAAA,OACnE;AAAA,IACF;AACE,MAAA,OAAO,IAAA;AAAA,QACLA,sBAAe,KAAK,CAAA;AAAA,QACpB,UAAU,KAAA,IAAS,OAAO,MAAM,IAAA,KAAS,QAAA,GAAW,MAAM,IAAA,GAAO;AAAA,OACnE;AAAA;AAEN;AAEA,SAAS,YAAY,IAAA,EAA2B;AAC9C,EAAA,IAAIC,yCAAA,CAAsB,MAAA,CAAO,IAAI,CAAA,EAAG;AACtC,IAAA,OAAOA,yCAAA,CAAsB,UAAA,CAAW,IAAI,CAAA,CAAE,IAAA;AAAA,EAChD;AACA,EAAA,OAAOC,yCAAA,CAAsB,UAAA,CAAW,IAAI,CAAA,CAAE,IAAA;AAChD;AAEA,SAAS,kBAAA,CACP,UACA,KAAA,EACQ;AACR,EAAA,MAAM,OAAA,GAAU,QAAA,CACb,MAAA,CAAO,CAAA,IAAA,KAAQ,CAACC,uCAAA,CAAoB,IAAI,CAAC,CAAA,CACzC,IAAA,CAAK,CAAC,CAAA,EAAG,MAAM,WAAA,CAAY,CAAC,CAAA,CAAE,aAAA,CAAc,WAAA,CAAY,CAAC,CAAA,EAAG,IAAI,CAAC,CAAA,CACjE,GAAA,CAAI,CAAA,IAAA,MAAS,EAAE,IAAA,EAAM,IAAA,EAAM,WAAA,CAAY,IAAI,GAAE,CAAE,CAAA;AAClD,EAAA,MAAM,MAAA,GAAS,CAAC,KAAA,KACd,KAAA,CACG,GAAA;AAAA,IACC,CAAC,EAAE,IAAA,EAAM,IAAA,EAAK,KACZ,QAAQF,yCAAA,CAAsB,MAAA,CAAO,IAAI,CAAA,GAAI,GAAA,GAAM,EAAA;AAAA,GACvD,CACC,KAAK,IAAI,CAAA;AAEd,EAAA,IAAI,MAAA,CAAO,OAAO,CAAA,CAAE,MAAA,GAAS,KAAA,EAAO;AAClC,IAAA,OAAO,OAAA,CAAQ,SAAS,CAAA,EAAG;AACzB,MAAA,OAAA,CAAQ,GAAA,EAAI;AACZ,MAAA,MAAM,OAAA,GAAU,OAAO,OAAO,CAAA;AAC9B,MAAA,IAAI,OAAA,CAAQ,MAAA,GAAS,CAAA,IAAK,KAAA,EAAO;AAC/B,QAAA,OAAO,OAAA,GAAU,CAAA,EAAG,OAAO,CAAA,QAAA,CAAA,GAAQ,QAAA;AAAA,MACrC;AAAA,IACF;AACA,IAAA,OAAO,QAAA;AAAA,EACT;AAGA,EAAA,MAAM,KAAA,GAAQ,CAAC,GAAG,OAAO,CAAA;AACzB,EAAA,KAAA,MAAW,SAAS,KAAA,EAAO;AACzB,IAAA,IAAI,CAACA,yCAAA,CAAsB,MAAA,CAAO,KAAA,CAAM,IAAI,CAAA,EAAG;AAC7C,MAAA;AAAA,IACF;AACA,IAAA,MAAM,WAAWA,yCAAA,CAAsB,UAAA,CAAW,MAAM,IAAI,CAAA,CACzD,SAAS,MAAA,CAAO,CAAA,IAAA,KAAQ,CAACE,uCAAA,CAAoB,IAAI,CAAC,CAAA,CAClD,KAAK,CAAC,CAAA,EAAG,MAAM,WAAA,CAAY,CAAC,CAAA,CAAE,aAAA,CAAc,YAAY,CAAC,CAAA,EAAG,IAAI,CAAC,CAAA,CACjE,IAAI,CAAA,IAAA,MAAS,EAAE,MAAM,IAAA,EAAM,CAAA,EAAG,MAAM,IAAI,CAAA,CAAA,EAAI,YAAY,IAAI,CAAC,IAAG,CAAE,CAAA;AACrE,IAAA,MAAM,KAAA,GAAQ,OAAA,CAAQ,OAAA,CAAQ,KAAK,CAAA;AACnC,IAAA,MAAM,SAAA,GAAY,CAAC,GAAG,OAAO,CAAA;AAC7B,IAAA,SAAA,CAAU,MAAA,CAAO,KAAA,EAAO,CAAA,EAAG,GAAG,QAAQ,CAAA;AACtC,IAAA,IAAI,MAAA,CAAO,SAAS,CAAA,CAAE,MAAA,IAAU,KAAA,EAAO;AACrC,MAAA,OAAA,CAAQ,MAAA,CAAO,KAAA,EAAO,CAAA,EAAG,GAAG,QAAQ,CAAA;AACpC,MAAA,KAAA,CAAM,IAAA,CAAK,GAAG,QAAQ,CAAA;AAAA,IACxB;AAAA,EACF;AACA,EAAA,OAAO,OAAO,OAAO,CAAA;AACvB;AAEA,SAAS,kBAAkB,OAAA,EAIxB;AACD,EAAA,MAAM,EAAE,KAAA,EAAO,kBAAA,EAAoB,OAAA,EAAQ,GAAI,OAAA;AAC/C,EAAA,MAAM,eAAe,KAAA,CAAM,MAAA,CAAO,UAAQ,CAACA,uCAAA,CAAoB,IAAI,CAAC,CAAA;AACpE,EAAA,MAAM,MAAA,GAAS,YAAA,CAAa,MAAA,CAAOF,yCAAA,CAAsB,MAAM,CAAA;AAE/D,EAAA,MAAM,eAAe,IAAA,CAAK,GAAA;AAAA,IACxB,CAAA;AAAA,IAAA,CACC,QAAQ,MAAA,CAAO,OAAA,IAAW,EAAA,IACzB,IAAA,CAAK,IAAI,CAAA,EAAG,GAAG,MAAA,CAAO,GAAA,CAAI,UAAQ,WAAA,CAAY,IAAI,CAAA,CAAE,MAAM,CAAC,CAAA,GAC3D;AAAA,GACJ;AACA,EAAA,MAAM,YAAwB,EAAC;AAC/B,EAAA,MAAM,cAA0B,EAAC;AAEjC,EAAA,KAAA,MAAW,QAAQ,YAAA,EAAc;AAC/B,IAAA,IAAIA,yCAAA,CAAsB,MAAA,CAAO,IAAI,CAAA,EAAG;AACtC,MAAA,MAAM,EAAE,IAAA,EAAM,QAAA,EAAS,GAAIA,yCAAA,CAAsB,WAAW,IAAI,CAAA;AAChE,MAAA,SAAA,CAAU,KAAK,CAAC,IAAA,EAAM,mBAAmB,QAAA,EAAU,YAAY,CAAC,CAAC,CAAA;AAAA,IACnE,CAAA,MAAO;AACL,MAAA,MAAM,EAAE,IAAA,EAAM,OAAA,EAAS,KAAI,GAAIC,yCAAA,CAAsB,WAAW,IAAI,CAAA;AACpE,MAAA,WAAA,CAAY,IAAA,CAAK,CAAC,IAAA,EAAM,GAAA,CAAI,WAAW,CAAC,CAAA;AAAA,IAC1C;AAAA,EACF;AACA,EAAA,IAAI,kBAAA,EAAoB;AACtB,IAAA,WAAA,CAAY,IAAA,CAAK,CAAC,MAAA,EAAQ,0BAA0B,CAAC,CAAA;AAAA,EACvD;AACA,EAAA,KAAA,MAAW,IAAA,IAAQ,CAAC,SAAA,EAAW,WAAW,CAAA,EAAG;AAC3C,IAAA,IAAA,CAAK,IAAA,CAAK,CAAC,CAAC,CAAC,CAAA,EAAG,CAAC,CAAC,CAAA,KAAM,CAAA,CAAE,aAAA,CAAc,CAAA,EAAG,IAAI,CAAC,CAAA;AAAA,EAClD;AAEA,EAAA,OAAO;AAAA,IACL,OAAA;AAAA,IACA,MAAA,CAAO,eAA2B,SAAA,EAAsB;AACtD,MAAA,OAAO,SAAA,CAAU,MAAA;AAAA,QACf,aAAA,CAAc,QAAQ,CAAA,IAAA,KAAQ;AAC5B,UAAA,IAAI,IAAA,CAAK,OAAO,UAAA,EAAY;AAC1B,YAAA,OAAO,CAAC,IAAI,CAAA;AAAA,UACd;AACA,UAAA,OAAO;AAAA,YACL,EAAE,KAAA,EAAO,SAAA,EAAW,IAAA,EAAM,SAAA,EAAU;AAAA,YACpC,EAAE,KAAA,EAAO,WAAA,EAAa,IAAA,EAAM,WAAA;AAAY,YAEvC,MAAA,CAAO,CAAA,OAAA,KAAW,QAAQ,IAAA,CAAK,MAAA,GAAS,CAAC,CAAA,CACzC,GAAA;AAAA,YACC,CAAC,EAAE,KAAA,EAAO,IAAA,EAAK,MAAiB;AAAA,cAC9B,IAAA,EAAM,SAAA;AAAA,cACN,IAAA,EAAM;AAAA,gBACJ,KAAA;AAAA,gBACA,UAAA,EAAY,CAAA;AAAA,gBACZ,IAAA,EAAM;AAAA,kBACJ,IAAA,EAAM,OAAA;AAAA,kBACN,IAAA,EAAM;AAAA,oBACJ,SAAA,EAAW,IAAA;AAAA,oBACX,YAAA,EAAc;AAAA,sBACZ;AAAA,wBACE,KAAA,EAAO,eAAA;AAAA,wBACP,WAAA,EAAa,CAAA;AAAA,wBACb,YAAA,EAAc;AAAA;AAChB;AACF;AACF;AACF;AACF,aACF;AAAA,WACF;AAAA,QACJ,CAAC;AAAA,OACH;AAAA,IACF;AAAA,GACF;AACF;AAEA,eAAe,cAAA,CACb,gBAAA,EACA,IAAA,EACA,WAAA,EACe;AACf,EAAA,MAAM,OAAA,GAAU;AAAA,IACd,IAAA;AAAA,IACA,IAAA,EAAM;AAAA,MACJ,KAAA,EAAO,CAAC,WAAA,EAAa,GAAG,iBAAiB,IAAI,CAAA,CAAE,KAAK,GAAG,CAAA;AAAA,MACvD,IAAA,EAAM,gBAAA,CAAiB,IAAA,CAAK,IAAA,CAAK,GAAG;AAAA;AACtC,GACF;AAEA,EAAA,IAAI,OAAO,gBAAA,CAAiB,OAAA,KAAY,UAAA,EAAY;AAClD,IAAA,MAAM,gBAAA,CAAiB,QAAQ,OAAO,CAAA;AAAA,EACxC,CAAA,MAAO;AACL,IAAA,MAAM,GAAA,GAAM,MAAM,gBAAA,CAAiB,OAAA,CAAQ,MAAA,EAAO;AAClD,IAAA,MAAM,EAAA,GACJ,OAAO,GAAA,CAAI,OAAA,KAAY,aACnB,GAAA,CAAI,OAAA,GACH,IAAI,OAAA,CAAgB,OAAA;AAC3B,IAAA,MAAM,GAAG,OAAO,CAAA;AAAA,EAClB;AACF;AAEA,eAAe,gBAAgB,OAAA,EAMb;AAChB,EAAA,MAAM,EAAE,OAAO,IAAA,EAAM,WAAA,EAAa,cAAc,EAAC,EAAG,SAAQ,GAAI,OAAA;AAChE,EAAA,MAAM,OAAO,CAAC,WAAA,EAAa,GAAG,WAAW,CAAA,CAAE,KAAK,GAAG,CAAA;AACnD,EAAA,MAAM,WAAA,GAAc,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA;AAChC,EAAA,MAAM,WAAW,KAAA,CAAM,GAAA;AAAA,IAAI,CAAA,IAAA,KACzBE,aAAA;AAAA,MACE;AAAA,QACE,IAAA,EAAM,YAAY,IAAI,CAAA;AAAA,QACtB,IAAA,EAAM;AAAA,OACR;AAAA,MACA,YAAY;AACV,QAAA,IAAI;AACF,UAAA,IAAIH,yCAAA,CAAsB,MAAA,CAAO,IAAI,CAAA,EAAG;AACtC,YAAA,MAAM,eAAA,CAAgB;AAAA,cACpB,KAAA,EAAOA,yCAAA,CAAsB,UAAA,CAAW,IAAI,CAAA,CAAE,QAAA;AAAA,cAC9C,IAAA,EAAM,WAAA;AAAA,cACN,WAAA;AAAA,cACA,aAAa,CAAC,GAAG,WAAA,EAAa,WAAA,CAAY,IAAI,CAAC,CAAA;AAAA,cAC/C;AAAA,aACD,CAAA;AAAA,UACH,CAAA,MAAO;AACL,YAAA,MAAM,cAAA;AAAA,cACJC,yCAAA,CAAsB,UAAA,CAAW,IAAI,CAAA,CAAE,OAAA;AAAA,cACvC,WAAA;AAAA,cACA;AAAA,aACF;AACA,YAAA,MAAM,UAAA,EAAW;AACjB,YAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,UAChB;AAAA,QACF,SAAS,KAAA,EAAgB;AACvB,UAAA,aAAA,CAAc,KAAK,CAAA;AAAA,QACrB;AAAA,MACF;AAAA;AACF,GACF;AACA,EAAA,MAAM,kBAAA,GAAqB,CAAC,KAAA,CAAM,IAAA,CAAK,UAAQ,WAAA,CAAY,IAAI,MAAM,MAAM,CAAA;AAC3E,EAAA,IAAI,kBAAA,IAAsB,KAAA,CAAM,MAAA,GAAS,CAAA,EAAG;AAC1C,IAAA,QAAA,CAAS,IAAA;AAAA,MACPE,aAAA;AAAA,QACE;AAAA,UACE,IAAA,EAAM,MAAA;AAAA,UACN,UAAA,EAAY,CAAC,cAAc,CAAA;AAAA,UAC3B,IAAA,EAAM;AAAA,SACR;AAAA,QACA,YAAY;AACV,UAAA,MAAM,eAAA,CAAgB;AAAA,YACpB,KAAA;AAAA,YACA,IAAA,EAAM,CAAC,GAAG,WAAA,EAAa,QAAQ,CAAA;AAAA,YAC/B,WAAA;AAAA,YACA,WAAA;AAAA,YACA;AAAA,WACD,CAAA;AAAA,QACH;AAAA;AACF,KACF;AAAA,EACF;AAEA,EAAA,MAAMC,SAAA;AAAA,IACJ;AAAA,MACE,IAAA;AAAA,MACA,OAAO,OAAA,GACH;AAAA,QACE,OAAA,EAAS;AAAA,UACP,IAAA,EAAM,OAAA;AAAA,UACN,KAAA,EAAO,GAAA;AAAA,UACP,WAAA,EAAa;AAAA;AACf,OACF,GACA,MAAA;AAAA,MACJ,QAAA;AAAA,MACA,MAAM,iBAAA,CAAkB;AAAA,QACtB,KAAA;AAAA,QACA,kBAAA,EAAoB,kBAAA,IAAsB,KAAA,CAAM,MAAA,GAAS,CAAA;AAAA,QACzD;AAAA,OACD;AAAA,KACH;AAAA,IACA,CAAA,MAAA,KAAU;AACR,MAAA,IAAI,OAAA,IAAW,MAAA,CAAO,KAAA,CAAM,OAAA,EAAS;AACnC,QAAA,OAAA,CAAQ,IAAI,OAAO,CAAA;AACnB,QAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AACd,QAAA;AAAA,MACF;AAEA,MAAA,IAAI,IAAA,CAAK,WAAW,CAAA,EAAG;AACrB,QAAA,MAAA,CAAO,QAAA,EAAS;AAChB,QAAA;AAAA,MACF;AAEA,MAAA,OAAA,CAAQ,GAAA,EAAI;AACZ,MAAA,OAAA,CAAQ,GAAA;AAAA,QACNP,sBAAA,CAAM,GAAA,CAAI,CAAA,iBAAA,EAAoB,CAAC,GAAG,WAAA,EAAa,GAAG,IAAI,CAAA,CAAE,IAAA,CAAK,GAAG,CAAC,CAAA,CAAE;AAAA,OACrE;AACA,MAAA,OAAA,CAAQ,GAAA,EAAI;AACZ,MAAA,MAAA,CAAO,QAAA,EAAS;AAChB,MAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AAAA,IAChB,CAAA;AAAA,IACA,CAAC,GAAG,IAAI;AAAA,GACV;AACF;AAEA,SAAS,yBAAyB,SAAA,EAA0B;AAC1D,EAAA,aAAA,CAAc,IAAIQ,qBAAA,CAAe,qBAAA,EAAuB,SAAS,CAAC,CAAA;AACpE;AAEA,SAAS,eAAe,IAAA,EAAyB;AAC/C,EAAA,MAAM,cAAA,GAAiB,IAAA,CAAK,OAAA,CAAQ,IAAI,CAAA;AACxC,EAAA,MAAM,UAAU,cAAA,KAAmB,EAAA,GAAK,OAAO,IAAA,CAAK,KAAA,CAAM,GAAG,cAAc,CAAA;AAC3E,EAAA,OAAO,QAAQ,QAAA,CAAS,IAAI,CAAA,IAAK,OAAA,CAAQ,SAAS,WAAW,CAAA;AAC/D;AA+BA,eAAsB,OAAO,OAAA,EAOX;AAChB,EAAA,MAAM,EAAE,OAAA,EAAS,IAAA,EAAM,OAAA,EAAQ,GAAI,OAAA;AACnC,EAAA,MAAM,KAAA,GAAQ,IAAIC,yBAAA,EAAa;AAE/B,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,IAAI,CAACC,iCAAA,CAAgB,MAAA,CAAO,MAAM,CAAA,EAAG;AACnC,MAAA,MAAM,IAAI,KAAA;AAAA,QACR,CAAA,kEAAA;AAAA,OACF;AAAA,IACF;AAEA,IAAA,KAAA,MAAW,gBAAgB,MAAMA,iCAAA,CAAgB,UAAA,CAAW,MAAM,EAC/D,QAAA,EAAU;AACX,MAAA,KAAA,CAAM,GAAA,CAAI,cAAc,MAAM,CAAA;AAAA,IAChC;AAAA,EACF;AAEA,EAAA,IACE,CAAC,OAAA,CAAQ,SAAA,CAAU,oBAAoB,CAAA,CAAE,QAAA,CAAS,wBAAwB,CAAA,EAC1E;AACA,IAAA,OAAA,CAAQ,EAAA,CAAG,sBAAsB,wBAAwB,CAAA;AAAA,EAC3D;AAEA,EAAA,MAAM,IAAA,GAAO,OAAA,CAAQ,IAAA,CAAK,KAAA,CAAM,CAAC,CAAA;AACjC,EAAA,IAAI,OAAA,IAAW,cAAA,CAAe,IAAI,CAAA,EAAG;AACnC,IAAA,OAAA,CAAQ,IAAI,OAAO,CAAA;AACnB,IAAA,OAAA,CAAQ,KAAK,CAAC,CAAA;AACd,IAAA;AAAA,EACF;AAEA,EAAA,MAAM,eAAA,CAAgB;AAAA,IACpB,OAAO,KAAA,CAAM,KAAA;AAAA,IACb,IAAA,EAAM,IAAA;AAAA,IACN,WAAA,EAAa,IAAA;AAAA,IACb;AAAA,GACD,CAAA;AACH;;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -221,6 +221,12 @@ declare function createCliModule(options: {
|
|
|
221
221
|
* directly imported modules. Module discovery and override behavior are left
|
|
222
222
|
* to the caller.
|
|
223
223
|
*
|
|
224
|
+
* Invoking the program or a command group without a subcommand displays
|
|
225
|
+
* help for that level and completes successfully. Command groups and commands
|
|
226
|
+
* are listed separately in alphabetical order. Group previews fit the terminal width
|
|
227
|
+
* (80 columns when unavailable), expanding nested groups breadth-first when space
|
|
228
|
+
* permits. Unexpanded groups have a trailing slash; truncated previews end in an ellipsis.
|
|
229
|
+
*
|
|
224
230
|
* @example
|
|
225
231
|
* ```ts
|
|
226
232
|
* import { runCli } from '@backstage/cli-node';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@backstage/cli-node",
|
|
3
|
-
"version": "0.3.5-next.
|
|
3
|
+
"version": "0.3.5-next.1",
|
|
4
4
|
"description": "Node.js library for Backstage CLIs",
|
|
5
5
|
"backstage": {
|
|
6
6
|
"role": "node-library"
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"zod": "^3.25.76 || ^4.0.0"
|
|
49
49
|
},
|
|
50
50
|
"devDependencies": {
|
|
51
|
-
"@backstage/backend-test-utils": "1.11.8-next.
|
|
51
|
+
"@backstage/backend-test-utils": "1.11.8-next.1",
|
|
52
52
|
"@backstage/cli": "0.36.7-next.0",
|
|
53
53
|
"@backstage/test-utils": "1.7.23-next.0",
|
|
54
54
|
"@types/proper-lockfile": "^4",
|