/** * Context-window constants — single source of truth. * * Several Claude Code budgets scale with the model's context window: * - the skill listing is allotted ~2% of context (CC 2.1.32, changelog L2860); * - the "CLAUDE.md is too long" warning threshold scales with it (CC 2.1.169). * * We cannot observe the user's actual context window, so scanners anchor on a * conservative 200k window (the smallest common size — it fires earliest, the * safe default when the window is unknown) and disclose the relaxed 1M figure. * * Zero external dependencies. */ // Conservative anchor: the smallest common context window. Budgets anchored // here fire earliest, which is the safe default when the window is unknown. export const CONTEXT_WINDOW_ANCHOR = 200_000; // Large context window (Opus/Sonnet 1M tier). Used to disclose how a budget // relaxes on large-context models. export const LARGE_CONTEXT_WINDOW = 1_000_000; // How much larger the 1M window is than the 200k anchor (= 5). A budget that // scales linearly with the window relaxes by this factor at 1M. export const LARGE_CONTEXT_SCALE = LARGE_CONTEXT_WINDOW / CONTEXT_WINDOW_ANCHOR; // Dependency-free thousands separator (repo invariant: zero external deps). export const withCommas = (n) => String(n).replace(/\B(?=(\d{3})+(?!\d))/g, ','); /** * @typedef {object} ResolvedContextWindow * @property {number} window - the context window budgets calibrate against * @property {boolean} advisory - true when the window is unknown: keep the anchor * but downgrade budget findings to info instead of * firing them as a breach * @property {'default'|'explicit'|'auto-unresolved'} source */ /** * Resolve the raw `--context-window` CLI value into a window + advisory flag. * * Design (B8): the DEFAULT (no flag) is byte-identical to the pre-B8 behavior — * the conservative 200k anchor at full severity. Only an explicit value changes * calibration. `auto` asks the tool to figure out the window; until model→window * probing ships (B8b) it cannot, so it keeps the conservative anchor but marks the * result advisory so SKL/CML downgrade their budget findings to info rather than * "crying wolf" with a breach on a window we cannot confirm. * * @param {string|number|null|undefined} arg * @returns {ResolvedContextWindow} */ export function resolveContextWindow(arg) { if (arg == null) { return { window: CONTEXT_WINDOW_ANCHOR, advisory: false, source: 'default' }; } if (String(arg).trim().toLowerCase() === 'auto') { return { window: CONTEXT_WINDOW_ANCHOR, advisory: true, source: 'auto-unresolved' }; } const n = typeof arg === 'number' ? arg : parseInt(String(arg).trim(), 10); if (Number.isFinite(n) && n > 0) { return { window: n, advisory: false, source: 'explicit' }; } // Unparseable / non-positive: fall back to the conservative default (no advisory). return { window: CONTEXT_WINDOW_ANCHOR, advisory: false, source: 'default' }; } /** * Scale a 200k-anchored budget to a given context window. Linear in the window, * so it is the identity at the anchor (keeps the default byte-stable). * * @param {number} anchorValue - the budget/threshold defined at the 200k anchor * @param {number} window - the target context window * @returns {number} */ export function scaleForWindow(anchorValue, window) { return Math.round(anchorValue * (window / CONTEXT_WINDOW_ANCHOR)); }