# Milestone 13: Shell Completions ## Overview Auto-completion for Cortex CLI in Bash, Zsh, Fish, and PowerShell. Tab-complete commands, node IDs, tags, and options. ## Motivation - Tab completion is expected in modern CLIs - Reduces typing and errors - Helps discoverability of commands - Professional polish ## Features ### 13.1 Command Completion ```bash cortex # add children decay export graph index journal link list query remove serve show update ``` ### 13.2 Option Completion ```bash cortex add -- # --title --content --tags --status --section --help ``` ### 13.3 Node ID Completion ```bash cortex show # abc123 def456 ghi789 (recent node IDs) cortex show abc # abc123 abc456 (matching prefixes) ``` ### 13.4 Tag Completion ```bash cortex list --tags # auth backend security api docs (existing tags) ``` ### 13.5 Kind/Status Completion ```bash cortex add # memory component task decision cortex list --status # active todo done deprecated ``` ### 13.6 Graph Completion ```bash cortex use # default work personal myproject ``` ## Implementation ### Completion Generator ```typescript // src/cli/completions/index.ts export function generateCompletions(shell: 'bash' | 'zsh' | 'fish' | 'powershell'): string { switch (shell) { case 'bash': return generateBashCompletions(); case 'zsh': return generateZshCompletions(); case 'fish': return generateFishCompletions(); case 'powershell': return generatePowerShellCompletions(); } } ``` ### Bash Completions ```bash # Generated by cortex completions bash _cortex_completions() { local cur prev words cword _init_completion || return local commands="add children decay export graph index journal link list query remove serve show update use graphs" local kinds="memory component task decision" local statuses="active todo doing done deprecated" case "${prev}" in cortex) COMPREPLY=($(compgen -W "${commands}" -- "${cur}")) return 0 ;; add) COMPREPLY=($(compgen -W "${kinds}" -- "${cur}")) return 0 ;; --kind) COMPREPLY=($(compgen -W "${kinds}" -- "${cur}")) return 0 ;; --status) COMPREPLY=($(compgen -W "${statuses}" -- "${cur}")) return 0 ;; --tags) # Dynamic: fetch existing tags local tags=$(cortex --get-tags 2>/dev/null) COMPREPLY=($(compgen -W "${tags}" -- "${cur}")) return 0 ;; show|update|remove|link|children) # Dynamic: fetch node IDs local nodes=$(cortex --get-nodes "${cur}" 2>/dev/null) COMPREPLY=($(compgen -W "${nodes}" -- "${cur}")) return 0 ;; use) # Dynamic: fetch graphs local graphs=$(cortex --get-graphs 2>/dev/null) COMPREPLY=($(compgen -W "${graphs}" -- "${cur}")) return 0 ;; esac # Options if [[ "${cur}" == -* ]]; then local opts="--help --version --title --content --tags --status --kind --limit --format" COMPREPLY=($(compgen -W "${opts}" -- "${cur}")) return 0 fi } complete -F _cortex_completions cortex ``` ### Zsh Completions ```zsh #compdef cortex _cortex() { local -a commands commands=( 'add:Add a node to the knowledge graph' 'query:Search the knowledge graph' 'show:Show a node and its connections' 'list:List nodes' 'update:Update a node' 'remove:Remove a node' 'link:Create a link between nodes' 'graph:Visualize the knowledge graph' 'children:List child nodes' 'journal:Daily journal' 'index:Index project' 'serve:Start web server' 'decay:Mark old nodes as stale' 'use:Switch active graph' 'graphs:Manage graphs' ) local -a kinds=(memory component task decision) local -a statuses=(active todo doing done deprecated) _arguments -C \ '1:command:->command' \ '*::arg:->args' case "$state" in command) _describe -t commands 'cortex commands' commands ;; args) case "$words[1]" in add) _arguments \ '1:kind:(memory component task decision)' \ '--title[Node title]:title:' \ '--content[Node content]:content:' \ '--tags[Tags]:tags:->tags' \ '--status[Status]:status:(active todo doing done deprecated)' ;; show|update|remove|children) _arguments '1:node:->nodes' ;; link) _arguments \ '1:from:->nodes' \ '2:to:->nodes' \ '--type[Edge type]:type:(depends_on contains implements blocked_by subtask_of relates_to supersedes about)' ;; list) _arguments \ '--kind[Filter by kind]:kind:(memory component task decision)' \ '--status[Filter by status]:status:(active todo doing done deprecated)' \ '--tags[Filter by tags]:tags:->tags' ;; use) _arguments '1:graph:->graphs' ;; esac ;; esac case "$state" in nodes) local -a nodes nodes=(${(f)"$(cortex --get-nodes 2>/dev/null)"}) _describe -t nodes 'nodes' nodes ;; tags) local -a tags tags=(${(f)"$(cortex --get-tags 2>/dev/null)"}) _describe -t tags 'tags' tags ;; graphs) local -a graphs graphs=(${(f)"$(cortex --get-graphs 2>/dev/null)"}) _describe -t graphs 'graphs' graphs ;; esac } _cortex ``` ### Fish Completions ```fish # cortex.fish complete -c cortex -f # Commands complete -c cortex -n __fish_use_subcommand -a add -d 'Add a node' complete -c cortex -n __fish_use_subcommand -a query -d 'Search' complete -c cortex -n __fish_use_subcommand -a show -d 'Show node' complete -c cortex -n __fish_use_subcommand -a list -d 'List nodes' complete -c cortex -n __fish_use_subcommand -a update -d 'Update node' complete -c cortex -n __fish_use_subcommand -a remove -d 'Remove node' complete -c cortex -n __fish_use_subcommand -a link -d 'Link nodes' complete -c cortex -n __fish_use_subcommand -a graph -d 'Visualize graph' # Kinds complete -c cortex -n '__fish_seen_subcommand_from add' -a 'memory component task decision' # Dynamic node completion complete -c cortex -n '__fish_seen_subcommand_from show update remove' -a '(cortex --get-nodes)' # Tags complete -c cortex -n '__fish_seen_subcommand_from list' -l tags -a '(cortex --get-tags)' ``` ### PowerShell Completions ```powershell # cortex.ps1 Register-ArgumentCompleter -Native -CommandName cortex -ScriptBlock { param($wordToComplete, $commandAst, $cursorPosition) $commands = @('add', 'query', 'show', 'list', 'update', 'remove', 'link', 'graph', 'children', 'journal', 'index', 'serve', 'decay', 'use', 'graphs') $kinds = @('memory', 'component', 'task', 'decision') $statuses = @('active', 'todo', 'doing', 'done', 'deprecated') $elements = $commandAst.CommandElements $command = $elements[1].Value if ($elements.Count -eq 2) { $commands | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } } elseif ($command -eq 'add' -and $elements.Count -eq 3) { $kinds | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } } elseif ($command -in @('show', 'update', 'remove')) { $nodes = cortex --get-nodes $wordToComplete 2>$null $nodes -split "`n" | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) } } } ``` ### CLI Support Commands ```typescript // Hidden commands for completion scripts program .command('--get-nodes [prefix]', { hidden: true }) .action(async (prefix) => { const nodes = await listNodes({ limit: 20 }); const filtered = prefix ? nodes.filter(n => n.id.startsWith(prefix)) : nodes; console.log(filtered.map(n => `${n.id.slice(0, 8)}\t${n.title}`).join('\n')); }); program .command('--get-tags', { hidden: true }) .action(async () => { const tags = await getAllTags(); console.log(tags.join('\n')); }); program .command('--get-graphs', { hidden: true }) .action(async () => { const graphs = listGraphs(); console.log(graphs.map(g => g.name).join('\n')); }); ``` ## CLI Commands | Command | Description | |---------|-------------| | `cortex completions bash` | Output bash completions | | `cortex completions zsh` | Output zsh completions | | `cortex completions fish` | Output fish completions | | `cortex completions powershell` | Output PowerShell completions | | `cortex completions install` | Auto-install for current shell | ## Installation Instructions ### Bash ```bash cortex completions bash > /etc/bash_completion.d/cortex # or cortex completions bash >> ~/.bashrc ``` ### Zsh ```bash cortex completions zsh > ~/.zsh/completions/_cortex # Add to ~/.zshrc: fpath=(~/.zsh/completions $fpath) ``` ### Fish ```bash cortex completions fish > ~/.config/fish/completions/cortex.fish ``` ### PowerShell ```powershell cortex completions powershell >> $PROFILE ``` ## Testing - [ ] Bash completions work - [ ] Zsh completions work - [ ] Fish completions work - [ ] PowerShell completions work - [ ] Dynamic node ID completion - [ ] Dynamic tag completion - [ ] Install command works ## Acceptance Criteria - [ ] All four shells supported - [ ] Commands and options complete - [ ] Node IDs complete dynamically - [ ] Tags complete dynamically - [ ] Easy installation command - [ ] No errors on missing cortex binary ## Estimated Effort - Bash completions: 2 hours - Zsh completions: 3 hours - Fish completions: 2 hours - PowerShell completions: 2 hours - CLI support commands: 2 hours - Install command: 1 hour - Testing: 2 hours - **Total: ~14 hours** ## Dependencies - None ## References - [Bash Programmable Completion](https://www.gnu.org/software/bash/manual/html_node/Programmable-Completion.html) - [Zsh Completion System](https://zsh.sourceforge.io/Doc/Release/Completion-System.html) - [Fish Completions](https://fishshell.com/docs/current/completions.html) - [PowerShell Tab Completion](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/register-argumentcompleter)