diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index abd0eacf..3dfd78f9 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -8,6 +8,7 @@ ### Fixed +- Fixed `/reload` not picking up changes in global settings.json ([#1241](https://github.com/badlogic/pi-mono/issues/1241)) - Fixed Unix bash detection to fall back to PATH lookup when `/bin/bash` is unavailable, including Termux setups ([#1230](https://github.com/badlogic/pi-mono/pull/1230) by [@VaclavSynacek](https://github.com/VaclavSynacek)) ## [0.51.5] - 2026-02-04 diff --git a/packages/coding-agent/src/core/agent-session.ts b/packages/coding-agent/src/core/agent-session.ts index 54dbb1a8..4eba14f1 100644 --- a/packages/coding-agent/src/core/agent-session.ts +++ b/packages/coding-agent/src/core/agent-session.ts @@ -1982,6 +1982,7 @@ export class AgentSession { async reload(): Promise { const previousFlagValues = this._extensionRunner?.getFlagValues(); await this._extensionRunner?.emit({ type: "session_shutdown" }); + this.settingsManager.reload(); resetApiProviders(); await this._resourceLoader.reload(); this._buildRuntime({ diff --git a/packages/coding-agent/src/core/settings-manager.ts b/packages/coding-agent/src/core/settings-manager.ts index 6111da1d..f4ac02e4 100644 --- a/packages/coding-agent/src/core/settings-manager.ts +++ b/packages/coding-agent/src/core/settings-manager.ts @@ -240,6 +240,29 @@ export class SettingsManager { return this.loadProjectSettings(); } + reload(): void { + let nextGlobalSettings: Settings | null = null; + + if (this.persist && this.settingsPath) { + try { + nextGlobalSettings = SettingsManager.loadFromFile(this.settingsPath); + this.globalSettingsLoadError = null; + } catch (error) { + this.globalSettingsLoadError = error as Error; + } + } + + if (nextGlobalSettings) { + this.globalSettings = nextGlobalSettings; + } + + this.modifiedFields.clear(); + this.modifiedNestedFields.clear(); + + const projectSettings = this.loadProjectSettings(); + this.settings = deepMergeSettings(this.globalSettings, projectSettings); + } + /** Apply additional overrides on top of current settings */ applyOverrides(overrides: Partial): void { this.settings = deepMergeSettings(this.settings, overrides); diff --git a/packages/coding-agent/src/modes/interactive/interactive-mode.ts b/packages/coding-agent/src/modes/interactive/interactive-mode.ts index 4dcc11c4..e256f449 100644 --- a/packages/coding-agent/src/modes/interactive/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive/interactive-mode.ts @@ -3710,6 +3710,22 @@ export class InteractiveMode { try { await this.session.reload(); setRegisteredThemes(this.session.resourceLoader.getThemes().themes); + this.hideThinkingBlock = this.settingsManager.getHideThinkingBlock(); + const themeName = this.settingsManager.getTheme(); + const themeResult = themeName ? setTheme(themeName, true) : { success: true }; + if (!themeResult.success) { + this.showError(`Failed to load theme "${themeName}": ${themeResult.error}\nFell back to dark theme.`); + } + const editorPaddingX = this.settingsManager.getEditorPaddingX(); + const autocompleteMaxVisible = this.settingsManager.getAutocompleteMaxVisible(); + this.defaultEditor.setPaddingX(editorPaddingX); + this.defaultEditor.setAutocompleteMaxVisible(autocompleteMaxVisible); + if (this.editor !== this.defaultEditor) { + this.editor.setPaddingX?.(editorPaddingX); + this.editor.setAutocompleteMaxVisible?.(autocompleteMaxVisible); + } + this.ui.setShowHardwareCursor(this.settingsManager.getShowHardwareCursor()); + this.ui.setClearOnShrink(this.settingsManager.getClearOnShrink()); this.rebuildAutocomplete(); const runner = this.session.extensionRunner; if (runner) { diff --git a/packages/coding-agent/test/settings-manager.test.ts b/packages/coding-agent/test/settings-manager.test.ts index 643908ed..eb81806b 100644 --- a/packages/coding-agent/test/settings-manager.test.ts +++ b/packages/coding-agent/test/settings-manager.test.ts @@ -151,6 +151,48 @@ describe("SettingsManager", () => { }); }); + describe("reload", () => { + it("should reload global settings from disk", () => { + const settingsPath = join(agentDir, "settings.json"); + writeFileSync( + settingsPath, + JSON.stringify({ + theme: "dark", + extensions: ["/before.ts"], + }), + ); + + const manager = SettingsManager.create(projectDir, agentDir); + + writeFileSync( + settingsPath, + JSON.stringify({ + theme: "light", + extensions: ["/after.ts"], + defaultModel: "claude-sonnet", + }), + ); + + manager.reload(); + + expect(manager.getTheme()).toBe("light"); + expect(manager.getExtensionPaths()).toEqual(["/after.ts"]); + expect(manager.getDefaultModel()).toBe("claude-sonnet"); + }); + + it("should keep previous settings when file is invalid", () => { + const settingsPath = join(agentDir, "settings.json"); + writeFileSync(settingsPath, JSON.stringify({ theme: "dark" })); + + const manager = SettingsManager.create(projectDir, agentDir); + + writeFileSync(settingsPath, "{ invalid json"); + manager.reload(); + + expect(manager.getTheme()).toBe("dark"); + }); + }); + describe("shellCommandPrefix", () => { it("should load shellCommandPrefix from settings", () => { const settingsPath = join(agentDir, "settings.json");