From 86f7261421605905a69c3f726915e00fc72b44f2 Mon Sep 17 00:00:00 2001 From: Ermin Muratovic Date: Mon, 6 Apr 2026 17:15:11 +0200 Subject: [PATCH] feat: Add --version flag to cforge-dev CLI Intercepts --version and -v flags before command dispatch and prints the version from package.json. Includes unit tests for getVersion() and integration tests that spawn the CLI via ts-node. Co-Authored-By: Claude Sonnet 4.6 --- src/cli/index.ts | 6 +++++ src/cli/utils/getVersion.ts | 8 +++++++ tests/cli/getVersion.test.ts | 46 ++++++++++++++++++++++++++++++++++++ 3 files changed, 60 insertions(+) create mode 100644 src/cli/utils/getVersion.ts create mode 100644 tests/cli/getVersion.test.ts diff --git a/src/cli/index.ts b/src/cli/index.ts index f58968a..999aa30 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -7,6 +7,7 @@ import { verifyCommand } from "./commands/verify"; import { releaseCommand } from "./commands/release"; import { chatCommand } from "./commands/chat"; import { auditCommand } from "./commands/audit"; +import { getVersion } from "./utils/getVersion"; const USAGE = `cforge-dev — AI-native SDLC orchestrator @@ -28,6 +29,11 @@ async function main(): Promise { process.exit(0); } + if (command === "--version" || command === "-v") { + console.log(getVersion()); + process.exit(0); + } + switch (command) { case "plan": await planCommand(args[0]); diff --git a/src/cli/utils/getVersion.ts b/src/cli/utils/getVersion.ts new file mode 100644 index 0000000..ae7be88 --- /dev/null +++ b/src/cli/utils/getVersion.ts @@ -0,0 +1,8 @@ +import fs from "fs"; +import path from "path"; + +export function getVersion(): string { + const pkgPath = path.resolve(__dirname, "../../../package.json"); + const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf-8")) as { version: string }; + return pkg.version; +} diff --git a/tests/cli/getVersion.test.ts b/tests/cli/getVersion.test.ts new file mode 100644 index 0000000..b0fd40e --- /dev/null +++ b/tests/cli/getVersion.test.ts @@ -0,0 +1,46 @@ +import { getVersion } from "../../src/cli/utils/getVersion"; +import { spawnSync } from "child_process"; +import path from "path"; + +const ROOT = path.resolve(__dirname, "../.."); +const TSNODE = path.join(ROOT, "node_modules/.bin/ts-node"); +const CLI = path.join(ROOT, "src/cli/index.ts"); + +describe("getVersion", () => { + it("returns a non-empty string", () => { + const version = getVersion(); + expect(typeof version).toBe("string"); + expect(version.length).toBeGreaterThan(0); + }); + + it("returns a valid semver version string", () => { + const version = getVersion(); + expect(version).toMatch(/^\d+\.\d+\.\d+/); + }); + + it("matches the version field in package.json", () => { + // eslint-disable-next-line @typescript-eslint/no-var-requires + const pkg = require("../../package.json") as { version: string }; + expect(getVersion()).toBe(pkg.version); + }); +}); + +describe("CLI version flags", () => { + it("outputs version when --version flag is provided", () => { + const result = spawnSync(TSNODE, [CLI, "--version"], { + cwd: ROOT, + encoding: "utf-8", + }); + expect(result.status).toBe(0); + expect(result.stdout.trim()).toMatch(/^\d+\.\d+\.\d+/); + }); + + it("outputs version when -v flag is provided", () => { + const result = spawnSync(TSNODE, [CLI, "-v"], { + cwd: ROOT, + encoding: "utf-8", + }); + expect(result.status).toBe(0); + expect(result.stdout.trim()).toMatch(/^\d+\.\d+\.\d+/); + }); +});