Commit Graph
48 Commits
Author SHA1 Message Date
Zoltan KochanandClaude Opus 5.5 6f95957063 docs: lint prose with Vale (#17238)
* docs: lint prose with Vale

Add Vale with an in-repo style, .vale/styles/pnpm, that turns the
writing rules in AGENTS.md and the Google developer documentation style
guide into lint rules. The stock Vale packages (Google, Microsoft,
RedHat, write-good) were too noisy to block on, for example 1,300
passive-voice hits in the v12 docs alone, so the rules are written for
this repo, following the GitLab model. Each one links the guideline it
enforces.

Levels:
- error, fails CI: dashes, plain-word substitutions, condescending
  words, "please", "note that", hedges, puffery, optional plurals,
  exclamation marks, ellipses, curly quotes, generic link text, product
  spellings, sentence-case headings, repeated words, double spaces,
  implementation history in comments; in changesets, bold or italic
  emphasis, internal names and release-line names.
- warning: future tense, sentences over 30 words, "instead of" and
  "so that" tails in changesets.
- suggestion: passive voice.

.vale.ini scopes the rules. Docs get every rule. Contributor Markdown
and code comments keep dashes and headings as warnings until their
roughly 8,100 em dashes are rewritten. Released changesets stay in
.changeset/ and are not rewritten, so lint-prose.mjs lints only the
changesets added since PROSE_BASE (the PR base in CI).

The prose workflow installs a pinned, checksum-verified Vale release and
runs `pnpm lint:prose`. The rest of this change rewrites the existing
docs, READMEs, contributor Markdown, and code comments to pass the
error-level rules. Only prose and comment text changed. Renamed
headings keep their anchors.

Spelling stays with cspell, which checks identifiers that Vale does not
see.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: keep prose lint from flattening meaning

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 21:48:09 +02:00
Sandeep 0e487587a0 docs: fix stale paths and package name in AGENTS.md (#16830) 2026-10-10 18:30:48 +02:00
KhảiandClaude Opus 5 1606ba03fb docs: add the documentation and comment principles and apply them (#16516)
* docs(agents): add the documentation and comment principles

Import the principles that transfer from KSXGitHub/perfectionist's
contributor guide, plus four of our own: concise and non-repeating text,
structured text over prose, removal over addition when reviewing or
fixing nitpicks, and a definition of the user-facing text that must not
name implementation details.

The root guide's "Comments" section gains "Register", "Prose that cannot
go stale", "User-facing text", and "Reviewing documentation and
comments". The pacquet style guide adds the Rust specifics (clap and
napi doc comments are user-facing; a default is documented on the
field, not the variant). DOCUMENTATION.md gains the renderer and link
table for each markdown surface.

The guides themselves are brought in line: counts over growable lists
become plain references, a quoted heading becomes an anchor link, and
the size limits are stated once, in the style guide, instead of three
times.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs: keep user-facing text free of implementation names

The `@pnpm/napi` README and type declarations named the Rust engine, the
in-repo package name, and TypeScript internals (`filterPkgsDiff`,
`nameFormatter`) that a user of the addon cannot reach. The pnpmfile
page in both docs trees explained a limitation by the IPC mechanism
behind it. Four changesets named the release line or implementation,
which the package targets already express.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(crates): cut restating and stale comments in pack, modules-yaml and nine more crates

Apply the comment principles to pack, versioning, pnpr-client,
package-is-installable, fs-packlist, workspace-task-scheduler,
engine-runtime-node-resolver, exportable-manifest, modules-yaml,
pnpr-registry, and pnpr-auth. Removed: call-site comments that repeat
the callee's doc, module rosters of exports that the `pub use` lines
already list, "not yet implemented" notes for behaviour that exists
(`beforePacking`, `hoistedLocations`), body narration, and history
framing. Comment-only; no code changes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(crates): cut restating and stale comments in the small resolver, catalog and pnpr crates

Apply the comment principles to the local, tarball, default, deno and
jsr resolvers, the catalog crates, detect-libc, config-parse-overrides,
env-replace, git-utils, matcher, diagnostics, and the pnpr policy,
cargo, error, osv and fixture crates. Removed: parentheticals that
repeat a `#[diagnostic(code)]` attribute, counts over lists of
variants, callers and entry points, rosters of callers, doc paragraphs
that repeat a sibling's or the module's text, comments narrating the
match arms or condition below them, and history framing. The
`pnpr-prepare --help` text no longer names the test harness.
Comment-only; no code changes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(crates): cut restating and stale comments in publish, workspace, registry and graph-hasher

Apply the comment principles to publish, auth-commands, registry,
workspace, lockfile-verification, default-reporter, the git resolver,
deps-inspection, hooks, graph-hasher, package-manifest, and the pnpr
shared-artifacts and route crates. Removed: a module roster of every
export, counts over lists, plan notes for work that landed ("Phase 5",
"Phase 6"), call-site comments repeating the callee's doc, docs
narrating match arms, a default claim on a `#[default]` variant, a
misattached doc, and history framing. Comment-only; no code changes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(crates): cut restating comments in napi, reporter and pnpr crates

Apply the comment principles to napi, reporter, resolving-resolver-base,
real-hoist, git-fetcher, workspace-manifest-writer, and the pnpr config
and storage crates. Removed: "Mirrors X in index.d.ts" sentences on
`#[napi]` items and other implementation names in addon-facing docs,
stale "not emitted yet" and "when it lands" notes for behaviour that
exists, step-by-step comments narrating the body, emit-site and caller
rosters, docs duplicated from a sibling or the module, a doc attached to
the wrong item, and history framing. Comment-only; no code changes.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs: cut restating and stale comments across the remaining crates and pnpm11

Apply the comment principles to the rest of the Rust workspace and to the
TypeScript CLI: the cli crate and its clap definitions, package-manager,
config, patching, the deps resolver, lockfile, pnpr, the npm resolver,
tarball, network, executor, cmd-shim, the benchmark and fixture tooling,
and the pnpm11 packages.

Removed: comments narrating the body, docs repeating a callee's, a
sibling's or the module's text, counts over growable lists, rosters of
callers and exports, "not yet implemented" notes for behaviour that
exists, history framing, and `@param` lines restating a signature.

One exception to comment-only: in `pnpr/crates/pnpr/src/resolver/resolve.rs`
the `Workspace` struct sat inside the doc block written for `resolve`, so
the struct moved above it and each doc now attaches to its own item.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(crates): cut body narration and duplicated docs in resolver, fs and package-manager

Removed: a numbered "Sequence:" list narrating `ensure_file`'s body and
the paragraph restating its backoff constants, the stress-test module
doc's roster of its own tests, refactor-history paragraphs in the peer
walk's finalize pass, call-site and caller-side copies of a callee's doc
(the `optional` AND-fold stays documented on `register_seeded_package`
and on `ResolvedPackage`), a verbatim quotation of a TypeScript test's
expected output in the pnpr search module doc, and field and digest-input
rosters in the package-manager.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(deps-restorer): cut plan references and re-attach misplaced docs

Removed the "slice 4" plan references and the comments narrating the
bodies they sat above. The `Auto` downgrade-chain doc moved from
`copy_and_log` to `auto_link`, the function it describes.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(deps-restorer): cut the remaining body narration in the hoist path

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs: cut the last body narration and a history clause in the cmd-shim test

`build_graph.rs` kept a `patches` parameter doc that re-derived what
`BuildOptions::patches` documents. The PowerShell-arguments test on main
said the arguments survived "before the shim ended its batch context
too", which describes the change rather than the behaviour.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(cmd-shim): point the PowerShell-shim link at its current module

Main moved `wants_powershell_shim` into `windows_shim_policy`, so the
shim writer's link to it no longer resolved and `cargo doc` failed.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(cli): link the fixture the ignored-build setup installs

The shortened doc named `workspace_with_unapproved_build` in backticks,
which `perfectionist::bare_identifier_reference` rejects for an item that
resolves in scope. It is an intra-doc link now.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(crates): restore two contracts and fix four dangling references

A review of this branch's sweep flagged seven places. Six needed a
change:

- `from_ini` documents again that a relative `cafile=` resolves against
  `npmrc_dir`, a precondition its callers have to honour.
- `hash_object` documents again that the private serializer's bytestream
  has to match pnpm 11's, because the digest is persisted and read by
  both.
- The hooked-manifests note no longer says "above" of a gate that lives
  in another module.
- The store-dir race test states its synchronization contract instead of
  labelling it "Post-Option-C".
- `GraphNodeHashOptions.nodeVersion` keeps `undefined` as a literal.
- The pnpr streaming module drops the sentence fragment that introduced
  its list.

The seventh, a `beforePacking` limitation in exportable-manifest, stays
removed: the note said the pnpmfile bridge cannot supply that hook, and
`pnpm_pack::lifecycle::apply_before_packing` has been running it since
before this branch.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(cli): say in `pnpm why --help` that `--exclude-peers` is ignored

Demoting the caveat to an ordinary comment took it out of the help,
which then advertised a flag that does nothing: `WhyArgs::run` never
reads `exclude_peers`, and pnpm 11's `why` handler never forwards its
`excludePeers` either. The doc comment states that behavior in the words
a user sees, and the parity reason stays in a comment beside it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

* docs(cli): drop the doc comment that described the wrong module

The comment described the `pnpm_deps_inspection as deps_tree` re-export
above it, but a doc comment attaches to the item that follows, so rustdoc
showed it as the description of `mod dispatch`. The `use` item already
names the alias, so the comment goes rather than moving.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QYTBQo8HY7xD2iz6hjo1CW

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-10-02 20:28:21 +02:00
Zoltan Kochan 4edeef9176 style(ts): port the perfectionist lint rules to ESLint (#16415)
Add TypeScript ports of the perfectionist rules that the Rust workspace
enforces through dylint.toml to @pnpm/eslint-config, with the same limits,
and fix every finding that needs no refactor.

The size and shape rules (function length, cognitive complexity, nesting,
local bindings, file length) are enforced for packages that already meet
them. The packages that do not are listed in PENDING_SIZE_AND_SHAPE_REFACTOR
in eslint.config.mjs and are refactored in follow-up changes.

The custom rules mirror perfectionist's semantics rather than reusing
sonarjs or max-lines-per-function, so that one limit means the same thing
in both codebases: a closure is a level of the body that contains it, a
nested function declaration is measured on its own, and a test-framework
callback plays the role of a #[test] function.

Bugs found and fixed along the way:
- a registry error body cut at exactly 64 KiB lost its truncation marker
- removing a dependency could leave dangling .bin shims
- constructor/__proto__ names crashed the projects graph, were skipped by
  the injected-deps syncer, and were dropped from writeWantedLockfile's
  returned lockfile

The CI chunk runner learns to run the node:test suite of the ESLint
config package.
2026-09-30 15:10:08 +02:00
Zoltan Kochan 07839df5c3 docs: move product documentation beside its implementation (#16385)
* docs: move website documentation into the pnpm repository

* docs: keep v11 and v12 documentation beside their implementations

* docs(pnpr): keep registry documentation beside its implementation

* ci: classify product documentation as documentation changes

* test: cover product documentation in Rust CI exclusions

* ci: isolate documentation publishing and support manual sync

* test: make dependency status fixture timestamps deterministic
2026-09-29 15:56:43 +02:00
Zoltan Kochan 11b9393080 fix: recognize WebContainers' async fs errors (#16253)
StackBlitz WebContainers reject asynchronous fs calls with errors that
inherit from Error but were not created by the native constructor, so
util.types.isNativeError() returns false for them. pnpm used that check
to recognize ENOENT and other codes, so a missing pnpm-lock.yaml was
rethrown and pnpm install failed on any project without a lockfile.

Add isError() to @pnpm/error, which accepts a native error or any
instanceof Error, and use it at every non-test call site. The native
check alone is still needed for Jest, where errors from another realm
fail instanceof. Update the AGENTS.md guidance to match.

Closes pnpm/pnpm#15649
2026-09-27 12:02:05 +02:00
Zoltan KochanandClaude Opus 5.5 aa0021c015 docs: route planned work to pnpm/tasks and stop labeling bug reports (#16198)
* docs: route planned work to pnpm/tasks and stop labeling bug reports

pnpm/pnpm issues are now reserved for bug reports against released pnpm
behavior. Planned work (PR follow-ups, refactors, performance, parity gaps,
CI and benchmark work, post-release docs) moved to the pnpm/tasks repository,
feature ideas go to Discussions, and security reports go through private
advisories.

AGENTS.md tells agents where to file each kind of issue. The bug report
template no longer adds the "type: bug" label, since every issue in this
repository is now a bug report.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* docs: defer security reporting to SECURITY.md

SECURITY.md sends pacquet and pnpr security issues to public issues while
they are not production ready, so AGENTS.md must not require a private
advisory for every vulnerability.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-26 15:35:29 +02:00
snmsoodan 33cc2f2b15 fix(pull-requests): make resolve-pr-conflicts --continue work during a rebase (#15589)
A rebase paused by resolve-pr-conflicts.sh leaves HEAD detached, so by the time
the user runs the same command with --continue, the branch check reads HEAD,
decides it is not on the PR branch, and runs `gh pr checkout`. That checkout
aborts on the resolutions staged for the paused rebase:

    error: Your local changes to the following files would be overwritten by checkout

The rebase could then only be finished by hand. Two changes fix the flow:

- Detect a paused rebase (rebase-merge/rebase-apply) before the branch check.
  With --continue, stay on the detached HEAD and resume the rebase in place.
  Before resuming, verify the rebase is rewriting the head branch of the PR
  named on the command line, so a stale or mistyped PR number cannot
  force-push one PR's rebase onto another PR's branch. Without --continue,
  stop and say to use --continue, rather than starting a nested rebase that
  fails only later.
- Add --no-push (alias --dry-run), which stops after a successful rebase and
  prints the push command instead of running it. A contributor's rebase lands
  on their own fork, so being able to review the rewritten commits between the
  rebase and the force-push matters.

Argument parsing moves from positional to a loop so the flags can be given in
any order, and both success paths share one finish_rebase() helper instead of
repeating the push and the mergeability check.

No changeset: nothing under .agents/ is published.

Tests: .agents/skills/pull-requests/scripts/resolve-pr-conflicts.test.sh stubs
git/gh/sleep and covers continuing a paused rebase (merge and apply backends),
--no-push, --dry-run, a rebase belonging to another branch, --continue with no
rebase, a rebase without --continue, an unknown option, and full runs with and
without --no-push. It fails on the previous script with the checkout error
above and passes on this one. It runs in the Compile & Lint job next to the
publication script tests, and the paths filter now watches
.agents/skills/**/scripts/** so that a script change runs it.

Closes pnpm/pnpm#13106.
2026-09-25 01:01:39 +02:00
Zoltan Kochan 85e7bbcca6 fix(config): report ignored project credentials (#15087)
Report npmrc-load warnings through the normal CLI stderr warning channel.
Link ignored project credential warnings to the npmrc documentation.
Project auth environment placeholders are intentionally ignored by default;
expanding them automatically would allow repository configuration to send
user environment secrets to an attacker-controlled registry.

The lockfile verifier already uses the shared resolver metadata fetcher and
configured auth headers. Cover frozen verification with a scoped registry
under a nested GitLab-style URL, proving configured auth sources authenticate
metadata and tarball requests.

Update the cmd-shim tests for the helper signatures on current main.

Closes pnpm/pnpm#15051.
2026-09-19 13:08:45 +02:00
Zoltan Kochan 44502ee491 docs: establish project philosophy and implementation workflow (#15023)
Record the maintainer's project philosophy as a shared reference for
implementation, triage, and review. Explain how feature value, abstractions,
compatibility, and user-selectable tradeoffs fit pnpm's core requirements.

Add a repository implementation workflow that checks existing capabilities,
prioritizes deduplication, assesses architectural impact, and validates through
the existing testing and review skills. Update review guidance to require
major releases for stable breaking changes.
2026-09-17 15:59:05 +02:00
Zoltan Kochan c8c818caf8 chore: consolidate code review in a repository skill (#15020) 2026-09-17 14:52:07 +02:00
Zoltan Kochan 40677ef2e9 chore: automate existing PR fixes through repository skills (#15018)
Extract the existing PR review-and-fix workflow into a repository skill and
invoke it from the git-wt hook. Commit and push verified fixes automatically,
then reuse the pull-requests skill to follow CI and review rounds to completion.
Preserve the existing PR status and leave merging to the maintainer.

Move the shared conflict-resolution script into the pull-requests skill.
2026-09-17 14:33:43 +02:00
Zoltan Kochan 6b84edfb3a chore: load .agents/skills in Claude Code via a .claude/skills symlink (#14995)
The repository's skills live in .agents/skills. Codex discovers that
directory on its own (verified with `codex debug prompt-input` on codex-cli
0.154.0, which lists a skill placed there). Claude Code does not: it scans
only .claude/skills, so the repo's skills were invisible to it unless each
contributor symlinked them into ~/.claude/skills by hand.

Add .claude/skills as a symlink to ../.agents/skills. Claude Code follows it
and lists the skills behind it, so the skills stay in one place and every
agent reads the same copy.

.claude was ignored wholesale, which would have kept the symlink untracked.
Narrow the rule so the root .claude directory and the skills symlink are
tracked while everything else under it, such as settings.local.json, stays
ignored.

No .codex/skills symlink: Codex already reads .agents/skills, so it would
only add a second path to the same files.
2026-09-17 01:42:31 +02:00
Zoltan Kochan 17ca785303 docs: keep agents with a PR from draft to green (#14989)
Agents routinely opened a pull request, pushed, and ended the turn: CI
results and review rounds arrive minutes later and nothing in the repo
said the task was still open. AGENTS.md documented how to open a PR and
how to resolve a thread, but never that a push leaves work outstanding.

Add a `pull-requests` skill covering the path a change takes. Open the
PR as a draft, because CI runs on a draft here and the reviewers do not,
so a failing check or a bug the author's own pass catches costs one push
rather than a review round. Mark it ready once the checks are green and
that pass is clean.

From there, run a loop after every push: wait for the checks, read the
whole round including the findings a reviewer leaves only in its summary
comment, verify each one before acting, reply on every thread with the
commit that fixed it once that commit is on the remote branch, keep the
title and description current because they become the squash commit, and
push again. A round counts as finished only when every reviewer's
summary names the head commit, since a round that has not started looks
exactly like one that found nothing.

The skill also covers conflicts that appear while the PR waits, and why
the fix is a rebase: main requires linear history and has merge commits
disabled. It covers opening a PR for an issue, where the timeline
cross-reference says nothing about what was done, so the issue gets a
comment naming the approach and whether it closes the issue whole or in
part. And it covers the traps: rounds land on the previous round's
fixes, resolving a thread needs GraphQL, and a fork run cancelled by the
approval sweep is not a failure.

The skill names no reviewer. The roster changes; what an author does
with a finding does not.

Replace the PR bullets in AGENTS.md with a pointer to the skill and the
rules that have to hold even when it is not loaded: open as a draft, a
push is not the end of the task, and agent-authored content is signed.
2026-09-16 23:16:25 +02:00
Zoltan Kochan 6d73648565 chore: run the tests a change affects, with smoke tests for its dependents (#14985)
`pnpm/CONTRIBUTING.md` required `just ready` before every commit, explicitly
including documentation and comment edits: a full `cargo nextest run` over
~11,500 tests for changes that cannot break them. The root guide's "never run
all tests" rule was scoped to the TypeScript sections, so it read as not
applying to Rust.

The checks now match what a change can break. Formatter, typos, and
workspace-wide check and lint before every commit, since those are cheap and
catch the cross-crate breakage a scoped selection hides, plus the tests for
what the diff affects. The full local run is reserved for changes whose blast
radius cannot be named, because CI already runs the suite on three platforms.

`just test-affected` resolves changed files to packages through `cargo
metadata` and runs them through `run-rust-tests.mjs`, expanding any `pnpr-*`
selection so feature unification does not silently skip backend tests, and
refusing to guess when a change reaches files every crate compiles against.
Selection is crate-level rather than `rdeps()`-based: `pnpm-cli` holds a third
of the workspace's tests and sits downstream of nearly everything, so `rdeps()`
selects 84% or more of the suite for any core crate. Restructuring that target
is tracked in pnpm/pnpm#14984.

Crate-level selection leaves the dependents unrun, so the new `smoke` profile
runs in their place: one end-to-end test per area of CLI behavior, triggered by
the dependent set rather than added to every run. Membership is by behavior
area rather than code coverage, since nearly every end-to-end test walks the
same install path. An exact-name filterset fails open, so a test checks every
entry against the suite sources.

The `testing-changes` skill carries the selection cookbook and the gotchas that
make a scoped run lie.

Related to pnpm/pnpm#14984.
2026-09-16 22:26:31 +02:00
Zoltan Kochan b44439419e fix(cli): honor pipeline package-manager pin flags (#14637) 2026-09-07 01:22:03 +02:00
Zoltan Kochan 1648084667 docs: make pnpm v12 the feature development target (#14561)
pnpm v12 is the target for new feature development. The TypeScript pnpm v11 implementation is maintenance-only.

Update the repository guidance so shared bugs are fixed and tested in both versions, while v12-only features and fixes do not create v11 parity work. Align the contributor, review, changeset, release, README, and PR checklist instructions with the same policy.
2026-09-05 00:01:43 +02:00
Zoltan KochanandClaude Fable 5.1 94d1b1f041 docs: add changeset style rules (#14473)
* docs: add changeset style rules

Release blog posts are assembled from changesets, and the pnpm 12.0 post
was called hard to read in https://github.com/orgs/pnpm/discussions/14399.
The patterns that made it read as generated (em dashes, "instead of"
tails, colon-joined lists of internals, reasoning asides) come from the
changesets themselves. Of the last 150 changesets, 14 have a contrast
tail, 9 a colon-joined list, and 7 an em dash.

Add a "Changeset style" section to AGENTS.md, adapted for release notes
from the unslop skill the discussion suggests, with two before/after
examples taken from real changesets. Point to it from CONTRIBUTING.md and
add it to the REVIEW_GUIDE.md changeset checks so reviewers enforce it.
AGENTS.md is used rather than a .claude skill because .claude is
gitignored and AGENTS.md is read by every agent.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XtDoGVb7JYAkfJFqQnDRiz

* docs: add language to changeset style example fences

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XtDoGVb7JYAkfJFqQnDRiz

---------

Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-02 17:33:04 +02:00
Zoltan Kochan 9798c9f611 revert: "chore(release): stop publishing @pnpm/exe from v12 (#14121)" (#14133)
This reverts commit afb4071811.
2026-08-24 15:35:45 +02:00
Zoltan Kochan afb4071811 chore(release): stop publishing @pnpm/exe from v12 (#14121)
Up to v11, `@pnpm/exe` was the build of pnpm that bundled a Node.js
runtime, so it ran where the JavaScript `pnpm` package could not. From
v12 the `pnpm` package is itself the native executable and needs no
Node.js, which left `@pnpm/exe` an equal-content copy of it, published
and dist-tagged for nothing.

generate-packages.mjs no longer emits the `pnpm-exe` wrapper dir, and
release.yml no longer packs or stages it. The per-platform
`@pnpm/exe.<target>` native packages are unchanged: they carry the
binaries the `pnpm` wrapper resolves.

update-latest.yml would have failed on the first v12 promotion, since it
unconditionally installs and dist-tags `@pnpm/exe` at the promoted
version. Both sites now pick the wrapper by major. The upgrade check
gates on the *starting* version so upgrading a v11 `@pnpm/exe` onto a
v12 release is still covered, and it gained `--allow-build=pnpm` because
from v12 the preinstall that swaps the placeholder bin for the native
one lives on the `pnpm` package -- without it that check would have
validated a placeholder.

No runtime code changes: both stacks' package-to-install selection
already converges on `pnpm` for major >= 12, the update notifier already
prints `pnpm`, and `@pnpm/exe` stays in the bin-resolver and global-alias
lists so v11-and-earlier installs keep working. Only the comments that
justified those behaviors with "published under both names" needed
correcting.
2026-08-24 02:39:51 +02:00
Zoltan Kochan 6e39ea3def chore(release): move the Rust CLI to the rc lane (#13666)
Switch pacquet and its fixed-group partner `@pnpm/napi` from the beta lane
to rc, so the next "pnpm version -r" cuts 12.0.0-rc.N prereleases instead
of continuing the 12.0.0-beta.N series. pnpr stays on alpha.
2026-08-05 21:39:46 +02:00
Zoltan KochanandManuel Pelloni 6fe023775d fix(pacquet): resolve latest through the maturity-aware picker (#13102)
`pacquet add <name>` without a version and `pacquet update --latest`
fetched the raw `latest` dist-tag, so with an active
`minimumReleaseAge` they could write a range into `package.json` that
the follow-up install rejects (related to pnpm/pnpm#11165).

Resolve the tag through the same package-picking path as install. The
maturity filter repoints `latest` to the newest mature version, keeping
the manifest and lockfile consistent and matching the TypeScript CLI.

Share one lazily constructed `LatestPicker` across every selector in a
command. This preserves command-validation and unmatched-selector error
ordering while reusing the policy, metadata cache, fetch locker, and
registries map. Report invalid `minimumReleaseAgeExclude` values with
`ERR_PNPM_INVALID_MINIMUM_RELEASE_AGE_EXCLUDE`, matching install and the
TypeScript CLI.

Add TypeScript and Rust regression coverage for bare update, update
with `--latest`, and add without a version.

---------

Co-authored-by: Manuel Pelloni <manuel.pelloni@m4ss.net>
2026-07-17 15:14:01 +02:00
Zoltan Kochan d3e1383ff4 feat(release): unify the TypeScript, Rust and pnpr release flows on pnpm's native versioning (#12949)
Merge the three release flows (TypeScript, Rust CLI + @pnpm/napi, pnpr)
into a single flow driven by pnpm's native workspace versioning
(pnpm/pnpm#12953), dropping the @changesets/cli dependency (Closes
pnpm/pnpm#12947).

The native engine keys package identity on the workspace directory, so
the Rust CLI wrapper is named pnpm (the v12 line at pnpm/npm/pnpm) and
shares the published name with the TypeScript CLI at pnpm11/pnpm.
Release configuration moves from .changeset/config.json to the
versioning key of pnpm-workspace.yaml: versioning.lanes puts the Rust
CLI, @pnpm/napi, and @pnpm/pnpr on an alpha lane (X.Y.Z-alpha.N
prereleases published under next) while the TypeScript CLI releases
stable on the main lane; versioning.fixed keeps the Rust CLI and
@pnpm/napi at one shared version; versioning.ignore freezes
@pnpm/logger, which is consumed as a catalog: peer the engine would
otherwise reject as an internal range.

Lanes replace the hand-rolled prerelease continuation, and the
committed .changeset/ledger.yaml replaces the .changeset-released
directory as the cherry-pick-safe record of consumed intents. bump.ts
drops both and is now just pnpm version -r plus syncRustVersions, which
mirrors the bumped wrapper versions into defaults.rs and the pnpr crate
version.

Because two workspace projects are named pnpm, name-based --filter=pnpm
is qualified by directory (pnpm{pnpm11/pnpm}) across the build and
release scripts, the meta-updater excludes the Rust wrappers by
directory, and changesets targeting the TypeScript CLI reference it as
./pnpm11/pnpm. release.yml's plan job gates per-product publish jobs on
which committed versions are unpublished; everything publishes via
trusted publishing. @changesets/cli, .changeset/config.json, and the
standalone pacquet/pnpr release workflows are removed; their npm
trusted-publisher bindings must be re-pointed at release.yml before the
first unified release.

pnpm-lock.yaml is regenerated from scratch: an incremental
--lockfile-only resolve after the @changesets/cli removal hit a pacquet
incremental-resolver bug (pnpm/pnpm#12958) that emptied a peer-context
snapshot the CLI depends on and broke the bundle build. A from-scratch
resolve is correct; the bug is filed separately.
2026-07-13 11:11:41 +02:00
Zoltan Kochan 8e17c3d366 refactor: rename the pacquet/ directory to pnpm/ (#12913)
Pure directory move plus path fixups: the Rust port ships as pnpm v12,
so the source tree now lives at pnpm/ (alongside pnpm11/, the frozen
TypeScript line). No identifiers change in this pass — crate names
(pacquet-*), the pacquet bin, PACQUET_VERSION, the @pacquet/* npm
package names v11's runPacquet spawns, the .pacquet virtual-store dir,
the benchmark harness's clone dir, and the pacquet-*.yml workflow
filenames (npm trusted publishing is bound to them) all stay for a
follow-up.

Also removes the root /pnpm/ .gitignore entry (build detritus in the
pre-pnpm11 package location): pnpm/ is real source now and must not be
ignored. Developers with a stale generated pnpm/ dir should delete it
before checking out this change.
2026-07-10 18:06:56 +02:00
Khải f57f5af8bd docs(pacquet): remove TypeScript-code references from comments and document the parity paradigm (#12737)
pacquet and the TypeScript pnpm CLI are co-developed parallel
implementations at near-complete feature parity, with neither stack
downstream of the other. Remove the GitHub permalinks and the "mirrors
upstream's X" framing that pointed pacquet's comments at the pnpm
TypeScript source, and rewrite the affected prose to describe pacquet's
own behavior. This also resolves the dead permalinks the PR originally
set out to repair: the links are gone rather than re-pinned, so they
cannot rot again.

Removed every /blob/ and /tree/ permalink to the pnpm-org TypeScript
repos (over 1,700 links across ~330 files) plus the cited TS symbols and
"Mirrors/Ports/matches upstream's X" prose. Kept issue/PR/CI references,
pnpm/pacquet self-references, third-party attributions, Rust intra-doc
links, shared-contract identifiers (ERR_PNPM_* codes, the pnpm-prefixed
reporter wire format), and generic pnpm-product mentions.

Updated the contributor guides to state the new paradigm: root and
pacquet AGENTS.md (cardinal rule rewritten, permalink-citation guidance
removed), pacquet CODE_STYLE_GUIDE.md (reporter section reframed around
the shared wire contract), pacquet README, and a few plan/task docs.

The Rust changes are comment-only except for three #[expect(reason =
"...")] attribute strings that themselves cited a TypeScript symbol.
2026-06-30 20:53:14 +02:00
Zoltan Kochan 99af755b6e docs: pacquet has ported nearly all commands, so mirror every user-visible change (#12708) 2026-06-28 22:55:27 +02:00
Zoltan Kochan 305295f838 docs: align agent comment conventions (#12657)
Move the agent comment guidance out of the TypeScript-only code style section into a repo-wide Comments section so it applies to the pnpm CLI, pacquet, and pnpr.

Keep the Rust-specific comment additions in pacquet AGENTS.md and have pnpr reference that canonical Rust guidance instead of copying the same rules. This removes ambiguity about whether pnpr follows the pacquet convention without creating another block to maintain.
2026-06-25 15:23:54 +02:00
Zoltan Kochan d7ba22ef95 docs: add review guide (#12522)
Add REVIEW_GUIDE.md as the repository's canonical code-review guide, distilled
from the maintainer's review history. Centralize the review framework: move the
AI Review Guidance out of AGENTS.md into the guide, move the engineering
conventions into AGENTS.md's Code Style section, and update the CodeRabbit and
Qodo configs to apply the guide and split review focus between the two bots
(CodeRabbit on correctness/conventions, Qodo on security/performance).
2026-06-19 23:33:39 +02:00
kimulacoandZoltan Kochan 11ebd9d232 fix(pacquet): preserve exec bit on clone/reflink import path (#12502)
On Linux reflink_copy::reflink uses FICLONE, which clones only the data into a
freshly-created 0o644 target, dropping the exec bit pacquet encodes in the
`-exec` CAS suffix. pnpm/pnpm#12385 restored it for the copy tier but left clone
out, so an undeclared executable like `@esbuild/linux-x64/bin/esbuild` failed
with EACCES. hardlink shares the store inode's 0o755 and copy was fixed, so only
clone was affected.

Extract the restoration (already duplicated in copy_file and git-fetcher's
materialize_into) into a shared
pacquet_fs::file_mode::restore_exec_bit_from_cas_suffix and route clone through
it. In auto_link / clone_or_copy_link only a reflink failure downgrades; the
post-reflink restoration error stays terminal, so it can't trigger a hardlink
retry against the just-created file that would mask it behind AlreadyExists.

Fixes pnpm/pnpm#12500.

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-06-19 11:19:32 +02:00
Zoltan Kochan 6ee484e3c5 fix(ci): run PR review automation for fork PRs via workflow_run (#12493)
Approvals on PRs from forks never got the `reviewed: coderabbit` label or a
Discord announcement. A pull_request_review run triggered by a forked PR is
granted a read-only token and no secrets, so the label step failed with HTTP
403 and the Discord step had no webhook.

Split the automation in two: the pull_request_review workflow now only records
the approval as an artifact (no token, no secrets), and a new workflow_run
companion runs from the default branch in base-repo context — where it has the
write-scoped token and secrets — to add the label and post to Discord.

The privileged half never checks out or executes PR content: it reads inert
data files, validates the PR number is an integer, maps the reviewer to a fixed
label, requests only actions:read + issues:write, surfaces a failed (vs absent)
artifact download instead of passing as a silent no-op, and scopes the Discord
webhook secret to the announce step.

Also documents that agents must open PRs using .github/pull_request_template.md,
since gh pr create does not apply it automatically.
2026-06-18 14:25:52 +02:00
Alessio AttilioandZoltan Kochan c2414e8236 docs: add PR template and clarify changeset purpose (#11290)
Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-06-18 11:47:53 +02:00
Zoltan Kochan 98745562b0 docs: configure AI review security and performance guidance (#12405)
* chore: tune ai review guidance

* docs: centralize ai review guidance
2026-06-14 17:39:28 +02:00
KhảiandClaude 8dfe43857d chore(husky): add git hook rejecting bare @mentions in commit messages (#12387)
* chore: add git hook rejecting bare `@mentions` in commit messages

* fix(husky): align bare-mention boundary with GitHub linkification rules

* fix(husky): keep mention boundaries intact when stripping code spans

* fix(husky): ignore the verbose-commit diff below the scissors line

* refactor(husky): split bare-mention hook into small single-purpose functions

* fix(husky): exempt tilde-fenced code blocks from mention scanning

* fix(husky): trim trailing punctuation from the reported scoped handle

* refactor(husky): detect bare mentions by scanning, not regex

Replace the single packed detection regex with a plain character scan and
small predicate functions: for each `@`, exempt it when it sits inside
backticks (odd backtick count before it), when it is not followed by an
ASCII letter/digit, or when it is preceded by one (email-like). This is
easier to read and reason about than the regex.

Side effect: the `~~~` tilde-fence special case is gone, so a mention inside
a `~~~` block is now flagged. Backtick code spans and fences are still
exempt.

* docs(husky): note readHandle precondition that the char after @ is alphanumeric

* refactor(husky): spell out abbreviated identifiers in the mention hook

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-13 22:24:37 +02:00
KhảiandClaude 75bf4bfe1e chore(husky): reject bare #NNN issue refs in commit messages (#12238)
* chore: reject bare #NNN issue refs in commit messages

Add a commit-msg hook (.husky/reject-bare-issue-refs.mjs) that rejects bare
'#NNN' references, which GitHub silently links to issues/PRs of this repo and
which AIs frequently misuse. Require qualified 'owner/repo#NNN' syntax or
absolute URLs instead, and document the rule in AGENTS.md/CLAUDE.md.

* docs: instruct agents to install git hooks before committing

---------

Co-authored-by: Claude <noreply@anthropic.com>
2026-06-07 00:47:49 +02:00
Zoltan Kochan d579e6cbb5 perf(pacquet): trim install-phase syscalls and allocations (#11864)
* perf(fs,package-manager): striped CAS lock + skip pre-flight stat on fresh-target imports

Two install-phase syscall trims:

- `cas_write_lock` swaps the per-path `DashMap<PathBuf, Arc<Mutex<()>>>`
  for 256 static `Mutex<()>` stripes keyed by hashed path. Every CAFS
  write previously paid one `PathBuf::to_path_buf` allocation, a
  `DashMap` shard write lock, plus an `Arc<Mutex<()>>` slot allocation
  even though contention was vanishingly rare. Striping keeps the
  writer/verifier coordination the per-path mutex provided while
  removing those per-call costs. With 256 stripes and ~10 rayon
  workers the false-sharing probability per pair is ~4%, and the
  guarded body (one `O_CREAT|O_EXCL` open + `write_all` of a tar
  entry) is microseconds long.

- `import_indexed_dir::populate_dir` now calls a new
  `import_into_fresh_target` instead of `link_file`. `populate_dir`
  only ever runs against a directory it just `mkdir`'d, so the
  `fs::metadata` pre-flight `link_file` performs to protect the
  Copy-method overwrite contract is wasted — every call is `NotFound`
  in practice and the EEXIST surface from the import syscall is the
  only collision signal we need. Saves ~170k `stat` syscalls per
  clean install on the alotta-files fixture. `link_file` still
  exists with the original semantics for any caller that genuinely
  doesn't know whether the target is fresh.

On the 3343-package alotta-files fixture against the verdaccio mock,
clean-install wall time goes from ~28s to ~19-22s on the local 10-core
machine — roughly closing the gap to pnpm (~20s) for that scenario.

Refs #11857, #11851.

* perf(store-dir): trim per-CAS-file allocations on the hot write path

Two micro-optimisations in `cas_file_path`, the helper every CAFS
write goes through:

- `cas_file_path` no longer `format!`s the sha-512 digest into a
  fresh `String`. Sha-512 is always 64 bytes / 128 hex chars, so
  render the hex into a stack buffer and slice it into the
  `file_path_by_hex_str` call instead. One heap allocation per file
  shaved off — ~170k on the alotta-files clean install.

- The repeated `self.v11().join("files")` rebuild used to walk two
  `PathBuf::join`s per call. Memoise the result behind a `OnceLock`
  on `StoreDir` (`cached_files_dir`) so `file_path_by_head_tail`
  borrows it without re-joining. Race-free initialisation across
  rayon workers, one allocation per process instead of one per file.

Refs #11857.

* docs(pacquet): address CodeRabbit nits

- Refresh `import_indexed_dir` doc comments so they name
  `import_into_fresh_target()` (the actual materialization helper
  after the fresh-target split) instead of `link_file()`.
- Add a const assertion that `NUM_CAS_LOCK_STRIPES` stays a power of
  two, since `cas_write_lock` uses `& (NUM_CAS_LOCK_STRIPES - 1)` as
  the stripe selector.

* docs: forbid past-implementation history in comments

- Extend AGENTS.md Comments rules: comments must describe the
  current contract, not what the code replaced. Phrasings like
  "used to", "previously", "the original X", or parentheticals
  naming a removed type belong in `git log`.
- Apply the rule to `cas_write_lock`'s doc, which previously
  framed itself in terms of the removed
  `DashMap<PathBuf, Arc<Mutex<()>>>` shape.
2026-05-25 14:36:05 +02:00
Zoltan Kochan 09b7e9d354 docs: widen pacquet parity scope to all dep-management commands (#11810)
Update the scope caveat in AGENTS.md to state that pacquet's parity
surface now covers `install`, `add`, `update`, and `remove`, rather
than `install` alone.
2026-05-21 11:04:03 +02:00
Zoltan Kochan 2a9bd897bf perf: record locally-resolved lockfile in verification cache (#11714)
The lockfile verification cache currently only records the lockfile that exists at the **start** of an install. So a flow like:

```
pnpm install <pkg>
rm -rf node_modules
pnpm install
```

re-runs the per-package registry round-trip against the newly written lockfile, even though the local resolver already enforced the policy when picking those versions. The fresh lockfile is now recorded immediately after each install-time write, so the second install takes the cache fast path.

## Implementation

### Recording the post-resolution lockfile

- New helper `recordLockfileVerified` (in `installing/deps-installer/src/install/`). Gated on `cacheDir` + non-empty `resolutionVerifiers` — same gate the pre-resolution verifier uses.
- Two thin combiners over the lockfile writers: `writeWantedLockfileAndRecordVerified` and `writeLockfilesAndRecordVerified`. The install paths use these so the record always runs alongside the write.

### Hash stability: writer returns the canonical lockfile

The cache stores `hashObject(LockfileObject)` and the next install computes the same hash off the file it loads from disk. For the hashes to match, both ends must compute over structurally identical objects. They don't, naïvely: the in-memory write object can carry `undefined` optional fields (e.g. `settings.dedupePeers = undefined` from `opts.dedupePeers || undefined` in install code) that YAML drops on serialize — `object-hash` treats undefined vs missing as distinct values.

- `writeWantedLockfile` / `writeLockfiles` (in `@pnpm/lockfile.fs`) now return the canonical post-write `LockfileObject`: `convertToLockfileObject(stripUndefinedDeep(lockfileFile))`. The strip walks the existing object graph in memory rather than going through a `yaml.load` round-trip, so non-cache callers (deploy, deps-restorer, make-dedicated-lockfile, agent server) pay near-zero cost.
- Install hooks hash the writer's returned value, not the raw in-memory input. Guaranteed by construction to match what the next reader produces.

### `useGitBranchLockfile` correctness

The pre-resolution verification gate and the new post-write recorder were both keying cache records on a hard-coded `pnpm-lock.yaml`. Under `useGitBranchLockfile` the actual file is `pnpm-lock.<branch>.yaml`, so the stat shortcut hit `ENOENT` and the cache effectively never engaged for git-branch users. Both sites now resolve the real filename via `getWantedLockfileName`. The wrappers compute it once and pass it to the writer via a new optional `lockfileName` opt so `useGitBranchLockfile` installs don't fork `getCurrentBranch` twice per write.

### Bug fix unrelated to the cache, found during review

`writeLockfiles`' differs branch was deciding whether to remove or keep `node_modules/.pnpm/lock.yaml` based on `isEmptyLockfile(wantedLockfile)`. Filtered-current callers (deps-restorer) pass an empty current against a non-empty wanted, so this could leave a stale current lockfile on disk. Fixed to key off the current.

### Comments policy

`AGENTS.md` (and `pacquet/AGENTS.md`) now spell out the comment defaults: write self-documenting code, do not restate at call sites what the callee's JSDoc / doc comment already says, comments are reserved for the non-obvious *why*. The pruning pass in this PR brings the changed code in line.

## API surface

- `@pnpm/lockfile.fs` (minor):
  - `writeWantedLockfile`: return widened from `Promise<void>` to `Promise<LockfileObject>`. New optional `lockfileName` opt.
  - `writeCurrentLockfile`: return widened to `Promise<LockfileObject | undefined>` (undefined when the empty-lockfile branch unlinks).
  - `writeLockfiles`: return widened from `Promise<void>` to `Promise<{ wantedLockfile, currentLockfile }>`. New optional `wantedLockfileName` opt. New exported `WriteLockfilesResult` type.
  - New export: `getWantedLockfileName`.
- `@pnpm/installing.deps-installer` (patch): internal-only wrappers; no external API change.
2026-05-18 14:55:16 +02:00
Zoltan Kochan 2e33bb1955 docs: split AGENTS.md into shared + pacquet-specific (#11640)
* docs: split AGENTS.md into shared + pacquet-specific

Before: root AGENTS.md and pacquet/AGENTS.md each maintained their own
copy of the GitHub PR workflow, agent-footer rule, "never ignore test
failures," Conventional Commits list, and code-reuse philosophy.
Drift waiting to happen.

After:
  - Root AGENTS.md owns the shared conventions (PR workflow, agent
    footer, conventional commits, code reuse, never-ignore-tests,
    PR-conflict script) and marks TS-only sections explicitly
    (setup/build, testing, linting, changesets, Standard Style, Jest
    gotchas).
  - pacquet/AGENTS.md opens with "Read ../AGENTS.md first" and keeps
    only pacquet-specific rules (cardinal rule, branded types, just
    recipes, insta snapshots, miette diagnostics, Rust style notes,
    the `bench:` commit type, things-not-to-do that are Rust-flavored).
  - Root adds a one-line entry for `pacquet/` in the repo structure
    list so first-time readers find the cross-link.

CLAUDE.md and pacquet/{CLAUDE,GEMINI}.md are unchanged — they're
symlinks to AGENTS.md and follow automatically.

* docs(agents): require parity between pnpm and pacquet

Add a "Keep pnpm and pacquet in sync" section to root AGENTS.md spelling
out the bidirectional obligation: any user-visible change (CLI surface,
lockfile/manifest format, error codes, defaults, env-var handling, log
emissions, store layout) must land in both stacks in the same PR, or
the originating PR must spawn a tracking issue. Pure refactors / perf
wins / TS-only test cleanups don't need mirroring.

Cross-link from pacquet/AGENTS.md's "cardinal rule" so a pacquet-side
reader knows the obligation goes both ways and where the pnpm-side
version lives.

* docs(agents): restore Rust-specific dependency-level guidance

The root "Keep the dependency on the right level" bullet uses npm
vocabulary ("package," "shared package"). For a Rust reader that
required mentally translating "package" → "crate" and made the
workspace-vs-crate distinction less obvious. Restore the pacquet
phrasing alongside the existing pacquet-specific notes.

* docs(agents): hand off cross-stack porting via the same PR

Drop the "open a tracking issue" fallback — it lets one side drift
behind while the issue sits in the backlog. Instead, the PR author
opens the PR with their side and flags in the description what still
needs porting; someone else pushes the matching commits to the same
PR before it lands. Both sides land together or not at all.

* docs(agents): drop external-repo framing from the cardinal rule

pacquet now lives in the same repo as pnpm, so the cardinal rule no
longer needs the "fetch pnpm/pnpm main, compare ls-remote SHAs, watch
your local clone for drift" mechanics. The reference TypeScript code
is just a few directories over (`pnpm/`, `pkg-manager/`, `resolving/`,
`lockfile/`, `store/`, etc.), and pnpm is the source of truth by
position in the repo, not by branch tracking.

Updates:

  - Root `AGENTS.md`: rephrase the cross-link line to drop the "follow
    pnpm's main" framing.
  - `pacquet/AGENTS.md` cardinal rule: redirect "find the equivalent
    code" from `https://github.com/pnpm/pnpm` to the in-repo
    TypeScript workspaces, drop the "confirm you're on the freshest
    main" paragraph, and reword the source-of-truth wording.
  - Permalink citation rule: generalize from "upstream pnpm" to "any
    GitHub repository, including this one" — citation SHAs now usually
    point at this repo's history.

* docs(agents): note pacquet's current scope is install-only

Without this caveat the parity rule reads as if every command needs
porting today. pacquet only implements `install` right now; resolution
and other commands (`update`, `add`, `remove`, `publish`, `exec`,
`run`, `dlx`, `audit`, etc.) live only in TypeScript, so changes there
don't need a pacquet-side port. The caveat also flags that the parity
rule's scope will widen as pacquet ports more commands.
2026-05-14 19:49:49 +02:00
Zoltan Kochan 286018ef2f docs: add PR/issue/comment instructions for agents (#11475)
Add a "Working with GitHub PRs, Issues, and Comments" section to AGENTS.md covering three rules:
Keep PR title and description current when pushing new changes.
Reply to resolved review comments with the resolution + commit hash and close the conversation.
Sign all agent-authored comments, issues, and PRs with a footer that names the agent and model.
2026-05-05 21:15:46 +02:00
Zoltan Kochan 3d67773188 docs: add instruction to never ignore test failures in AGENTS.md 2026-04-04 12:10:34 +02:00
Alessio AttilioandZoltan Kochan d8be9706d9 fix: respect frozen-lockfile flag when migrating config dependencies (#11067)
* fix: respect frozen-lockfile flag when migrating config dependencies

* fix: throw FROZEN_LOCKFILE_WITH_OUTDATED_LOCKFILE when installing config deps with --frozen-lockfile

* fix: correct changeset package name and clean up minor issues

- Fix changeset referencing non-existent @pnpm/config.deps-installer
  (should be @pnpm/installing.env-installer)
- Fix merge artifact in AGENTS.md
- Revert unnecessary Promise.all refactoring in migrateConfigDeps.ts
- Remove extra blank line in test file

* fix: move frozenLockfile check to call site and add missing tests

Move the frozenLockfile check from migrateConfigDepsToLockfile() to
normalizeForInstall() to minimize the number of check points.

Add unit tests for all frozenLockfile code paths:
- installConfigDeps: migration fails with frozenLockfile
- resolveAndInstallConfigDeps: old-format migration, new-format
  resolution, and up-to-date lockfile success
- resolveConfigDeps: fails with frozenLockfile

* refactor: consolidate duplicate frozenLockfile checks in resolveAndInstallConfigDeps

Merge two identical frozenLockfile throw statements into a single check
covering both lockfileChanged and depsToResolve conditions.

* Delete respect-frozen-lockfile.md

* refactor: order fields

---------

Co-authored-by: Zoltan Kochan <z@kochan.io>
2026-03-28 18:17:52 +01:00
Zoltan Kochan 130a44d682 docs: fix changeset 2026-03-26 16:02:38 +01:00
Zoltan Kochan f7bb668100 docs: add PR conflict resolution guide and helper script (#11060)
Add a "Resolving Conflicts in GitHub PRs" section to AGENTS.md with
step-by-step instructions for force-fetching refs, rebasing, resolving
lockfile conflicts, and verifying mergeability.

Add shell/resolve-pr-conflicts.sh that automates the workflow: fetches
metadata, force-updates the base ref, rebases, auto-resolves lockfile
conflicts via pnpm install, force-pushes, and verifies the result.
2026-03-22 13:22:11 +01:00
Zoltan Kochan 9b801c888d fix: check allowBuild for packages with cached side-effects (#11039)
Closes #11035

## Summary

### Root cause fix: don't apply cached side-effects for unapproved packages
When importing packages from the store, side-effects cache was applied for any package not explicitly denied (`allowBuild !== false`). This meant unapproved packages (`allowBuild === undefined`) got cached build artifacts, setting `isBuilt: true` and bypassing the `allowBuild` check in `buildModules`.

**Fix:** Only apply side-effects cache when `allowBuild` returns `true` (explicitly approved). Changed in three locations:
- `installing/deps-restorer/src/index.ts` (isolated linker)
- `installing/deps-restorer/src/linkHoistedModules.ts` (hoisted linker)
- `installing/deps-installer/src/install/link.ts` (non-headless install)

### Revocation detection
When a package's build approval is revoked between installs (was `true` in `.modules.yaml`, now undefined), detect it in `mutateModules` and add to `ignoredBuilds` so `strictDepBuilds` fails.

### Status messages in `_rebuild`
Users now see what happened to each package during rebuild:
- `pkg@version: built successfully`
- `pkg@version: skipped (no build scripts)`
- `pkg@version: skipped (not allowed)`
- `pkg@version: reused from store cache`

And during install:
- `pkg@version: reused from store (side effects cache)`

### `buildSelectedPkgs` fixes
- Preserve `storeDir`, `virtualStoreDir`, `virtualStoreDirMaxLength` from existing `.modules.yaml` instead of overwriting with config-derived values (which caused "reinstall from scratch" prompt)
- Write `allowBuilds` to `.modules.yaml` so GVS doesn't detect a mismatch on next install
- Merge `ignoredBuilds` with existing entries for packages not being rebuilt
2026-03-21 12:51:24 +01:00
Zoltan Kochan a7cca3f361 docs(AGENTS): add code reuse and function argument guidelines 2026-02-14 20:44:30 +01:00
Zoltan Kochan 2ea64631eb fix: skip symlinks pointing outside package root in git and file deps (#10493) 2026-01-21 15:45:56 +01:00
Zoltan Kochan 43e9b5f22d docs: update AGENTS.md 2026-01-16 20:06:12 +01:00
Zoltan Kochan 02c8ec50cb docs: add AI agent guides (#10469) 2026-01-16 16:31:31 +01:00