argsbarg 3.4.1 → 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 +26 -1
- package/biome.json +29 -6
- package/bun.lock +22 -0
- package/docs/install.md +1 -1
- package/docs/mcp.md +63 -3
- package/index.d.ts +51 -51
- 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 +3 -3
- 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 +23 -12
- package/src/docs/mcp-guide.ts +112 -11
- 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 +8 -10
- 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 +35 -4
- package/src/install/gh-release-update.ts +31 -23
- package/src/install/index.ts +69 -19
- package/src/install/install.test.ts +57 -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 +51 -3
- package/src/install/plan.ts +96 -7
- package/src/install/shell.ts +1 -4
- package/src/install/status.ts +15 -7
- package/src/install/uninstall.ts +49 -5
- 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 +38 -14
- 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/builtins/export.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { type CliCapabilities, resolveCapabilities } from "../capabilities.ts";
|
|
2
|
+
import { cliBuiltinDocsGroupIfEnabled } from "../docs/builtin.ts";
|
|
3
|
+
import { visibleOptions } from "../hidden.ts";
|
|
2
4
|
import type { CliFallbackMode, CliNode, CliOption, CliPositional, CliProgram } from "../types.ts";
|
|
3
5
|
import { isCliRouter } from "../types.ts";
|
|
4
|
-
import { visibleOptions } from "../hidden.ts";
|
|
5
6
|
import { cliBuiltinCompletionGroup } from "./completion-group.ts";
|
|
6
7
|
import { cliBuiltinInstallCommand } from "./install.ts";
|
|
7
8
|
import { cliBuiltinMcpCommand } from "./mcp.ts";
|
|
8
9
|
import { cliBuiltinVersionCommand } from "./version.ts";
|
|
9
|
-
import { cliBuiltinDocsGroupIfEnabled } from "../docs/builtin.ts";
|
|
10
10
|
|
|
11
11
|
/** JSON-safe command node (no handlers). */
|
|
12
12
|
export interface CliSchemaExport {
|
|
@@ -55,22 +55,31 @@ function exportBuiltinNode(cmd: CliNode): CliSchemaExport | null {
|
|
|
55
55
|
return out;
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
function pushExportedBuiltin(builtins: CliSchemaExport[], cmd: CliNode): void {
|
|
59
|
+
const node = exportBuiltinNode(cmd);
|
|
60
|
+
if (node) {
|
|
61
|
+
builtins.push(node);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
58
65
|
/** Built-in subtrees matching help visibility for `--schema` export. */
|
|
59
|
-
export function exportPresentationBuiltins(
|
|
66
|
+
export function exportPresentationBuiltins(
|
|
67
|
+
program: CliProgram,
|
|
68
|
+
caps?: CliCapabilities,
|
|
69
|
+
): CliSchemaExport[] {
|
|
60
70
|
const resolved = caps ?? resolveCapabilities(program);
|
|
61
|
-
const builtins: CliSchemaExport[] = [
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
];
|
|
71
|
+
const builtins: CliSchemaExport[] = [];
|
|
72
|
+
pushExportedBuiltin(builtins, cliBuiltinCompletionGroup(program));
|
|
73
|
+
pushExportedBuiltin(builtins, cliBuiltinVersionCommand());
|
|
65
74
|
if (resolved.install) {
|
|
66
|
-
builtins
|
|
75
|
+
pushExportedBuiltin(builtins, cliBuiltinInstallCommand(program));
|
|
67
76
|
}
|
|
68
77
|
const docsGroup = cliBuiltinDocsGroupIfEnabled(program);
|
|
69
78
|
if (docsGroup) {
|
|
70
|
-
builtins
|
|
79
|
+
pushExportedBuiltin(builtins, docsGroup);
|
|
71
80
|
}
|
|
72
81
|
if (resolved.mcp) {
|
|
73
|
-
builtins
|
|
82
|
+
pushExportedBuiltin(builtins, cliBuiltinMcpCommand(program));
|
|
74
83
|
}
|
|
75
84
|
return builtins;
|
|
76
85
|
}
|
package/src/builtins/index.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
export { completionBashScript } from "./completion-bash.ts";
|
|
2
|
-
export { completionZshScript } from "./completion-zsh.ts";
|
|
3
2
|
export { completionFishScript } from "./completion-fish.ts";
|
|
4
3
|
export { cliBuiltinCompletionGroup } from "./completion-group.ts";
|
|
4
|
+
export { completionZshScript } from "./completion-zsh.ts";
|
|
5
|
+
export { builtinInterceptRoot, dispatchBuiltin } from "./dispatch.ts";
|
|
6
|
+
export { type CliSchemaExport, exportPresentationBuiltins } from "./export.ts";
|
|
5
7
|
export { cliBuiltinInstallCommand, installBuiltinOptions } from "./install.ts";
|
|
6
8
|
export { cliBuiltinMcpCommand } from "./mcp.ts";
|
|
7
|
-
export {
|
|
8
|
-
|
|
9
|
-
|
|
9
|
+
export {
|
|
10
|
+
cliParseRoot,
|
|
11
|
+
cliPresentationRoot,
|
|
12
|
+
parseBuiltins,
|
|
13
|
+
presentationBuiltins,
|
|
14
|
+
} from "./presentation.ts";
|
|
10
15
|
export { collectScopes, type ScopeRec } from "./scopes.ts";
|
package/src/builtins/install.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { resolveCapabilities } from "../capabilities.ts";
|
|
2
|
-
import {
|
|
2
|
+
import { type CliLeaf, type CliOption, CliOptionKind, type CliProgram } from "../types.ts";
|
|
3
3
|
|
|
4
4
|
/** Install command options (dynamic: `--mcp` only when MCP is enabled). */
|
|
5
5
|
export function installBuiltinOptions(root: CliProgram): CliOption[] {
|
|
@@ -42,12 +42,14 @@ export function installBuiltinOptions(root: CliProgram): CliOption[] {
|
|
|
42
42
|
},
|
|
43
43
|
{
|
|
44
44
|
name: "uninstall",
|
|
45
|
-
description:
|
|
45
|
+
description:
|
|
46
|
+
"Remove installed artifacts (use --all or scoped flags; skips targets not on disk).",
|
|
46
47
|
kind: CliOptionKind.Presence,
|
|
47
48
|
},
|
|
48
49
|
{
|
|
49
50
|
name: "prefix",
|
|
50
|
-
description:
|
|
51
|
+
description:
|
|
52
|
+
"Install directory for the binary (default ~/.local/bin; overrides INSTALL_PREFIX).",
|
|
51
53
|
kind: CliOptionKind.String,
|
|
52
54
|
},
|
|
53
55
|
{
|
|
@@ -67,7 +69,8 @@ export function installBuiltinOptions(root: CliProgram): CliOption[] {
|
|
|
67
69
|
},
|
|
68
70
|
{
|
|
69
71
|
name: "quiet",
|
|
70
|
-
description:
|
|
72
|
+
description:
|
|
73
|
+
"Suppress informational output (requires --yes, --json, --reinstall, or --update).",
|
|
71
74
|
kind: CliOptionKind.Presence,
|
|
72
75
|
},
|
|
73
76
|
];
|
|
@@ -103,11 +106,7 @@ export function cliBuiltinInstallCommand(root: CliProgram): CliLeaf {
|
|
|
103
106
|
` ${app} install --reinstall`,
|
|
104
107
|
];
|
|
105
108
|
if (resolveCapabilities(root).update) {
|
|
106
|
-
notesLines.push(
|
|
107
|
-
"",
|
|
108
|
-
"Upgrade to latest release:",
|
|
109
|
-
` ${app} install --update`,
|
|
110
|
-
);
|
|
109
|
+
notesLines.push("", "Upgrade to latest release:", ` ${app} install --update`);
|
|
111
110
|
}
|
|
112
111
|
notesLines.push(
|
|
113
112
|
"",
|
|
@@ -122,7 +121,8 @@ export function cliBuiltinInstallCommand(root: CliProgram): CliLeaf {
|
|
|
122
121
|
);
|
|
123
122
|
return {
|
|
124
123
|
key: "install",
|
|
125
|
-
description:
|
|
124
|
+
description:
|
|
125
|
+
"Install the binary, shell completions, agent skills, and MCP config to your user environment.",
|
|
126
126
|
notes: notesLines.join("\n"),
|
|
127
127
|
options: installBuiltinOptions(root),
|
|
128
128
|
handler: () => {},
|
package/src/builtins/mcp.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { resolveCapabilities } from "../capabilities.ts";
|
|
2
2
|
import { docsEnabled } from "../docs/resolve.ts";
|
|
3
|
-
import { type CliLeaf, type CliProgram, type CliRouter
|
|
3
|
+
import { CliFallbackMode, type CliLeaf, type CliProgram, type CliRouter } from "../types.ts";
|
|
4
4
|
|
|
5
5
|
/** Built-in `mcp` router: bare `myapp mcp` runs stdio (via hidden `serve` fallback); `mcp bundle` packs `.mcpb`. */
|
|
6
6
|
export function cliBuiltinMcpCommand(program: CliProgram): CliRouter {
|
|
7
7
|
const caps = resolveCapabilities(program);
|
|
8
8
|
const lines = [
|
|
9
|
-
"Stdio MCP server. Add to Cursor or Claude:",
|
|
9
|
+
"Stdio MCP server. Add to Cursor, Claude Code, or Claude Desktop:",
|
|
10
10
|
"",
|
|
11
11
|
" command: {argsbarg:program}",
|
|
12
12
|
" args: mcp",
|
|
@@ -28,7 +28,7 @@ export function cliBuiltinMcpCommand(program: CliProgram): CliRouter {
|
|
|
28
28
|
|
|
29
29
|
const bundle: CliLeaf = {
|
|
30
30
|
key: "bundle",
|
|
31
|
-
description: "Pack a Claude Desktop MCP Bundle (.mcpb) from dist/<key
|
|
31
|
+
description: "Pack a Claude Desktop MCP Bundle (.mcpb) from dist/<key>.",
|
|
32
32
|
handler: () => {},
|
|
33
33
|
};
|
|
34
34
|
|
|
@@ -1,20 +1,17 @@
|
|
|
1
1
|
import type { CliCapabilities } from "../capabilities.ts";
|
|
2
2
|
import { resolveCapabilities } from "../capabilities.ts";
|
|
3
|
+
import { cliBuiltinDocsGroupIfEnabled } from "../docs/builtin.ts";
|
|
3
4
|
import { presentationNode, visibleOptions } from "../hidden.ts";
|
|
4
5
|
import type { CliLeaf, CliNode, CliProgram, CliRouter } from "../types.ts";
|
|
5
|
-
import { isCliLeaf
|
|
6
|
+
import { isCliLeaf } from "../types.ts";
|
|
6
7
|
import { cliBuiltinCompletionGroup } from "./completion-group.ts";
|
|
7
8
|
import { cliBuiltinInstallCommand } from "./install.ts";
|
|
8
9
|
import { cliBuiltinMcpCommand } from "./mcp.ts";
|
|
9
10
|
import { cliBuiltinVersionCommand } from "./version.ts";
|
|
10
|
-
import { cliBuiltinDocsGroupIfEnabled } from "../docs/builtin.ts";
|
|
11
11
|
|
|
12
12
|
/** All built-in command nodes for argv parsing (includes hidden builtins). */
|
|
13
13
|
export function parseBuiltins(program: CliProgram, caps: CliCapabilities): CliNode[] {
|
|
14
|
-
const builtins: CliNode[] = [
|
|
15
|
-
cliBuiltinCompletionGroup(program),
|
|
16
|
-
cliBuiltinVersionCommand(),
|
|
17
|
-
];
|
|
14
|
+
const builtins: CliNode[] = [cliBuiltinCompletionGroup(program), cliBuiltinVersionCommand()];
|
|
18
15
|
if (caps.install) {
|
|
19
16
|
builtins.push(cliBuiltinInstallCommand(program));
|
|
20
17
|
}
|
|
@@ -98,10 +95,13 @@ export function cliPresentationRoot(program: CliProgram): CliRouter {
|
|
|
98
95
|
}
|
|
99
96
|
|
|
100
97
|
/** Root help notes: consumer `program.notes` plus agent discovery when `docs` is enabled. */
|
|
101
|
-
export function presentationRootNotes(
|
|
98
|
+
export function presentationRootNotes(
|
|
99
|
+
program: CliProgram,
|
|
100
|
+
caps: CliCapabilities,
|
|
101
|
+
): string | undefined {
|
|
102
102
|
const parts: string[] = [];
|
|
103
103
|
if ((program.notes ?? "").trim().length > 0) {
|
|
104
|
-
parts.push(program.notes
|
|
104
|
+
parts.push((program.notes ?? "").trim());
|
|
105
105
|
}
|
|
106
106
|
if (caps.docs) {
|
|
107
107
|
parts.push(`For AI agents: \`${program.key} docs skill\`.`);
|
package/src/builtins/scopes.ts
CHANGED
|
@@ -25,7 +25,7 @@ function walkScopes(cmdPath: string, cmd: CliNode, acc: ScopeRec[]): void {
|
|
|
25
25
|
wantsFiles: hasPositionalArguments(cmd),
|
|
26
26
|
});
|
|
27
27
|
for (const ch of kids) {
|
|
28
|
-
const nextPath = cmdPath === "" ? ch.key : cmdPath
|
|
28
|
+
const nextPath = cmdPath === "" ? ch.key : `${cmdPath}/${ch.key}`;
|
|
29
29
|
walkScopes(nextPath, ch, acc);
|
|
30
30
|
}
|
|
31
31
|
}
|
package/src/builtins/version.ts
CHANGED
package/src/completion.ts
CHANGED
|
@@ -3,11 +3,11 @@ Re-export shim — completion emitters and built-in trees live in ./builtins/.
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
export {
|
|
6
|
-
completionBashScript,
|
|
7
|
-
completionZshScript,
|
|
8
|
-
completionFishScript,
|
|
9
|
-
cliPresentationRoot,
|
|
10
6
|
cliBuiltinCompletionGroup,
|
|
11
7
|
cliBuiltinInstallCommand,
|
|
12
8
|
cliBuiltinMcpCommand,
|
|
9
|
+
cliPresentationRoot,
|
|
10
|
+
completionBashScript,
|
|
11
|
+
completionFishScript,
|
|
12
|
+
completionZshScript,
|
|
13
13
|
} from "./builtins/index.ts";
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { expect, test } from "bun:test";
|
|
2
|
+
import { cliSchemaExport } from "../schema.ts";
|
|
2
3
|
import type { CliProgram } from "../types.ts";
|
|
3
4
|
import { CliOptionKind } from "../types.ts";
|
|
4
5
|
import { generateApiGuide, generateApiGuideBody } from "./api-guide.ts";
|
|
5
|
-
import { cliSchemaExport } from "../schema.ts";
|
|
6
6
|
|
|
7
7
|
const nestedFixture: CliProgram = {
|
|
8
8
|
key: "nested.ts",
|
|
@@ -125,7 +125,7 @@ test("generateApiGuide and cliSchemaExport include leaf outputSchema", () => {
|
|
|
125
125
|
],
|
|
126
126
|
};
|
|
127
127
|
const schema = cliSchemaExport(fixture);
|
|
128
|
-
expect(schema.commands
|
|
128
|
+
expect(schema.commands?.[0]?.outputSchema).toEqual({
|
|
129
129
|
type: "object",
|
|
130
130
|
properties: { id: { type: "string" } },
|
|
131
131
|
required: ["id"],
|
package/src/docs/api-guide.ts
CHANGED
|
@@ -101,7 +101,7 @@ function renderCommandNode(
|
|
|
101
101
|
lines.push("#### Options", "");
|
|
102
102
|
lines.push("| Option | Type | Required | Description |");
|
|
103
103
|
lines.push("| --- | --- | --- | --- |");
|
|
104
|
-
for (const opt of node.options
|
|
104
|
+
for (const opt of node.options ?? []) {
|
|
105
105
|
lines.push(formatOptionRow(opt));
|
|
106
106
|
}
|
|
107
107
|
lines.push("");
|
|
@@ -111,7 +111,7 @@ function renderCommandNode(
|
|
|
111
111
|
lines.push("#### Positionals", "");
|
|
112
112
|
lines.push("| Argument | Type | Required | Description |");
|
|
113
113
|
lines.push("| --- | --- | --- | --- |");
|
|
114
|
-
for (const p of node.positionals
|
|
114
|
+
for (const p of node.positionals ?? []) {
|
|
115
115
|
lines.push(formatPositionalRow(p));
|
|
116
116
|
}
|
|
117
117
|
lines.push("");
|
package/src/docs/builtin.ts
CHANGED
|
@@ -1,4 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
CliFallbackMode,
|
|
3
|
+
type CliLeaf,
|
|
4
|
+
type CliOption,
|
|
5
|
+
CliOptionKind,
|
|
6
|
+
type CliProgram,
|
|
7
|
+
type CliRouter,
|
|
8
|
+
} from "../types.ts";
|
|
2
9
|
import {
|
|
3
10
|
DOCS_ROUTER_DESCRIPTION,
|
|
4
11
|
docsEffectiveDefaultTopic,
|
|
@@ -16,7 +23,11 @@ const DOCS_SAVE_OPTION: CliOption = {
|
|
|
16
23
|
kind: CliOptionKind.Presence,
|
|
17
24
|
};
|
|
18
25
|
|
|
19
|
-
function runDocsTopic(
|
|
26
|
+
function runDocsTopic(
|
|
27
|
+
program: CliProgram,
|
|
28
|
+
topic: string,
|
|
29
|
+
ctx: { hasFlag(name: string): boolean },
|
|
30
|
+
): void {
|
|
20
31
|
if (ctx.hasFlag("save")) {
|
|
21
32
|
process.stdout.write(`${saveDocsTopic(program, topic)}\n`);
|
|
22
33
|
return;
|
|
@@ -43,24 +54,32 @@ function docsRouterNotes(): string {
|
|
|
43
54
|
|
|
44
55
|
/** Built-in `docs` router with bundled topic subcommands. */
|
|
45
56
|
export function cliBuiltinDocsGroup(program: CliProgram): CliRouter {
|
|
46
|
-
const docs = program.docs
|
|
57
|
+
const docs = program.docs;
|
|
58
|
+
if (!docs) {
|
|
59
|
+
throw new Error("docs not enabled");
|
|
60
|
+
}
|
|
47
61
|
const leaves: CliLeaf[] = [];
|
|
48
62
|
|
|
49
63
|
for (const key of docsUserTopicKeys(docs)) {
|
|
50
|
-
const topic = docs.topics[key]
|
|
64
|
+
const topic = docs.topics[key];
|
|
65
|
+
if (!topic) {
|
|
66
|
+
throw new Error(`docs topic missing: ${key}`);
|
|
67
|
+
}
|
|
51
68
|
leaves.push(docsLeaf(program, key, docsTopicDescription(key, topic.description)));
|
|
52
69
|
}
|
|
53
70
|
|
|
54
71
|
if (docsIncludesMcpTopic(program)) {
|
|
55
|
-
leaves.push(
|
|
56
|
-
docsLeaf(program, "mcp", "Print MCP server setup and tool guidance."),
|
|
57
|
-
);
|
|
72
|
+
leaves.push(docsLeaf(program, "mcp", "Print MCP server setup and tool guidance."));
|
|
58
73
|
}
|
|
59
74
|
|
|
60
75
|
leaves.push(
|
|
61
76
|
docsLeaf(program, "schema", "Print the full command tree as JSON."),
|
|
62
77
|
docsLeaf(program, "api", "Print the full command reference as markdown."),
|
|
63
|
-
docsLeaf(
|
|
78
|
+
docsLeaf(
|
|
79
|
+
program,
|
|
80
|
+
"skill",
|
|
81
|
+
"Print a reference agent SKILL, use `install --skill` for optimized.",
|
|
82
|
+
),
|
|
64
83
|
);
|
|
65
84
|
|
|
66
85
|
return {
|
package/src/docs/docs.test.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { afterEach, beforeEach, expect, test } from "bun:test";
|
|
2
2
|
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
|
|
3
|
-
import { join } from "node:path";
|
|
4
3
|
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
5
|
import { cliPresentationRoot } from "../builtins/presentation.ts";
|
|
6
6
|
import { completionBashScript } from "../completion.ts";
|
|
7
7
|
import { cliInvoke } from "../index.ts";
|
|
8
8
|
import type { CliProgram } from "../types.ts";
|
|
9
9
|
import { cliValidateProgram } from "../validate.ts";
|
|
10
|
-
import { docsEffectiveDefaultTopic } from "./resolve.ts";
|
|
11
10
|
import { generateMcpGuide } from "./mcp-guide.ts";
|
|
11
|
+
import { docsEffectiveDefaultTopic } from "./resolve.ts";
|
|
12
12
|
import { saveDocsTopic } from "./save.ts";
|
|
13
13
|
|
|
14
14
|
let workDir: string;
|
|
@@ -64,13 +64,15 @@ test("docs reserved when enabled", () => {
|
|
|
64
64
|
|
|
65
65
|
test("docs rejects reserved topic keys", () => {
|
|
66
66
|
const root = docsFixture();
|
|
67
|
-
|
|
67
|
+
const docs = root.docs;
|
|
68
|
+
if (!docs) throw new Error("expected docs fixture");
|
|
69
|
+
docs.topics.schema = { text: "nope" };
|
|
68
70
|
expect(() => cliValidateProgram(root)).toThrow(/reserved/);
|
|
69
|
-
delete
|
|
70
|
-
|
|
71
|
+
delete docs.topics.schema;
|
|
72
|
+
docs.topics.skill = { text: "nope" };
|
|
71
73
|
expect(() => cliValidateProgram(root)).toThrow(/reserved/);
|
|
72
|
-
delete
|
|
73
|
-
|
|
74
|
+
delete docs.topics.skill;
|
|
75
|
+
docs.topics.api = { text: "nope" };
|
|
74
76
|
expect(() => cliValidateProgram(root)).toThrow(/reserved/);
|
|
75
77
|
});
|
|
76
78
|
|
|
@@ -102,6 +104,8 @@ test("docs mcp when MCP enabled", async () => {
|
|
|
102
104
|
expect(result.exitCode).toBe(0);
|
|
103
105
|
expect(result.stdout).toContain("MCP server (myapp)");
|
|
104
106
|
expect(result.stdout).toContain("myapp mcp");
|
|
107
|
+
expect(result.stdout).toContain("claude_desktop_config.json");
|
|
108
|
+
expect(result.stdout).toContain("install --mcp --yes");
|
|
105
109
|
});
|
|
106
110
|
|
|
107
111
|
test("docs rejects unknown subcommand", async () => {
|
|
@@ -125,9 +129,9 @@ test("presentation includes docs subtree", () => {
|
|
|
125
129
|
const presentation = cliPresentationRoot(docsFixture());
|
|
126
130
|
const docsNode = presentation.commands.find((c) => c.key === "docs");
|
|
127
131
|
expect(docsNode).toBeDefined();
|
|
128
|
-
expect(
|
|
129
|
-
|
|
130
|
-
);
|
|
132
|
+
expect(
|
|
133
|
+
docsNode && "commands" in docsNode && docsNode.commands.some((c) => c.key === "readme"),
|
|
134
|
+
).toBe(true);
|
|
131
135
|
});
|
|
132
136
|
|
|
133
137
|
test("docs schema prints JSON", async () => {
|
|
@@ -192,9 +196,16 @@ test("completions offer docs subcommands", () => {
|
|
|
192
196
|
expect(bash).toContain("skill) echo");
|
|
193
197
|
});
|
|
194
198
|
|
|
195
|
-
test("generateMcpGuide includes schema URI", () => {
|
|
199
|
+
test("generateMcpGuide includes schema URI and install targets", () => {
|
|
196
200
|
const guide = generateMcpGuide(docsFixture(true));
|
|
197
201
|
expect(guide).toContain("myapp://schema");
|
|
202
|
+
expect(guide).toContain("~/.cursor/mcp.json");
|
|
203
|
+
expect(guide).toContain("claude_desktop_config.json");
|
|
204
|
+
expect(guide).toContain("## Installation");
|
|
205
|
+
expect(guide).toContain("## Running directly");
|
|
206
|
+
expect(guide).toContain("install --bin");
|
|
207
|
+
expect(guide).toContain("OpenAI Codex");
|
|
208
|
+
expect(guide).toContain("ChatGPT");
|
|
198
209
|
});
|
|
199
210
|
|
|
200
211
|
test("docs --save writes topic file", async () => {
|
package/src/docs/mcp-guide.ts
CHANGED
|
@@ -1,11 +1,75 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { resolveCapabilities } from "../capabilities.ts";
|
|
2
|
+
import { expectedOpenCodeMcpEntry, OPENCODE_CONFIG_SCHEMA } from "../install/mcp-opencode.ts";
|
|
2
3
|
import {
|
|
3
4
|
collectMcpTools,
|
|
5
|
+
type McpToolDef,
|
|
4
6
|
mcpServerId,
|
|
5
7
|
resolveMcpSchemaUri,
|
|
6
|
-
type McpToolDef,
|
|
7
8
|
} from "../mcp/tools.ts";
|
|
8
|
-
import {
|
|
9
|
+
import { collectOptionDefs } from "../parse.ts";
|
|
10
|
+
import { CliOptionKind, type CliProgram } from "../types.ts";
|
|
11
|
+
|
|
12
|
+
/** Extra host notes for generated `docs mcp` (manual fallbacks and ChatGPT Connectors). */
|
|
13
|
+
function appendManualHostSetup(lines: string[], root: CliProgram, serverId: string): void {
|
|
14
|
+
const openCodeEntry = expectedOpenCodeMcpEntry(root);
|
|
15
|
+
|
|
16
|
+
lines.push(
|
|
17
|
+
"| OpenCode | `~/.config/opencode/*` (when `~/.config/opencode` exists) |",
|
|
18
|
+
"| OpenAI Codex | `~/.codex/config.toml` via `codex mcp add` (when `codex` is on PATH) |",
|
|
19
|
+
"| ChatGPT desktop | `chatgpt_mcp_config.json` (when ChatGPT app data exists) |",
|
|
20
|
+
"",
|
|
21
|
+
"Claude Desktop paths by platform:",
|
|
22
|
+
"",
|
|
23
|
+
"- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`",
|
|
24
|
+
"- **Windows:** `%APPDATA%\\Claude\\claude_desktop_config.json`",
|
|
25
|
+
"- **Linux:** `~/.config/Claude/claude_desktop_config.json`",
|
|
26
|
+
"",
|
|
27
|
+
"ChatGPT desktop JSON (when auto-installed):",
|
|
28
|
+
"",
|
|
29
|
+
"- **macOS:** `~/Library/Application Support/ChatGPT/chatgpt_mcp_config.json`",
|
|
30
|
+
"- **Windows:** `%APPDATA%\\OpenAI\\ChatGPT\\chatgpt_mcp_config.json`",
|
|
31
|
+
"",
|
|
32
|
+
"Restart Claude Desktop and ChatGPT desktop after changing their config files.",
|
|
33
|
+
"",
|
|
34
|
+
"### Manual fallbacks",
|
|
35
|
+
"",
|
|
36
|
+
"**OpenCode** (no `~/.config/opencode` yet):",
|
|
37
|
+
"",
|
|
38
|
+
"```json",
|
|
39
|
+
JSON.stringify(
|
|
40
|
+
{
|
|
41
|
+
$schema: OPENCODE_CONFIG_SCHEMA,
|
|
42
|
+
mcp: { [serverId]: openCodeEntry },
|
|
43
|
+
},
|
|
44
|
+
null,
|
|
45
|
+
2,
|
|
46
|
+
),
|
|
47
|
+
"```",
|
|
48
|
+
"",
|
|
49
|
+
"**Codex** (`codex` not on PATH):",
|
|
50
|
+
"",
|
|
51
|
+
"```toml",
|
|
52
|
+
`[mcp_servers.${serverId}]`,
|
|
53
|
+
`command = "${root.key}"`,
|
|
54
|
+
'args = ["mcp"]',
|
|
55
|
+
"```",
|
|
56
|
+
"",
|
|
57
|
+
`Or after installing Codex CLI: \`codex mcp add ${serverId} -- ${root.key} mcp\`.`,
|
|
58
|
+
"",
|
|
59
|
+
"### ChatGPT web (Connectors)",
|
|
60
|
+
"",
|
|
61
|
+
`OpenAI's documented path for **ChatGPT web/desktop** is **Settings → Connectors → Developer mode** with a **remote HTTPS MCP URL** — not local stdio. ChatGPT does not spawn \`${root.key} mcp\` directly.`,
|
|
62
|
+
"",
|
|
63
|
+
"For local stdio, bridge and tunnel, then register the HTTPS URL in Connectors:",
|
|
64
|
+
"",
|
|
65
|
+
`1. Expose \`${root.key} mcp\` over HTTP (e.g. \`mcp-remote\`).`,
|
|
66
|
+
"2. Tunnel if needed (ngrok, Cloudflare Tunnel).",
|
|
67
|
+
"3. Add the public URL as a custom connector.",
|
|
68
|
+
"",
|
|
69
|
+
"Desktop `chatgpt_mcp_config.json` is merged when the ChatGPT app is installed; support varies by build. Use Connectors when local JSON is absent or tools do not appear.",
|
|
70
|
+
"",
|
|
71
|
+
);
|
|
72
|
+
}
|
|
9
73
|
|
|
10
74
|
/** Formats one exposed MCP tool for the auto-generated MCP guide. */
|
|
11
75
|
function formatToolLine(root: CliProgram, tool: McpToolDef): string {
|
|
@@ -24,20 +88,55 @@ export function generateMcpGuide(root: CliProgram): string {
|
|
|
24
88
|
const tools = collectMcpTools(root);
|
|
25
89
|
const schemaUri = resolveMcpSchemaUri(root);
|
|
26
90
|
const serverId = mcpServerId(root);
|
|
27
|
-
const mcp = root.mcpServer
|
|
91
|
+
const mcp = root.mcpServer;
|
|
92
|
+
if (!mcp) {
|
|
93
|
+
throw new Error("MCP server not enabled");
|
|
94
|
+
}
|
|
95
|
+
const caps = resolveCapabilities(root);
|
|
28
96
|
|
|
29
97
|
const lines: string[] = [
|
|
30
98
|
`# MCP server (${root.key})`,
|
|
31
99
|
"",
|
|
32
100
|
`${root.key} exposes an MCP server with features similar to the CLI.`,
|
|
33
101
|
"",
|
|
34
|
-
"##
|
|
102
|
+
"## Installation",
|
|
103
|
+
"",
|
|
104
|
+
"### `install --mcp`",
|
|
35
105
|
"",
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
if (caps.install) {
|
|
109
|
+
lines.push(
|
|
110
|
+
`Install the CLI first so \`${root.key}\` is on your PATH (e.g. \`${root.key} install --bin --yes\` or \`install --all --yes\`). Host configs reference the binary by name.`,
|
|
111
|
+
"",
|
|
112
|
+
);
|
|
113
|
+
} else {
|
|
114
|
+
lines.push(
|
|
115
|
+
`The CLI binary \`${root.key}\` must already be on your PATH. Host configs reference it by name.`,
|
|
116
|
+
"",
|
|
117
|
+
);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
lines.push(
|
|
36
121
|
"```bash",
|
|
37
|
-
`${root.key} mcp`,
|
|
122
|
+
`${root.key} install --mcp --yes`,
|
|
38
123
|
"```",
|
|
39
124
|
"",
|
|
40
|
-
"
|
|
125
|
+
"Merges the server entry below into host config when each host is present:",
|
|
126
|
+
"",
|
|
127
|
+
"| Host | Config file |",
|
|
128
|
+
"| --- | --- |",
|
|
129
|
+
"| Cursor | `~/.cursor/mcp.json` (when `~/.cursor` exists) |",
|
|
130
|
+
"| Claude Code | `~/.claude.json` |",
|
|
131
|
+
"| Claude Desktop | `claude_desktop_config.json` (when Claude Desktop app data exists) |",
|
|
132
|
+
);
|
|
133
|
+
|
|
134
|
+
appendManualHostSetup(lines, root, serverId);
|
|
135
|
+
|
|
136
|
+
lines.push(
|
|
137
|
+
"### Manual `mcpServers` entry",
|
|
138
|
+
"",
|
|
139
|
+
"For Cursor, Claude, and ChatGPT desktop JSON configs, add under `mcpServers`:",
|
|
41
140
|
"",
|
|
42
141
|
"```json",
|
|
43
142
|
JSON.stringify(
|
|
@@ -54,13 +153,15 @@ export function generateMcpGuide(root: CliProgram): string {
|
|
|
54
153
|
),
|
|
55
154
|
"```",
|
|
56
155
|
"",
|
|
57
|
-
"
|
|
156
|
+
"## Running directly",
|
|
157
|
+
"",
|
|
158
|
+
"Start the stdio MCP server without editing host config:",
|
|
58
159
|
"",
|
|
59
160
|
"```bash",
|
|
60
|
-
`${root.key}
|
|
161
|
+
`${root.key} mcp`,
|
|
61
162
|
"```",
|
|
62
163
|
"",
|
|
63
|
-
|
|
164
|
+
);
|
|
64
165
|
|
|
65
166
|
if (mcp.shellEnv || mcp.envFile) {
|
|
66
167
|
lines.push("## Environment", "");
|
|
@@ -71,7 +172,7 @@ export function generateMcpGuide(root: CliProgram): string {
|
|
|
71
172
|
}
|
|
72
173
|
if (mcp.envFile) {
|
|
73
174
|
lines.push(
|
|
74
|
-
|
|
175
|
+
`- **\`envFile\`** — loads \`${mcp.envFile}\` after shell env (overrides for its keys).`,
|
|
75
176
|
);
|
|
76
177
|
}
|
|
77
178
|
lines.push("");
|
package/src/docs/resolve.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type { CliDocsConfig, CliProgram } from "../types.ts";
|
|
2
1
|
import { cliSchemaJson } from "../schema.ts";
|
|
3
2
|
import { generateSkillBundle } from "../skill/generate.ts";
|
|
3
|
+
import type { CliDocsConfig, CliProgram } from "../types.ts";
|
|
4
4
|
import { generateApiGuide } from "./api-guide.ts";
|
|
5
5
|
import { generateMcpGuide } from "./mcp-guide.ts";
|
|
6
6
|
|
|
@@ -31,7 +31,11 @@ export function docsEffectiveDefaultTopic(docs: CliDocsConfig): string {
|
|
|
31
31
|
if (keys.length === 0) {
|
|
32
32
|
throw new Error("docs.topics must be non-empty");
|
|
33
33
|
}
|
|
34
|
-
|
|
34
|
+
const first = keys[0];
|
|
35
|
+
if (first === undefined) {
|
|
36
|
+
throw new Error("docs.topics must be non-empty");
|
|
37
|
+
}
|
|
38
|
+
return first;
|
|
35
39
|
}
|
|
36
40
|
|
|
37
41
|
/** Whether MCP auto-guide topic is included. */
|
|
@@ -53,7 +57,10 @@ export function docsTopicDescription(key: string, custom?: string): string {
|
|
|
53
57
|
|
|
54
58
|
/** Markdown body for one docs topic key. */
|
|
55
59
|
export function docsTopicText(program: CliProgram, topic: string): string {
|
|
56
|
-
const docs = program.docs
|
|
60
|
+
const docs = program.docs;
|
|
61
|
+
if (!docs) {
|
|
62
|
+
throw new Error("docs not enabled");
|
|
63
|
+
}
|
|
57
64
|
if (topic === "mcp") {
|
|
58
65
|
if (!docsIncludesMcpTopic(program)) {
|
|
59
66
|
throw new Error("Unknown docs topic 'mcp'.");
|
package/src/docs/save.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
+
import { generatedFileHtmlComment, insertGeneratedHint } from "../skill/hint.ts";
|
|
3
4
|
import type { CliProgram } from "../types.ts";
|
|
4
5
|
import { docsTopicContent } from "./resolve.ts";
|
|
5
|
-
import { generatedFileHtmlComment, insertGeneratedHint } from "../skill/hint.ts";
|
|
6
6
|
|
|
7
7
|
/** Relative output directory for `docs --save`. */
|
|
8
8
|
export const DOCS_SAVE_DIR = "docs";
|
|
@@ -21,12 +21,20 @@ export function docsSaveGeneratedHint(program: CliProgram, topic: string): strin
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
/** Inserts save hint without breaking YAML frontmatter (`docs skill`). */
|
|
24
|
-
export function applySaveGeneratedHint(
|
|
24
|
+
export function applySaveGeneratedHint(
|
|
25
|
+
program: CliProgram,
|
|
26
|
+
topic: string,
|
|
27
|
+
content: string,
|
|
28
|
+
): string {
|
|
25
29
|
if (!docsTopicIsGeneratedByArgsbarg(topic)) {
|
|
26
30
|
return content;
|
|
27
31
|
}
|
|
28
32
|
const hint = docsSaveGeneratedHint(program, topic);
|
|
29
|
-
return insertGeneratedHint(
|
|
33
|
+
return insertGeneratedHint(
|
|
34
|
+
content,
|
|
35
|
+
hint,
|
|
36
|
+
topic === "skill" ? { afterFrontmatter: true } : undefined,
|
|
37
|
+
);
|
|
30
38
|
}
|
|
31
39
|
|
|
32
40
|
/** File body for `--save` (hint on argsbarg-generated markdown only). */
|