Accumulate OpenCode settings restarts behind Apply & Restart
Defer OpenCode reloads after settings mutations, track pending changes, and expose a top-right Apply & Restart OpenCode action with a counter so sessions stay available until the user explicitly applies. Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
This commit is contained in:
co-authored by
Serhii Dziupin
parent
775da6e9f4
commit
57819dd164
@@ -1,14 +1,12 @@
|
||||
import { create } from 'zustand';
|
||||
import { devtools, persist } from 'zustand/middleware';
|
||||
import { createDeferredSafeJSONStorage } from './utils/safeStorage';
|
||||
import {
|
||||
startConfigUpdate,
|
||||
finishConfigUpdate,
|
||||
} from '@/lib/configUpdate';
|
||||
import { startConfigUpdate } from '@/lib/configUpdate';
|
||||
import { refreshAfterOpenCodeRestart } from '@/stores/useAgentsStore';
|
||||
import { useProjectsStore } from '@/stores/useProjectsStore';
|
||||
import { opencodeClient } from '@/lib/opencode/client';
|
||||
import { runtimeFetch } from '@/lib/runtime-fetch';
|
||||
import { noteDeferredRestartFromPayload } from '@/lib/opencode/deferredRestart';
|
||||
|
||||
export type PluginScope = 'user' | 'project';
|
||||
type PluginParsedKind = 'npm' | 'path';
|
||||
@@ -43,6 +41,8 @@ export type PluginMutationResult = {
|
||||
reloadFailed?: boolean;
|
||||
message?: string;
|
||||
warning?: string;
|
||||
requiresManualRestart?: boolean;
|
||||
restartDeferred?: boolean;
|
||||
};
|
||||
|
||||
export type RegistryResult =
|
||||
@@ -91,6 +91,9 @@ type RegistryInfoResponse = {
|
||||
type PluginMutationPayload = {
|
||||
success?: boolean;
|
||||
requiresReload?: boolean;
|
||||
requiresRestart?: boolean;
|
||||
restartDeferred?: boolean;
|
||||
requiresManualRestart?: boolean;
|
||||
message?: string;
|
||||
reloadDelayMs?: number;
|
||||
reloadFailed?: boolean;
|
||||
@@ -248,7 +251,7 @@ export const usePluginsStore = create<PluginsStore>()(
|
||||
body: JSON.stringify(buildEntryBody(input)),
|
||||
});
|
||||
return response;
|
||||
}, get);
|
||||
}, get, { restartId: input.spec });
|
||||
if (result.ok) {
|
||||
void get().loadRegistryInfo({ specs: [input.spec], force: true });
|
||||
}
|
||||
@@ -265,7 +268,7 @@ export const usePluginsStore = create<PluginsStore>()(
|
||||
body: JSON.stringify(buildEntryBody(input)),
|
||||
});
|
||||
return response;
|
||||
}, get);
|
||||
}, get, { restartId: id });
|
||||
if (result.ok && nextSpec) {
|
||||
void get().loadRegistryInfo({ specs: [nextSpec], force: true });
|
||||
}
|
||||
@@ -280,7 +283,7 @@ export const usePluginsStore = create<PluginsStore>()(
|
||||
headers: buildDirectoryHeaders(configDirectory),
|
||||
});
|
||||
return response;
|
||||
}, get);
|
||||
}, get, { restartId: id });
|
||||
|
||||
if (result.ok && get().selectedId === id) {
|
||||
set({ selectedId: null });
|
||||
@@ -317,7 +320,7 @@ export const usePluginsStore = create<PluginsStore>()(
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
return response;
|
||||
}, get);
|
||||
}, get, { restartId: input.fileName });
|
||||
},
|
||||
|
||||
updateFile: async (id, input) => {
|
||||
@@ -328,7 +331,7 @@ export const usePluginsStore = create<PluginsStore>()(
|
||||
body: JSON.stringify(input),
|
||||
});
|
||||
return response;
|
||||
}, get);
|
||||
}, get, { restartId: id });
|
||||
},
|
||||
|
||||
deleteFile: async (id) => {
|
||||
@@ -338,7 +341,7 @@ export const usePluginsStore = create<PluginsStore>()(
|
||||
headers: buildDirectoryHeaders(configDirectory),
|
||||
});
|
||||
return response;
|
||||
}, get);
|
||||
}, get, { restartId: id });
|
||||
|
||||
if (result.ok && get().selectedId === id) {
|
||||
set({ selectedId: null });
|
||||
@@ -425,9 +428,8 @@ async function runPluginMutation(
|
||||
progressMessage: string,
|
||||
request: (configDirectory: string | null) => Promise<Response>,
|
||||
get: () => PluginsStore,
|
||||
options?: { restartId?: string },
|
||||
): Promise<PluginMutationResult> {
|
||||
startConfigUpdate(progressMessage);
|
||||
let requiresReload = false;
|
||||
try {
|
||||
const configDirectory = getConfigDirectory();
|
||||
const response = await request(configDirectory);
|
||||
@@ -439,8 +441,30 @@ async function runPluginMutation(
|
||||
|
||||
invalidatePluginCache(configDirectory);
|
||||
|
||||
if (payload?.requiresManualRestart) {
|
||||
await get().loadPlugins({ force: true });
|
||||
return {
|
||||
ok: true,
|
||||
requiresManualRestart: true,
|
||||
reloadFailed: payload?.reloadFailed === true,
|
||||
message: payload?.message,
|
||||
warning: payload?.warning,
|
||||
};
|
||||
}
|
||||
|
||||
if (noteDeferredRestartFromPayload(payload, 'plugins', { id: options?.restartId })) {
|
||||
await get().loadPlugins({ force: true });
|
||||
return {
|
||||
ok: true,
|
||||
restartDeferred: true,
|
||||
reloadFailed: payload?.reloadFailed === true,
|
||||
message: payload?.message,
|
||||
warning: payload?.warning,
|
||||
};
|
||||
}
|
||||
|
||||
if (payload?.requiresReload) {
|
||||
requiresReload = true;
|
||||
startConfigUpdate(progressMessage);
|
||||
await refreshAfterOpenCodeRestart({
|
||||
message: payload.message,
|
||||
delayMs: payload.reloadDelayMs ?? CLIENT_RELOAD_DELAY_MS,
|
||||
@@ -458,8 +482,6 @@ async function runPluginMutation(
|
||||
} catch (error) {
|
||||
console.error('[PluginsStore] Failed to update plugin configuration:', error);
|
||||
return { ok: false };
|
||||
} finally {
|
||||
if (!requiresReload) finishConfigUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user