From 11cdcc3eb7546972fc99144c431d14525430d9ea Mon Sep 17 00:00:00 2001 From: glorydavid03023 Date: Fri, 26 Jun 2026 04:40:15 -0500 Subject: [PATCH] feat(mcp): add PowerShell shell completion Extend `gittensory-mcp completion` to support PowerShell alongside bash, zsh, and fish. `completion powershell` prints a `Register-ArgumentCompleter` script that completes top-level commands and the subcommands of `profile`, `cache`, `agent`, and `maintain`, driven by the same `CLI_COMMAND_SPEC` single source of truth. `--json` returns `{ shell, script }` as for the other shells. PowerShell is a primary shell on Windows and was previously rejected as an unsupported shell; this closes that gap. Tests cover the generated PowerShell script (Register-ArgumentCompleter, CompletionResult, command/subcommand lists) and update the unsupported-shell case to a still-unsupported shell. Co-Authored-By: Claude Opus 4.8 (1M context) --- packages/gittensory-mcp/README.md | 8 ++++- packages/gittensory-mcp/bin/gittensory-mcp.js | 36 +++++++++++++++++-- test/unit/mcp-cli-basics.test.ts | 12 +++++-- 3 files changed, 50 insertions(+), 6 deletions(-) diff --git a/packages/gittensory-mcp/README.md b/packages/gittensory-mcp/README.md index 945f47ffe2..e5633e6a66 100644 --- a/packages/gittensory-mcp/README.md +++ b/packages/gittensory-mcp/README.md @@ -49,6 +49,7 @@ gittensory-mcp init-client --print codex --agent-profile miner-planner gittensory-mcp completion bash gittensory-mcp completion zsh gittensory-mcp completion fish +gittensory-mcp completion powershell gittensory-mcp decision-pack --login jsonbored --json gittensory-mcp repo-decision --login jsonbored --repo we-promise/sure --json gittensory-mcp analyze-branch --login jsonbored --json @@ -79,7 +80,7 @@ Add `--json` for machine-readable output: ### Shell completion -`gittensory-mcp completion ` prints a tab-completion script for your shell. It completes top-level commands and the subcommands of `profile`, `cache`, and `agent`. Add `--json` to get `{ "shell": "...", "script": "..." }` for tooling. +`gittensory-mcp completion ` prints a tab-completion script for your shell. It completes top-level commands and the subcommands of `profile`, `cache`, `agent`, and `maintain`. Add `--json` to get `{ "shell": "...", "script": "..." }` for tooling. ```sh # bash (add to ~/.bashrc) @@ -92,6 +93,11 @@ source <(gittensory-mcp completion zsh) gittensory-mcp completion fish > ~/.config/fish/completions/gittensory-mcp.fish ``` +```powershell +# PowerShell (add to your $PROFILE) +gittensory-mcp completion powershell | Out-String | Invoke-Expression +``` + For near-term what-if scoreability, pass the situational assumptions explicitly: ```sh diff --git a/packages/gittensory-mcp/bin/gittensory-mcp.js b/packages/gittensory-mcp/bin/gittensory-mcp.js index 31ba73fa59..faf5a455da 100755 --- a/packages/gittensory-mcp/bin/gittensory-mcp.js +++ b/packages/gittensory-mcp/bin/gittensory-mcp.js @@ -44,7 +44,7 @@ const CLI_COMMAND_SPEC = { agent: ["plan", "status", "explain", "packet"], maintain: ["status", "approve", "reject", "pause", "resume", "set-level"], }; -const COMPLETION_SHELLS = ["bash", "zsh", "fish"]; +const COMPLETION_SHELLS = ["bash", "zsh", "fish", "powershell"]; const AGENT_PROFILE_IDS = ["miner-planner", "miner-auto-dev", "maintainer-triage", "repo-owner-intake"]; // #784 maintain set-level — the autonomy dial's action classes + levels (must mirror src/settings/autonomy.ts). const MAINTAIN_ACTION_CLASSES = ["review", "request_changes", "approve", "merge", "close", "label"]; @@ -1674,7 +1674,8 @@ function buildCompletionScript(shell) { const withSubcommands = Object.entries(CLI_COMMAND_SPEC).filter(([, subcommands]) => subcommands.length > 0); if (shell === "bash") return buildBashCompletion(topLevel, withSubcommands); if (shell === "zsh") return buildZshCompletion(topLevel, withSubcommands); - return buildFishCompletion(topLevel, withSubcommands); + if (shell === "fish") return buildFishCompletion(topLevel, withSubcommands); + return buildPowershellCompletion(topLevel, withSubcommands); } function buildBashCompletion(topLevel, withSubcommands) { @@ -1735,11 +1736,40 @@ ${topLevelLines} ${subcommandLines}`; } +function buildPowershellCompletion(topLevel, withSubcommands) { + const commandList = topLevel.map((command) => `'${command}'`).join(", "); + const subcommandEntries = withSubcommands + .map(([command, subcommands]) => ` '${command}' = @(${subcommands.map((subcommand) => `'${subcommand}'`).join(", ")})`) + .join("\n"); + return `# gittensory-mcp PowerShell completion. Add to your $PROFILE: +# gittensory-mcp completion powershell | Out-String | Invoke-Expression +Register-ArgumentCompleter -Native -CommandName gittensory-mcp -ScriptBlock { + param($wordToComplete, $commandAst, $cursorPosition) + $commands = @(${commandList}) + $subcommands = @{ +${subcommandEntries} + } + $elements = $commandAst.CommandElements + if ($elements.Count -le 2) { + $commands | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { + [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) + } + return + } + $sub = $subcommands[[string]$elements[1].Value] + if ($sub) { + $sub | Where-Object { $_ -like "$wordToComplete*" } | ForEach-Object { + [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_) + } + } +}`; +} + function printHelp() { process.stdout.write(`Usage: gittensory-mcp --stdio gittensory-mcp version [--json] - gittensory-mcp completion bash|zsh|fish [--json] + gittensory-mcp completion bash|zsh|fish|powershell [--json] gittensory-mcp login [--profile name] [--github-token ] [--json] gittensory-mcp logout [--profile name] [--all] [--json] gittensory-mcp whoami [--profile name] [--json] diff --git a/test/unit/mcp-cli-basics.test.ts b/test/unit/mcp-cli-basics.test.ts index fbc9f3411d..eb7239cb4a 100644 --- a/test/unit/mcp-cli-basics.test.ts +++ b/test/unit/mcp-cli-basics.test.ts @@ -176,6 +176,14 @@ describe("gittensory-mcp CLI — basics", () => { expect(fish).toContain("__fish_seen_subcommand_from agent"); }); + it("prints a PowerShell argument-completer script", () => { + const ps = run(["completion", "powershell"]); + expect(ps).toContain("Register-ArgumentCompleter -Native -CommandName gittensory-mcp"); + expect(ps).toContain("[System.Management.Automation.CompletionResult]::new"); + expect(ps).toContain("$commands = @('login', 'logout'"); + expect(ps).toContain("'maintain' = @('status', 'approve', 'reject', 'pause', 'resume', 'set-level')"); + }); + it("emits completion as machine-readable json", () => { const payload = JSON.parse(run(["completion", "zsh", "--json"])) as { shell: string; script: string }; expect(payload.shell).toBe("zsh"); @@ -183,8 +191,8 @@ describe("gittensory-mcp CLI — basics", () => { }); it("rejects missing or unsupported completion shells", () => { - expect(() => run(["completion"])).toThrow(/Usage: gittensory-mcp completion /); - expect(() => run(["completion", "powershell"])).toThrow(/Unsupported shell: powershell/); + expect(() => run(["completion"])).toThrow(/Usage: gittensory-mcp completion /); + expect(() => run(["completion", "tcsh"])).toThrow(/Unsupported shell: tcsh/); }); it("reports resolved configuration provenance via config", () => {