7 Commits
Author SHA1 Message Date
sunsunsun 85dea36952 fix: harden Windows path publication contracts 2026-09-18 23:47:26 +08:00
sunsunsun 6ee68078a0 fix: close Windows path contract review gaps 2026-09-18 22:10:08 +08:00
sunsunsun b0b62c0ec5 fix: unify cross-platform path contracts 2026-09-18 20:44:14 +08:00
Chaoran Hu 93ffea49f0 fix(packaging): make the canonical archify.zip reproducible on Windows (#385)
* fix(packaging): accept Windows-style absolute output paths in build-zip.sh

On Git Bash, `scripts/build-zip.sh C:\path\out.zip` (or `C:/...`) exited
with ENOENT: the script treated any path not starting with `/` as relative
and prepended `$(pwd)/`, and MSYS then handed Node a mixed path such as
`D:\repo\C;C:\Program Files\Git\Users\...`. Skip the prefix for drive paths,
which Node resolves natively, and add a win32-only regression test.

The repository's own package-gate tests pass os.tmpdir() paths, so on a
clean Windows checkout two of them failed before building anything.

* fix(packaging): record Git index modes so archify.zip reproduces on Windows

scripts/write-deterministic-zip.mjs derived each entry's mode from
fs.stat(), but NTFS cannot store an executable bit: after the stager's
chmod(0o755), stat() still reports 0o666 on Windows, so
archify/bin/archify.mjs (index mode 100755) was written as 0644 and the
archive differed from the committed bytes in four central-directory
bytes while every payload matched.

The stager now records every staged file's Git index mode in a manifest
outside the staged tree (--mode-manifest), the writer requires that
manifest and fails closed when it disagrees with the staged files, and
build-zip.sh passes it between them. Linux bytes are unchanged; together
with the output-path fix in the previous commit, a Windows rebuild is now
byte-identical to archify.zip.

Refs #384

* fix(packaging): harden output-path and mode-manifest handling from review

- build-zip.sh also passes \\-prefixed absolute paths (UNC shares, the
  device namespace) through untouched instead of prefixing the cwd.
- stage-clean-skill.mjs compares the manifest and destination by their
  physical locations (existing ancestors resolved through symlinks),
  refuses a manifest path that already exists, creates the manifest
  exclusively, and removes it on failure only when this invocation
  created it.
- Tests: the Windows path regression also builds through a \\.\ device
  path; the stager suite covers an existing manifest path and a
  symlinked-ancestor alias on both sides.

Addresses the CodeRabbit findings on #385.

Refs #384
2026-09-12 10:15:44 +08:00
sunsunsun 50e2e63d77 fix(zip): pin canonical toolchain and ZIP32 bounds 2026-08-26 22:22:59 +08:00
sunsunsun eed82c9ebd build(zip): protect canonical archive publication 2026-08-26 20:55:44 +08:00
sunsunsun 99564e0c8d build(zip): make canonical archive reproducible 2026-08-26 20:13:07 +08:00