Skip to content

Fix Windows build: exclude pi-coding-agent from packaged app#3727

Closed
wojtekn wants to merge 4 commits into
trunkfrom
fix-windows-path-too-long
Closed

Fix Windows build: exclude pi-coding-agent from packaged app#3727
wojtekn wants to merge 4 commits into
trunkfrom
fix-windows-path-too-long

Conversation

@wojtekn

@wojtekn wojtekn commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Related issues

Follows up on #3707 (migrate @mariozechner/pi-* to @earendil-works/pi-*).

How AI was used in this PR

Claude Code diagnosed the root cause and wrote the fix.

Proposed Changes

After #3707 landed, the Windows Squirrel build started failing with:

The specified path, file name, or both are too long. The fully qualified file name
must be less than 260 characters, and the directory name must be less than 248 characters.

Root cause: @earendil-works/pi-coding-agent is a devDependency of apps/studio (only needed for import type { SessionEntry } — erased at compile time). However, after install:bundle runs npm install --no-workspaces, galactus (electron-packager's DestroyerOfModules) doesn't reliably prune the nested node_modules under pi-coding-agent. Its transitive @mistralai/mistralai dependency contains filenames like getchatcompletionfieldoptionscountsv1observability...post.js that reach 200+ chars on their own. With the Windows build agent prefix (C:\buildkite-agent\builds\ci-windows-...\automattic\studio\) the total path hits ~295 chars — 35 over the 260-char limit.

The fix adds an explicit ignore pattern to forge.config.ts so electron-forge never copies pi-coding-agent into the packaged output, regardless of whether the devDep prune works. This is a belt-and-suspenders approach since the package should already be excluded as a devDep.

Testing Instructions

  • Windows build should pass (Squirrel maker no longer encounters long paths)
  • macOS and Linux builds unaffected (no 260-char path limit)
  • App functionality unchanged — pi-coding-agent was only imported for TypeScript types, not included at runtime

Pre-merge Checklist

  • I have checked this code is correct to the best of my ability
  • I have tested this change on a supported platform
  • My changes generate no new deprecation warnings

… path-too-long error

@earendil-works/pi-coding-agent is a devDependency used only for TypeScript
types (import type). Its transitive @mistralai/mistralai dep contains filenames
like getchatcompletionfieldoptionscountsv1...post.js that, when nested under
pi-coding-agent/node_modules/, exceed Windows' 260-char path limit and cause the
Squirrel/NuGet maker to fail.

galactus (DestroyerOfModules) should prune devDeps from the packaged output, but
after install:bundle's standalone npm install the pruning doesn't reliably remove
the nested node_modules. Adding an explicit forge ignore pattern is a reliable
safety net.
@wojtekn wojtekn requested review from a team and youknowriad June 8, 2026 16:19
@wpmobilebot

wpmobilebot commented Jun 8, 2026

Copy link
Copy Markdown
Collaborator

📊 Performance Test Results

Comparing b4b995d vs trunk

app-size

Metric trunk b4b995d Diff Change
App Size (Mac) 1384.35 MB 1384.35 MB +0.00 MB ⚪ 0.0%

site-editor

Metric trunk b4b995d Diff Change
load 1604 ms 1643 ms +39 ms ⚪ 0.0%

site-startup

Metric trunk b4b995d Diff Change
siteCreation 9063 ms 9026 ms 37 ms ⚪ 0.0%
siteStartup 4407 ms 4414 ms +7 ms ⚪ 0.0%

Results are median values from multiple test runs.

Legend: 🟢 Improvement (faster) | 🔴 Regression (slower) | ⚪ No change (<50ms diff)

wojtekn added 3 commits June 8, 2026 20:07
electron-winstaller ships nuget.exe v4.0, which predates long-path support.
Long paths require nuget.exe >= 4.8 AND the LongPathsEnabled registry key.
Download the latest nuget.exe at build time to satisfy both conditions.

Also removes the forge ignore workarounds for pi-coding-agent, react-native
and @react-native that were added to work around the old NuGet limitation.
Write-Host "--- :windows: Enabling long path support"
New-ItemProperty -Path "HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem" `
-Name "LongPathsEnabled" -Value 1 -PropertyType DWORD -Force
If ($LastExitCode -ne 0) { Exit $LastExitCode }

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. The AMI already should enable long paths with these instructions:

Write-Output "Enable long path behavior"
# See:
#
# - https://docs.microsoft.com/en-us/windows/desktop/fileio/naming-a-file#maximum-path-length-limitation
# - https://support.atlassian.com/bamboo/kb/git-checkouts-fail-on-windows-with-filename-too-long-error-unable-to-create-file-errors/
Set-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\FileSystem' -Name 'LongPathsEnabled' -Value 1
git config --system core.longpaths true

I see this command adds -PropertyType DWORD -Force which maybe should be pushed upstream to the AMI, too.

However, it's hard to tell whether the issue is with the original command or with electron-winstaller below. That is, I wonder if the latest stable version of that package will work without the additional params in the long-path configuration.

@mokagio

mokagio commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Discovered with Claude: The LongPathsEnabled registry key does not seem to reach the binary that's actually throwing.

The failure is in Squirrel's bundled Update.exe, which uses the legacy .NET Framework path handling. The stack trace from build 17201 suggest it:

System.AggregateException: One or more errors occurred.
 ---> System.IO.PathTooLongException: The specified path, file name, or both are too long.
      The fully qualified file name must be less than 260 characters, and the directory
      name must be less than 248 characters.
   at System.IO.Path.LegacyNormalizePath(String path, Boolean fullCheck, Int32 maxPathLength, Boolean expandShortPaths)
   at System.IO.Path.InternalGetDirectoryName(String path)
   at Squirrel.ReleasePackage.<>c__DisplayClass14_0.b__0()
   at System.Threading.Tasks.Task.Execute()
   --- End of inner exception stack trace ---
   at Squirrel.ReleasePackage.CreateReleasePackage(String outputFile, String packagesRootDir, ...)
   at Squirrel.Update.Program.Releasify(...)
   at Squirrel.Update.Program.main(String[] args)

The key frame is System.IO.Path.LegacyNormalizePath.

@mokagio

mokagio commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

I researched an alternative with AI and pushed it in #3735

@wojtekn

wojtekn commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

Closing in favor of #3735

@wojtekn wojtekn closed this Jun 9, 2026
wojtekn added a commit that referenced this pull request Jun 9, 2026
<!-- blue -->
> [!NOTE]  
> @wojtekn this JS/TS manipulation of the Electron build structure is
outside my area of expertise, so it's possible the result is a big AI
slop. At the same time, it does seem to address the build failure issue
with the long path, so it might be a good place to start.
>
> I'm having my agent address the Copilot comments now. Next step will
be to get a different one to look over the work for possible
improvements.

## Related issues

- Related to #3727 (alternative fix for the same Windows
`PathTooLongException`)

## How AI was used in this PR

Claude Code (Opus 4.8) diagnosed the root cause from the CI logs,
verified the fix empirically against a reproduced bundle tree, and wrote
the prune script and tests. I reviewed the analysis and the diff.

## Proposed Changes

The Windows Squirrel maker crashes with `PathTooLongException` while
packing the app. The real cause is `@earendil-works/pi-coding-agent`'s
transitive `@mistralai/mistralai` — a speakeasy-generated SDK whose
~200-char filenames, nested under `pi-coding-agent/node_modules`, exceed
Windows' 260-char path limit. The AWS Bedrock SDK (`@aws-sdk`/`@smithy`)
overflows the same way.

These are **lazy, dynamically-imported** `pi-ai` providers, and Studio
only ever exposes the **Anthropic and OpenAI** model families
(`tools/common/ai/models.ts`). Mistral, Bedrock and Google are therefore
unreachable dead weight. This strips them from the bundled CLI during
packaging, which:

- fixes the path limit — **183 over-limit files → 0** (worst path drops
to 236 / 260), and
- reclaims tens of MB from the installer.

A missing provider degrades gracefully through pi-ai's lazy loader, so
removing them is safe.

> Note: this is an alternative to #3727, opened in parallel rather than
stacked because that PR's commits (forge `ignore`, registry key,
`nuget.exe` swap) are no-ops for this failure — the exception is thrown
by Squirrel's legacy `Update.exe` (`Path.LegacyNormalizePath`), which
the `ignore`/registry/nuget levers don't reach. See #3727 for that
analysis.

## Testing Instructions

- `npm test -- --project scripts` — unit tests for the prune (removes
targets in hoisted + nested locations; keeps Anthropic/OpenAI and
unrelated `@google/*`).
- Verified end-to-end against a reproduced bundle install:
`pruneUnusedProviders` removed every offender at both the top level and
under `pi-coding-agent`, taking over-260 files from 183 to 0.
- The Windows build (`make:windows-*`) should now pass the Squirrel
maker; macOS/Linux unaffected (and benefit from the smaller bundle).

## Pre-merge Checklist

- [x] Have you checked for TypeScript, React or other console errors?
(`npm run typecheck` and `eslint` pass)

---

*Authored by Claude (Opus 4.8) on behalf of @mokagio with approval.*

---------

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
Co-authored-by: Wojtek Naruniec <wojtek@naruniec.me>
Co-authored-by: Wojtek Naruniec <wojtek.naruniec@automattic.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.

3 participants