Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion packages/gittensory-mcp/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -79,7 +80,7 @@ Add `--json` for machine-readable output:

### Shell completion

`gittensory-mcp completion <bash|zsh|fish>` 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 <bash|zsh|fish|powershell>` 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)
Expand All @@ -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
Expand Down
36 changes: 33 additions & 3 deletions packages/gittensory-mcp/bin/gittensory-mcp.js
Original file line number Diff line number Diff line change
Expand Up @@ -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"];
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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 <token>] [--json]
gittensory-mcp logout [--profile name] [--all] [--json]
gittensory-mcp whoami [--profile name] [--json]
Expand Down
12 changes: 10 additions & 2 deletions test/unit/mcp-cli-basics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,15 +176,23 @@ 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");
expect(payload.script).toContain("#compdef gittensory-mcp");
});

it("rejects missing or unsupported completion shells", () => {
expect(() => run(["completion"])).toThrow(/Usage: gittensory-mcp completion <bash\|zsh\|fish>/);
expect(() => run(["completion", "powershell"])).toThrow(/Unsupported shell: powershell/);
expect(() => run(["completion"])).toThrow(/Usage: gittensory-mcp completion <bash\|zsh\|fish\|powershell>/);
expect(() => run(["completion", "tcsh"])).toThrow(/Unsupported shell: tcsh/);
});

it("reports resolved configuration provenance via config", () => {
Expand Down