diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 8027be1d..5ca41e74 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,10 @@ ## [Unreleased] +### Breaking Changes + +- Disabled OSC 9;4 terminal progress indicators by default. Set `terminal.showTerminalProgress` to `true` in `/settings` to re-enable ([#3588](https://github.com/badlogic/pi-mono/issues/3588)) + ### Fixed - Fixed `ctx.ui.setWorkingMessage()` to persist across loader recreation, matching the behavior of `ctx.ui.setWorkingIndicator()` ([#3566](https://github.com/badlogic/pi-mono/issues/3566)) diff --git a/packages/coding-agent/src/core/settings-manager.ts b/packages/coding-agent/src/core/settings-manager.ts index 6e8835ef..cd2339ac 100644 --- a/packages/coding-agent/src/core/settings-manager.ts +++ b/packages/coding-agent/src/core/settings-manager.ts @@ -27,6 +27,7 @@ export interface TerminalSettings { showImages?: boolean; // default: true (only relevant if terminal supports images) imageWidthCells?: number; // default: 60 (preferred inline image width in terminal cells) clearOnShrink?: boolean; // default: false (clear empty rows when content shrinks) + showTerminalProgress?: boolean; // default: false (OSC 9;4 terminal progress indicators) } export interface ImageSettings { @@ -905,6 +906,19 @@ export class SettingsManager { this.save(); } + getShowTerminalProgress(): boolean { + return this.settings.terminal?.showTerminalProgress ?? false; + } + + setShowTerminalProgress(enabled: boolean): void { + if (!this.globalSettings.terminal) { + this.globalSettings.terminal = {}; + } + this.globalSettings.terminal.showTerminalProgress = enabled; + this.markModified("terminal", "showTerminalProgress"); + this.save(); + } + getImageAutoResize(): boolean { return this.settings.images?.autoResize ?? true; } diff --git a/packages/coding-agent/src/modes/interactive/components/settings-selector.ts b/packages/coding-agent/src/modes/interactive/components/settings-selector.ts index 518e0095..e56bcf54 100644 --- a/packages/coding-agent/src/modes/interactive/components/settings-selector.ts +++ b/packages/coding-agent/src/modes/interactive/components/settings-selector.ts @@ -52,6 +52,7 @@ export interface SettingsConfig { autocompleteMaxVisible: number; quietStartup: boolean; clearOnShrink: boolean; + showTerminalProgress: boolean; } export interface SettingsCallbacks { @@ -77,6 +78,7 @@ export interface SettingsCallbacks { onAutocompleteMaxVisibleChange: (maxVisible: number) => void; onQuietStartupChange: (enabled: boolean) => void; onClearOnShrinkChange: (enabled: boolean) => void; + onShowTerminalProgressChange: (enabled: boolean) => void; onCancel: () => void; } @@ -372,6 +374,16 @@ export class SettingsSelectorComponent extends Container { values: ["true", "false"], }); + // Terminal progress toggle (insert after clear-on-shrink) + const clearOnShrinkIndex = items.findIndex((item) => item.id === "clear-on-shrink"); + items.splice(clearOnShrinkIndex + 1, 0, { + id: "terminal-progress", + label: "Terminal progress", + description: "Show OSC 9;4 progress indicators in the terminal tab bar", + currentValue: config.showTerminalProgress ? "true" : "false", + values: ["true", "false"], + }); + // Add borders this.addChild(new DynamicBorder()); @@ -440,6 +452,9 @@ export class SettingsSelectorComponent extends Container { case "clear-on-shrink": callbacks.onClearOnShrinkChange(newValue === "true"); break; + case "terminal-progress": + callbacks.onShowTerminalProgressChange(newValue === "true"); + break; } }, callbacks.onCancel, diff --git a/packages/coding-agent/src/modes/interactive/interactive-mode.ts b/packages/coding-agent/src/modes/interactive/interactive-mode.ts index 510de099..125eae96 100644 --- a/packages/coding-agent/src/modes/interactive/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive/interactive-mode.ts @@ -2594,7 +2594,9 @@ export class InteractiveMode { switch (event.type) { case "agent_start": - this.ui.terminal.setProgress(true); + if (this.settingsManager.getShowTerminalProgress()) { + this.ui.terminal.setProgress(true); + } // Restore main escape handler if retry handler is still active // (retry success event fires later, but we need main handler now) if (this.retryEscapeHandler) { @@ -2769,7 +2771,9 @@ export class InteractiveMode { } case "agent_end": - this.ui.terminal.setProgress(false); + if (this.settingsManager.getShowTerminalProgress()) { + this.ui.terminal.setProgress(false); + } if (this.loadingAnimation) { this.loadingAnimation.stop(); this.loadingAnimation = undefined; @@ -2788,7 +2792,9 @@ export class InteractiveMode { break; case "compaction_start": { - this.ui.terminal.setProgress(true); + if (this.settingsManager.getShowTerminalProgress()) { + this.ui.terminal.setProgress(true); + } // Keep editor active; submissions are queued during compaction. this.autoCompactionEscapeHandler = this.defaultEditor.onEscape; this.defaultEditor.onEscape = () => { @@ -2812,7 +2818,9 @@ export class InteractiveMode { } case "compaction_end": { - this.ui.terminal.setProgress(false); + if (this.settingsManager.getShowTerminalProgress()) { + this.ui.terminal.setProgress(false); + } if (this.autoCompactionEscapeHandler) { this.defaultEditor.onEscape = this.autoCompactionEscapeHandler; this.autoCompactionEscapeHandler = undefined; @@ -3711,6 +3719,7 @@ export class InteractiveMode { autocompleteMaxVisible: this.settingsManager.getAutocompleteMaxVisible(), quietStartup: this.settingsManager.getQuietStartup(), clearOnShrink: this.settingsManager.getClearOnShrink(), + showTerminalProgress: this.settingsManager.getShowTerminalProgress(), }, { onAutoCompactChange: (enabled) => { @@ -3821,6 +3830,9 @@ export class InteractiveMode { this.settingsManager.setClearOnShrink(enabled); this.ui.setClearOnShrink(enabled); }, + onShowTerminalProgressChange: (enabled) => { + this.settingsManager.setShowTerminalProgress(enabled); + }, onCancel: () => { done(); this.ui.requestRender(); @@ -5329,7 +5341,9 @@ export class InteractiveMode { stop(): void { this.unregisterSignalHandlers(); - this.ui.terminal.setProgress(false); + if (this.settingsManager.getShowTerminalProgress()) { + this.ui.terminal.setProgress(false); + } if (this.loadingAnimation) { this.loadingAnimation.stop(); this.loadingAnimation = undefined;