|
| 1 | +# CLI Completion Specification |
| 2 | + |
| 3 | +## Purpose |
| 4 | + |
| 5 | +The `openspec completion` command SHALL provide shell completion functionality for all OpenSpec CLI commands, flags, and dynamic values (change IDs, spec IDs), with support for Zsh (including Oh My Zsh) and a scalable architecture ready for future shells (bash, fish, PowerShell). The completion system SHALL integrate with Zsh's native completion behavior rather than attempting to customize the user experience. |
| 6 | + |
| 7 | +## ADDED Requirements |
| 8 | + |
| 9 | +### Requirement: Native Shell Behavior Integration |
| 10 | + |
| 11 | +The completion system SHALL respect and integrate with Zsh's native completion patterns and user interaction model. |
| 12 | + |
| 13 | +#### Scenario: Zsh native completion |
| 14 | + |
| 15 | +- **WHEN** generating Zsh completion scripts |
| 16 | +- **THEN** use Zsh completion system with `_arguments`, `_describe`, and `compadd` |
| 17 | +- **AND** completions SHALL trigger on single TAB (standard Zsh behavior) |
| 18 | +- **AND** display as an interactive menu that users navigate with TAB/arrow keys |
| 19 | +- **AND** support Oh My Zsh's enhanced menu styling automatically |
| 20 | + |
| 21 | +#### Scenario: No custom UX patterns |
| 22 | + |
| 23 | +- **WHEN** implementing Zsh completion |
| 24 | +- **THEN** do NOT attempt to customize completion trigger behavior |
| 25 | +- **AND** do NOT override Zsh-specific navigation patterns |
| 26 | +- **AND** ensure completions feel native to experienced Zsh users |
| 27 | + |
| 28 | +### Requirement: Command Structure |
| 29 | + |
| 30 | +The completion command SHALL follow a subcommand pattern for generating and managing completion scripts. |
| 31 | + |
| 32 | +#### Scenario: Available subcommands |
| 33 | + |
| 34 | +- **WHEN** user executes `openspec completion --help` |
| 35 | +- **THEN** display available subcommands: |
| 36 | + - `zsh` - Generate Zsh completion script |
| 37 | + - `install [shell]` - Install completion for Zsh (auto-detects or requires explicit shell) |
| 38 | + - `uninstall [shell]` - Remove completion for Zsh (auto-detects or requires explicit shell) |
| 39 | + |
| 40 | +### Requirement: Shell Detection |
| 41 | + |
| 42 | +The completion system SHALL automatically detect the user's current shell environment. |
| 43 | + |
| 44 | +#### Scenario: Detecting Zsh from environment |
| 45 | + |
| 46 | +- **WHEN** no shell is explicitly specified |
| 47 | +- **THEN** read the `$SHELL` environment variable |
| 48 | +- **AND** extract the shell name from the path (e.g., `/bin/zsh` → `zsh`) |
| 49 | +- **AND** validate the shell is `zsh` |
| 50 | +- **AND** throw an error if the shell is not `zsh`, with message indicating only Zsh is currently supported |
| 51 | + |
| 52 | +#### Scenario: Non-Zsh shell detection |
| 53 | + |
| 54 | +- **WHEN** shell path indicates bash, fish, powershell, or other non-Zsh shell |
| 55 | +- **THEN** throw error: "Shell '<name>' is not supported yet. Currently supported: zsh" |
| 56 | + |
| 57 | +### Requirement: Completion Generation |
| 58 | + |
| 59 | +The completion command SHALL generate Zsh completion scripts on demand. |
| 60 | + |
| 61 | +#### Scenario: Generating Zsh completion |
| 62 | + |
| 63 | +- **WHEN** user executes `openspec completion zsh` |
| 64 | +- **THEN** output a complete Zsh completion script to stdout |
| 65 | +- **AND** include completions for all commands: init, list, show, validate, archive, view, update, change, spec, completion |
| 66 | +- **AND** include all command-specific flags and options |
| 67 | +- **AND** use Zsh's `_arguments` and `_describe` built-in functions |
| 68 | +- **AND** support dynamic completion for change and spec IDs |
| 69 | + |
| 70 | +### Requirement: Dynamic Completions |
| 71 | + |
| 72 | +The completion system SHALL provide context-aware dynamic completions for project-specific values. |
| 73 | + |
| 74 | +#### Scenario: Completing change IDs |
| 75 | + |
| 76 | +- **WHEN** completing arguments for commands that accept change names (show, validate, archive) |
| 77 | +- **THEN** discover active changes from `openspec/changes/` directory |
| 78 | +- **AND** exclude archived changes in `openspec/changes/archive/` |
| 79 | +- **AND** return change IDs as completion suggestions |
| 80 | +- **AND** only provide suggestions when inside an OpenSpec-enabled project |
| 81 | + |
| 82 | +#### Scenario: Completing spec IDs |
| 83 | + |
| 84 | +- **WHEN** completing arguments for commands that accept spec names (show, validate) |
| 85 | +- **THEN** discover specs from `openspec/specs/` directory |
| 86 | +- **AND** return spec IDs as completion suggestions |
| 87 | +- **AND** only provide suggestions when inside an OpenSpec-enabled project |
| 88 | + |
| 89 | +#### Scenario: Completion caching |
| 90 | + |
| 91 | +- **WHEN** dynamic completions are requested |
| 92 | +- **THEN** cache discovered change and spec IDs for 2 seconds |
| 93 | +- **AND** reuse cached values for subsequent requests within cache window |
| 94 | +- **AND** automatically refresh cache after expiration |
| 95 | + |
| 96 | +#### Scenario: Project detection |
| 97 | + |
| 98 | +- **WHEN** user requests completions outside an OpenSpec project |
| 99 | +- **THEN** skip dynamic change/spec ID completions |
| 100 | +- **AND** only suggest static commands and flags |
| 101 | + |
| 102 | +### Requirement: Installation Automation |
| 103 | + |
| 104 | +The completion command SHALL automatically install completion scripts into shell configuration files. |
| 105 | + |
| 106 | +#### Scenario: Installing for Oh My Zsh |
| 107 | + |
| 108 | +- **WHEN** user executes `openspec completion install zsh` |
| 109 | +- **THEN** detect if Oh My Zsh is installed by checking for `$ZSH` environment variable or `~/.oh-my-zsh/` directory |
| 110 | +- **AND** create custom completions directory at `~/.oh-my-zsh/custom/completions/` if it doesn't exist |
| 111 | +- **AND** write completion script to `~/.oh-my-zsh/custom/completions/_openspec` |
| 112 | +- **AND** ensure `~/.oh-my-zsh/custom/completions` is in `$fpath` by updating `~/.zshrc` if needed |
| 113 | +- **AND** display success message with instruction to run `exec zsh` or restart terminal |
| 114 | + |
| 115 | +#### Scenario: Installing for standard Zsh |
| 116 | + |
| 117 | +- **WHEN** user executes `openspec completion install zsh` and Oh My Zsh is not detected |
| 118 | +- **THEN** create completions directory at `~/.zsh/completions/` if it doesn't exist |
| 119 | +- **AND** write completion script to `~/.zsh/completions/_openspec` |
| 120 | +- **AND** add `fpath=(~/.zsh/completions $fpath)` to `~/.zshrc` if not already present |
| 121 | +- **AND** add `autoload -Uz compinit && compinit` to `~/.zshrc` if not already present |
| 122 | +- **AND** display success message with instruction to run `exec zsh` or restart terminal |
| 123 | + |
| 124 | +#### Scenario: Auto-detecting Zsh for installation |
| 125 | + |
| 126 | +- **WHEN** user executes `openspec completion install` without specifying a shell |
| 127 | +- **THEN** detect current shell using shell detection logic |
| 128 | +- **AND** install completion if detected shell is Zsh |
| 129 | +- **AND** throw error if detected shell is not Zsh |
| 130 | +- **AND** display which shell was detected |
| 131 | + |
| 132 | +#### Scenario: Already installed |
| 133 | + |
| 134 | +- **WHEN** completion is already installed for the target shell |
| 135 | +- **THEN** display message indicating completion is already installed |
| 136 | +- **AND** offer to reinstall/update by overwriting existing files |
| 137 | +- **AND** exit with code 0 |
| 138 | + |
| 139 | +### Requirement: Uninstallation |
| 140 | + |
| 141 | +The completion command SHALL remove installed completion scripts and configuration. |
| 142 | + |
| 143 | +#### Scenario: Uninstalling Oh My Zsh completion |
| 144 | + |
| 145 | +- **WHEN** user executes `openspec completion uninstall zsh` |
| 146 | +- **THEN** remove `~/.oh-my-zsh/custom/completions/_openspec` if Oh My Zsh is detected |
| 147 | +- **AND** remove `~/.zsh/completions/_openspec` if standard Zsh setup is detected |
| 148 | +- **AND** optionally remove fpath modifications from `~/.zshrc` (with confirmation) |
| 149 | +- **AND** display success message |
| 150 | + |
| 151 | +#### Scenario: Auto-detecting Zsh for uninstallation |
| 152 | + |
| 153 | +- **WHEN** user executes `openspec completion uninstall` without specifying a shell |
| 154 | +- **THEN** detect current shell and uninstall completion if shell is Zsh |
| 155 | +- **AND** throw error if detected shell is not Zsh |
| 156 | + |
| 157 | +#### Scenario: Not installed |
| 158 | + |
| 159 | +- **WHEN** attempting to uninstall completion that isn't installed |
| 160 | +- **THEN** display message indicating completion is not installed |
| 161 | +- **AND** exit with code 0 |
| 162 | + |
| 163 | +### Requirement: Architecture Patterns |
| 164 | + |
| 165 | +The completion implementation SHALL follow clean architecture principles with TypeScript best practices. |
| 166 | + |
| 167 | +#### Scenario: Shell-specific generators |
| 168 | + |
| 169 | +- **WHEN** implementing completion generators |
| 170 | +- **THEN** create `ZshCompletionGenerator` class for Zsh |
| 171 | +- **AND** implement a common `CompletionGenerator` interface with methods: |
| 172 | + - `generate(): string` - Returns complete shell script |
| 173 | + - `getInstallPath(): string` - Returns target installation path |
| 174 | + - `getConfigFile(): string` - Returns shell configuration file path |
| 175 | +- **AND** design interface to be extensible for future shells (bash, fish, powershell) |
| 176 | + |
| 177 | +#### Scenario: Dynamic completion providers |
| 178 | + |
| 179 | +- **WHEN** implementing dynamic completions |
| 180 | +- **THEN** create a `CompletionProvider` class that encapsulates project discovery logic |
| 181 | +- **AND** implement methods: |
| 182 | + - `getChangeIds(): Promise<string[]>` - Discovers active change IDs |
| 183 | + - `getSpecIds(): Promise<string[]>` - Discovers spec IDs |
| 184 | + - `isOpenSpecProject(): boolean` - Checks if current directory is OpenSpec-enabled |
| 185 | +- **AND** implement caching with 2-second TTL using class properties |
| 186 | + |
| 187 | +#### Scenario: Command registry |
| 188 | + |
| 189 | +- **WHEN** defining completable commands |
| 190 | +- **THEN** create a centralized `CommandDefinition` type with properties: |
| 191 | + - `name: string` - Command name |
| 192 | + - `description: string` - Help text |
| 193 | + - `flags: FlagDefinition[]` - Available flags |
| 194 | + - `acceptsChangeId: boolean` - Whether command takes change ID argument |
| 195 | + - `acceptsSpecId: boolean` - Whether command takes spec ID argument |
| 196 | + - `subcommands?: CommandDefinition[]` - Nested subcommands |
| 197 | +- **AND** export a `COMMAND_REGISTRY` constant with all command definitions |
| 198 | +- **AND** generators consume this registry to ensure consistency |
| 199 | + |
| 200 | +#### Scenario: Type-safe shell detection |
| 201 | + |
| 202 | +- **WHEN** implementing shell detection |
| 203 | +- **THEN** define a `SupportedShell` type as literal type: `'zsh'` |
| 204 | +- **AND** implement `detectShell()` function that returns 'zsh' or throws error |
| 205 | +- **AND** design type to be extensible (e.g., future: `'bash' | 'zsh' | 'fish' | 'powershell'`) |
| 206 | + |
| 207 | +### Requirement: Error Handling |
| 208 | + |
| 209 | +The completion command SHALL provide clear error messages for common failure scenarios. |
| 210 | + |
| 211 | +#### Scenario: Unsupported shell |
| 212 | + |
| 213 | +- **WHEN** user requests completion for unsupported shell (bash, fish, powershell, etc.) |
| 214 | +- **THEN** display error message: "Shell '<name>' is not supported yet. Currently supported: zsh" |
| 215 | +- **AND** exit with code 1 |
| 216 | + |
| 217 | +#### Scenario: Permission errors during installation |
| 218 | + |
| 219 | +- **WHEN** installation fails due to file permission issues |
| 220 | +- **THEN** display clear error message indicating permission problem |
| 221 | +- **AND** suggest using appropriate permissions or alternative installation method |
| 222 | +- **AND** exit with code 1 |
| 223 | + |
| 224 | +#### Scenario: Missing shell configuration directory |
| 225 | + |
| 226 | +- **WHEN** expected shell configuration directory doesn't exist |
| 227 | +- **THEN** create the directory automatically (with user notification) |
| 228 | +- **AND** proceed with installation |
| 229 | + |
| 230 | +#### Scenario: Shell not detected |
| 231 | + |
| 232 | +- **WHEN** `openspec completion install` cannot detect current shell or detects non-Zsh shell |
| 233 | +- **THEN** display error: "Could not detect Zsh. Please specify explicitly: openspec completion install zsh" |
| 234 | +- **AND** exit with code 1 |
| 235 | + |
| 236 | +### Requirement: Output Format |
| 237 | + |
| 238 | +The completion command SHALL provide machine-parseable and human-readable output. |
| 239 | + |
| 240 | +#### Scenario: Script generation output |
| 241 | + |
| 242 | +- **WHEN** generating completion script to stdout |
| 243 | +- **THEN** output only the completion script content (no extra messages) |
| 244 | +- **AND** allow redirection to files: `openspec completion zsh > /path/to/_openspec` |
| 245 | + |
| 246 | +#### Scenario: Installation success output |
| 247 | + |
| 248 | +- **WHEN** installation completes successfully |
| 249 | +- **THEN** display formatted success message with: |
| 250 | + - Checkmark indicator |
| 251 | + - Installation location |
| 252 | + - Next steps (shell reload instructions) |
| 253 | +- **AND** use colors when terminal supports it (unless `--no-color` is set) |
| 254 | + |
| 255 | +#### Scenario: Verbose installation output |
| 256 | + |
| 257 | +- **WHEN** user provides `--verbose` flag during installation |
| 258 | +- **THEN** display detailed steps: |
| 259 | + - Shell detection result |
| 260 | + - Target file paths |
| 261 | + - Configuration modifications |
| 262 | + - File creation confirmations |
| 263 | + |
| 264 | +### Requirement: Testing Support |
| 265 | + |
| 266 | +The completion implementation SHALL be testable with unit and integration tests. |
| 267 | + |
| 268 | +#### Scenario: Mock shell environment |
| 269 | + |
| 270 | +- **WHEN** writing tests for shell detection |
| 271 | +- **THEN** allow overriding `$SHELL` environment variable |
| 272 | +- **AND** use dependency injection for file system operations |
| 273 | + |
| 274 | +#### Scenario: Generator output verification |
| 275 | + |
| 276 | +- **WHEN** testing completion generators |
| 277 | +- **THEN** verify generated scripts contain expected patterns |
| 278 | +- **AND** test that command registry is properly consumed |
| 279 | +- **AND** ensure dynamic completion placeholders are present |
| 280 | + |
| 281 | +#### Scenario: Installation simulation |
| 282 | + |
| 283 | +- **WHEN** testing installation logic |
| 284 | +- **THEN** use temporary test directories instead of actual home directories |
| 285 | +- **AND** verify file creation without modifying real shell configurations |
| 286 | +- **AND** test path resolution logic independently |
| 287 | + |
| 288 | +## Not in Scope |
| 289 | + |
| 290 | +The following shells are **architecturally documented but not implemented** in this proposal. They will be added in future proposals: |
| 291 | + |
| 292 | +- **Bash completion** - Will use bash-completion framework with `_init_completion`, `compgen`, and `COMPREPLY` |
| 293 | +- **Fish completion** - Will use Fish's declarative `complete -c` syntax |
| 294 | +- **PowerShell completion** - Will use `Register-ArgumentCompleter` with completion result objects |
| 295 | + |
| 296 | +The plugin-based architecture (CompletionGenerator interface, command registry, dynamic providers) is designed to make adding these shells straightforward in follow-up changes. |
| 297 | + |
| 298 | +## Why |
| 299 | + |
| 300 | +Shell completions are essential for professional CLI tools and significantly improve developer experience by reducing friction, errors, and cognitive load during daily workflows. |
0 commit comments