# Managed by IssueSpec. Hand edits are welcome; keep the schema valid. id: 15 title: windows support for terminal windows state: closed author: name: k33g email: ph.charriere@gmail.com createdAt: 2026-08-31T04:40:00.000Z updatedAt: 2026-09-02T03:51:59.496Z labels: - priority::medium body: | Terminal windows (#7) ship for Linux and macOS only. On Windows, `F8` opens a message saying they are not supported yet and changes nothing else. Everything above the pseudo-terminal is already portable. `Parser`, `Screen`, `Encode` and `View` are pure Go with no platform assumptions, and the whole VT/ANSI emulator is tested without a process behind it. What is missing is one file. ## The platform surface `internal/terminal` isolates the whole of it in three build-tagged files, each implementing the same three functions: func openPTY() (master, slave *os.File, err error) func setWinsize(f *os.File, width, height int) error func childAttributes() *syscall.SysProcAttr | File | Platform | | --- | --- | | `pty_linux.go` | `TIOCSPTLCK`, `TIOCGPTN` -> `/dev/pts/N` | | `pty_darwin.go` | `TIOCPTYGRANT`, `TIOCPTYUNLK`, `TIOCPTYGNAME` | | `pty_other.go` | returns `ErrUnsupported` | Windows means adding `pty_windows.go` and narrowing `pty_other.go`'s build tag. No other file should need to change. ## Why it is not a fourth ioctl Windows has no `/dev/ptmx`. The equivalent is **ConPTY**, available from Windows 10 1809, and it does not fit the same shape: - `CreatePseudoConsole` takes two pipe handles and returns an `HPCON`, rather than handing back a master and a slave file. - The child is started with `CreateProcess` and an attribute list carrying `PROC_THREAD_ATTRIBUTE_PSEUDOCONSOLE_HANDLE` — not `os/exec`'s `SysProcAttr{Setsid, Setctty}`. `exec.Cmd` may not be usable directly. - Resizing is `ResizePseudoConsole(hpcon, COORD)`, not an ioctl. - There is no controlling terminal and no `SIGWINCH`: job control has no equivalent, and `Ctrl-C` reaches the child through the console rather than through a process group. So the contract above may need widening — most likely `Session` gaining a platform-provided `resize` and `close` rather than `setWinsize` alone. Keep the change inside `internal/terminal`; `internal/app` should not learn that Windows exists. ## Which shell `shellOrDefault` falls back to `/bin/sh`, which is meaningless there. Windows needs its own default — `%COMSPEC%`, or PowerShell — decided before the port, because it is the first thing a user notices. ## Notes - `golang.org/x/sys/windows` carries the ConPTY bindings, and is already in the module graph as `golang.org/x/sys`. No new dependency. - The emulator sends `TERM=xterm-256color`; ConPTY emits VT sequences, so the existing parser should be close to sufficient. Expect differences in how the alternate screen and the cursor-visibility modes are used. - This cannot be developed or tested in the current sandbox: it is Linux, and no Windows machine is reachable from it. Whoever takes it needs Windows. ## Checklist - [ ] decide the default shell on Windows (%COMSPEC% or PowerShell) - [ ] add `pty_windows.go` using `CreatePseudoConsole` / `ResizePseudoConsole` - [ ] narrow the build tag on `pty_other.go` - [ ] widen the platform contract if `exec.Cmd` cannot carry the HPCON - [ ] run the `internal/terminal` suite on Windows and unskip what passes - [ ] update `docs/*/reference/terminal.md`, which currently says Windows is unsupported tasks: [] comments: []