Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ dotnet run --project src/CodeShellManager/CodeShellManager.csproj

**Requirements:** .NET 10 SDK, Windows 10/11 (uses ConPTY + WebView2)

### Visual Studio: Hot Reload disabled

`Properties/launchSettings.json` ships with `"hotReloadEnabled": false`, and the csproj sets `<MetadataUpdaterSupport>false</MetadataUpdaterSupport>` in Debug. Both are workarounds for a `System.ExecutionEngineException` that crashes the app on F5 under .NET 10.0.8 + VS 18 — `Microsoft.Extensions.DotNetDeltaApplier.dll` faults during its own startup before any managed code runs. Ctrl+F5 (Start Without Debugging) is unaffected either way. **Remove both when the runtime bug is fixed upstream.**

### Command-line flags

| Flag | Effect |
Expand All @@ -36,7 +40,7 @@ PTY (ConPTY) → PseudoTerminal → TerminalBridge → WebView2 (xterm.js)
AlertDetector → SessionViewModel.RaiseAlert()
```

- **PseudoTerminal** (`Terminal/PseudoTerminal.cs`): Windows ConPTY wrapper, P/Invoke only
- **PseudoTerminal** (`Terminal/PseudoTerminal.cs`): Windows ConPTY wrapper, P/Invoke only. Implements `IPseudoTerminal` (`Terminal/IPseudoTerminal.cs`) — the minimum surface needed by `RunInstance` (`DataReceived`, `Exited`, `ExitCode`, `Start`). Tests inject a fake via the `internal RunInstance(item, Func<IPseudoTerminal>)` constructor.
- **TerminalBridge** (`Terminal/TerminalBridge.cs`): Routes bytes between PTY and xterm.js via WebView2 messages. Surfaces accelerator keys (Ctrl-combos, F-keys, Esc) via `_webView.PreviewKeyDown` — the newer WPF WebView2 wrapper forwards accelerators through standard key events rather than a separate `CoreWebView2Controller.AcceleratorKeyPressed`. Bridge re-raises them as `AcceleratorKeyPressed` so `MainWindow.OnBridgeAcceleratorKey` can run global shortcuts even when the terminal has focus.
- **OutputIndexer** (`Terminal/OutputIndexer.cs`): Async channels → SQLite, strips ANSI
- **AlertDetector** (`Services/AlertDetector.cs`): Regex on raw PTY output, fires after 1.5s idle
Expand Down Expand Up @@ -249,6 +253,16 @@ Each session gets a collapsible 📝 notepad panel between the terminal toolbar

`AlertDetector.NotifyUserInteracted()` clears alert state on user input.

## Session Spinners

Two overlays cover launch and shutdown so the user sees progress instead of a blank pane.

**Launch overlay (per session)** lives in `Assets/terminal.html` and `Assets/terminal-transparent.html` as a CSS-animated rotating SVG arc with a phase label. Visible by default; `TerminalBridge` posts `setBootState` after `NavigationCompleted` (label = `Starting {cmd}…` for local, `Connecting to {host}…` for SSH; accent = session color) and `bootDone` on the first PTY byte (via `OnPtyData → PostBootDoneIfNeeded`, race-safe via `Interlocked.CompareExchange`). An 8-second fallback timer scheduled in `NavCompleted` also calls `PostBootDoneIfNeeded` so silent sessions and slow SSH handshakes don't lock the user out of the pane.

**Shutdown overlay (app-level)** is a `Grid x:Name="ShutdownOverlay"` on `MainWindow.xaml` with a `Storyboard`-rotated `Path`. `OnClosing` shows it then `await Dispatcher.InvokeAsync(() => {}, DispatcherPriority.Background)` to force a render pass before the existing synchronous session-disposal loop blocks the UI thread.

Full design: `docs/superpowers/specs/2026-05-16-session-spinners-design.md`.

## Search

- All PTY output is stripped of ANSI and indexed to SQLite FTS5 by `OutputIndexer`
Expand Down Expand Up @@ -295,6 +309,10 @@ Unit tests cover model logic (`ShellSession`, etc.) and run headless. UI tests r

`ShellSession.BuildSshArgs()` is `internal` — accessible from tests via `[assembly: InternalsVisibleTo("CodeShellManager.Tests")]` in `AssemblyInfo.cs`.

**`IPseudoTerminal` testability seam.** `PseudoTerminal` implements `IPseudoTerminal` (in `Terminal/IPseudoTerminal.cs`), and `RunInstance` / `SessionRunner` both expose an `internal` constructor that accepts a `Func<IPseudoTerminal>` factory. Production code uses the parameterless public ctors which default to `() => new PseudoTerminal()`; tests pass a hand-rolled `FakePseudoTerminal` to exercise the run-command lifecycle (Run, Stop, Dismiss, kill-and-restart, 1MB output-buffer cap) without spawning a real ConPTY child. Keep the interface surface minimal — only what `RunInstance` actually calls (`DataReceived`, `Exited`, `ExitCode`, `Start`).

**SearchService tests** open a fresh file-backed SQLite at `Path.GetTempPath()` per test for isolation. The test class is `IDisposable` and clears the connection pool (`SqliteConnection.ClearAllPools()`) before deleting the file on Windows. Seed `session_history` rows with explicit timestamps rather than `Task.Delay` — Windows' 15.6ms timer granularity makes wall-clock-based ordering flaky on CI.

## Releases

CI/CD is in `.github/workflows/build.yml`. Releases are triggered by pushing a `v*.*.*` tag:
Expand Down
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,19 @@ Built with WPF + [xterm.js](https://xtermjs.org/) + Windows ConPTY for full pseu
## Features

- **Multi-terminal grid** — run up to 18 sessions simultaneously in configurable layouts (1, 2, 3, 4, 6 columns; 2×2, 6×2, 6×3 grids); the active pane is highlighted with a 2px accent ring so it's easy to spot
- **Sidebar groups** — organise sessions into named groups with their own color and filter strip; bulk actions (sleep / close / re-group) operate on the active group
- **Sleep & wake** — 💤 button parks a session: PTY torn down, but the session (and its notes) stays in the sidebar so you can wake it later from where you left off. Great when you have many long-running projects but only need a few live at once.
- **Recently closed** — Ctrl+Shift+T reopens the last-closed session (browser convention); the New Session dialog also lists the last 10 closed sessions for one-click revival
- **Per-session run commands** — define a list of labelled commands per session (Test, Build, Watch…); ▶ runs the default, F5 / Shift+F5 run/stop it, output streams into a side drawer without touching the parent terminal. Optional post-run URL opens in your browser on exit code 0.
- **Full-text search** — all terminal output indexed to SQLite FTS5; instant search across every session, ever
- **Per-project notepad** — collapsible 📝 notes panel on every terminal, auto-saved and searchable
- **Alert detection** — detects when Claude is waiting for input or tool approval; green/orange dot indicators
- **Git status** — shows branch and dirty state in the sidebar per session
- **Session rename** — double-click any session name or click ✏ to rename inline
- **Auto-resume** — automatically resumes the last Claude Code session when restoring on startup (`--resume <id>`); toggleable in Settings
- **SSH remote sessions** — connect to remote hosts using your existing SSH config; sessions persist across restarts
- **Windows Terminal profile import** — opt-in import of profiles from Windows Terminal's `settings.json`; pick a profile in the New Session dialog to stamp its font, color scheme, cursor and padding onto the new terminal
- **Launch & shutdown spinners** — every starting session shows a brief overlay (`Starting <cmd>…` or `Connecting to <host>…`) until the first PTY byte arrives; closing the window shows a "Shutting down…" overlay during session disposal
- **Session history** — clicking a search result from a closed session offers to relaunch it
- **Configurable launch commands** — customise the commands available in the New Session dialog
- **Claude badge** — sessions running `claude` commands get a visual indicator
Expand Down Expand Up @@ -86,9 +91,13 @@ dotnet run --project src/CodeShellManager/CodeShellManager.csproj
| Key | Action |
|-----|--------|
| `Ctrl+T` | New session |
| `Ctrl+Shift+T` | Reopen the most-recently-closed session |
| `Ctrl+Alt+T` | Duplicate the active session |
| `Ctrl+W` | Close active session |
| `Ctrl+F` | Toggle search |
| `Ctrl+Tab` | Cycle sessions |
| `Ctrl+Tab` / `Ctrl+Shift+Tab` | Cycle sessions |
| `F5` | Run the active session's default run-command |
| `Shift+F5` | Stop the active session's running run-command |
| `Escape` (in search) | Close search panel |

## Layout Options
Expand Down
Loading
Loading