Fix orphaned features when deleting worktrees (#820)

* Changes from fix/orphaned-features

* fix: Handle feature migration failures and improve UI accessibility

* feat: Add event emission for worktree deletion and feature migration

* fix: Handle OpenCode model errors and prevent duplicate model IDs

* feat: Add summary dialog and async verify with loading state

* fix: Add type attributes to buttons and improve OpenCode model selection

* fix: Add null checks for onVerify callback and opencode model selection
This commit is contained in:
gsxdsm
2026-02-28 15:42:10 -08:00
committed by GitHub
parent 1c0e460dd1
commit 63b0a4fb38
29 changed files with 838 additions and 85 deletions

View File

@@ -174,6 +174,7 @@ export function parseLocalStorageSettings(): Partial<GlobalSettings> | null {
defaultRequirePlanApproval: state.defaultRequirePlanApproval as boolean,
muteDoneSound: state.muteDoneSound as boolean,
disableSplashScreen: state.disableSplashScreen as boolean,
defaultSortNewestCardOnTop: state.defaultSortNewestCardOnTop as boolean,
enhancementModel: state.enhancementModel as GlobalSettings['enhancementModel'],
validationModel: state.validationModel as GlobalSettings['validationModel'],
phaseModels: state.phaseModels as GlobalSettings['phaseModels'],
@@ -685,6 +686,12 @@ export function hydrateStoreFromSettings(settings: GlobalSettings): void {
(modelId) => !modelId.startsWith('amazon-bedrock/')
);
const persistedKnownDynamicModelIds =
settings.knownDynamicModelIds ?? current.knownDynamicModelIds;
const sanitizedKnownDynamicModelIds = persistedKnownDynamicModelIds.filter(
(modelId) => !modelId.startsWith('amazon-bedrock/')
);
// Convert ProjectRef[] to Project[] (minimal data, features will be loaded separately)
const projects = (settings.projects ?? []).map((ref) => ({
id: ref.id,
@@ -764,6 +771,7 @@ export function hydrateStoreFromSettings(settings: GlobalSettings): void {
},
muteDoneSound: settings.muteDoneSound ?? false,
disableSplashScreen: settings.disableSplashScreen ?? false,
defaultSortNewestCardOnTop: settings.defaultSortNewestCardOnTop ?? false,
serverLogLevel: settings.serverLogLevel ?? 'info',
enableRequestLogging: settings.enableRequestLogging ?? true,
showQueryDevtools: settings.showQueryDevtools ?? true,
@@ -777,6 +785,7 @@ export function hydrateStoreFromSettings(settings: GlobalSettings): void {
enabledOpencodeModels: sanitizedEnabledOpencodeModels,
opencodeDefaultModel: sanitizedOpencodeDefaultModel,
enabledDynamicModelIds: sanitizedDynamicModelIds,
knownDynamicModelIds: sanitizedKnownDynamicModelIds,
disabledProviders: settings.disabledProviders ?? [],
enableAiCommitMessages: settings.enableAiCommitMessages ?? true,
enableSkills: settings.enableSkills ?? true,
@@ -906,6 +915,7 @@ function buildSettingsUpdateFromStore(): Record<string, unknown> {
defaultRequirePlanApproval: state.defaultRequirePlanApproval,
muteDoneSound: state.muteDoneSound,
disableSplashScreen: state.disableSplashScreen,
defaultSortNewestCardOnTop: state.defaultSortNewestCardOnTop,
serverLogLevel: state.serverLogLevel,
enableRequestLogging: state.enableRequestLogging,
enhancementModel: state.enhancementModel,
@@ -914,6 +924,7 @@ function buildSettingsUpdateFromStore(): Record<string, unknown> {
defaultThinkingLevel: state.defaultThinkingLevel,
defaultReasoningEffort: state.defaultReasoningEffort,
enabledDynamicModelIds: state.enabledDynamicModelIds,
knownDynamicModelIds: state.knownDynamicModelIds,
disabledProviders: state.disabledProviders,
enableAiCommitMessages: state.enableAiCommitMessages,
enableSkills: state.enableSkills,

View File

@@ -69,6 +69,7 @@ const SETTINGS_FIELDS_TO_SYNC = [
'defaultFeatureModel',
'muteDoneSound',
'disableSplashScreen',
'defaultSortNewestCardOnTop',
'serverLogLevel',
'enableRequestLogging',
'showQueryDevtools',
@@ -86,6 +87,7 @@ const SETTINGS_FIELDS_TO_SYNC = [
'enabledCopilotModels',
'copilotDefaultModel',
'enabledDynamicModelIds',
'knownDynamicModelIds',
'disabledProviders',
'autoLoadClaudeMd',
'useClaudeCodeSystemPrompt',
@@ -482,6 +484,14 @@ export function useSettingsSync(): SettingsSyncState {
return;
}
// If the sort preference changed, sync immediately so it survives a page refresh
// before the debounce timer fires (1s debounce would be lost on quick refresh).
if (newState.defaultSortNewestCardOnTop !== prevState.defaultSortNewestCardOnTop) {
logger.debug('defaultSortNewestCardOnTop changed, syncing immediately');
syncNow();
return;
}
// If projects array changed *meaningfully*, sync immediately.
// This is critical — projects list changes must sync right away to prevent loss
// when switching between Electron and web modes or closing the app.
@@ -705,6 +715,12 @@ export async function refreshSettingsFromServer(): Promise<boolean> {
(modelId) => !modelId.startsWith('amazon-bedrock/')
);
const persistedKnownDynamicModelIds =
serverSettings.knownDynamicModelIds ?? currentAppState.knownDynamicModelIds;
const sanitizedKnownDynamicModelIds = persistedKnownDynamicModelIds.filter(
(modelId) => !modelId.startsWith('amazon-bedrock/')
);
// Migrate phase models to canonical format
const migratedPhaseModels = serverSettings.phaseModels
? {
@@ -788,6 +804,7 @@ export async function refreshSettingsFromServer(): Promise<boolean> {
muteDoneSound: serverSettings.muteDoneSound,
defaultMaxTurns: serverSettings.defaultMaxTurns ?? 10000,
disableSplashScreen: serverSettings.disableSplashScreen ?? false,
defaultSortNewestCardOnTop: serverSettings.defaultSortNewestCardOnTop ?? false,
serverLogLevel: serverSettings.serverLogLevel ?? 'info',
enableRequestLogging: serverSettings.enableRequestLogging ?? true,
enhancementModel: serverSettings.enhancementModel,
@@ -807,6 +824,7 @@ export async function refreshSettingsFromServer(): Promise<boolean> {
enabledCopilotModels: sanitizedEnabledCopilotModels,
copilotDefaultModel: sanitizedCopilotDefaultModel,
enabledDynamicModelIds: sanitizedDynamicModelIds,
knownDynamicModelIds: sanitizedKnownDynamicModelIds,
disabledProviders: serverSettings.disabledProviders ?? [],
autoLoadClaudeMd: serverSettings.autoLoadClaudeMd ?? true,
useClaudeCodeSystemPrompt: serverSettings.useClaudeCodeSystemPrompt ?? true,