Skip to content

Commit d6b4c2b

Browse files
Arthur742RamosCopilotclaude
authored
feat: add bootcamp completion for bash/zsh/fish (#54)
Adds `bootcamp completion <shell>` which prints a tab-completion script for bash, zsh, or fish. The completion spec (subcommands, aliases, and option flags) is collected from the live Commander `program` at runtime, so the scripts always match the real CLI surface and never drift as commands are added or changed. - src/completion.ts: pure, fully-testable spec collection + per-shell renderers - src/commands/completion-command.ts: validation, exit codes, injectable IO - Generated bash script validated with `bash -n` and a functional COMPREPLY check Tests: 17 unit (spec + renderers), 4 wrapper unit (validation/DI), 4 E2E spawning the real CLI for each shell + the unsupported-shell error path. Co-authored-by: Arthur742Ramos <223556219+Copilot@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 9887363 commit d6b4c2b

8 files changed

Lines changed: 624 additions & 2 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
99

1010
### Added
1111

12+
- `bootcamp completion <bash|zsh|fish>` command to print a shell completion script for tab-completing subcommands, their aliases, and option flags. The completion data is derived from the live CLI definition, so it can never drift from the actual command surface; pipe it to your shell's completion directory (or `source <(bootcamp completion bash)`).
1213
- `bootcamp styles` command (alias `style`) to list the built-in style packs and the documentation sections each one enables, so users can choose a `--style` without reading the source. Prints a per-pack summary (tone, depth, emoji, first-task count, enabled sections) plus a section-coverage matrix, flags the default pack (`oss`), and supports `--json` for scripting.
1314
- `bootcamp init` command to scaffold a `.bootcamprc.json` configuration file in the current directory. Refuses to overwrite an existing config unless `--force`, supports `--print` to preview the config on stdout without writing, `--path` for a custom output location, and `--style` to preset a built-in style pack.
1415
- `bootcamp health <repo-url>` command: a standalone, deterministic onboarding-readiness score for any repository (local path or remote URL) without invoking the LLM. Prints a human-readable report by default, supports `--json` for scripting, and offers a CI gate via `--check`/`--min-score` (exits non-zero when the score falls below the threshold). Reuses the same `computeRepoHealth` engine that powers `HEALTH.md`.

README.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -145,8 +145,8 @@ Onboarding Risk: 18/100 (A) 🟢
145145
| GitHub stars | 29 |
146146
| Generated files | 14+ |
147147
| Test suite | 1,000+ tests |
148-
| Source files | 48 TypeScript modules |
149-
| Test files | 70 Vitest files |
148+
| Source files | 50 TypeScript modules |
149+
| Test files | 73 Vitest files |
150150
| Lines of code | 13,381 TypeScript LOC (src/) |
151151
| Languages supported | 10+ |
152152
| Generation time | < 60 seconds |
@@ -583,6 +583,7 @@ npm install -g @mermaid-js/mermaid-cli
583583
| `bootcamp init` | Scaffold a `.bootcamprc.json` config (`--force`, `--print`, `--style`) |
584584
| `bootcamp styles` | List the built-in style packs and the sections each enables (`--json`) |
585585
| `bootcamp doctor` | Diagnose your environment (`--json`) |
586+
| `bootcamp completion <shell>` | Print a shell completion script (bash, zsh, fish) |
586587
| `bootcamp cache list\|prune\|clear` | Manage the analysis cache |
587588

588589
## Programmatic API

src/cli.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import { pathToFileURL } from "url";
2424
import { clearCache, getCacheDir, pruneCache } from "./cache.js";
2525
import { runAskCommand } from "./commands/ask-command.js";
2626
import { runCacheList } from "./commands/cache-list.js";
27+
import { runCompletionCommand } from "./commands/completion-command.js";
2728
import { runPullRequestDiff } from "./commands/diff-command.js";
2829
import { runDocsCommand } from "./commands/docs-command.js";
2930
import { runDoctor } from "./commands/doctor-command.js";
@@ -403,6 +404,13 @@ program
403404
runStylesCommand({ json: opts.json });
404405
});
405406

407+
program
408+
.command("completion <shell>")
409+
.description("Print a shell completion script (bash, zsh, or fish)")
410+
.action((shell: string) => {
411+
runCompletionCommand(program, { shell });
412+
});
413+
406414
const cacheCommand = program
407415
.command("cache")
408416
.description("Manage the analysis cache");

src/commands/completion-command.ts

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/**
2+
* `bootcamp completion <shell>` command.
3+
*
4+
* Prints a shell completion script (bash/zsh/fish) to stdout, derived from the
5+
* live Commander program so it always matches the real command surface. This
6+
* module handles validation and process wiring; the script generation lives in
7+
* `src/completion.ts`. Dependencies are injectable for unit testing.
8+
*/
9+
10+
import chalk from "chalk";
11+
import type { Command } from "commander";
12+
13+
import {
14+
collectCompletionSpec,
15+
isSupportedShell,
16+
renderCompletion,
17+
SUPPORTED_SHELLS,
18+
} from "../completion.js";
19+
20+
export interface CompletionCommandOptions {
21+
shell?: string;
22+
}
23+
24+
export interface CompletionCommandDeps {
25+
log?: (message: string) => void;
26+
error?: (message: string) => void;
27+
exit?: (code: number) => void;
28+
}
29+
30+
/**
31+
* Run the `completion` command against a configured `program`.
32+
*
33+
* Prints the requested shell's completion script to stdout. On an unknown or
34+
* missing shell, writes an error to stderr and exits non-zero.
35+
*/
36+
export function runCompletionCommand(
37+
program: Command,
38+
options: CompletionCommandOptions,
39+
deps: CompletionCommandDeps = {}
40+
): void {
41+
const log = deps.log ?? ((msg: string) => console.log(msg));
42+
const error = deps.error ?? ((msg: string) => console.error(msg));
43+
const exit = deps.exit ?? ((code: number) => process.exit(code));
44+
45+
const shell = (options.shell ?? "").toLowerCase();
46+
47+
if (!shell) {
48+
error(chalk.red(`Missing shell. Choose one of: ${SUPPORTED_SHELLS.join(", ")}`));
49+
exit(1);
50+
return;
51+
}
52+
53+
if (!isSupportedShell(shell)) {
54+
error(
55+
chalk.red(`Unsupported shell: ${shell}.`) +
56+
chalk.dim(` Choose one of: ${SUPPORTED_SHELLS.join(", ")}`)
57+
);
58+
exit(1);
59+
return;
60+
}
61+
62+
const spec = collectCompletionSpec(program);
63+
log(renderCompletion(shell, spec));
64+
}

0 commit comments

Comments
 (0)