diff --git a/get-shit-done/bin/lib/core.cjs b/get-shit-done/bin/lib/core.cjs index 32f97c0fe..6b2167e50 100644 --- a/get-shit-done/bin/lib/core.cjs +++ b/get-shit-done/bin/lib/core.cjs @@ -1488,7 +1488,7 @@ function checkAgentsInstalled() { * Users can override with model_overrides in config.json for custom/latest models. */ const MODEL_ALIAS_MAP = { - 'opus': 'claude-opus-4-6', + 'opus': 'claude-opus-4-7', 'sonnet': 'claude-sonnet-4-6', 'haiku': 'claude-haiku-4-5', }; @@ -1506,11 +1506,9 @@ const MODEL_ALIAS_MAP = { * provider-specific IDs the runtime cannot accept. */ const RUNTIME_PROFILE_MAP = { - claude: { - opus: { model: 'claude-opus-4-6' }, - sonnet: { model: 'claude-sonnet-4-6' }, - haiku: { model: 'claude-haiku-4-5' }, - }, + claude: Object.fromEntries( + Object.entries(MODEL_ALIAS_MAP).map(([tier, model]) => [tier, { model }]) + ), codex: { opus: { model: 'gpt-5.4', reasoning_effort: 'xhigh' }, sonnet: { model: 'gpt-5.3-codex', reasoning_effort: 'medium' }, diff --git a/tests/core.test.cjs b/tests/core.test.cjs index 3d232de0a..1ad7d6879 100644 --- a/tests/core.test.cjs +++ b/tests/core.test.cjs @@ -379,6 +379,24 @@ describe('resolveModelInternal', () => { assert.strictEqual(resolveModelInternal(tmpDir, 'gsd-planner'), ''); }); }); + + describe('resolve_model_ids: true', () => { + // Regression test for #2712: MODEL_ALIAS_MAP must track current model releases. + test('opus alias resolves to claude-opus-4-7', () => { + writeConfig({ resolve_model_ids: true, model_profile: 'quality' }); + assert.strictEqual(resolveModelInternal(tmpDir, 'gsd-planner'), 'claude-opus-4-7'); + }); + + test('sonnet alias resolves to claude-sonnet-4-6', () => { + writeConfig({ resolve_model_ids: true, model_profile: 'balanced' }); + assert.strictEqual(resolveModelInternal(tmpDir, 'gsd-executor'), 'claude-sonnet-4-6'); + }); + + test('haiku alias resolves to claude-haiku-4-5', () => { + writeConfig({ resolve_model_ids: true, model_profile: 'budget' }); + assert.strictEqual(resolveModelInternal(tmpDir, 'gsd-codebase-mapper'), 'claude-haiku-4-5'); + }); + }); }); // ─── escapeRegex ─────────────────────────────────────────────────────────────── diff --git a/tests/issue-2517-runtime-aware-profiles.test.cjs b/tests/issue-2517-runtime-aware-profiles.test.cjs index b9c2ce9c2..e5a4e7691 100644 --- a/tests/issue-2517-runtime-aware-profiles.test.cjs +++ b/tests/issue-2517-runtime-aware-profiles.test.cjs @@ -90,7 +90,7 @@ describe('issue #2517: backwards compat — no runtime key set', () => { test('resolve_model_ids:true still maps alias -> full Claude ID with no runtime', () => { writeConfig(tmpDir, { model_profile: 'balanced', resolve_model_ids: true }); - assert.strictEqual(resolveModelInternal(tmpDir, 'gsd-planner'), 'claude-opus-4-6'); + assert.strictEqual(resolveModelInternal(tmpDir, 'gsd-planner'), 'claude-opus-4-7'); }); test('resolve_model_ids:"omit" still returns "" with no runtime', () => { @@ -125,7 +125,7 @@ describe('issue #2517: runtime "claude" is a no-op for resolution (finding #4)', test('runtime:"claude" + resolve_model_ids:"omit" returns "" (finding #4 regression)', () => { // The pre-fix bug: runtime:"claude" hijacked the resolution chain and - // returned `claude-opus-4-6` even when the user explicitly asked for the + // returned the resolved Claude ID even when the user explicitly asked for the // omit semantics. writeConfig(tmpDir, { runtime: 'claude', @@ -141,7 +141,7 @@ describe('issue #2517: runtime "claude" is a no-op for resolution (finding #4)', model_profile: 'quality', resolve_model_ids: true, }); - assert.strictEqual(resolveModelInternal(tmpDir, 'gsd-planner'), 'claude-opus-4-6'); + assert.strictEqual(resolveModelInternal(tmpDir, 'gsd-planner'), 'claude-opus-4-7'); }); test('reasoning_effort is null on Claude (never leaks)', () => { @@ -587,6 +587,6 @@ describe('issue #2517: RUNTIME_PROFILE_MAP single source of truth (finding #16)' const codexOpus = RUNTIME_PROFILE_MAP.codex?.opus; assert.deepStrictEqual(codexOpus, { model: 'gpt-5.4', reasoning_effort: 'xhigh' }); const claudeOpus = RUNTIME_PROFILE_MAP.claude?.opus; - assert.deepStrictEqual(claudeOpus, { model: 'claude-opus-4-6' }); + assert.deepStrictEqual(claudeOpus, { model: 'claude-opus-4-7' }); }); }); diff --git a/tests/model-alias-map.test.cjs b/tests/model-alias-map.test.cjs index 1e21960d6..85916bade 100644 --- a/tests/model-alias-map.test.cjs +++ b/tests/model-alias-map.test.cjs @@ -13,8 +13,8 @@ const assert = require('node:assert/strict'); const { MODEL_ALIAS_MAP } = require('../get-shit-done/bin/lib/core.cjs'); describe('MODEL_ALIAS_MAP (#1690 regression)', () => { - test('opus maps to claude-opus-4-6', () => { - assert.equal(MODEL_ALIAS_MAP.opus, 'claude-opus-4-6'); + test('opus maps to claude-opus-4-7', () => { + assert.equal(MODEL_ALIAS_MAP.opus, 'claude-opus-4-7'); }); test('sonnet maps to claude-sonnet-4-6', () => {