mirror of
https://github.com/garrytan/gstack.git
synced 2026-11-15 12:57:22 +01:00
W7 R3: resolveClaudeOverlay allowlist and validation table
scripts/models.ts gains CLAUDE_OVERLAY_MODELS and resolveClaudeOverlay(id), which maps a --claude-model value to a Claude overlay or an error with problem, cause and fix (bare Claude Code aliases, unknown IDs, non-Claude families). A claude-* ID without its own overlay uses the generic one. `bun scripts/models.ts claude-overlay <id>` is setup's bridge.
This commit is contained in:
1 parent
ac20ef1e13
commit
50d896fa66
2 files changed
+144
No files matched your search
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* `resolveClaudeOverlay` — the validation table behind `./setup --claude-model`.
|
||||
*/
|
||||
import { describe, expect, test } from 'bun:test';
|
||||
import { spawnSync } from 'node:child_process';
|
||||
import { existsSync } from 'node:fs';
|
||||
import { join, resolve } from 'node:path';
|
||||
import { ALL_MODEL_NAMES, CLAUDE_OVERLAY_MODELS, resolveClaudeOverlay } from '../scripts/models';
|
||||
|
||||
const ROOT = resolve(import.meta.dir, '..');
|
||||
|
||||
describe('resolveClaudeOverlay', () => {
|
||||
test.each([
|
||||
['claude', 'claude', false],
|
||||
['opus-4-7', 'opus-4-7', false],
|
||||
['claude-opus-4-7', 'opus-4-7', false],
|
||||
['claude-opus-4-8-20260115', 'opus-4-8', false],
|
||||
['claude-opus-4-8-latest', 'opus-4-8', false],
|
||||
['claude-sonnet-5[1m]', 'sonnet-5', false],
|
||||
[' Claude-Sonnet-5 ', 'sonnet-5', false],
|
||||
['claude-fable-5-1', 'fable-5', false],
|
||||
['claude-opus-5-5', 'claude', true],
|
||||
['claude-opus-4-7-1', 'claude', true],
|
||||
['claude-haiku-4-5', 'claude', true],
|
||||
['claude-3-opus-20240229', 'claude', true],
|
||||
])('%p uses the %p overlay', (id, overlay, generic) => {
|
||||
expect(resolveClaudeOverlay(id)).toEqual({ overlay, generic });
|
||||
});
|
||||
|
||||
test.each([
|
||||
['opus', 'alias'],
|
||||
['sonnet', 'alias'],
|
||||
['haiku', 'alias'],
|
||||
['default', 'alias'],
|
||||
['Opus[1m]', 'alias'],
|
||||
['gpt-5.4', 'non-claude'],
|
||||
['gemini', 'non-claude'],
|
||||
['o3', 'non-claude'],
|
||||
['gpt-6-astra', 'non-claude'],
|
||||
['banana', 'unknown'],
|
||||
['', 'unknown'],
|
||||
])('%p is rejected as %p with problem, cause and fix', (id, kind) => {
|
||||
const result = resolveClaudeOverlay(id);
|
||||
expect('error' in result).toBe(true);
|
||||
if (!('error' in result)) return;
|
||||
expect(result.error.kind).toBe(kind);
|
||||
for (const part of [result.error.problem, result.error.cause, result.error.fix]) expect(part.length).toBeGreaterThan(10);
|
||||
expect(result.error.fix).toContain('claude');
|
||||
});
|
||||
|
||||
test('every Claude overlay is a known model with an overlay file', () => {
|
||||
for (const overlay of CLAUDE_OVERLAY_MODELS) {
|
||||
expect((ALL_MODEL_NAMES as readonly string[]).includes(overlay)).toBe(true);
|
||||
expect(existsSync(join(ROOT, 'model-overlays', `${overlay}.md`))).toBe(true);
|
||||
}
|
||||
});
|
||||
|
||||
test('the CLI bridge setup calls prints overlay and generic flag, or the error lines', () => {
|
||||
const run = (id: string) => spawnSync('bun', ['run', 'scripts/models.ts', 'claude-overlay', id], { cwd: ROOT, encoding: 'utf8', timeout: 30_000 });
|
||||
const ok = run('claude-opus-5-5');
|
||||
expect(ok.status).toBe(0);
|
||||
expect(ok.stdout).toBe('claude\t1\n');
|
||||
const bad = run('opus');
|
||||
expect(bad.status).toBe(1);
|
||||
expect(bad.stdout).toBe('');
|
||||
expect(bad.stderr.trim().split('\n')).toHaveLength(3);
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user