mirror of
https://github.com/garrytan/gbrain.git
synced 2026-07-27 22:15:33 +00:00
* feat(eval): cycle-default — single source of truth for TTY/non-TTY cycle count (#1784) * fix(jobs): decouple 'jobs watch' format (--json) from loop (--follow); non-TTY prints one human snapshot (#1784) * fix(reindex): human cost-refusal unless --json; spend guardrail unchanged (#1784) * fix(eval): annotate non-interactive cycle/budget defaults; runner core TTY-agnostic (#1784) * chore: bump version and changelog (v0.42.15.0) Decouple CLI primary output from process.stdout.isTTY (#1784): human by default, JSON only with --json; jobs watch non-TTY one-shots; eval banners annotate non-interactive defaults; reindex-code refusal is human unless --json. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * docs: CLAUDE.md Key Files notes for v0.42.15.0 isTTY-output decoupling (#1784) Annotate jobs.ts (jobs watch format/loop split + resolveWatchMode + the new cycle-default.ts), reindex-code.ts (human cost-refusal), and eval-cross-modal.ts (cycle/budget banner annotations). Regenerate llms-full.txt. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
61 lines
2.1 KiB
TypeScript
61 lines
2.1 KiB
TypeScript
/**
|
|
* v0.42.11.0 (#1784) — cycle-default resolver unit tests.
|
|
*
|
|
* Pins the 4 branches of resolveCycleDefault + the banner-suffix contract.
|
|
* Pure functions, no DB, no env mutation.
|
|
*/
|
|
import { describe, test, expect } from 'bun:test';
|
|
import {
|
|
resolveCycleDefault,
|
|
cycleDefaultSuffix,
|
|
DEFAULT_CYCLES_TTY,
|
|
DEFAULT_CYCLES_NONTTY,
|
|
} from '../../src/core/eval/cycle-default.ts';
|
|
|
|
describe('resolveCycleDefault', () => {
|
|
test('explicit value wins (TTY) — no annotation', () => {
|
|
const r = resolveCycleDefault(5, true);
|
|
expect(r).toEqual({ cycles: 5, usedNonTtyDefault: false });
|
|
});
|
|
|
|
test('explicit value wins (non-TTY) — no annotation', () => {
|
|
const r = resolveCycleDefault(5, false);
|
|
expect(r).toEqual({ cycles: 5, usedNonTtyDefault: false });
|
|
});
|
|
|
|
test('TTY default → 3, no annotation', () => {
|
|
const r = resolveCycleDefault(undefined, true);
|
|
expect(r).toEqual({ cycles: DEFAULT_CYCLES_TTY, usedNonTtyDefault: false });
|
|
expect(r.cycles).toBe(3);
|
|
});
|
|
|
|
test('non-TTY default → 1, ANNOTATED (the silent-degradation case)', () => {
|
|
const r = resolveCycleDefault(undefined, false);
|
|
expect(r).toEqual({ cycles: DEFAULT_CYCLES_NONTTY, usedNonTtyDefault: true });
|
|
expect(r.cycles).toBe(1);
|
|
});
|
|
|
|
test('explicit 1 in non-TTY is NOT flagged as the default (user asked for it)', () => {
|
|
const r = resolveCycleDefault(1, false);
|
|
expect(r.usedNonTtyDefault).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('cycleDefaultSuffix', () => {
|
|
test('empty unless the non-TTY default was applied', () => {
|
|
expect(cycleDefaultSuffix({ cycles: 3, usedNonTtyDefault: false })).toBe('');
|
|
expect(cycleDefaultSuffix({ cycles: 5, usedNonTtyDefault: false })).toBe('');
|
|
});
|
|
|
|
test('names the --cycles override when annotated', () => {
|
|
const s = cycleDefaultSuffix({ cycles: 1, usedNonTtyDefault: true });
|
|
expect(s).toContain('non-interactive default');
|
|
expect(s).toContain('--cycles');
|
|
});
|
|
|
|
test('round-trips with resolveCycleDefault non-TTY path', () => {
|
|
expect(cycleDefaultSuffix(resolveCycleDefault(undefined, false))).not.toBe('');
|
|
expect(cycleDefaultSuffix(resolveCycleDefault(undefined, true))).toBe('');
|
|
});
|
|
});
|