Defer OpenCode restarts for config mutations
Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
This commit is contained in:
co-authored by
Serhii Dziupin
parent
824d1fbbf4
commit
775da6e9f4
@@ -1,9 +1,9 @@
|
||||
import { buildDeferredRestartResponse } from './config-mutation-response.js';
|
||||
|
||||
export const registerConfigEntityRoutes = (app, dependencies) => {
|
||||
const {
|
||||
resolveProjectDirectory,
|
||||
resolveOptionalProjectDirectory,
|
||||
refreshOpenCodeAfterConfigChange,
|
||||
clientReloadDelayMs,
|
||||
getAgentSources,
|
||||
getAgentConfig,
|
||||
createAgent,
|
||||
@@ -26,51 +26,14 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
||||
expandSnippets,
|
||||
} = dependencies;
|
||||
|
||||
// Build the response for a config mutation based on whether OpenCode actually
|
||||
// reloaded the change. When connected to an external OpenCode server that
|
||||
// OpenChamber cannot restart, the change is persisted to disk but the running
|
||||
// server will not serve it until the user restarts that server. We must not
|
||||
// report a clean "reloading" success in that case, otherwise the UI silently
|
||||
// reverts the edit to the stale value on the next refresh.
|
||||
const buildConfigMutationResponse = (refreshResult, { liveMessage, manualRestartMessage }) => {
|
||||
if (refreshResult && refreshResult.external) {
|
||||
return {
|
||||
success: true,
|
||||
requiresReload: false,
|
||||
requiresManualRestart: true,
|
||||
message: manualRestartMessage,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
success: true,
|
||||
requiresReload: true,
|
||||
message: liveMessage,
|
||||
reloadDelayMs: clientReloadDelayMs,
|
||||
};
|
||||
};
|
||||
|
||||
// Persist to disk immediately; OpenCode restart is deferred to an explicit
|
||||
// Apply & Restart so settings edits do not interrupt live sessions.
|
||||
const completeMcpMutation = async (res, action, name, applyChange) => {
|
||||
applyChange();
|
||||
|
||||
try {
|
||||
await refreshOpenCodeAfterConfigChange(`mcp ${action}`);
|
||||
return res.json({
|
||||
success: true,
|
||||
requiresReload: true,
|
||||
message: `MCP server "${name}" ${action}d. Reloading interface…`,
|
||||
reloadDelayMs: clientReloadDelayMs,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error(`[API:MCP ${action}] Reload failed after config write:`, error);
|
||||
return res.json({
|
||||
success: true,
|
||||
requiresReload: false,
|
||||
reloadFailed: true,
|
||||
message: `MCP server "${name}" ${action}d, but OpenCode reload failed.`,
|
||||
warning: error.message || 'OpenCode reload failed after the MCP configuration changed',
|
||||
});
|
||||
}
|
||||
const past = action === 'delete' ? 'deleted' : `${action}d`;
|
||||
return res.json(buildDeferredRestartResponse(
|
||||
`MCP server "${name}" ${past}. Restart OpenCode to apply.`,
|
||||
));
|
||||
};
|
||||
|
||||
app.get('/api/config/agents/:name', async (req, res) => {
|
||||
@@ -128,14 +91,9 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
||||
console.log('[Server] Scope:', scope, 'Working directory:', directory);
|
||||
|
||||
createAgent(agentName, config, directory, scope);
|
||||
const refreshResult = await refreshOpenCodeAfterConfigChange('agent creation', {
|
||||
agentName
|
||||
});
|
||||
|
||||
res.json(buildConfigMutationResponse(refreshResult, {
|
||||
liveMessage: `Agent ${agentName} created successfully. Reloading interface…`,
|
||||
manualRestartMessage: `Agent ${agentName} saved. Restart your connected OpenCode server to apply the change.`,
|
||||
}));
|
||||
res.json(buildDeferredRestartResponse(
|
||||
`Agent ${agentName} created successfully. Restart OpenCode to apply.`,
|
||||
));
|
||||
} catch (error) {
|
||||
console.error('Failed to create agent:', error);
|
||||
res.status(500).json({ error: error.message || 'Failed to create agent' });
|
||||
@@ -156,14 +114,12 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
||||
console.log('[Server] Working directory:', directory);
|
||||
|
||||
updateAgent(agentName, updates, directory);
|
||||
const refreshResult = await refreshOpenCodeAfterConfigChange('agent update');
|
||||
|
||||
console.log(`[Server] Agent ${agentName} updated successfully`);
|
||||
|
||||
res.json(buildConfigMutationResponse(refreshResult, {
|
||||
liveMessage: `Agent ${agentName} updated successfully. Reloading interface…`,
|
||||
manualRestartMessage: `Agent ${agentName} saved. Restart your connected OpenCode server to apply the change.`,
|
||||
}));
|
||||
res.json(buildDeferredRestartResponse(
|
||||
`Agent ${agentName} updated successfully. Restart OpenCode to apply.`,
|
||||
));
|
||||
} catch (error) {
|
||||
console.error('[Server] Failed to update agent:', error);
|
||||
console.error('[Server] Error stack:', error.stack);
|
||||
@@ -181,12 +137,9 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
||||
|
||||
const scope = req.body?.scope;
|
||||
deleteAgent(agentName, directory, scope);
|
||||
const refreshResult = await refreshOpenCodeAfterConfigChange('agent deletion');
|
||||
|
||||
res.json(buildConfigMutationResponse(refreshResult, {
|
||||
liveMessage: `Agent ${agentName} deleted successfully. Reloading interface…`,
|
||||
manualRestartMessage: `Agent ${agentName} deleted. Restart your connected OpenCode server to apply the change.`,
|
||||
}));
|
||||
res.json(buildDeferredRestartResponse(
|
||||
`Agent ${agentName} deleted successfully. Restart OpenCode to apply.`,
|
||||
));
|
||||
} catch (error) {
|
||||
console.error('Failed to delete agent:', error);
|
||||
res.status(500).json({ error: error.message || 'Failed to delete agent' });
|
||||
@@ -323,16 +276,9 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
||||
console.log('[Server] Scope:', scope, 'Working directory:', directory);
|
||||
|
||||
createCommand(commandName, config, directory, scope);
|
||||
await refreshOpenCodeAfterConfigChange('command creation', {
|
||||
commandName
|
||||
});
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
requiresReload: true,
|
||||
message: `Command ${commandName} created successfully. Reloading interface…`,
|
||||
reloadDelayMs: clientReloadDelayMs,
|
||||
});
|
||||
res.json(buildDeferredRestartResponse(
|
||||
`Command ${commandName} created successfully. Restart OpenCode to apply.`,
|
||||
));
|
||||
} catch (error) {
|
||||
console.error('Failed to create command:', error);
|
||||
res.status(500).json({ error: error.message || 'Failed to create command' });
|
||||
@@ -353,16 +299,12 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
||||
console.log('[Server] Working directory:', directory);
|
||||
|
||||
updateCommand(commandName, updates, directory);
|
||||
await refreshOpenCodeAfterConfigChange('command update');
|
||||
|
||||
console.log(`[Server] Command ${commandName} updated successfully`);
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
requiresReload: true,
|
||||
message: `Command ${commandName} updated successfully. Reloading interface…`,
|
||||
reloadDelayMs: clientReloadDelayMs,
|
||||
});
|
||||
res.json(buildDeferredRestartResponse(
|
||||
`Command ${commandName} updated successfully. Restart OpenCode to apply.`,
|
||||
));
|
||||
} catch (error) {
|
||||
console.error('[Server] Failed to update command:', error);
|
||||
console.error('[Server] Error stack:', error.stack);
|
||||
@@ -379,14 +321,9 @@ export const registerConfigEntityRoutes = (app, dependencies) => {
|
||||
}
|
||||
|
||||
deleteCommand(commandName, directory);
|
||||
await refreshOpenCodeAfterConfigChange('command deletion');
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
requiresReload: true,
|
||||
message: `Command ${commandName} deleted successfully. Reloading interface…`,
|
||||
reloadDelayMs: clientReloadDelayMs,
|
||||
});
|
||||
res.json(buildDeferredRestartResponse(
|
||||
`Command ${commandName} deleted successfully. Restart OpenCode to apply.`,
|
||||
));
|
||||
} catch (error) {
|
||||
console.error('Failed to delete command:', error);
|
||||
res.status(500).json({ error: error.message || 'Failed to delete command' });
|
||||
|
||||
Reference in New Issue
Block a user