Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ program
String(cfg.threshold),
)
.option("--scoring <method>", "Scoring method: copeland (default) or weighted", "copeland")
.option("--no-color", "Disable colored output")
.option("--output-format <format>", "Output format: text (default) or json", "text")
.option("--verbose", "Show detailed output from each agent")
.action(async (promptArg: string | undefined, opts) => {
const prompt = resolvePrompt(promptArg, opts.file);
Expand Down Expand Up @@ -79,6 +81,17 @@ program
process.exit(1);
}

// --no-color: commander parses --no-color as opts.color === false
if (opts.color === false) {
process.env.NO_COLOR = "1";
}

const validFormats = ["text", "json"];
if (!validFormats.includes(opts.outputFormat)) {
console.error(`Error: --output-format must be one of: ${validFormats.join(", ")}`);
process.exit(1);
}

const knownModels = ["sonnet", "opus", "haiku"];
if (!knownModels.includes(opts.model) && !opts.model.startsWith("claude-")) {
console.warn(
Expand All @@ -97,6 +110,7 @@ program
runner: opts.runner,
scoring: opts.scoring,
verbose: opts.verbose ?? false,
outputFormat: opts.outputFormat,
});
});

Expand Down
41 changes: 40 additions & 1 deletion src/commands/run.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import assert from "node:assert/strict";
import { describe, it } from "node:test";
import { afterEach, describe, it } from "node:test";
import type { RunOptions } from "../types.js";
import { makeResultFilename, preflightValidation } from "./run.js";

Expand All @@ -13,6 +13,7 @@ function makeOpts(overrides: Partial<RunOptions> = {}): RunOptions {
threshold: 0.3,
verbose: false,
scoring: "weighted",
outputFormat: "text",
...overrides,
};
}
Expand Down Expand Up @@ -78,3 +79,41 @@ describe("makeResultFilename", () => {
assert.equal(filename, "run-2026-03-28T18-09-50-100Z.json");
});
});

describe("outputFormat option", () => {
it("accepts text as default output format", () => {
const opts = makeOpts({ outputFormat: "text" });
assert.equal(opts.outputFormat, "text");
});

it("accepts json output format", () => {
const opts = makeOpts({ outputFormat: "json" });
assert.equal(opts.outputFormat, "json");
});
});

describe("NO_COLOR environment variable", () => {
const originalNoColor = process.env.NO_COLOR;

afterEach(() => {
if (originalNoColor === undefined) {
delete process.env.NO_COLOR;
} else {
process.env.NO_COLOR = originalNoColor;
}
});

it("can be set to disable colors", () => {
process.env.NO_COLOR = "1";
assert.equal(process.env.NO_COLOR, "1");
});

it("picocolors respects NO_COLOR", async () => {
process.env.NO_COLOR = "1";
// picocolors checks NO_COLOR at import time, but its createColors
// function can be used to verify the behavior
const pc = await import("picocolors");
const colors = pc.createColors(false);
assert.equal(colors.bold("test"), "test");
});
});
8 changes: 6 additions & 2 deletions src/commands/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,12 @@ export async function run(opts: RunOptions): Promise<void> {
};

// Display results
displayResults(result);
displayApplyInstructions(result);
if (opts.outputFormat === "json") {
console.log(JSON.stringify(result));
} else {
displayResults(result);
displayApplyInstructions(result);
}

// Save result to .thinktank/
await saveResult(result);
Expand Down
1 change: 1 addition & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export interface RunOptions {
verbose: boolean;
runner?: string;
scoring: "weighted" | "copeland";
outputFormat: "text" | "json";
}

export interface AgentResult {
Expand Down
Loading