@runa-cmd/completions 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 Runa CLI Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,221 @@
1
+ # @runa-cmd/completions
2
+
3
+ Auto-generate shell completion scripts for any Runa CLI. One command, three shells — bash, zsh, and fish.
4
+
5
+ Your Zod schema is the source of truth: enum values become completion candidates, commands and subcommands get tab-completed, and option flags (including `--no-*` booleans) work out of the box.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ pnpm add @runa-cmd/completions
11
+ ```
12
+
13
+ > Peer dependencies: `@runa-cmd/core` and `zod ^4.0.0`.
14
+ > Zero runtime dependencies.
15
+
16
+ ## Quick Start
17
+
18
+ ```ts
19
+ import { defineCLI, defineCommand } from '@runa-cmd/core';
20
+ import { z } from '@runa-cmd/core/zod';
21
+ import { completionsPlugin } from '@runa-cmd/completions';
22
+
23
+ const deploy = defineCommand({
24
+ meta: { name: 'deploy', description: 'Deploy a service' },
25
+ options: {
26
+ env: z.enum(['staging', 'production']).describe('Target environment'),
27
+ },
28
+ run({ options }) {
29
+ console.log(`Deploying to ${options.env}...`);
30
+ },
31
+ });
32
+
33
+ const cli = defineCLI({
34
+ meta: { name: 'my-tool', version: '1.0.0' },
35
+ commands: { deploy },
36
+ plugins: [completionsPlugin()],
37
+ });
38
+
39
+ cli.run();
40
+ ```
41
+
42
+ ```bash
43
+ # Generate and install bash completions
44
+ $ my-tool completions bash > ~/.local/share/bash-completion/completions/my-tool
45
+
46
+ # Or get install instructions
47
+ $ my-tool completions bash --instructions
48
+
49
+ # Tab-complete in action
50
+ $ my-tool d<TAB> → deploy
51
+ $ my-tool deploy --e<TAB> → --env
52
+ $ my-tool deploy --env <TAB> → staging production
53
+ ```
54
+
55
+ ## Supported Shells
56
+
57
+ | Shell | Script Type | Features |
58
+ |---|---|---|
59
+ | **Bash** | `complete -F` with `compgen` | Commands, subcommands, options, enum values, `--no-*` booleans |
60
+ | **Zsh** | `_arguments -C` with state dispatch | Same + grouped option specs with descriptions |
61
+ | **Fish** | `complete -c` directives | Same + native condition-based filtering |
62
+
63
+ ## How It Works
64
+
65
+ 1. The plugin registers a `completions` command with `addCommands` capability
66
+ 2. The command takes a positional `shell` arg (`bash`, `zsh`, or `fish`)
67
+ 3. On execution, it introspects the CLI schema via `api.getSchema()`
68
+ 4. A shell-specific generator produces a self-contained completion script
69
+ 5. The script is written to stdout — pipe it to a file or eval it
70
+
71
+ ### What Gets Completed
72
+
73
+ | Element | Example | Completed? |
74
+ |---|---|---|
75
+ | Top-level commands | `my-tool de<TAB>` → `deploy` | ✅ |
76
+ | Nested subcommands | `my-tool config g<TAB>` → `get` | ✅ |
77
+ | Long options | `my-tool deploy --e<TAB>` → `--env` | ✅ |
78
+ | Short aliases | `my-tool deploy -e<TAB>` | ✅ |
79
+ | Boolean negation | `my-tool --no-<TAB>` → `--no-color` | ✅ |
80
+ | Enum values | `--env <TAB>` → `staging production` | ✅ |
81
+ | Command descriptions | Shown in zsh/fish completions | ✅ |
82
+
83
+ ## API
84
+
85
+ ### `completionsPlugin(options?)`
86
+
87
+ Creates the completions plugin. Returns a `PluginConfig` compatible with `defineCLI`.
88
+
89
+ ```ts
90
+ import { completionsPlugin } from '@runa-cmd/completions';
91
+
92
+ completionsPlugin({
93
+ commandName: 'complete', // Override command name (default: 'completions')
94
+ });
95
+ ```
96
+
97
+ ### `CompletionsPluginOptions`
98
+
99
+ ```ts
100
+ interface CompletionsPluginOptions {
101
+ commandName?: string; // Override the command name (default: 'completions')
102
+ }
103
+ ```
104
+
105
+ ### Direct Generator Functions
106
+
107
+ For advanced use cases (custom output, testing, etc.), the generators are exported directly:
108
+
109
+ ```ts
110
+ import {
111
+ generateBashCompletions,
112
+ generateZshCompletions,
113
+ generateFishCompletions,
114
+ } from '@runa-cmd/completions';
115
+
116
+ // schema: CLISchema from api.getSchema()
117
+ const bashScript = generateBashCompletions(schema, 'my-tool');
118
+ const zshScript = generateZshCompletions(schema, 'my-tool');
119
+ const fishScript = generateFishCompletions(schema, 'my-tool');
120
+ ```
121
+
122
+ ### `getInstallInstructions(shell, binName)`
123
+
124
+ Returns shell-specific install instructions as a string:
125
+
126
+ ```ts
127
+ import { getInstallInstructions } from '@runa-cmd/completions';
128
+
129
+ console.log(getInstallInstructions('bash', 'my-tool'));
130
+ // # Bash completions for my-tool
131
+ // #
132
+ // # Option 1: Add to your .bashrc (loads on every shell start)
133
+ // # echo 'eval "$(my-tool completions bash)"' >> ~/.bashrc
134
+ // ...
135
+ ```
136
+
137
+ ## Install Instructions by Shell
138
+
139
+ ### Bash
140
+
141
+ ```bash
142
+ # Option 1: Source in .bashrc
143
+ echo 'eval "$(my-tool completions bash)"' >> ~/.bashrc
144
+
145
+ # Option 2: Save to bash-completion directory (recommended)
146
+ my-tool completions bash > ~/.local/share/bash-completion/completions/my-tool
147
+ ```
148
+
149
+ ### Zsh
150
+
151
+ ```bash
152
+ # Save to a completions directory in your fpath
153
+ mkdir -p ~/.zsh/completions
154
+ my-tool completions zsh > ~/.zsh/completions/_my-tool
155
+
156
+ # Add to .zshrc (before compinit):
157
+ # fpath=(~/.zsh/completions $fpath)
158
+ # autoload -Uz compinit && compinit
159
+ ```
160
+
161
+ ### Fish
162
+
163
+ ```bash
164
+ # Save to fish completions directory (auto-loaded)
165
+ my-tool completions fish > ~/.config/fish/completions/my-tool.fish
166
+ ```
167
+
168
+ ## With Other Plugins
169
+
170
+ Completions work alongside help and MCP — just add all plugins:
171
+
172
+ ```ts
173
+ import { helpPlugin } from '@runa-cmd/help';
174
+ import { mcpPlugin } from '@runa-cmd/mcp';
175
+ import { completionsPlugin } from '@runa-cmd/completions';
176
+
177
+ const cli = defineCLI({
178
+ meta: { name: 'my-tool', version: '1.0.0' },
179
+ commands: { deploy, init },
180
+ plugins: [helpPlugin(), mcpPlugin(), completionsPlugin()],
181
+ });
182
+ ```
183
+
184
+ ```bash
185
+ $ my-tool --help # Human-readable help
186
+ $ my-tool --mcp # MCP server for AI agents
187
+ $ my-tool completions bash # Shell completions script
188
+ ```
189
+
190
+ ## Shell Escaping
191
+
192
+ All values (command names, descriptions, enum values) are properly escaped for each shell context:
193
+
194
+ | Shell | Escaping Strategy |
195
+ |---|---|
196
+ | Bash | Single-quote context: `'` → `'\''` |
197
+ | Zsh | Same as bash |
198
+ | Fish | `'` → `\'`, `\` → `\\` |
199
+
200
+ Descriptions are truncated to 80 characters and newlines are collapsed to spaces.
201
+
202
+ ## Architecture
203
+
204
+ ```
205
+ completionsPlugin()
206
+ │
207
+ ├── plugin.ts Runa plugin (adds completions command)
208
+ ├── generators/
209
+ │ ├── bash.ts Bash completion script generator
210
+ │ ├── zsh.ts Zsh completion script generator
211
+ │ ├── fish.ts Fish completion script generator
212
+ │ └── escape.ts Shell-specific string escaping
213
+ ├── install.ts Install instruction templates
214
+ └── types.ts Shell type and plugin options
215
+ ```
216
+
217
+ Zero runtime dependencies. Everything is derived from `CLISchema` at generation time.
218
+
219
+ ## License
220
+
221
+ MIT
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @runa-cmd/completions — Bash completion script generator
3
+ *
4
+ * Generates a self-contained bash completion script from a CLISchema.
5
+ * Uses raw COMP_WORDS/COMP_CWORD — no dependency on bash-completion package.
6
+ */
7
+ import type { CLISchema } from '@runa-cmd/core';
8
+ /**
9
+ * Generate a complete bash completion script from a CLISchema.
10
+ *
11
+ * @param schema - Full CLI schema from api.getSchema()
12
+ * @param binName - The CLI binary name
13
+ * @returns Complete bash script as a string
14
+ */
15
+ export declare function generateBashCompletions(schema: CLISchema, binName: string): string;
16
+ //# sourceMappingURL=bash.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bash.d.ts","sourceRoot":"","sources":["../../src/generators/bash.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAA+B,MAAM,gBAAgB,CAAC;AAoG7E;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAkElF"}
@@ -0,0 +1,155 @@
1
+ /**
2
+ * @runa-cmd/completions — Bash completion script generator
3
+ *
4
+ * Generates a self-contained bash completion script from a CLISchema.
5
+ * Uses raw COMP_WORDS/COMP_CWORD — no dependency on bash-completion package.
6
+ */
7
+ import { escapeBash } from './escape.js';
8
+ /** Replace non-identifier characters with underscores */
9
+ function safeName(name) {
10
+ return name.replace(/[^a-zA-Z0-9_]/g, '_');
11
+ }
12
+ /** Build --long option names for an option, including --no-* for booleans */
13
+ function optionFlags(opt) {
14
+ const flags = [`--${opt.name}`];
15
+ if (opt.type === 'boolean') {
16
+ flags.push(`--no-${opt.name}`);
17
+ }
18
+ if (opt.alias) {
19
+ for (const a of opt.alias) {
20
+ flags.push(a);
21
+ }
22
+ }
23
+ return flags;
24
+ }
25
+ /** Build the list of all option flag strings for a command context */
26
+ function buildOptWords(options, globalOptions) {
27
+ const all = [...options, ...globalOptions];
28
+ return all.flatMap(optionFlags).join(' ');
29
+ }
30
+ /** Build prev-matching case entries for enum options */
31
+ function buildPrevCases(options, globalOptions) {
32
+ const lines = [];
33
+ const all = [...options, ...globalOptions];
34
+ for (const opt of all) {
35
+ if (opt.type === 'enum' && opt.enumValues?.length) {
36
+ const triggers = [`--${opt.name}`];
37
+ if (opt.alias) {
38
+ for (const a of opt.alias) {
39
+ triggers.push(a);
40
+ }
41
+ }
42
+ const pattern = triggers.join('|');
43
+ const values = opt.enumValues.map((v) => escapeBash(v)).join(' ');
44
+ lines.push(` ${pattern})`);
45
+ lines.push(` COMPREPLY=($(compgen -W '${values}' -- "$cur"))`);
46
+ lines.push(' return ;;');
47
+ }
48
+ }
49
+ return lines.join('\n');
50
+ }
51
+ /**
52
+ * Recursively collect all case entries for the command tree.
53
+ * Each command becomes a case pattern based on its path.
54
+ */
55
+ function collectCases(commands, globalOptions, prefix) {
56
+ const entries = [];
57
+ for (const cmd of commands) {
58
+ const path = prefix ? `${prefix}_${cmd.name}` : `_${cmd.name}`;
59
+ const optWords = buildOptWords(cmd.options, globalOptions);
60
+ const hasSubcmds = cmd.subcommands && cmd.subcommands.length > 0;
61
+ const subcmdNames = hasSubcmds ? (cmd.subcommands ?? []).map((s) => s.name).join(' ') : '';
62
+ const lines = [];
63
+ lines.push(` "${path}")`);
64
+ // prev-matching for enum values in this command's context
65
+ const prevCases = buildPrevCases(cmd.options, globalOptions);
66
+ if (prevCases) {
67
+ lines.push(' case "$prev" in');
68
+ lines.push(prevCases);
69
+ lines.push(' esac');
70
+ }
71
+ if (hasSubcmds) {
72
+ lines.push(' if [[ "$cur" == -* ]]; then');
73
+ lines.push(` COMPREPLY=($(compgen -W '${optWords}' -- "$cur"))`);
74
+ lines.push(' else');
75
+ lines.push(` COMPREPLY=($(compgen -W '${subcmdNames}' -- "$cur"))`);
76
+ lines.push(' fi');
77
+ }
78
+ else {
79
+ lines.push(' if [[ "$cur" == -* ]]; then');
80
+ lines.push(` COMPREPLY=($(compgen -W '${optWords}' -- "$cur"))`);
81
+ lines.push(' fi');
82
+ }
83
+ lines.push(' ;;');
84
+ entries.push(lines.join('\n'));
85
+ if (hasSubcmds) {
86
+ entries.push(...collectCases(cmd.subcommands ?? [], globalOptions, path));
87
+ }
88
+ }
89
+ return entries;
90
+ }
91
+ /**
92
+ * Generate a complete bash completion script from a CLISchema.
93
+ *
94
+ * @param schema - Full CLI schema from api.getSchema()
95
+ * @param binName - The CLI binary name
96
+ * @returns Complete bash script as a string
97
+ */
98
+ export function generateBashCompletions(schema, binName) {
99
+ const funcName = `_${safeName(binName)}_completions`;
100
+ const { commands, globalOptions } = schema;
101
+ const globalOptWords = globalOptions.flatMap(optionFlags).join(' ');
102
+ const topCmdNames = commands.map((c) => c.name).join(' ');
103
+ // Top-level prev cases for global enum options
104
+ const topPrevCases = buildPrevCases([], globalOptions);
105
+ // Nested command cases
106
+ const cmdCases = collectCases(commands, globalOptions, '');
107
+ // Build the top-level option words (commands' options don't apply here)
108
+ const topOptWords = globalOptWords;
109
+ const lines = [];
110
+ lines.push('#!/usr/bin/env bash');
111
+ lines.push(`# Bash completions for ${escapeBash(binName)}`);
112
+ lines.push('# Generated by @runa-cmd/completions');
113
+ lines.push('');
114
+ lines.push(`${funcName}() {`);
115
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: these are bash variables, not JS template literals
116
+ lines.push(' local cur="${COMP_WORDS[COMP_CWORD]}"');
117
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: bash variable
118
+ lines.push(' local prev="${COMP_WORDS[COMP_CWORD-1]}"');
119
+ lines.push('');
120
+ lines.push(' # Build command path from COMP_WORDS');
121
+ lines.push(' local cmd_path=""');
122
+ lines.push(' local i=1');
123
+ lines.push(' while [[ $i -lt $COMP_CWORD ]]; do');
124
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: bash variable
125
+ lines.push(' case "${COMP_WORDS[i]}" in');
126
+ lines.push(' -*) ;;');
127
+ // biome-ignore lint/suspicious/noTemplateCurlyInString: bash variable
128
+ lines.push(' *) cmd_path="${cmd_path}_${COMP_WORDS[i]}" ;;');
129
+ lines.push(' esac');
130
+ lines.push(' ((i++))');
131
+ lines.push(' done');
132
+ lines.push('');
133
+ lines.push(' case "$cmd_path" in');
134
+ lines.push(' "")');
135
+ // Top-level prev cases
136
+ if (topPrevCases) {
137
+ lines.push(' case "$prev" in');
138
+ lines.push(topPrevCases);
139
+ lines.push(' esac');
140
+ }
141
+ lines.push(' if [[ "$cur" == -* ]]; then');
142
+ lines.push(` COMPREPLY=($(compgen -W '${topOptWords}' -- "$cur"))`);
143
+ lines.push(' else');
144
+ lines.push(` COMPREPLY=($(compgen -W '${topCmdNames}' -- "$cur"))`);
145
+ lines.push(' fi');
146
+ lines.push(' ;;');
147
+ for (const entry of cmdCases) {
148
+ lines.push(entry);
149
+ }
150
+ lines.push(' esac');
151
+ lines.push('}');
152
+ lines.push(`complete -F ${funcName} ${binName}`);
153
+ return lines.join('\n');
154
+ }
155
+ //# sourceMappingURL=bash.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bash.js","sourceRoot":"","sources":["../../src/generators/bash.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ /**
2
+ * @runa-cmd/completions — Shell escape helpers
3
+ *
4
+ * Per-shell escape functions for safely embedding strings in generated
5
+ * completion scripts. Each function handles the quoting rules of its
6
+ * target shell. Descriptions are truncated to 80 chars.
7
+ */
8
+ /**
9
+ * Escape a string for embedding in a single-quoted bash context.
10
+ *
11
+ * In bash single quotes, the ONLY special character is `'` itself.
12
+ * We end the current quote, insert an escaped quote, and restart: `'\''`
13
+ */
14
+ export declare function escapeBash(str: string): string;
15
+ /**
16
+ * Escape a string for embedding in a single-quoted zsh context.
17
+ *
18
+ * Zsh single-quote escaping is identical to bash: `'\''`
19
+ */
20
+ export declare function escapeZsh(str: string): string;
21
+ /**
22
+ * Escape a string for embedding in a single-quoted fish context.
23
+ *
24
+ * Fish uses backslash escaping inside single quotes:
25
+ * - `\` → `\\`
26
+ * - `'` → `\'`
27
+ */
28
+ export declare function escapeFish(str: string): string;
29
+ //# sourceMappingURL=escape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escape.d.ts","sourceRoot":"","sources":["../../src/generators/escape.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAWH;;;;;GAKG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED;;;;;;GAMG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAE9C"}
@@ -0,0 +1,43 @@
1
+ /**
2
+ * @runa-cmd/completions — Shell escape helpers
3
+ *
4
+ * Per-shell escape functions for safely embedding strings in generated
5
+ * completion scripts. Each function handles the quoting rules of its
6
+ * target shell. Descriptions are truncated to 80 chars.
7
+ */
8
+ const MAX_DESC_LENGTH = 80;
9
+ /** Truncate and collapse newlines for safe embedding */
10
+ function sanitize(str) {
11
+ const collapsed = str.replace(/\n/g, ' ').replace(/\s+/g, ' ').trim();
12
+ if (collapsed.length <= MAX_DESC_LENGTH)
13
+ return collapsed;
14
+ return `${collapsed.slice(0, MAX_DESC_LENGTH - 1)}\u2026`;
15
+ }
16
+ /**
17
+ * Escape a string for embedding in a single-quoted bash context.
18
+ *
19
+ * In bash single quotes, the ONLY special character is `'` itself.
20
+ * We end the current quote, insert an escaped quote, and restart: `'\''`
21
+ */
22
+ export function escapeBash(str) {
23
+ return sanitize(str).replace(/'/g, "'\\''");
24
+ }
25
+ /**
26
+ * Escape a string for embedding in a single-quoted zsh context.
27
+ *
28
+ * Zsh single-quote escaping is identical to bash: `'\''`
29
+ */
30
+ export function escapeZsh(str) {
31
+ return sanitize(str).replace(/'/g, "'\\''");
32
+ }
33
+ /**
34
+ * Escape a string for embedding in a single-quoted fish context.
35
+ *
36
+ * Fish uses backslash escaping inside single quotes:
37
+ * - `\` → `\\`
38
+ * - `'` → `\'`
39
+ */
40
+ export function escapeFish(str) {
41
+ return sanitize(str).replace(/\\/g, '\\\\').replace(/'/g, "\\'");
42
+ }
43
+ //# sourceMappingURL=escape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"escape.js","sourceRoot":"","sources":["../../src/generators/escape.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,eAAe,GAAG,EAAE,CAAC;AAE3B,wDAAwD;AACxD,SAAS,QAAQ,CAAC,GAAW;IAC5B,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACtE,IAAI,SAAS,CAAC,MAAM,IAAI,eAAe;QAAE,OAAO,SAAS,CAAC;IAC1D,OAAO,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,eAAe,GAAG,CAAC,CAAC,QAAQ,CAAC;AAC3D,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW;IACrC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,SAAS,CAAC,GAAW;IACpC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,UAAU,CAAC,GAAW;IACrC,OAAO,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,EAAE,KAAK,CAAC,CAAC;AAClE,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @runa-cmd/completions — Fish completion script generator
3
+ *
4
+ * Generates fish completions as a flat list of `complete` directives.
5
+ * Uses __fish_use_subcommand and __fish_seen_subcommand_from for context.
6
+ */
7
+ import type { CLISchema } from '@runa-cmd/core';
8
+ /**
9
+ * Generate a complete fish completion script from a CLISchema.
10
+ *
11
+ * @param schema - Full CLI schema from api.getSchema()
12
+ * @param binName - The CLI binary name
13
+ * @returns Complete fish script as a string
14
+ */
15
+ export declare function generateFishCompletions(schema: CLISchema, binName: string): string;
16
+ //# sourceMappingURL=fish.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fish.d.ts","sourceRoot":"","sources":["../../src/generators/fish.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAA+B,MAAM,gBAAgB,CAAC;AA4E7E;;;;;;GAMG;AACH,wBAAgB,uBAAuB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CA4BlF"}
@@ -0,0 +1,86 @@
1
+ /**
2
+ * @runa-cmd/completions — Fish completion script generator
3
+ *
4
+ * Generates fish completions as a flat list of `complete` directives.
5
+ * Uses __fish_use_subcommand and __fish_seen_subcommand_from for context.
6
+ */
7
+ import { escapeFish } from './escape.js';
8
+ /** Generate complete directives for a single option */
9
+ function optionDirectives(binName, opt, condition) {
10
+ const lines = [];
11
+ const desc = opt.description ? ` -d '${escapeFish(opt.description)}'` : '';
12
+ const shortAlias = opt.alias?.find((a) => a.startsWith('-') && !a.startsWith('--'));
13
+ const shortFlag = shortAlias ? ` -s ${shortAlias.replace(/^-/, '')}` : '';
14
+ const condPart = condition ? ` -n '${condition}'` : '';
15
+ if (opt.type === 'boolean') {
16
+ // Boolean flags don't take values — no -r
17
+ lines.push(`complete -c ${binName}${condPart}` + ` -l ${opt.name}${shortFlag}${desc}`);
18
+ // --no-* variant
19
+ lines.push(`complete -c ${binName}${condPart}` + ` -l no-${opt.name}${desc}`);
20
+ }
21
+ else if (opt.type === 'enum' && opt.enumValues?.length) {
22
+ const vals = opt.enumValues.map((v) => escapeFish(v)).join(' ');
23
+ lines.push(`complete -c ${binName}${condPart}` +
24
+ ` -l ${opt.name}${shortFlag}${desc}` +
25
+ ` -r -a '${vals}'`);
26
+ }
27
+ else {
28
+ // string, number, array — require argument
29
+ lines.push(`complete -c ${binName}${condPart}` + ` -l ${opt.name}${shortFlag}${desc} -r`);
30
+ }
31
+ return lines;
32
+ }
33
+ /**
34
+ * Recursively generate complete directives for commands.
35
+ */
36
+ function generateCommandDirectives(binName, commands, globalOptions, parentCondition, _parentName) {
37
+ const lines = [];
38
+ for (const cmd of commands) {
39
+ const desc = cmd.description ? ` -d '${escapeFish(cmd.description)}'` : '';
40
+ // Command itself
41
+ lines.push(`complete -c ${binName}` +
42
+ ` -n '${parentCondition}'` +
43
+ ` -a '${escapeFish(cmd.name)}'${desc}`);
44
+ // Command options
45
+ const cmdCondition = `__fish_seen_subcommand_from ${cmd.name}`;
46
+ for (const opt of cmd.options) {
47
+ lines.push(...optionDirectives(binName, opt, cmdCondition));
48
+ }
49
+ // Subcommands
50
+ if (cmd.subcommands && cmd.subcommands.length > 0) {
51
+ lines.push(...generateCommandDirectives(binName, cmd.subcommands, globalOptions, cmdCondition, cmd.name));
52
+ }
53
+ }
54
+ return lines;
55
+ }
56
+ /**
57
+ * Generate a complete fish completion script from a CLISchema.
58
+ *
59
+ * @param schema - Full CLI schema from api.getSchema()
60
+ * @param binName - The CLI binary name
61
+ * @returns Complete fish script as a string
62
+ */
63
+ export function generateFishCompletions(schema, binName) {
64
+ const { commands, globalOptions } = schema;
65
+ const lines = [];
66
+ lines.push(`# Fish completions for ${escapeFish(binName)}`);
67
+ lines.push('# Generated by @runa-cmd/completions');
68
+ lines.push('');
69
+ lines.push(`complete -c ${binName} -f`);
70
+ lines.push('');
71
+ // Global options (no condition — available everywhere)
72
+ if (globalOptions.length > 0) {
73
+ lines.push('# Global options');
74
+ for (const opt of globalOptions) {
75
+ lines.push(...optionDirectives(binName, opt, ''));
76
+ }
77
+ lines.push('');
78
+ }
79
+ // Commands
80
+ if (commands.length > 0) {
81
+ lines.push('# Commands');
82
+ lines.push(...generateCommandDirectives(binName, commands, globalOptions, '__fish_use_subcommand', null));
83
+ }
84
+ return lines.join('\n');
85
+ }
86
+ //# sourceMappingURL=fish.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fish.js","sourceRoot":"","sources":["../../src/generators/fish.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @runa-cmd/completions — Zsh completion script generator
3
+ *
4
+ * Generates a zsh completion script using _arguments -C with state
5
+ * machine dispatch. One function per command level.
6
+ */
7
+ import type { CLISchema } from '@runa-cmd/core';
8
+ /**
9
+ * Generate a complete zsh completion script from a CLISchema.
10
+ *
11
+ * @param schema - Full CLI schema from api.getSchema()
12
+ * @param binName - The CLI binary name
13
+ * @returns Complete zsh script as a string
14
+ */
15
+ export declare function generateZshCompletions(schema: CLISchema, binName: string): string;
16
+ //# sourceMappingURL=zsh.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zsh.d.ts","sourceRoot":"","sources":["../../src/generators/zsh.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,SAAS,EAA+B,MAAM,gBAAgB,CAAC;AAkI7E;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CA0DjF"}
@@ -0,0 +1,180 @@
1
+ /**
2
+ * @runa-cmd/completions — Zsh completion script generator
3
+ *
4
+ * Generates a zsh completion script using _arguments -C with state
5
+ * machine dispatch. One function per command level.
6
+ */
7
+ import { escapeZsh } from './escape.js';
8
+ /** Replace non-identifier characters with underscores */
9
+ function safeName(name) {
10
+ return name.replace(/[^a-zA-Z0-9_]/g, '_');
11
+ }
12
+ /** Format an option spec for _arguments */
13
+ function formatOptionSpec(opt) {
14
+ const specs = [];
15
+ const desc = opt.description ? escapeZsh(opt.description) : '';
16
+ const shortAlias = opt.alias?.find((a) => a.startsWith('-') && !a.startsWith('--'));
17
+ if (opt.type === 'boolean') {
18
+ // Boolean with alias
19
+ if (shortAlias) {
20
+ specs.push(`'(${shortAlias} --${opt.name})'` + `{${shortAlias},--${opt.name}}` + `'[${desc}]'`);
21
+ specs.push(`'--no-${opt.name}[${desc}]'`);
22
+ }
23
+ else {
24
+ specs.push(`'--${opt.name}[${desc}]'`);
25
+ specs.push(`'--no-${opt.name}[${desc}]'`);
26
+ }
27
+ }
28
+ else if (opt.type === 'enum' && opt.enumValues?.length) {
29
+ const vals = opt.enumValues.map((v) => escapeZsh(v)).join(' ');
30
+ if (shortAlias) {
31
+ specs.push(`'(${shortAlias} --${opt.name})'` +
32
+ `{${shortAlias},--${opt.name}}` +
33
+ `'[${desc}]:${opt.name}:(${vals})'`);
34
+ }
35
+ else {
36
+ specs.push(`'--${opt.name}[${desc}]` + `:${opt.name}:(${vals})'`);
37
+ }
38
+ }
39
+ else {
40
+ // string, number, array — require value but no candidates
41
+ if (shortAlias) {
42
+ specs.push(`'(${shortAlias} --${opt.name})'` +
43
+ `{${shortAlias},--${opt.name}}` +
44
+ `'[${desc}]:${opt.name}:'`);
45
+ }
46
+ else {
47
+ specs.push(`'--${opt.name}[${desc}]` + `:${opt.name}:'`);
48
+ }
49
+ }
50
+ return specs;
51
+ }
52
+ /** Build _arguments option specs for a list of options */
53
+ function buildArgSpecs(options, globalOptions) {
54
+ const all = [...globalOptions, ...options];
55
+ return all.flatMap(formatOptionSpec);
56
+ }
57
+ /**
58
+ * Recursively generate zsh functions for a command tree.
59
+ * Returns an array of function definition strings.
60
+ */
61
+ function generateCommandFunctions(commands, globalOptions, parentFunc) {
62
+ const blocks = [];
63
+ for (const cmd of commands) {
64
+ const funcName = `${parentFunc}_${safeName(cmd.name)}`;
65
+ const hasSubcmds = cmd.subcommands && cmd.subcommands.length > 0;
66
+ const argSpecs = buildArgSpecs(cmd.options, globalOptions);
67
+ const lines = [];
68
+ lines.push(`${funcName}() {`);
69
+ if (hasSubcmds) {
70
+ lines.push(' local -a commands');
71
+ lines.push(' local state line');
72
+ lines.push('');
73
+ lines.push(' _arguments -C \\');
74
+ for (const spec of argSpecs) {
75
+ lines.push(` ${spec} \\`);
76
+ }
77
+ lines.push(" '1:command:->cmds' \\");
78
+ lines.push(" '*::arg:->args'");
79
+ lines.push('');
80
+ lines.push(' case "$state" in');
81
+ lines.push(' cmds)');
82
+ lines.push(' commands=(');
83
+ for (const sub of cmd.subcommands ?? []) {
84
+ const d = sub.description ? escapeZsh(sub.description) : '';
85
+ lines.push(` '${escapeZsh(sub.name)}:${d}'`);
86
+ }
87
+ lines.push(' )');
88
+ lines.push(" _describe 'command' commands");
89
+ lines.push(' ;;');
90
+ lines.push(' args)');
91
+ lines.push(' case "$line[1]" in');
92
+ for (const sub of cmd.subcommands ?? []) {
93
+ lines.push(` ${sub.name})`);
94
+ lines.push(` ${funcName}_${safeName(sub.name)}`);
95
+ lines.push(' ;;');
96
+ }
97
+ lines.push(' esac');
98
+ lines.push(' ;;');
99
+ lines.push(' esac');
100
+ }
101
+ else {
102
+ // Leaf command — just _arguments with options
103
+ if (argSpecs.length > 0) {
104
+ lines.push(' _arguments \\');
105
+ for (let i = 0; i < argSpecs.length; i++) {
106
+ const suffix = i < argSpecs.length - 1 ? ' \\' : '';
107
+ lines.push(` ${argSpecs[i]}${suffix}`);
108
+ }
109
+ }
110
+ }
111
+ lines.push('}');
112
+ blocks.push(lines.join('\n'));
113
+ // Recurse into subcommands
114
+ if (hasSubcmds) {
115
+ blocks.push(...generateCommandFunctions(cmd.subcommands ?? [], globalOptions, funcName));
116
+ }
117
+ }
118
+ return blocks;
119
+ }
120
+ /**
121
+ * Generate a complete zsh completion script from a CLISchema.
122
+ *
123
+ * @param schema - Full CLI schema from api.getSchema()
124
+ * @param binName - The CLI binary name
125
+ * @returns Complete zsh script as a string
126
+ */
127
+ export function generateZshCompletions(schema, binName) {
128
+ const funcName = `_${safeName(binName)}`;
129
+ const { commands, globalOptions } = schema;
130
+ const globalArgSpecs = buildArgSpecs([], globalOptions);
131
+ const lines = [];
132
+ lines.push(`#compdef ${binName}`);
133
+ lines.push(`# Zsh completions for ${escapeZsh(binName)}`);
134
+ lines.push('# Generated by @runa-cmd/completions');
135
+ lines.push('');
136
+ // Main function
137
+ lines.push(`${funcName}() {`);
138
+ lines.push(' local -a commands');
139
+ lines.push(' local state line');
140
+ lines.push('');
141
+ lines.push(' _arguments -C \\');
142
+ for (const spec of globalArgSpecs) {
143
+ lines.push(` ${spec} \\`);
144
+ }
145
+ lines.push(" '1:command:->cmds' \\");
146
+ lines.push(" '*::arg:->args'");
147
+ lines.push('');
148
+ lines.push(' case "$state" in');
149
+ lines.push(' cmds)');
150
+ lines.push(' commands=(');
151
+ for (const cmd of commands) {
152
+ const d = cmd.description ? escapeZsh(cmd.description) : '';
153
+ lines.push(` '${escapeZsh(cmd.name)}:${d}'`);
154
+ }
155
+ lines.push(' )');
156
+ lines.push(" _describe 'command' commands");
157
+ lines.push(' ;;');
158
+ lines.push(' args)');
159
+ lines.push(' case "$line[1]" in');
160
+ for (const cmd of commands) {
161
+ lines.push(` ${cmd.name})`);
162
+ lines.push(` ${funcName}_${safeName(cmd.name)}`);
163
+ lines.push(' ;;');
164
+ }
165
+ lines.push(' esac');
166
+ lines.push(' ;;');
167
+ lines.push(' esac');
168
+ lines.push('}');
169
+ lines.push('');
170
+ // Command functions
171
+ const cmdFuncs = generateCommandFunctions(commands, globalOptions, funcName);
172
+ for (const fn of cmdFuncs) {
173
+ lines.push(fn);
174
+ lines.push('');
175
+ }
176
+ // Call the main function
177
+ lines.push(funcName);
178
+ return lines.join('\n');
179
+ }
180
+ //# sourceMappingURL=zsh.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"zsh.js","sourceRoot":"","sources":["../../src/generators/zsh.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * @runa-cmd/completions — Public API
3
+ *
4
+ * Barrel re-exports for the completions plugin package.
5
+ */
6
+ export { generateBashCompletions } from './generators/bash.js';
7
+ export { generateFishCompletions } from './generators/fish.js';
8
+ export { generateZshCompletions } from './generators/zsh.js';
9
+ export { getInstallInstructions } from './install.js';
10
+ export { completionsPlugin } from './plugin.js';
11
+ export type { CompletionsPluginOptions, Shell } from './types.js';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAEtD,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAEhD,YAAY,EAAE,wBAAwB,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,14 @@
1
+ /**
2
+ * @runa-cmd/completions — Public API
3
+ *
4
+ * Barrel re-exports for the completions plugin package.
5
+ */
6
+ // Generators (for advanced use / direct invocation)
7
+ export { generateBashCompletions } from './generators/bash.js';
8
+ export { generateFishCompletions } from './generators/fish.js';
9
+ export { generateZshCompletions } from './generators/zsh.js';
10
+ // Install instructions
11
+ export { getInstallInstructions } from './install.js';
12
+ // Plugin
13
+ export { completionsPlugin } from './plugin.js';
14
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,oDAAoD;AACpD,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,uBAAuB;AACvB,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AACtD,SAAS;AACT,OAAO,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * @runa-cmd/completions — Install instructions
3
+ *
4
+ * Returns shell-specific installation instructions for the
5
+ * generated completion scripts.
6
+ */
7
+ import type { Shell } from './types.js';
8
+ /**
9
+ * Get shell-specific installation instructions for the completion script.
10
+ *
11
+ * @param shell - Target shell
12
+ * @param binName - CLI binary name
13
+ * @returns Multi-line instruction string
14
+ */
15
+ export declare function getInstallInstructions(shell: Shell, binName: string): string;
16
+ //# sourceMappingURL=install.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.d.ts","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC;;;;;;GAMG;AACH,wBAAgB,sBAAsB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAS5E"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * @runa-cmd/completions — Install instructions
3
+ *
4
+ * Returns shell-specific installation instructions for the
5
+ * generated completion scripts.
6
+ */
7
+ /**
8
+ * Get shell-specific installation instructions for the completion script.
9
+ *
10
+ * @param shell - Target shell
11
+ * @param binName - CLI binary name
12
+ * @returns Multi-line instruction string
13
+ */
14
+ export function getInstallInstructions(shell, binName) {
15
+ switch (shell) {
16
+ case 'bash':
17
+ return getBashInstructions(binName);
18
+ case 'zsh':
19
+ return getZshInstructions(binName);
20
+ case 'fish':
21
+ return getFishInstructions(binName);
22
+ }
23
+ }
24
+ function getBashInstructions(binName) {
25
+ return `# Bash completions for ${binName}
26
+ #
27
+ # Option 1: Add to your .bashrc (loads on every shell start)
28
+ #
29
+ # echo 'eval "$(${binName} completions bash)"' >> ~/.bashrc
30
+ #
31
+ # Option 2: Save to bash-completion directory (recommended)
32
+ #
33
+ # ${binName} completions bash > ~/.local/share/bash-completion/completions/${binName}
34
+ #
35
+ # Then restart your shell or run:
36
+ #
37
+ # source ~/.bashrc
38
+ `;
39
+ }
40
+ function getZshInstructions(binName) {
41
+ return `# Zsh completions for ${binName}
42
+ #
43
+ # Option 1: Save to a completions directory in your fpath
44
+ #
45
+ # mkdir -p ~/.zsh/completions
46
+ # ${binName} completions zsh > ~/.zsh/completions/_${binName}
47
+ #
48
+ # Then add to your .zshrc (before compinit):
49
+ #
50
+ # fpath=(~/.zsh/completions $fpath)
51
+ # autoload -Uz compinit && compinit
52
+ #
53
+ # Option 2: Add to your .zshrc directly
54
+ #
55
+ # echo 'eval "$(${binName} completions zsh)"' >> ~/.zshrc
56
+ #
57
+ # Then restart your shell or run:
58
+ #
59
+ # source ~/.zshrc
60
+ `;
61
+ }
62
+ function getFishInstructions(binName) {
63
+ return `# Fish completions for ${binName}
64
+ #
65
+ # Save to fish completions directory (auto-loaded by convention):
66
+ #
67
+ # ${binName} completions fish > ~/.config/fish/completions/${binName}.fish
68
+ #
69
+ # Fish automatically loads completions from this directory.
70
+ # No additional configuration needed.
71
+ `;
72
+ }
73
+ //# sourceMappingURL=install.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install.js","sourceRoot":"","sources":["../src/install.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAY,EAAE,OAAe;IACnE,QAAQ,KAAK,EAAE,CAAC;QACf,KAAK,MAAM;YACV,OAAO,mBAAmB,CAAC,OAAO,CAAC,CAAC;QACrC,KAAK,KAAK;YACT,OAAO,kBAAkB,CAAC,OAAO,CAAC,CAAC;QACpC,KAAK,MAAM;YACV,OAAO,mBAAmB,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;AACF,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAe;IAC3C,OAAO,0BAA0B,OAAO;;;;oBAIrB,OAAO;;;;MAIrB,OAAO,kEAAkE,OAAO;;;;;CAKrF,CAAC;AACF,CAAC;AAED,SAAS,kBAAkB,CAAC,OAAe;IAC1C,OAAO,yBAAyB,OAAO;;;;;MAKlC,OAAO,0CAA0C,OAAO;;;;;;;;;oBAS1C,OAAO;;;;;CAK1B,CAAC;AACF,CAAC;AAED,SAAS,mBAAmB,CAAC,OAAe;IAC3C,OAAO,0BAA0B,OAAO;;;;MAInC,OAAO,kDAAkD,OAAO;;;;CAIrE,CAAC;AACF,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * @runa-cmd/completions — completionsPlugin()
3
+ *
4
+ * A Runa plugin that adds a `completions` command for generating
5
+ * shell completion scripts. Each shell (bash, zsh, fish) gets a
6
+ * self-contained script derived from the CLI's schema.
7
+ */
8
+ import type { PluginConfig } from '@runa-cmd/core';
9
+ import type { CompletionsPluginOptions } from './types.js';
10
+ /**
11
+ * Create a completions plugin that adds a `completions` command.
12
+ *
13
+ * Usage:
14
+ * mycli completions bash → outputs bash completion script
15
+ * mycli completions zsh → outputs zsh completion script
16
+ * mycli completions fish → outputs fish completion script
17
+ *
18
+ * Add --instructions flag to get install instructions instead.
19
+ */
20
+ export declare function completionsPlugin(opts?: CompletionsPluginOptions): PluginConfig;
21
+ //# sourceMappingURL=plugin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.d.ts","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAOnD,OAAO,KAAK,EAAE,wBAAwB,EAAS,MAAM,YAAY,CAAC;AAWlE;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,GAAE,wBAA6B,GAAG,YAAY,CA0CnF"}
package/dist/plugin.js ADDED
@@ -0,0 +1,61 @@
1
+ import { defineCommand, definePlugin } from '@runa-cmd/core';
2
+ import { z } from 'zod';
3
+ import { generateBashCompletions } from './generators/bash.js';
4
+ import { generateFishCompletions } from './generators/fish.js';
5
+ import { generateZshCompletions } from './generators/zsh.js';
6
+ import { getInstallInstructions } from './install.js';
7
+ const generators = {
8
+ bash: generateBashCompletions,
9
+ zsh: generateZshCompletions,
10
+ fish: generateFishCompletions,
11
+ };
12
+ /**
13
+ * Create a completions plugin that adds a `completions` command.
14
+ *
15
+ * Usage:
16
+ * mycli completions bash → outputs bash completion script
17
+ * mycli completions zsh → outputs zsh completion script
18
+ * mycli completions fish → outputs fish completion script
19
+ *
20
+ * Add --instructions flag to get install instructions instead.
21
+ */
22
+ export function completionsPlugin(opts = {}) {
23
+ const commandName = opts.commandName ?? 'completions';
24
+ return definePlugin({
25
+ meta: {
26
+ name: '@runa-cmd/completions',
27
+ version: '0.1.0',
28
+ description: 'Shell completion script generation',
29
+ },
30
+ capabilities: { addCommands: true },
31
+ setup(api) {
32
+ const completionsCmd = defineCommand({
33
+ meta: {
34
+ name: commandName,
35
+ description: 'Generate shell completion script',
36
+ },
37
+ args: {
38
+ shell: z.enum(['bash', 'zsh', 'fish']).describe('Target shell'),
39
+ },
40
+ options: {
41
+ instructions: z
42
+ .boolean()
43
+ .optional()
44
+ .default(false)
45
+ .describe('Print install instructions instead of the script'),
46
+ },
47
+ run({ args, options }) {
48
+ const schema = api.getSchema();
49
+ const binName = schema.meta.name;
50
+ if (options.instructions) {
51
+ process.stdout.write(getInstallInstructions(args.shell, binName));
52
+ return;
53
+ }
54
+ process.stdout.write(generators[args.shell](schema, binName));
55
+ },
56
+ });
57
+ api.addCommand(commandName, completionsCmd);
58
+ },
59
+ });
60
+ }
61
+ //# sourceMappingURL=plugin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin.js","sourceRoot":"","sources":["../src/plugin.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC7D,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,uBAAuB,EAAE,MAAM,sBAAsB,CAAC;AAC/D,OAAO,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAGtD,MAAM,UAAU,GAGZ;IACH,IAAI,EAAE,uBAAuB;IAC7B,GAAG,EAAE,sBAAsB;IAC3B,IAAI,EAAE,uBAAuB;CAC7B,CAAC;AAEF;;;;;;;;;GASG;AACH,MAAM,UAAU,iBAAiB,CAAC,OAAiC,EAAE;IACpE,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,IAAI,aAAa,CAAC;IAEtD,OAAO,YAAY,CAAC;QACnB,IAAI,EAAE;YACL,IAAI,EAAE,uBAAuB;YAC7B,OAAO,EAAE,OAAO;YAChB,WAAW,EAAE,oCAAoC;SACjD;QACD,YAAY,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE;QACnC,KAAK,CAAC,GAAG;YACR,MAAM,cAAc,GAAG,aAAa,CAAC;gBACpC,IAAI,EAAE;oBACL,IAAI,EAAE,WAAW;oBACjB,WAAW,EAAE,kCAAkC;iBAC/C;gBACD,IAAI,EAAE;oBACL,KAAK,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,cAAc,CAAC;iBAC/D;gBACD,OAAO,EAAE;oBACR,YAAY,EAAE,CAAC;yBACb,OAAO,EAAE;yBACT,QAAQ,EAAE;yBACV,OAAO,CAAC,KAAK,CAAC;yBACd,QAAQ,CAAC,kDAAkD,CAAC;iBAC9D;gBACD,GAAG,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE;oBACpB,MAAM,MAAM,GAAG,GAAG,CAAC,SAAS,EAAE,CAAC;oBAC/B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC;oBAEjC,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;wBAC1B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,sBAAsB,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC,CAAC;wBAClE,OAAO;oBACR,CAAC;oBAED,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;gBAC/D,CAAC;aACD,CAAC,CAAC;YAEH,GAAG,CAAC,UAAU,CAAC,WAAW,EAAE,cAAc,CAAC,CAAC;QAC7C,CAAC;KACD,CAAC,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * @runa-cmd/completions — Type definitions
3
+ *
4
+ * Plugin options and shell type for completionsPlugin().
5
+ */
6
+ /** Supported shells for completion generation */
7
+ export type Shell = 'bash' | 'zsh' | 'fish';
8
+ /** Options for completionsPlugin() */
9
+ export interface CompletionsPluginOptions {
10
+ /** Override the command name (default: 'completions') */
11
+ commandName?: string;
12
+ }
13
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,iDAAiD;AACjD,MAAM,MAAM,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,CAAC;AAE5C,sCAAsC;AACtC,MAAM,WAAW,wBAAwB;IACxC,yDAAyD;IACzD,WAAW,CAAC,EAAE,MAAM,CAAC;CACrB"}
package/dist/types.js ADDED
@@ -0,0 +1,7 @@
1
+ /**
2
+ * @runa-cmd/completions — Type definitions
3
+ *
4
+ * Plugin options and shell type for completionsPlugin().
5
+ */
6
+ export {};
7
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;;GAIG"}
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@runa-cmd/completions",
3
+ "version": "0.1.0",
4
+ "description": "Shell completion script generation for Runa CLIs. Auto-generate bash, zsh, and fish completions from your Zod schemas.",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "keywords": [
8
+ "cli",
9
+ "completions",
10
+ "bash",
11
+ "zsh",
12
+ "fish",
13
+ "shell",
14
+ "tab-completion",
15
+ "runa"
16
+ ],
17
+ "main": "./dist/index.js",
18
+ "types": "./dist/index.d.ts",
19
+ "exports": {
20
+ ".": {
21
+ "types": "./dist/index.d.ts",
22
+ "import": "./dist/index.js"
23
+ }
24
+ },
25
+ "peerDependencies": {
26
+ "zod": "^4.0.0",
27
+ "@runa-cmd/core": "0.1.0"
28
+ },
29
+ "engines": {
30
+ "node": ">=18.3.0"
31
+ },
32
+ "publishConfig": {
33
+ "access": "public"
34
+ },
35
+ "repository": {
36
+ "type": "git",
37
+ "url": "https://github.com/jrodrigopuca/runa-cmd.git",
38
+ "directory": "packages/completions"
39
+ },
40
+ "homepage": "https://github.com/jrodrigopuca/runa-cmd/tree/main/packages/completions#readme",
41
+ "bugs": {
42
+ "url": "https://github.com/jrodrigopuca/runa-cmd/issues"
43
+ },
44
+ "files": [
45
+ "dist",
46
+ "README.md"
47
+ ],
48
+ "devDependencies": {
49
+ "@types/node": "^25.6.0",
50
+ "typescript": "^6.0.2",
51
+ "zod": "^4.3.6",
52
+ "@runa-cmd/core": "0.1.0"
53
+ },
54
+ "scripts": {
55
+ "build": "tsc",
56
+ "dev": "tsc --watch --preserveWatchOutput",
57
+ "typecheck": "tsc --noEmit",
58
+ "test": "vitest run",
59
+ "test:watch": "vitest",
60
+ "lint": "biome check .",
61
+ "lint:fix": "biome check --write .",
62
+ "clean": "rm -rf dist"
63
+ }
64
+ }