perf(desktop): speed up Windows update installation#6169

merged14
main
GitHub fork: t3code/optimize-windows-update-installation
openedAug 11, 2026byWWout Stiens
View on GitHubTwo-way sync enabledPR last imported 20d ago

Windows desktop updates still spend most of their install time creating loose files, even after the bundled-server work in #5877 reduced the payload to roughly 1,200 files.

This PR moves the bundled server and only its runtime-external/native dependency closure into a dedicated resources/server.asar sidecar. The Windows primary reads the archive in place through Electron. WSL extracts it atomically into a versioned cache only when WSL is enabled.

After rebasing onto current main with #5877:

  • The shared external-package list drives both bundling and the sidecar dependency roots: @ff-labs/fff-node, msgpackr-extract, and node-pty.
  • The emitted-bundle guards, native-loader checks, dependency-closure checks, and isolated runtime probe remain in place.
  • The final copied sidecar is checked for its server entry, unpacked natives, resource monitor, an 80-file payload budget, and successful node bin.mjs --version execution from a clean extracted tree.
  • On same-architecture Windows builds, the packaged primary must also create and destroy a real FileFinder from inside server.asar, proving Electron redirects both fff and ffi natives to the .unpacked sibling. Cross-architecture builds retain the structural and extracted-sidecar checks without executing the target Electron binary.
  • WSL extraction uses one globally bounded eight-entry traversal, avoiding recursive concurrency pools and unbounded fiber growth.\n- The existing release path continues to supply the Linux node-pty prebuild used by WSL.

Verification:

  • vp run --filter @t3tools/scripts typecheck
  • vp run --filter @t3tools/desktop typecheck
  • vp run --filter t3 typecheck
  • vp run --filter t3 build:bundle
  • focused lint and formatting checks\n- direct nested traversal probe: 4,681 entries visited, maximum concurrency 8, active work returned to 0\n- direct x64-host/ARM64-target probe confirmed the target executable is skipped before filesystem access
  • real local sidecar stage and extracted-runtime probe: 3 dependency roots, 85,095,471-byte sidecar, 33 unpacked natives, and 36 files in the synthetic packaged payload
  • positive and missing-dependency runtime probes both passed
  • focused Vitest files remain blocked before collection by the existing @effect/vitest config error, reproduced after vp i

Implemented by GPT-5.6-sol with Codex in the T3 Code harness.


Note

High Risk Large Windows packaging and backend bootstrap change (dual-ASAR layout, WSL extraction, native-load probes); regressions would break installs, updates, or WSL/primary backends on Windows.

Overview Windows update/install speed is the main goal: the bundled server and its runtime-external/native deps move out of app.asar into a dedicated resources/server.asar sidecar (natives in server.asar.unpacked), delivered via extraResources, with NSIS differentialPackage: true kept on.

Runtime: DesktopEnvironment gains serverRoot (packaged Windows โ†’ resources/server.asar; elsewhere unchanged). The Windows primary still runs the entry through asar-aware ELECTRON_RUN_AS_NODE. DesktopWslServerTree materializes the sidecar into a version-keyed wsl-server-tree/<version> directory on first WSL use (bounded copy, serialized callers, stale sweep); resolveWsl preflight now depends on that instead of app.asar.unpacked. The @ff-labs/fff-node patch generalizes .asar โ†’ .asar.unpacked for any archive segment.

Build/packaging: Windows drops asarUnpack on the app; stageWindowsServerSidecar hoists a minimal prod install, packs with @electron/asar, and omits the server tree from the app stage. selectCliRuntimeExternalDependencies drives sidecar roots (aligned with bundling). Post-build validateWindowsPackagedPayload checks sidecar integrity, unpacked natives, resource monitor, an 80-file budget, extracted bin.mjs --version, and on same-arch builds a live fff probe via the packaged Electron binary.

Docs/tests: Release notes describe the new Windows payload topology; broad desktop and artifact tests cover the new paths.

Reviewed by Cursor Bugbot for commit f9a65c27628a032cc2b81c03a510aff39665aa79. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Ship Windows server bundle as a separate server.asar sidecar to speed up updates

  • Moves the Windows server bundle out of app.asar and into a dedicated resources/server.asar (with natives in server.asar.unpacked), so NSIS differential updates only re-download changed blocks rather than a monolithic archive.
  • Adds stageWindowsServerSidecar in build-desktop-artifact.ts to install hoisted production dependencies for both win32 and linux targets, pack them into server.asar, and place unpacked natives alongside.
  • Adds DesktopWslServerTree in DesktopWslServerTree.ts to extract and version-key the sidecar into a state directory before WSL backend startup, serializing concurrent callers and sweeping stale versions.
  • Updates DesktopEnvironment so serverRoot points to resources/server.asar on packaged Windows, and DesktopBackendConfiguration.resolveWsl gates WSL preflight on successful sidecar extraction.
  • Adds validateWindowsPackagedPayload to verify sidecar integrity, unpacked native presence, resource-monitor existence, fff native load via ELECTRON_RUN_AS_NODE, isolated self-containment check, and a โ‰ค80-file budget before artifact finalization.
  • Behavioral Change: Windows app.asar no longer contains the server tree; NSIS differential packaging is now enabled (differentialPackage: true), which changes blockmap size and update download behavior.

Macroscope summarized f9a65c2.

Synced from GitHub

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

โš™๏ธ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 571fd5f2-ac02-447c-abd9-ca7ab067f5cb

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • ๐Ÿ” Trigger review

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.

โค๏ธ Share

Comment @coderabbitai help to get the list of available commands.

Synced from GitHub

Approvability

Verdict: Needs human review

This PR restructures Windows packaging from loose files to a server.asar sidecar architecture and introduces lazy runtime extraction for WSL users. With ~1800 additions including a new DesktopWslServerTree service, new build/validation logic, new dependencies, and production deployment topology changes, this significant architectural change warrants human review.

You can customize Macroscope's approvability policy. Learn more.

I reproduced two Windows blockers on the current head (4e8da44e5018a19e8cb8a2f1d2d7e053cc00e9db) with a real unsigned x64 NSIS build.

Command:

powershell
1node scripts/build-desktop-artifact.ts --platform win --target nsis --arch x64 \
2 --build-version 0.0.34-nightly.20260812.6169 \
3 --output-dir release/pr-review/6169/head --keep-stage
  1. The build runs for 255.22 s, produces the installer, then exits 1 in validateWindowsPackagedPayload:
1WindowsPackagedPayloadValidationError: Windows packaged payload contains an invalid server.asar sidecar.
2[cause]: Error: "apps/server/dist/bin.mjs" was not found in this archive

The entry is present. On Windows, @electron/asar.statFile expects a native-separator path: statFile(asarPath, "apps\\server\\dist\\bin.mjs") succeeds, while the current hard-coded "apps/server/dist/bin.mjs" fails. The three new payload-validation tests fail for the same reason.

  1. Independently, the generated win-unpacked/resources has server.asar but no server.asar.unpacked directory. The source staging directory contains 35 native files (29,905,936 bytes), and the ASAR header declares all 35 as unpacked, but none are copied into the packaged app. The resulting payload has only 34 total files. Bypassing the validator would therefore still ship a Windows backend that cannot load those native modules.

Please fix both paths and add a Windows-running regression test/build check before merging. The current Linux CI is green but does not exercise this behavior.

Follow-up from launching the exact generated win-unpacked/T3 Code (Nightly).exe with isolated APPDATA and T3CODE_HOME:

  • The Electron root stays alive but has MainWindowHandle = 0; no renderer/window is created.
  • No server-runtime.json readiness receipt is written.
  • The backend restarted 11 times during the observation window.
  • Every child exits with ERR_DLOPEN_FAILED while resolving the absent path:
1resources\server.asar.unpacked\node_modules\@yuuang\ffi-rs-win32-x64-msvc\ffi-rs.win32-x64-msvc.node

So the missing unpacked sidecar is confirmed as a user-visible startup failure, not just a packaging invariant.

.github/workflows/windows-package-smoke.ymllines 5โ€“13Outdated ยท e8e553cOpen thread
โ€ฆโ€ฆ@@ -0,0 +1,56 @@
10+ - "pnpm-lock.yaml"
11+ - "pnpm-workspace.yaml"
12+ - "scripts/build-desktop-artifact.ts"
13+ - "scripts/package.json"
MmacroscopeappBoton lines 5โ€“13Aug 12, 2026

๐ŸŸก Medium workflows/windows-package-smoke.yml:5

The pull_request.paths filter omits source directories that this job actually builds โ€” apps/desktop/src/**, apps/server/src/**, workspace packages, and native/resource-monitor/**. A PR that changes, for example, the resource-monitor Rust source matches none of the listed paths, so this smoke job never runs even though build-desktop-artifact.ts compiles and packages that code. Consider adding the missing paths (or broadening the trigger) so changes to built source actually exercise this job.

diff
1 pull_request:
2 paths:
3 - ".github/workflows/windows-package-smoke.yml"
4 - "apps/desktop/package.json"
5 - "apps/desktop/src/**"
6 - "apps/server/package.json"
7 - "apps/server/src/**"
8+ - "native/resource-monitor/**"
9+ - "package.json"
10+ - "packages/**"
11 - "patches/**"
12 - "pnpm-lock.yaml"
13 - "pnpm-workspace.yaml"
14 - "scripts/build-desktop-artifact.ts"
15 - "scripts/package.json"
๐Ÿค– Copy this AI Prompt to have your agent fix this:
text
1In file @.github/workflows/windows-package-smoke.yml around lines 5-13:
2
3The `pull_request.paths` filter omits source directories that this job actually builds โ€” `apps/desktop/src/**`, `apps/server/src/**`, workspace packages, and `native/resource-monitor/**`. A PR that changes, for example, the resource-monitor Rust source matches none of the listed paths, so this smoke job never runs even though `build-desktop-artifact.ts` compiles and packages that code. Consider adding the missing paths (or broadening the trigger) so changes to built source actually exercise this job.

[gpt-5.6-sol] RESPONDING ON BEHALF OF WOUT:

This workflow is intentionally scoped to Windows packaging-topology inputs, not every source file transitively compiled by build:desktop. Normal CI already builds and tests application/workspace source. Expanding this to packages/** and all desktop/server source would run a 32-vCPU Windows NSIS build for most product PRs without exercising a different packaging path. Package manifests, workspace/lock configuration, patches, the artifact builder, and the smoke workflow itself are included because those can change the staged dependency/resource topology this check owns.

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

[gpt-5.6-sol] RESPONDING ON BEHALF OF WOUT:

@SunkenInTime Thanks for the concrete Windows repro. Both blockers are fixed on the latest head.

  • The ASAR entry check now uses the host-native path from path.join(...), so statFile succeeds on Windows.
  • server.asar and server.asar.unpacked are now staged under one parent resource directory and copied with a single electron-builder matcher, avoiding the dropped standalone .unpacked FileSet.
  • Added a path-filtered Windows CI workflow that builds and validates a real unsigned x64 NSIS artifact.

The new Windows package run passed: Windows Package Smoke. The final payload validator reported 70 files and all 35 ASAR-unpacked sidecar natives present. The fixes landed in e8e553cb3; the current head is f9b6fbf5b.

CcursorBotreviewed ยท 1 inline threadAug 12, 2026
Synced from GitHub

Cursor Bugbot has reviewed your changes using high effort and found 1 potential issue.

Fix All in Cursor

โŒ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit f9b6fbf5b0f7887e956161a36a4b393e7fef1db2. Configure here.

scripts/build-desktop-artifact.tsline 698Outdated ยท f9b6fbfOpen thread
โ€ฆโ€ฆ@@ -632,14 +692,47 @@ export const DESKTOP_FILE_EXCLUSIONS = [
695+ // Windows stages the server sidecar below prod-resources so electron-builder
696+ // can copy it using project-relative extraResources matchers. Keep those
697+ // staging inputs out of app.asar; they are emitted once at resources/.
698+ "!apps/desktop/prod-resources/windows-server{,/**/*}",
CcursorBoton line 698Aug 12, 2026

Unsupported brace exclusion pattern

High Severity

DESKTOP_FILE_EXCLUSIONS now uses bash-style brace expansion in an electron-builder files pattern. electron-builder does not honor {,/**/*} there, so the windows-server staging tree is not excluded from app.asar. That can duplicate the sidecar into the app payload, inflate update size, and push the Windows package over the 100-file validation budget.

Reviewed by Cursor Bugbot for commit f9b6fbf5b0f7887e956161a36a4b393e7fef1db2. Configure here.

[gpt-5.6-sol] RESPONDING ON BEHALF OF WOUT:

Electron-builder does use minimatch brace patterns internally, including this exact {,/**/*} form, so the original pattern was supported. Still, there is no value in leaving this ambiguous: 5a0b97e1d replaces it with explicit directory and descendant exclusions, and the packaging test asserts both literals.

Re-tested the updated head 5a0b97e1d671008a7ae507e47997c8cb9ccd30c6 end to end on Windows 11 after the three follow-up commits.

The original blockers are fixed:

  • the exact release build completed successfully in 285.31s and validated server.asar plus 35 unpacked native sidecars
  • the resulting installer is 161,607,727 bytes (154.12 MiB)
  • an isolated silent install completed in 11.42s and produced 70 installed files
  • the packaged backend receipt appeared 3.88s after process start
  • the actual installed Electron window rendered the T3 Code UI successfully
  • focused desktop/scripts typechecks pass, and the new CI Package unsigned x64 NSIS artifact job is green

The remaining 7/69 failures in my Windows-focused local test selection are path-separator expectations in tests; the functional sidecar validation cases passed and CI Check/Test are green. I consider the two packaging findings I reported above resolved and this updated PR ready to merge.

Synced from GitHub

hey @StiensWout, thanks for the work and the Windows verification here. could you update/rework this PR on current main now that #5877 has merged?

the merged work improves the foundation this PR can build on:

  • the server cli now bundles ordinary js dependencies
  • one shared external-package list drives both bundling and packaging
  • Windows only needs the required external/native closure outside the asar instead of the whole node_modules tree
  • emitted-bundle guards and an isolated runtime probe catch missing, incorrectly bundled, or staging-leaked dependencies

with that in place, server.asar should be buildable from the bundled server output plus only the required external/native packages. it should no longer need a separate hoisted install of the full server dependency tree. that should make the sidecar smaller and simpler while retaining the merged correctness checks.

suggested rework:

  1. rebase onto current main; the current textual conflicts are in scripts/build-desktop-artifact.ts and its test.
  2. preserve the shared external list, emitted-bundle checks, selective packaging model, symlink-isolated probe, and regression tests.
  3. derive the sidecar contents from the bundled server plus the shared runtime-external/native closure instead of resolvedServerDependencies wholesale.
  4. adapt the self-containment probe to validate the extracted sidecar tree, in addition to checking the asar entry, unpacked natives, resource monitor, and file-count budget.
  5. recalibrate the file-count budget against the current topology.
  6. expand the Windows smoke workflow paths to cover the bundler/external-list and desktop runtime files. either include the release WSL prebuild or clearly scope the job as Windows-primary/package-only.
  7. rerun the real NSIS install/launch and WSL backend test with build staging removed, then report the incremental file-count, install/update-time, and artifact-size benefit over current main.

one possible approach is to split this into:

  • a low-risk PR for Windows package CI and payload/integrity guards
  • a measured architecture PR for server.asar, backend-root changes, and lazy WSL extraction/cache

that would let the validation improvements land independently while the runtime topology gets focused benchmarking and review. the sidecar reportedly reduced the installed payload from 1,192 files to 70, so keeping it together may also be reasonable if the new benchmark still shows a worthwhile gain. happy for you to choose whichever structure you think is best.

[gpt-5.6-sol] RESPONDING ON BEHALF OF WOUT:

Rebased and reworked on current main (7e01d33f0); the latest head is db44b0f3b.

  • The sidecar is now built from the bundled server plus the shared runtime-external closure only: @ff-labs/fff-node, msgpackr-extract, and node-pty.
  • The emitted-bundle/native guards, selective closure checks, and symlink-isolated runtime probe from #5877 remain intact.
  • Validation now extracts the final copied resources/server.asar, blocks ancestor/global module leakage, checks the server entry, unpacked natives and resource monitor, then executes node bin.mjs --version from that clean tree.
  • The payload budget is recalibrated to 80 files.
  • WSL still extracts atomically into its versioned cache on first use.

Wout requested that this PR not add repository CI, so the PR-added Windows package-smoke workflow has been removed; the final diff has no .github changes. The standard Check, Test, Release Smoke, native analysis, fingerprint, Cursor, and Macroscope checks are green on the latest head.

For concrete topology evidence, the local isolated stage has 3 dependency roots, 33 unpacked natives, and 36 files in the synthetic packaged payload. The Windows package run on the immediately preceding code-equivalent head also passed with 70 files and 35 sidecar natives; the only subsequent source change was deleting that workflow. I have not claimed fresh NSIS install/update timing or a real WSL end-to-end run for the rebased topology, because those were not rerun from this Linux worktree.

Tt3-code-botBotrequested changes ยท 1 inline threadAug 14, 2026
Synced from GitHub

requesting changes on exact head db44b0f3bca31c678ac1aaa6a275cac27822a95a. the sidecar rework now correctly uses the bundled server plus the shared minimal external/native closure, and the focused tests/static checks pass. however, the windows primary has a native-library path blocker: it runs from server.asar, while the existing fff patch only redirects app.asar paths to their .unpacked sibling. the current extracted plain-node probe cannot catch failures caused by electron's in-asar path. please fix the redirect for this sidecar and add a primary-runtime probe that exercises fff from inside the packed archive.

verified locally: 90 focused tests, desktop/server/scripts typechecks, formatting, focused lint, build:desktop, a real minimal sidecar stage, extracted native imports, and materialized linux node-pty spawn. these do not replace windows nsis + primary + wsl end-to-end validation or performance measurements on this rebased head.

apps/desktop/src/app/DesktopEnvironment.tsline 169Outdated ยท db44b0fOpen thread
โ€ฆโ€ฆ@@ -157,6 +164,10 @@ const make = Effect.fn("desktop.environment.make")(function* (
159166 const appRoot = input.isPackaged ? input.appPath : rootDir;
167+ const serverRoot =
168+ input.isPackaged && input.platform === "win32"
169+ ? path.join(input.resourcesPath, "server.asar")
Tt3-code-botBoton line 169Aug 14, 2026

blocking: this changes the primary entry to resources/server.asar, but patches/@ff-labs__fff-node@0.9.4.patch only rewrites a native path containing the literal app.asar segment. electron's patched fs makes existsSync(server.asar/.../fff_c.dll) succeed, so fff returns that archived path instead of server.asar.unpacked/...; ffi-rs/dlopen then fails because an asar member is not a real library path. the analogous electron probe succeeds from app.asar and fails from server.asar with cannot open shared object file: Not a directory. please generalize the unpacked-path redirect and cover the windows-primary in-asar native load, not only the extracted plain-node tree.

[gpt-5.6-sol] RESPONDING ON BEHALF OF WOUT:

Fixed on 6935615b9.

  • The fff patch now redirects the first path segment ending in .asar to that archive's .asar.unpacked sibling, so both app.asar and server.asar use a real native-library path.
  • Windows payload validation now launches the final packaged .exe with ELECTRON_RUN_AS_NODE=1, imports fff-node from inside server.asar, and must successfully create and destroy a native FileFinder.
  • Added focused coverage asserting that the final primary/runtime path and native-load probe are invoked.

I also ran the probe directly with Electron against a real temporary server.asar containing the patched fff package, ffi-rs, and their actual Linux native libraries; the in-ASAR FileFinder create/destroy completed successfully. Scripts typecheck, focused lint/format, frozen install, and the server bundle build pass.

apps/desktop/src/wsl/DesktopWslServerTree.tsline 87Outdated ยท 6935615Open thread
โ€ฆโ€ฆ@@ -0,0 +1,201 @@
84+ }),
85+ // Bounded concurrency keeps the extraction fast on real disks without
86+ // exhausting file descriptors on huge node_modules directories.
87+ { concurrency: 8, discard: true },
MmacroscopeappBoton line 87Aug 14, 2026

๐ŸŸ  High wsl/DesktopWslServerTree.ts:87

copyTree has no tree-wide concurrency limit: each recursive directory invokes Effect.forEach with its own { concurrency: 8 }, so nested directories multiply the number of concurrent stat/readFile/writeFile operations beyond eight and can exhaust file descriptors or memory during large node_modules extractions. Pass one shared semaphore through the traversal and acquire it around each filesystem operation.

๐Ÿค– Copy this AI Prompt to have your agent fix this:
text
1In file @apps/desktop/src/wsl/DesktopWslServerTree.ts around line 87:
2
3`copyTree` has no tree-wide concurrency limit: each recursive directory invokes `Effect.forEach` with its own `{ concurrency: 8 }`, so nested directories multiply the number of concurrent `stat`/`readFile`/`writeFile` operations beyond eight and can exhaust file descriptors or memory during large `node_modules` extractions. Pass one shared semaphore through the traversal and acquire it around each filesystem operation.

[gpt-5.6-sol] RESPONDING ON BEHALF OF WOUT:

Fixed in 725738c5e. The recursive copy now receives one shared eight-permit semaphore for the full extraction tree. Directory creation, listing, and stat calls acquire that shared gate, while each file holds one permit across its read/write pair so nested directories cannot multiply filesystem concurrency or retain unbounded file buffers. Local per-directory traversal remains bounded at eight. Desktop typecheck and targeted lint pass; the focused Vitest file remains blocked during collection by the existing @effect/vitest .config error.

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

patches/@ff-labs__fff-node@0.9.4.patchlines 20โ€“20Outdated ยท 725738cOpen thread
โ€ฆโ€ฆ@@ -11,16 +11,18 @@ index ee181aef5007e4bf34a49479c089ca30f73a320b..327e2c55c83cc4c50d396a3109190ef1
19-+ const asarSegment = `${sep}app.asar${sep}`;
20-+ if (!binaryPath.includes(asarSegment)) {
19++ const pathSegments = binaryPath.split(sep);
20++ const asarIndex = pathSegments.findIndex((segment) => segment.endsWith(".asar"));
MmacroscopeappBoton lines 20โ€“20Aug 14, 2026

๐ŸŸ  High patches/@ff-labs__fff-node@0.9.4.patch:20

resolveUnpackedAsarPath rewrites the first .asar segment, so an installation under a directory such as C:\tools.asar\T3 Code\resources\server.asar\... probes tools.asar.unpacked and then falls back to the virtual server.asar path. The native fff library therefore cannot be loaded even when it exists under server.asar.unpacked; select the archive segment nearest the binary instead.

suggestion
1 const asarIndex = pathSegments.findLastIndex((segment) => segment.endsWith(".asar"));
๐Ÿค– Copy this AI Prompt to have your agent fix this:
text
1In file @patches/@ff-labs__fff-node@0.9.4.patch around line 20:
2
3`resolveUnpackedAsarPath` rewrites the first `.asar` segment, so an installation under a directory such as `C:\tools.asar\T3 Code\resources\server.asar\...` probes `tools.asar.unpacked` and then falls back to the virtual `server.asar` path. The native `fff` library therefore cannot be loaded even when it exists under `server.asar.unpacked`; select the archive segment nearest the binary instead.

[gpt-5.6-sol] RESPONDING ON BEHALF OF WOUT:

Fixed in ee24370b6. The fff patch now uses findLastIndex, so it rewrites the .asar segment nearest the native package and ignores an earlier .asar suffix in the installation path. The patch hash is updated, and a frozen reinstall confirms the installed dependency contains the revised lookup.

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

scripts/build-desktop-artifact.tsline 2500Outdated ยท 725738cOpen thread
โ€ฆโ€ฆ@@ -2050,6 +2176,379 @@ const stageWslNodePtyPrebuild = Effect.fn("stageWslNodePtyPrebuild")(function* (
2497+ `${WINDOWS_SERVER_ASAR_RESOURCE}.unpacked`,
2498+ ...unpackedFile.split("/"),
2499+ );
2500+ if (!(yield* fs.exists(unpackedPath).pipe(Effect.orElseSucceed(() => false)))) {
MmacroscopeappBoton line 2500Aug 14, 2026

๐ŸŸก Medium scripts/build-desktop-artifact.ts:2500

validateWindowsPackagedPayload accepts directories and other non-file entries as unpacked native files and as t3-resource-monitor.exe, so malformed payloads pass validation and fail when node-pty, msgpackr-extract, or the packaged application loads them. fs.exists only checks presence; require fs.stat(...).type === "File" for each expected native path and for resourceMonitorPath.

๐Ÿค– Copy this AI Prompt to have your agent fix this:
text
1In file @scripts/build-desktop-artifact.ts around line 2500:
2
3`validateWindowsPackagedPayload` accepts directories and other non-file entries as unpacked native files and as `t3-resource-monitor.exe`, so malformed payloads pass validation and fail when `node-pty`, `msgpackr-extract`, or the packaged application loads them. `fs.exists` only checks presence; require `fs.stat(...).type === "File"` for each expected native path and for `resourceMonitorPath`.

[gpt-5.6-sol] RESPONDING ON BEHALF OF WOUT:

Fixed in ee24370b6. Windows payload validation now requires every ASAR-unpacked native path and the resource-monitor executable to stat as a regular file; missing paths, directories, and other non-file entries all fail with the existing targeted validation reason. Added focused coverage that replaces each required executable file with a directory and verifies both failures.

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

Tt3-code-botBotrequested changes ยท 2 inline threadsAug 14, 2026
Synced from GitHub

re-reviewed exact head ee24370b6116e34d19b5f14f92f78c3b34b30c49. the prior server.asar fff blocker is fixed: the patch now selects the nearest .asar segment, and the packaged windows-primary validator exercises FileFinder.create() and destroy() through the final archive. regular-file payload validation is also fixed.

two blockers remain. first, the executable probe gates only on win32, so an x64 windows host building the documented arm64 target will produce the arm64 payload and then try to execute its arm64 electron binary locally. second, the shared WSL semaphore caps filesystem operations and retained file buffers, but each recursive directory still creates its own eight-way Effect.forEach, so recursive task growth remains unbounded.

verified locally: frozen install, 92 focused tests, the full desktop/scripts suites (753 tests), desktop/server/scripts typechecks, focused lint/formatting, build:desktop, and git diff --check pass. exact-head check, test, and release smoke are green; the vercel authorization failure is unrelated. no exact-head windows nsis or windows+wsl end-to-end run is present.

scripts/build-desktop-artifact.tsline 2343Outdated ยท ee24370Open thread
โ€ฆโ€ฆ@@ -2050,6 +2176,384 @@ const stageWslNodePtyPrebuild = Effect.fn("stageWslNodePtyPrebuild")(function* (
2340+ readonly asarPath: string;
2341+ readonly verbose: boolean;
2342+}) {
2343+ const hostPlatform = yield* HostProcessPlatform;
Tt3-code-botBoton line 2343Aug 14, 2026

blocking: this only compares the host platform. the repo exposes dist:desktop:win:arm64, so an x64 windows machine can cross-package an arm64 payload; this function then reaches the process spawn below and tries to execute that arm64 .exe on the x64 host, rejecting an otherwise valid cross-build. pass the target arch into validation and run this native probe only when host and target architectures match, while keeping structural checks for mismatched cross-target builds and requiring a same-arch target smoke test. please add an x64-host/arm64-target regression case.

[gpt-5.6-sol] RESPONDING ON BEHALF OF WOUT:

Fixed in c50eb1b28. Windows payload validation now receives the target architecture, and the packaged-primary fff probe runs only when both the host platform is win32 and the host architecture matches that target. ASAR structure, unpacked natives, the resource monitor, file count, and the extracted plain-Node self-containment probe still run for cross-target builds. Added an x64-host/ARM64-target regression that asserts the Electron primary is not spawned while the structural Node probe still is, and made the existing x64/x64 case explicitly require the native probe. The release runbook now requires a same-architecture probe for each release target.

apps/desktop/src/wsl/DesktopWslServerTree.tsline 73Outdated ยท ee24370Open thread
โ€ฆโ€ฆ@@ -0,0 +1,210 @@
70+ Effect.gen(function* () {
71+ yield* ioSemaphore.withPermit(fs.makeDirectory(to, { recursive: true }));
72+ const entries = yield* ioSemaphore.withPermit(fs.readDirectory(from));
73+ yield* Effect.forEach(
Tt3-code-botBoton line 73Aug 14, 2026

blocking: the shared semaphore caps concurrent filesystem calls and file buffers, but it does not cap recursive traversal tasks. every directory starts another independent Effect.forEach(..., { concurrency: 8 }); an exact structural probe on an eight-way, four-level tree reached 3,726 simultaneously active entry effects across 4,681 directories while I/O stayed at eight. the ASAR entry count is not bounded by the outer 80-file payload guard, so a wider dependency tree can create thousands of fibers and retained directory arrays during first-use WSL extraction. use one globally bounded work queue/worker pool, or otherwise bound the whole traversal, and add a nested-tree concurrency regression.

[gpt-5.6-sol] RESPONDING ON BEHALF OF WOUT:

Fixed in 72afc57a8. Recursive Effect.forEach pools and the shared I/O semaphore are gone. One LIFO work list now owns all child scheduling and processes at most eight entries per batch, so directory traversal, filesystem work, and retained file buffers share one global bound with no recursive fiber fan-out. Added the exact eight-way, four-level structural regression: all 4,681 nodes are visited, maximum overlapping entry effects is 8, and active work returns to 0. The same probe also passes directly against the implementation.

Added 12 commits

  • fix(desktop): restore materialized WSL test root21c548d
  • fix(desktop): validate Windows sidecar packaging305733b
  • chore: remove Windows package smoke workflow381e351
  • fix(desktop): align Windows sidecar with bundled server3907857
  • fix(desktop): bound WSL extraction concurrency3acca5d
  • fix(desktop): validate packaged native files537709e
  • fix(desktop): load fff from server sidecar716a5de
  • fix(desktop): bound WSL extraction traversal72afc57
  • ci: scope Windows package smoke install8d6c6bf
  • fix(desktop): make sidecar exclusions explicita2fce6e
  • fix(desktop): skip cross-arch native probec50eb1b
  • perf(desktop): speed up Windows update installationfe7a8c6
scripts/build-desktop-artifact.tsline 2351Outdated ยท 72afc57Open thread
โ€ฆโ€ฆ@@ -2050,6 +2176,388 @@ const stageWslNodePtyPrebuild = Effect.fn("stageWslNodePtyPrebuild")(function* (
2348+ const fs = yield* FileSystem.FileSystem;
2349+ const path = yield* Path.Path;
2350+ let executablePath: string | undefined;
2351+ for (const entry of (yield* fs.readDirectory(input.packagedAppDir)).sort()) {
MmacroscopeappBoton line 2351Aug 14, 2026

๐ŸŸ  High scripts/build-desktop-artifact.ts:2351

verifyWindowsPrimaryFffNativeLoad launches the wrong executable in standard Electron Windows payloads: chrome_crashpad_handler.exe sorts before the packaged application executable, so the probe passes Node flags to the crashpad helper and fails otherwise-valid builds. Select the packaged application's executable explicitly (or exclude helper executables) instead of using the first alphabetically sorted .exe.

๐Ÿค– Copy this AI Prompt to have your agent fix this:
text
1In file @scripts/build-desktop-artifact.ts around line 2351:
2
3`verifyWindowsPrimaryFffNativeLoad` launches the wrong executable in standard Electron Windows payloads: `chrome_crashpad_handler.exe` sorts before the packaged application executable, so the probe passes Node flags to the crashpad helper and fails otherwise-valid builds. Select the packaged application's executable explicitly (or exclude helper executables) instead of using the first alphabetically sorted `.exe`.

[gpt-5.6-sol] RESPONDING ON BEHALF OF WOUT:

Fixed in 7a1e399c3. The artifact builder now passes the exact application executable name derived from the same resolveDesktopProductName value used in electron-builder configuration. The native probe stats and launches that path directly instead of scanning root .exe files. The focused fixture now contains both chrome_crashpad_handler.exe and a later-sorting t3code.exe, and asserts that the application executable receives the Electron/Node probe. Scripts typecheck and targeted lint/format pass.

Sorry, I'm unable to act on this request because you do not have permissions within this repository.

Added 1 commit

  • fix(desktop): target the packaged app executable7a1e399
Tt3-code-botBotrequested changes ยท 1 inline threadAug 14, 2026
Synced from GitHub

re-reviewed exact head 7a1e399c3c40ca41829ec488b685067624a38df6. the prior WSL traversal blocker is fixed: extraction now uses one iterative work list with a global eight-task bound, and the 4,681-node regression holds the active maximum at eight. the original cross-architecture execution failure and helper-executable selection are also fixed.

one packaging blocker remains: the architecture mismatch returns before validating that the expected application executable exists and is a regular file. an x64 host can therefore accept an arm64 payload with a valid sidecar/resource monitor but no primary app executable. keep executable existence/type validation architecture-independent and skip only its execution; add a mismatch regression that deletes the expected app executable.

verified locally: frozen install, 94 focused tests, all 755 desktop/scripts tests, desktop/server/scripts typechecks, full lint and formatting, build:desktop, and git diff --check pass. exact-head required checks (Test, Check, Mobile Native Static Analysis, and Release Smoke) pass. the vercel authorization failure is non-required and unrelated. windows + WSL release readiness remains separate, with no fresh same-architecture windows NSIS, packaged-primary, or WSL end-to-end evidence.

scripts/build-desktop-artifact.tsline 2347Outdated ยท 7a1e399Open thread
โ€ฆโ€ฆ@@ -2050,6 +2176,382 @@ const stageWslNodePtyPrebuild = Effect.fn("stageWslNodePtyPrebuild")(function* (
2344+}) {
2345+ const hostPlatform = yield* HostProcessPlatform;
2346+ const hostArchitecture = yield* HostProcessArchitecture;
2347+ if (hostPlatform !== "win32" || hostArchitecture !== input.targetArch) return;
Tt3-code-botBoton line 2347Aug 14, 2026

blocking: this returns before the exact executable path is statted below. an x64 windows host validating an arm64 payload can therefore accept a package whose sidecar and resource monitor are valid but whose primary app executable is entirely missing. only execution is architecture-dependent; construct/stat the expected executable for every target, then gate the spawn on host/target compatibility. please add a cross-architecture regression that removes the expected app executable and requires validation to fail.

[gpt-5.6-sol] RESPONDING ON BEHALF OF WOUT:

Fixed in f9a65c276. The exact primary executable is now constructed and stat-validated before host/target compatibility can skip only its execution. Added a cross-architecture regression that deletes the expected executable and requires validation to fail with WindowsPrimaryNativeProbeError.

Added 1 commit

  • fix(desktop): validate cross-arch app executablef9a65c2
Tt3-code-botBotapproved these changesAug 14, 2026
Synced from GitHub

re-reviewed exact head f9a65c27628a032cc2b81c03a510aff39665aa79. the final blocker is fixed: the expected application executable is now constructed and stat-validated for every target before architecture compatibility skips only execution, and the new x64-host/arm64-target regression removes the executable and requires WindowsPrimaryNativeProbeError. the previously verified fff sidecar loading, exact app selection, WSL traversal bound, payload checks, and bundled/minimal external closure remain intact.

verified locally: 95 focused tests and all 756 desktop/scripts tests pass; desktop/server/scripts typechecks, focused lint/formatting, and git diff --check pass. exact-head required checks (Test, Check, Mobile Native Static Analysis, and Release Smoke) pass. the vercel authorization failure is non-required and unrelated.

code review approved. the PR is textually mergeable and its required checks are green. windows + WSL release readiness remains separate because this head still has no fresh same-architecture windows NSIS, packaged-primary, or WSL end-to-end evidence.

Re-tested exact head f9a65c27628a032cc2b81c03a510aff39665aa79 on Windows with the worktree-local/locked toolchain.

The real unsigned x64 NSIS flow is green: it produced the installer + blockmap, validated a 69-file payload with all 35 ASAR-unpacked natives, successfully ran the packaged T3 Code (Alpha).exe fff/FileFinder probe, and completed the isolated extracted-sidecar node bin.mjs --version check.

One non-blocking test-portability follow-up remains. This focused command reports 85 passed / 10 failed on Windows:

powershell
1.\node_modules\.bin\vp.cmd test run `
2 apps/desktop/src/app/DesktopEnvironment.test.ts `
3 apps/desktop/src/backend/DesktopBackendConfiguration.test.ts `
4 apps/desktop/src/wsl/DesktopWslServerTree.test.ts `
5 scripts/build-desktop-artifact.test.ts `
6 scripts/lib/cli-external-packages.test.ts

The PR-added failures are:

  • validates every ASAR-unpacked native... and rejects a sidecar whose extracted server bundle cannot resolve reach the same-arch primary probe and try to spawn the fixture's text file named t3code.exe, which fails with spawn UNKNOWN on Windows. Those cases need a mock child-process layer (or another fixture strategy) when the test is exercising validation rather than the real executable.
  • skips the primary native probe for cross-architecture Windows payloads observes an ELECTRON_RUN_AS_NODE=1 command on Windows and fails its assertion, so the host-architecture override/layer precedence is not doing what this regression expects in the actual target environment.
  • The new DesktopEnvironment sidecar assertion and DesktopBackendConfiguration primary assertion build/expect paths with literal /, so they fail against the Windows Path.Path implementation. Using the injected path service (or normalizing before comparison) would make them platform-safe.

There are additional pre-existing POSIX-path assertions in those suites, but the cases above are introduced by this PR. I would fix these so the Windows-specific regression suite is trustworthy on Windows; I did not find a new functional packaging blocker in the real artifact flow.