fix(agents): stop falsely reporting saved agent edits on external OpenCode; make model-selector shortcut customizable (#1839)

* feat(shortcuts): make 'Open model selector' shortcut customizable

Lets users remap the model selector shortcut (e.g. to Ctrl+M) via
Settings > OpenChamber > Shortcuts, matching OpenCode's quick
model-switch keybinding workflow.

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

* fix(agents): surface manual-restart needed when on external OpenCode

Agent prompt/permission/settings edits are written to disk, but an
external OpenCode server (skip-start or auto-detected on the default
port) is not owned by OpenChamber and is only health-probed on config
change, so it keeps serving its startup-cached config until restarted.
The API previously claimed a successful reload, so the UI silently
reverted the edit to the stale/default value on refresh.

Now refreshOpenCodeAfterConfigChange reports whether a real reload
happened; agent routes return requiresManualRestart for external mode;
and the agents UI keeps the saved values and warns the user to restart
their OpenCode server instead of showing a false success. Managed mode
behavior is unchanged (process is restarted and reload is live).

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>

---------

Co-authored-by: Serhii Dziupin <makeittech@users.noreply.github.com>
This commit is contained in:
Serhii Dziupin
2026-06-26 19:37:45 +03:00
committed by GitHub
co-authored by Serhii Dziupin
parent 3e3cd82a47
commit f4e90ca232
15 changed files with 155 additions and 53 deletions
+13 -1
View File
@@ -753,12 +753,22 @@ export const createOpenCodeLifecycleRuntime = (deps) => {
await restartOpenCode();
// A managed OpenCode process is restarted (and thus re-reads config from
// disk) by restartOpenCode(). An external OpenCode server is NOT owned by
// OpenChamber: restartOpenCode() only re-probes its health, so the freshly
// written config is on disk but the running server keeps serving its old,
// startup-cached config until the user restarts it themselves. Report this
// honestly so callers don't claim the change is live.
const external = state.isExternalOpenCode === true;
try {
await waitForOpenCodeReady();
state.isOpenCodeReady = true;
state.openCodeNotReadySince = 0;
if (agentName) {
// Waiting for the agent to appear only makes sense when we actually
// reloaded config. An external server will never surface it here.
if (agentName && !external) {
await waitForAgentPresence(agentName);
}
@@ -770,6 +780,8 @@ export const createOpenCodeLifecycleRuntime = (deps) => {
console.error(`Failed to refresh OpenCode after ${reason}:`, error.message);
throw error;
}
return { reloaded: !external, external };
};
const bootstrapOpenCodeAtStartup = async () => {