argsbarg 1.4.1 → 1.4.3

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/docs/mcp.md CHANGED
@@ -22,17 +22,19 @@ const cli: CliCommand = {
22
22
  2. Run the MCP server:
23
23
 
24
24
  ```bash
25
- myapp mcp
25
+ myapp ai mcp
26
26
  ```
27
27
 
28
28
  The process reads NDJSON requests from stdin and writes NDJSON responses to stdout. It stays alive until stdin closes.
29
29
 
30
30
  3. Point your MCP client at that command. See [Client setup](#client-setup).
31
31
 
32
+ Optionally install an agent skill for discovery without MCP: see [docs/ai-skills.md](ai-skills.md).
33
+
32
34
  The `examples/nested.ts` demo enables MCP — try:
33
35
 
34
36
  ```bash
35
- bun run examples/nested.ts mcp
37
+ bun run examples/nested.ts ai mcp
36
38
  ```
37
39
 
38
40
  ## Client setup
@@ -46,17 +48,17 @@ Add a server entry under `mcpServers` in your Cursor MCP config:
46
48
  "mcpServers": {
47
49
  "myapp": {
48
50
  "command": "bun",
49
- "args": ["run", "myapp.ts", "mcp"]
51
+ "args": ["run", "myapp.ts", "ai", "mcp"]
50
52
  }
51
53
  }
52
54
  }
53
55
  ```
54
56
 
55
- Use your real binary or script path. For a compiled CLI, `command` can be the installed binary and `args` can be `["mcp"]` only.
57
+ Use your real binary or script path. For a compiled CLI, `command` can be the installed binary and `args` can be `["ai", "mcp"]`.
56
58
 
57
59
  ### Other MCP hosts
58
60
 
59
- Any host that spawns a subprocess and wires stdin/stdout works the same way: the **command** is your app, and **`mcp`** is the subcommand that starts the server.
61
+ Any host that spawns a subprocess and wires stdin/stdout works the same way: the **command** is your app, and **`ai mcp`** starts the server.
60
62
 
61
63
  ## Configuration
62
64
 
@@ -83,7 +85,7 @@ mcpServer: {
83
85
 
84
86
  ## Tools
85
87
 
86
- Every **user-defined leaf command** in your schema becomes one MCP tool. Built-ins (`completion`, `mcp`) are not exposed as tools.
88
+ Every **user-defined leaf command** in your schema becomes one MCP tool. Built-ins (`completion`, `ai`) are not exposed as tools.
87
89
 
88
90
  ### Tool names
89
91
 
@@ -138,7 +140,7 @@ mcpTool: {
138
140
  Each tool’s `inputSchema` is a JSON Schema object built from your CLI definition:
139
141
 
140
142
  - **Options** — parent-scoped flags are included (e.g. `stat`’s `--json` appears on `stat_owner_lookup`). Presence options are `boolean`; string, number, and **enum** options match their `CliOptionKind` (`Enum` uses JSON Schema `enum`). Required options are listed in `required`.
141
- - **Positionals** — one property per `CliPositional` on the leaf. Single-slot positionals are `string`; varargs tails (`argMax: 0`) are `string[]`. Required positionals are listed in `required`.
143
+ - **Positionals** — one property per `CliPositional` on the leaf. Single-slot positionals are `string`; varargs tails (`argMax: 0`) are `string[]`. Required positionals are listed in `required`. For varargs, agents may also pass a comma-separated string (`"a,b"`) or a single string (`"a"`) — both are coerced to separate argv tokens at dispatch time.
142
144
 
143
145
  Arguments are a **flat JSON object** keyed by option and positional names (same names as in your schema, including hyphenated option names like `"user-name"`).
144
146
 
@@ -275,7 +277,7 @@ Requests without an `id` are treated as notifications and do not receive a respo
275
277
  ### Manual smoke test
276
278
 
277
279
  ```bash
278
- printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | bun run examples/nested.ts mcp
280
+ printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' | bun run examples/nested.ts ai mcp
279
281
  ```
280
282
 
281
283
  You should get one JSON line on stdout with `result.capabilities` and `result.serverInfo`.
@@ -284,11 +286,11 @@ You should get one JSON line on stdout with `result.capabilities` and `result.se
284
286
 
285
287
  When MCP is enabled:
286
288
 
287
- - Do not declare a top-level command named **`mcp`** — it is reserved for the built-in subcommand.
289
+ - Do not declare a top-level command named **`ai`** — it is reserved for the built-in AI integration group.
288
290
  - Do not declare a top-level command named **`completion`** — reserved for shell completions.
289
291
  - Do not declare an option named **`schema`** — reserved for `--schema`.
290
292
 
291
- Running `myapp mcp` without `mcpServer` on the root fails with an error (exit 1).
293
+ Running `myapp ai mcp` without `mcpServer` on the root fails with an error (exit 1).
292
294
 
293
295
  ## Design notes
294
296
 
package/index.d.ts CHANGED
@@ -23,6 +23,10 @@ export declare class CliContext {
23
23
  * This is the TypeScript-native advantage over the Swift version.
24
24
  */
25
25
  typedOpt<T>(name: string, parse: (s: string) => T): T | null;
26
+ /** Returns the value(s) for a named positional slot. Varargs slots return string[]; single slots return string | undefined. */
27
+ positional(name: string): string | string[] | undefined;
28
+ private _posMap;
29
+ private _positionalMap;
26
30
  }
27
31
  /**
28
32
  * How a leaf handler was dispatched.
@@ -42,21 +46,20 @@ export declare enum CliOptionKind {
42
46
  Enum = "enum"
43
47
  }
44
48
  /**
45
- * When fallbackCommand is used for missing or unknown top-level tokens.
46
- * Only the program root may set a non-default mode or a non-nil fallbackCommand.
49
+ * When `fallbackCommand` is used for missing or unknown subcommand tokens at a routing node.
47
50
  */
48
51
  export declare enum CliFallbackMode {
49
52
  /**
50
- * If argv has no first subcommand, route to `fallbackCommand`; if the first token is unknown, error.
53
+ * If argv has no next subcommand, route to `fallbackCommand`; if the token is unknown, error.
51
54
  */
52
55
  MissingOnly = "missingOnly",
53
56
  /**
54
- * If argv has no first subcommand or the first token is not a known child, route to `fallbackCommand`.
57
+ * If argv has no next subcommand or the token is not a known child, route to `fallbackCommand`.
55
58
  */
56
59
  MissingOrUnknown = "missingOrUnknown",
57
60
  /**
58
- * If the first token is present but not a known child, route to `fallbackCommand`.
59
- * When the first subcommand token is missing (empty argv), do not use fallback (implicit root help).
61
+ * If the next token is present but not a known child, route to `fallbackCommand`.
62
+ * When the subcommand token is missing (exhausted argv), do not use fallback (implicit scoped help).
60
63
  */
61
64
  UnknownOnly = "unknownOnly"
62
65
  }
@@ -102,7 +105,7 @@ export interface CliPositional {
102
105
  argMax?: number;
103
106
  }
104
107
  /**
105
- * Root-only. Enables `myapp mcp` and MCP stdio server metadata.
108
+ * Root-only. Enables `myapp ai mcp` and MCP stdio server metadata.
106
109
  */
107
110
  export interface CliMcpServerConfig {
108
111
  /** `initialize` serverInfo.name (default: root `key`). */
@@ -162,6 +165,15 @@ export interface CliMcpToolConfig {
162
165
  */
163
166
  requiresEnv?: string[];
164
167
  }
168
+ /**
169
+ * Root-only. Opt out of `ai skill` install commands with `{ enabled: false }`.
170
+ */
171
+ export interface CliAiSkillConfig {
172
+ /** When `false`, disable `ai skill *` install commands (default: enabled). */
173
+ enabled?: boolean;
174
+ /** Skill directory name (default: sanitized root `key`). */
175
+ name?: string;
176
+ }
165
177
  /**
166
178
  * Base properties shared by all command nodes.
167
179
  */
@@ -174,8 +186,10 @@ export interface CliCommandBase {
174
186
  notes?: string;
175
187
  /** Global or command-level flags/options. */
176
188
  options?: CliOption[];
177
- /** Root-only. When set, enables the `mcp` built-in subcommand. */
189
+ /** Root-only. When set, enables the `ai mcp` built-in subcommand. */
178
190
  mcpServer?: CliMcpServerConfig;
191
+ /** Root-only. Opt out of `ai skill` install with `{ enabled: false }`. */
192
+ aiSkill?: CliAiSkillConfig;
179
193
  /** Leaf-only. Per-tool MCP exposure and metadata. */
180
194
  mcpTool?: CliMcpToolConfig;
181
195
  }
@@ -192,16 +206,16 @@ export type CliCommand = (CliCommandBase & {
192
206
  positionals?: CliPositional[];
193
207
  /** Nested subcommands (empty for leaf commands). */
194
208
  commands?: never;
195
- /** Default top-level subcommand (routing commands only). */
209
+ /** Default subcommand (routing commands only). */
196
210
  fallbackCommand?: never;
197
- /** How fallbackCommand is applied (routing commands only). */
211
+ /** How fallbackCommand is applied at this routing node (routing commands only). */
198
212
  fallbackMode?: never;
199
213
  }) | (CliCommandBase & {
200
214
  /** Nested subcommands. */
201
215
  commands: CliCommand[];
202
- /** Default top-level subcommand when argv omits a command or uses an unknown first token. */
216
+ /** Default subcommand when argv omits a command or uses an unknown token at this routing node. */
203
217
  fallbackCommand?: string;
204
- /** How fallbackCommand is applied. */
218
+ /** How fallbackCommand is applied at this routing node (not root-only). */
205
219
  fallbackMode?: CliFallbackMode;
206
220
  /** Handler function (leaf commands only). */
207
221
  handler?: never;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "argsbarg",
3
- "version": "1.4.1",
3
+ "version": "1.4.3",
4
4
  "type": "module",
5
5
  "scripts": {
6
6
  "//just": "echo this app uses justfile for development tasks"
package/src/ai.ts ADDED
@@ -0,0 +1,7 @@
1
+ /*
2
+ This module re-exports AI agent integration entry points (skill install).
3
+ MCP stdio serving remains in mcp.ts.
4
+ */
5
+
6
+ export { cliSkillInstall, type SkillInstallOpts } from "./skill/install.ts";
7
+ export { generateSkillBundle, type SkillBundle, type SkillTarget } from "./skill/generate.ts";
package/src/completion.ts CHANGED
@@ -597,21 +597,62 @@ export function cliPresentationRoot(root: CliCommand): CliCommand {
597
597
  } as CliCommand;
598
598
  }
599
599
 
600
+ /** Presence options for skill install leaves (`--global`, `--force`). */
601
+ function skillInstallOptions(): CliOption[] {
602
+ return [
603
+ {
604
+ name: "global",
605
+ description: "Install to the user skills directory (~/.cursor/skills or ~/.claude/skills).",
606
+ kind: CliOptionKind.Presence,
607
+ },
608
+ {
609
+ name: "force",
610
+ description: "Overwrite an existing skill directory.",
611
+ kind: CliOptionKind.Presence,
612
+ },
613
+ ];
614
+ }
615
+
600
616
  /** Built-in commands shown in help and merged for routing CLIs. */
601
617
  function presentationBuiltins(root: CliCommand): CliCommand[] {
602
- const cmds: CliCommand[] = [cliBuiltinCompletionGroup(root.key)];
618
+ return [cliBuiltinCompletionGroup(root.key), cliBuiltinAiGroup(root)];
619
+ }
620
+
621
+ /** Builds the `ai` built-in command group (MCP + skill install). */
622
+ export function cliBuiltinAiGroup(root: CliCommand): CliCommand {
623
+ const aiChildren: CliCommand[] = [
624
+ {
625
+ key: "skill",
626
+ description: "Install agent skill files for Cursor or Claude Code.",
627
+ commands: [
628
+ {
629
+ key: "cursor",
630
+ description: "Install Cursor skill (SKILL.md + reference.md).",
631
+ options: skillInstallOptions(),
632
+ handler: () => {},
633
+ },
634
+ {
635
+ key: "claude",
636
+ description: "Install Claude Code skill (SKILL.md + reference.md).",
637
+ options: skillInstallOptions(),
638
+ handler: () => {},
639
+ },
640
+ ],
641
+ },
642
+ ];
643
+
603
644
  if (root.mcpServer !== undefined) {
604
- cmds.push(cliBuiltinMcpCommand());
645
+ aiChildren.unshift({
646
+ key: "mcp",
647
+ description: "Run as an MCP server over stdio (for AI agents).",
648
+ handler: () => {},
649
+ });
605
650
  }
606
- return cmds;
607
- }
608
651
 
609
- /** Builds the static `mcp` leaf command (merged when `root.mcpServer` is set). */
610
- export function cliBuiltinMcpCommand(): CliCommand {
611
652
  return {
612
- key: "mcp",
613
- description: "Run as an MCP server over stdio (for AI agents).",
614
- handler: () => {},
653
+ key: "ai",
654
+ description: "AI agent integration (MCP server and skill install).",
655
+ commands: aiChildren,
615
656
  };
616
657
  }
617
658
 
package/src/context.ts CHANGED
@@ -68,4 +68,42 @@ export class CliContext {
68
68
  return null;
69
69
  }
70
70
  }
71
+
72
+ /** Returns the value(s) for a named positional slot. Varargs slots return string[]; single slots return string | undefined. */
73
+ positional(name: string): string | string[] | undefined {
74
+ return this._positionalMap()[name];
75
+ }
76
+
77
+ private _posMap: Record<string, string | string[]> | undefined;
78
+
79
+ private _positionalMap(): Record<string, string | string[]> {
80
+ if (this._posMap) return this._posMap;
81
+
82
+ let node: CliCommand = this.schema;
83
+ for (const seg of this.commandPath) {
84
+ const child = (node.commands ?? []).find((c) => c.key === seg);
85
+ if (!child) {
86
+ this._posMap = {};
87
+ return {};
88
+ }
89
+ node = child;
90
+ }
91
+
92
+ const map: Record<string, string | string[]> = {};
93
+ let argIdx = 0;
94
+ for (const p of node.positionals ?? []) {
95
+ const { argMax = 1 } = p;
96
+ if (argMax === 0) {
97
+ map[p.name] = this.args.slice(argIdx);
98
+ argIdx = this.args.length;
99
+ } else {
100
+ const val = this.args[argIdx];
101
+ if (val !== undefined) map[p.name] = val;
102
+ argIdx++;
103
+ }
104
+ }
105
+
106
+ this._posMap = map;
107
+ return map;
108
+ }
71
109
  }