Skip to content

修复非 ASCII 路径下构建失败等 Windows 问题,并补上 CI - #1

Open
Tianbuyu-wwx wants to merge 2 commits into
Stry233:mainfrom
Tianbuyu-wwx:fix/windows-portability-and-ci
Open

Tianbuyu-wwx wants to merge 2 commits into
Stry233:mainfrom
Tianbuyu-wwx:fix/windows-portability-and-ci

Conversation

@Tianbuyu-wwx

@Tianbuyu-wwx Tianbuyu-wwx commented Sep 16, 2026 •

Copy link
Copy Markdown

修复非 ASCII 路径下构建失败等 Windows 问题,并补上 CI

感谢 review(以及"好夸张的行动力"😂)。以下按您提出的四点逐条回应。改动已收窄:生产日志调整(vite.config.ts)已从本 PR 移除。


1. 范围收窄

现在只包含 Windows 与公共仓库兼容性两类改动:

类别 内容
Windows / 非 ASCII 路径 .gitattributes、writeAll 改异步递归拷贝、generate-headers 的守卫、4 个受影响测试
公共仓库兼容性 公共快照缺 docs/internal/、CHANGELOG 已发布小节,脚本与测试不再把内部形态当作唯一真相
CI 新增 .github/workflows/ci.yml(ubuntu + windows,Node 24)

已移除:vite.config.ts 的 dropConsole 改动。若您有兴趣,我可以单独开一个 PR,并附上实测数据(一次生产构建会话的 console 消息计数与调用点数量)。

2. 中文路径:补了一条能复现该崩溃的测试

新增 copies licenses/ completely when the checkout path is not ASCII:把工作目录切到一个含非 ASCII 字符的临时路径再触发许可拷贝,断言的是结果的完整性(目录树逐文件一致、逐字节相同),而不是"没有抛错"。

修复前后实测(同一台机器、同一条用例):

版本 结果
修复前(fs.cpSync 递归) Worker exited unexpectedly with exit code 3221226505(即 0xC0000409,进程级中止)
修复后(fs/promises.cp) 通过,40ms

同时把原有的 copies licenses/ through 升级为 copies licenses/ through, in full:对 licenses/ 全部 185 个文件做树结构与逐字节比对(实测 ~1.4s),不再只断言"目录非空"。

CI 的 windows-latest(Node 24)会运行这两条。

3. 压缩测试:按运行环境分别钉预期,并保留完整性与大小限制检查

inflate 优先使用平台的 DecompressionStream。拼接 gzip 成员的行为按运行时不同而不同——RFC 1952 允许一个 gzip 文件由多个成员组成:

  • Node(本文件运行环境):zlib 支持的流会读完整串并返回两段(实测 Node 22.23.1 返回 2× 原始长度)
  • 浏览器:流在第一个成员处停下,对后续字节报错

原测试对两者都断言 rejects,这就是它在 Node 下失败的原因。现在按环境分别钉死:

环境 断言
Node 返回两段,且逐字节等于原始数据两次(内容完整性)
无平台流(回落自研解码器,用 vi.stubGlobal 复现) 必须拒绝,不得返回不完整缓冲
大小限制 单成员但展开后超过调用方上限 ⇒ 拒绝而非缓冲;decompress 的绝对上限仍报 safety limit

4. 几处等待时间:附上实测与失败现象

文件 原来的情况 现在的预算
canvas/object-remove-cost 单跑三条 117 / 823 / 396ms;全量并行下三条都超时 60s(与仓库其它重测试一致)
kit/generate-operation 单个生成用例实测 584–1246ms,且有成对跑"逐字节一致"的用例 60s(同仓库其它生成类测试)
legal/build-pages 完整树比对实测 ~1.4s;此前根本跑不到这里(同步拷贝先把 worker 弄崩了) 60s
ui/shell/windows 默认 5s 下该行在并行时超时;同文件相邻用例实测 8450ms 20s(仓库其它 UI 测试的既有等待值)
ui/agent/setup-readiness settle() 是固定轮数而非等条件成立;该用例实测 ~2.3s 20s

这几处没有放宽任何断言,只是把等待预算写明并给出依据(60s / 20s 都是仓库里已有的值)。另有一处 tour-overlay 的采样竞态是补 await frames(2) 让采样器看到第二个端点,不是超时。

关于合并方式

已了解:公共仓库 main 由发布流程统一更新,审核通过的改动先进入开发版本、验证后随版本发布,不直接 Squash / Rebase。如需我调整提交形态(拆分、合并,或改用补丁文件),请告知。


验证

  • npm run lint(即 tsc --noEmit):0 错误
  • 全量测试:681 文件通过 / 8761 用例通过 / 0 失败(698 文件、8838 用例)
  • 本地构建(检出路径含中文):dist/licenses 185 个文件
  • CI 覆盖 ubuntu-latest 与 windows-latest,Node 24

Six shipped guards and the release build fail on a Windows checkout, and nothing in the
repository says so because no workflow runs them. A Linux-only job cannot see any of
these, which is how they reached a release.

Path portability
- Add `.gitattributes` pinning `* text=auto eol=lf`. Git for Windows defaults to
  `core.autocrlf=true`, so a clean clone checked every text file out as CRLF and the
  byte-comparison guards failed on it: LICENSE is pinned by length (11558 vs 11357 — one
  byte per line) and by SHA-256, NOTICE's copyright line carried a trailing `\r`, and
  public/_headers, vercel.json, the index.html CSP meta and docs/ARCHITECTURE.md are all
  compared as text. Ten tests across five files failed on a fresh clone for this reason
  alone. `licenses/**` is excluded: those files are copied verbatim from the shipped
  packages and several upstream LICENSE files are CRLF, so normalising them would make the
  committed copies differ from what `npm run legal:licenses` produces.
- `legal-pages-core`: `writeAll` is async and copies `licenses/` with `fs/promises.cp`. The
  SYNCHRONOUS recursive copy aborts the process (0xC0000409) whenever the SOURCE path holds
  any non-ASCII character, so `npm run build` could not complete from a checkout under a
  path like `E:\项目\…` — it exited 127 with an EMPTY `dist/licenses`, dropping all 185
  third-party licence files the legal pages link to, and it killed the build-pages worker
  outright. `build-legal-pages.mts` awaits it; the tests do too.
- `generate-headers`: guard the ESA deployment doc on `docs/internal/` existing. The public
  snapshot does not carry that tree, so `--check` reported permanent drift and
  `npm run legal:headers:check` failed on every clone.
- `operation-purity` exempted three macro bindings by POSIX suffix while building paths with
  `path.join`, so on Windows the exemption never applied and the three intended files were
  reported as offenders. Offender paths are reported POSIX-normalised as well.

Diagnostics
- `vite.config`: drop `dropConsole`. Oxc's transform is all-or-nothing and cannot tell a
  library's log from a failure report, so it also removed the editor's own error reports and
  the console banner `console-banner.ts` prints on purpose. Measured on a production build,
  a session of boot → draw → generate → 3D → open export emits two console messages and both
  are the app's own; the library call sites that remain in the bundle do not fire in use.

Guards that failed for reasons of their own
- `compression-compat` asserted a native stream rejects concatenated gzip members. Browsers
  do; Node's zlib-backed stream does not, and RFC 1952 allows a gzip file to be a sequence of
  members. It now pins the invariant that holds either way — the output cap — and documents
  the divergence rather than assuming one runtime's behaviour.
- `root-docs` asserted the changelog was still STAGED (`## [Unreleased]`, no released
  heading) while the repository has published to v1.1.15. It now pins what holds in both
  states: at most one staged heading, and every released heading well formed.
- Budgets the suite's own comments already called tight are now stated rather than inherited:
  `object-remove-cost` (sprite construction in jsdom), `build-pages` (a real 185-file licence
  copy, which these tests never reached before because the crash came first),
  `generate-operation` (21 full generations, several as a determinism pair),
  `agent/skills`-adjacent Help chunk in `windows.test.tsx`, and the lazy Help chunk's dialog.
- `windows.test.tsx`, `chrome/tour-overlay` and `agent/setup-readiness` read an async surface
  in a single turn: the menu's rows, a sampler's second endpoint, and a panel handover driven
  by a fixed number of settle turns. Each now waits for what it asserts.

CI
- `.github/workflows/ci.yml` runs type-check, tests, build and the drift guards on ubuntu and
  windows, with actions pinned by SHA and the Node floor read from `.node-version`. Windows is
  in the matrix on purpose: it is the only place the first two fixes above are observable.

Verified on the committing machine (Windows, checkout under `E:\项目\PetitMaker`):
`npm run lint` clean; `npm run test:run` 8760 passed, no failures, no crashed workers — the
same suite reported 17 failures plus a worker crash before; `npm run build` exits 0 with all
185 licences copied into `dist/licenses`, where the identical command exited 127 with an empty
`dist/licenses` before; `stamp:check`, `docs:check`, `legal:licenses:check`,
`legal:headers:check` and `legal:validate` all pass.

Signed-off-by: 天不语 <2364309541@qq.com>
@Tianbuyu-wwx Tianbuyu-wwx reopened this Sep 16, 2026
@Tianbuyu-wwx Tianbuyu-wwx changed the title Hold the guards and the build on Windows, and add CI 修复非 ASCII 路径下构建失败等 Windows 问题,并补上 CI Sep 16, 2026
@Stry233

Stry233 commented Sep 17, 2026

Copy link
Copy Markdown
Owner

感谢!好夸张的行动力 (゚∀。)。已经完成了这次改动的review。我的结论是换行符、Windows 路径,以及公共仓库中的校验脚本问题,都值得修复。

这次 PR 同时涉及兼容性修复、生产日志和测试行为调整,范围比较大。建议先保留 Windows 和公共仓库兼容性相关改动,将生产日志调整单独讨论。中文路径的问题,方便的话能否补一个 Windows + Node 24 下的测试,确认复制操作正常完成且文件完整?压缩测试希望明确区分不同运行环境的预期结果,并保留内容完整性和输出大小限制的检查。几处等待时间的调整,也请补充原来的耗时或失败现象,方便判断是否需要延长。

另说明一下贡献的接收方式:公共仓库的 main 由发布流程统一更新。审核通过的改动会先整合到开发版本,完成验证后随版本发布,因此这里不会直接使用 Squash 或Rebase 合并。我们会在本 PR 中说明最终采纳的内容,并链接对应的公开发布记录。

目前贡献指南对这个流程说明得还不够清楚,我们会补充。再次感谢🙏!

@Tianbuyu-wwx

Copy link
Copy Markdown
Author

感谢大佬的回复,请稍等一下我将补充测试重新按流程提交❍⩊❍

另外我感觉AI部分其实有些可以优化的地方:
1.比如显示思考时可以默认滑动到输出的底端,在用户有操作时才保持在用户滑动到的位置
2.可以加入更多的模型提供商比如DeepSeek来减少操作,甚至可以默认路由一些各个平台的免费模型来当做免费的AI提供使用,减少门槛,(如openrouter有免费模型,针对免费模型智力的问题可以专门写提示词或使用其他方法)
3.在思考模式为最高时实测执行非常慢,而且在某些模型上效果也不太好(这里特指ds),缓存命中率也非常低(如图)
4.已完成被折叠的计划步骤不可以回看,已打开的计划步骤无法折叠
5.或许可以将现有的AI辅助建造继续改进,继续优化skill,当用户让AI列方案时可以使用选项卡加图片的形式给用户预览选项而不是纯文字(如图,你们其实已经做了)
6.或许可以试试直接使用生成器生成地图?

我会持续使用网站进行测试,另外尝试对AI部分进行优化,到时候我再交一份PR。

最后再次感谢大佬的观看,我的QQ是2364309541,一二测还有三测的名字应该都是天不语,欢迎大佬三测来我家玩(^ω^)

Screenshot_20260917_120615 Screenshot_20260917_120333

Scope is now the Windows and public-repository compatibility fixes only. The
production logging change to vite.config.ts is out of this PR.

The non-ASCII path has a test that reproduces the abort: the license copy is
driven from a working directory holding non-ASCII characters, and the
assertions are about the COMPLETE result — same tree, same bytes — rather than
that the call returned. Before the fix it kills the worker with exit code
3221226505; after it passes in 40ms. The existing copy test now compares all
185 files byte for byte instead of asserting the directory is non-empty.

The concatenated-member case pins an answer per environment instead of
accepting either one: Node's platform stream reads the sequence of members
RFC 1952 defines and returns both (measured: 2x the payload), so that is
asserted with byte-for-byte content, while the no-platform fallback is driven
with the streams stubbed and must refuse rather than hand back a partial
buffer. The output cap is checked on its own, with a payload that trips it.

Every wait budget now states what was measured and what was seen to fail:
117/823/396ms for object-remove-cost with timeouts under a parallel run,
584-1246ms per generation case in generate-operation, ~1.4s for the full
license-tree comparison, 8450ms for a neighbouring case in windows.test, and
~2.3s for the setup handover. No assertion was loosened.

Signed-off-by: 天不语 <2364309541@qq.com>
@Stry233

Stry233 commented Sep 17, 2026

Copy link
Copy Markdown
Owner

谢谢!相关建议我同步到反馈频道上了(https://pd.qq.com/g/pd76247629, 欢迎加入),为方便追踪,可以给它们单开一些issue(我就不代劳啦,毕竟是你的contribution~),针对其中几点,我可以提一些我的想法

  1. 没问题,这个我可以在下一版里实现一下
  2. 这个从威胁模型的角度上看不一定能很安全的实现,考虑到资源滥用,审查成本和网络攻击等因素,这个系统一开始的设计就是0后端的,如果我们要默认路由一些模型,这就意味着API key需要明文写在前端里,这不符合安全惯例,将API key分发给多实体可能也不符合相关平台的协议。不过这块我可以再研究一下~
  3. 这里我其实没有太多的方法,这个项目没有什么后训练或部署的流程,模型本身受限于提供商,可能只能在harness上做一些额外的工作,但我认为是很有限的
  4. 了解,这个也可以简单优化一下UX
  5. 是的,我们内部迭代了一版harness rsi的框架,最近正在部署到实际环境中,之后几版应该会看到一些变化
  6. 这个其实我们已经试过了,很遗憾如果直接将生成器直接连入agent,那agent会开始拼了命的偷懒😂,什么任务都是靠生成器抽奖来完成,所以在部署时我们刻意关闭了agent对程序化生成器的访问

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.

2 participants