argsbarg 3.3.12 → 3.3.13

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 CHANGED
@@ -7,6 +7,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [3.3.13] - 2026-06-21
11
+
12
+ ### Changed
13
+
14
+ - **Agent skills** — `SKILL.md` is a compact command index; `reference.md` holds the full `docs api` guide. `docs skill` notes recommend `install --skill` for the optimized persisted bundle.
15
+
10
16
  ## [3.3.12] - 2026-06-21
11
17
 
12
18
  ### Changed
@@ -323,7 +329,8 @@ const cli = { ... } satisfies CliProgram; // or : CliProgram
323
329
  - Migrate schemas: rename every `children` property to **`commands`**; move positional definitions to **`CliPositional`** objects on `positionals` and strip `positional` / `argMin` / `argMax` from flag definitions under `options` (flags only carry `name`, `description`, `kind`, and optional `shortName`).
324
330
  - Imports: use `CliPositional` where needed; replace `CliOptionDef` with `CliOption` or `CliPositional` as appropriate.
325
331
 
326
- [Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v3.3.12...HEAD
332
+ [Unreleased]: https://github.com/bdombro/bun-argsbarg/compare/v3.3.13...HEAD
333
+ [3.3.13]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.3.13
327
334
  [3.3.12]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.3.12
328
335
  [3.3.11]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.3.11
329
336
  [3.3.10]: https://github.com/bdombro/bun-argsbarg/releases/tag/v3.3.10
package/docs/ai-skills.md CHANGED
@@ -31,8 +31,8 @@ For library use, call `cliSkillInstall(root, "cursor" | "claude", { global: true
31
31
 
32
32
  ## Generated content
33
33
 
34
- - **`SKILL.md`** — YAML frontmatter, when-to-use guidance, the same command reference as `docs api` (without the API doc header), pitfalls
35
- - **`reference.md`** — full `docs schema` JSON export
34
+ - **`SKILL.md`** — YAML frontmatter, compact command index, pitfalls, and a pointer to `reference.md`
35
+ - **`reference.md`** — full `docs api` markdown reference
36
36
 
37
37
  Installed files include an HTML comment hint (`Generated by myapp install --skill; do not edit.`) after SKILL.md frontmatter and at the top of `reference.md`.
38
38
 
@@ -43,10 +43,10 @@ Skills describe **shell invocation only** — no MCP setup, `mcp.json`, or `tool
43
43
  | Mechanism | Role |
44
44
  | --- | --- |
45
45
  | **`myapp mcp`** (requires `mcpServer`) | Runtime tool execution over MCP |
46
- | **`myapp install --skill`** | Static shell command reference for agents (same body as `docs api`) |
46
+ | **`myapp install --skill`** | Persists optimized skill bundle (`SKILL.md` index + `reference.md` full API) |
47
47
  | **`myapp docs`** (requires `docs`) | Bundled markdown on stdout (`docs mcp` when MCP enabled) |
48
48
 
49
- Command reference in skills reuses the `docs api` command tree. See [cli-program.md](cli-program.md).
49
+ `SKILL.md` is the routing index; `reference.md` matches `docs api`. Prefer `install --skill` over `docs skill` for agents. See [cli-program.md](cli-program.md).
50
50
 
51
51
  See also:
52
52
 
@@ -68,7 +68,7 @@ When `docs.enabled` is `true`:
68
68
 
69
69
  - **`docs schema`** — same JSON as the former root `--schema` flag (handlers omitted; built-in subtrees included for leaf roots).
70
70
  - **`docs api`** — markdown rendering of the same command tree (options, positionals, subcommands, fallback routing).
71
- - **`docs skill`** — prints generated Cursor `SKILL.md` content (same prose as `install --skill`, without writing files).
71
+ - **`docs skill`** — prints the compact `SKILL.md` index. Prefer `install --skill --yes` for agents (persists index + full API in `reference.md`).
72
72
 
73
73
  ## MCP guide (`docs mcp`)
74
74
 
@@ -84,7 +84,7 @@ All `docs` subcommands are hidden from MCP `tools/list` (`mcpTool: { enabled: fa
84
84
 
85
85
  | Channel | Role |
86
86
  | --- | --- |
87
- | `install --skill` | Writes `SKILL.md` (API command reference) + `reference.md` to disk |
87
+ | `install --skill` | Writes compact `SKILL.md` + full-API `reference.md` to disk |
88
88
  | `docs skill` | Print generated `SKILL.md` to stdout |
89
89
  | `docs api` | Print command tree markdown to stdout |
90
90
  | `docs schema` | Print command tree JSON to stdout |
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "argsbarg",
3
- "version": "3.3.12",
3
+ "version": "3.3.13",
4
4
  "type": "module",
5
5
  "engines": {
6
6
  "bun": ">=1.3"
@@ -55,7 +55,20 @@ export function cliBuiltinDocsGroup(program: CliProgram): CliRouter {
55
55
  leaves.push(
56
56
  docsLeaf(program, "schema", "Print the full command tree as JSON."),
57
57
  docsLeaf(program, "api", "Print the command tree as markdown."),
58
- docsLeaf(program, "skill", "Print generated Cursor SKILL.md content."),
58
+ {
59
+ key: "skill",
60
+ description: "Print generated SKILL.md (compact command index).",
61
+ notes: [
62
+ "Prefer `{argsbarg:program} install --skill --yes` for agents: it persists an optimized skill bundle",
63
+ "(`SKILL.md` index + `reference.md` full API) to your skill directory.",
64
+ "`docs skill` prints the index only; use `docs api` or installed `reference.md` for full detail.",
65
+ ].join(" "),
66
+ options: [DOCS_SAVE_OPTION],
67
+ mcpTool: { enabled: false },
68
+ handler: (ctx) => {
69
+ runDocsTopic(program, "skill", ctx);
70
+ },
71
+ },
59
72
  );
60
73
 
61
74
  return {
@@ -152,11 +152,24 @@ test("docs skill prints Cursor SKILL.md", async () => {
152
152
  expect(result.exitCode).toBe(0);
153
153
  expect(result.stdout).toContain("---");
154
154
  expect(result.stdout).toContain("name: myapp");
155
- expect(result.stdout).toContain("#### Options");
156
- expect(result.stdout).not.toContain("## Commands");
155
+ expect(result.stdout).toContain("## Commands");
156
+ expect(result.stdout).toContain("read `reference.md`");
157
+ expect(result.stdout).not.toContain("#### Options");
157
158
  expect(result.stdout).not.toContain("mcp.json");
158
159
  });
159
160
 
161
+ test("docs skill help recommends install --skill", async () => {
162
+ const presentation = cliPresentationRoot(docsFixture());
163
+ const docsNode = presentation.commands.find((c) => c.key === "docs");
164
+ expect(docsNode && "commands" in docsNode).toBe(true);
165
+ if (docsNode && "commands" in docsNode) {
166
+ const skill = docsNode.commands.find((c) => c.key === "skill");
167
+ expect(skill?.description).toContain("compact command index");
168
+ expect(skill?.notes).toContain("install --skill --yes");
169
+ expect(skill?.notes).toContain("reference.md");
170
+ }
171
+ });
172
+
160
173
  test("presentation includes docs schema and skill", () => {
161
174
  const presentation = cliPresentationRoot(docsFixture());
162
175
  const docsNode = presentation.commands.find((c) => c.key === "docs");
package/src/index.test.ts CHANGED
@@ -1808,22 +1808,24 @@ test("install config on non-root node is rejected", () => {
1808
1808
  expect(() => cliValidateProgram(root)).toThrow(/install is only supported on the program root/);
1809
1809
  });
1810
1810
 
1811
- test("generateSkillBundle includes frontmatter and API command reference", () => {
1811
+ test("generateSkillBundle includes frontmatter and compact command index", () => {
1812
1812
  const bundle = generateSkillBundle(nestedMcpFixture, "cursor");
1813
1813
  expect(bundle.dirName).toBe("nested_ts");
1814
1814
  expect(bundle.skillMd).toMatch(/^---\nname: nested_ts\n/);
1815
- expect(bundle.skillMd).toContain("`nested.ts stat owner lookup`");
1816
- expect(bundle.skillMd).toContain("#### Options");
1815
+ expect(bundle.skillMd).toContain("## Commands");
1816
+ expect(bundle.skillMd).toContain("`nested.ts stat owner lookup <path>`");
1817
1817
  expect(bundle.skillMd).toContain("Invoke via shell:");
1818
- expect(bundle.skillMd).not.toContain("## Commands");
1818
+ expect(bundle.skillMd).toContain("read `reference.md`");
1819
+ expect(bundle.skillMd).not.toContain("#### Options");
1819
1820
  expect(bundle.skillMd).not.toContain("CLI API reference");
1820
1821
  expect(bundle.skillMd).not.toContain("mcp.json");
1821
1822
  expect(bundle.skillMd).not.toContain("Prefer MCP");
1822
1823
  expect(bundle.skillMd).not.toContain("tools/call");
1823
1824
  expect(bundle.skillMd).not.toContain("Generated by");
1824
- expect(bundle.referenceMd).toContain("```json");
1825
+ expect(bundle.referenceMd).toContain("CLI API reference");
1826
+ expect(bundle.referenceMd).toContain("#### Options");
1825
1827
  expect(bundle.referenceMd).not.toContain("Generated by");
1826
- expect(() => JSON.parse(bundle.referenceMd.match(/```json\n([\s\S]*?)\n```/)![1]!)).not.toThrow();
1828
+ expect(bundle.referenceMd).not.toContain("```json");
1827
1829
  });
1828
1830
 
1829
1831
  test("cliSkillInstall writes project Cursor skill files", () => {
@@ -1836,7 +1838,8 @@ test("cliSkillInstall writes project Cursor skill files", () => {
1836
1838
  const skillDir = join(cwd, ".cursor", "skills", "nested_ts");
1837
1839
  expect(existsSync(join(skillDir, "SKILL.md"))).toBe(true);
1838
1840
  expect(existsSync(join(skillDir, "reference.md"))).toBe(true);
1839
- expect(readFileSync(join(skillDir, "SKILL.md"), "utf8")).toContain("`nested.ts stat owner lookup`");
1841
+ expect(readFileSync(join(skillDir, "SKILL.md"), "utf8")).toContain("## Commands");
1842
+ expect(readFileSync(join(skillDir, "reference.md"), "utf8")).toContain("CLI API reference");
1840
1843
  const skillText = readFileSync(join(skillDir, "SKILL.md"), "utf8");
1841
1844
  expect(skillText.startsWith("---\n")).toBe(true);
1842
1845
  const hint = "<!-- Generated by nested.ts install --skill; do not edit. -->";
@@ -2,10 +2,10 @@
2
2
  This module generates Agent Skills content (SKILL.md + reference.md) from a CLI schema.
3
3
  */
4
4
 
5
- import { generateApiGuideBody } from "../docs/api-guide.ts";
6
- import { cliSchemaJson } from "../schema.ts";
7
- import { collectMcpTools, sanitizeToolSegment } from "../mcp/tools.ts";
8
- import { CliProgram } from "../types.ts";
5
+ import { generateApiGuide } from "../docs/api-guide.ts";
6
+ import { collectOptionDefs } from "../parse.ts";
7
+ import { collectMcpTools, sanitizeToolSegment, type McpToolDef } from "../mcp/tools.ts";
8
+ import { CliProgram, CliOptionKind } from "../types.ts";
9
9
 
10
10
  export type SkillTarget = "cursor" | "claude";
11
11
 
@@ -31,10 +31,47 @@ function skillDescription(root: CliProgram): string {
31
31
  return truncate(desc, 1024);
32
32
  }
33
33
 
34
+ /** CLI path with required single-slot positionals for the compact catalog. */
35
+ function commandCatalogPath(root: CliProgram, tool: McpToolDef): string {
36
+ const base = tool.path.length > 0 ? `${root.key} ${tool.path.join(" ")}` : root.key;
37
+ const slots = (tool.leaf.positionals ?? [])
38
+ .filter((p) => (p.argMin ?? 1) > 0 && (p.argMax ?? 1) === 1)
39
+ .map((p) => `<${p.name}>`);
40
+ if (slots.length === 0) {
41
+ return base;
42
+ }
43
+ return `${base} ${slots.join(" ")}`;
44
+ }
45
+
46
+ /** Formats one command line for the SKILL.md index (details live in reference.md). */
47
+ function formatCommandEntry(root: CliProgram, tool: McpToolDef): string {
48
+ const cliPath = commandCatalogPath(root, tool);
49
+ let line = `- **\`${cliPath}\`** — ${tool.leaf.description}`;
50
+ const opts = collectOptionDefs(root, tool.path);
51
+ const flags = opts.filter((o) => o.kind === CliOptionKind.Presence).map((o) => `--${o.name}`);
52
+ if (flags.length > 0) {
53
+ line += ` (flags: ${flags.join(", ")})`;
54
+ }
55
+ const enums = opts.filter((o) => o.kind === CliOptionKind.Enum && o.choices?.length);
56
+ for (const e of enums) {
57
+ line += ` (\`--${e.name}\`: ${e.choices!.join(" | ")})`;
58
+ }
59
+ const varargs = (tool.leaf.positionals ?? []).filter((p) => (p.argMax ?? 1) === 0);
60
+ if (varargs.length > 0) {
61
+ line += ` (varargs: ${varargs.map((p) => p.name).join(", ")})`;
62
+ }
63
+ const env = tool.leaf.mcpTool?.requiresEnv;
64
+ if (env && env.length > 0) {
65
+ line += ` [requires env: ${env.join(", ")}]`;
66
+ }
67
+ return line;
68
+ }
69
+
34
70
  /** Builds SKILL.md body for the given target. */
35
71
  function buildSkillMd(root: CliProgram, target: SkillTarget, dirName: string): string {
36
72
  const name = sanitizeToolSegment(root.key);
37
73
  const description = skillDescription(root);
74
+ const tools = collectMcpTools(root);
38
75
 
39
76
  const lines: string[] = [
40
77
  "---",
@@ -46,10 +83,6 @@ function buildSkillMd(root: CliProgram, target: SkillTarget, dirName: string): s
46
83
  "",
47
84
  root.description,
48
85
  "",
49
- "## When to use",
50
- "",
51
- `Use this skill when working with **${root.key}** — shell commands and automation for this application.`,
52
- "",
53
86
  "## Execution",
54
87
  "",
55
88
  "Invoke via shell:",
@@ -58,18 +91,32 @@ function buildSkillMd(root: CliProgram, target: SkillTarget, dirName: string): s
58
91
  `${root.key} <subcommand> [options] [args]`,
59
92
  "```",
60
93
  "",
61
- generateApiGuideBody(root).trimEnd(),
94
+ "## Commands",
62
95
  "",
96
+ ];
97
+
98
+ if (tools.length === 0) {
99
+ lines.push("(No leaf commands in schema.)", "");
100
+ } else {
101
+ for (const tool of tools) {
102
+ lines.push(formatCommandEntry(root, tool));
103
+ }
104
+ lines.push("");
105
+ }
106
+
107
+ lines.push(
63
108
  "## Pitfalls",
64
109
  "",
65
110
  "- Use `--` before tokens that look like flags when they are positional arguments.",
66
- "- Required environment variables are listed per command in descriptions (`requires env`).",
111
+ "- Required environment variables are listed per command above (`requires env`) and in `reference.md`.",
67
112
  "",
68
113
  "## Reference",
69
114
  "",
70
- "See `reference.md` in this skill directory for the full `docs schema` JSON export.",
115
+ "This file is a command index. For full option tables, positionals, notes, and built-ins,",
116
+ `read \`reference.md\` in this skill directory (same content as \`${root.key} docs api\`).`,
117
+ "Search for the command path you need before invoking.",
71
118
  "",
72
- ];
119
+ );
73
120
 
74
121
  if (target === "cursor") {
75
122
  lines.push(
@@ -96,18 +143,9 @@ function buildSkillMd(root: CliProgram, target: SkillTarget, dirName: string): s
96
143
  return lines.join("\n");
97
144
  }
98
145
 
99
- /** Builds reference.md with pretty-printed schema JSON. */
146
+ /** Builds reference.md with the full `docs api` markdown guide. */
100
147
  function buildReferenceMd(root: CliProgram): string {
101
- return [
102
- `# ${root.key} — CLI reference`,
103
- "",
104
- "Generated from the program `docs schema` export. Handlers and runtime-only nodes are omitted.",
105
- "",
106
- "```json",
107
- cliSchemaJson(root).trimEnd(),
108
- "```",
109
- "",
110
- ].join("\n");
148
+ return generateApiGuide(root);
111
149
  }
112
150
 
113
151
  /** Generates SKILL.md and reference.md for Cursor or Claude Code. */