fix: resolve four bug reports (#2290, #2282, #2276, #2272)

- #2290 suggest-compact: honor ECC_CONTEXT_WINDOW_TOKENS / CLAUDE_CODE_AUTO_COMPACT_WINDOW
  so 400k-window models (Opus 4.x) no longer report ~double context usage; add
  override + isolation tests in transcript-context.test.js.
- #2282 install: bare-language syntax is legacy-only by design, but the error
  now distinguishes a supported-but-wrong-mode target (gemini/codex/…) from a
  genuinely unknown one and points to --profile/--modules/--skills.
- #2276 cost-report: the command + cost-tracking skill targeted a SQLite DB no
  tracker writes. Repoint both at the real ~/.claude/metrics/costs.jsonl (JSONL,
  estimated_cost_usd), reduce cumulative-per-session snapshots to latest-per-session,
  and use node instead of sqlite3 for cross-platform support.
- #2272 gateguard: make the 'confirm no existing file' checklist item
  tool-agnostic (Glob/Grep or find/grep via Bash) so hosts without a Glob tool
  don't get a dead tool call.

Full suite 2839/2839; lint green.
This commit is contained in:
Affaan Mustafa
2026-06-18 16:49:58 -04:00
parent 51184b692e
commit b3268fef80
7 changed files with 325 additions and 424 deletions
+39 -29
View File
@@ -78,47 +78,32 @@ function tracked(filePath) {
console.log('readLatestContextTokens:');
test('sums input + cache_read + cache_creation from the latest usage record', () => {
const file = tracked(writeTranscript([
usageRecord({ input: 10, cacheRead: 20, cacheCreation: 5 }),
usageRecord({ input: 100, cacheRead: 150000, cacheCreation: 7000 })
]));
const file = tracked(writeTranscript([usageRecord({ input: 10, cacheRead: 20, cacheCreation: 5 }), usageRecord({ input: 100, cacheRead: 150000, cacheCreation: 7000 })]));
const result = readLatestContextTokens(file);
assert.ok(result, 'Expected a usage result');
assert.strictEqual(result.tokens, 157100);
});
test('returns the model id alongside the token count', () => {
const file = tracked(writeTranscript([
usageRecord({ input: 1000 }, 'claude-opus-4-5[1m]')
]));
const file = tracked(writeTranscript([usageRecord({ input: 1000 }, 'claude-opus-4-5[1m]')]));
const result = readLatestContextTokens(file);
assert.strictEqual(result.model, 'claude-opus-4-5[1m]');
});
test('skips trailing records without usage (e.g. tool results)', () => {
const file = tracked(writeTranscript([
usageRecord({ input: 5000 }),
JSON.stringify({ type: 'user', message: { content: 'tool result' } }),
JSON.stringify({ type: 'system', subtype: 'info' })
]));
const file = tracked(writeTranscript([usageRecord({ input: 5000 }), JSON.stringify({ type: 'user', message: { content: 'tool result' } }), JSON.stringify({ type: 'system', subtype: 'info' })]));
const result = readLatestContextTokens(file);
assert.strictEqual(result.tokens, 5000);
});
test('skips malformed JSONL lines without throwing', () => {
const file = tracked(writeTranscript([
usageRecord({ input: 4200 }),
'{not json at all',
''
]));
const file = tracked(writeTranscript([usageRecord({ input: 4200 }), '{not json at all', '']));
const result = readLatestContextTokens(file);
assert.strictEqual(result.tokens, 4200);
});
test('returns null for a transcript with no usage records', () => {
const file = tracked(writeTranscript([
JSON.stringify({ type: 'user', message: { content: 'hello' } })
]));
const file = tracked(writeTranscript([JSON.stringify({ type: 'user', message: { content: 'hello' } })]));
assert.strictEqual(readLatestContextTokens(file), null);
});
@@ -132,10 +117,7 @@ test('returns null for empty or non-string paths', () => {
});
test('ignores zero-token usage records', () => {
const file = tracked(writeTranscript([
usageRecord({ input: 999 }),
usageRecord({ input: 0 })
]));
const file = tracked(writeTranscript([usageRecord({ input: 999 }), usageRecord({ input: 0 })]));
const result = readLatestContextTokens(file);
assert.strictEqual(result.tokens, 999);
});
@@ -154,10 +136,42 @@ test('only scans the transcript tail (latest records win on large files)', () =>
// ── resolveContextWindowTokens ──
console.log('\nresolveContextWindowTokens:');
// Isolation: an env-set window override (either knob) otherwise leaks into the
// default-window assertions below and fails them (#2290).
delete process.env.ECC_CONTEXT_WINDOW_TOKENS;
delete process.env.CLAUDE_CODE_AUTO_COMPACT_WINDOW;
test('defaults to the standard 200k window', () => {
assert.strictEqual(resolveContextWindowTokens(50000, 'claude-sonnet-4-6'), STANDARD_CONTEXT_WINDOW_TOKENS);
});
test('honors an explicit ECC_CONTEXT_WINDOW_TOKENS override (e.g. 400k models, #2290)', () => {
process.env.ECC_CONTEXT_WINDOW_TOKENS = '400000';
try {
assert.strictEqual(resolveContextWindowTokens(50000, 'claude-opus-4-x'), 400000);
} finally {
delete process.env.ECC_CONTEXT_WINDOW_TOKENS;
}
});
test('honors Claude Code native CLAUDE_CODE_AUTO_COMPACT_WINDOW override', () => {
process.env.CLAUDE_CODE_AUTO_COMPACT_WINDOW = '400000';
try {
assert.strictEqual(resolveContextWindowTokens(50000, 'claude-opus-4-x'), 400000);
} finally {
delete process.env.CLAUDE_CODE_AUTO_COMPACT_WINDOW;
}
});
test('ignores a non-positive / invalid window override', () => {
process.env.ECC_CONTEXT_WINDOW_TOKENS = 'not-a-number';
try {
assert.strictEqual(resolveContextWindowTokens(50000, 'claude-sonnet-4-6'), STANDARD_CONTEXT_WINDOW_TOKENS);
} finally {
delete process.env.ECC_CONTEXT_WINDOW_TOKENS;
}
});
test('detects a 1M window from the [1m] model marker', () => {
assert.strictEqual(resolveContextWindowTokens(50000, 'claude-opus-4-5[1m]'), LARGE_CONTEXT_WINDOW_TOKENS);
});
@@ -191,11 +205,7 @@ test('COMPACT_CONTEXT_THRESHOLD=0 disables the signal', () => {
test('invalid COMPACT_CONTEXT_THRESHOLD falls back to the default', () => {
for (const bad of ['-5', 'abc', '99999999999']) {
assert.strictEqual(
resolveContextThreshold({ COMPACT_CONTEXT_THRESHOLD: bad }, STANDARD_CONTEXT_WINDOW_TOKENS),
DEFAULT_CONTEXT_THRESHOLD_STANDARD,
`Expected fallback for ${bad}`
);
assert.strictEqual(resolveContextThreshold({ COMPACT_CONTEXT_THRESHOLD: bad }, STANDARD_CONTEXT_WINDOW_TOKENS), DEFAULT_CONTEXT_THRESHOLD_STANDARD, `Expected fallback for ${bad}`);
}
});