SPB Git

spb/khaelor Public

KHAELOR — a terminal-native autonomous engineering agent powered by Anthropic.

TypeScript 82.9% HTML 14.9% CSS 1.1% JavaScript 0.7%
3.4 KB · 104 lines typescript
Raw Blame History
1/**2 * KHAELOR3 * File: tests/cli/args.test.ts4 * Description: CLI argv parsing — flags, values, errors, and the missing-API-key message quality.5 *6 * Author: Simon-Pierre Boucher7 * Contact: contact@spboucher.ai8 */910import { describe, expect, it } from "vitest";11import {12  KHAELOR_VERSION,13  helpText,14  missingApiKeyMessage,15  parseArgs,16} from "../../src/cli/args.js";1718describe("parseArgs", () => {19  it("defaults: interactive mode, no flags", () => {20    const parsed = parseArgs([]);21    expect(parsed.help).toBe(false);22    expect(parsed.version).toBe(false);23    expect(parsed.debug).toBe(false);24    expect(parsed.print).toBeNull();25    expect(parsed.resume).toBeNull();26    expect(parsed.model).toBeNull();27    expect(parsed.errors).toEqual([]);28  });2930  it("parses --model, --debug, --version, --help", () => {31    const parsed = parseArgs(["--model", "claude-sonnet-5", "--debug", "--version", "--help"]);32    expect(parsed.model).toBe("claude-sonnet-5");33    expect(parsed.debug).toBe(true);34    expect(parsed.version).toBe(true);35    expect(parsed.help).toBe(true);36    expect(parsed.errors).toEqual([]);37  });3839  it("parses short aliases -h, -v, -p", () => {40    expect(parseArgs(["-h"]).help).toBe(true);41    expect(parseArgs(["-v"]).version).toBe(true);42    expect(parseArgs(["-p", "hello"]).print).toBe("hello");43  });4445  it("parses --print with the prompt value", () => {46    const parsed = parseArgs(["--print", "read the file and report"]);47    expect(parsed.print).toBe("read the file and report");48    expect(parsed.errors).toEqual([]);49  });5051  it("parses --resume, --aux-model, --thinking, --max-output-tokens", () => {52    const parsed = parseArgs([53      "--resume", "01ABC",54      "--aux-model", "claude-haiku-4-5",55      "--thinking", "off",56      "--max-output-tokens", "2048",57    ]);58    expect(parsed.resume).toBe("01ABC");59    expect(parsed.auxModel).toBe("claude-haiku-4-5");60    expect(parsed.thinking).toBe("off");61    expect(parsed.maxOutputTokens).toBe(2048);62  });6364  it("rejects a flag missing its value", () => {65    expect(parseArgs(["--model"]).errors).toContain("--model requires a value");66    expect(parseArgs(["--print", "--debug"]).errors).toContain("--print requires a value");67  });6869  it("rejects non-integer --max-output-tokens", () => {70    expect(parseArgs(["--max-output-tokens", "lots"]).errors.length).toBe(1);71    expect(parseArgs(["--max-output-tokens", "-5"]).errors.length).toBe(1);72  });7374  it("rejects unknown options by name", () => {75    const parsed = parseArgs(["--frobnicate"]);76    expect(parsed.errors).toEqual(["unknown option: --frobnicate"]);77  });7879  it("help text documents every user-facing flag", () => {80    const help = helpText();81    for (const flag of ["--model", "--print", "--resume", "--debug", "--version", "--help"]) {82      expect(help).toContain(flag);83    }84    expect(help).toContain("ANTHROPIC_API_KEY");85  });8687  it("version constant matches package shape", () => {88    expect(KHAELOR_VERSION).toMatch(/^\d+\.\d+\.\d+$/);89  });90});9192describe("missing API key message", () => {93  it("is actionable: names the env var and where keys come from", () => {94    const message = missingApiKeyMessage();95    expect(message).toContain("ANTHROPIC_API_KEY");96    expect(message).toContain("export ANTHROPIC_API_KEY=");97    expect(message).toContain("console.anthropic.com");98  });99100  it("never contains secret-shaped material", () => {101    expect(missingApiKeyMessage()).not.toMatch(/sk-ant-/);102  });103});104