Repository navigation
ShadowCode 2.3.0: Windows - #10
Draft
ShadowfetchStudio wants to merge 56 commits into
Draft
ShadowfetchStudio wants to merge 56 commits into
ShadowfetchStudio wants to merge 56 commits into
Conversation
windows.yml compiles the whole workspace on GitHub's Windows runner and reports every error at once (--keep-going, full log kept as an artifact). docs/WINDOWS_PORT.md lists the phases and the Windows design for each Unix-only area (shell, sandbox, job objects, ConPTY, named pipes, Credential Manager, %APPDATA%, packaging). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Important Draft PR not reviewedDraft PRs are not automatically reviewed by default.
To automatically review draft PRs, update your CodeRabbit configuration: reviews:
auto_review:
drafts: true
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The first Windows build (GitHub runner) compiled every C/C++ dependency and stopped at 87 errors in the engine and a missing app icon: - Doctor, the project map and change history no longer need Unix: the profile privacy check is per platform and PATH lookups find .exe/.cmd. - Windows stand-ins where the Unix version is not ported yet, each saying so: the vendor CLI runner's types, the drawer's terminals (need ConPTY), managed worktree removal (kept, never removed less carefully). - Agent shell commands on Windows run without a sandbox, with the existing warning; Require sandbox and the network allow-list refuse them. They use Git for Windows' bash (never System32's WSL bash), else PowerShell. - The Flatpak relay socket and held-directory paths are Unix-only; voice input uses cpal on Windows (WASAPI). - Tests that need symlinks or #! scripts are Unix-only; script helpers skip the execute bit on Windows. - tauri.windows.conf.json and assets/icons/shadow-agent.ico (16-256 px) for the Windows resource file. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…and remote The engine's control channel (control/transport.rs) keeps its Unix socket and peer-user checks; on Windows it is a named pipe that refuses remote clients, whose only access rule is this user's SID, and whose server a client checks runs as this user before sending anything. The CLI, MCP, ACP, plugins, lifecycle and remote modules now build on Windows: the approval prompt reads stdin on a detached thread, an MCP server's process tree is ended with taskkill, and the AppImage parent check is Unix-only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… modes are Unix-only The control-socket suites and the fake vendor CLI suites (shell scripts behind a Unix-only runner) are gated per file, as other suites already are; single tests that make a FIFO, a symlink or a file mode are gated per test. Fake gh/glab scripts are only marked executable on Unix. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ns; unit tests run - paths::sync_directory: Windows cannot open a folder as a file, so the fsync after a rename (atomic_write, workspace edits, worktree records) is skipped there instead of failing every save. - Workspace file opens never follow a final symlink on Windows either. - Linking exported rules fails clearly on Windows instead of reporting links it never made. - The Windows job treats warnings as errors and now runs the engine's unit tests (phase 2, not yet required), listing the failures. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…hs, memory figures Found by the engine's unit tests on Windows (554 of 605 passed): - Remote access tokens and the local model server's key read random bytes from /dev/urandom; they now use getrandom (already in the lockfile). - canonicalize gave `\\?\C:\...` verbatim paths, which Git and people do not expect; paths::Canonical (dunce) returns the plain form when it names the same file, and is the standard call on Unix. - Project-relative paths shown to the agent and in approvals are joined with `/` (paths::slash). Approval checks compare them as text: with `\`, deleting .git\objects was not recognized as unrecoverable. - The model picker reads installed and free memory on Windows (GlobalMemoryStatusEx). - ACP tool locations are the system's own absolute form. - .gitattributes keeps LF in every checkout: bundled templates are hashed and sources are read as written. - Tests built on AppImage, Flatpak, bubblewrap or Unix-path fixtures are gated to their systems. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…fixtures gated - The worktree advisory lock opens its folder with backup semantics (and without following a link): Windows refuses a plain open of a folder, which failed every worktree task with "Access is denied". - Model and runtime file identity on Windows adds the volume serial, file index and change time, so a same-size replacement with its time restored is still noticed, as inode and ctime do on Unix. - Hook fingerprints: the "made runnable" step is Unix-only (no mode bit). - Tests whose fixtures are shell scripts or Unix paths are gated to Unix. - The Windows unit-test step prints error backtraces. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…est-helper errors Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…kspace listings - Windows flushes a file (FlushFileBuffers) and changes its time only through a handle that may write; paths::sync_file and Compare's index copy open one. These failed backups and every worktree task's snapshot with "Access is denied". - Workspace list, read, search and find report project paths with `/`, as do profile-relative rule paths, so the file tree, the agent's tools, mentions and skill paths match on every system. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
What a shell command or a worktree setup script starts joins its job (process::Job, kill-on-close). Cancelling, a timeout or dropping the owner ends the whole tree, as killing the process group does on Unix; closing ShadowCode closes the job too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ine endings in tests - A profile skill's supporting files are linked beside the staged SKILL.md on Unix; Windows needs extra rights for symlinks, so regular files up to 4 MB are copied instead (folders are not). - The Windows job turns off core.autocrlf for the tests, whose repositories expect the bytes they committed. - Test fixtures change file times through writable handles, split shown paths on either separator, and retry a delete a virus scanner may hold. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A second job in the Windows workflow builds the NSIS installer (per-user, no administrator rights; WebView2 is fetched by its bootstrapper when missing), checks that the built app reports its version, and keeps the installer as a 14-day artifact. It is not attached to any release. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ound failure Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The cleanup that quarantines a checkout before Git removes it now runs on Windows instead of refusing: - Identities are the volume serial and file index, read from open handles (cap-std stats by opening; cap_fs_ext exposes dev/ino/nlink), so a swapped folder or file is still refused. - Folders are opened with backup semantics and never through a link or junction; files are opened without following links. - The exclusive rename is SetFileInformationByHandle(FileRenameInfo) with the held destination folder as root and ReplaceIfExists false, the counterpart of renameat2(RENAME_NOREPLACE). - Git writes its own paths with `/` on Windows; the expected pointers in cleanup and repair are rendered that way. - No modes or folder flushes on Windows; the Unix scenarios stay Unix-only. Linux and macOS behave as before (their unit and worktree tests pass). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SetFileInformationByHandle refuses a relative root (error 87); the destination is the held folder's final path plus the plain name, and the source is still opened through its held folder. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…istings From the first Windows run of the integration tests: - Workspace::relative_text names a project path with `/`. Checkpoints, reviews, change tracking, the editor feed and Git requests use it; with `\`, an edit inside "Only change these" was treated as outside it, and "Ignore this file" would have written `src\foo` into .gitignore, where `\` is an escape. in_scope also accepts either separator on Windows. - Folder listings report their path and parent with `/`. - Test fixtures put `/` paths into Git config and JSON, which read `\` as an escape. - Suites built on parts not ported yet are Unix-only, each with its reason: local models (fake llama-server), terminals, the vendor runner, fake language servers, and fake gh/glab; so are single tests of the vendor runner and the SQLite inspector. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… gates - Fixture paths go into SQL/JSON, Git config and shell commands with `/`; a check's output may end in CRLF on Windows (Python's print). - Timings compare within the precision SQLite keeps for JSON reals (15 digits), a last-bit difference that can occur on any system. - A refused local connection takes seconds on Windows; two tests that wait on one get 30 seconds. - A literal search for `\` is skipped on Windows, whose project paths contain it. - Unix-only, each for its input: file modes, a SIGTERM graceful stop, MSYS process IDs from `$!`, `bash` that is WSL's, fake shell-script `gh`, and file names Windows forbids. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…e Unix-only Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…eplace it Windows counts Instant from boot, so a just-started runner cannot hold an instant ten minutes old; and an in-place rewrite of the same size within one tick of its file clock changes nothing Windows reports. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Unix keeps the database's folder pinned through a custom VFS on /proc/self/fd (or openat on macOS). On Windows each folder on the way is opened without following links and without sharing delete access, so the held parent cannot be renamed or removed while SQLite reads, and the database is opened read-only by that folder's own path through SQLite's Windows VFS. The inspector route and tools are available on Windows; only its symlink and FIFO tests stay Unix-only. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- scripts/build-llama.cpp.sh builds the pinned llama.cpp on Windows (Git Bash): every x86-64 CPU variant as a loadable module, compiled by clang-cl through the Visual Studio generator as upstream does, without OpenMP, plus Vulkan when the Vulkan SDK is installed. - The Windows installer job builds the CPU runtime, checks that llama-server.exe runs, and bundles it as llama.cpp\ beside the app. - The runtime is found as llama-server.exe in that folder or under %LOCALAPPDATA%\ShadowCode\llama.cpp; it runs in a job object (it ends with ShadowCode) and keeps the variables Windows DLLs need to load. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…em variables
- paths::home_dir reads USERPROFILE on Windows: a program started from
Explorer has no HOME, so the app would have refused to start ("HOME is
not set"). Every reader of the home folder uses it.
- App folders on Windows: settings in %APPDATA%\ShadowCode\config, history,
models and caches in %LOCALAPPDATA%\ShadowCode.
- process::platform_env keeps SystemRoot and the other variables every
Windows program needs (without it even Winsock fails) wherever a child is
started from a cleared environment: commands, MCP servers, vendor probes,
language-server installs and the local model runtime.
- The installer job runs the built app without HOME and checks where its
folders went.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…m variables for language servers Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The runner that drives Codex, Claude Code, Cursor, Grok and Antigravity is no longer Unix-only: - Its pipe readiness check (bytes waiting before an approval reply) is PeekNamedPipe on Windows, the counterpart of poll(POLLIN). - The vendor and everything it starts run in a kill-on-close job object; stopping a turn ends the job. - Vendor turns, their checkpoints, usage and MCP servers are recorded as on Unix; the engine no longer refuses them on Windows. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… run on Windows Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The drawer's terminals now work on Windows, with the Unix version's contract: the user's shell (PowerShell 7 when installed, else Windows PowerShell) on a pseudo console in the project folder with the user's environment, a bounded scrollback read by cursor, coalesced output wake-ups, resize, and hang-up by closing the console. The shell and what it starts run in a job object, ended after the hang-up's grace period. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Agent shell commands on Windows run in ShadowCode's AppContainer: - Writable: the project and a fresh scratch folder (also HOME, TEMP, TMP). - Readable: Windows and Program Files (as for every container), plus the home layout's toolchain folders, the user's own PATH folders and the shell's folder, granted read-only. - Hidden: the rest of the home folder: credentials, other projects. - Network off: no capabilities, so no network at all, loopback included. Network on: the internet and private-network capabilities. The allow-list is refused, since the container cannot reach its proxy on this computer. - Grants are access entries for ShadowCode's container SID only, added once per folder (checked before re-applying, since propagation through a large project is slow). - A process attribute Rust cannot set yet starts the container, so the command runs through a launcher: ShadowCode's executable with --shadowcode-sandbox, or the engine's shadowcode-sandbox binary in tests. - When the sandbox cannot be set up, commands fall back as on macOS: refused under "Require sandbox", otherwise run with a warning. A Windows-only test checks that the project is written, a secret in the home folder is not read, and nothing is written outside the project. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…t is Unix-only Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nts use Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…andles Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Every program loads user32, which cannot start (0xC0000142) when its AppContainer has no access to the window station and desktop. On the interactive desktop (WinSta0) containers already have it and nothing is changed; elsewhere (a service, a CI runner) the launcher grants ShadowCode's container SID use of its own window station and desktop. Tests: the fake Codex's shim runs Python by its full path. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dates The pinned libcurl 8.14.1-r2 and libexpat 2.8.4-r0 left the Alpine 3.21 repository (replaced by 8.14.1-r3 and 2.9.0-r0), so the pinned build container could no longer install its tools and every native package build failed, on main as well. They are build-tool dependencies; the runtime links statically from its recorded sources. The whole list was checked to resolve in the pinned container. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ites LF Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… the sandbox Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The diagnostics on the Windows runner showed system programs and PowerShell 7 start in the AppContainer, Git for Windows' bash (MSYS2) does not (its runtime fails with 0xC0000142) and Windows PowerShell cannot load its own modules there. Sandboxed commands therefore run in PowerShell 7; the command result says so. Without PowerShell 7 the sandbox reports itself unavailable and the usual fallback applies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…test waits for the pause boundary Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…source On the Windows runner PowerShell 7 started in the AppContainer but could not enter the project: it lists every parent folder to normalize a path, and the container may not list C:\Users (only an administrator could change that). busybox-w32 is a native Windows sh with the usual tools that changes folder with the plain Win32 call; commands keep their POSIX syntax. - scripts/build-busybox-w32.sh cross-compiles the commit pinned in tools/busybox-w32.pin with mingw-w64, as upstream does; the output keeps its GPL-2.0 LICENSE and a COMMIT naming the exact source. - A Linux job in the Windows workflow builds it; the tests and the installer (as busybox\ beside the app) use that build. - Without the bundled shell the sandbox is unavailable and the usual fallback applies. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ents - The sandbox isolation test passes on Windows: the project is written, a home-folder secret is not read, nothing is written outside. - busybox-w32 opens /dev/null as `nul` with create and truncate flags, which an AppContainer is refused; a small patch (shipped with the binary) opens the device without them. - Replacing a file is briefly refused on Windows while another replacement of it is in flight or a scanner holds it; atomic writes retry for up to about a second (concurrent config updates failed). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s lock Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
An AppContainer may not open the NUL device (cmd's >nul is refused as well). The launcher opens it, passes the handle inherited and names it in SHADOWCODE_NULL_HANDLE; the busybox-w32 patch falls back to a copy of it. It also stands in for a missing standard handle. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd sandbox pass on CI Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
release-windows.yml builds the per-user NSIS installer with llama.cpp and the sandbox shell, installs it through scripts/install-windows.ps1 and requires the doctor's new AppContainer check to pass, then attaches the installer, the complete busybox-w32 source (GPL-2.0) and ShadowCode_<v>_windows.sha256. release.yml dispatches it after publishing. Windows now reports its own sandbox in doctor and Settings (not bubblewrap), and the allow-list option says it is refused there. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Windows: a per-user installer with local models, terminals, subscription tools and an AppContainer sandbox for agent commands. Version files, trust range 0.33.0–2.3.0, release notes and changelog. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… own folder The busybox test relied on the other test's grant of busybox's folder, which ran in parallel and rewrote that folder's permissions under it. It now runs the doctor's probe (which grants the folder) first, and the two tests take turns. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…4 catches up
Alpine published libcurl 8.14.1-r3 for x86_64 on October 18; the 3.21
aarch64 builder has not updated its index since (still r2), so the exact
pin broke every aarch64 build. apk-packages.txt may now replace one pin on
one architecture ("aarch64:libcurl=8.14.1-r2"); every package is still
pinned exactly, and an override must name a pinned package. libcurl is a
build-container dependency (Git's), not part of the shipped runtime.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
ShadowCode 2.3.0: ShadowCode runs on Windows.
What's in it
windows-latestrunner (.github/workflows/windows.yml). All engine unit tests and integration suites pass there.dunce,/in agent-facing paths);%APPDATA%/%LOCALAPPDATA%folders; llama.cpp built with MSVC (CPU); SQLite inspector without following links; vendor runner pipes viaPeekNamedPipe.shbuilt from a pinned commit with one patch (the container may not open NUL, so/dev/nulluses a handle the launcher opens). Doctor and Settings report it.release-windows.ymlbuilds the per-user NSIS installer with llama.cpp and the sandbox shell, installs it throughscripts/install-windows.ps1, requires the doctor's sandbox check, and attaches the installer, the complete busybox source (GPL-2.0) andShadowCode_<v>_windows.sha256.release.ymldispatches it after publishing.aarch64:libcurl=8.14.1-r2).Not covered
Details:
docs/WINDOWS_PORT.md.🤖 Generated with Claude Code