argsbarg 7.0.5 → 7.0.7
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 +22 -1
- package/README.md +3 -3
- package/docs/README.md +1 -1
- package/docs/ai-skills.md +14 -59
- package/docs/bundled-docs.md +11 -15
- package/docs/cli-program.md +11 -12
- package/docs/configure.md +9 -11
- package/docs/output-schema.md +0 -1
- package/examples/full-example/AGENTS.md +3 -1
- package/examples/full-example/docs/README.md +1 -1
- package/examples/full-example/docs/http.md +1 -1
- package/examples/full-example/docs/mcp.md +1 -1
- package/examples/full-example/docs/openapi.json +1 -6
- package/examples/full-example/justfile +0 -1
- package/examples/full-example/{docs/skill.md → skills/full-example/SKILL.md} +10 -8
- package/examples/full-example/src/program.ts +0 -1
- package/examples/full-example-json/AGENTS.md +3 -1
- package/examples/full-example-json/docs/README.md +1 -1
- package/examples/full-example-json/docs/http.md +1 -1
- package/examples/full-example-json/docs/mcp.md +5 -5
- package/examples/full-example-json/docs/openapi.json +1 -6
- package/examples/full-example-json/justfile +0 -1
- package/examples/full-example-json/{docs/skill.md → skills/full-example-json/SKILL.md} +15 -13
- package/examples/full-example-json/src/program.ts +0 -1
- package/index.d.ts +5 -3
- package/package.json +1 -1
- package/src/builtins/builtins.test.ts +1 -22
- package/src/builtins/configure-copy.ts +4 -11
- package/src/builtins/presentation.ts +2 -5
- package/src/cli-tool/create.test.ts +1 -0
- package/src/cli-tool/create.ts +5 -1
- package/src/configure/artifacts/status.test.ts +5 -5
- package/src/configure/artifacts/target-effective.ts +1 -2
- package/src/configure/artifacts/target-skill.ts +9 -15
- package/src/configure/artifacts/targets/skill.ts +8 -1
- package/src/configure/artifacts/targets.test.ts +5 -5
- package/src/configure/configure.test.ts +4 -4
- package/src/core/parse.test.ts +1 -93
- package/src/core/types.ts +5 -3
- package/src/core/validate.ts +4 -2
- package/src/docs/builtin.ts +5 -3
- package/src/docs/cli-guide.ts +3 -3
- package/src/docs/docs.test.ts +3 -45
- package/src/docs/resolve.ts +5 -5
- package/src/docs/save.ts +52 -15
- package/src/help.test.ts +6 -7
- package/src/skill/generate.ts +32 -154
- package/src/skill/hint.ts +6 -32
- package/src/skill/install.ts +10 -31
package/src/docs/docs.test.ts
CHANGED
|
@@ -76,9 +76,6 @@ test("docs rejects reserved topic keys", () => {
|
|
|
76
76
|
docs.topics["cli-schema"] = { text: "nope" };
|
|
77
77
|
expect(() => cliValidateProgram(root)).toThrow(/reserved/);
|
|
78
78
|
delete docs.topics["cli-schema"];
|
|
79
|
-
docs.topics.skill = { text: "nope" };
|
|
80
|
-
expect(() => cliValidateProgram(root)).toThrow(/reserved/);
|
|
81
|
-
delete docs.topics.skill;
|
|
82
79
|
docs.topics.cli = { text: "nope" };
|
|
83
80
|
expect(() => cliValidateProgram(root)).toThrow(/reserved/);
|
|
84
81
|
delete docs.topics.cli;
|
|
@@ -128,9 +125,6 @@ test("built-in docs work without topics", async () => {
|
|
|
128
125
|
const cliRef = await new Cli(root).invoke(["docs", "cli"]);
|
|
129
126
|
expect(cliRef.exitCode).toBe(0);
|
|
130
127
|
expect(cliRef.stdout).toContain("CLI API reference");
|
|
131
|
-
const skill = await new Cli(root).invoke(["docs", "skill"]);
|
|
132
|
-
expect(skill.exitCode).toBe(0);
|
|
133
|
-
expect(skill.stdout).toContain("name: myapp");
|
|
134
128
|
});
|
|
135
129
|
|
|
136
130
|
test("bare docs shows router help", () => {
|
|
@@ -253,40 +247,14 @@ test("skipsRequiredAppConfigExit includes docs and config builtins", () => {
|
|
|
253
247
|
expect(skipsRequiredAppConfigExit(["run"], caps)).toBe(false);
|
|
254
248
|
});
|
|
255
249
|
|
|
256
|
-
test("docs
|
|
257
|
-
const result = await new Cli(docsFixture()).invoke(["docs", "skill"]);
|
|
258
|
-
expect(result.exitCode).toBe(0);
|
|
259
|
-
expect(result.stdout).toContain("---");
|
|
260
|
-
expect(result.stdout).toContain("name: myapp");
|
|
261
|
-
expect(result.stdout).toContain("## Commands");
|
|
262
|
-
expect(result.stdout).toContain("For full detail, open `reference.md`");
|
|
263
|
-
expect(result.stdout).not.toContain("#### Options");
|
|
264
|
-
expect(result.stdout).not.toContain("mcp.json");
|
|
265
|
-
});
|
|
266
|
-
|
|
267
|
-
/** Docs skill help recommends configure. */
|
|
268
|
-
test("docs skill help recommends configure", async () => {
|
|
269
|
-
const presentation = cliPresentationRoot(docsFixture());
|
|
270
|
-
const docsNode = presentation.commands.find((c) => c.key === "docs");
|
|
271
|
-
expect(docsNode && "commands" in docsNode).toBe(true);
|
|
272
|
-
if (docsNode && "commands" in docsNode) {
|
|
273
|
-
const skill = docsNode.commands.find((c) => c.key === "skill");
|
|
274
|
-
expect(skill?.description).toContain("reference agent SKILL");
|
|
275
|
-
expect(skill?.description).toContain("configure");
|
|
276
|
-
expect(skill?.notes).toBeUndefined();
|
|
277
|
-
expect(docsNode.notes).toContain("--save");
|
|
278
|
-
expect(docsNode.notes).not.toContain("install --skill");
|
|
279
|
-
}
|
|
280
|
-
});
|
|
281
|
-
|
|
282
|
-
test("presentation includes docs cli-schema and skill", () => {
|
|
250
|
+
test("presentation includes docs cli-schema and cli without skill", () => {
|
|
283
251
|
const presentation = cliPresentationRoot(docsFixture());
|
|
284
252
|
const docsNode = presentation.commands.find((c) => c.key === "docs");
|
|
285
253
|
expect(docsNode && "commands" in docsNode).toBe(true);
|
|
286
254
|
if (docsNode && "commands" in docsNode) {
|
|
287
255
|
expect(docsNode.commands.some((c) => c.key === "cli-schema")).toBe(true);
|
|
288
256
|
expect(docsNode.commands.some((c) => c.key === "cli")).toBe(true);
|
|
289
|
-
expect(docsNode.commands.some((c) => c.key === "skill")).toBe(
|
|
257
|
+
expect(docsNode.commands.some((c) => c.key === "skill")).toBe(false);
|
|
290
258
|
}
|
|
291
259
|
});
|
|
292
260
|
|
|
@@ -296,7 +264,7 @@ test("completions offer docs subcommands", () => {
|
|
|
296
264
|
expect(bash).toContain("readme) echo");
|
|
297
265
|
expect(bash).toContain("cli-schema) echo");
|
|
298
266
|
expect(bash).toContain("cli) echo");
|
|
299
|
-
expect(bash).toContain("skill) echo");
|
|
267
|
+
expect(bash).not.toContain("skill) echo");
|
|
300
268
|
});
|
|
301
269
|
|
|
302
270
|
test("generateMcpGuide includes schema URI and .agents install", () => {
|
|
@@ -329,16 +297,6 @@ test("docs cli --save prepends generated hint", async () => {
|
|
|
329
297
|
expect(text).toContain("CLI API reference");
|
|
330
298
|
});
|
|
331
299
|
|
|
332
|
-
test("docs skill --save keeps frontmatter first", async () => {
|
|
333
|
-
const result = await new Cli(docsFixture()).invoke(["docs", "skill", "--save"]);
|
|
334
|
-
expect(result.exitCode).toBe(0);
|
|
335
|
-
const text = readFileSync(join(workDir, "docs/skill.md"), "utf8");
|
|
336
|
-
expect(text.startsWith("---\n")).toBe(true);
|
|
337
|
-
expect(text).toContain("name: myapp");
|
|
338
|
-
const hint = "<!-- Generated by myapp docs skill --save; do not edit. -->";
|
|
339
|
-
expect(text.indexOf(hint)).toBeGreaterThan(text.indexOf("---\n", 4));
|
|
340
|
-
});
|
|
341
|
-
|
|
342
300
|
test("docs cli-schema --save writes JSON file", async () => {
|
|
343
301
|
const result = await new Cli(docsFixture()).invoke(["docs", "cli-schema", "--save"]);
|
|
344
302
|
expect(result.exitCode).toBe(0);
|
package/src/docs/resolve.ts
CHANGED
|
@@ -1,13 +1,16 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This module resolves and prints bundled documentation topics for the `docs` built-in.
|
|
3
|
+
*/
|
|
4
|
+
|
|
1
5
|
import { cliSchemaJson } from "../core/schema.ts";
|
|
2
6
|
import type { CliDocsConfig, CliProgram } from "../core/types.ts";
|
|
3
7
|
import { openApiJson } from "../http/openapi.ts";
|
|
4
|
-
import { generateSkillBundle } from "../skill/generate.ts";
|
|
5
8
|
import { generateCliGuide } from "./cli-guide.ts";
|
|
6
9
|
import { generateHttpGuide } from "./http-guide.ts";
|
|
7
10
|
import { generateMcpGuide } from "./mcp-guide.ts";
|
|
8
11
|
|
|
9
12
|
/** Built-in docs subcommand keys not allowed in `docs.topics`. */
|
|
10
|
-
export const DOCS_BUILTIN_TOPIC_KEYS = ["http", "mcp", "all", "cli-schema", "cli", "
|
|
13
|
+
export const DOCS_BUILTIN_TOPIC_KEYS = ["http", "mcp", "all", "cli-schema", "cli", "openapi"] as const;
|
|
11
14
|
|
|
12
15
|
export type DocsBuiltinTopicKey = (typeof DOCS_BUILTIN_TOPIC_KEYS)[number];
|
|
13
16
|
|
|
@@ -98,9 +101,6 @@ export function docsTopicContent(program: CliProgram, topic: string): string {
|
|
|
98
101
|
if (topic === "cli") {
|
|
99
102
|
return generateCliGuide(program);
|
|
100
103
|
}
|
|
101
|
-
if (topic === "skill") {
|
|
102
|
-
return `${generateSkillBundle(program).skillMd}\n`;
|
|
103
|
-
}
|
|
104
104
|
const text = docsTopicText(program, topic);
|
|
105
105
|
return text.endsWith("\n") ? text : `${text}\n`;
|
|
106
106
|
}
|
package/src/docs/save.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This module persists bundled documentation topics to disk when `--save` is passed.
|
|
3
|
+
It writes documentation under `./docs/`.
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
-
import { join } from "node:path";
|
|
7
|
+
import { dirname, join } from "node:path";
|
|
3
8
|
import type { CliProgram } from "../core/types.ts";
|
|
4
9
|
import { generatedFileHtmlComment, insertGeneratedHint } from "../skill/hint.ts";
|
|
5
10
|
import { docsTopicContent } from "./resolve.ts";
|
|
@@ -8,34 +13,57 @@ import { docsTopicContent } from "./resolve.ts";
|
|
|
8
13
|
export const DOCS_SAVE_DIR = "docs";
|
|
9
14
|
|
|
10
15
|
/** Builtin docs topics generated by argsbarg (not consumer `docs.topics`). */
|
|
11
|
-
export const DOCS_GENERATED_SAVE_TOPICS = ["mcp", "cli", "
|
|
16
|
+
export const DOCS_GENERATED_SAVE_TOPICS = ["mcp", "cli", "http"] as const;
|
|
12
17
|
|
|
13
18
|
/** Whether `--save` should prepend a generated-file hint (argsbarg writers only). */
|
|
14
|
-
export function docsTopicIsGeneratedByArgsbarg(
|
|
19
|
+
export function docsTopicIsGeneratedByArgsbarg(
|
|
20
|
+
/** Topic name. */
|
|
21
|
+
topic: string,
|
|
22
|
+
): boolean {
|
|
15
23
|
return (DOCS_GENERATED_SAVE_TOPICS as readonly string[]).includes(topic);
|
|
16
24
|
}
|
|
17
25
|
|
|
18
26
|
/** HTML comment for generated markdown saved with `--save`. */
|
|
19
|
-
export function docsSaveGeneratedHint(
|
|
27
|
+
export function docsSaveGeneratedHint(
|
|
28
|
+
/** Program definition. */
|
|
29
|
+
program: CliProgram,
|
|
30
|
+
/** Topic name. */
|
|
31
|
+
topic: string,
|
|
32
|
+
): string {
|
|
20
33
|
return generatedFileHtmlComment(`${program.key} docs ${topic} --save`);
|
|
21
34
|
}
|
|
22
35
|
|
|
23
|
-
/** Inserts save hint
|
|
24
|
-
export function applySaveGeneratedHint(
|
|
36
|
+
/** Inserts save hint into markdown content. */
|
|
37
|
+
export function applySaveGeneratedHint(
|
|
38
|
+
/** Program definition. */
|
|
39
|
+
program: CliProgram,
|
|
40
|
+
/** Topic name. */
|
|
41
|
+
topic: string,
|
|
42
|
+
/** Markdown text. */
|
|
43
|
+
content: string,
|
|
44
|
+
): string {
|
|
25
45
|
if (!docsTopicIsGeneratedByArgsbarg(topic)) {
|
|
26
46
|
return content;
|
|
27
47
|
}
|
|
28
48
|
const hint = docsSaveGeneratedHint(program, topic);
|
|
29
|
-
return insertGeneratedHint(content, hint
|
|
49
|
+
return insertGeneratedHint(content, hint);
|
|
30
50
|
}
|
|
31
51
|
|
|
32
52
|
/** File body for `--save` (hint on argsbarg-generated markdown only). */
|
|
33
|
-
export function docsTopicContentForSave(
|
|
53
|
+
export function docsTopicContentForSave(
|
|
54
|
+
/** Program definition. */
|
|
55
|
+
program: CliProgram,
|
|
56
|
+
/** Topic name. */
|
|
57
|
+
topic: string,
|
|
58
|
+
): string {
|
|
34
59
|
return applySaveGeneratedHint(program, topic, docsTopicContent(program, topic));
|
|
35
60
|
}
|
|
36
61
|
|
|
37
62
|
/** Filename for a saved docs topic. */
|
|
38
|
-
export function docsSaveFilename(
|
|
63
|
+
export function docsSaveFilename(
|
|
64
|
+
/** Topic name. */
|
|
65
|
+
topic: string,
|
|
66
|
+
): string {
|
|
39
67
|
if (topic === "cli-schema") {
|
|
40
68
|
return "cli-schema.json";
|
|
41
69
|
}
|
|
@@ -46,17 +74,26 @@ export function docsSaveFilename(topic: string): string {
|
|
|
46
74
|
}
|
|
47
75
|
|
|
48
76
|
/** Relative path under cwd for a saved docs topic. */
|
|
49
|
-
export function docsSaveRelativePath(
|
|
77
|
+
export function docsSaveRelativePath(
|
|
78
|
+
/** Topic identifier. */
|
|
79
|
+
topic: string,
|
|
80
|
+
/** Program root for resolving app-specific paths. */
|
|
81
|
+
_program?: CliProgram,
|
|
82
|
+
): string {
|
|
50
83
|
return join(DOCS_SAVE_DIR, docsSaveFilename(topic));
|
|
51
84
|
}
|
|
52
85
|
|
|
53
86
|
/** Writes one docs topic under `./docs/`; returns relative path written. */
|
|
54
|
-
export function saveDocsTopic(
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
87
|
+
export function saveDocsTopic(
|
|
88
|
+
/** Program definition root. */
|
|
89
|
+
program: CliProgram,
|
|
90
|
+
/** Topic identifier to save. */
|
|
91
|
+
topic: string,
|
|
92
|
+
): string {
|
|
93
|
+
const rel = docsSaveRelativePath(topic, program);
|
|
59
94
|
const abs = join(process.cwd(), rel);
|
|
95
|
+
mkdirSync(dirname(abs), { recursive: true });
|
|
96
|
+
|
|
60
97
|
writeFileSync(abs, docsTopicContentForSave(program, topic), "utf8");
|
|
61
98
|
return rel;
|
|
62
99
|
}
|
package/src/help.test.ts
CHANGED
|
@@ -64,7 +64,7 @@ describe("cliResolveNotes", () => {
|
|
|
64
64
|
});
|
|
65
65
|
|
|
66
66
|
describe("cliHelpRender", () => {
|
|
67
|
-
test("docs help lists schema
|
|
67
|
+
test("docs help lists schema and cli subcommands", () => {
|
|
68
68
|
const root = testProgram({
|
|
69
69
|
key: "app",
|
|
70
70
|
version: "1.0.0",
|
|
@@ -85,8 +85,7 @@ describe("cliHelpRender", () => {
|
|
|
85
85
|
expect(help).toContain("Print the full CLI command tree as JSON.");
|
|
86
86
|
expect(help).toContain("cli");
|
|
87
87
|
expect(help).toContain("markdown");
|
|
88
|
-
expect(help).toContain("skill");
|
|
89
|
-
expect(help).toContain("reference agent SKILL");
|
|
88
|
+
expect(help).not.toContain("skill");
|
|
90
89
|
});
|
|
91
90
|
|
|
92
91
|
test("root help omits legacy --schema flag", () => {
|
|
@@ -106,7 +105,7 @@ describe("cliHelpRender", () => {
|
|
|
106
105
|
expect(help).not.toContain("--schema");
|
|
107
106
|
});
|
|
108
107
|
|
|
109
|
-
test("root help
|
|
108
|
+
test("root help omits agent docs hint when docs enabled", () => {
|
|
110
109
|
const root = testProgram({
|
|
111
110
|
key: "myapp",
|
|
112
111
|
version: "1.0.0",
|
|
@@ -117,7 +116,7 @@ describe("cliHelpRender", () => {
|
|
|
117
116
|
commands: [{ key: "run", description: "Run.", handler: () => {} }],
|
|
118
117
|
});
|
|
119
118
|
const help = cliHelpRender(cliPresentationRoot(root), [], false);
|
|
120
|
-
expect(help).toContain("
|
|
119
|
+
expect(help).not.toContain("docs skill");
|
|
121
120
|
expect(help).not.toContain("install --skill");
|
|
122
121
|
});
|
|
123
122
|
|
|
@@ -134,7 +133,7 @@ describe("cliHelpRender", () => {
|
|
|
134
133
|
expect(help).not.toContain("docs skill");
|
|
135
134
|
});
|
|
136
135
|
|
|
137
|
-
test("root help includes program notes
|
|
136
|
+
test("root help includes program notes", () => {
|
|
138
137
|
const root = testProgram({
|
|
139
138
|
key: "myapp",
|
|
140
139
|
version: "1.0.0",
|
|
@@ -147,6 +146,6 @@ describe("cliHelpRender", () => {
|
|
|
147
146
|
});
|
|
148
147
|
const help = cliHelpRender(cliPresentationRoot(root), [], false);
|
|
149
148
|
expect(help).toContain("See `myapp docs readme` for the user guide.");
|
|
150
|
-
expect(help).toContain("
|
|
149
|
+
expect(help).not.toContain("docs skill");
|
|
151
150
|
});
|
|
152
151
|
});
|
package/src/skill/generate.ts
CHANGED
|
@@ -1,29 +1,22 @@
|
|
|
1
1
|
/*
|
|
2
|
-
This module generates
|
|
2
|
+
This module generates the MCP routing skill (SKILL.md) for Claude Code plugin zips.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { defaultConfigEntryTitle } from "../config/entry.ts";
|
|
6
|
-
import {
|
|
7
|
-
import { generateCliGuide } from "../docs/cli-guide.ts";
|
|
6
|
+
import type { CliProgram } from "../core/types.ts";
|
|
8
7
|
import {
|
|
9
8
|
collectMcpTools,
|
|
10
9
|
leafWireOptions,
|
|
11
|
-
type McpToolDef,
|
|
12
10
|
mcpServerId,
|
|
13
11
|
resolveMcpSchemaUri,
|
|
14
12
|
sanitizeToolSegment,
|
|
15
13
|
} from "../mcp/tools.ts";
|
|
16
|
-
import { skillDirName } from "./naming.ts";
|
|
17
|
-
|
|
18
|
-
export interface SkillBundle {
|
|
19
|
-
dirName: string;
|
|
20
|
-
skillMd: string;
|
|
21
|
-
referenceMd: string;
|
|
22
|
-
}
|
|
23
14
|
|
|
24
15
|
/** MCP routing skill for Claude Code plugin zips (SKILL.md only). */
|
|
25
16
|
export interface PluginSkillBundle {
|
|
17
|
+
/** Target directory name under `skills/`. */
|
|
26
18
|
dirName: string;
|
|
19
|
+
/** Generated plugin SKILL.md content. */
|
|
27
20
|
skillMd: string;
|
|
28
21
|
}
|
|
29
22
|
|
|
@@ -43,168 +36,63 @@ function pluginSkillDescription(root: CliProgram): string {
|
|
|
43
36
|
return truncate(desc, 1024);
|
|
44
37
|
}
|
|
45
38
|
|
|
46
|
-
/** Builds
|
|
47
|
-
function skillDescription(root: CliProgram): string {
|
|
48
|
-
const tools = collectMcpTools(root);
|
|
49
|
-
const paths = tools.map((t) => (t.path.length > 0 ? t.path.join(" ") : root.key));
|
|
50
|
-
const sample = paths.slice(0, 5).join(", ");
|
|
51
|
-
const more = paths.length > 5 ? `, and ${paths.length - 5} more` : "";
|
|
52
|
-
const desc = `Operates the ${root.key} CLI (${sample}${more}). Use when the user mentions ${root.key}${paths.length > 0 ? `, ${paths.slice(0, 3).join(", ")}` : ""}, or related tasks.`;
|
|
53
|
-
return truncate(desc, 1024);
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
/** CLI path with required single-slot positionals for the compact catalog. */
|
|
57
|
-
function commandCatalogPath(root: CliProgram, tool: McpToolDef): string {
|
|
58
|
-
const base = tool.path.length > 0 ? `${root.key} ${tool.path.join(" ")}` : root.key;
|
|
59
|
-
const slots = (tool.leaf.positionals ?? [])
|
|
60
|
-
.filter((p) => (p.argMin ?? 1) > 0 && (p.argMax ?? 1) === 1)
|
|
61
|
-
.map((p) => `<${p.name}>`);
|
|
62
|
-
if (slots.length === 0) {
|
|
63
|
-
return base;
|
|
64
|
-
}
|
|
65
|
-
return `${base} ${slots.join(" ")}`;
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/** Formats one command line for the SKILL.md index (details live in reference.md). */
|
|
69
|
-
function formatCommandEntry(root: CliProgram, tool: McpToolDef): string {
|
|
70
|
-
const cliPath = commandCatalogPath(root, tool);
|
|
71
|
-
let line = `- **\`${cliPath}\`** — ${tool.leaf.description}`;
|
|
72
|
-
const opts = leafWireOptions(tool.leaf);
|
|
73
|
-
const flags = opts.filter((o) => o.kind === CliOptionKind.Presence).map((o) => `--${o.name}`);
|
|
74
|
-
if (flags.length > 0) {
|
|
75
|
-
line += ` (flags: ${flags.join(", ")})`;
|
|
76
|
-
}
|
|
77
|
-
const enums = opts.filter((o) => o.kind === CliOptionKind.Enum && o.choices?.length);
|
|
78
|
-
for (const e of enums) {
|
|
79
|
-
line += ` (\`--${e.name}\`: ${e.choices?.join(" | ")})`;
|
|
80
|
-
}
|
|
81
|
-
const varargs = (tool.leaf.positionals ?? []).filter((p) => (p.argMax ?? 1) === 0);
|
|
82
|
-
if (varargs.length > 0) {
|
|
83
|
-
line += ` (varargs: ${varargs.map((p) => p.name).join(", ")})`;
|
|
84
|
-
}
|
|
85
|
-
return line;
|
|
86
|
-
}
|
|
87
|
-
|
|
39
|
+
/** Builds configuration section lines for YAML and markdown. */
|
|
88
40
|
function buildConfigurationSection(root: CliProgram): string[] {
|
|
89
|
-
|
|
90
|
-
if (!schema || Object.keys(schema).length === 0) {
|
|
41
|
+
if (!root.appConfig || Object.keys(root.appConfig.entries).length === 0) {
|
|
91
42
|
return [];
|
|
92
43
|
}
|
|
93
|
-
const
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
const
|
|
97
|
-
|
|
44
|
+
const entries = root.appConfig.entries;
|
|
45
|
+
const lines: string[] = ["## Configuration", ""];
|
|
46
|
+
for (const name of Object.keys(entries).sort()) {
|
|
47
|
+
const entry = entries[name];
|
|
48
|
+
if (!entry) continue;
|
|
49
|
+
const title = defaultConfigEntryTitle(name);
|
|
50
|
+
const envStr = entry.env ? ` (env: \`${entry.env}\`)` : "";
|
|
51
|
+
const desc = entry.description ? ` — ${entry.description}` : "";
|
|
52
|
+
lines.push(`- **${name}** (\`${title}\`${envStr})${desc}`);
|
|
98
53
|
}
|
|
99
54
|
lines.push("");
|
|
100
55
|
return lines;
|
|
101
56
|
}
|
|
102
57
|
|
|
103
|
-
/** Builds SKILL.md
|
|
104
|
-
function
|
|
105
|
-
const name = dirName;
|
|
106
|
-
const description = skillDescription(root);
|
|
107
|
-
const tools = collectMcpTools(root);
|
|
108
|
-
|
|
58
|
+
/** Builds SKILL.md for Claude Code plugin zips (MCP routing only). */
|
|
59
|
+
function buildPluginSkillMd(root: CliProgram, dirName: string): string {
|
|
109
60
|
const lines: string[] = [
|
|
110
61
|
"---",
|
|
111
|
-
`
|
|
112
|
-
`
|
|
113
|
-
`description: ${description}`,
|
|
114
|
-
"enabled: true",
|
|
62
|
+
`name: ${dirName}`,
|
|
63
|
+
`description: ${pluginSkillDescription(root)}`,
|
|
115
64
|
"---",
|
|
116
65
|
"",
|
|
117
66
|
`# ${root.key}`,
|
|
118
67
|
"",
|
|
119
68
|
root.description,
|
|
120
69
|
"",
|
|
121
|
-
"##
|
|
70
|
+
"## MCP Tools",
|
|
122
71
|
"",
|
|
123
|
-
|
|
72
|
+
`Server id: \`${mcpServerId(root)}\``,
|
|
124
73
|
"",
|
|
125
|
-
"
|
|
126
|
-
`${root.key} <subcommand> [options] [args]`,
|
|
127
|
-
"```",
|
|
74
|
+
"Prefer using MCP tools over terminal commands when available.",
|
|
128
75
|
"",
|
|
129
|
-
|
|
76
|
+
`- Run \`tools/list\` against \`${mcpServerId(root)}\` to discover tools.`,
|
|
77
|
+
`- Read schema resource \`${resolveMcpSchemaUri(root)}\` for types.`,
|
|
130
78
|
"",
|
|
131
79
|
];
|
|
132
80
|
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
81
|
+
const tools = collectMcpTools(root);
|
|
82
|
+
if (tools.length > 0) {
|
|
83
|
+
lines.push("### Available tools", "");
|
|
136
84
|
for (const tool of tools) {
|
|
137
|
-
|
|
85
|
+
const toolName = sanitizeToolSegment(tool.path.join("_"));
|
|
86
|
+
const desc = tool.leaf.description;
|
|
87
|
+
const wire = leafWireOptions(tool.leaf);
|
|
88
|
+
const flags = wire.length > 0 ? ` (flags: ${wire.map((o) => `--${o.name}`).join(", ")})` : "";
|
|
89
|
+
lines.push(`- \`${toolName}\` — ${desc}${flags}`);
|
|
138
90
|
}
|
|
139
91
|
lines.push("");
|
|
140
92
|
}
|
|
141
93
|
|
|
142
94
|
lines.push(...buildConfigurationSection(root));
|
|
143
95
|
|
|
144
|
-
lines.push(
|
|
145
|
-
"## Pitfalls",
|
|
146
|
-
"",
|
|
147
|
-
"- Pass `--` before arguments that look like flags.",
|
|
148
|
-
"",
|
|
149
|
-
"## Reference",
|
|
150
|
-
"",
|
|
151
|
-
`For full detail, open \`reference.md\` in this skill directory (same as \`${root.key} docs cli\`).`,
|
|
152
|
-
"",
|
|
153
|
-
"## Install location",
|
|
154
|
-
"",
|
|
155
|
-
"Install follows the https://dotagentsprotocol.com:",
|
|
156
|
-
"",
|
|
157
|
-
`- Auto-install: \`${root.key} configure install\` when \`skill.enabled\` → \`~/.agents/skills/${dirName}/\``,
|
|
158
|
-
`- Cursor and most coding agents read \`~/.agents/skills/\` natively`,
|
|
159
|
-
"",
|
|
160
|
-
"**Claude Code (manual):** symlink or copy into Claude's skill directory:",
|
|
161
|
-
"",
|
|
162
|
-
"```bash",
|
|
163
|
-
"mkdir -p ~/.claude/skills",
|
|
164
|
-
`ln -sf ~/.agents/skills/${dirName} ~/.claude/skills/${dirName}`,
|
|
165
|
-
"```",
|
|
166
|
-
"",
|
|
167
|
-
`Project override (optional): \`.agents/skills/${dirName}/\``,
|
|
168
|
-
"",
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
return lines.join("\n");
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
/** Builds reference.md with the compact `docs cli` markdown guide. */
|
|
175
|
-
function buildReferenceMd(root: CliProgram): string {
|
|
176
|
-
return generateCliGuide(root, { compact: true });
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
/** Builds MCP routing SKILL.md for Claude Code plugin zips. */
|
|
180
|
-
function buildPluginSkillMd(root: CliProgram, dirName: string): string {
|
|
181
|
-
const name = sanitizeToolSegment(root.key);
|
|
182
|
-
const description = pluginSkillDescription(root);
|
|
183
|
-
const serverId = mcpServerId(root);
|
|
184
|
-
const schemaUri = resolveMcpSchemaUri(root);
|
|
185
|
-
|
|
186
|
-
const lines: string[] = [
|
|
187
|
-
"---",
|
|
188
|
-
`name: ${name}`,
|
|
189
|
-
`description: ${description}`,
|
|
190
|
-
"---",
|
|
191
|
-
"",
|
|
192
|
-
`# ${root.key}`,
|
|
193
|
-
"",
|
|
194
|
-
root.description,
|
|
195
|
-
"",
|
|
196
|
-
"## Execution",
|
|
197
|
-
"",
|
|
198
|
-
"This plugin bundles an MCP server. Use MCP tools to fulfill requests.",
|
|
199
|
-
"",
|
|
200
|
-
`- Server id: \`${serverId}\` (configured in plugin \`.mcp.json\`)`,
|
|
201
|
-
"- Tool names and argument shapes come from MCP `tools/list`",
|
|
202
|
-
`- Full schema: \`${schemaUri}\` (same as \`${root.key} docs cli-schema\`)`,
|
|
203
|
-
"",
|
|
204
|
-
];
|
|
205
|
-
|
|
206
|
-
lines.push(...buildConfigurationSection(root));
|
|
207
|
-
|
|
208
96
|
lines.push(
|
|
209
97
|
"## Claude Code plugin",
|
|
210
98
|
"",
|
|
@@ -223,13 +111,3 @@ export function generatePluginSkillBundle(root: CliProgram): PluginSkillBundle {
|
|
|
223
111
|
skillMd: buildPluginSkillMd(root, dirName),
|
|
224
112
|
};
|
|
225
113
|
}
|
|
226
|
-
|
|
227
|
-
/** Generates SKILL.md and reference.md for agent skill install. */
|
|
228
|
-
export function generateSkillBundle(root: CliProgram): SkillBundle {
|
|
229
|
-
const dirName = skillDirName(root.key);
|
|
230
|
-
return {
|
|
231
|
-
dirName,
|
|
232
|
-
skillMd: buildSkillMd(root, dirName),
|
|
233
|
-
referenceMd: buildReferenceMd(root),
|
|
234
|
-
};
|
|
235
|
-
}
|
package/src/skill/hint.ts
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
|
+
/*
|
|
2
|
+
This module provides HTML comment hints embedded in generated documentation
|
|
3
|
+
and plugin artifacts to mark them as machine-generated.
|
|
4
|
+
*/
|
|
5
|
+
|
|
1
6
|
import type { CliProgram } from "../core/types.ts";
|
|
2
7
|
|
|
3
|
-
/** YAML frontmatter block at the start of
|
|
8
|
+
/** YAML frontmatter block at the start of markdown files. */
|
|
4
9
|
export const MARKDOWN_FRONTMATTER_RE = /^---\r?\n[\s\S]*?\r?\n---\r?\n/;
|
|
5
10
|
|
|
6
11
|
/** HTML comment marking argsbarg-generated markdown. */
|
|
@@ -19,42 +24,11 @@ export function insertGeneratedHint(content: string, hint: string, options?: { a
|
|
|
19
24
|
return `${hint}${content}`;
|
|
20
25
|
}
|
|
21
26
|
|
|
22
|
-
/** Hint for `configure` skill output files. */
|
|
23
|
-
export function skillInstallHint(program: CliProgram): string {
|
|
24
|
-
return generatedFileHtmlComment(`${program.key} configure`);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
/** Applies install hints to SKILL.md (after frontmatter) and reference.md. */
|
|
28
|
-
export function applySkillInstallHints(
|
|
29
|
-
program: CliProgram,
|
|
30
|
-
skillMd: string,
|
|
31
|
-
referenceMd: string,
|
|
32
|
-
): { skillMd: string; referenceMd: string } {
|
|
33
|
-
const hint = skillInstallHint(program);
|
|
34
|
-
return {
|
|
35
|
-
skillMd: insertGeneratedHint(skillMd, hint, { afterFrontmatter: true }),
|
|
36
|
-
referenceMd: insertGeneratedHint(referenceMd, hint),
|
|
37
|
-
};
|
|
38
|
-
}
|
|
39
|
-
|
|
40
27
|
/** Hint for `mcp bundle` plugin skill output. */
|
|
41
28
|
export function skillBundleHint(program: CliProgram): string {
|
|
42
29
|
return generatedFileHtmlComment(`${program.key} mcp bundle`);
|
|
43
30
|
}
|
|
44
31
|
|
|
45
|
-
/** Applies bundle hints to SKILL.md (after frontmatter) and reference.md. */
|
|
46
|
-
export function applySkillBundleHints(
|
|
47
|
-
program: CliProgram,
|
|
48
|
-
skillMd: string,
|
|
49
|
-
referenceMd: string,
|
|
50
|
-
): { skillMd: string; referenceMd: string } {
|
|
51
|
-
const hint = skillBundleHint(program);
|
|
52
|
-
return {
|
|
53
|
-
skillMd: insertGeneratedHint(skillMd, hint, { afterFrontmatter: true }),
|
|
54
|
-
referenceMd: insertGeneratedHint(referenceMd, hint),
|
|
55
|
-
};
|
|
56
|
-
}
|
|
57
|
-
|
|
58
32
|
/** Applies bundle hint to plugin SKILL.md (after frontmatter). */
|
|
59
33
|
export function applyPluginSkillHint(program: CliProgram, skillMd: string): string {
|
|
60
34
|
return insertGeneratedHint(skillMd, skillBundleHint(program), { afterFrontmatter: true });
|
package/src/skill/install.ts
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
/*
|
|
2
|
+
This module provides paths and helpers for agent skill directories (~/.agents/skills/<key>/).
|
|
3
|
+
Skill generation is removed; skills are authored directly in repositories under skills/<app>/SKILL.md.
|
|
4
|
+
*/
|
|
5
|
+
|
|
2
6
|
import { join } from "node:path";
|
|
3
7
|
import type { CliProgram } from "../core/types.ts";
|
|
4
|
-
import {
|
|
5
|
-
import { generateSkillBundle } from "./generate.ts";
|
|
6
|
-
import { applySkillInstallHints } from "./hint.ts";
|
|
8
|
+
import { userHome } from "../paths/host.ts";
|
|
7
9
|
import { skillDirName } from "./naming.ts";
|
|
8
10
|
|
|
9
11
|
export { skillDirName } from "./naming.ts";
|
|
10
12
|
|
|
13
|
+
/** Options for agent skill installation. */
|
|
11
14
|
export interface SkillInstallOpts {
|
|
15
|
+
/** When true, installs to user home ~/.agents/skills/<key>/; otherwise project .agents/skills/<key>/. */
|
|
12
16
|
global?: boolean;
|
|
17
|
+
/** When true, removes existing directory before installing. */
|
|
13
18
|
rimraf?: boolean;
|
|
19
|
+
/** When true, computes file paths without writing to disk. */
|
|
14
20
|
dry?: boolean;
|
|
15
21
|
}
|
|
16
22
|
|
|
@@ -20,33 +26,6 @@ export function resolveAgentsSkillDir(root: CliProgram, global = true): string {
|
|
|
20
26
|
return join(base, ".agents", "skills", skillDirName(root.key));
|
|
21
27
|
}
|
|
22
28
|
|
|
23
|
-
/** Writes skill.md, SKILL.md (compatibility copy), and reference.md; returns changed file paths. */
|
|
24
|
-
export function cliSkillInstall(root: CliProgram, opts: SkillInstallOpts): string[] {
|
|
25
|
-
const bundle = generateSkillBundle(root);
|
|
26
|
-
const { skillMd, referenceMd } = applySkillInstallHints(root, bundle.skillMd, bundle.referenceMd);
|
|
27
|
-
const dir = resolveAgentsSkillDir(root, opts.global ?? true);
|
|
28
|
-
const changed: string[] = [];
|
|
29
|
-
|
|
30
|
-
if (opts.rimraf && existsSync(dir) && !opts.dry) {
|
|
31
|
-
rmSync(dir, { recursive: true, force: true });
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
const skillPath = join(dir, "skill.md");
|
|
35
|
-
const skillCompatPath = join(dir, "SKILL.md");
|
|
36
|
-
const refPath = join(dir, "reference.md");
|
|
37
|
-
|
|
38
|
-
if (!opts.dry) {
|
|
39
|
-
mkdirSync(dir, { recursive: true });
|
|
40
|
-
writeFileSync(skillPath, skillMd, "utf8");
|
|
41
|
-
writeFileSync(skillCompatPath, skillMd, "utf8");
|
|
42
|
-
writeFileSync(refPath, referenceMd, "utf8");
|
|
43
|
-
process.stdout.write(`Installed skill to ${displayHomePath(dir)}/\n`);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
changed.push(skillPath, skillCompatPath, refPath);
|
|
47
|
-
return changed;
|
|
48
|
-
}
|
|
49
|
-
|
|
50
29
|
/** True when the plan action kind installs the agent skill bundle. */
|
|
51
30
|
export function isAgentSkillActionKind(kind: string): boolean {
|
|
52
31
|
return kind === "agent-skill";
|