From fd526a7cec6a8d2069228e0c22076c11cb3fca29 Mon Sep 17 00:00:00 2001 From: mikemikimike <13286568797@163.com> Date: Sun, 6 Sep 2026 17:59:22 +0800 Subject: [PATCH] fix: reject unknown ignore targets (#9) --- CHANGELOG.md | 7 +++++++ package.json | 2 +- src/cli.js | 7 ++++++- test/ctxtrim.test.js | 20 ++++++++++++++++++++ 4 files changed, 34 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 659ae1c..59a2224 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to this project are documented here, following [Keep a Changelog](https://keepachangelog.com/) and semantic versioning. +## [0.1.3] - 2026-09-06 + +### Fixed + +- Reject unknown `--targets` values with a clear error instead of silently + skipping all ignore-file writes. + ## [0.1.2] - 2026-08-09 ### Fixed diff --git a/package.json b/package.json index eba3b63..ec62996 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "ctxtrim", - "version": "0.1.2", + "version": "0.1.3", "description": "Trim what bloats your AI coding context. Scan a repo, find the high-cost/low-value files ballooning your Claude Code / Cursor / Codex context, and write ignore files to cut token cost. Zero dependencies.", "type": "module", "bin": { diff --git a/src/cli.js b/src/cli.js index db5f35f..200b096 100644 --- a/src/cli.js +++ b/src/cli.js @@ -58,7 +58,12 @@ export function run(argv, { version }) { const target = o.path || "."; if (!existsSync(target)) { process.stderr.write(`ctxtrim: path not found: ${target}\n`); return 2; } if (!["text", "json"].includes(o.format)) { process.stderr.write(`ctxtrim: unknown --format\n`); return 2; } - const targets = o.targets.split(",").map((s) => s.trim()).filter((s) => TARGETS[s]); + const targets = o.targets.split(",").map((s) => s.trim()).filter(Boolean); + const unknownTargets = targets.filter((s) => !TARGETS[s]); + if (unknownTargets.length) { + process.stderr.write(`ctxtrim: unknown --targets: ${unknownTargets.join(", ")}. Valid targets: ${Object.keys(TARGETS).join(", ")}\n`); + return 2; + } const scan = scanRepo(target, { maxTokens: o.maxTokens }); let wrote = null; diff --git a/test/ctxtrim.test.js b/test/ctxtrim.test.js index 72793df..6afc630 100644 --- a/test/ctxtrim.test.js +++ b/test/ctxtrim.test.js @@ -1,4 +1,6 @@ import fs, { mkdtempSync, rmSync, truncateSync, writeFileSync } from "node:fs"; +import { existsSync } from "node:fs"; +import { spawnSync } from "node:child_process"; import { syncBuiltinESMExports } from "node:module"; import { tmpdir } from "node:os"; import { test } from "node:test"; @@ -10,6 +12,7 @@ import { classify, classifyPath } from "../src/classify.js"; import { merge, block } from "../src/ignore.js"; const repo = join(dirname(fileURLToPath(import.meta.url)), "fixtures", "sample-repo"); +const cli = join(dirname(fileURLToPath(import.meta.url)), "..", "bin", "ctxtrim.js"); test("token estimate is ~chars/4", () => { assert.equal(estimateTokens("aaaaaaaa"), 2); // 8 chars @@ -133,3 +136,20 @@ test("clean repo (only source) reports nothing to trim", () => { const s = scanRepo(join(repo, "src")); assert.equal(s.totals.trimTokens, 0); }); + +test("unknown --targets values fail before writing ignore files", (t) => { + const root = mkdtempSync(join(tmpdir(), "ctxtrim-invalid-target-")); + t.after(() => rmSync(root, { recursive: true, force: true })); + writeFileSync(join(root, "package-lock.json"), "{}\n"); + + const result = spawnSync(process.execPath, [cli, root, "--write", "--targets", "bogus,cursor"], { + encoding: "utf8", + }); + + assert.equal(result.status, 2); + assert.match(result.stderr, /unknown --targets: bogus/); + assert.match(result.stderr, /Valid targets: cursor, gemini, generic/); + assert.equal(existsSync(join(root, ".cursorignore")), false); + assert.equal(existsSync(join(root, ".aiexclude")), false); + assert.equal(existsSync(join(root, ".aiignore")), false); +});