# Handoff — 2026-09-17 — terminal windows and tools on Windows ## State Done, tested where it can be, gate green, documented in the library and in the six editors, **not committed**, on `main`. `git status` in turbo-core lists the touched files; nothing is staged. The Windows path is compiled and vetted, never run. ## Next steps 1. **Commit and tag turbo-core `v0.9.0`** — minor, because `tools.Shell` (a constant) became `tools.Shell()` and `tools.ShellArgs()`. `01-release.tag.sh` runs `make check`; in this sandbox `release_test.go` fails on the `cp`-NUL problem (documented in `summary.md`), not on the code — run it on the Mac. 2. **Re-pin the six editors** (`go get codeberg.org/turbo-editors/turbo-core@v0.9.0 && go mod tidy && GOWORK=off make check`), then tag each. Their documentation already describes Windows terminal windows; until the re-pin the binaries do not have them. 3. **Run the five-step protocol on a Windows machine**, the first anyone will have: (a) `F8` — a cmd.exe prompt appears and `dir` lists the directory; (b) drag the window's corner — the prompt repaints at the new width (`mode con` reports it); (c) `Alt-` ▸ a tool with `output = "terminal"` (Run) — the program runs and, when it ends, `Ctrl-W` closes the window (the console-closing goroutine gave the reader its EOF); (d) a long command in a terminal window — `Ctrl-C` interrupts it; (e) a tool with `output = "popup"` — output arrives, and `Escape` while it runs stops the whole tree (the job object). Report what the window showed, in SGR if possible. 4. If (c) hangs — the window never says the command finished — the suspect is the order in `windowsChild.Close` / `closeConsoleWhenTheShellExits`: conhost may need the *input* pipe closed before `ClosePseudoConsole` returns. If the first screen is garbage, the suspect is conhost's start-up sequences reaching an emulator that has only ever read Unix shells; capture the raw bytes (`TURBO_ACP_TRACE` does not cover terminals — add a temporary `io.TeeReader` in `View.read`). ## Watch out for - **`unsafe.Pointer(handle)` is what `go vet` flags**, which is why `UpdateProcThreadAttribute` is called through a `LazyProc` with `uintptr` arguments. Do not "simplify" it back to x/sys's `Update`. - **cmd.exe's command line is composed verbatim** (`"cmd.exe" /S /C ""`), in two places that cannot share code without breaking the package layering: `terminal/windows.go` (`windowsCommandLine`) and `tools/shell.go` (`cmdExeCommandLine`). Change both or neither. - **The job object is assigned after `Start`**; a child cmd.exe spawns in those first milliseconds escapes it. Accepted; documented in `tools/README.md`. - **`GOOS=windows go test -c ./terminal` compiles the Windows tests but cannot run them here.** `windows_test.go` is untagged on purpose so its ten tests run on Linux. - **The sandbox truncated one `Write` to zero bytes** (`tools/shell_unix.go`); it was rewritten from Python with a byte comparison. Check file sizes after any write here.