argsbarg 3.6.4 → 4.0.0
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 +28 -2
- package/README.md +21 -9
- package/docs/README.md +12 -8
- package/docs/bundled-docs.md +1 -1
- package/docs/cli-program.md +62 -2
- package/docs/config-schema.md +192 -0
- package/docs/developing.md +13 -0
- package/docs/install.md +38 -1
- package/docs/mcp.md +43 -19
- package/docs/output-schema.md +74 -52
- package/docs/templates/cursor/rules/cli-program.mdc +10 -5
- package/examples/config-app/main.ts +20 -0
- package/examples/config-app/program.ts +81 -0
- package/examples/config-app/schema.ts +37 -0
- package/examples/config-app/types.ts +19 -0
- package/examples/consumer-app/README.md +56 -0
- package/examples/consumer-app/bun.lock +75 -0
- package/examples/consumer-app/capabilities.test.ts +69 -0
- package/examples/consumer-app/package.json +17 -0
- package/examples/consumer-app/schemas/configSchemas.ts +6 -0
- package/examples/consumer-app/schemas/generated/app-config.json +40 -0
- package/examples/consumer-app/schemas/generated/status.json +28 -0
- package/examples/consumer-app/schemas/outputSchemas.ts +6 -0
- package/examples/consumer-app/scripts/schemagen/discover-schema-roots.test.ts +25 -0
- package/examples/consumer-app/scripts/schemagen/discover-schema-roots.ts +93 -0
- package/examples/consumer-app/scripts/schemagen/naming.ts +82 -0
- package/examples/consumer-app/scripts/schemagen.ts +76 -0
- package/examples/consumer-app/src/commands/status/types.ts +11 -0
- package/examples/consumer-app/src/main.ts +15 -0
- package/examples/consumer-app/src/program.ts +116 -0
- package/examples/consumer-app/src/types.ts +23 -0
- package/examples/consumer-app/tsconfig.json +14 -0
- package/examples/formats.ts +10 -3
- package/examples/mcp-test.ts +27 -8
- package/examples/minimal.ts +4 -3
- package/examples/nested.ts +5 -4
- package/examples/option-required.ts +8 -4
- package/index.d.ts +152 -75
- package/package.json +1 -1
- package/src/builtins/builtins.test.ts +13 -0
- package/src/builtins/config.test.ts +82 -0
- package/src/builtins/config.ts +220 -0
- package/src/builtins/dispatch.ts +18 -9
- package/src/builtins/export.ts +8 -33
- package/src/builtins/index.ts +1 -0
- package/src/builtins/install.ts +13 -0
- package/src/builtins/mcp.ts +1 -1
- package/src/builtins/presentation.ts +2 -17
- package/src/builtins/registry.ts +40 -0
- package/src/capabilities.ts +46 -0
- package/src/cli-errors.ts +15 -0
- package/src/cli.ts +389 -0
- package/src/config/bootstrap.ts +265 -0
- package/src/config/context.test.ts +61 -0
- package/src/config/context.ts +98 -0
- package/src/config/entry.ts +81 -0
- package/src/config/file.test.ts +112 -0
- package/src/config/file.ts +120 -0
- package/src/config/manifest.ts +62 -0
- package/src/config/resolve.test.ts +88 -0
- package/src/config/resolve.ts +167 -0
- package/src/config/schema.ts +101 -0
- package/src/config/validate.test.ts +63 -0
- package/src/config/validate.ts +292 -0
- package/src/config.integration.test.ts +100 -0
- package/src/context.ts +5 -0
- package/src/docs/docs.test.ts +16 -16
- package/src/docs/mcp-guide.ts +35 -11
- package/src/hidden-mcpb.test.ts +40 -2
- package/src/index.ts +4 -3
- package/src/install/index.ts +46 -3
- package/src/install/paths.ts +5 -20
- package/src/install/plan.ts +6 -0
- package/src/install/status.ts +12 -0
- package/src/install/uninstall.ts +11 -0
- package/src/install/update.test.ts +5 -5
- package/src/invoke.test.ts +207 -0
- package/src/mcp/bundle.ts +9 -116
- package/src/mcp/claude.test.ts +73 -0
- package/src/mcp/claude.ts +168 -0
- package/src/mcp/env.ts +3 -37
- package/src/mcp/server.ts +18 -10
- package/src/mcp/tools.ts +3 -7
- package/src/mcp/zip.ts +82 -0
- package/src/mcp.integration.test.ts +502 -0
- package/src/{index.test.ts → parse.test.ts} +24 -935
- package/src/paths/host.ts +40 -0
- package/src/schema.ts +1 -1
- package/src/skill/generate.ts +18 -5
- package/src/skill/hint.ts +18 -0
- package/src/skill/install.ts +1 -5
- package/src/test-fixtures.ts +192 -0
- package/src/types.ts +39 -13
- package/src/validate.ts +70 -0
- package/src/completion.ts +0 -13
- package/src/invoke.ts +0 -217
- package/src/mcp.ts +0 -28
- package/src/runtime.ts +0 -134
package/src/invoke.ts
DELETED
|
@@ -1,217 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
This module invokes leaf CLI handlers without exiting the process.
|
|
3
|
-
It parses argv against the user schema, captures stdout/stderr, and patches
|
|
4
|
-
process.exit so MCP tool calls can run handlers repeatedly.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { format } from "node:util";
|
|
8
|
-
import { builtinInterceptRoot, dispatchBuiltin } from "./builtins/dispatch.ts";
|
|
9
|
-
import { cliParseRoot, cliPresentationRoot } from "./builtins/presentation.ts";
|
|
10
|
-
import { CliContext } from "./context.ts";
|
|
11
|
-
import { ParseKind, parse, postParseValidate } from "./parse.ts";
|
|
12
|
-
import { type CliNode, type CliProgram, type CliRouter, isCliLeaf, isCliRouter } from "./types.ts";
|
|
13
|
-
|
|
14
|
-
/** Outcome of a non-exiting CLI invocation. */
|
|
15
|
-
export type CliInvokeKind = "ok" | "help" | "error";
|
|
16
|
-
|
|
17
|
-
/** Result of cliInvoke: captured output and exit metadata without process.exit. */
|
|
18
|
-
export interface CliInvokeResult {
|
|
19
|
-
/** Invocation outcome. */
|
|
20
|
-
kind: CliInvokeKind;
|
|
21
|
-
/** Simulated exit code. */
|
|
22
|
-
exitCode: number;
|
|
23
|
-
/** Captured stdout during handler execution. */
|
|
24
|
-
stdout: string;
|
|
25
|
-
/** Captured stderr during handler execution. */
|
|
26
|
-
stderr: string;
|
|
27
|
-
/** Set when kind === "error" (parse/validation message). */
|
|
28
|
-
errorMsg?: string;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
/** Thrown internally when a patched process.exit fires during handler execution. */
|
|
32
|
-
class CliInvokeExit extends Error {
|
|
33
|
-
/** Exit code passed to process.exit. */
|
|
34
|
-
readonly code: number;
|
|
35
|
-
|
|
36
|
-
/** Creates an exit signal with the given status code. */
|
|
37
|
-
constructor(code: number) {
|
|
38
|
-
super(`process.exit(${code})`);
|
|
39
|
-
this.name = "CliInvokeExit";
|
|
40
|
-
this.code = code;
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
/** Looks up a subcommand or routing node by `key`. */
|
|
45
|
-
function findChild(cmds: CliNode[], name: string): CliNode | undefined {
|
|
46
|
-
return cmds.find((c) => c.key === name);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Parses argv against the user root, runs the leaf handler, and returns captured output.
|
|
51
|
-
* Never calls process.exit.
|
|
52
|
-
*/
|
|
53
|
-
export async function cliInvoke(root: CliProgram, argv: string[]): Promise<CliInvokeResult> {
|
|
54
|
-
let parseRoot: CliNode = root;
|
|
55
|
-
let completionParseRoot: CliRouter = cliPresentationRoot(root);
|
|
56
|
-
let isLeafCompletionIntercept = false;
|
|
57
|
-
|
|
58
|
-
if (isCliLeaf(root)) {
|
|
59
|
-
const intercept = builtinInterceptRoot(root, argv);
|
|
60
|
-
if (intercept.isLeafCompletionIntercept || intercept.parseRoot !== root) {
|
|
61
|
-
parseRoot = intercept.parseRoot;
|
|
62
|
-
completionParseRoot = isCliRouter(intercept.parseRoot)
|
|
63
|
-
? intercept.parseRoot
|
|
64
|
-
: cliPresentationRoot(root);
|
|
65
|
-
isLeafCompletionIntercept = intercept.isLeafCompletionIntercept;
|
|
66
|
-
}
|
|
67
|
-
} else {
|
|
68
|
-
parseRoot = cliParseRoot(root);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
let pr = parse(parseRoot, argv);
|
|
72
|
-
pr = postParseValidate(parseRoot, pr);
|
|
73
|
-
|
|
74
|
-
if (pr.kind === ParseKind.Help) {
|
|
75
|
-
return {
|
|
76
|
-
kind: "help",
|
|
77
|
-
exitCode: 1,
|
|
78
|
-
stdout: "",
|
|
79
|
-
stderr: "",
|
|
80
|
-
errorMsg: "Help is not available via MCP tool calls.",
|
|
81
|
-
};
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
if (pr.kind === ParseKind.Error) {
|
|
85
|
-
return {
|
|
86
|
-
kind: "error",
|
|
87
|
-
exitCode: 1,
|
|
88
|
-
stdout: "",
|
|
89
|
-
stderr: pr.errorMsg,
|
|
90
|
-
errorMsg: pr.errorMsg,
|
|
91
|
-
};
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
let current: CliNode = parseRoot;
|
|
95
|
-
for (const seg of pr.path) {
|
|
96
|
-
if (!isCliRouter(current)) {
|
|
97
|
-
return {
|
|
98
|
-
kind: "error",
|
|
99
|
-
exitCode: 1,
|
|
100
|
-
stdout: "",
|
|
101
|
-
stderr: "Internal error: missing handler for path.",
|
|
102
|
-
errorMsg: "Internal error: missing handler for path.",
|
|
103
|
-
};
|
|
104
|
-
}
|
|
105
|
-
const ch = findChild(current.commands, seg);
|
|
106
|
-
if (!ch) {
|
|
107
|
-
return {
|
|
108
|
-
kind: "error",
|
|
109
|
-
exitCode: 1,
|
|
110
|
-
stdout: "",
|
|
111
|
-
stderr: "Internal error: missing handler for path.",
|
|
112
|
-
errorMsg: "Internal error: missing handler for path.",
|
|
113
|
-
};
|
|
114
|
-
}
|
|
115
|
-
current = ch;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
if (!("handler" in current) || !current.handler) {
|
|
119
|
-
return {
|
|
120
|
-
kind: "error",
|
|
121
|
-
exitCode: 1,
|
|
122
|
-
stdout: "",
|
|
123
|
-
stderr: "Internal error: missing handler for path.",
|
|
124
|
-
errorMsg: "Internal error: missing handler for path.",
|
|
125
|
-
};
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
const handler = current.handler;
|
|
129
|
-
const ctx = new CliContext(root.key, pr.path, pr.args, pr.opts, root, "mcp");
|
|
130
|
-
|
|
131
|
-
let stdout = "";
|
|
132
|
-
let stderr = "";
|
|
133
|
-
const origExit = process.exit;
|
|
134
|
-
const origStdoutWrite = process.stdout.write.bind(process.stdout);
|
|
135
|
-
const origStderrWrite = process.stderr.write.bind(process.stderr);
|
|
136
|
-
const origConsoleLog = console.log;
|
|
137
|
-
const origConsoleError = console.error;
|
|
138
|
-
const origConsoleInfo = console.info;
|
|
139
|
-
const origConsoleWarn = console.warn;
|
|
140
|
-
|
|
141
|
-
process.exit = ((code?: number) => {
|
|
142
|
-
throw new CliInvokeExit(code ?? 0);
|
|
143
|
-
}) as typeof process.exit;
|
|
144
|
-
|
|
145
|
-
process.stdout.write = ((chunk: string | Uint8Array, ...args: unknown[]) => {
|
|
146
|
-
stdout += typeof chunk === "string" ? chunk : new TextDecoder().decode(chunk);
|
|
147
|
-
if (typeof args[0] === "function") {
|
|
148
|
-
(args[0] as () => void)();
|
|
149
|
-
}
|
|
150
|
-
return true;
|
|
151
|
-
}) as typeof process.stdout.write;
|
|
152
|
-
|
|
153
|
-
process.stderr.write = ((chunk: string | Uint8Array, ...args: unknown[]) => {
|
|
154
|
-
stderr += typeof chunk === "string" ? chunk : new TextDecoder().decode(chunk);
|
|
155
|
-
if (typeof args[0] === "function") {
|
|
156
|
-
(args[0] as () => void)();
|
|
157
|
-
}
|
|
158
|
-
return true;
|
|
159
|
-
}) as typeof process.stderr.write;
|
|
160
|
-
|
|
161
|
-
console.log = (...args: unknown[]) => {
|
|
162
|
-
stdout += `${format(...args)}\n`;
|
|
163
|
-
};
|
|
164
|
-
console.info = (...args: unknown[]) => {
|
|
165
|
-
stdout += `${format(...args)}\n`;
|
|
166
|
-
};
|
|
167
|
-
console.warn = (...args: unknown[]) => {
|
|
168
|
-
stderr += `${format(...args)}\n`;
|
|
169
|
-
};
|
|
170
|
-
console.error = (...args: unknown[]) => {
|
|
171
|
-
stderr += `${format(...args)}\n`;
|
|
172
|
-
};
|
|
173
|
-
|
|
174
|
-
try {
|
|
175
|
-
if (pr.kind === ParseKind.Ok) {
|
|
176
|
-
await dispatchBuiltin(root, pr, {
|
|
177
|
-
isLeafCompletionIntercept,
|
|
178
|
-
parseRoot: completionParseRoot,
|
|
179
|
-
});
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
await Promise.resolve(handler(ctx));
|
|
183
|
-
return { kind: "ok", exitCode: 0, stdout, stderr };
|
|
184
|
-
} catch (err) {
|
|
185
|
-
if (err instanceof CliInvokeExit) {
|
|
186
|
-
if (err.code === 0) {
|
|
187
|
-
return { kind: "ok", exitCode: 0, stdout, stderr };
|
|
188
|
-
}
|
|
189
|
-
const msg = stderr.trim() || `Exit code ${err.code}`;
|
|
190
|
-
return { kind: "error", exitCode: err.code, stdout, stderr, errorMsg: msg };
|
|
191
|
-
}
|
|
192
|
-
if (err instanceof Error) {
|
|
193
|
-
return {
|
|
194
|
-
kind: "error",
|
|
195
|
-
exitCode: 1,
|
|
196
|
-
stdout,
|
|
197
|
-
stderr: `${err.message}\n`,
|
|
198
|
-
errorMsg: err.message,
|
|
199
|
-
};
|
|
200
|
-
}
|
|
201
|
-
return {
|
|
202
|
-
kind: "error",
|
|
203
|
-
exitCode: 1,
|
|
204
|
-
stdout,
|
|
205
|
-
stderr: "Unknown error\n",
|
|
206
|
-
errorMsg: "Unknown error",
|
|
207
|
-
};
|
|
208
|
-
} finally {
|
|
209
|
-
process.exit = origExit;
|
|
210
|
-
process.stdout.write = origStdoutWrite;
|
|
211
|
-
process.stderr.write = origStderrWrite;
|
|
212
|
-
console.log = origConsoleLog;
|
|
213
|
-
console.error = origConsoleError;
|
|
214
|
-
console.info = origConsoleInfo;
|
|
215
|
-
console.warn = origConsoleWarn;
|
|
216
|
-
}
|
|
217
|
-
}
|
package/src/mcp.ts
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
This module starts the ArgsBarg MCP stdio server for opt-in program roots.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { bootstrapMcpEnv } from "./mcp/env.ts";
|
|
6
|
-
import { mcpServeStdioLoop } from "./mcp/server.ts";
|
|
7
|
-
import type { CliProgram } from "./types.ts";
|
|
8
|
-
|
|
9
|
-
/**
|
|
10
|
-
* Runs the MCP JSON-RPC server on stdin/stdout until stdin closes, then exits.
|
|
11
|
-
* Caller must ensure `root.mcpServer` is set.
|
|
12
|
-
*/
|
|
13
|
-
export async function cliMcpServeStdio(root: CliProgram): Promise<never> {
|
|
14
|
-
try {
|
|
15
|
-
if (root.mcpServer) {
|
|
16
|
-
bootstrapMcpEnv(root.mcpServer);
|
|
17
|
-
}
|
|
18
|
-
await mcpServeStdioLoop(root);
|
|
19
|
-
process.exit(0);
|
|
20
|
-
} catch (err) {
|
|
21
|
-
if (err instanceof Error) {
|
|
22
|
-
process.stderr.write(`${err.message}\n`);
|
|
23
|
-
} else {
|
|
24
|
-
process.stderr.write("MCP server error.\n");
|
|
25
|
-
}
|
|
26
|
-
process.exit(1);
|
|
27
|
-
}
|
|
28
|
-
}
|
package/src/runtime.ts
DELETED
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
/*
|
|
2
|
-
This module runs parsed commands, help, errors, completion, and leaf handlers.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { builtinInterceptRoot, dispatchBuiltin } from "./builtins/dispatch.ts";
|
|
6
|
-
import { cliParseRoot, cliPresentationRoot } from "./builtins/presentation.ts";
|
|
7
|
-
import { resolveCapabilities } from "./capabilities.ts";
|
|
8
|
-
import { CliContext } from "./context.ts";
|
|
9
|
-
import { cliHelpRender } from "./help.ts";
|
|
10
|
-
import { ParseKind, parse, postParseValidate } from "./parse.ts";
|
|
11
|
-
import type { CliRouter } from "./types.ts";
|
|
12
|
-
import { type CliNode, type CliProgram, isCliLeaf, isCliRouter } from "./types.ts";
|
|
13
|
-
import { cliValidateProgram } from "./validate.ts";
|
|
14
|
-
|
|
15
|
-
function cliRootMergedWithBuiltins(program: CliProgram): CliRouter {
|
|
16
|
-
return cliParseRoot(program);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
export async function cliRun(
|
|
20
|
-
program: CliProgram,
|
|
21
|
-
argv: string[] = process.argv.slice(2),
|
|
22
|
-
): Promise<never> {
|
|
23
|
-
try {
|
|
24
|
-
cliValidateProgram(program);
|
|
25
|
-
} catch (err) {
|
|
26
|
-
if (err instanceof Error) {
|
|
27
|
-
process.stderr.write(`${err.message}\n`);
|
|
28
|
-
} else {
|
|
29
|
-
process.stderr.write("Invalid CLI definition.\n");
|
|
30
|
-
}
|
|
31
|
-
process.exit(1);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const caps = resolveCapabilities(program);
|
|
35
|
-
|
|
36
|
-
if (argv.length >= 1 && argv[0] === "mcp" && !caps.mcp) {
|
|
37
|
-
process.stderr.write(
|
|
38
|
-
"MCP is not enabled. Set mcpServer: { enabled: true } on the program root.\n",
|
|
39
|
-
);
|
|
40
|
-
process.exit(1);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
if (argv.length >= 1 && argv[0] === "install" && !caps.install) {
|
|
44
|
-
process.stderr.write(
|
|
45
|
-
"install is disabled. Remove install.enabled: false from the program root.\n",
|
|
46
|
-
);
|
|
47
|
-
process.exit(1);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
if (argv.length >= 1 && argv[0] === "docs" && !caps.docs) {
|
|
51
|
-
process.stderr.write("docs is not enabled. Set docs: { enabled: true } on the program root.\n");
|
|
52
|
-
process.exit(1);
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
let parseRoot: CliNode;
|
|
56
|
-
let completionParseRoot: CliRouter = cliRootMergedWithBuiltins(program);
|
|
57
|
-
let isLeafCompletionIntercept = false;
|
|
58
|
-
|
|
59
|
-
if (isCliLeaf(program)) {
|
|
60
|
-
const intercept = builtinInterceptRoot(program, argv);
|
|
61
|
-
if (intercept.isLeafCompletionIntercept || intercept.parseRoot !== program) {
|
|
62
|
-
parseRoot = intercept.parseRoot;
|
|
63
|
-
completionParseRoot = isCliRouter(intercept.parseRoot)
|
|
64
|
-
? intercept.parseRoot
|
|
65
|
-
: cliRootMergedWithBuiltins(program);
|
|
66
|
-
isLeafCompletionIntercept = intercept.isLeafCompletionIntercept;
|
|
67
|
-
} else {
|
|
68
|
-
parseRoot = program;
|
|
69
|
-
}
|
|
70
|
-
} else {
|
|
71
|
-
parseRoot = cliRootMergedWithBuiltins(program);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
let pr = parse(parseRoot, argv);
|
|
75
|
-
pr = postParseValidate(parseRoot, pr);
|
|
76
|
-
|
|
77
|
-
if (pr.kind === ParseKind.Help) {
|
|
78
|
-
process.stdout.write(cliHelpRender(cliParseRoot(program), pr.helpPath, false));
|
|
79
|
-
process.exit(pr.helpExplicit ? 0 : 1);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
if (pr.kind === "error") {
|
|
83
|
-
const color = process.stderr.isTTY;
|
|
84
|
-
const msg = color ? `\u001B[31m${pr.errorMsg}\u001B[0m` : pr.errorMsg;
|
|
85
|
-
process.stderr.write(`${msg}\n`);
|
|
86
|
-
process.stderr.write(cliHelpRender(cliPresentationRoot(program), pr.errorHelpPath, true));
|
|
87
|
-
process.exit(1);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
if (pr.kind === ParseKind.Ok) {
|
|
91
|
-
await dispatchBuiltin(program, pr, {
|
|
92
|
-
isLeafCompletionIntercept,
|
|
93
|
-
parseRoot: completionParseRoot,
|
|
94
|
-
});
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
let current: CliNode = parseRoot;
|
|
98
|
-
for (const seg of pr.path) {
|
|
99
|
-
if (!isCliRouter(current)) {
|
|
100
|
-
process.stderr.write("Internal error: missing handler for path.\n");
|
|
101
|
-
process.exit(1);
|
|
102
|
-
}
|
|
103
|
-
const ch = current.commands.find((candidate) => candidate.key === seg);
|
|
104
|
-
if (!ch) {
|
|
105
|
-
process.stderr.write("Internal error: missing handler for path.\n");
|
|
106
|
-
process.exit(1);
|
|
107
|
-
}
|
|
108
|
-
current = ch;
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
if (!isCliLeaf(current) || !current.handler) {
|
|
112
|
-
process.stderr.write("Internal error: missing handler for path.\n");
|
|
113
|
-
process.exit(1);
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
const ctx = new CliContext(program.key, pr.path, pr.args, pr.opts, program, "cli");
|
|
117
|
-
try {
|
|
118
|
-
await Promise.resolve(current.handler(ctx));
|
|
119
|
-
process.exit(0);
|
|
120
|
-
} catch (err) {
|
|
121
|
-
if (err instanceof Error) {
|
|
122
|
-
process.stderr.write(`${err.message}\n`);
|
|
123
|
-
}
|
|
124
|
-
process.exit(1);
|
|
125
|
-
}
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
export function cliErrWithHelp(ctx: CliContext, msg: string): never {
|
|
129
|
-
const color = process.stderr.isTTY;
|
|
130
|
-
const line = color ? `\u001B[31m${msg}\u001B[0m` : msg;
|
|
131
|
-
process.stderr.write(`${line}\n`);
|
|
132
|
-
process.stderr.write(cliHelpRender(cliPresentationRoot(ctx.program), ctx.commandPath, true));
|
|
133
|
-
process.exit(1);
|
|
134
|
-
}
|