feat(e2e): claude-code smoke with Zstd + tar.gz + archive verify#12
Merged
robertsLando merged 9 commits intomainfrom Apr 23, 2026
Merged
feat(e2e): claude-code smoke with Zstd + tar.gz + archive verify#12robertsLando merged 9 commits intomainfrom
robertsLando merged 9 commits intomainfrom
Conversation
- Add `Zstd` to the compress-node enum (core/inputs.ts), regenerate action.yml / packages/build/action.yml / docs/inputs.md, rebundle dist. Zstd requires Node.js >= 22.15 on the build host. - New `claude-code-smoke` e2e job: installs @anthropic-ai/claude-code from npm, builds via SEA mode with compress-node=Zstd + tar.gz + sha256 on ubuntu-x64/arm64, macos-arm64, windows-x64. Runs the binary with `claude --version`, then recomputes the sha256 against the sidecar and extracts the tarball to re-verify --version on the archived copy. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- @anthropic-ai/claude-code >= 2.1.117 ships as a thin wrapper that delegates to a native binary via optionalDependencies; pkg can't bundle that. Pin 2.1.114, the last release whose `bin.claude` points at a real `cli.js`. - pkg 6.17 is the first yao-pkg/pkg to accept `--compress Zstd`; the action's default pkg-version (~6.16.0) rejected it with "Invalid compression algorithm Zstd". Override to ~6.18.0 for this job. - Resolve `pkg.bin.claude` explicitly (instead of Object.values()[0]) so a future per-OS alias can't steer us at the wrong entrypoint. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR extends the action’s compress-node input to support Zstd compression and adds a new real-world E2E smoke workflow job that builds and validates a SEA-packaged @anthropic-ai/claude-code binary across multiple OS/arch runners.
Changes:
- Add
Zstdtocompress-nodeinput parsing/types, plus regeneratedaction.yml,packages/build/action.yml, docs, and bundleddist/artifacts. - Add unit test coverage ensuring
parseInputsaccepts canonicalZstd(and still rejects lowercasezstd). - Add
claude-code-smokeE2E job that builds a SEA binary withcompress-node: Zstd+tar.gz, runs--version, then verifies archive integrity and checksum sidecar.
Reviewed changes
Copilot reviewed 6 out of 8 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
packages/core/src/inputs.ts |
Adds Zstd to input description, type union, and enum parsing. |
packages/core/test/unit/inputs.test.ts |
Adds unit test ensuring Zstd is accepted and validates case-sensitivity behavior. |
.github/workflows/e2e.yml |
Adds claude-code-smoke job to build/run/verify an archived SEA binary across OS/arch matrix. |
action.yml |
Regenerated input docs to include Zstd in compress-node description. |
packages/build/action.yml |
Regenerated input docs to include Zstd in compress-node description. |
docs/inputs.md |
Regenerated inputs documentation for compress-node: Zstd. |
packages/build/dist/index.mjs |
Rebundled dist reflecting new compress-node enum value and description. |
packages/windows-metadata/dist/index.mjs |
Rebundled dist reflecting updated compress-node description. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- 2.1.113 already switched @anthropic-ai/claude-code from a pure-JS cli.js entrypoint to a native-binary wrapper (bin/claude.exe). My earlier pin of 2.1.114 landed inside the new layout, so pkg was compiling a shell-script placeholder that errors at runtime. 2.1.112 is the last pure-JS release — verified locally with SEA+Zstd: builds in ~20s, binary runs and prints "2.1.112 (Claude Code)" on --version. - Previous `--version` step captured output via `out=$(... 2>&1)` under `set -e`, which aborted before echoing when the binary exited non- zero (as it did on every runner). Suspend `set -e` around the capture so the logs actually show what the binary printed. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Surfaced by the new claude-code-smoke e2e: - macOS: the macos-latest runner's bsdtar rejects `--mtime` outright with "Option --mtime is not supported", even though upstream libarchive accepts it. The action was always passing --mtime; tiny- cjs never hit this because its macOS matrix entry uses zip. Keep --mtime on GNU tar (linux) only; rely on the utimes pre-pin for bsdtar paths (archive() is single-file, so the header inherits that mtime). Test updated to assert --mtime presence only on linux. - Windows: git-bash's `sha256sum` escapes the output line with a leading backslash when the filename contains backslashes (Windows paths), per GNU coreutils convention. The e2e's verify step was comparing `\<digest>` against the sidecar's clean hex. Strip the leading backslash via sed before parsing. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GNU tar from git-bash parses `D:\a\...` as a remote host:path target
(colon-separated rsh syntax), producing:
tar (child): Cannot connect to D: resolve failed
Convert any Windows drive-letter path to the POSIX form (`/d/a/...`)
via cygpath before invoking tar. No-op on Linux/macOS — falls back to
echo when cygpath isn't on PATH. --version + sha256 sidecar check
already passed on Windows in the previous run; this unblocks the
tar-round-trip tail.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Review follow-ups on #12: - Guard the pin: assert the resolved bin entry is a JS file (.js/.mjs/ .cjs) before patching it into the fixture package.json. If the @anthropic-ai/claude-code pin ever drifts past 2.1.112 into the native-binary wrapper layout (bin → bin/claude.exe shell-script placeholder), fail loudly rather than bundling garbage. - Replace the ad-hoc `${fix//\\//}` backslash-strip with the same cygpath helper used in the verify step, so the fixture path emitted to GITHUB_OUTPUT is always POSIX-form on Windows git-bash. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…mpatible Reverting the $fix cygpath conversion from 3fca6c7. cygpath -u emits POSIX form (/d/a/...), which GNU tar in git-bash handles correctly but Node's fs on Windows misparses as drive-relative, producing paths like D:\d\a\_temp\... and failing with ENOENT. The composite's build step is Node-based, not shell-tar-based, so it wants the drive-letter- plus-forward-slash form (D:/a/...) that ${fix//\\//} produces. cygpath stays in the verify step where tar is the consumer — different tool, different path convention. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Surfaced by matrix e2e debugging: the orchestrator emitted every pkg argv twice (once as "[pkg-action] pkg …" in main.ts, once as "[pkg-action] Invoking: …" from the runner) and was silent through the finalize stages — no signal for when archive started, when the checksum was computed, or which shasum files were written. - Drop the main.ts pre-log; runPkg's "Invoking:" already carries the command path, and GH Actions renders the raw `[command]` line too, so three copies was overkill. - Log pkg wall time after runPkg completes. - Group the per-target finalize loop under a `logger.startGroup` so each target collapses into its own fold in the GH Actions UI — matters for matrix runs where 4+ targets interleave. - Add explicit archive/checksum progress lines with sizes + timings (`archive → …`, `archived … (17.8 MB, 4.2s)`, `sha256 <digest> <file>`) so any downstream verification failure trivially diffs against the build log. - Log each SHASUMS file as it's written, with entry count. - Include overall wall time in the final "done" line. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The pkg CLI emits ~15–30 lines per build (Walking dependencies, node download/extract, SEA asset generation, blob injection, strip warnings) and the GH-Actions exec shim adds `[command]` echo on top. On a multi- target run all of that interleaved with finalize output is hard to skim. Wrap runPkg in startGroup/endGroup with a header that names the target list, so reviewers see a single collapsible "pkg build (targets=…)" block followed by the one-line wall-time summary. Same pattern we already use for the per-target finalize blocks. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
robertsLando
added a commit
that referenced
this pull request
Apr 23, 2026
Main (PR #12) wired the claude-code-smoke job through the action using `mode: sea` and `compress-node: Zstd` inputs. Those inputs no longer exist on this branch, so move both values into the package.json#pkg field that the fixture-prep step already injects. No behavior change on main; on this branch the e2e now exercises the pkg-config path the slim input surface forces users onto.
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.
Summary
Zstdto thecompress-nodeinput enum inpackages/core/src/inputs.ts(+ regeneratedaction.yml,packages/build/action.yml,docs/inputs.mdviayarn gen, rebundled dist). Zstd requires Node.js ≥ 22.15 on the build host —.node-versionalready pins 22.22.claude-code-smokee2e job that pulls@anthropic-ai/claude-codefrom npm, builds a native binary per runner with SEA +compress-node: Zstd+compress: tar.gz+ sha256 checksum, then runsclaude --versionon the binary and on the tar-extracted copy..tar.gzextension, extracts the tarball, and re-runs--versionon the extracted binary.Test plan
yarn test— 225/225 pass, including newparseInputs accepts Zstd compress-nodecaseyarn lint— cleanyarn gen+yarn build— committed outputs match source (codegen-drift job will re-verify on CI)claude-code-smokejob green on all 4 runners (ubuntu x64, ubuntu arm64, macos arm64, windows x64)🤖 Generated with Claude Code