Skip to content

Commit e8fe9e6

Browse files
Copilotclaude
andcommitted
feat: report repo-bootcamp version in bootcamp doctor
`bootcamp doctor` diagnoses Node, git, gh, auth, mermaid, and cache, but never surfaced which version of the tool itself was running — the first thing you want in a bug report. It now reports the running package version as the leading info check ("repo-bootcamp: v1.2.3") and exposes it as `environment.toolVersion` in `--json` output. Also fixes a stray duplicate `### Added` header in the CHANGELOG Unreleased section. Tests: extended doctor unit tests (version info check + JSON toolVersion field) and added a new doctor E2E spec (none existed) asserting the human report shows the version and the JSON payload carries environment.toolVersion and a `version` check. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 6d69092 commit e8fe9e6

5 files changed

Lines changed: 50 additions & 3 deletions

File tree

CHANGELOG.md

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

1010
### Added
1111

12-
### Added
13-
12+
- `bootcamp doctor` now reports the running `repo-bootcamp` version as the first diagnostic line (and `environment.toolVersion` in `--json` output), so it's easy to include in bug reports.
1413
- Interactive Q&A mode (`bootcamp ask` and `--interactive`) now supports **slash commands**: `/help` (alias `/?`) shows the command reference, `/files` lists the detected repository files, `/clear` clears the screen, and `/exit` (aliases `/quit`, `exit`, `quit`) ends the session. Unknown slash commands are reported instead of being sent to the assistant. The input classifier and renderers are pure and unit-tested.
1514
- `bootcamp metrics <repo-url>` command: a standalone, deterministic codebase-metrics report for any repository (local path or remote URL) without invoking the LLM. Surfaces language breakdown, source/test/doc/config composition, average/median file size, test-to-source ratio, size classification, top-level directory distribution, largest-file hotspots, and an **approachability score (0-100 + A–F grade)** with human-readable drivers. Prints a human-readable report by default, supports `--json` for scripting, and offers a CI gate via `--check`/`--min-score` (exits non-zero when approachability is below the threshold). Reuses the same `computeCodebaseMetrics` engine that powers `METRICS.md` — mirroring the existing `bootcamp health` command.
1615
- Web demo file viewer now has **Copy** and **Download** buttons: copy a generated doc's contents to the clipboard (async Clipboard API with a `document.execCommand` fallback and a timeout guard) or download it as a file, directly from the preview modal.

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ Onboarding Risk: 18/100 (A) 🟢
146146
| Generated files | 14+ |
147147
| Test suite | 1,000+ tests |
148148
| Source files | 51 TypeScript modules |
149-
| Test files | 76 Vitest files |
149+
| Test files | 77 Vitest files |
150150
| Lines of code | 13,381 TypeScript LOC (src/) |
151151
| Languages supported | 10+ |
152152
| Generation time | < 60 seconds |

src/doctor.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { readdir } from "fs/promises";
1515
import { isMermaidCliAvailable } from "./diagrams.js";
1616
import { getCacheDir, listCacheEntries } from "./cache.js";
1717
import { formatBytes } from "./metrics.js";
18+
import pkg from "../package.json" with { type: "json" };
1819

1920
const execFileAsync = promisify(execFile);
2021

@@ -52,6 +53,8 @@ export interface DoctorReport {
5253

5354
/** A pure snapshot of the host environment, consumed by `evaluateDoctor`. */
5455
export interface EnvironmentSnapshot {
56+
/** The running repo-bootcamp package version (from package.json). */
57+
toolVersion: string;
5558
nodeVersion: string;
5659
platform: string;
5760
arch: string;
@@ -79,6 +82,15 @@ export function parseNodeMajor(version: string): number {
7982
export function evaluateDoctor(env: EnvironmentSnapshot): DoctorReport {
8083
const checks: DoctorCheck[] = [];
8184

85+
// repo-bootcamp version (info) — surfaced so users can include it in bug reports.
86+
checks.push({
87+
id: "version",
88+
label: "repo-bootcamp",
89+
severity: "optional",
90+
status: "info",
91+
detail: `v${env.toolVersion}`,
92+
});
93+
8294
// Node.js (required)
8395
const major = parseNodeMajor(env.nodeVersion);
8496
const nodeOk = Number.isFinite(major) && major >= MIN_NODE_MAJOR;
@@ -285,6 +297,7 @@ export async function gatherEnvironment(): Promise<EnvironmentSnapshot> {
285297
}
286298

287299
return {
300+
toolVersion: pkg.version,
288301
nodeVersion: process.version,
289302
platform: process.platform,
290303
arch: process.arch,

test/doctor.test.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414

1515
function env(overrides: Partial<EnvironmentSnapshot> = {}): EnvironmentSnapshot {
1616
return {
17+
toolVersion: "1.0.0",
1718
nodeVersion: "v20.11.0",
1819
platform: "linux",
1920
arch: "x64",
@@ -51,6 +52,16 @@ describe("evaluateDoctor", () => {
5152
expect(node?.status).toBe("ok");
5253
});
5354

55+
it("reports the running tool version as an info check", () => {
56+
const report = evaluateDoctor(env({ toolVersion: "2.3.4" }));
57+
const version = report.checks.find((c) => c.id === "version");
58+
expect(version).toBeDefined();
59+
expect(version?.status).toBe("info");
60+
expect(version?.detail).toBe("v2.3.4");
61+
// info checks never fail the overall report
62+
expect(report.ok).toBe(true);
63+
});
64+
5465
it("fails (required) on an old Node version", () => {
5566
const report = evaluateDoctor(env({ nodeVersion: "v18.19.0" }));
5667
expect(report.ok).toBe(false);
@@ -165,6 +176,7 @@ describe("runDoctor", () => {
165176
expect(payload.ok).toBe(true);
166177
expect(Array.isArray(payload.checks)).toBe(true);
167178
expect(payload.environment.nodeVersion).toBe("v20.11.0");
179+
expect(payload.environment.toolVersion).toBe("1.0.0");
168180
});
169181
});
170182

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { describe, expect, it } from "vitest";
2+
3+
import { runCli } from "./helpers.js";
4+
5+
describe("doctor command", () => {
6+
it("prints a human-readable environment report including the tool version", async () => {
7+
const result = await runCli(["doctor"], { NO_COLOR: "1" }, 60_000);
8+
// `doctor` exits 0 when required checks pass; in CI Node/git are present.
9+
expect(result.stdout).toContain("repo-bootcamp environment check");
10+
expect(result.stdout).toMatch(/repo-bootcamp:\s*v\d+\.\d+\.\d+/);
11+
expect(result.stdout).toContain("Node.js runtime");
12+
}, 60_000);
13+
14+
it("emits valid JSON with --json including environment.toolVersion", async () => {
15+
const result = await runCli(["doctor", "--json"], { NO_COLOR: "1" }, 60_000);
16+
const parsed = JSON.parse(result.stdout);
17+
expect(typeof parsed.ok).toBe("boolean");
18+
expect(Array.isArray(parsed.checks)).toBe(true);
19+
expect(parsed.checks.some((c: { id: string }) => c.id === "version")).toBe(true);
20+
expect(typeof parsed.environment.toolVersion).toBe("string");
21+
expect(parsed.environment.toolVersion).toMatch(/^\d+\.\d+\.\d+/);
22+
}, 60_000);
23+
});

0 commit comments

Comments
 (0)