Skip to content

feat: Windows support (wt.exe backend, build tags, CI + release)#62

Open
samarthya-gupta1 wants to merge 3 commits into
mainfrom
flow-windows-build
Open

feat: Windows support (wt.exe backend, build tags, CI + release)#62
samarthya-gupta1 wants to merge 3 commits into
mainfrom
flow-windows-build

Conversation

@samarthya-gupta1
Copy link
Copy Markdown

Summary

Native Windows support across binary, spawn layer, release pipeline, and install docs.

  • Build tags on macOS-only backends (iterm, terminal, warp, ghostty) and the app tests that depend on iterm stubs. Cross-platform DB-seed helpers moved to testhelpers_test.go so non-spawn tests still compile everywhere.
  • Spawner split into spawner_darwin.go / spawner_windows.go / spawner_unix.go sharing the Backend enum + POSIX ShellQuote. Windows defaults to BackendWT; linux defaults to zellij/kitty.
  • New internal/wt package — Windows Terminal backend via wt.exe -w 0 nt -d <cwd> --title <title> powershell.exe -NoExit -Command <ps>. Env injected as $env:NAME='value';. FocusSession returns (false, nil) for v1 — wt.exe exposes no tab-enumeration API.
  • Claude harness runPS splitclaude_ps_unix.go keeps ps -axo; new claude_ps_windows.go uses powershell.exe -NoProfile -NonInteractive -Command "Get-CimInstance Win32_Process | ... | Select -ExpandProperty CommandLine".
  • Release workflow — matrix now also builds flow-windows-amd64.exe on ubuntu-latest (CGO disabled; pure Go via modernc.org/sqlite); included in SHA256SUMS.
  • CItest job runs on ubuntu/macos/windows-latest; build job cross-compiles all three.
  • README — second <details> block for Windows install (PowerShell Invoke-WebRequest, %LOCALAPPDATA%\Programs\flow, no xattr; prereqs: Windows Terminal + Claude Code on PATH). "Where flow runs" section updated.

Known v1 limitations on Windows:

  • No tab-focus on a live session (falls through to "switch manually" message).
  • flow do --with inject text containing single quotes may break PowerShell parsing — POSIX '\'' escape doesn't translate to PowerShell ''. Shell-safe bootstrap prompt path is unaffected.
  • make install/make uninstall remain bash-only; Windows users use the PowerShell install snippet in the README.

Closes the "Add Windows support to the flow CLI" task tracked locally in flow.

Test plan

  • go build ./... succeeds on darwin, linux, windows (cross-compiled locally)
  • go vet ./... clean on all three OSes
  • go test ./... passes on darwin (12 packages green)
  • Test binaries cross-compile under GOOS=windows / GOOS=linux
  • CI: windows-latest go test ./... passes (this PR triggers it for the first time)
  • CI: ubuntu-latest go test ./... passes
  • CI: macos-latest go test ./... passes
  • CI: Windows + Linux + macOS cross-builds succeed
  • Smoke test on a Windows 11 ARM VM (UTM): flow init, flow add task, flow do <slug> opens a Windows Terminal tab running Claude Code
  • Release dry-run: tag triggers release.yml and produces flow-windows-amd64.exe + checksums

🤖 Generated with Claude Code

samarthya-gupta1 and others added 3 commits May 27, 2026 11:48
Adds native Windows support across the binary, spawn layer, release
pipeline, and install docs:

- Build-tag iterm/terminal/warp/ghostty (and their tests) //go:build
  darwin so the tree compiles cleanly under GOOS=windows.
- Split spawner into spawner_darwin / spawner_windows / spawner_unix
  variants sharing the Backend enum + POSIX ShellQuote. Windows
  defaults to BackendWT.
- New internal/wt package: Windows Terminal spawn backend via
  `wt.exe -w 0 nt -d <cwd> --title <t> powershell.exe -NoExit
  -Command <ps>` with env-prefix injection (`$env:NAME='value';`),
  newline flattening, and PowerShell single-quote escaping.
  FocusSession returns (false, nil) for v1 — wt.exe exposes no
  programmatic tab-enumeration API.
- Split claude harness runPS per-OS: POSIX `ps -axo pid,command` on
  unix; PowerShell `Get-CimInstance Win32_Process | …
  Select-Object -ExpandProperty CommandLine` on Windows.
- Release workflow matrix now builds flow-windows-amd64.exe on
  ubuntu-latest (CGO disabled; pure Go via modernc.org/sqlite).
- CI matrix runs `go test ./...` on ubuntu/macos/windows-latest and
  `go build ./...` for all three targets.
- README: second <details> block for Windows install (PowerShell
  Invoke-WebRequest, %LOCALAPPDATA%\Programs\flow, no xattr). "Where
  flow runs" updated.

Shared DB-seed helpers (seedTask, seedTaskAtCwd) moved from
do_test.go to testhelpers_test.go so non-spawn tests can use them
cross-platform. App tests that drive the spawn path through iterm
stubs are tagged darwin.

Known v1 Windows limitations: no tab-focus on live sessions; --with
inject text containing single quotes may break PowerShell parsing
(the shell-safe bootstrap prompt works fine); make install/uninstall
remains bash-only — Windows users use the PowerShell snippet in the
README.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`AUX` is a reserved DOS device name on Windows, so any file named
`aux.<ext>` fails to check out — `git checkout` returns "error:
invalid path 'internal/app/aux.go'" with rc=128. The Windows CI job
added in the preceding commit hit this before it could even reach
`go build`, and matrix fail-fast cascaded the cancellation to the
ubuntu and macos test jobs.

Rename internal/app/aux.go → auxfiles.go (and aux_test.go →
auxfiles_test.go) via `git mv` so history is preserved. The
exported / package-internal function names (`enumerateAuxFiles`)
are unchanged; only the on-disk file name needed to change.

Also set fail-fast: false on the test and build matrices so future
single-job failures yield full signal on every push instead of
cancelling siblings.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
`os.UserHomeDir()` on Windows reads %USERPROFILE% (with
%HOMEDRIVE%+%HOMEPATH% as fallback), not $HOME. Tests that
overrode only HOME silently leaked writes into the real
runner's profile — `C:\Users\runneradmin\.claude\` — and
cascaded into "skill already exists" failures across the
skill suite.

Introduce a testHome(t, dir) helper in testhelpers_test.go
that sets both HOME and USERPROFILE via t.Setenv (auto-
cleanup). Route initTempFlowRoot and withTempHome through it.

Also fix TestCmdEditPlaybook: EDITOR=/usr/bin/true doesn't
exist on Windows. Add a noopEditor() helper that returns
"true" on Unix and "cmd /c rem" on Windows — both are
no-ops that exit 0 regardless of file-path argument.

These were the only Windows-specific test issues — the 18
failures in PR #62 CI all funnel into one of these two
root causes (HOME pollution + missing editor binary).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant