250 Commits

Author SHA1 Message Date
Zoltan Kochan
86af5326ff ci(pacquet): scope the e2e run to the pnpm package only
Now that --no-runtime fixed the VM-modules loader, tests actually run.
The next failure mode was real: other workspace packages (e.g.
@pnpm/building.commands) shell out to pnpm in their tests, and
PNPM_E2E_BIN routes those calls through pacquet, which doesn't
implement every command they exercise. Add a dedicated
test-pkgs-pnpm script so the e2e job runs jest only in the pnpm
package and PNPM_E2E_BIN affects nothing else.

Written by an agent (Claude Code, claude-opus-4-7).
2026-05-21 22:12:34 +02:00
Zoltan Kochan
43d8c05697 ci(pacquet): pass --no-runtime to pnpm install
test.yml's working install path uses --no-runtime so pnpm doesn't try
to materialize an executionEnv runtime that conflicts with the one
pnpm/setup pinned. The competing runtime install is the last
discoverable difference between this job and the standard e2e job.

Written by an agent (Claude Code, claude-opus-4-7).
2026-05-21 22:03:39 +02:00
Zoltan Kochan
3a948505f7 ci(pacquet): disable verifyDepsBeforeRun for the test step
pnpm-workspace.yaml sets verifyDepsBeforeRun: install, so every script
gets a re-install side effect before it runs. test.yml's standard e2e
job sets pnpm_config_verify_deps_before_run: false to disable this;
without that override the auto-reinstall seems to leave the loader in
the state that triggers jest's "module is already linked".

Written by an agent (Claude Code, claude-opus-4-7).
2026-05-21 21:49:41 +02:00
Zoltan Kochan
397a400d29 ci(pacquet): call .test through the test-pkgs-all script chain
pnpm's hidden-script guard fires when \`pn -r .test\` is the top-level
shell command but not when the same call lives inside another script.
Driving the run through \`pn run test-pkgs-all\` (which then chains into
\`pn -r .test\` internally) is the call shape main CI uses successfully.

Written by an agent (Claude Code, claude-opus-4-7).
2026-05-21 21:37:32 +02:00
Zoltan Kochan
5d24e2e7cd ci(pacquet): drop --filter so pn -r can call the hidden .test script
Adding --filter=pnpm re-enabled pnpm's hidden-script guard and broke the
invocation with ERR_PNPM_HIDDEN_SCRIPT. Recursive mode bypasses that
guard on its own; --if-present silently skips workspace packages that
don't define .test, so the unfiltered form does the right thing.

Written by an agent (Claude Code, claude-opus-4-7).
2026-05-21 21:28:56 +02:00
Zoltan Kochan
5a04ddb96b ci(pacquet): invoke .test via pn -r so the call shape matches test.yml
test.yml's standard e2e job drives the same jest config successfully via
\`pn -r .test\`, which executes the hidden \`.test\` script under pnpm's
spawn path. Running jest directly (pnpm exec, ./node_modules/.bin/jest,
etc.) hits the \`module is already linked\` VM-modules regression for
reasons that aren't clear yet but seem tied to that spawn path.

Written by an agent (Claude Code, claude-opus-4-7).
2026-05-21 21:20:10 +02:00
Zoltan Kochan
6dce0847d4 ci(pacquet): run tsgo --build from pnpm/
The repo root has no tsconfig.json — tsgo needs to start from
pnpm/tsconfig.json so it can walk the project references and build
all the workspace packages the e2e tests import.

Written by an agent (Claude Code, claude-opus-4-7).
2026-05-21 21:09:22 +02:00
Zoltan Kochan
1e606e2fdf ci(pacquet): run jest under pnpm's pinned runtime to match the standard e2e job
Earlier attempts to drive the suite under the runner's own Node (or a
separately-installed Node from actions/setup-node) all tripped jest's
"module is already linked" VM-modules regression. The working pattern
test.yml uses for the standard e2e job is to pin a runtime through
pnpm/setup and run jest via `pn` so it inherits that Node — the suite
already passes there on 22.13.0.

PNPM_E2E_BIN points at pacquet, so `dist/pnpm.mjs` is never read; we
can skip the bundle step (and with it the `pnx node@runtime:24.6.0`
collision) and run only `tsgo --build` to produce the lib/ outputs
the tests import from.

Written by an agent (Claude Code, claude-opus-4-7).
2026-05-21 21:02:25 +02:00
Zoltan Kochan
815e8f6d42 ci(pacquet): pass --runInBand so jest's VM-modules loader stays in one process
With --experimental-vm-modules and multiple worker processes the same
module ends up linked twice and every suite errors with "module is
already linked". The base config's maxWorkers: 1 keeps file execution
sequential but still spawns worker processes; --runInBand forces the
main process to do everything, which is what the VM-modules path
expects.

Written by an agent (Claude Code, claude-opus-4-7).
2026-05-21 20:50:37 +02:00
Zoltan Kochan
01fcfccc50 ci(pacquet): resolve the jest shim from the workspace root
pnpm hoists the jest .bin shim to the monorepo root rather than to
pnpm/, so the previous relative path 404'd.

Written by an agent (Claude Code, claude-opus-4-7).
2026-05-21 20:40:14 +02:00
Zoltan Kochan
4564af4c24 ci(pacquet): exec the jest shim directly so PATH Node 22.13.0 runs it
`node $(which jest)` tried to feed Node the shell shim and crashed with
SyntaxError. Calling the shim directly lets it `exec node` against
PATH, which is the pinned 22.13.0 — the same trick that side-steps
pnpm exec's embedded Node 24.x.

Written by an agent (Claude Code, claude-opus-4-7).
2026-05-21 20:30:18 +02:00
Zoltan Kochan
c941f6ab12 ci(pacquet): run jest under the pinned Node, not pnpm exec's embedded one
`pnpm exec jest` was still hitting the "module is already linked"
regression because pnpm spawns under its own embedded Node 24.x
regardless of what `actions/setup-node` puts on PATH. Resolve the jest
script path through pnpm but invoke it directly with `node`, so the
pinned Node 22.13.0 is the one that actually runs the suite.

Written by an agent (Claude Code, claude-opus-4-7).
2026-05-21 20:20:24 +02:00
Zoltan Kochan
e37b694951 ci(pacquet): pin Node 22.13.0 on PATH for the jest step
The runner image's Node 24.x patches trip jest's ESM VM-modules path
with "module is already linked", failing all suites before any test
runs. Bundling still needs the runner's Node so `pnx node@runtime:24.6.0`
can resolve, so the pin is added after `pn compile-only` and only
affects the test step.

Written by an agent (Claude Code, claude-opus-4-7).
2026-05-21 20:10:53 +02:00
Zoltan Kochan
3e138137cb ci(pacquet): use the runner Node so pnx node@runtime:24.6.0 can resolve
Pinning the action's `runtime:` to Node 22.13.0 broke `pn bundle`'s
`pnx node@runtime:24.6.0 bundle.ts` call with
ERR_PNPM_NO_IMPORTER_MANIFEST_FOUND — the on-demand runtime fetch
collides with the pre-installed one. ci.yml's compile job already
demonstrates the working pattern: leave runtime unset, drive
compilation through `pn compile-only`.

Written by an agent (Claude Code, claude-opus-4-7).
2026-05-21 20:00:15 +02:00
Zoltan Kochan
19d5d714c7 test(pnpm): run e2e suite against pacquet via PNPM_E2E_BIN
The pnpm CLI e2e tests already exercise the bundled `pnpm.mjs` end-to-end,
so they can serve as a parity probe for the Rust port too. A new
`PNPM_E2E_BIN` env var swaps the spawned binary in `execPnpm`/`execPnpmSync`/
`spawnPnpm`, and a `skipIfPacquet` helper gates the per-test cases that
the port doesn't yet pass. Every failing test in the existing suite was
marked from a local sweep against `target/release/pacquet`; pacquet-CI
gets a new job that builds the binary, builds the pnpm bundle, and runs
jest with the env var set so future regressions surface in CI.

Written by an agent (Claude Code, claude-opus-4-7).
2026-05-21 19:46:53 +02:00
Zoltan Kochan
f279d77d60 fix(pacquet/cli): patch --version literal during release build (#11812)
The `pacquet --version` string is a hardcoded clap attribute in
`cli_args.rs`. It didn't get bumped for the 0.2.2 release, so the
published binary still reports 0.2.1. Bump the literal to 0.2.2 and
add a release-workflow step that rewrites the attribute from
`inputs.version` before `cross build`, so future releases stay
correct automatically. A trailing `grep -F` fails the job loudly if
the regex stops matching after a future refactor of the attribute.
2026-05-21 14:02:45 +02:00
Zoltan Kochan
b206a15395 feat(installing): delegate fetch / import / link to pacquet when configured (#11734)
When `configDependencies` declares pacquet (under either the unscoped `pacquet` or the scoped `@pnpm/pacquet` alias), pnpm delegates the fetch / import / link / build phases of an install to the pacquet Rust binary. Pnpm keeps owning dependency resolution — pacquet's resolver isn't ready yet — and hands pacquet a freshly-written lockfile to materialize.

Covered install shapes:

- frozen install (`tryFrozenInstall` → pacquet, no resolve needed)
- default isolated `nodeLinker` (`installInContext`: lockfileOnly resolve via JS, then pacquet)
- hoisted `nodeLinker` (same resolve-then-materialize shape)
- workspace partial install (subset of workspace projects mutated)
- agent-server install (`@pnpm/agent.client` resolves, pacquet materializes)

```yaml
# pnpm-workspace.yaml
configDependencies:
  "@pnpm/pacquet": "^0.2.0"     # or unscoped `pacquet`
```

## How it works

- `installing/commands/src/runPacquet.ts` resolves the platform binary via `createRequire(realpath(.pnpm-config/<name>/package.json))` — same algorithm the upstream wrapper uses, but skipping the JS shim's extra Node startup.
- Pacquet's NDJSON stderr is forwarded through `@pnpm/logger`'s global `streamParser` so `@pnpm/cli.default-reporter` renders its events the same way it renders pnpm's own. Non-JSON stderr lines pass through verbatim.
- A few pnpm-side log emits (`importing_done` placeholder, `pnpm:summary`) are suppressed when pacquet will take over so the reporter doesn't close streams or lock in empty diffs before pacquet's real events arrive. Pacquet's duplicate `pnpm:progress status:resolved` events are filtered on the resolve-then-materialize paths so the reporter doesn't double-count.
- `installing/deps-installer/src/install/index.ts` gates the delegation on a `runPacquet?: () => Promise<void>` callback in `StrictInstallOptions`. The CLI layer in `installing/commands/src/installDeps.ts` constructs the callback, threaded through both the single-project and workspace-recursive paths.
- The `pacquet` and `@pnpm/pacquet` npm packages ship the same JS shim from `pacquet/npm/pacquet/scripts/generate-packages.mjs`; per-platform binaries stay under the existing `@pacquet/<plat>-<arch>` scope and aren't duplicated.
2026-05-19 20:56:15 +02:00
Khải
61e724cef3 ci(pacquet): pass --workspace --all-targets to clippy and check (#11735)
Co-authored-by: Claude <noreply@anthropic.com>
2026-05-19 08:24:07 +02:00
Zoltan Kochan
471b59025d chore: update pnpm to v11.1.3 (#11719)
* chore: update pnpm to v11.1.3

* fix: lock pacquet version
2026-05-18 17:23:32 +02:00
dependabot[bot]
85ceff2383 chore(deps): bump the github-actions group across 1 directory with 7 updates (#11642)
Bumps the github-actions group with 7 updates in the / directory:

| Package | From | To |
| --- | --- | --- |
| [actions/upload-artifact](https://github.com/actions/upload-artifact) | `7.0.0` | `7.0.1` |
| [github/codeql-action](https://github.com/github/codeql-action) | `4.32.5` | `4.35.4` |
| [actions/download-artifact](https://github.com/actions/download-artifact) | `8.0.0` | `8.0.1` |
| [softprops/action-gh-release](https://github.com/softprops/action-gh-release) | `2.5.0` | `3.0.0` |
| [actions/setup-node](https://github.com/actions/setup-node) | `6.2.0` | `6.4.0` |
| [vedantmgoyal9/winget-releaser](https://github.com/vedantmgoyal9/winget-releaser) | `19e706d4c9121098010096f9c495a70a7518b30f` | `7bd472be23763def6e16bd06cc8b1cdfab0e2fd5` |
| [cbrgm/mastodon-github-action](https://github.com/cbrgm/mastodon-github-action) | `2.1.26` | `2.2.0` |



Updates `actions/upload-artifact` from 7.0.0 to 7.0.1
- [Release notes](https://github.com/actions/upload-artifact/releases)
- [Commits](bbbca2ddaa...043fb46d1a)

Updates `github/codeql-action` from 4.32.5 to 4.35.4
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](c793b717bc...68bde559de)

Updates `actions/download-artifact` from 8.0.0 to 8.0.1
- [Release notes](https://github.com/actions/download-artifact/releases)
- [Commits](70fc10c6e5...3e5f45b2cf)

Updates `softprops/action-gh-release` from 2.5.0 to 3.0.0
- [Release notes](https://github.com/softprops/action-gh-release/releases)
- [Changelog](https://github.com/softprops/action-gh-release/blob/master/CHANGELOG.md)
- [Commits](a06a81a03e...b430933298)

Updates `actions/setup-node` from 6.2.0 to 6.4.0
- [Release notes](https://github.com/actions/setup-node/releases)
- [Commits](6044e13b5d...48b55a011b)

Updates `vedantmgoyal9/winget-releaser` from 19e706d4c9121098010096f9c495a70a7518b30f to 7bd472be23763def6e16bd06cc8b1cdfab0e2fd5
- [Release notes](https://github.com/vedantmgoyal9/winget-releaser/releases)
- [Commits](19e706d4c9...7bd472be23)

Updates `cbrgm/mastodon-github-action` from 2.1.26 to 2.2.0
- [Release notes](https://github.com/cbrgm/mastodon-github-action/releases)
- [Commits](fc8b40e2ec...776364a15d)

---
updated-dependencies:
- dependency-name: actions/download-artifact
  dependency-version: 8.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: actions/setup-node
  dependency-version: 6.4.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: actions/upload-artifact
  dependency-version: 7.0.1
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: github-actions
- dependency-name: cbrgm/mastodon-github-action
  dependency-version: 2.2.0
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: github/codeql-action
  dependency-version: 4.35.4
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: github-actions
- dependency-name: softprops/action-gh-release
  dependency-version: 3.0.0
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: github-actions
- dependency-name: vedantmgoyal9/winget-releaser
  dependency-version: 7bd472be23763def6e16bd06cc8b1cdfab0e2fd5
  dependency-type: direct:production
  dependency-group: github-actions
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-05-15 21:39:30 +02:00
Zoltan Kochan
7ff112bac6 ci: run install with pacquet (#11657) 2026-05-15 08:10:46 +02:00
Zoltan Kochan
e8fc34389a ci: pin Run tests step to bash so $TEST_SCRIPT expands on Windows (#11659)
Without an explicit shell, the step ran under PowerShell on
windows-latest, where `$TEST_SCRIPT` is not a variable (PowerShell
exposes env vars as `$env:TEST_SCRIPT`). `pn run ""` then exited 0
and just listed available scripts — the Windows test legs have been
silently no-op'ing since the env-var move in #11608.

The sibling `Verify Node version` and `Determine test scope` steps
already pin `shell: bash`; this brings `Run tests` in line.

---
Written by an agent (Claude Code, claude-opus-4-7).
2026-05-15 01:28:11 +02:00
Zoltan Kochan
a4f3c6d3b7 ci: enable manual releases for pacquet and pnpm (#11652)
Two related workflow changes:

### `pacquet-release-to-npm.yml`: switch to `workflow_dispatch`

The trigger was "push to main touching `pacquet/npm/pacquet/package.json`" — the version came from a committed bump and the workflow auto-fired on every such commit. Switch to `workflow_dispatch` only, with a `version` input (validated as semver). The workflow patches `pacquet/npm/pacquet/package.json` before `generate-packages.mjs` runs, so the version is single-sourced from the manual trigger rather than needing a separate commit to bump the manifest first.

The committed manifest now omits the `version` field entirely — it only exists at release time inside the runner.

Dropped along the way:

- The `check` job (EndBug/version-check against unpkg) — no longer needed when the operator types the version.
- The `Create GitHub Release` step — no draft release, no `v*.*.*` git tag. The pacquet `v0.x.x` tag scheme collided with pnpm's `v11.x.x`; npm is the authoritative artifact store and provenance attestations stay attached via `--provenance` on `pnpm publish`.
- `contents: write` on the publish job (no longer needs to create a tag).

### `release.yml`: add `workflow_dispatch` as a lib-only republish path

Add a `workflow_dispatch:` trigger alongside the existing tag-push trigger. Tag-push behaves exactly as before. Manual dispatch becomes a fast **lib-only republish** path — useful after a version bump to one or more lib packages that doesn't warrant a full CLI release.

On `workflow_dispatch` from any ref, the following are skipped (guarded with `if: startsWith(github.ref, 'refs/tags/')`):

- `Publish @pnpm/exe` step — also contains the multi-minute `build-artifacts` call.
- `Publish pnpm CLI` step.
- `Copy Artifacts`, `Attest build provenance` (the `dist/*` attestation), `Generate release description`, `Release` (`softprops/action-gh-release`) — these are the GitHub-Release-side ceremony. Without an explicit `tag_name`, `softprops/action-gh-release@v2.5.0` defaults to `github.ref_name`, which on a manual dispatch from main would create a junk release tagged literally `main`.

What still runs on `workflow_dispatch`:

- `actions/checkout`, garnet scan, `pnpm/setup`
- `Publish internal workspace packages (static token)` — i.e. `pn publish --filter=!pnpm --filter=!@pnpm/exe --access=public --provenance`

Compilation is handled by each lib package's own `prepublishOnly: tsgo --build` hook (which `pnpm publish` runs automatically), same as the existing tag-push flow.

The npm registry rejects any version already on it, so re-running on an already-released tree is a no-op — that's the safety net for accidental clicks.

## How to use

**pacquet release**: Actions → Release Pacquet → Run workflow → fill in `version` (e.g. `0.2.3` or `0.2.3-rc.1`) → Run. No tag, no GitHub release.

**pnpm full release**: still triggered by a `v*.*.*` tag push. Publishes @pnpm/exe + libs + CLI, attests, copies artifacts, creates a draft GitHub release.

**pnpm lib-only republish**: Actions → Release → Run workflow → choose `main` → Run. Publishes just the internal workspace packages from whatever versions are currently in each `package.json`. Skips CLI, @pnpm/exe, build-artifacts, GitHub release.
2026-05-14 22:50:42 +02:00
Zoltan Kochan
1575076d08 chore(pacquet): fold registry-mock into root workspace, fix npm metadata (#11643)
* chore(pacquet): fold registry-mock into root workspace, fix npm metadata

Two unrelated cleanups bundled because they touch the same publishing/
workspace plumbing:

1. **`pacquet/npm/pacquet/package.json` metadata** — the imported file
   still pointed at the standalone repo: `repository.url` was
   `pnpm/pacquet`, `repository.directory` was `npm/pacquet`, `homepage`
   and `bugs` likewise. Repoint at `pnpm/pnpm`. Update
   `generate-packages.mjs` so the per-platform packages it emits at
   release time also point at `pnpm/pnpm`.

2. **Fold `pacquet/tasks/registry-mock` into the root pnpm workspace**.
   Pacquet's standalone-repo nested-workspace setup pinned
   `nodeLinker: hoisted` "for verdaccio CJS resolution," but pnpm's
   own jest globalSetup (`__utils__/jest-config/with-registry/`) calls
   the same `@pnpm/registry-mock.start()` API under the default
   isolated linker without issue, and verified locally that
   `node launch.mjs prepare` works after consolidation. The hoisted
   constraint was scoped to standalone-pacquet's install pattern; in
   the monorepo it's unnecessary.

Changes for (2):
  - Add `pacquet/tasks/registry-mock` to `pnpm-workspace.yaml`.
  - Rename the package `@pnpm-private/pacquet-registry-mock-launcher`
    (private, matches the `@pnpm-private/*` convention used by other
    internal workspace members) and switch `@pnpm/registry-mock` to
    `catalog:` (the root catalog already pins it at 6.0.0).
  - Delete `pacquet/tasks/registry-mock/pnpm-lock.yaml` and
    `pnpm-workspace.yaml` — root install handles both now.
  - Delete `pacquet/package.json` and `pacquet/pnpm-lock.yaml` — the
    file only had a `cargo build` script + `devEngines: pnpm`, both
    already covered by root, and nothing referenced it.
  - `justfile install` is now just `pnpm install` (was
    `cd pacquet/tasks/registry-mock && pnpm install --frozen-lockfile`).
  - `pacquet-integrated-benchmark.yml` path filter and cache key
    swap the deleted nested lockfile for the root `pnpm-lock.yaml` /
    `pnpm-workspace.yaml`.

Verified: `pnpm install` resolves the workspace member, the lockfile
gains a `pacquet/tasks/registry-mock` importer entry, and
`pacquet/tasks/registry-mock/node_modules/@pnpm/registry-mock` is
linked correctly under the isolated layout.

* fix(pacquet): match meta-updater conventions in registry-mock launcher

The previous version of `pacquet/tasks/registry-mock/package.json`
omitted `version`, which crashed `pn lint:meta` (meta-updater hits
`manifest.version!.split('.')[0]` for every workspace package).

Backfill all the fields meta-updater would emit for an internal
`@pnpm-private/*` private package, matching `__typecheck__/package.json`
and friends:

  - `version: 1100.0.0` (the pnpm 11.x convention for non-experimental
    internal packages)
  - self-devDep entry (`workspace:*`) that meta-updater would otherwise
    inject
  - `keywords: [pnpm, pnpm11]`
  - `repository` pointing at this directory inside pnpm/pnpm

This is the same shape every other `@pnpm-private/*` private workspace
member uses; it lets `pn lint:meta --test` pass without modifying the
file.

* fix: update lockfile

* chore(pacquet): add build:pacquet script at root

Restore the `cargo build --release --bin pacquet` shortcut that lived in
the deleted `pacquet/package.json`. Naming it `build:pacquet` (rather
than `build`) matches the existing namespacing convention in this
file (`lint:ts`, `lint:meta`) and leaves room for a general `build`
script later. Invoke with `pnpm build:pacquet` or `pn build:pacquet`
from the repo root.
2026-05-14 21:05:03 +02:00
Zoltan Kochan
d2b64b6689 ci(pacquet): fix all zizmor code-scanning findings (#11641)
* ci(pacquet): fix all zizmor code-scanning findings

Resolves the 90 alerts opened by zizmor against the imported pacquet-*
workflows and shared composite actions:

- unpinned-uses: pin every third-party action to a SHA + version comment
  (matching SHAs already used elsewhere in the repo where applicable;
  taiki-e/install-action collapsed onto v2.78.0 with explicit `tool:` input).
- artipacked: add `persist-credentials: false` to every actions/checkout.
- template-injection: pass `inputs.*` and `steps.*.outputs.*` through `env:`
  in binstall/rustup composite actions and pacquet-release-to-npm.yml.
- excessive-permissions: add top-level `permissions: contents: read` to
  pacquet-release-to-npm.yml; move issues/pull-requests writes from the
  workflow level to the benchmark-compare job in pacquet-micro-benchmark.yml.
- dangerous-triggers: keep workflow_run in pacquet-integrated-benchmark-
  comment.yml but suppress with a documented zizmor: ignore — the trigger
  is the recommended pattern for posting comments back to fork PRs.
- superfluous-actions: keep softprops/action-gh-release with a zizmor:
  ignore (matches release.yml).

Verified by running `zizmor .github` locally with no remaining findings.

* ci(pacquet): point SHA pins at the patch-version tag

Swatinem/rust-cache and montudor/action-zip were pinned to the SHA the
major-version alias (`v2`, `v1`) resolves to, but the version comments
claimed `v2.9.1` / `v1.0.0`. zizmor's online `ref-version-mismatch`
audit flagged the inconsistency. Repoint at the SHAs the patch-version
tags actually annotate so the pin and the comment agree.
2026-05-14 19:33:30 +02:00
Zoltan Kochan
763ddf1c99 chore(pacquet): wire pacquet workflows into monorepo (#11635)
* chore(pacquet): wire pacquet workflows into monorepo

Move Cargo workspace, Rust toolchain configs, justfile, composite actions,
and 7 workflow files out of `pacquet/` and up to the repo root so:

  - cargo / just / taplo run from repo root, the way the rest of the
    monorepo's tooling does
  - GitHub Actions actually discovers the workflows (it only reads
    `.github/workflows/` at the repo root)

Workflows are prefixed with `pacquet-` and renamed to "Pacquet ..." so
they don't collide with the existing pnpm CI. Path filters are scoped
to `pacquet/**` so they don't trigger on every commit. The cargo entry
from pacquet's standalone `dependabot.yml` is folded into the root one;
pacquet's `CODEOWNERS` and `pull_request_template.md` are dropped because
the root copies supersede them.

Path rewrites:
  - `Cargo.toml` workspace members → `pacquet/crates/*`, `pacquet/tasks/*`
  - all path-deps in `[workspace.dependencies]` → `pacquet/...`
  - `justfile` recipes (`install`, `install-hooks`) point at `pacquet/...`
  - `.taplo.toml` include globs → `pacquet/crates/*/*.toml`, `pacquet/tasks/*/*.toml`
  - `pacquet/npm/pacquet/scripts/generate-packages.mjs` REPO_ROOT walks one
    more level up
  - workflow `paths:` filters, `hashFiles(...)`, and shell paths all updated

Verified: `cargo metadata` resolves the workspace, `cargo fmt --check`
clean, `taplo format --check` picks up all 26 Cargo.tomls, `actionlint`
reports no new issues (the `type:`-on-input warnings on the rustup action
predate this move).

* chore(pacquet): drop pnpm version pin from pacquet CI workflows

The monorepo's root `package.json` declares `pnpm@11.1.1` under
`packageManager`, which conflicts with the workflows' explicit
`version: 11.0.0-rc.5` and trips `pnpm/action-setup` ERR_PNPM_BAD_PM_VERSION.

The pin was a pacquet-era workaround for the v9 lockfile while pnpm 11
was still pre-release. Stable 11.x writes v9 too, so let action-setup
read the version from `packageManager` like every other workflow in
this repo does.

* chore(pacquet): use pnpm/setup matching the rest of the monorepo

Replaces `pnpm/action-setup@v6` with the same `pnpm/setup@b1cac3...`
SHA the rest of pnpm/pnpm uses (release.yml, test.yml, ci.yml,
benchmark.yml, audit.yml). Reads pnpm version from `packageManager`
in root package.json, and skips the implicit `pnpm install` since
pacquet does its own scoped install via `just install` (which only
touches `pacquet/tasks/registry-mock/`).

The release workflow now also installs Node via the same action
(`runtime: node@22`) instead of via `pnpm runtime -g set node 22`,
since pnpm/setup handles runtimes in one step.

* chore(pacquet): tighten permissions and Dependabot cooldown

Address zizmor warnings on the pacquet CI changes:

  - `dependabot.yml`: the cargo entry I added in the previous commit
    inherited from pacquet's standalone repo and is missing the
    `cooldown: default-days: 7` the github-actions entry uses. Add it
    so cargo and github-actions debounce updates consistently.

  - `pacquet-ci.yml`, `pacquet-codecov.yml`, `pacquet-cargo-unused.yml`
    lacked a top-level `permissions:` block, so GITHUB_TOKEN inherited
    the repo default. Declare `contents: read` — every job in these
    workflows only reads the repo and runs local checks.

The other four pacquet workflows already declare permissions
explicitly (integrated-benchmark/comment, micro-benchmark, release).

* chore(pacquet): add "reimagining" to cspell dictionary

cspell at the repo root scans all `**/README.md` and was rejecting
`pacquet/README.md` and `pacquet/npm/pacquet/README.md`, which describe
pacquet as "not a reimagining of pnpm." Add the word to the existing
allow-list rather than rewording two READMEs imported from a separate
repo.

* fix(pacquet): prefix workspace-relative paths with pacquet/

Two Rust source files looked up paths off the cargo workspace root
(\`cargo locate-project --workspace\`), which now resolves to the
monorepo root rather than the pacquet directory. Add the \`pacquet/\`
prefix:

  - \`tasks/registry-mock/src/dirs.rs\` — \`registry_mock()\` was
    pointing the node launcher at \`<repo>/tasks/registry-mock/launch.mjs\`
    instead of \`<repo>/pacquet/tasks/registry-mock/launch.mjs\`, which
    failed every Pacquet CI test job ("Cannot find module ...launch.mjs").
  - \`tasks/micro-benchmark/src/main.rs\` — same idea for the
    fixtures folder.
2026-05-14 18:17:45 +02:00
Zoltan Kochan
9844cdf3a9 ci: integrate garnet-org/action for supply-chain monitoring (#11626)
Adds the Garnet network-monitoring action to the smoke test job, the
release workflow, and the npm tag workflow. The full CI test matrix is
left untouched to keep per-job overhead off the broad cross-platform
runs; the smoke test still exercises a representative install/test flow.
2026-05-14 08:25:30 +02:00
Zoltan Kochan
6b2a955a15 ci: address zizmor findings across workflows (#11608)
Resolves all 30 zizmor alerts reported on main after #11607:

- template-injection (19): move `${{ ... }}` interpolations in `run:` blocks
  to `env:` so untrusted-ish values (workflow_dispatch inputs, github.ref_name,
  github.actor) can't break out of shell quoting.
- artipacked (8): add `persist-credentials: false` to `actions/checkout` in
  audit, benchmark, ci, codeql-analysis, docker, release, test workflows.
  `update-lockfile.yml` keeps the persisted token (later step pushes to a
  branch) with a `zizmor: ignore[artipacked]` comment and justification.
- dependabot-cooldown (1): add a 7-day cooldown so brand-new (potentially
  malicious) Actions releases don't get auto-PR'd day-of-release.
- ref-version-mismatch (1): `bluwy/release-for-reddit-action` SHA pointed at
  the `v2` tag, not a non-existent `v2.0.0`. Fix the comment.
- superfluous-actions (1): mark `softprops/action-gh-release` with a
  `zizmor: ignore` and justification — the release pipeline is sensitive and
  the action is battle-tested; we're not swapping it for `gh release` here.

Verified locally with `zizmor --persona regular .github` (online audits on):
  No findings to report. Good job! (2 ignored, 32 suppressed)

---
Written by an agent (Claude Code, claude-opus-4-7).
2026-05-12 22:03:41 +02:00
Zoltan Kochan
6335860e0c ci: add zizmor workflow for GitHub Actions security analysis (#11607)
- Adds `.github/workflows/zizmor.yml` running [zizmor](https://github.com/zizmorcore/zizmor-action) against the repo's GitHub Actions workflows.
- Triggers: push to `main` and `release/**`, and PRs targeting those branches.
- Empty workflow-level `permissions: {}` with job-level grants (`security-events: write`, `contents: read`, `actions: read`) so findings upload to the Code scanning alerts feed.
- Pins `actions/checkout` and `zizmorcore/zizmor-action` by commit SHA, matching the pinning convention used elsewhere in `.github/workflows/`.
2026-05-12 21:48:11 +02:00
Zoltan Kochan
dcc171a948 chore(ci): migrate workflows to pnpm/setup (#11589)
## Summary

Migrates CI workflows from `pnpm/action-setup` + manual `pn runtime set node …` + `pn install` to the new combined `pnpm/setup` action (see https://github.com/pnpm/setup/pull/1).

`pnpm/setup` installs pnpm and the JS runtime in one step. It also runs `pnpm install` automatically when a `package.json` is present, so per-workflow install steps are dropped. When the `runtime` input is set, the action passes `--no-runtime` to `pnpm install` so the matrix-selected Node version isn't shadowed by a different `devEngines.runtime` pin.

## What changed

| Workflow | Migration |
|---|---|
| `test.yml` | `pnpm/setup` with `runtime: node@${{ inputs.node }}`. Verify-Node step asserts the matrix version stayed active. Verify-npm step retained as canary (npm comes from the runner image, not the pnpm-installed runtime). |
| `ci.yml` | `pnpm/setup` (no `runtime` input — `devEngines.runtime` in package.json handles the Node pin). |
| `release.yml` | `pnpm/setup` with `runtime: node@26.0.0`. |
| `benchmark.yml` | `pnpm/setup` with `runtime: node@26.0.0`. |
| `audit.yml` | `pnpm/setup` with `install: false` — audit only needs pnpm itself, not `node_modules`. |
| `update-lockfile.yml` | `pnpm/setup` with `install: false` — the job deletes `pnpm-lock.yaml` and regenerates it via `--lockfile-only`, so the action's auto-install would be wasted. |
| `update-latest.yml` | Untouched — it only uses npm, no pnpm setup needed. |

## Caveats / things to watch

- **npm availability.** `pnpm runtime set node` does not extract npm. The runner image's pre-installed Node toolchain provides `npm` on PATH; if a future runner image change removes that, dlx-style git-hosted dependency tests in `test.yml` will fail. The `Verify npm` step in `test.yml` is the canary.

## Related upstream change

- [pnpm/setup#3](https://github.com/pnpm/setup/pull/3) — added the `install` input so callers like `audit.yml` and `update-lockfile.yml` can opt out of the action's auto-install.
2026-05-12 19:31:54 +02:00
Zoltan Kochan
7e3145f9fc chore: add devEngines.runtime (#11553)
Adds `devEngines.runtime` to pin the Node.js version (24.6.0, `onFail: download`) the project uses for development, so contributors don't have to manage Node versions manually.

CI changes that come with it:

- Bumps pnpm to **11.1.1** and `pnpm/action-setup` to a bootstrap that ships `@zkochan/cmd-shim` 9.0.3. The cmd-shim update is required because the previous shim's `exec cmd /C` got mangled by Git Bash's MSYS path conversion (`/C` → Windows path), which broke any `pn …` invocation from `shell: bash` on Windows.
- Switches the install step to `pn install --no-runtime` so the per-test-matrix Node version chosen by `pn runtime -g set node …` isn't overridden by the project-pinned 24.6.0.
- Adds a `Verify Node version` step that asserts `pn node -v` matches the matrix's Node.
2026-05-12 14:43:05 +02:00
Zoltan Kochan
80037699fb ci: update dist-tag in update-latest.yml 2026-05-07 12:42:52 +02:00
Zoltan Kochan
d98ac7e4bb ci(release): split publish into three steps to force trusted publishing (#11496)
The previous "Publish Packages" step ran `pn release` after writing
NPM_TOKEN into pnpm's config. With a static `_authToken` configured,
`pnpm publish` bails out of OIDC entirely (see #11495 for the longer-
term fix), so every package — including `pnpm` and `@pnpm/exe` — was
silently being published with the legacy token instead of using npm's
trusted publishing. The result: published metadata showed
`_npmUser: pnpmuser` and no provenance attestation.

Until #11495 ships, work around the precedence bug by structuring the
job so the packages we *want* trusted publishing for never see a
static token at all:

1. `@pnpm/exe` — published in a step with no NPM_TOKEN. pnpm has no
   token to short-circuit on, performs OIDC, gets a `trustedPublisher`
   entry on npm.
2. Internal workspace packages — these don't have trusted publishing
   configured on npm, so they still need the static token. The token
   is written, the publish runs, then `pn config delete` removes the
   token before the next step.
3. `pnpm` — published in a step with no NPM_TOKEN, same rationale as
   step 1.

CI-only change; no changeset needed.
2026-05-06 17:19:24 +02:00
Zoltan Kochan
f79f0540ac chore: update Node.js to 26.0.0 (#11472)
* chore: update Node.js to 26.0.0

* fix(jest-config): use amaro for type stripping on Node.js 26

Node.js v26 removed the `transform` mode and `sourceMap` option from
`module.stripTypeScriptTypes`. Switch the Jest transform to call
`amaro.transformSync` directly (the same wasm transformer Node.js wraps)
so we keep inline source maps for tests.
2026-05-05 22:18:12 +02:00
Zoltan Kochan
7e91e4b35f ci: update pnpm/action-setup 2026-05-04 22:24:17 +02:00
Zoltan Kochan
4852e6f85d docs(release): correct rationale comment on macos-latest runner (#11446)
The previous comment attributed the darwin SEA crashes to ldid producing
bad page hashes, but the upstream minimal `node --build-sea` + `codesign`
repro (nodejs/node#62893) shows codesign-signed binaries crash too. The
bug is in LIEF's Mach-O surgery during --build-sea, not in signing.

Rewrite the comment to state the actual reasons the job runs on macOS
(native codesign avoids building ldid; macos-latest is Apple Silicon so
verify-binary.mjs can smoke-test the darwin-arm64 SEA) and explicitly
note that this does NOT fix the darwin-x64 crash.

Comment-only change. No behaviour change.
2026-05-04 14:56:29 +02:00
Zoltan Kochan
caf5b7d422 ci(release): attest build provenance for release artifacts (#11441)
Generate Sigstore-backed SLSA build provenance for the platform tarballs
and zips produced by `pn copy-artifacts` via actions/attest-build-provenance,
so users can verify with `gh attestation verify` that the binaries attached
to a GitHub release came from this repository's release workflow rather
than from a manual upload.

This complements the release attestation that GitHub auto-generates for
Releases (predicate `https://in-toto.io/attestation/release/v0.2`), which
only proves what files were attached to a tag, not how they were built.
The new attestation uses `https://slsa.dev/provenance/v1` and binds each
artifact's digest to the workflow_ref, commit SHA, and runner identity.

The `pn release` step already publishes npm tarballs with provenance, so
this closes the same gap on the GitHub Release side.
2026-05-04 13:09:06 +02:00
Zoltan Kochan
d374e330ad ci(release): build artifacts on macos-latest to fix darwin-x64 signing (#11415)
* ci(release): build artifacts on macos-latest to fix darwin-x64 signing

Cross-signing darwin Mach-O binaries on Linux with the saurik fork of
ldid produces an ad-hoc signature whose page hashes don't match the
post-postject layout for Node.js 25's chained fixups, leaving fixups
unapplied at load and crashing the binary in __cxx_global_var_init
(EXC_BAD_ACCESS at 0x3 — the unprocessed chain-entry tag).

Running the release on macos-latest lets pack-app's adHocSignMacBinary
use native codesign, which understands chained fixups. Drops the entire
ldid build step.

* ci(release): document why release runs on macos-latest
2026-05-01 21:54:51 +02:00
Zoltan Kochan
1beb41652b ci: run all tests on release branches 2026-04-22 02:17:03 +02:00
Zoltan Kochan
bcf49c9cd9 ci: don't continue release on error 2026-04-21 01:33:57 +02:00
Zoltan Kochan
9ae1ca7253 feat: publish base docker image to GHCR (#11302)
* feat: publish base docker image to GHCR

Adds a Dockerfile (debian:stable-slim + pnpm standalone binary) and a
release-triggered workflow that builds multi-arch images and pushes to
ghcr.io/pnpm/pnpm. Users who need Node.js can install it inside the
container via `pnpm runtime set node <version>`.

Refs #11300

* docs: add docker/README.md

* chore(cspell): add buildx to dictionary

* docs: mention devEngines.runtime as alternative to pnpm runtime set

* fix(docker): pin base image, verify tarball sha256, harden download

- Pin `debian:stable-slim` to a digest for reproducibility.
- Compute pnpm tarball SHA256 in the workflow and verify it inside the
  build, detecting tampered artifacts regardless of what `pnpm --version`
  reports.
- Download the tarball to disk with `--retry` instead of `curl | tar`
  for resilience under multi-arch QEMU builds.
- README: use `--load` so the local test image is available to `docker run`.

* chore(cspell): sort dictionary additions

* fix(docker): address Copilot review feedback

- Include $PNPM_HOME/bin on PATH so pnpm-installed globals (node, etc.)
  are discoverable, and make $PNPM_HOME writable for non-root users.
- Document that `pnpm runtime set node` needs `-g` to install globally.
- Pass workflow inputs via env: instead of inlining GitHub expressions
  into shell, and validate the version string before use.

* fix(docker): install libatomic1 for pnpm standalone binary

The pnpm linux standalone binary dynamically links against
libatomic.so.1, which is not present in debian:stable-slim by
default. Without it, `pnpm --version` fails during the build with:

  pnpm: error while loading shared libraries: libatomic.so.1:
  cannot open shared object file: No such file or directory

Caught by local build testing.
2026-04-19 18:59:24 +02:00
Zoltan Kochan
a4305c91b4 ci: remove not needed comment from release.yml 2026-03-30 18:35:59 +02:00
Zoltan Kochan
6bb68e54e7 chore: update pnpm to beta 4 2026-03-30 00:34:47 +02:00
Zoltan Kochan
55a06023fc ci: update release.yml 2026-03-29 13:15:13 +02:00
Zoltan Kochan
d6b8e281b6 chore: use pn instead of pnpm (#11124) 2026-03-28 11:55:51 +01:00
Zoltan Kochan
be681cc3fc ci: fix windows 2026-03-27 20:44:08 +01:00
Zoltan Kochan
b09ae0a9bc ci: update action-setup and use devEngines 2026-03-27 11:15:58 +01:00
Zoltan Kochan
3967d89c17 ci: fix windows 2026-03-25 14:00:58 +01:00
Zoltan Kochan
439cb684a3 fix: allow benchmark workflow to run against PRs from forks 2026-03-24 21:34:46 +01:00
Zoltan Kochan
cd2dc7d481 refactor: prefix internal scripts with . to hide them (#11051)
* fix: ensure PNPM_HOME/bin is in PATH during pnpm setup

When upgrading from old pnpm (global bin = PNPM_HOME) to new pnpm
(global bin = PNPM_HOME/bin), `pnpm setup` would fail because the
spawned `pnpm add -g` checks that the global bin dir is in PATH.
Prepend PNPM_HOME/bin to PATH in the spawned process env so the
check passes during the transition.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* chore: update pnpm to v11 beta 2

* chore: update pnpm to v11 beta 2

* chore: update pnpm to v11 beta 2

* chore: update pnpm to v11 beta 2

* fix: lint

* refactor: rename _-prefixed scripts to .-prefixed scripts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix: update root package.json to use .test instead of _test

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* ci: update action-setup

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-21 14:30:56 +01:00