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%
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