feat: Address review comments, add stage/unstage functionality, conflict resolution improvements, support for Sonnet 4.6

This commit is contained in:
gsxdsm
2026-02-18 18:58:33 -08:00
parent df9a6314da
commit 983eb21faa
66 changed files with 2317 additions and 823 deletions

View File

@@ -197,8 +197,43 @@ export function OpencodeModelConfiguration({
onDynamicModelToggle,
isLoadingDynamicModels = false,
}: OpencodeModelConfigurationProps) {
// Determine the free tier models to display.
// When dynamic models are available from CLI, use the opencode provider models
// from the dynamic list (they reflect the actual currently-available models).
// Fall back to the hardcoded OPENCODE_MODELS only when CLI hasn't returned data.
const dynamicOpencodeFreeModels = useMemo(() => {
const opencodeModelsFromCli = dynamicModels.filter((m) => m.provider === 'opencode');
if (opencodeModelsFromCli.length === 0) return null;
// Convert dynamic ModelDefinition to OpencodeModelConfig for the static section
return opencodeModelsFromCli.map(
(m): OpencodeModelConfig => ({
id: m.id.replace('opencode/', 'opencode-') as OpencodeModelId,
label: m.name.replace(/\s*\(Free\)\s*$/, '').replace(/\s*\(OpenCode\)\s*$/, ''),
description: m.description,
supportsVision: m.supportsVision ?? false,
provider: 'opencode' as OpencodeProvider,
tier: 'free',
})
);
}, [dynamicModels]);
// Use dynamically discovered free tier models when available, otherwise hardcoded fallback
const effectiveStaticModels = dynamicOpencodeFreeModels ?? OPENCODE_MODELS;
// Build an effective config map that includes dynamic models (for default model dropdown lookup)
const effectiveModelConfigMap = useMemo(() => {
const map = { ...OPENCODE_MODEL_CONFIG_MAP };
if (dynamicOpencodeFreeModels) {
for (const model of dynamicOpencodeFreeModels) {
map[model.id] = model;
}
}
return map;
}, [dynamicOpencodeFreeModels]);
// Group static models by provider for organized display
const modelsByProvider = OPENCODE_MODELS.reduce(
const modelsByProvider = effectiveStaticModels.reduce(
(acc, model) => {
if (!acc[model.provider]) {
acc[model.provider] = [];
@@ -217,7 +252,7 @@ export function OpencodeModelConfiguration({
const [dynamicProviderSearch, setDynamicProviderSearch] = useState('');
const normalizedDynamicSearch = dynamicProviderSearch.trim().toLowerCase();
const hasDynamicSearch = normalizedDynamicSearch.length > 0;
const allStaticModelIds = OPENCODE_MODELS.map((model) => model.id);
const allStaticModelIds = effectiveStaticModels.map((model) => model.id);
const selectableStaticModelIds = allStaticModelIds.filter(
(modelId) => modelId !== opencodeDefaultModel
);
@@ -378,7 +413,7 @@ export function OpencodeModelConfiguration({
</SelectTrigger>
<SelectContent>
{enabledOpencodeModels.map((modelId) => {
const model = OPENCODE_MODEL_CONFIG_MAP[modelId];
const model = effectiveModelConfigMap[modelId];
if (!model) return null;
const ModelIconComponent = getModelIcon(modelId);
return (