diff --git a/packages/pi-coding-agent/src/modes/interactive/components/keybinding-hints.ts b/packages/pi-coding-agent/src/modes/interactive/components/keybinding-hints.ts index 6d546a712..42e8b4334 100644 --- a/packages/pi-coding-agent/src/modes/interactive/components/keybinding-hints.ts +++ b/packages/pi-coding-agent/src/modes/interactive/components/keybinding-hints.ts @@ -6,13 +6,25 @@ import { type EditorAction, getEditorKeybindings, type KeyId } from "@gsd/pi-tui import type { AppAction, KeybindingsManager } from "../../../core/keybindings.js"; import { theme } from "../theme/theme.js"; +const isMac = process.platform === "darwin"; + +/** + * Convert a key identifier to a platform-appropriate display string. + * On macOS, "alt+" is shown as "⌥" (Option key symbol). + */ +export function formatKeyForDisplay(key: string): string { + if (!isMac) return key; + return key.replace(/\balt\+/gi, "⌥"); +} + /** * Format keys array as display string (e.g., ["ctrl+c", "escape"] -> "ctrl+c/escape"). + * Applies platform-specific formatting (e.g., alt -> ⌥ on macOS). */ function formatKeys(keys: KeyId[]): string { if (keys.length === 0) return ""; - if (keys.length === 1) return keys[0]!; - return keys.join("/"); + if (keys.length === 1) return formatKeyForDisplay(keys[0]!); + return keys.map(formatKeyForDisplay).join("/"); } /** diff --git a/packages/pi-coding-agent/src/modes/interactive/components/scoped-models-selector.ts b/packages/pi-coding-agent/src/modes/interactive/components/scoped-models-selector.ts index 37d334cca..22f677540 100644 --- a/packages/pi-coding-agent/src/modes/interactive/components/scoped-models-selector.ts +++ b/packages/pi-coding-agent/src/modes/interactive/components/scoped-models-selector.ts @@ -169,7 +169,7 @@ export class ScopedModelsSelectorComponent extends Container implements Focusabl const enabledCount = this.enabledIds?.length ?? this.allIds.length; const allEnabled = this.enabledIds === null; const countText = allEnabled ? "all enabled" : `${enabledCount}/${this.allIds.length} enabled`; - const parts = ["Enter toggle", "^A all", "^X clear", "^P provider", "Alt+↑↓ reorder", "^S save", countText]; + const parts = ["Enter toggle", "^A all", "^X clear", "^P provider", `${process.platform === "darwin" ? "⌥↑↓" : "Alt+↑↓"} reorder`, "^S save", countText]; return this.isDirty ? theme.fg("dim", ` ${parts.join(" · ")} `) + theme.fg("warning", "(unsaved)") : theme.fg("dim", ` ${parts.join(" · ")}`); diff --git a/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts b/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts index dea8f940f..daacd9c52 100644 --- a/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts +++ b/packages/pi-coding-agent/src/modes/interactive/components/settings-selector.ts @@ -163,7 +163,7 @@ export class SettingsSelectorComponent extends Container { id: "follow-up-mode", label: "Follow-up mode", description: - "Alt+Enter queues follow-up messages until agent stops. 'one-at-a-time': deliver one, wait for response. 'all': deliver all at once.", + `${process.platform === "darwin" ? "⌥Enter" : "Alt+Enter"} queues follow-up messages until agent stops. 'one-at-a-time': deliver one, wait for response. 'all': deliver all at once.`, currentValue: config.followUpMode, values: ["one-at-a-time", "all"], }, diff --git a/packages/pi-coding-agent/src/modes/interactive/components/tree-selector.ts b/packages/pi-coding-agent/src/modes/interactive/components/tree-selector.ts index 86e36f362..a5072a98f 100644 --- a/packages/pi-coding-agent/src/modes/interactive/components/tree-selector.ts +++ b/packages/pi-coding-agent/src/modes/interactive/components/tree-selector.ts @@ -1127,7 +1127,7 @@ export class TreeSelectorComponent extends Container implements Focusable { this.addChild(new Text(theme.bold(" Session Tree"), 1, 0)); this.addChild( new TruncatedText( - theme.fg("muted", " ↑/↓: move. ←/→: page. ^←/^→ or Alt+←/Alt+→: fold/branch. Shift+L: label. ") + + theme.fg("muted", ` ↑/↓: move. ←/→: page. ^←/^→ or ${process.platform === "darwin" ? "⌥←/⌥→" : "Alt+←/Alt+→"}: fold/branch. Shift+L: label. `) + theme.fg("muted", "^D/^T/^U/^L/^A: filters (^O/⇧^O cycle)"), 0, 0, diff --git a/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts b/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts index e8ffdb9a6..bbbe910d9 100644 --- a/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts +++ b/packages/pi-coding-agent/src/modes/interactive/interactive-mode.ts @@ -79,7 +79,7 @@ import { ExtensionEditorComponent } from "./components/extension-editor.js"; import { ExtensionInputComponent } from "./components/extension-input.js"; import { ExtensionSelectorComponent } from "./components/extension-selector.js"; import { FooterComponent } from "./components/footer.js"; -import { appKey, appKeyHint, editorKey, keyHint, rawKeyHint } from "./components/keybinding-hints.js"; +import { appKey, appKeyHint, editorKey, formatKeyForDisplay, keyHint, rawKeyHint } from "./components/keybinding-hints.js"; import { LoginDialogComponent } from "./components/login-dialog.js"; import { ModelSelectorComponent } from "./components/model-selector.js"; import { OAuthSelectorComponent } from "./components/oauth-selector.js"; @@ -4288,7 +4288,7 @@ export class InteractiveMode { `; for (const [key, shortcut] of shortcuts) { const description = shortcut.description ?? shortcut.extensionPath; - const keyDisplay = key.replace(/\b\w/g, (c) => c.toUpperCase()); + const keyDisplay = formatKeyForDisplay(key).replace(/\b\w/g, (c) => c.toUpperCase()); hotkeys += `| \`${keyDisplay}\` | ${description} |\n`; } } diff --git a/src/resources/extensions/gsd/auto.ts b/src/resources/extensions/gsd/auto.ts index 05a3d3b6e..55fcb2c47 100644 --- a/src/resources/extensions/gsd/auto.ts +++ b/src/resources/extensions/gsd/auto.ts @@ -911,7 +911,7 @@ function updateProgressWidget( const hintParts: string[] = []; hintParts.push("esc pause"); - hintParts.push("Ctrl+Alt+G dashboard"); + hintParts.push(process.platform === "darwin" ? "⌃⌥G dashboard" : "Ctrl+Alt+G dashboard"); lines.push(...ui.hints(hintParts)); lines.push(...ui.bar()); diff --git a/src/resources/extensions/gsd/dashboard-overlay.ts b/src/resources/extensions/gsd/dashboard-overlay.ts index 427b6f120..f51c7aa2c 100644 --- a/src/resources/extensions/gsd/dashboard-overlay.ts +++ b/src/resources/extensions/gsd/dashboard-overlay.ts @@ -3,7 +3,7 @@ * * Full-screen overlay showing auto-mode progress: milestone/slice/task * breakdown, current unit, completed units, timing, and activity log. - * Toggled with Ctrl+Alt+G or opened from /gsd status. + * Toggled with Ctrl+Alt+G (⌃⌥G on macOS) or opened from /gsd status. */ import type { Theme } from "@gsd/pi-coding-agent";