Files
pnpm/pacquet/crates/cli/README.md
Zoltan Kochan 62900806fe feat(config,cli,tarball): support offline / preferOffline settings (#513)
* feat(config,cli,tarball): support `offline` / `preferOffline` settings

Adds the two settings to `Config`, `pnpm-workspace.yaml` parsing, and
`pacquet install` as `--offline` / `--prefer-offline` flags. CLI
flags merge into Config (boolean OR) before leak, so any source
(yaml, CLI) flips `true` and never the other way.

Upstream pnpm gates the metadata-fetch path in [`pickPackage`](https://github.com/pnpm/pnpm/blob/94240bc046/resolving/npm-resolver/src/pickPackage.ts):
when `offline: true` and no cached metadata exists, it fails with
`ERR_PNPM_NO_OFFLINE_META`; `preferOffline: true` biases the resolver
toward the cached copy. Pacquet's frozen-install path has **no
metadata fetch** (the lockfile pins every resolution), so the
upstream flag is semantically a no-op on pacquet's current flow.

To make the flag actually useful for frozen installs, pacquet adds a
**tarball-side gate** (no upstream equivalent — pnpm doesn't gate
tarball downloads on `offline`): when both the warm prefetch and the
SQLite `index.db` lookup miss, the fetcher refuses the network and
errors with `ERR_PACQUET_NO_OFFLINE_TARBALL`. Same shape as
`ERR_PNPM_NO_OFFLINE_META`, scoped to tarballs because that's what
pacquet's frozen install needs network for. Documented as a pacquet-
specific divergence in the field's rustdoc.

`prefer_offline` is a no-op today — the warm prefetch +
`load_cached_cas_paths` already prefer the local store. The field
exists so `.npmrc` / yaml / CLI all parse cleanly; Stage 2's resolver
will honour it on the metadata path.

- `Config.offline` / `Config.prefer_offline`: bool, default `false`.
- `WorkspaceYaml.offline` / `WorkspaceYaml.prefer_offline`:
  `Option<bool>`; applied via the existing `apply!` macro.
- `InstallArgs.offline` / `InstallArgs.prefer_offline`: bool CLI
  flags; merged into Config in `cli_args.rs` between `config()` and
  `State::init` (the brief window when `Config::leak` returns
  `&'static mut Config`).
- `DownloadTarballToStore.offline` / `DownloadZipArchiveToStore.offline`:
  bool fields. Wired through the three construction sites in
  `package-manager`.
- `TarballError::NoOfflineTarball { package_id, url }`: new variant.
  `tarball_error_to_request_retry` updated for exhaustiveness;
  `code: ERR_PACQUET_NO_OFFLINE_TARBALL` in the retry-logger
  projection so a future surface that runs this error through the
  retry path renders the right code.

- `offline_mode_skips_network_on_cache_miss` — `mockito` server with
  `.expect(0)`; the offline gate must fire before the network is
  touched. Asserts variant shape AND the diagnostic code (the code
  is part of the user-facing surface).
- `offline_mode_still_uses_prefetched_cache` — same `.expect(0)`
  guard but with a prefetched cache hit; pins that the prefetch
  branch short-circuits *before* the offline check so warm installs
  under `--offline` succeed.

Regression-catch verified: gating the gate behind `false &&` flipped
`offline_mode_skips_network_on_cache_miss` red with the wrong-variant
panic message. Reverted before commit.

All bulk-edit fixups (15 `DownloadTarballToStore` / `DownloadZipArchiveToStore`
literals in tests + micro-benchmark, 1 `Config` literal in package-
manager tests) get `offline: false` to match the prior implicit
default.

* docs(cli): pin pickPackage link to commit SHA (#513 review)

Per project guideline: upstream pnpm citations link to a specific
commit SHA (first 10 hex chars), not a branch name. Same SHA the
PR's rustdoc and commit body already use for the same file.

Resolves CodeRabbit review comment on `crates/cli/README.md`:
<https://github.com/pnpm/pacquet/pull/513#discussion_r3238182177>.
2026-05-14 02:11:47 +02:00

3.8 KiB

Options

pnpm documentation

Done Command Notes
-C , --dir
-w, --workspace-root

Manage dependencies

pacquet add <pkg>

pnpm documentation

  • [~] Install from npm registry
    • Install with tags are not supported. Example: pacquet add fastify@latest
  • Install from the workspace
  • Install from local file system
  • Install from remote tarball
  • Install from Git repository
Done Command Notes
--save-prod
--save-dev
--save-optional
--save-exact
--save-peer
--ignore-workspace-root-check
--global
--workspace
--filter <package_selector>

pacquet install

pnpm documentation

Done Command Notes
--force
--offline Frozen-install only: refuses network fetches; errors with ERR_PACQUET_NO_OFFLINE_TARBALL when a snapshot isn't cached. Stage 2 resolver will additionally gate metadata fetches like upstream's pickPackage.
--prefer-offline No-op on frozen-install (warm prefetch already prefers the local store). Reserved for Stage 2's resolver.
--prod
--dev
--no-optional
--lockfile-only
--fix-lockfile
--frozen-lockfile
--reporter=
--use-store-server
--shamefully-hoist
--ignore-scripts
--filter <package_selector>
--resolution-only

Run scripts

pacquet run

pnpm documentation

Done Command Notes
script-shell
shell-emulator
--recursive
--if-present
--parallel
--stream
--aggregate-output
enable-pre-post-scripts
--resume-from <package_name>
--report-summary
--filter <package_selector>

pacquet test

pnpm documentation

pacquet start

pnpm documentation

Misc.

pacquet store

pnpm documentation

Done Command Notes
status
add
~ prune Currently prune removes all packages inside the directory
path

pacquet init

pnpm documentation