neuro-cli 4.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.
Files changed (175) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +510 -0
  3. package/dist/advisor/advisor.d.ts +50 -0
  4. package/dist/advisor/advisor.js +178 -0
  5. package/dist/agents/base.d.ts +62 -0
  6. package/dist/agents/base.js +215 -0
  7. package/dist/agents/orchestrator.d.ts +46 -0
  8. package/dist/agents/orchestrator.js +192 -0
  9. package/dist/agents/team.d.ts +51 -0
  10. package/dist/agents/team.js +210 -0
  11. package/dist/api/models.d.ts +23 -0
  12. package/dist/api/models.js +514 -0
  13. package/dist/api/ollama.d.ts +153 -0
  14. package/dist/api/ollama.js +751 -0
  15. package/dist/api/openrouter.d.ts +55 -0
  16. package/dist/api/openrouter.js +223 -0
  17. package/dist/commands/commands.d.ts +43 -0
  18. package/dist/commands/commands.js +308 -0
  19. package/dist/config/config.d.ts +8 -0
  20. package/dist/config/config.js +311 -0
  21. package/dist/context/compaction.d.ts +54 -0
  22. package/dist/context/compaction.js +251 -0
  23. package/dist/context/custom-agents.d.ts +107 -0
  24. package/dist/context/custom-agents.js +397 -0
  25. package/dist/context/custom-tools.d.ts +120 -0
  26. package/dist/context/custom-tools.js +564 -0
  27. package/dist/context/git-checkpoint.d.ts +52 -0
  28. package/dist/context/git-checkpoint.js +240 -0
  29. package/dist/context/neuro-md.d.ts +48 -0
  30. package/dist/context/neuro-md.js +202 -0
  31. package/dist/context/neuroignore.d.ts +102 -0
  32. package/dist/context/neuroignore.js +441 -0
  33. package/dist/context/repo-map.d.ts +38 -0
  34. package/dist/context/repo-map.js +220 -0
  35. package/dist/context/skill-standard.d.ts +262 -0
  36. package/dist/context/skill-standard.js +1156 -0
  37. package/dist/context/skill-system.d.ts +75 -0
  38. package/dist/context/skill-system.js +578 -0
  39. package/dist/context/tree-sitter.d.ts +99 -0
  40. package/dist/context/tree-sitter.js +1956 -0
  41. package/dist/core/acp.d.ts +325 -0
  42. package/dist/core/acp.js +1498 -0
  43. package/dist/core/api-server.d.ts +143 -0
  44. package/dist/core/api-server.js +550 -0
  45. package/dist/core/approval.d.ts +81 -0
  46. package/dist/core/approval.js +432 -0
  47. package/dist/core/auto-compact.d.ts +127 -0
  48. package/dist/core/auto-compact.js +436 -0
  49. package/dist/core/auto-mode.d.ts +232 -0
  50. package/dist/core/auto-mode.js +831 -0
  51. package/dist/core/background-session.d.ts +166 -0
  52. package/dist/core/background-session.js +696 -0
  53. package/dist/core/cicd.d.ts +257 -0
  54. package/dist/core/cicd.js +1443 -0
  55. package/dist/core/cloud-sync.d.ts +156 -0
  56. package/dist/core/cloud-sync.js +582 -0
  57. package/dist/core/code-review.d.ts +132 -0
  58. package/dist/core/code-review.js +1191 -0
  59. package/dist/core/completion.d.ts +49 -0
  60. package/dist/core/completion.js +384 -0
  61. package/dist/core/context.d.ts +38 -0
  62. package/dist/core/context.js +144 -0
  63. package/dist/core/diff-preview.d.ts +35 -0
  64. package/dist/core/diff-preview.js +173 -0
  65. package/dist/core/doom-loop.d.ts +51 -0
  66. package/dist/core/doom-loop.js +179 -0
  67. package/dist/core/engine.d.ts +183 -0
  68. package/dist/core/engine.js +942 -0
  69. package/dist/core/extended-thinking.d.ts +103 -0
  70. package/dist/core/extended-thinking.js +269 -0
  71. package/dist/core/fallback.d.ts +54 -0
  72. package/dist/core/fallback.js +104 -0
  73. package/dist/core/git-worktree.d.ts +139 -0
  74. package/dist/core/git-worktree.js +614 -0
  75. package/dist/core/headless.d.ts +30 -0
  76. package/dist/core/headless.js +101 -0
  77. package/dist/core/i18n.d.ts +83 -0
  78. package/dist/core/i18n.js +739 -0
  79. package/dist/core/linting.d.ts +129 -0
  80. package/dist/core/linting.js +699 -0
  81. package/dist/core/model-router.d.ts +109 -0
  82. package/dist/core/model-router.js +581 -0
  83. package/dist/core/multi-model.d.ts +243 -0
  84. package/dist/core/multi-model.js +1099 -0
  85. package/dist/core/multi-session.d.ts +144 -0
  86. package/dist/core/multi-session.js +442 -0
  87. package/dist/core/multimodal.d.ts +125 -0
  88. package/dist/core/multimodal.js +286 -0
  89. package/dist/core/observability.d.ts +93 -0
  90. package/dist/core/observability.js +737 -0
  91. package/dist/core/os-sandbox.d.ts +122 -0
  92. package/dist/core/os-sandbox.js +1193 -0
  93. package/dist/core/outcome-grading.d.ts +228 -0
  94. package/dist/core/outcome-grading.js +1123 -0
  95. package/dist/core/output-styles.d.ts +57 -0
  96. package/dist/core/output-styles.js +382 -0
  97. package/dist/core/parallel-agents.d.ts +183 -0
  98. package/dist/core/parallel-agents.js +563 -0
  99. package/dist/core/plugin-bundle.d.ts +236 -0
  100. package/dist/core/plugin-bundle.js +887 -0
  101. package/dist/core/plugin-sdk.d.ts +139 -0
  102. package/dist/core/plugin-sdk.js +273 -0
  103. package/dist/core/prompt-cache.d.ts +163 -0
  104. package/dist/core/prompt-cache.js +599 -0
  105. package/dist/core/sandbox.d.ts +127 -0
  106. package/dist/core/sandbox.js +369 -0
  107. package/dist/core/scheduled-tasks.d.ts +151 -0
  108. package/dist/core/scheduled-tasks.js +502 -0
  109. package/dist/core/security-scanner.d.ts +160 -0
  110. package/dist/core/security-scanner.js +1494 -0
  111. package/dist/core/session.d.ts +83 -0
  112. package/dist/core/session.js +269 -0
  113. package/dist/core/shell-completion.d.ts +51 -0
  114. package/dist/core/shell-completion.js +674 -0
  115. package/dist/core/smart-monitor.d.ts +146 -0
  116. package/dist/core/smart-monitor.js +1199 -0
  117. package/dist/core/spec-driven.d.ts +233 -0
  118. package/dist/core/spec-driven.js +1485 -0
  119. package/dist/core/spending-warnings.d.ts +123 -0
  120. package/dist/core/spending-warnings.js +456 -0
  121. package/dist/core/sub-agent.d.ts +298 -0
  122. package/dist/core/sub-agent.js +1023 -0
  123. package/dist/core/telemetry.d.ts +157 -0
  124. package/dist/core/telemetry.js +412 -0
  125. package/dist/core/terminal-ux.d.ts +134 -0
  126. package/dist/core/terminal-ux.js +649 -0
  127. package/dist/core/testing.d.ts +146 -0
  128. package/dist/core/testing.js +1200 -0
  129. package/dist/core/types.d.ts +439 -0
  130. package/dist/core/types.js +6 -0
  131. package/dist/core/undo-redo.d.ts +112 -0
  132. package/dist/core/undo-redo.js +290 -0
  133. package/dist/core/updater.d.ts +159 -0
  134. package/dist/core/updater.js +608 -0
  135. package/dist/core/vim-mode.d.ts +151 -0
  136. package/dist/core/vim-mode.js +771 -0
  137. package/dist/core/voice.d.ts +137 -0
  138. package/dist/core/voice.js +538 -0
  139. package/dist/core/web-dashboard.d.ts +109 -0
  140. package/dist/core/web-dashboard.js +484 -0
  141. package/dist/hooks/hooks.d.ts +74 -0
  142. package/dist/hooks/hooks.js +160 -0
  143. package/dist/hooks/llm-evaluator.d.ts +165 -0
  144. package/dist/hooks/llm-evaluator.js +560 -0
  145. package/dist/index.d.ts +3 -0
  146. package/dist/index.js +1186 -0
  147. package/dist/lsp/lsp-manager.d.ts +63 -0
  148. package/dist/lsp/lsp-manager.js +351 -0
  149. package/dist/mcp/client.d.ts +133 -0
  150. package/dist/mcp/client.js +684 -0
  151. package/dist/mcp/mcp-apps.d.ts +70 -0
  152. package/dist/mcp/mcp-apps.js +1007 -0
  153. package/dist/tools/bash.d.ts +5 -0
  154. package/dist/tools/bash.js +195 -0
  155. package/dist/tools/browser.d.ts +92 -0
  156. package/dist/tools/browser.js +1570 -0
  157. package/dist/tools/extended.d.ts +6 -0
  158. package/dist/tools/extended.js +191 -0
  159. package/dist/tools/file.d.ts +10 -0
  160. package/dist/tools/file.js +382 -0
  161. package/dist/tools/github.d.ts +389 -0
  162. package/dist/tools/github.js +759 -0
  163. package/dist/tools/index.d.ts +9 -0
  164. package/dist/tools/index.js +40 -0
  165. package/dist/tools/memory.d.ts +6 -0
  166. package/dist/tools/memory.js +197 -0
  167. package/dist/tools/registry.d.ts +29 -0
  168. package/dist/tools/registry.js +64 -0
  169. package/dist/tools/web.d.ts +6 -0
  170. package/dist/tools/web.js +150 -0
  171. package/dist/ui/renderer.d.ts +97 -0
  172. package/dist/ui/renderer.js +279 -0
  173. package/dist/ui/theme.d.ts +27 -0
  174. package/dist/ui/theme.js +106 -0
  175. package/package.json +83 -0
@@ -0,0 +1,674 @@
1
+ // ============================================================
2
+ // NeuroCLI - Shell Completion Script Generator
3
+ // Generates completion scripts for bash, zsh, and fish
4
+ // Includes CLI commands, slash commands, models, themes,
5
+ // permission modes, agent names, and dynamic session IDs
6
+ // ============================================================
7
+ import { writeFileSync, mkdirSync } from 'fs';
8
+ import { dirname } from 'path';
9
+ // ---------------------------------------------------------------------------
10
+ // ShellCompletionGenerator
11
+ // ---------------------------------------------------------------------------
12
+ export class ShellCompletionGenerator {
13
+ options;
14
+ constructor(options) {
15
+ this.options = options;
16
+ }
17
+ /**
18
+ * Generate a completion script for the given shell type.
19
+ */
20
+ generate(shell) {
21
+ switch (shell) {
22
+ case 'bash':
23
+ return this.generateBash();
24
+ case 'zsh':
25
+ return this.generateZsh();
26
+ case 'fish':
27
+ return this.generateFish();
28
+ default:
29
+ throw new Error(`Unsupported shell type: ${shell}`);
30
+ }
31
+ }
32
+ // =========================================================================
33
+ // Bash completion
34
+ // =========================================================================
35
+ generateBash() {
36
+ const cmdNames = this.options.commands.map(c => c.name);
37
+ const slashCmdNames = this.options.slashCommands.map(s => s.startsWith('/') ? s : '/' + s);
38
+ const lines = [
39
+ '#!/usr/bin/env bash',
40
+ '# ------------------------------------------------------------------',
41
+ '# NeuroCLI bash completion',
42
+ '# Install: source this file or place in /etc/bash_completion.d/',
43
+ '# neuro completion bash > ~/.neuro/completion/neuro.bash',
44
+ '# echo "source ~/.neuro/completion/neuro.bash" >> ~/.bashrc',
45
+ '# ------------------------------------------------------------------',
46
+ '',
47
+ '_neuro_completion() {',
48
+ ' local cur prev opts cmd',
49
+ ' COMPREPLY=()',
50
+ ' cur="${COMP_WORDS[COMP_CWORD]}"',
51
+ ' prev="${COMP_WORDS[COMP_CWORD-1]}"',
52
+ '',
53
+ ];
54
+ // -- Determine the active subcommand ---------------------------------
55
+ lines.push(' # Determine the active subcommand');
56
+ lines.push(' cmd=""');
57
+ lines.push(' for ((i=1; i<COMP_CWORD; i++)); do');
58
+ lines.push(' case "${COMP_WORDS[i]}" in');
59
+ for (const name of cmdNames) {
60
+ lines.push(` ${this.bashEscape(name)})`);
61
+ lines.push(` cmd="${this.bashEscape(name)}"`);
62
+ lines.push(' break;;');
63
+ }
64
+ lines.push(' esac');
65
+ lines.push(' done');
66
+ lines.push('');
67
+ // -- Main command completion ------------------------------------------
68
+ lines.push(' # Main command completion');
69
+ lines.push(' if [[ -z "$cmd" ]]; then');
70
+ lines.push(` opts="${cmdNames.map(n => this.bashEscape(n)).join(' ')}"`);
71
+ lines.push(' # Global options');
72
+ lines.push(' opts="${opts} --help --version -h -V"');
73
+ lines.push(' opts="${opts} -k --api-key -m --model -t --theme --no-streaming --auto-approve"');
74
+ lines.push(' opts="${opts} -c --continue -r --resume --fork --permission-mode --diff-preview --no-diff-preview"');
75
+ lines.push('');
76
+ lines.push(' # Complete option values that need it');
77
+ lines.push(' case "$prev" in');
78
+ lines.push(' -m|--model)');
79
+ lines.push(` COMPREPLY=( $(compgen -W "${this.options.models.map(m => this.bashEscape(m)).join(' ')}" -- "$cur") )`);
80
+ lines.push(' return 0;;');
81
+ lines.push(' -t|--theme)');
82
+ lines.push(` COMPREPLY=( $(compgen -W "${this.options.themes.map(t => this.bashEscape(t)).join(' ')}" -- "$cur") )`);
83
+ lines.push(' return 0;;');
84
+ lines.push(' --permission-mode)');
85
+ lines.push(` COMPREPLY=( $(compgen -W "${this.options.permissionModes.join(' ')}" -- "$cur") )`);
86
+ lines.push(' return 0;;');
87
+ lines.push(' -r|--resume)');
88
+ lines.push(' COMPREPLY=( $(compgen -W "$(neuro sessions --list-ids 2>/dev/null || echo latest)" -- "$cur") )');
89
+ lines.push(' return 0;;');
90
+ lines.push(' -k|--api-key)');
91
+ lines.push(' return 0;;');
92
+ lines.push(' esac');
93
+ lines.push('');
94
+ lines.push(' COMPREPLY=( $(compgen -W "$opts" -- "$cur") )');
95
+ lines.push(' return 0');
96
+ lines.push(' fi');
97
+ lines.push('');
98
+ // -- Per-command option completion ------------------------------------
99
+ lines.push(' # Per-command option completion');
100
+ lines.push(' case "$cmd" in');
101
+ for (const command of this.options.commands) {
102
+ lines.push(` ${this.bashEscape(command.name)})`);
103
+ // Build the option list for this command
104
+ const flagList = command.options
105
+ .map(o => o.flags.split(/[\s,|]+/).filter(Boolean))
106
+ .flat()
107
+ .map(f => this.bashEscape(f))
108
+ .join(' ');
109
+ lines.push(` local cmd_opts="${flagList}"`);
110
+ // Options that require dynamic values
111
+ for (const opt of command.options) {
112
+ const flags = opt.flags.split(/[\s,|]+/).filter(Boolean);
113
+ const takesModel = /model/i.test(opt.flags) || /model/i.test(opt.description);
114
+ const takesAgent = /agent/i.test(opt.flags) || /agent/i.test(opt.description);
115
+ const takesTheme = /theme/i.test(opt.flags) || /theme/i.test(opt.description);
116
+ const takesPermission = /permission/i.test(opt.flags) || /permission/i.test(opt.description);
117
+ const takesFormat = /format/i.test(opt.flags) || /format/i.test(opt.description);
118
+ const takesTransport = /transport/i.test(opt.flags) || /transport/i.test(opt.description);
119
+ const takesSession = /continue|session/i.test(opt.flags);
120
+ if (takesModel || takesAgent || takesTheme || takesPermission || takesFormat || takesTransport || takesSession) {
121
+ for (const flag of flags) {
122
+ lines.push(` ${flag})`);
123
+ if (takesModel) {
124
+ lines.push(` COMPREPLY=( $(compgen -W "${this.options.models.map(m => this.bashEscape(m)).join(' ')}" -- "$cur") )`);
125
+ }
126
+ else if (takesAgent) {
127
+ lines.push(` COMPREPLY=( $(compgen -W "${this.options.agents.map(a => this.bashEscape(a)).join(' ')}" -- "$cur") )`);
128
+ }
129
+ else if (takesTheme) {
130
+ lines.push(` COMPREPLY=( $(compgen -W "${this.options.themes.join(' ')}" -- "$cur") )`);
131
+ }
132
+ else if (takesPermission) {
133
+ lines.push(` COMPREPLY=( $(compgen -W "${this.options.permissionModes.join(' ')}" -- "$cur") )`);
134
+ }
135
+ else if (takesFormat) {
136
+ lines.push(' COMPREPLY=( $(compgen -W "text json stream-json" -- "$cur") )');
137
+ }
138
+ else if (takesTransport) {
139
+ lines.push(' COMPREPLY=( $(compgen -W "stdio sse http" -- "$cur") )');
140
+ }
141
+ else if (takesSession) {
142
+ lines.push(' COMPREPLY=( $(compgen -W "$(neuro sessions --list-ids 2>/dev/null || echo latest)" -- "$cur") )');
143
+ }
144
+ lines.push(' return 0;;');
145
+ }
146
+ }
147
+ }
148
+ // Subcommand completion
149
+ if (command.subcommands && command.subcommands.length > 0) {
150
+ const subNames = command.subcommands.map(s => this.bashEscape(s.name)).join(' ');
151
+ lines.push(` local subcmds="${subNames}"`);
152
+ lines.push(' # If previous word is the command itself, complete subcommands');
153
+ lines.push(` if [[ "$prev" == "${this.bashEscape(command.name)}" ]]; then`);
154
+ lines.push(' COMPREPLY=( $(compgen -W "$subcmds" -- "$cur") )');
155
+ lines.push(' return 0');
156
+ lines.push(' fi');
157
+ lines.push(' COMPREPLY=( $(compgen -W "$cmd_opts $subcmds" -- "$cur") )');
158
+ }
159
+ else {
160
+ lines.push(' COMPREPLY=( $(compgen -W "$cmd_opts" -- "$cur") )');
161
+ }
162
+ lines.push(' return 0;;');
163
+ }
164
+ lines.push(' esac');
165
+ lines.push('');
166
+ // -- Slash command completion (inside interactive) --------------------
167
+ lines.push(' # Slash command completion (for interactive mode arguments)');
168
+ lines.push(' # These are provided for reference; interactive readline uses CompletionEngine');
169
+ lines.push(` local slash_cmds="${slashCmdNames.map(s => this.bashEscape(s)).join(' ')}"`);
170
+ lines.push('');
171
+ lines.push('}');
172
+ lines.push('');
173
+ lines.push('complete -F _neuro_completion neuro');
174
+ lines.push('');
175
+ return lines.join('\n');
176
+ }
177
+ // =========================================================================
178
+ // Zsh completion
179
+ // =========================================================================
180
+ generateZsh() {
181
+ const lines = [
182
+ '#compdef neuro',
183
+ '# ------------------------------------------------------------------',
184
+ '# NeuroCLI zsh completion',
185
+ '# Install:',
186
+ '# neuro completion zsh > ~/.zfunc/_neuro',
187
+ '# fpath=(~/.zfunc $fpath) && autoload -Uz compinit && compinit',
188
+ '# ------------------------------------------------------------------',
189
+ '',
190
+ ];
191
+ // -- Dynamic completion helper functions -------------------------------
192
+ lines.push('# Dynamic completion helpers');
193
+ lines.push('(( $+functions[_neuro_models] )) ||');
194
+ lines.push('_neuro_models() {');
195
+ lines.push(' local models; models=(');
196
+ for (const model of this.options.models) {
197
+ lines.push(` '${this.zshEscape(model)}:${this.zshEscape(model)}'`);
198
+ }
199
+ lines.push(' )');
200
+ lines.push(' _describe -t models "model" models');
201
+ lines.push('}');
202
+ lines.push('');
203
+ lines.push('(( $+functions[_neuro_themes] )) ||');
204
+ lines.push('_neuro_themes() {');
205
+ lines.push(' local themes; themes=(');
206
+ for (const theme of this.options.themes) {
207
+ lines.push(` '${this.zshEscape(theme)}:${this.zshEscape(theme)} theme'`);
208
+ }
209
+ lines.push(' )');
210
+ lines.push(' _describe -t themes "theme" themes');
211
+ lines.push('}');
212
+ lines.push('');
213
+ lines.push('(( $+functions[_neuro_permission_modes] )) ||');
214
+ lines.push('_neuro_permission_modes() {');
215
+ lines.push(' local modes; modes=(');
216
+ for (const mode of this.options.permissionModes) {
217
+ lines.push(` '${mode}:${mode} mode'`);
218
+ }
219
+ lines.push(' )');
220
+ lines.push(' _describe -t modes "permission mode" modes');
221
+ lines.push('}');
222
+ lines.push('');
223
+ lines.push('(( $+functions[_neuro_agents] )) ||');
224
+ lines.push('_neuro_agents() {');
225
+ lines.push(' local agents; agents=(');
226
+ for (const agent of this.options.agents) {
227
+ lines.push(` '${this.zshEscape(agent)}:${this.zshEscape(agent)} agent'`);
228
+ }
229
+ lines.push(' )');
230
+ lines.push(' _describe -t agents "agent" agents');
231
+ lines.push('}');
232
+ lines.push('');
233
+ lines.push('(( $+functions[_neuro_session_ids] )) ||');
234
+ lines.push('_neuro_session_ids() {');
235
+ lines.push(' local ids; ids=(${(f)"$(neuro sessions --list-ids 2>/dev/null)"} latest)');
236
+ lines.push(' _describe -t sessionids "session id" ids');
237
+ lines.push('}');
238
+ lines.push('');
239
+ lines.push('(( $+functions[_neuro_slash_commands] )) ||');
240
+ lines.push('_neuro_slash_commands() {');
241
+ lines.push(' local cmds; cmds=(');
242
+ for (const sc of this.options.slashCommands) {
243
+ const name = sc.startsWith('/') ? sc : '/' + sc;
244
+ lines.push(` '${this.zshEscape(name)}:${this.zshEscape(name)}'`);
245
+ }
246
+ lines.push(' )');
247
+ lines.push(' _describe -t slashcmds "slash command" cmds');
248
+ lines.push('}');
249
+ lines.push('');
250
+ // -- Main completion function -----------------------------------------
251
+ lines.push('_neuro() {');
252
+ lines.push(' local curcontext="$curcontext" state line ret=1');
253
+ lines.push(' typeset -A opt_args');
254
+ lines.push('');
255
+ lines.push(' # Global options');
256
+ lines.push(' local global_opts=(');
257
+ lines.push(' \'-k[API key]:api-key:\'');
258
+ lines.push(' \'-m[Model to use]:model:_neuro_models\'');
259
+ lines.push(' \'-t[UI theme]:theme:_neuro_themes\'');
260
+ lines.push(' \'--no-streaming[Disable streaming output]\'');
261
+ lines.push(' \'--auto-approve[Auto-approve all tool calls]\'');
262
+ lines.push(' \'-c[Continue most recent session]\'');
263
+ lines.push(' \'-r[Resume specific session]:session:_neuro_session_ids\'');
264
+ lines.push(' \'--fork[Fork the resumed session]\'');
265
+ lines.push(' \'--permission-mode[Permission mode]:mode:_neuro_permission_modes\'');
266
+ lines.push(' \'--diff-preview[Enable diff preview]\'');
267
+ lines.push(' \'--no-diff-preview[Disable diff preview]\'');
268
+ lines.push(' \'--help[Show help]\'');
269
+ lines.push(' \'--version[Show version]\'');
270
+ lines.push(' )');
271
+ lines.push('');
272
+ // -- Subcommands with descriptions and options ------------------------
273
+ lines.push(' local -a subcommands');
274
+ lines.push(' subcommands=(');
275
+ for (const command of this.options.commands) {
276
+ lines.push(` '${this.zshEscape(command.name)}:${this.zshEscape(command.description)}'`);
277
+ }
278
+ lines.push(' )');
279
+ lines.push('');
280
+ lines.push(' _arguments -C \\');
281
+ lines.push(' "$global_opts[@]" \\');
282
+ lines.push(` '1":command:->command" \\`);
283
+ lines.push(` "*::arg:->args" \\`);
284
+ lines.push(' && ret=0');
285
+ lines.push('');
286
+ // -- State: command ---------------------------------------------------
287
+ lines.push(' case $state in');
288
+ lines.push(' command)');
289
+ lines.push(' _describe -t commands "neuro command" subcommands && ret=0');
290
+ lines.push(' ;;');
291
+ lines.push(' args)');
292
+ lines.push(' case $words[1] in');
293
+ for (const command of this.options.commands) {
294
+ lines.push(` ${this.zshEscape(command.name)})`);
295
+ const cmdOpts = [];
296
+ for (const opt of command.options) {
297
+ const parts = opt.flags.split(/[\s,|]+/).filter(Boolean);
298
+ const takesModel = /model/i.test(opt.flags) || /model/i.test(opt.description);
299
+ const takesAgent = /agent/i.test(opt.flags) || /agent/i.test(opt.description);
300
+ const takesTheme = /theme/i.test(opt.flags) || /theme/i.test(opt.description);
301
+ const takesPermission = /permission/i.test(opt.flags) || /permission/i.test(opt.description);
302
+ const takesFormat = /format/i.test(opt.flags) || /format/i.test(opt.description);
303
+ const takesTransport = /transport/i.test(opt.flags) || /transport/i.test(opt.description);
304
+ const takesSession = /continue|session/i.test(opt.flags);
305
+ let valueAction = '';
306
+ if (takesModel)
307
+ valueAction = ':model:_neuro_models';
308
+ else if (takesAgent)
309
+ valueAction = ':agent:_neuro_agents';
310
+ else if (takesTheme)
311
+ valueAction = ':theme:_neuro_themes';
312
+ else if (takesPermission)
313
+ valueAction = ':mode:_neuro_permission_modes';
314
+ else if (takesFormat)
315
+ valueAction = ':format:(text json stream-json)';
316
+ else if (takesTransport)
317
+ valueAction = ':transport:(stdio sse http)';
318
+ else if (takesSession)
319
+ valueAction = ':session:_neuro_session_ids';
320
+ for (const part of parts) {
321
+ const escaped = this.zshEscape(part);
322
+ const desc = this.zshEscape(opt.description);
323
+ if (valueAction) {
324
+ cmdOpts.push(`'${escaped}[${desc}]${valueAction}'`);
325
+ }
326
+ else {
327
+ cmdOpts.push(`'${escaped}[${desc}]'`);
328
+ }
329
+ }
330
+ }
331
+ if (command.subcommands && command.subcommands.length > 0) {
332
+ lines.push(' local -a subcmds');
333
+ lines.push(' subcmds=(');
334
+ for (const sub of command.subcommands) {
335
+ lines.push(` '${this.zshEscape(sub.name)}:${this.zshEscape(sub.description)}'`);
336
+ }
337
+ lines.push(' )');
338
+ if (cmdOpts.length > 0) {
339
+ lines.push(' _arguments \\');
340
+ for (let i = 0; i < cmdOpts.length; i++) {
341
+ lines.push(` ${cmdOpts[i]} \\`);
342
+ }
343
+ lines.push(' "1:subcommand:->subcmd" && ret=0');
344
+ }
345
+ else {
346
+ lines.push(' _describe -t subcmds "subcommand" subcmds && ret=0');
347
+ }
348
+ lines.push(' case $state in');
349
+ lines.push(' subcmd)');
350
+ lines.push(' _describe -t subcmds "subcommand" subcmds && ret=0');
351
+ lines.push(' ;;');
352
+ lines.push(' esac');
353
+ }
354
+ else if (cmdOpts.length > 0) {
355
+ lines.push(' _arguments \\');
356
+ for (let i = 0; i < cmdOpts.length; i++) {
357
+ lines.push(` ${cmdOpts[i]}${i < cmdOpts.length - 1 ? ' \\' : ''}`);
358
+ }
359
+ lines.push(' && ret=0');
360
+ }
361
+ lines.push(' ;;');
362
+ }
363
+ lines.push(' esac');
364
+ lines.push(' ;;');
365
+ lines.push(' esac');
366
+ lines.push('');
367
+ lines.push(' return ret');
368
+ lines.push('}');
369
+ lines.push('');
370
+ lines.push('_neuro "$@"');
371
+ lines.push('');
372
+ return lines.join('\n');
373
+ }
374
+ // =========================================================================
375
+ // Fish completion
376
+ // =========================================================================
377
+ generateFish() {
378
+ const lines = [
379
+ '# ------------------------------------------------------------------',
380
+ '# NeuroCLI fish completion',
381
+ '# Install:',
382
+ '# neuro completion fish > ~/.config/fish/completions/neuro.fish',
383
+ '# ------------------------------------------------------------------',
384
+ '',
385
+ ];
386
+ // -- Disable file completions -----------------------------------------
387
+ lines.push('complete -c neuro -f');
388
+ lines.push('');
389
+ // -- Helper: model completions ----------------------------------------
390
+ lines.push('# Models');
391
+ for (const model of this.options.models) {
392
+ lines.push(`complete -c neuro -n '__fish_use_subcommand' -l model -d '${this.fishEscape(model)}'`);
393
+ }
394
+ lines.push('');
395
+ // -- Global options ---------------------------------------------------
396
+ lines.push('# Global options');
397
+ lines.push("complete -c neuro -n '__fish_use_subcommand' -s k -l api-key -d 'OpenRouter API key' -r");
398
+ lines.push("complete -c neuro -n '__fish_use_subcommand' -s m -l model -d 'Model to use' -r");
399
+ lines.push("complete -c neuro -n '__fish_use_subcommand' -s t -l theme -d 'UI theme' -r");
400
+ lines.push("complete -c neuro -n '__fish_use_subcommand' -l no-streaming -d 'Disable streaming output'");
401
+ lines.push("complete -c neuro -n '__fish_use_subcommand' -l auto-approve -d 'Auto-approve all tool calls'");
402
+ lines.push("complete -c neuro -n '__fish_use_subcommand' -s c -l continue -d 'Continue most recent session'");
403
+ lines.push("complete -c neuro -n '__fish_use_subcommand' -s r -l resume -d 'Resume specific session' -r");
404
+ lines.push("complete -c neuro -n '__fish_use_subcommand' -l fork -d 'Fork the resumed session'");
405
+ lines.push("complete -c neuro -n '__fish_use_subcommand' -l permission-mode -d 'Permission mode' -r");
406
+ lines.push("complete -c neuro -n '__fish_use_subcommand' -l diff-preview -d 'Enable diff preview'");
407
+ lines.push("complete -c neuro -n '__fish_use_subcommand' -l no-diff-preview -d 'Disable diff preview'");
408
+ lines.push("complete -c neuro -n '__fish_use_subcommand' -s h -l help -d 'Show help'");
409
+ lines.push("complete -c neuro -n '__fish_use_subcommand' -s V -l version -d 'Show version'");
410
+ lines.push('');
411
+ // -- Condition function: only complete for a specific subcommand ------
412
+ // Build a helper that checks if a given subcommand is the active one
413
+ const cmdNames = this.options.commands.map(c => c.name);
414
+ const allCmdsExcept = (exclude) => cmdNames.filter(n => n !== exclude).map(n => this.fishEscape(n)).join(' ');
415
+ // -- Subcommands ------------------------------------------------------
416
+ lines.push('# Subcommands');
417
+ for (const command of this.options.commands) {
418
+ lines.push(`complete -c neuro -n '__fish_use_subcommand' -a '${this.fishEscape(command.name)}' -d '${this.fishEscape(command.description)}'`);
419
+ }
420
+ lines.push('');
421
+ // -- Per-command options ----------------------------------------------
422
+ lines.push('# Per-command options');
423
+ for (const command of this.options.commands) {
424
+ const condition = `__fish_seen_subcommand_from ${this.fishEscape(command.name)}`;
425
+ for (const opt of command.options) {
426
+ const flags = opt.flags.split(/[\s,|]+/).filter(Boolean);
427
+ const takesModel = /model/i.test(opt.flags) || /model/i.test(opt.description);
428
+ const takesAgent = /agent/i.test(opt.flags) || /agent/i.test(opt.description);
429
+ const takesTheme = /theme/i.test(opt.flags) || /theme/i.test(opt.description);
430
+ const takesPermission = /permission/i.test(opt.flags) || /permission/i.test(opt.description);
431
+ const takesFormat = /format/i.test(opt.flags) || /format/i.test(opt.description);
432
+ const takesTransport = /transport/i.test(opt.flags) || /transport/i.test(opt.description);
433
+ const takesSession = /continue|session/i.test(opt.flags);
434
+ // Determine if the option takes a required argument
435
+ const takesArg = takesModel || takesAgent || takesTheme || takesPermission || takesFormat || takesTransport || takesSession;
436
+ const requireFlag = takesArg ? ' -r' : '';
437
+ for (const flag of flags) {
438
+ const escaped = this.fishEscape(flag);
439
+ const desc = this.fishEscape(opt.description);
440
+ let argCompletions = '';
441
+ if (takesModel) {
442
+ argCompletions = ` -a '${this.options.models.map(m => this.fishEscape(m)).join(' ')}'`;
443
+ }
444
+ else if (takesAgent) {
445
+ argCompletions = ` -a '${this.options.agents.map(a => this.fishEscape(a)).join(' ')}'`;
446
+ }
447
+ else if (takesTheme) {
448
+ argCompletions = ` -a '${this.options.themes.join(' ')}'`;
449
+ }
450
+ else if (takesPermission) {
451
+ argCompletions = ` -a '${this.options.permissionModes.join(' ')}'`;
452
+ }
453
+ else if (takesFormat) {
454
+ argCompletions = " -a 'text json stream-json'";
455
+ }
456
+ else if (takesTransport) {
457
+ argCompletions = " -a 'stdio sse http'";
458
+ }
459
+ else if (takesSession) {
460
+ argCompletions = " -a '(neuro sessions --list-ids 2>/dev/null; echo latest)'";
461
+ }
462
+ lines.push(`complete -c neuro -n '${condition}'${flag.length === 1 ? ` -s ${escaped}` : ` -l ${escaped.replace(/^-+/, '')}`}${requireFlag} -d '${desc}'${argCompletions}`);
463
+ }
464
+ }
465
+ // Subcommands of this command
466
+ if (command.subcommands && command.subcommands.length > 0) {
467
+ for (const sub of command.subcommands) {
468
+ lines.push(`complete -c neuro -n '${condition}' -a '${this.fishEscape(sub.name)}' -d '${this.fishEscape(sub.description)}'`);
469
+ }
470
+ }
471
+ }
472
+ lines.push('');
473
+ // -- Slash commands (informational) -----------------------------------
474
+ lines.push('# Slash commands (for interactive mode reference)');
475
+ for (const sc of this.options.slashCommands) {
476
+ const name = sc.startsWith('/') ? sc : '/' + sc;
477
+ lines.push(`# ${this.fishEscape(name)}`);
478
+ }
479
+ lines.push('');
480
+ return lines.join('\n');
481
+ }
482
+ // =========================================================================
483
+ // Write to file
484
+ // =========================================================================
485
+ writeToFile(shell, filePath) {
486
+ const content = this.generate(shell);
487
+ const dir = dirname(filePath);
488
+ try {
489
+ mkdirSync(dir, { recursive: true });
490
+ }
491
+ catch {
492
+ // Directory may already exist
493
+ }
494
+ writeFileSync(filePath, content, 'utf-8');
495
+ }
496
+ // =========================================================================
497
+ // Default options -- mirrors the real NeuroCLI configuration
498
+ // =========================================================================
499
+ static getDefaultOptions() {
500
+ return {
501
+ commands: [
502
+ {
503
+ name: 'run',
504
+ description: 'Run a task in headless/CI mode',
505
+ options: [
506
+ { flags: '-m, --model', description: 'Model to use' },
507
+ { flags: '-a, --agent', description: 'Agent to use' },
508
+ { flags: '--max-turns', description: 'Max agent iterations' },
509
+ { flags: '--allowed-tools', description: 'Comma-separated list of allowed tools' },
510
+ { flags: '-f, --format', description: 'Output format: text, json, stream-json' },
511
+ { flags: '--auto', description: 'Auto-approve all tool calls' },
512
+ { flags: '--continue', description: 'Continue a specific session' },
513
+ ],
514
+ },
515
+ {
516
+ name: 'ask',
517
+ description: 'Ask a single question and exit',
518
+ options: [
519
+ { flags: '-m, --model', description: 'Model to use' },
520
+ { flags: '-a, --agent', description: 'Agent to use' },
521
+ { flags: '-f, --format', description: 'Output format: text, json' },
522
+ ],
523
+ },
524
+ {
525
+ name: 'models',
526
+ description: 'List available models',
527
+ options: [],
528
+ },
529
+ {
530
+ name: 'agents',
531
+ description: 'List available agents',
532
+ options: [],
533
+ },
534
+ {
535
+ name: 'config',
536
+ description: 'Show or modify configuration',
537
+ options: [
538
+ { flags: '--set-key', description: 'Set API key' },
539
+ { flags: '--set-model', description: 'Set default model' },
540
+ { flags: '--set-theme', description: 'Set UI theme' },
541
+ { flags: '--set-permission', description: 'Set permission mode (manual, auto, plan, yolo)' },
542
+ { flags: '--show', description: 'Show current config' },
543
+ ],
544
+ },
545
+ {
546
+ name: 'sessions',
547
+ description: 'List or manage sessions',
548
+ options: [
549
+ { flags: '--clear', description: 'Clear all sessions' },
550
+ ],
551
+ },
552
+ {
553
+ name: 'mcp',
554
+ description: 'Manage MCP (Model Context Protocol) servers',
555
+ options: [
556
+ { flags: '-t, --transport', description: 'Transport type: stdio, sse, http' },
557
+ { flags: '--headers', description: 'HTTP headers as JSON string' },
558
+ ],
559
+ subcommands: [
560
+ { name: 'add', description: 'Add an MCP server' },
561
+ { name: 'list', description: 'List configured MCP servers' },
562
+ { name: 'remove', description: 'Remove an MCP server' },
563
+ { name: 'connect', description: 'Connect to an MCP server' },
564
+ { name: 'disconnect', description: 'Disconnect from an MCP server' },
565
+ { name: 'health', description: 'Check MCP server health' },
566
+ ],
567
+ },
568
+ ],
569
+ models: [
570
+ 'qwen/qwen3-coder:free',
571
+ 'qwen/qwen3-next-80b-a3b-instruct:free',
572
+ 'nvidia/nemotron-3-super-120b-a12b:free',
573
+ 'nvidia/nemotron-3-ultra-550b-a55b:free',
574
+ 'nvidia/nemotron-3-nano-omni-30b-a3b-reasoning:free',
575
+ 'nvidia/nemotron-3-nano-30b-a3b:free',
576
+ 'nvidia/nemotron-nano-12b-v2-vl:free',
577
+ 'nvidia/nemotron-nano-9b-v2:free',
578
+ 'meta-llama/llama-3.3-70b-instruct:free',
579
+ 'meta-llama/llama-3.2-3b-instruct:free',
580
+ 'google/gemma-4-31b-it:free',
581
+ 'google/gemma-4-26b-a4b-it:free',
582
+ 'poolside/laguna-m.1:free',
583
+ 'poolside/laguna-xs-2.1:free',
584
+ 'cohere/north-mini-code:free',
585
+ 'openai/gpt-oss-20b:free',
586
+ 'nousresearch/hermes-3-llama-3.1-405b:free',
587
+ 'tencent/hy3:free',
588
+ 'cognitivecomputations/dolphin-mistral-24b-venice-edition:free',
589
+ 'openrouter/free',
590
+ 'anthropic/claude-sonnet-4',
591
+ 'anthropic/claude-opus-4',
592
+ 'anthropic/claude-3.5-haiku',
593
+ 'google/gemini-2.5-pro',
594
+ 'google/gemini-2.5-flash',
595
+ 'openai/gpt-4o',
596
+ 'openai/gpt-4o-mini',
597
+ 'openai/o3',
598
+ 'openai/o4-mini',
599
+ 'meta-llama/llama-4-maverick',
600
+ 'deepseek/deepseek-r1',
601
+ 'deepseek/deepseek-chat',
602
+ 'qwen/qwen3-235b-a22b',
603
+ 'mistralai/mistral-large-2411',
604
+ ],
605
+ themes: ['dracula', 'dark', 'nord', 'light'],
606
+ permissionModes: ['manual', 'auto', 'plan', 'yolo'],
607
+ agents: ['Planner', 'Coder', 'Reviewer', 'Researcher', 'Tester', 'Debugger', 'Architect', 'DevOps'],
608
+ slashCommands: [
609
+ '/help',
610
+ '/model',
611
+ '/agent',
612
+ '/auto',
613
+ '/orchestrate',
614
+ '/plan',
615
+ '/direct',
616
+ '/plan-mode',
617
+ '/stats',
618
+ '/theme',
619
+ '/clear',
620
+ '/exit',
621
+ '/quit',
622
+ '/resume',
623
+ '/compact',
624
+ '/undo',
625
+ '/redo',
626
+ '/mcp',
627
+ '/fork',
628
+ '/init',
629
+ '/permission',
630
+ '/perm',
631
+ '/doctor',
632
+ '/export',
633
+ '/import',
634
+ '/sandbox',
635
+ '/whitelist',
636
+ '/blacklist',
637
+ ],
638
+ };
639
+ }
640
+ // =========================================================================
641
+ // Escaping helpers
642
+ // =========================================================================
643
+ /**
644
+ * Escape a string for safe embedding in a bash double-quoted context.
645
+ * Escapes: backslash, double-quote, dollar, backtick, and exclamation.
646
+ */
647
+ bashEscape(str) {
648
+ return str
649
+ .replace(/\\/g, '\\\\')
650
+ .replace(/"/g, '\\"')
651
+ .replace(/\$/g, '\\$')
652
+ .replace(/`/g, '\\`')
653
+ .replace(/!/g, '\\!');
654
+ }
655
+ /**
656
+ * Escape a string for safe embedding in a zsh single-quoted context.
657
+ * Inside single quotes only the single quote itself needs escaping;
658
+ * zsh uses '\'' (end quote, escaped quote, reopen quote).
659
+ */
660
+ zshEscape(str) {
661
+ return str.replace(/'/g, "'\\''");
662
+ }
663
+ /**
664
+ * Escape a string for safe embedding in a fish completion description
665
+ * or argument. Fish uses single quotes; escape single quotes and
666
+ * backslashes.
667
+ */
668
+ fishEscape(str) {
669
+ return str
670
+ .replace(/\\/g, '\\\\')
671
+ .replace(/'/g, "\\'");
672
+ }
673
+ }
674
+ //# sourceMappingURL=shell-completion.js.map