argsbarg 3.4.2 → 3.5.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 +14 -1
- package/biome.json +29 -6
- package/bun.lock +22 -0
- package/docs/install.md +1 -1
- package/docs/mcp.md +45 -1
- package/index.d.ts +50 -50
- package/justfile +27 -6
- package/package.json +4 -2
- package/scripts/release.ts +26 -9
- package/src/builtins/builtins.test.ts +9 -4
- package/src/builtins/completion-bash.ts +74 -50
- package/src/builtins/completion-fish.ts +3 -8
- package/src/builtins/completion-group.ts +1 -1
- package/src/builtins/completion-zsh.ts +80 -42
- package/src/builtins/dispatch.ts +20 -16
- package/src/builtins/export.ts +19 -10
- package/src/builtins/index.ts +9 -4
- package/src/builtins/install.ts +10 -10
- package/src/builtins/mcp.ts +1 -1
- package/src/builtins/presentation.ts +8 -8
- package/src/builtins/scopes.ts +1 -1
- package/src/builtins/version.ts +1 -1
- package/src/completion.ts +4 -4
- package/src/docs/api-guide.test.ts +2 -2
- package/src/docs/api-guide.ts +2 -2
- package/src/docs/builtin.ts +27 -8
- package/src/docs/docs.test.ts +18 -11
- package/src/docs/mcp-guide.ts +105 -24
- package/src/docs/resolve.ts +10 -3
- package/src/docs/save.ts +11 -3
- package/src/headless.test.ts +8 -16
- package/src/help.ts +73 -43
- package/src/hidden-mcpb.test.ts +7 -6
- package/src/hidden.ts +2 -2
- package/src/index.test.ts +113 -89
- package/src/index.ts +24 -24
- package/src/install/binary.ts +12 -5
- package/src/install/completions.ts +7 -3
- package/src/install/detect-installed.ts +29 -4
- package/src/install/gh-release-update.ts +31 -23
- package/src/install/index.ts +69 -19
- package/src/install/install.test.ts +31 -8
- package/src/install/mcp-codex.test.ts +57 -0
- package/src/install/mcp-codex.ts +125 -0
- package/src/install/mcp-config.ts +12 -5
- package/src/install/mcp-opencode.test.ts +98 -0
- package/src/install/mcp-opencode.ts +149 -0
- package/src/install/paths.ts +29 -3
- package/src/install/plan.ts +73 -6
- package/src/install/shell.ts +1 -4
- package/src/install/status.ts +12 -6
- package/src/install/uninstall.ts +38 -4
- package/src/install/update.test.ts +2 -2
- package/src/install/update.ts +3 -1
- package/src/invoke.ts +12 -9
- package/src/mcp/bundle.ts +36 -8
- package/src/mcp/env.ts +7 -13
- package/src/mcp/server.ts +12 -6
- package/src/mcp/tools.ts +20 -4
- package/src/mcp.ts +3 -3
- package/src/parse.ts +96 -24
- package/src/runtime.ts +22 -12
- package/src/schema.ts +11 -5
- package/src/skill/generate.ts +4 -4
- package/src/skill/install.ts +6 -2
- package/src/validate.ts +21 -16
package/src/runtime.ts
CHANGED
|
@@ -2,26 +2,29 @@
|
|
|
2
2
|
This module runs parsed commands, help, errors, completion, and leaf handlers.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { resolveCapabilities } from "./capabilities.ts";
|
|
6
5
|
import { builtinInterceptRoot, dispatchBuiltin } from "./builtins/dispatch.ts";
|
|
7
6
|
import { cliParseRoot, cliPresentationRoot } from "./builtins/presentation.ts";
|
|
8
|
-
import
|
|
9
|
-
import { type CliNode, type CliProgram, isCliLeaf, isCliRouter } from "./types.ts";
|
|
7
|
+
import { resolveCapabilities } from "./capabilities.ts";
|
|
10
8
|
import { CliContext } from "./context.ts";
|
|
11
9
|
import { cliHelpRender } from "./help.ts";
|
|
12
|
-
import { parse, postParseValidate
|
|
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
13
|
import { cliValidateProgram } from "./validate.ts";
|
|
14
14
|
|
|
15
15
|
function cliRootMergedWithBuiltins(program: CliProgram): CliRouter {
|
|
16
16
|
return cliParseRoot(program);
|
|
17
17
|
}
|
|
18
18
|
|
|
19
|
-
export async function cliRun(
|
|
19
|
+
export async function cliRun(
|
|
20
|
+
program: CliProgram,
|
|
21
|
+
argv: string[] = process.argv.slice(2),
|
|
22
|
+
): Promise<never> {
|
|
20
23
|
try {
|
|
21
24
|
cliValidateProgram(program);
|
|
22
25
|
} catch (err) {
|
|
23
26
|
if (err instanceof Error) {
|
|
24
|
-
process.stderr.write(err.message
|
|
27
|
+
process.stderr.write(`${err.message}\n`);
|
|
25
28
|
} else {
|
|
26
29
|
process.stderr.write("Invalid CLI definition.\n");
|
|
27
30
|
}
|
|
@@ -31,12 +34,16 @@ export async function cliRun(program: CliProgram, argv: string[] = process.argv.
|
|
|
31
34
|
const caps = resolveCapabilities(program);
|
|
32
35
|
|
|
33
36
|
if (argv.length >= 1 && argv[0] === "mcp" && !caps.mcp) {
|
|
34
|
-
process.stderr.write(
|
|
37
|
+
process.stderr.write(
|
|
38
|
+
"MCP is not enabled. Set mcpServer: { enabled: true } on the program root.\n",
|
|
39
|
+
);
|
|
35
40
|
process.exit(1);
|
|
36
41
|
}
|
|
37
42
|
|
|
38
43
|
if (argv.length >= 1 && argv[0] === "install" && !caps.install) {
|
|
39
|
-
process.stderr.write(
|
|
44
|
+
process.stderr.write(
|
|
45
|
+
"install is disabled. Remove install.enabled: false from the program root.\n",
|
|
46
|
+
);
|
|
40
47
|
process.exit(1);
|
|
41
48
|
}
|
|
42
49
|
|
|
@@ -75,13 +82,16 @@ export async function cliRun(program: CliProgram, argv: string[] = process.argv.
|
|
|
75
82
|
if (pr.kind === "error") {
|
|
76
83
|
const color = process.stderr.isTTY;
|
|
77
84
|
const msg = color ? `\u001B[31m${pr.errorMsg}\u001B[0m` : pr.errorMsg;
|
|
78
|
-
process.stderr.write(msg
|
|
85
|
+
process.stderr.write(`${msg}\n`);
|
|
79
86
|
process.stderr.write(cliHelpRender(cliPresentationRoot(program), pr.errorHelpPath, true));
|
|
80
87
|
process.exit(1);
|
|
81
88
|
}
|
|
82
89
|
|
|
83
90
|
if (pr.kind === ParseKind.Ok) {
|
|
84
|
-
await dispatchBuiltin(program, pr, {
|
|
91
|
+
await dispatchBuiltin(program, pr, {
|
|
92
|
+
isLeafCompletionIntercept,
|
|
93
|
+
parseRoot: completionParseRoot,
|
|
94
|
+
});
|
|
85
95
|
}
|
|
86
96
|
|
|
87
97
|
let current: CliNode = parseRoot;
|
|
@@ -109,7 +119,7 @@ export async function cliRun(program: CliProgram, argv: string[] = process.argv.
|
|
|
109
119
|
process.exit(0);
|
|
110
120
|
} catch (err) {
|
|
111
121
|
if (err instanceof Error) {
|
|
112
|
-
process.stderr.write(err.message
|
|
122
|
+
process.stderr.write(`${err.message}\n`);
|
|
113
123
|
}
|
|
114
124
|
process.exit(1);
|
|
115
125
|
}
|
|
@@ -118,7 +128,7 @@ export async function cliRun(program: CliProgram, argv: string[] = process.argv.
|
|
|
118
128
|
export function cliErrWithHelp(ctx: CliContext, msg: string): never {
|
|
119
129
|
const color = process.stderr.isTTY;
|
|
120
130
|
const line = color ? `\u001B[31m${msg}\u001B[0m` : msg;
|
|
121
|
-
process.stderr.write(line
|
|
131
|
+
process.stderr.write(`${line}\n`);
|
|
122
132
|
process.stderr.write(cliHelpRender(cliPresentationRoot(ctx.program), ctx.commandPath, true));
|
|
123
133
|
process.exit(1);
|
|
124
134
|
}
|
package/src/schema.ts
CHANGED
|
@@ -2,10 +2,16 @@
|
|
|
2
2
|
This module serializes the CLI schema tree to JSON for machine-readable introspection.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
|
-
import { type
|
|
6
|
-
import { exportPresentationBuiltins, type CliSchemaExport } from "./builtins/export.ts";
|
|
5
|
+
import { type CliSchemaExport, exportPresentationBuiltins } from "./builtins/export.ts";
|
|
7
6
|
import { cliResolveNotes } from "./help.ts";
|
|
8
7
|
import { visibleOptions } from "./hidden.ts";
|
|
8
|
+
import {
|
|
9
|
+
type CliNode,
|
|
10
|
+
type CliProgram,
|
|
11
|
+
isCliLeaf,
|
|
12
|
+
isCliRouter,
|
|
13
|
+
leafOutputSchema,
|
|
14
|
+
} from "./types.ts";
|
|
9
15
|
|
|
10
16
|
const RESERVED = new Set(["completion", "install", "docs", "mcp", "version"]);
|
|
11
17
|
|
|
@@ -60,8 +66,8 @@ function exportCommand(cmd: CliNode, root: CliProgram): CliSchemaExport | null {
|
|
|
60
66
|
/** Resolves `{argsbarg:program}` in exported notes using the root program key. */
|
|
61
67
|
function resolveSchemaNotes(node: CliSchemaExport, appKey: string): CliSchemaExport {
|
|
62
68
|
const out: CliSchemaExport = { ...node };
|
|
63
|
-
if ((out.notes ?? "").length > 0) {
|
|
64
|
-
out.notes = cliResolveNotes(out.notes
|
|
69
|
+
if ((out.notes ?? "").length > 0 && out.notes !== undefined) {
|
|
70
|
+
out.notes = cliResolveNotes(out.notes, appKey);
|
|
65
71
|
}
|
|
66
72
|
if (out.commands) {
|
|
67
73
|
out.commands = out.commands.map((ch) => resolveSchemaNotes(ch, appKey));
|
|
@@ -83,7 +89,7 @@ export function cliSchemaExport(root: CliProgram): CliSchemaExport {
|
|
|
83
89
|
}
|
|
84
90
|
|
|
85
91
|
export function cliSchemaJson(root: CliProgram): string {
|
|
86
|
-
return JSON.stringify(cliSchemaExport(root), null, 2)
|
|
92
|
+
return `${JSON.stringify(cliSchemaExport(root), null, 2)}\n`;
|
|
87
93
|
}
|
|
88
94
|
|
|
89
95
|
export type { CliSchemaExport };
|
package/src/skill/generate.ts
CHANGED
|
@@ -3,9 +3,9 @@ This module generates Agent Skills content (SKILL.md + reference.md) from a CLI
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { generateApiGuide } from "../docs/api-guide.ts";
|
|
6
|
+
import { collectMcpTools, type McpToolDef, sanitizeToolSegment } from "../mcp/tools.ts";
|
|
6
7
|
import { collectOptionDefs } from "../parse.ts";
|
|
7
|
-
import {
|
|
8
|
-
import { CliProgram, CliOptionKind } from "../types.ts";
|
|
8
|
+
import { CliOptionKind, type CliProgram } from "../types.ts";
|
|
9
9
|
|
|
10
10
|
export type SkillTarget = "cursor" | "claude";
|
|
11
11
|
|
|
@@ -18,7 +18,7 @@ export interface SkillBundle {
|
|
|
18
18
|
/** Truncates text to maxLen with ellipsis. */
|
|
19
19
|
function truncate(text: string, maxLen: number): string {
|
|
20
20
|
if (text.length <= maxLen) return text;
|
|
21
|
-
return text.slice(0, maxLen - 1)
|
|
21
|
+
return `${text.slice(0, maxLen - 1)}…`;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/** Builds third-person skill description for YAML frontmatter. */
|
|
@@ -54,7 +54,7 @@ function formatCommandEntry(root: CliProgram, tool: McpToolDef): string {
|
|
|
54
54
|
}
|
|
55
55
|
const enums = opts.filter((o) => o.kind === CliOptionKind.Enum && o.choices?.length);
|
|
56
56
|
for (const e of enums) {
|
|
57
|
-
line += ` (\`--${e.name}\`: ${e.choices
|
|
57
|
+
line += ` (\`--${e.name}\`: ${e.choices?.join(" | ")})`;
|
|
58
58
|
}
|
|
59
59
|
const varargs = (tool.leaf.positionals ?? []).filter((p) => (p.argMax ?? 1) === 0);
|
|
60
60
|
if (varargs.length > 0) {
|
package/src/skill/install.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync, mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { homedir } from "node:os";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
-
import { CliProgram } from "../types.ts";
|
|
4
|
+
import type { CliProgram } from "../types.ts";
|
|
5
5
|
import { generateSkillBundle, type SkillTarget } from "./generate.ts";
|
|
6
6
|
import { applySkillInstallHints } from "./hint.ts";
|
|
7
7
|
|
|
@@ -25,7 +25,11 @@ function resolveSkillDir(target: SkillTarget, dirName: string, global: boolean):
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
/** Writes SKILL.md and reference.md; returns changed file paths. */
|
|
28
|
-
export function cliSkillInstall(
|
|
28
|
+
export function cliSkillInstall(
|
|
29
|
+
root: CliProgram,
|
|
30
|
+
target: SkillTarget,
|
|
31
|
+
opts: SkillInstallOpts,
|
|
32
|
+
): string[] {
|
|
29
33
|
const bundle = generateSkillBundle(root, target);
|
|
30
34
|
const { skillMd, referenceMd } = applySkillInstallHints(root, bundle.skillMd, bundle.referenceMd);
|
|
31
35
|
const dir = resolveSkillDir(target, bundle.dirName, opts.global ?? false);
|
package/src/validate.ts
CHANGED
|
@@ -3,17 +3,17 @@ This module validates CLI schemas before execution.
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { reservedCommandNames, resolveCapabilities } from "./capabilities.ts";
|
|
6
|
+
import { DOCS_BUILTIN_TOPIC_KEYS } from "./docs/resolve.ts";
|
|
7
|
+
import { resolveMcpSchemaUri } from "./mcp/tools.ts";
|
|
6
8
|
import {
|
|
7
9
|
type CliLeaf,
|
|
8
10
|
type CliNode,
|
|
9
|
-
type CliProgram,
|
|
10
11
|
CliOptionKind,
|
|
12
|
+
type CliProgram,
|
|
11
13
|
CliSchemaValidationError,
|
|
12
14
|
isCliLeaf,
|
|
13
15
|
isCliRouter,
|
|
14
16
|
} from "./types.ts";
|
|
15
|
-
import { resolveMcpSchemaUri } from "./mcp/tools.ts";
|
|
16
|
-
import { DOCS_BUILTIN_TOPIC_KEYS } from "./docs/resolve.ts";
|
|
17
17
|
|
|
18
18
|
/** Validates `docs` configuration on the program root. */
|
|
19
19
|
function validateDocsConfig(docs: import("./types.ts").CliDocsConfig): void {
|
|
@@ -93,17 +93,17 @@ function walkNode(node: CliNode, program: CliProgram, isRoot: boolean): void {
|
|
|
93
93
|
const rogue = node as CliProgram;
|
|
94
94
|
if (rogue.mcpServer !== undefined) {
|
|
95
95
|
throw new CliSchemaValidationError(
|
|
96
|
-
|
|
96
|
+
`mcpServer is only supported on the program root (not on ${node.key})`,
|
|
97
97
|
);
|
|
98
98
|
}
|
|
99
99
|
if (rogue.install !== undefined) {
|
|
100
100
|
throw new CliSchemaValidationError(
|
|
101
|
-
|
|
101
|
+
`install is only supported on the program root (not on ${node.key})`,
|
|
102
102
|
);
|
|
103
103
|
}
|
|
104
104
|
if (rogue.docs !== undefined) {
|
|
105
105
|
throw new CliSchemaValidationError(
|
|
106
|
-
|
|
106
|
+
`docs is only supported on the program root (not on ${node.key})`,
|
|
107
107
|
);
|
|
108
108
|
}
|
|
109
109
|
}
|
|
@@ -115,9 +115,7 @@ function walkNode(node: CliNode, program: CliProgram, isRoot: boolean): void {
|
|
|
115
115
|
const outputSchema = node.outputSchema;
|
|
116
116
|
const legacyOutputSchema = node.mcpTool?.outputSchema;
|
|
117
117
|
if (outputSchema !== undefined && legacyOutputSchema !== undefined) {
|
|
118
|
-
throw new CliSchemaValidationError(
|
|
119
|
-
"Set outputSchema on the leaf only, not under mcpTool",
|
|
120
|
-
);
|
|
118
|
+
throw new CliSchemaValidationError("Set outputSchema on the leaf only, not under mcpTool");
|
|
121
119
|
}
|
|
122
120
|
const resolved = outputSchema ?? legacyOutputSchema;
|
|
123
121
|
if (
|
|
@@ -132,7 +130,7 @@ function walkNode(node: CliNode, program: CliProgram, isRoot: boolean): void {
|
|
|
132
130
|
const rogue = node as unknown as CliLeaf;
|
|
133
131
|
if (rogue.mcpTool !== undefined) {
|
|
134
132
|
throw new CliSchemaValidationError(
|
|
135
|
-
|
|
133
|
+
`mcpTool is only supported on leaf commands (not on ${node.key})`,
|
|
136
134
|
);
|
|
137
135
|
}
|
|
138
136
|
}
|
|
@@ -160,9 +158,7 @@ function walkNode(node: CliNode, program: CliProgram, isRoot: boolean): void {
|
|
|
160
158
|
}
|
|
161
159
|
|
|
162
160
|
if (node.fallbackMode !== undefined && node.fallbackCommand === undefined) {
|
|
163
|
-
throw new CliSchemaValidationError(
|
|
164
|
-
`fallbackMode requires fallbackCommand on '${node.key}'`,
|
|
165
|
-
);
|
|
161
|
+
throw new CliSchemaValidationError(`fallbackMode requires fallbackCommand on '${node.key}'`);
|
|
166
162
|
}
|
|
167
163
|
|
|
168
164
|
if (node.fallbackCommand !== undefined) {
|
|
@@ -233,10 +229,15 @@ function validateOptions(scopeKey: string, options: import("./types.ts").CliOpti
|
|
|
233
229
|
}
|
|
234
230
|
}
|
|
235
231
|
|
|
236
|
-
function validatePositionals(
|
|
232
|
+
function validatePositionals(
|
|
233
|
+
scopeKey: string,
|
|
234
|
+
positionals: import("./types.ts").CliPositional[],
|
|
235
|
+
): void {
|
|
237
236
|
for (const p of positionals) {
|
|
238
237
|
if (p.argMin !== undefined && p.argMin < 0) {
|
|
239
|
-
throw new CliSchemaValidationError(
|
|
238
|
+
throw new CliSchemaValidationError(
|
|
239
|
+
`argMin must be >= 0 for positional ${scopeKey}/${p.name}`,
|
|
240
|
+
);
|
|
240
241
|
}
|
|
241
242
|
if (p.argMax !== undefined && p.argMax < 0) {
|
|
242
243
|
throw new CliSchemaValidationError(
|
|
@@ -262,7 +263,11 @@ function validatePositionals(scopeKey: string, positionals: import("./types.ts")
|
|
|
262
263
|
}
|
|
263
264
|
|
|
264
265
|
for (let idx = 0; idx < positionals.length; idx++) {
|
|
265
|
-
const
|
|
266
|
+
const positional = positionals[idx];
|
|
267
|
+
if (!positional) {
|
|
268
|
+
continue;
|
|
269
|
+
}
|
|
270
|
+
const { argMax = 1 } = positional;
|
|
266
271
|
if (argMax === 0 && idx + 1 < positionals.length) {
|
|
267
272
|
throw new CliSchemaValidationError(
|
|
268
273
|
`Unlimited positional (argMax == 0) must be last in scope ${scopeKey}`,
|