argsbarg 7.0.6 → 7.0.8
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 +4 -4
- package/docs/README.md +1 -1
- package/docs/ai-skills.md +14 -62
- package/docs/bundled-docs.md +9 -13
- package/docs/cli-program.md +10 -11
- package/docs/configure.md +9 -11
- package/docs/output-schema.md +1 -1
- package/examples/full-example/AGENTS.md +3 -3
- package/examples/full-example/docs/README.md +1 -1
- package/examples/full-example/justfile +0 -1
- package/examples/full-example/skills/full-example/SKILL.md +0 -2
- package/examples/full-example/src/program.ts +0 -1
- package/examples/full-example-json/AGENTS.md +3 -3
- package/examples/full-example-json/docs/README.md +1 -1
- package/examples/full-example-json/justfile +0 -1
- package/examples/full-example-json/skills/full-example-json/SKILL.md +0 -2
- 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/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 -112
- 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 -47
- package/src/docs/resolve.ts +5 -5
- package/src/docs/save.ts +9 -20
- package/src/help.test.ts +250 -8
- package/src/help.ts +397 -46
- package/src/skill/generate.ts +30 -156
- package/src/skill/hint.ts +2 -15
- package/src/skill/install.ts +3 -35
package/src/docs/save.ts
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
/*
|
|
2
2
|
This module persists bundled documentation topics to disk when `--save` is passed.
|
|
3
|
-
It writes documentation under `./docs
|
|
3
|
+
It writes documentation under `./docs/`.
|
|
4
4
|
*/
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
7
7
|
import { dirname, join } from "node:path";
|
|
8
8
|
import type { CliProgram } from "../core/types.ts";
|
|
9
9
|
import { generatedFileHtmlComment, insertGeneratedHint } from "../skill/hint.ts";
|
|
10
|
-
import { skillDirName } from "../skill/naming.ts";
|
|
11
10
|
import { docsTopicContent } from "./resolve.ts";
|
|
12
11
|
|
|
13
12
|
/** Relative output directory for `docs --save`. */
|
|
14
13
|
export const DOCS_SAVE_DIR = "docs";
|
|
15
14
|
|
|
16
15
|
/** Builtin docs topics generated by argsbarg (not consumer `docs.topics`). */
|
|
17
|
-
export const DOCS_GENERATED_SAVE_TOPICS = ["mcp", "cli", "
|
|
16
|
+
export const DOCS_GENERATED_SAVE_TOPICS = ["mcp", "cli", "http"] as const;
|
|
18
17
|
|
|
19
18
|
/** Whether `--save` should prepend a generated-file hint (argsbarg writers only). */
|
|
20
19
|
export function docsTopicIsGeneratedByArgsbarg(
|
|
@@ -34,7 +33,7 @@ export function docsSaveGeneratedHint(
|
|
|
34
33
|
return generatedFileHtmlComment(`${program.key} docs ${topic} --save`);
|
|
35
34
|
}
|
|
36
35
|
|
|
37
|
-
/** Inserts save hint
|
|
36
|
+
/** Inserts save hint into markdown content. */
|
|
38
37
|
export function applySaveGeneratedHint(
|
|
39
38
|
/** Program definition. */
|
|
40
39
|
program: CliProgram,
|
|
@@ -47,7 +46,7 @@ export function applySaveGeneratedHint(
|
|
|
47
46
|
return content;
|
|
48
47
|
}
|
|
49
48
|
const hint = docsSaveGeneratedHint(program, topic);
|
|
50
|
-
return insertGeneratedHint(content, hint
|
|
49
|
+
return insertGeneratedHint(content, hint);
|
|
51
50
|
}
|
|
52
51
|
|
|
53
52
|
/** File body for `--save` (hint on argsbarg-generated markdown only). */
|
|
@@ -74,20 +73,17 @@ export function docsSaveFilename(
|
|
|
74
73
|
return `${topic}.md`;
|
|
75
74
|
}
|
|
76
75
|
|
|
77
|
-
/** Relative path under cwd for a saved docs topic
|
|
76
|
+
/** Relative path under cwd for a saved docs topic. */
|
|
78
77
|
export function docsSaveRelativePath(
|
|
79
78
|
/** Topic identifier. */
|
|
80
79
|
topic: string,
|
|
81
|
-
/** Program root for resolving app-specific paths
|
|
82
|
-
|
|
80
|
+
/** Program root for resolving app-specific paths. */
|
|
81
|
+
_program?: CliProgram,
|
|
83
82
|
): string {
|
|
84
|
-
if (topic === "skill" && program) {
|
|
85
|
-
return join("skills", skillDirName(program.key), "SKILL.md");
|
|
86
|
-
}
|
|
87
83
|
return join(DOCS_SAVE_DIR, docsSaveFilename(topic));
|
|
88
84
|
}
|
|
89
85
|
|
|
90
|
-
/** Writes one docs topic under `./docs
|
|
86
|
+
/** Writes one docs topic under `./docs/`; returns relative path written. */
|
|
91
87
|
export function saveDocsTopic(
|
|
92
88
|
/** Program definition root. */
|
|
93
89
|
program: CliProgram,
|
|
@@ -98,13 +94,6 @@ export function saveDocsTopic(
|
|
|
98
94
|
const abs = join(process.cwd(), rel);
|
|
99
95
|
mkdirSync(dirname(abs), { recursive: true });
|
|
100
96
|
|
|
101
|
-
if (topic === "skill") {
|
|
102
|
-
const legacyDoc = join(process.cwd(), DOCS_SAVE_DIR, "skill.md");
|
|
103
|
-
if (existsSync(legacyDoc)) {
|
|
104
|
-
rmSync(legacyDoc, { force: true });
|
|
105
|
-
}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
97
|
writeFileSync(abs, docsTopicContentForSave(program, topic), "utf8");
|
|
109
98
|
return rel;
|
|
110
99
|
}
|
package/src/help.test.ts
CHANGED
|
@@ -5,7 +5,14 @@ Help rendering and label formatting tests.
|
|
|
5
5
|
import { describe, expect, test } from "bun:test";
|
|
6
6
|
import { cliPresentationRoot } from "./builtins/presentation.ts";
|
|
7
7
|
import { type CliOption, CliOptionKind, type CliPositional } from "./core/types.ts";
|
|
8
|
-
import {
|
|
8
|
+
import {
|
|
9
|
+
CLI_NOTES_PROGRAM,
|
|
10
|
+
cliHelpRender,
|
|
11
|
+
cliOptionLabel,
|
|
12
|
+
cliPositionalLabel,
|
|
13
|
+
cliResolveNotes,
|
|
14
|
+
schemaToYamlLines,
|
|
15
|
+
} from "./help.ts";
|
|
9
16
|
import { testProgram } from "./test/fixtures.ts";
|
|
10
17
|
|
|
11
18
|
describe("cliOptionLabel", () => {
|
|
@@ -64,7 +71,7 @@ describe("cliResolveNotes", () => {
|
|
|
64
71
|
});
|
|
65
72
|
|
|
66
73
|
describe("cliHelpRender", () => {
|
|
67
|
-
test("docs help lists schema
|
|
74
|
+
test("docs help lists schema and cli subcommands", () => {
|
|
68
75
|
const root = testProgram({
|
|
69
76
|
key: "app",
|
|
70
77
|
version: "1.0.0",
|
|
@@ -85,8 +92,7 @@ describe("cliHelpRender", () => {
|
|
|
85
92
|
expect(help).toContain("Print the full CLI command tree as JSON.");
|
|
86
93
|
expect(help).toContain("cli");
|
|
87
94
|
expect(help).toContain("markdown");
|
|
88
|
-
expect(help).toContain("skill");
|
|
89
|
-
expect(help).toContain("reference agent SKILL");
|
|
95
|
+
expect(help).not.toContain("skill");
|
|
90
96
|
});
|
|
91
97
|
|
|
92
98
|
test("root help omits legacy --schema flag", () => {
|
|
@@ -106,7 +112,7 @@ describe("cliHelpRender", () => {
|
|
|
106
112
|
expect(help).not.toContain("--schema");
|
|
107
113
|
});
|
|
108
114
|
|
|
109
|
-
test("root help
|
|
115
|
+
test("root help omits agent docs hint when docs enabled", () => {
|
|
110
116
|
const root = testProgram({
|
|
111
117
|
key: "myapp",
|
|
112
118
|
version: "1.0.0",
|
|
@@ -117,7 +123,7 @@ describe("cliHelpRender", () => {
|
|
|
117
123
|
commands: [{ key: "run", description: "Run.", handler: () => {} }],
|
|
118
124
|
});
|
|
119
125
|
const help = cliHelpRender(cliPresentationRoot(root), [], false);
|
|
120
|
-
expect(help).toContain("
|
|
126
|
+
expect(help).not.toContain("docs skill");
|
|
121
127
|
expect(help).not.toContain("install --skill");
|
|
122
128
|
});
|
|
123
129
|
|
|
@@ -134,7 +140,7 @@ describe("cliHelpRender", () => {
|
|
|
134
140
|
expect(help).not.toContain("docs skill");
|
|
135
141
|
});
|
|
136
142
|
|
|
137
|
-
test("root help includes program notes
|
|
143
|
+
test("root help includes program notes", () => {
|
|
138
144
|
const root = testProgram({
|
|
139
145
|
key: "myapp",
|
|
140
146
|
version: "1.0.0",
|
|
@@ -147,6 +153,242 @@ describe("cliHelpRender", () => {
|
|
|
147
153
|
});
|
|
148
154
|
const help = cliHelpRender(cliPresentationRoot(root), [], false);
|
|
149
155
|
expect(help).toContain("See `myapp docs readme` for the user guide.");
|
|
150
|
-
expect(help).toContain("
|
|
156
|
+
expect(help).not.toContain("docs skill");
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
/** Tests that non-TTY help strips box characters and renders plain text. */
|
|
160
|
+
test("non-TTY help strips boxes and renders clean plain text", () => {
|
|
161
|
+
const root = testProgram({
|
|
162
|
+
key: "myapp",
|
|
163
|
+
version: "1.0.0",
|
|
164
|
+
description: "Test application.",
|
|
165
|
+
commands: [
|
|
166
|
+
{
|
|
167
|
+
key: "status",
|
|
168
|
+
description: "Show status.",
|
|
169
|
+
options: [
|
|
170
|
+
{
|
|
171
|
+
name: "verbose",
|
|
172
|
+
shortName: "v",
|
|
173
|
+
description: "Verbose output.",
|
|
174
|
+
kind: CliOptionKind.Presence,
|
|
175
|
+
},
|
|
176
|
+
],
|
|
177
|
+
handler: () => {},
|
|
178
|
+
},
|
|
179
|
+
],
|
|
180
|
+
});
|
|
181
|
+
const help = cliHelpRender(cliPresentationRoot(root), ["status"], false, { isTTY: false });
|
|
182
|
+
expect(help).not.toContain("╭─");
|
|
183
|
+
expect(help).not.toContain("╰─");
|
|
184
|
+
expect(help).not.toContain("│");
|
|
185
|
+
expect(help).toContain("Usage:\n myapp status [OPTIONS]");
|
|
186
|
+
expect(help).toContain("Options:\n --help, -h Show help for this command.\n --verbose, -v Verbose output.");
|
|
187
|
+
});
|
|
188
|
+
|
|
189
|
+
/** Tests that TTY help renders rounded UTF-8 boxes. */
|
|
190
|
+
test("TTY help renders rounded UTF-8 boxes and omits output schema by default", () => {
|
|
191
|
+
const root = testProgram({
|
|
192
|
+
key: "myapp",
|
|
193
|
+
version: "1.0.0",
|
|
194
|
+
description: "Test application.",
|
|
195
|
+
commands: [
|
|
196
|
+
{
|
|
197
|
+
key: "status",
|
|
198
|
+
description: "Show status.",
|
|
199
|
+
outputSchema: {
|
|
200
|
+
type: "object",
|
|
201
|
+
properties: {
|
|
202
|
+
version: { type: "string", description: "App version." },
|
|
203
|
+
},
|
|
204
|
+
required: ["version"],
|
|
205
|
+
},
|
|
206
|
+
handler: () => {},
|
|
207
|
+
},
|
|
208
|
+
],
|
|
209
|
+
});
|
|
210
|
+
const help = cliHelpRender(cliPresentationRoot(root), ["status"], false, { isTTY: true });
|
|
211
|
+
expect(help).toContain("╭");
|
|
212
|
+
expect(help).toContain("╰");
|
|
213
|
+
expect(help).toContain("│");
|
|
214
|
+
expect(help).not.toContain("Output Schema");
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
/** Tests that non-TTY help automatically includes output schema in YAML by default. */
|
|
218
|
+
test("non-TTY help automatically includes output schema in YAML by default", () => {
|
|
219
|
+
const root = testProgram({
|
|
220
|
+
key: "myapp",
|
|
221
|
+
version: "1.0.0",
|
|
222
|
+
description: "Test application.",
|
|
223
|
+
commands: [
|
|
224
|
+
{
|
|
225
|
+
key: "status",
|
|
226
|
+
description: "Show status.",
|
|
227
|
+
outputSchema: {
|
|
228
|
+
type: "object",
|
|
229
|
+
properties: {
|
|
230
|
+
version: { type: "string", description: "App version." },
|
|
231
|
+
},
|
|
232
|
+
required: ["version"],
|
|
233
|
+
},
|
|
234
|
+
handler: () => {},
|
|
235
|
+
},
|
|
236
|
+
],
|
|
237
|
+
});
|
|
238
|
+
const help = cliHelpRender(cliPresentationRoot(root), ["status"], false, { isTTY: false });
|
|
239
|
+
expect(help).toContain("Output Schema (with --json):");
|
|
240
|
+
expect(help).toContain("# App version.");
|
|
241
|
+
expect(help).toContain("version: string");
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
/** Tests that json leaf commands render Output Schema (JSON) and Input Schema. */
|
|
245
|
+
test("json leaf renders Output Schema (JSON) and Input Schema in non-TTY mode", () => {
|
|
246
|
+
const root = testProgram({
|
|
247
|
+
key: "myapp",
|
|
248
|
+
version: "1.0.0",
|
|
249
|
+
description: "Test application.",
|
|
250
|
+
commands: [
|
|
251
|
+
{
|
|
252
|
+
key: "create",
|
|
253
|
+
kind: "json",
|
|
254
|
+
description: "Create resource.",
|
|
255
|
+
inputSchema: {
|
|
256
|
+
type: "object",
|
|
257
|
+
properties: {
|
|
258
|
+
name: { type: "string", description: "Resource name." },
|
|
259
|
+
},
|
|
260
|
+
required: ["name"],
|
|
261
|
+
},
|
|
262
|
+
outputSchema: {
|
|
263
|
+
type: "object",
|
|
264
|
+
properties: {
|
|
265
|
+
id: { type: "string", description: "Generated ID." },
|
|
266
|
+
},
|
|
267
|
+
required: ["id"],
|
|
268
|
+
},
|
|
269
|
+
handler: () => {},
|
|
270
|
+
},
|
|
271
|
+
],
|
|
272
|
+
});
|
|
273
|
+
const help = cliHelpRender(cliPresentationRoot(root), ["create"], false, { isTTY: false });
|
|
274
|
+
expect(help).toContain("Input Schema:");
|
|
275
|
+
expect(help).toContain("# Resource name.");
|
|
276
|
+
expect(help).toContain("name: string");
|
|
277
|
+
expect(help).toContain("Output Schema (JSON):");
|
|
278
|
+
expect(help).toContain("# Generated ID.");
|
|
279
|
+
expect(help).toContain("id: string");
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
/** Tests for converting JSON Schema to human- and agent-friendly YAML lines. */
|
|
284
|
+
describe("schemaToYamlLines", () => {
|
|
285
|
+
/** Tests primitive properties with required and optional keys and comments. */
|
|
286
|
+
test("formats primitive properties with descriptions and optionality", () => {
|
|
287
|
+
const schema = {
|
|
288
|
+
type: "object",
|
|
289
|
+
properties: {
|
|
290
|
+
documentId: {
|
|
291
|
+
type: "string",
|
|
292
|
+
description: "Unique document identifier.",
|
|
293
|
+
},
|
|
294
|
+
index: {
|
|
295
|
+
type: "integer",
|
|
296
|
+
},
|
|
297
|
+
},
|
|
298
|
+
required: ["documentId"],
|
|
299
|
+
};
|
|
300
|
+
const lines = schemaToYamlLines(schema, 0);
|
|
301
|
+
expect(lines).toEqual(["# Unique document identifier.", "documentId: string", "index?: integer"]);
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
/** Tests enums, string formats, and union types. */
|
|
305
|
+
test("formats enums, string formats, and union types", () => {
|
|
306
|
+
const schema = {
|
|
307
|
+
type: "object",
|
|
308
|
+
properties: {
|
|
309
|
+
format: {
|
|
310
|
+
type: "string",
|
|
311
|
+
enum: ["pdf", "html"],
|
|
312
|
+
},
|
|
313
|
+
createdAt: {
|
|
314
|
+
type: "string",
|
|
315
|
+
format: "date-time",
|
|
316
|
+
},
|
|
317
|
+
status: {
|
|
318
|
+
anyOf: [{ type: "string" }, { type: "number" }],
|
|
319
|
+
},
|
|
320
|
+
},
|
|
321
|
+
};
|
|
322
|
+
const lines = schemaToYamlLines(schema, 0);
|
|
323
|
+
expect(lines).toEqual(['format?: "pdf" | "html"', "createdAt?: string (date-time)", "status?: string | number"]);
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
/** Tests nested objects and arrays of objects with definitions. */
|
|
327
|
+
test("formats nested objects and arrays of objects with definition resolution", () => {
|
|
328
|
+
const schema = {
|
|
329
|
+
type: "object",
|
|
330
|
+
properties: {
|
|
331
|
+
tab: {
|
|
332
|
+
type: "object",
|
|
333
|
+
description: "Active tab metadata.",
|
|
334
|
+
properties: {
|
|
335
|
+
tabId: { type: "string" },
|
|
336
|
+
title: { type: "string" },
|
|
337
|
+
},
|
|
338
|
+
required: ["tabId", "title"],
|
|
339
|
+
},
|
|
340
|
+
tabs: {
|
|
341
|
+
type: "array",
|
|
342
|
+
items: {
|
|
343
|
+
$ref: "#/definitions/TabItem",
|
|
344
|
+
},
|
|
345
|
+
},
|
|
346
|
+
},
|
|
347
|
+
definitions: {
|
|
348
|
+
TabItem: {
|
|
349
|
+
type: "object",
|
|
350
|
+
properties: {
|
|
351
|
+
tabId: { type: "string" },
|
|
352
|
+
title: { type: "string" },
|
|
353
|
+
index: { type: "integer" },
|
|
354
|
+
},
|
|
355
|
+
required: ["tabId", "title", "index"],
|
|
356
|
+
},
|
|
357
|
+
},
|
|
358
|
+
required: ["tab"],
|
|
359
|
+
};
|
|
360
|
+
const lines = schemaToYamlLines(schema, 0);
|
|
361
|
+
expect(lines).toEqual([
|
|
362
|
+
"# Active tab metadata.",
|
|
363
|
+
"tab:",
|
|
364
|
+
" tabId: string",
|
|
365
|
+
" title: string",
|
|
366
|
+
"tabs?:",
|
|
367
|
+
" - tabId: string",
|
|
368
|
+
" title: string",
|
|
369
|
+
" index: integer",
|
|
370
|
+
]);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
/** Tests recursive references handle cycles gracefully without infinite loop. */
|
|
374
|
+
test("handles recursive definition references without infinite loop", () => {
|
|
375
|
+
const schema = {
|
|
376
|
+
type: "object",
|
|
377
|
+
properties: {
|
|
378
|
+
name: { type: "string" },
|
|
379
|
+
parent: { $ref: "#/definitions/TreeNode" },
|
|
380
|
+
},
|
|
381
|
+
definitions: {
|
|
382
|
+
TreeNode: {
|
|
383
|
+
type: "object",
|
|
384
|
+
properties: {
|
|
385
|
+
name: { type: "string" },
|
|
386
|
+
parent: { $ref: "#/definitions/TreeNode" },
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
};
|
|
391
|
+
const lines = schemaToYamlLines(schema, 0);
|
|
392
|
+
expect(lines).toEqual(["name?: string", "parent?:", " name?: string", " parent?: TreeNode"]);
|
|
151
393
|
});
|
|
152
394
|
});
|