From 9aeacc803c70018132a82e23673fab7966c5ea68 Mon Sep 17 00:00:00 2001 From: deseltrus Date: Sun, 15 Mar 2026 07:33:06 +0100 Subject: [PATCH] feat(prefs): model selection via select list instead of free-text input The preferences wizard now shows available models from the model registry as a selectable list instead of requiring users to manually type model IDs. Falls back to text input when no authenticated models are available. Co-Authored-By: Claude Opus 4.6 (1M context) --- src/resources/extensions/gsd/commands.ts | 47 +++++++++++++++++------- 1 file changed, 33 insertions(+), 14 deletions(-) diff --git a/src/resources/extensions/gsd/commands.ts b/src/resources/extensions/gsd/commands.ts index eae9b2214..c42ea113e 100644 --- a/src/resources/extensions/gsd/commands.ts +++ b/src/resources/extensions/gsd/commands.ts @@ -315,22 +315,41 @@ async function handlePrefsWizard( const modelPhases = ["research", "planning", "execution", "completion"] as const; const models: Record = (prefs.models as Record) ?? {}; - for (const phase of modelPhases) { - const current = models[phase] ?? ""; - const input = await ctx.ui.input( - `Model for ${phase} phase${current ? ` (current: ${current})` : ""}:`, - current || "e.g. claude-sonnet-4-20250514", - ); - if (input !== null && input !== undefined) { - const val = input.trim(); - if (val) { - models[phase] = val; - } else if (current) { - // User cleared it — remove - delete models[phase]; + const availableModels = ctx.modelRegistry.getAvailable(); + if (availableModels.length > 0) { + const modelOptions = availableModels.map(m => `${m.id} · ${m.provider}`); + modelOptions.push("(keep current)", "(clear)"); + + for (const phase of modelPhases) { + const current = models[phase] ?? ""; + const title = `Model for ${phase} phase${current ? ` (current: ${current})` : ""}:`; + const choice = await ctx.ui.select(title, modelOptions); + + if (choice && choice !== "(keep current)") { + if (choice === "(clear)") { + delete models[phase]; + } else { + models[phase] = choice.split(" · ")[0]; + } + } + } + } else { + // No authenticated models available — fall back to text input + for (const phase of modelPhases) { + const current = models[phase] ?? ""; + const input = await ctx.ui.input( + `Model for ${phase} phase${current ? ` (current: ${current})` : ""}:`, + current || "e.g. claude-sonnet-4-20250514", + ); + if (input !== null && input !== undefined) { + const val = input.trim(); + if (val) { + models[phase] = val; + } else if (current) { + delete models[phase]; + } } } - // null/undefined = Escape/skip — keep existing value } if (Object.keys(models).length > 0) { prefs.models = models;