| 🛟 Updated. 28d5985 k33g 20h ago | 1 | # Handoff — 2026-09-17 — terminal windows and tools on Windows |
| 2 | |
| 3 | ## State |
| 4 | |
| 5 | 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. |
| 6 | |
| 7 | ## Next steps |
| 8 | |
| 9 | 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. |
| 10 | 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. |
| 11 | 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-<toolchain>` ▸ 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. |
| 12 | 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`). |
| 13 | |
| 14 | ## Watch out for |
| 15 | |
| 16 | - **`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`. |
| 17 | - **cmd.exe's command line is composed verbatim** (`"cmd.exe" /S /C "<command>"`), 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. |
| 18 | - **The job object is assigned after `Start`**; a child cmd.exe spawns in those first milliseconds escapes it. Accepted; documented in `tools/README.md`. |
| 19 | - **`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. |
| 20 | - **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. |