argsbarg 3.3.13 → 3.4.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/src/schema.ts CHANGED
@@ -2,13 +2,18 @@
2
2
  This module serializes the CLI schema tree to JSON for machine-readable introspection.
3
3
  */
4
4
 
5
- import { type CliNode, type CliProgram, isCliLeaf, isCliRouter } from "./types.ts";
5
+ import { type CliNode, type CliProgram, isCliLeaf, isCliRouter, leafOutputSchema } from "./types.ts";
6
6
  import { exportPresentationBuiltins, type CliSchemaExport } from "./builtins/export.ts";
7
7
  import { cliResolveNotes } from "./help.ts";
8
+ import { visibleOptions } from "./hidden.ts";
8
9
 
9
10
  const RESERVED = new Set(["completion", "install", "docs", "mcp", "version"]);
10
11
 
11
- function exportCommand(cmd: CliNode, root: CliProgram): CliSchemaExport {
12
+ function exportCommand(cmd: CliNode, root: CliProgram): CliSchemaExport | null {
13
+ if (cmd.hidden) {
14
+ return null;
15
+ }
16
+
12
17
  const out: CliSchemaExport = {
13
18
  key: cmd.key,
14
19
  description: cmd.description,
@@ -18,14 +23,19 @@ function exportCommand(cmd: CliNode, root: CliProgram): CliSchemaExport {
18
23
  out.notes = cmd.notes;
19
24
  }
20
25
 
21
- if ((cmd.options ?? []).length > 0) {
22
- out.options = cmd.options;
26
+ const options = visibleOptions(cmd.options);
27
+ if (options.length > 0) {
28
+ out.options = options;
23
29
  }
24
30
 
25
31
  if (isCliLeaf(cmd)) {
26
32
  if ((cmd.positionals ?? []).length > 0) {
27
33
  out.positionals = cmd.positionals;
28
34
  }
35
+ const outputSchema = leafOutputSchema(cmd);
36
+ if (outputSchema !== undefined) {
37
+ out.outputSchema = outputSchema;
38
+ }
29
39
  out.commands = exportPresentationBuiltins(root);
30
40
  return out;
31
41
  }
@@ -39,7 +49,9 @@ function exportCommand(cmd: CliNode, root: CliProgram): CliSchemaExport {
39
49
 
40
50
  const children = isCliRouter(cmd) ? cmd.commands.filter((ch) => !RESERVED.has(ch.key)) : [];
41
51
  if (children.length > 0) {
42
- out.commands = children.map((ch) => exportCommand(ch, root));
52
+ out.commands = children
53
+ .map((ch) => exportCommand(ch, root))
54
+ .filter((ch): ch is CliSchemaExport => ch !== null);
43
55
  }
44
56
 
45
57
  return out;
@@ -59,7 +71,15 @@ function resolveSchemaNotes(node: CliSchemaExport, appKey: string): CliSchemaExp
59
71
 
60
72
  /** Returns the JSON-safe command tree (handlers omitted). */
61
73
  export function cliSchemaExport(root: CliProgram): CliSchemaExport {
62
- return resolveSchemaNotes(exportCommand(root, root), root.key);
74
+ const exported = exportCommand(root, root);
75
+ if (!exported) {
76
+ return {
77
+ key: root.key,
78
+ description: root.description,
79
+ commands: exportPresentationBuiltins(root),
80
+ };
81
+ }
82
+ return resolveSchemaNotes(exported, root.key);
63
83
  }
64
84
 
65
85
  export function cliSchemaJson(root: CliProgram): string {
@@ -107,14 +107,12 @@ function buildSkillMd(root: CliProgram, target: SkillTarget, dirName: string): s
107
107
  lines.push(
108
108
  "## Pitfalls",
109
109
  "",
110
- "- Use `--` before tokens that look like flags when they are positional arguments.",
111
- "- Required environment variables are listed per command above (`requires env`) and in `reference.md`.",
110
+ "- Pass `--` before arguments that look like flags.",
111
+ "- Commands marked `[requires env: ...]` need those variables set in the shell.",
112
112
  "",
113
113
  "## Reference",
114
114
  "",
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.",
115
+ `For full detail, open \`reference.md\` in this skill directory (same as \`${root.key} docs api\`).`,
118
116
  "",
119
117
  );
120
118
 
package/src/types.ts CHANGED
@@ -50,6 +50,8 @@ export enum CliFallbackMode {
50
50
  export interface CliOption {
51
51
  /** Option name (e.g., "name", "verbose"). */
52
52
  name: string;
53
+ /** When `true`, omit from help, schema, completions, and MCP tool inputSchema (still parseable). */
54
+ hidden?: boolean;
53
55
  /** Description shown in help. */
54
56
  description: string;
55
57
  /** Option kind: presence flag, string value, or number value. */
@@ -87,6 +89,19 @@ export interface CliPositional {
87
89
  argMax?: number;
88
90
  }
89
91
 
92
+ /** Optional metadata for `mcp bundle` MCP Bundle output (program root `mcpServer.bundle` only). */
93
+ export interface CliMcpBundleConfig {
94
+ author?: {
95
+ name: string;
96
+ email?: string;
97
+ url?: string;
98
+ };
99
+ /** Repo-relative path to a PNG icon copied into the bundle. */
100
+ icon?: string;
101
+ /** Manifest `long_description` (defaults to program description). */
102
+ longDescription?: string;
103
+ }
104
+
90
105
  /**
91
106
  * Enables `myapp mcp` and MCP stdio server metadata (program root only).
92
107
  * Must include `enabled: true`; omit `mcpServer` entirely to disable MCP.
@@ -113,6 +128,8 @@ export interface CliMcpServerConfig {
113
128
  * URIs must be unique and must not equal schemaResourceUri.
114
129
  */
115
130
  resources?: CliMcpResource[];
131
+ /** Optional MCP Bundle (`.mcpb`) metadata for `mcp bundle`. */
132
+ bundle?: CliMcpBundleConfig;
116
133
  }
117
134
 
118
135
  /**
@@ -148,6 +165,10 @@ export interface CliMcpToolConfig {
148
165
  * Empty string counts as absent.
149
166
  */
150
167
  requiresEnv?: string[];
168
+ /**
169
+ * @deprecated Set `outputSchema` on the leaf command instead.
170
+ */
171
+ outputSchema?: Record<string, unknown>;
151
172
  }
152
173
 
153
174
  /**
@@ -211,6 +232,8 @@ export interface CliDocsConfig {
211
232
  export interface CliNodeBase {
212
233
  /** Program or command key (e.g., "myapp", "stat", "owner"). */
213
234
  key: string;
235
+ /** When `true`, omit from help listings, schema, completions, and MCP tools (still invocable). */
236
+ hidden?: boolean;
214
237
  /** Short description shown in help. */
215
238
  description: string;
216
239
  /** Additional notes shown in help (`{argsbarg:program}` → program key). */
@@ -227,6 +250,11 @@ export type CliLeaf = CliNodeBase & {
227
250
  handler: CliHandler;
228
251
  /** Positional argument definitions. */
229
252
  positionals?: CliPositional[];
253
+ /**
254
+ * JSON Schema for structured stdout (e.g. with `--json` or MCP when the handler emits JSON).
255
+ * Exported in `docs schema`, `docs api`, and MCP `tools/list`; not validated at runtime yet.
256
+ */
257
+ outputSchema?: Record<string, unknown>;
230
258
  /** Per-tool MCP exposure and metadata. */
231
259
  mcpTool?: CliMcpToolConfig;
232
260
  };
@@ -273,6 +301,11 @@ export function isCliRouter(node: CliNode): node is CliRouter {
273
301
  return "commands" in node && Array.isArray(node.commands);
274
302
  }
275
303
 
304
+ /** Resolves structured stdout schema from the leaf (prefers leaf field over legacy `mcpTool.outputSchema`). */
305
+ export function leafOutputSchema(leaf: CliLeaf): Record<string, unknown> | undefined {
306
+ return leaf.outputSchema ?? leaf.mcpTool?.outputSchema;
307
+ }
308
+
276
309
  /**
277
310
  * Handler closure type for leaf commands.
278
311
  * Supports both sync and async handlers.
package/src/validate.ts CHANGED
@@ -112,6 +112,22 @@ function walkNode(node: CliNode, program: CliProgram, isRoot: boolean): void {
112
112
  if (isRoot && node.mcpTool !== undefined) {
113
113
  throw new CliSchemaValidationError("mcpTool is only supported on leaf commands");
114
114
  }
115
+ const outputSchema = node.outputSchema;
116
+ const legacyOutputSchema = node.mcpTool?.outputSchema;
117
+ if (outputSchema !== undefined && legacyOutputSchema !== undefined) {
118
+ throw new CliSchemaValidationError(
119
+ "Set outputSchema on the leaf only, not under mcpTool",
120
+ );
121
+ }
122
+ const resolved = outputSchema ?? legacyOutputSchema;
123
+ if (
124
+ resolved !== undefined &&
125
+ (typeof resolved !== "object" || resolved === null || Array.isArray(resolved))
126
+ ) {
127
+ throw new CliSchemaValidationError(
128
+ "outputSchema must be a JSON Schema object (not null or an array)",
129
+ );
130
+ }
115
131
  } else {
116
132
  const rogue = node as unknown as CliLeaf;
117
133
  if (rogue.mcpTool !== undefined) {