镜像站点 · 本页由第三方 GitHub 只读镜像提供,非 GitHub 官方站点,不接受任何登录或凭据输入。前往 github.com
Skip to content

[Spec 1658] windows-native-non-wsl-support - #1859

Open
amrmelsayed wants to merge 274 commits into
mainfrom
builder/spir-1658
Open

amrmelsayed wants to merge 274 commits into
mainfrom
builder/spir-1658

Conversation

@amrmelsayed

@amrmelsayed amrmelsayed commented Oct 23, 2026 •

Copy link
Copy Markdown
Collaborator

Summary

Native (non-WSL) Windows support at parity with macOS and Linux, built over 12 phases (1-11 plus 3b) in one PR, then restructured at the pr gate by Plan Amendment 2 (phases A2-1 to A2-5, owner-directed): platform-dependent behaviour now sits behind four capabilities instead of isWindows() forks in shared code. WSL 2 stays documented as a supported alternative.

Closes #1658

Changes

  • Platform capabilities (Amendment 2): lib/platform/{command-launch,host-paths,processes,shellper-transport}.ts, each with a .posix.ts and a .windows.ts implementation and one accessor that picks by the seam. The POSIX implementations are the pre-refactor macOS/Linux code moved verbatim (scripted comparison against origin/main per phase); the Windows ones are adapters over the Windows modules. Product isWindows() calls went from 103 to 56 (including the four accessors). Each remaining one is listed with its reason in the plan (A2.5, A2.10): mostly single-site one-offs (doctor sections, install checks, Tower start/stop, worktree links), plus eight IDE-server forks recorded individually; the IDE server lifecycle is the next capability candidate. Tests force the platform through forceHostPlatform / useHostPlatform.
  • Shellper transport over named pipes with a Windows-only per-session secret and reconnect identity (schema v19). The POSIX endpoint, handshake, no-secret path and reconnect gate are unchanged, pinned by goldens and contract tests.
  • Process census (PowerShell CIM, with creation times), killSessionTree session teardown, and a per-session Job Object for re-parented descendants. Orphan and husk sweeps work on Windows.
  • Tower lifecycle: tower stop over HTTP (POST /api/shutdown: keyed, local, not tunnel-borne). A Tower started inside a session launches through CIM so it survives that session.
  • Git Bash is the only plumbing shell (layout-verified resolver; System32 bash is rejected). One PATHEXT shim resolver (codev-sdk/node/executable) and an MSYS path translator. PowerShell for human shells.
  • Worktree links without Developer Mode (junction / hard link / copy). Handle-tolerant worktree removal.
  • Workspace keys canonical on Windows (M6: c:\ vs C:\ no longer splits a workspace); the dashboard's Open IDE link (M7) and workspace buttons (M8) handle Windows paths.
  • ConPTY render-gate capture recorder and replay harness. Codev IDE server (Tower-managed Codev IDE server from npm: embed sidebar vsix, discover codev-ide-server on PATH, pass --extensions-dir #1789) on Windows.
  • POSIX residue sweep (including the codev entrypoint and a drive-root hang). A preinstall guard refuses a Node version with no prebuilds. doctor gains Windows prerequisite checks.
  • windows.yml (dispatch only, never required): probes, targeted tests, and the unit / cli-e2e / post-release-e2e suites on Node 22 and 24.
  • Docs: DEPENDENCIES.md (both trees), README, the release protocol, arch.md Platform Layer (capabilities), lessons-learned, and the runnable-worktrees skill.

Testing (code head 5bc668fb1; later commits change only docs, comments and porch files)

Known gaps (recorded in the review)

  • Windows release blocker: bare user-tool spawns look up programs in the cwd before PATH; ruled a follow-up after this PR, and Windows support is not announced until it lands.
  • Render gate holds all mail to Codex agents: region-end pattern misses the 'GPT-6.1-Sol default' status line #1858: mail to codex agents holds on every platform; codex ConPTY validation awaits the owner's scope decision.
  • Pre-existing, recorded for follow-up: M10 (a launch during an in-flight stop is wiped), M11 (a stop after a Tower restart leaves reconnected shellpers alive), M12 (the afx CLI cannot target a non-default Tower port).

Open before the pr gate

Spec

codev/specs/1658-windows-native-non-wsl-support.md

Plan

codev/plans/1658-windows-native-non-wsl-support.md (Amendment 2)

Review

codev/reviews/1658-windows-native-non-wsl-support.md

…source builds from npm output; probe the published package
# Conflicts:
#	.github/workflows/windows.yml
#	scripts/windows-probe.mjs
…ARM64 leg, failing probe exit, guarded seam, missed launch sites
…ilure; probe published 3.3.3 (the 2026-09-09 release)
…session secret, WELCOME reconnect identity

Endpoint abstraction (POSIX socket path, log path and handshake unchanged;
Windows \\.\pipe\codev-shellper-<user>-<uuid>). Windows shellpers gate every
connection on a Tower-minted secret passed via env (never argv), stripped
from the PTY child, persisted in global.db (migration v19). Windows reconnect
verifies WELCOME sessionId/shellperPid instead of start time; an identity
refusal cleans the row without signaling the live pid (#1686 guard kept for
transient failures).
… not stdout EOF

On Windows the shellper's closeSync(1) leaves Tower's stdout pipe open, so
creation timed out waiting for 'end' (windows.yml run 39566654461).
@amrmelsayed

Copy link
Copy Markdown
Collaborator Author

Windows dispatch on head 1dfb17ccf79c438a6c197f5659374b17c54cd6a1, after merging main (v3.3.7, #1869 Open IDE, #1877 pid-reuse row deletion).

Purpose: run the Windows suites over the merge resolution (husk sweep on #1877's single PID_REUSE_TOLERANCE_MS, session-manager reconnect, tower routes/terminals with the IDE routes).

Run: https://github.com/cluesmith/codev/actions/runs/42547114468

…er and reused-pid block, #1869 token-rotation stubs

getProcessStartTime reads no start time on Windows, so #1686's live-row tests record any value there and #1877's reused-pid block skips on win32. #1869's token-rotation block drives #!/bin/sh stub servers and asserts POSIX modes, so it takes the file's posixStubsOnly marker like every other block.
@amrmelsayed

Copy link
Copy Markdown
Collaborator Author

Windows run 42547114468 (head 1dfb17ccf) failed on unit tests. Cause: tests that came in with the main merge.

Fixed at 7903facff49b31c5338a84b204ad81026679863e. Windows re-run: https://github.com/cluesmith/codev/actions/runs/42551557753

… URI path (Windows drive and UNC)

The IDE reads ?folder= as the path part of a URI. #1869's dashboard link passed the raw workspace path, which on Windows (C:\a\b) the IDE cannot resolve. ideFolderUriPath converts drive and UNC paths; POSIX paths pass through.
@amrmelsayed

Copy link
Copy Markdown
Collaborator Author

Windows dispatch on head 7f776ca999ca186e9d5f69c000e8864b99123e0f.

Purpose: finding M7. The dashboard's Open IDE link (#1869) sent a raw Windows path as ?folder=, which the IDE reads as a URI path and cannot resolve. ideFolderUriPath in tower.html converts drive and UNC paths (POSIX unchanged), with spec-1658-ide-folder-uri.test.ts evaluating the template's real function. This run covers the Windows suites on the new head.

Run: https://github.com/cluesmith/codev/actions/runs/42713989622

…the path from a data attribute

Start, Stop, Restart, + Create and copy path embedded the workspace path in a single-quoted inline JS string; escapeHtml leaves backslashes alone, so a Windows path's backslashes became JS escapes. Each element now carries data-workspace-path and its handler reads this.dataset.workspacePath, as openIde already did. The M7 test's fixture paths become neutral.
@amrmelsayed

Copy link
Copy Markdown
Collaborator Author

Windows dispatch on head 84f1f75a12ab697ad70142fe0095473ac1812f5c.

Purpose: finding M8. The dashboard's Start, Stop, Restart, + Create and copy-path buttons embedded the workspace path in a single-quoted inline JS string, so a Windows path's backslashes were read as JS escapes. Each now carries data-workspace-path and reads this.dataset.workspacePath. spec-1658-dashboard-workspace-path.test.ts renders the template's real renderInstance / renderRecentItem. This run covers the Windows suites on the new head.

Run: https://github.com/cluesmith/codev/actions/runs/42715696142

…owner-directed, architect-approved for scope)
…oved verbatim, Windows via Git Bash adapters)

Shared code asks commandLaunch() instead of branching on isWindows(): runStreaming, porch runCheck, forge concepts, the dev runner, shell sessions, builder launch scripts, bare-command spawns, which-probes, the terminal profile and the workspace shell. Site-specific POSIX forms are passed in, not unified. ptyCommand stays a leaf module (the shellper loads it). Adds the scoped useHostPlatform test helper and a contract test for both implementations.
…c exec and terminal profile; record as-built deviations (A2.10)
… verbatim, Windows canonicalization and separators behind it)

Workspace canonicalization and keys, home expansion, separators, prefix tests, builder-worktree splitting, the state/notifications/send/consult worktree matchers, architect shellper cwd identity and canvas-relay file canonicalization ask hostPaths(). workspace-path.ts and host-paths.ts keep their exported names as thin wrappers; the Windows native-answer cache and sameWindowsPath now live in the Windows implementation, which stays a leaf module. Contract test for both implementations.
@amrmelsayed

Copy link
Copy Markdown
Collaborator Author

Plan Amendment 2 (platform-seam refactor, owner-directed, approved 2026-11-09) Windows dispatches:

…ementations; one home for the default ops; reuse BuilderWorktreeRef; A2.10 and A2.9 entries
…verbatim, Windows modules behind adapters)

listProcessCensus, getProcessStartTime (incl. its darwin/linux switch), getProcessesOnPort(+Async), killSessionTree, waitForTreeExit, the husk sweep's console-host check and start-time lookup ask processes(). The Windows census, teardown and port query move unchanged into process-census-windows.ts, process-tree-windows.ts and port-windows.ts, which import nothing that reaches the accessor (no cycle); the original modules re-export their names. Contract test pins census failure ([] on POSIX, reject on Windows) and the synchronous POSIX group signal.
…-export; port.ts header states its graph; POSIX startTime covered; A2.10 entry (budgets and commandLineText recorded)
…rceHostPlatform/useHostPlatform (41 suites); arch.md Platform Layer describes the capabilities; A2.10 records A2-4 and the A2-3 ruling

No product code changed. Kept as written: platform.test.ts, the two vi.mock factories that pin linux at module-mock time, and six mid-test resets. host-platform-helpers.test.ts proves an override does not leak into the next test.
…blank lines removed; forceHostPlatform registers its reset first and documents the afterEach order and ctx.skip gap; platform.ts docstring points at the helpers; arch.md census wording; A2.10 counts corrected
…IX moved verbatim, Windows pipe/secret/identity behind it)

The endpoint, the per-session secret, the reconnect gate (start time and socket file on POSIX; the row's secret and session id on Windows), the ENOENT refusal, the spawn-info read, the attach scan and how a shellper's command line reads ask shellperTransport(). reconnectSession keeps its shared steps. Branches on the endpoint's form or on a secret's presence are data and stay. PID_REUSE_TOLERANCE_MS and the two command-line parsers move to leaf modules (re-exported), so the implementations import nothing that reaches back. Contract test for both implementations.
…tested, Windows refusal pinned, the real-socket test skips on a Windows host; spec-1280 third sighting recorded
…chitect ruling: three sightings, MSYS fork emulation under load); Flaky Tests entry
…ower), findings M10-M12, vitest worker-exit flake, PR CMAP round 4; porch rebuttals tracked
@amrmelsayed

Copy link
Copy Markdown
Collaborator Author

Architect integration review, round 3 (final head after Amendment 2)

Head reviewed: 369cb9809f4a7b750abb4b1dfd4092c552a72286 (docs-only over code head 5bc668fb1). POSIX: all 8 required checks green on both. Windows: run 42734572993 green on the code head (attempt 2; attempt 1 was the vitest pool exit recorded under Flaky Tests).

Method. High tier (392 files). Three-way consultation: Claude (worktree read; the consult-generated diff was 0 bytes again, third occurrence, tracked as a consult filing), Codex, Gemini (via agy). Plus my own per-phase reads of A2-1 through A2-5 against origin/main, each recorded at the time: moved POSIX bodies verified verbatim at the porch check runner, streaming runner, forge exec, terminal base env, workspace canonicalization, architect identity check, canvas relay fallback, process start time, kill tree, and the shellper reconnect gate.

Verdicts

Reviewer Verdict Substance
Claude COMMENT No new integration defect requiring a change in this lane. Capability seam is a genuine improvement; rounds 1 to 3 must-fixes confirmed closed; cycle claim checked mechanically.
Codex REQUEST_CHANGES Restates the four declared owner-held gate items only.
Gemini REQUEST_CHANGES Architecture clean, zero-cycle leaf design, SDK boundary intact, hot-tier cap respected; holds only on the declared gate items.

Architect position: no builder code change required. Merge remains gated on the four owner-held items already declared in the review's "Open at the PR gate": (1) Claude ConPTY fixtures (directory absent at the head, confirmed), (2) the owner's Windows manual pass on packs built from the final head (A2.8 table), (3) the #1858 Codex scope decision, (4) the README wording versus the cwd-first lookup follow-up.

Rulings on reviewer findings

  1. doctor.ts:668 which ${cmd} shell interpolation (Claude). The token comes from a repo-local forge config via loadForgeConfig at 1616 and commandExists(r.executable) at 1645. Pre-existing: the same line is on main today (doctor.ts:303). Preserved verbatim under Amendment 2 rule 1 (A2.9); the Windows path is now the safe one (PATHEXT resolver, no shell). Ruling on the parked A2.9 item: unify commandExists on the shell-free resolver and retire the caller-supplied POSIX probe, in the cwd-first follow-up, not this lane. Same threat class, same fix lane.
  2. Transitional shapes without a tracking number (Claude): posixDetached, posixCollapseWhitespace, posixProbe. Accepted. The issue number goes into each comment once the follow-up is filed; until then they reference A2.9 by name.
  3. PR body "each remaining one is a single-site one-off" (Claude): overstated. ide-version.ts and ide-server.ts carry 8 forks that A2-1 records individually; the IDE server lifecycle is the next capability candidate if IDE work grows. Builder: soften that sentence to match the A2.5/A2.10 record. Docs only.
  4. architect-session-holder.listProcessEntries keeps its own ps on POSIX (Claude), so creationTime and the pre-reap PID-reuse check are Windows-only. Pre-existing, documented on the field. Builder: one clause in arch.md Platform Layer so the asymmetry is not rediscovered. Docs only.
  5. shellper-transport.posix.ts value-imports processes() (Claude): verified not a cycle; deliberate. Builder: one header line stating it. Comment only.
  6. Two files named host-paths.ts (Claude): conscious facade choice, noted, no change.
  7. 36 bare user-tool spawn sites (Gemini, from the review's inventory): that is the cwd-first follow-up's scope, ruled a Windows release blocker on 2026-10-23. Not this lane.

Follow-ups the architect files after merge (owner's word pending)

cwd-first executable lookup hardening incl. unified shell-free commandExists (release blocker); M10 launch-during-stop wipe and M11 post-restart stop kills nothing (both reproduced on 3.3.7); M12 afx CLI has no Tower port option; macOS CI has no real-worktree spawn e2e; spec-1280 measurement suite skipped on Windows (MSYS fork under load); M9 legacy consolidation /.builders/ only; POSIX divergences umbrella (A2.9, incl. the four disagreeing builder-worktree matchers and the two temp-root checks); POSIX-CI static lint against new raw platform forks; consult 0-byte diff on large PRs.

Next

Builder applies items 3 to 5 (docs and one comment), reports the head, then repacks tarballs + vsix from that head with RECHECK.txt from the A2.8 table. Owner's Windows pass follows on that head; then the pr gate word.

…SIX ps (creation time and pre-reap PID-reuse check are Windows-only); shellper-transport.posix.ts states its processes() import is not a cycle
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.

windows: native (non-WSL) support — tracking map and go/no-go; WSL2 is the supported path today

1 participant