diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 5962c092..0a1674be 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -13,6 +13,14 @@ - Built-in tool details types exported: `BashToolDetails`, `ReadToolDetails`, `GrepToolDetails`, `FindToolDetails`, `LsToolDetails`, `TruncationResult` - Type guards exported for narrowing: `isBashToolResult`, `isReadToolResult`, `isEditToolResult`, `isWriteToolResult`, `isGrepToolResult`, `isFindToolResult`, `isLsToolResult` +### Added + +- **Kitty keyboard protocol support**: Shift+Enter, Alt+Enter, Shift+Tab, Ctrl+D, and all Ctrl+key combinations now work in Ghostty, Kitty, WezTerm, and other modern terminals. ([#225](https://github.com/badlogic/pi-mono/pull/225) by [@kim0](https://github.com/kim0)) + +- **`/hotkeys` command**: Shows all keyboard shortcuts in a formatted table. + +- **Markdown table borders**: Tables now render with proper top and bottom borders. + ### Changed - **Skills standard compliance**: Skills now adhere to the [Agent Skills standard](https://agentskills.io/specification). Validates name (must match parent directory, lowercase, max 64 chars), description (required, max 1024 chars), and frontmatter fields. Warns on violations but remains lenient. Prompt format changed to XML structure. Removed `{baseDir}` placeholder in favor of relative paths. ([#231](https://github.com/badlogic/pi-mono/issues/231)) diff --git a/packages/coding-agent/README.md b/packages/coding-agent/README.md index 6358cd4d..8024a29c 100644 --- a/packages/coding-agent/README.md +++ b/packages/coding-agent/README.md @@ -167,6 +167,7 @@ The agent reads, writes, and edits files, and executes commands via bash. | `/queue` | Set message queue mode: one-at-a-time (default) or all-at-once | | `/export [file]` | Export session to self-contained HTML | | `/session` | Show session info: path, message counts, token usage, cost | +| `/hotkeys` | Show all keyboard shortcuts | | `/changelog` | Display full version history | | `/branch` | Create new conversation branch from a previous message | | `/resume` | Switch to a different session (interactive selector) | @@ -199,8 +200,8 @@ The agent reads, writes, and edits files, and executes commands via bash. |-----|--------| | Arrow keys | Move cursor / browse history (Up when empty) | | Option+Left/Right | Move by word | -| Ctrl+A / Home | Start of line | -| Ctrl+E / End | End of line | +| Ctrl+A / Home / Cmd+Left | Start of line | +| Ctrl+E / End / Cmd+Right | End of line | **Editing:** @@ -219,6 +220,7 @@ The agent reads, writes, and edits files, and executes commands via bash. | Tab | Path completion / accept autocomplete | | Escape | Cancel autocomplete / abort streaming | | Ctrl+C | Clear editor (first) / exit (second) | +| Ctrl+D | Exit (when editor is empty) | | Shift+Tab | Cycle thinking level | | Ctrl+P | Cycle models (scoped by `--models`) | | Ctrl+O | Toggle tool output expansion | diff --git a/packages/coding-agent/src/modes/interactive/interactive-mode.ts b/packages/coding-agent/src/modes/interactive/interactive-mode.ts index 45a3515c..f0d53ece 100644 --- a/packages/coding-agent/src/modes/interactive/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive/interactive-mode.ts @@ -158,6 +158,7 @@ export class InteractiveMode { { name: "copy", description: "Copy last agent message to clipboard" }, { name: "session", description: "Show session info and stats" }, { name: "changelog", description: "Show changelog entries" }, + { name: "hotkeys", description: "Show all keyboard shortcuts" }, { name: "branch", description: "Create a new branch from a previous message" }, { name: "login", description: "Login with OAuth provider" }, { name: "logout", description: "Logout from OAuth provider" }, @@ -207,6 +208,9 @@ export class InteractiveMode { theme.fg("dim", "ctrl+c twice") + theme.fg("muted", " to exit") + "\n" + + theme.fg("dim", "ctrl+d") + + theme.fg("muted", " to exit (empty)") + + "\n" + theme.fg("dim", "ctrl+k") + theme.fg("muted", " to delete line") + "\n" + @@ -619,6 +623,11 @@ export class InteractiveMode { this.editor.setText(""); return; } + if (text === "/hotkeys") { + this.handleHotkeysCommand(); + this.editor.setText(""); + return; + } if (text === "/branch") { this.showUserMessageSelector(); this.editor.setText(""); @@ -1636,6 +1645,48 @@ export class InteractiveMode { this.ui.requestRender(); } + private handleHotkeysCommand(): void { + const hotkeys = ` +**Navigation** +| Key | Action | +|-----|--------| +| \`Arrow keys\` | Move cursor / browse history (Up when empty) | +| \`Option+Left/Right\` | Move by word | +| \`Ctrl+A\` / \`Home\` / \`Cmd+Left\` | Start of line | +| \`Ctrl+E\` / \`End\` / \`Cmd+Right\` | End of line | + +**Editing** +| Key | Action | +|-----|--------| +| \`Enter\` | Send message | +| \`Shift+Enter\` / \`Alt+Enter\` | New line | +| \`Ctrl+W\` / \`Option+Backspace\` | Delete word backwards | +| \`Ctrl+U\` | Delete to start of line | +| \`Ctrl+K\` | Delete to end of line | + +**Other** +| Key | Action | +|-----|--------| +| \`Tab\` | Path completion / accept autocomplete | +| \`Escape\` | Cancel autocomplete / abort streaming | +| \`Ctrl+C\` | Clear editor (first) / exit (second) | +| \`Ctrl+D\` | Exit (when editor is empty) | +| \`Shift+Tab\` | Cycle thinking level | +| \`Ctrl+P\` | Cycle models | +| \`Ctrl+O\` | Toggle tool output expansion | +| \`Ctrl+T\` | Toggle thinking block visibility | +| \`/\` | Slash commands | +| \`!\` | Run bash command | +`; + this.chatContainer.addChild(new Spacer(1)); + this.chatContainer.addChild(new DynamicBorder()); + this.chatContainer.addChild(new Text(theme.bold(theme.fg("accent", "Keyboard Shortcuts")), 1, 0)); + this.chatContainer.addChild(new Spacer(1)); + this.chatContainer.addChild(new Markdown(hotkeys.trim(), 1, 1, getMarkdownTheme())); + this.chatContainer.addChild(new DynamicBorder()); + this.ui.requestRender(); + } + private async handleClearCommand(): Promise { // Stop loading animation if (this.loadingAnimation) { diff --git a/packages/tui/src/components/markdown.ts b/packages/tui/src/components/markdown.ts index d6e8671f..6e0cdc56 100644 --- a/packages/tui/src/components/markdown.ts +++ b/packages/tui/src/components/markdown.ts @@ -585,6 +585,10 @@ export class Markdown implements Component { } } + // Render top border + const topBorderCells = columnWidths.map((w) => "─".repeat(w)); + lines.push("┌─" + topBorderCells.join("─┬─") + "─┐"); + // Render header with wrapping const headerCellLines: string[][] = token.header.map((cell, i) => { const text = this.renderInlineTokens(cell.tokens || []); @@ -622,6 +626,10 @@ export class Markdown implements Component { } } + // Render bottom border + const bottomBorderCells = columnWidths.map((w) => "─".repeat(w)); + lines.push("└─" + bottomBorderCells.join("─┴─") + "─┘"); + lines.push(""); // Add spacing after table return lines; }