# npm/cli — codebase unpack

> Canonical page: https://codevetter.com/unpack/cli

This is a deterministic Repo Unpack scan of npm/cli — a structural map, not a review, security audit, or maintainer-endorsed description.

- Scanned commit: b317f16c80df02ea3628cfa77170d5ae9b59720c (2026-10-01)
- Last upstream commit: fix: write registry allowScripts keys under install-strategy=linked (#9941)
- Generated by codevetter 1.15.0 on 2026-10-02
- 3955 files scanned · 130.8 MB

Source inspection; upstream code and tests were not executed.

## Languages

- JSON: 3913 files
- JavaScript: 1639 files
- Markdown: 262 files
- Python: 58 files
- YAML: 33 files
- Shell: 5 files
- C++: 2 files
- C#: 1 files

## Repository structure

- workspaces/ — 3420 files
- test/ — 141 files
- lib/ — 137 files
- docs/ — 100 files
- tap-snapshots/ — 40 files
- .github/ — 34 files
- scripts/ — 29 files
- smoke-tests/ — 13 files

Probable source entrypoint: `index.js` (inferred from the tree, not upstream docs)

## Source layout — lib/

- lib/cli/ — 4 files
- lib/commands/ — 79 files
- lib/utils/ — 47 files
- lib/arborist-cmd.js — 1 file
- lib/base-cmd.js — 1 file
- lib/cli.js — 1 file
- lib/lifecycle-cmd.js — 1 file
- lib/npm.js — 1 file
- lib/package-url-cmd.js — 1 file
- lib/trust-cmd.js — 1 file

## Package

- package.json: npm v12.2.0 — 80 declared dependencies

## Structural health signals

Average score 6.1/10 across 96 files; 60 hotspots. These are deterministic review leads, not proof of a bug.

## Recent history

- b317f16c80df (2026-10-02) fix: write registry allowScripts keys under install-strategy=linked (#9941)
- c276cadf785c (2026-09-30) chore: release 12.2.0
- 9741b645b011 (2026-09-30) feat(dist-tag): support OIDC authentication (#10038)
- 0c3b82a9a612 (2026-09-24) docs: update npm stage docs to reflect that it can create new packages (#10017)
- e1581be90119 (2026-09-24) chore(config): isolate tests from host npmrc files (#10015)

## Overview

At commit b317f16c80df02ea3628cfa77170d5ae9b59720c, this repository implements npm 12.2.0, a Node.js command-line package manager for JavaScript developers and package publishers. It combines dependency graph resolution, reproducible installation, package execution, registry administration, and publishing through npm and npx entrypoints. Distinctive capabilities in this source include install-script approvals, release-age restrictions, local dependency patches, root-owned manifest transformations, and staged publishing.

## System map

The runtime is a Node.js CLI with a central Npm object coordinating configuration, command dispatch, output, and error handling. Independently packaged workspaces provide dependency-tree management and registry operations. Persistent state spans project manifests and locks, installed modules, caches, logs, and user configuration. Distribution bundles runtime dependencies and builds documentation during packaging.
- package.json exposes npm through bin/npm-cli.js and npx through bin/npx-cli.js; index.js invokes the CLI when executed directly and rejects imports with the removed-programmatic-API error. — [package.json#L35-48](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/package.json#L35-L48) [bin/npm-cli.js#L1-2](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/bin/npm-cli.js#L1-L2) [index.js#L1-5](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/index.js#L1-L5)
- lib/cli.js optionally enables Node's compile cache, then validateEngines installs early syntax-error handlers before loading the asynchronous CLI entry module. — [lib/cli.js#L1-12](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/cli.js#L1-L12) [lib/cli/validate-engines.js#L15-42](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/cli/validate-engines.js#L15-L42)
- Npm constructs Config and Display alongside LogFile and Timers; Npm.cmd resolves registered names before dynamically requiring a command implementation. — [lib/npm.js#L20-29](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/npm.js#L20-L29) [lib/npm.js#L41-70](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/npm.js#L41-L70)
- execCommandClass handles recursive subcommands, help, workspace support, developer-engine checks, and separate execution branches for commands with definitions versus legacy commands. — [lib/npm.js#L230-267](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/npm.js#L230-L267) [lib/npm.js#L270-313](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/npm.js#L270-L313)
- Config stores default, builtin, global, user, project, environment, and CLI layers in a prototype chain; flat options are generated from lower to higher priority. — [workspaces/config/lib/index.js#L42-55](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/config/lib/index.js#L42-L55) [workspaces/config/lib/index.js#L116-122](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/config/lib/index.js#L116-L122) [workspaces/config/lib/index.js#L212-228](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/config/lib/index.js#L212-L228)
- Arborist owns actual, virtual, and ideal dependency trees and composes tracker, resolution, loading, rebuilding, reification, and isolated-install behavior through mixins. — [workspaces/arborist/lib/arborist/index.js#L1-27](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/index.js#L1-L27) [workspaces/arborist/lib/arborist/index.js#L39-50](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/index.js#L39-L50)
- Installation delegates to Arborist and pacote; publishing delegates to libnpmpack, libnpmpublish, npm-registry-fetch, and optional CI OIDC exchange. — [lib/commands/install.js#L147-176](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/install.js#L147-L176) [lib/commands/publish.js#L1-17](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/publish.js#L1-L17) [lib/commands/publish.js#L145-158](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/publish.js#L145-L158)
- The distributable includes bin, lib, documentation, and man pages with bundled runtime dependencies; prepack builds docs, test invokes TAP, lint invokes ESLint, and supported Node versions are explicitly constrained. — [package.json#L12-18](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/package.json#L12-L18) [package.json#L119-130](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/package.json#L119-L130) [package.json#L213-230](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/package.json#L213-L230) [package.json#L264-266](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/package.json#L264-L266)

## Feature catalog

The command registry spans dependency maintenance, package inspection, script execution, registry administration, publishing, and developer assistance. Commands support aliases and abbreviations, with workspace behavior determined by command metadata. Specialized surfaces manage script approvals, patches, trusted publishing, and staged release approval. The catalog below groups registered commands; detailed implementation inspection concentrated on installation, execution, authentication, auditing, and publishing.
- Dependency maintenance commands include install, ci, update, uninstall, dedupe, find-dupes, prune, rebuild, and link; install supports global mode, workspace selection, package-lock-only, platform filters, and source restrictions. — [lib/utils/cmd-list.js#L5-74](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/cmd-list.js#L5-L74) [lib/commands/install.js#L18-50](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/install.js#L18-L50) [lib/commands/install.js#L106-144](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/install.js#L106-L144)
- Inspection and discovery commands include ls, ll, explain, query, outdated, diff, sbom, fund, search, and view; audit implements advisory reporting, fix, and installed-package signature verification. — [lib/utils/cmd-list.js#L5-74](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/cmd-list.js#L5-L74) [lib/commands/audit.js#L48-101](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/audit.js#L48-L101) [lib/commands/audit.js#L104-137](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/audit.js#L104-L137)
- Execution and project workflows include run, exec, start, stop, restart, test, install-test, install-ci-test, init, edit, and explore; npx maps to exec, and run supports script listing plus workspace execution. — [lib/utils/cmd-list.js#L19-74](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/cmd-list.js#L19-L74) [bin/npx-cli.js#L3-7](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/bin/npx-cli.js#L3-L7) [lib/commands/run.js#L42-85](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/run.js#L42-L85)
- Release commands include pack, publish, unpublish, version, dist-tag, deprecate, and undeprecate; stage exposes publish, list, view, approve, reject, and download with deferred proof-of-presence. — [lib/utils/cmd-list.js#L16-74](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/cmd-list.js#L16-L74) [lib/commands/stage/index.js#L3-14](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/stage/index.js#L3-L14) [lib/commands/publish.js#L204-216](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/publish.js#L204-L216)
- Account and registry administration commands include access, org, owner, team, profile, token, login, logout, and whoami; trust provides GitHub, GitLab, CircleCI, list, and revoke subcommands. — [lib/utils/cmd-list.js#L5-74](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/cmd-list.js#L5-L74) [lib/commands/trust/index.js#L3-14](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/trust/index.js#L3-L14) [lib/commands/login.js#L15-44](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/login.js#L15-L44)
- Configuration and local diagnostics are registered as config, get, set, pkg, cache, doctor, ping, prefix, and root; command validation rejects unknown CLI options while unknown file settings warn unless strict-npmrc is enabled. — [lib/utils/cmd-list.js#L5-74](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/cmd-list.js#L5-L74) [lib/base-cmd.js#L372-430](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/base-cmd.js#L372-L430)
- Help and navigation commands include help, help-search, docs, bugs, repo, and completion; command classes generate usage from descriptions, aliases, parameters, definitions, and subcommand tables. — [lib/utils/cmd-list.js#L5-74](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/cmd-list.js#L5-L74) [lib/base-cmd.js#L25-70](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/base-cmd.js#L25-L70) [lib/base-cmd.js#L121-135](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/base-cmd.js#L121-L135)
- Policy and repair features include install-scripts approve/deny/ls/prune, approve-scripts and deny-scripts, patch add/commit/update/ls/rm, and min-release-age filtering with exemptions and blocked-audit-fix reporting. — [lib/commands/install-scripts.js#L3-19](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/install-scripts.js#L3-L19) [lib/commands/patch.js#L48-88](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/patch.js#L48-L88) [workspaces/config/lib/definitions/definitions.js#L1541-1575](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/config/lib/definitions/definitions.js#L1541-L1575) [lib/commands/audit.js#L79-90](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/audit.js#L79-L90)

## Data flow

CLI arguments, environment settings, and configuration files become typed configuration and flattened options consumed by command implementations. Installation turns requested specs and manifest metadata into an ideal graph, then reconciles that graph with disk. Authentication produces registry-scoped configuration, while publishing produces tarball bytes and registry requests. Output is routed through proc-log and finalized centrally.
- npx rewrites process.argv to npm exec, translates -p, --shell, and --no-install, removes obsolete options, and inserts -- before the first positional argument before invoking cli(process). — [bin/npx-cli.js#L3-7](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/bin/npx-cli.js#L3-L7) [bin/npx-cli.js#L66-123](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/bin/npx-cli.js#L66-L123) [bin/npx-cli.js#L125-130](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/bin/npx-cli.js#L125-L130)
- Config.load loads defaults and builtin configuration, parses CLI and npm_config_* environment values, then discovers project, user, and global files before exporting child-process settings. — [workspaces/config/lib/index.js#L247-278](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/config/lib/index.js#L247-L278) [workspaces/config/lib/index.js#L367-401](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/config/lib/index.js#L367-L401) [workspaces/config/lib/index.js#L860-865](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/config/lib/index.js#L860-L865)
- Npm.#load takes positional arguments from parsedArgv.remain, removes the command token, resolves aliases, initializes display settings, and returns the raw command spelling plus remaining arguments. — [lib/npm.js#L83-111](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/npm.js#L83-L111) [lib/npm.js#L178-187](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/npm.js#L178-L187) [lib/utils/cmd-list.js#L144-172](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/cmd-list.js#L144-L172)
- Install combines flatOptions, destination path, requested additions, workspace names, and resolved script policy into Arborist options; buildIdealTree initializes state, applies extensions and requests, resolves dependencies, checks platform compatibility, and resolves patches. — [lib/commands/install.js#L147-158](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/install.js#L147-L158) [workspaces/arborist/lib/arborist/build-ideal-tree.js#L177-198](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/build-ideal-tree.js#L177-L198)
- Reification passes each non-link node's resolved source and integrity to pacote.extract, determines root source-policy eligibility from dependency edges, then applies its patch; link nodes instead enter a filesystem symlink path. — [workspaces/arborist/lib/arborist/reify.js#L695-715](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/reify.js#L695-L715) [workspaces/arborist/lib/arborist/reify.js#L740-775](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/reify.js#L740-L775)
- Successful installation persistence updates dependency fields through PackageJson.save, saves ideal-tree lock metadata, then transfers idealTree to actualTree and writes node_modules/.package-lock.json or a linked-layout hidden lock. — [workspaces/arborist/lib/arborist/reify.js#L1990-2034](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/reify.js#L1990-L2034) [workspaces/arborist/lib/arborist/reify.js#L257-274](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/reify.js#L257-L274)
- Login selects a registry, obtains a token through auth.login, stores it under a registry-scoped user configuration key, and serializes raw INI data to the configured user file with mode 0600. — [lib/commands/login.js#L15-44](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/login.js#L15-L44) [lib/utils/auth.js#L35-65](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/auth.js#L35-L65) [workspaces/config/lib/index.js#L884-896](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/config/lib/index.js#L884-L896) [workspaces/config/lib/index.js#L936-939](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/config/lib/index.js#L936-L939)
- Publishing transforms a package spec into a prepared manifest and in-memory tarball, rereads publication settings, selects registry credentials, and sends bytes through libpub; Npm.finish flushes buffered output with final JSON/error metadata. — [lib/commands/publish.js#L95-129](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/publish.js#L95-L129) [lib/commands/publish.js#L145-162](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/publish.js#L145-L162) [lib/commands/publish.js#L204-225](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/publish.js#L204-L225) [lib/npm.js#L324-338](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/npm.js#L324-L338)

## Behavior traces

The investigated flows include startup and dispatch, installation through filesystem persistence, clean installation, login through credential persistence, explicit script execution, and publishing. Each trace follows source call order and preserves significant branches. Installation and ci differ in validation, cleanup, and root-script timing. These are static traces rather than observed runtime executions.
- Startup: npm-cli.js → cli(process) → validateEngines → getCli() → entry(process, validation) → gracefulify(fs) → new ExitHandler → new Npm → npm.load(); unsupported but parseable Node versions receive a warning. — [bin/npm-cli.js#L1-2](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/bin/npm-cli.js#L1-L2) [lib/cli.js#L9-12](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/cli.js#L9-L12) [lib/cli/validate-engines.js#L28-42](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/cli/validate-engines.js#L28-L42) [lib/cli/entry.js#L6-36](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/cli/entry.js#L6-L36)
- Dispatch: entry awaits load, exits early for version-only mode or missing commands, starts npm.exec(command,args), launches an unawaited update notification, awaits execution, and routes success or failure to exitHandler.exit. — [lib/cli/entry.js#L35-70](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/cli/entry.js#L35-L70) [lib/npm.js#L114-118](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/npm.js#L114-L118) [lib/npm.js#L205-225](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/npm.js#L205-L225)
- Bare local install: Install.exec → resolveAllowScripts → root preinstall when scripts are enabled → new Arborist → strictAllowScriptsPreflight → arb.reify → install/postinstall/prepublish/preprepare/prepare/postprepare → reifyFinish; explicit additions and global installs skip this root lifecycle sequence. — [lib/commands/install.js#L147-191](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/install.js#L147-L191) [lib/utils/strict-allow-scripts-preflight.js#L16-38](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/strict-allow-scripts-preflight.js#L16-L38) [lib/utils/reify-finish.js#L8-22](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/reify-finish.js#L8-L22)
- Arborist persistence: reify → _loadTrees → _diffTrees → #reifyPackages → _saveIdealTree → actualize tree → save hidden lock; local tree loading runs loadActual and buildIdealTree concurrently, while global loading builds ideal state first. — [workspaces/arborist/lib/arborist/reify.js#L118-164](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/reify.js#L118-L164) [workspaces/arborist/lib/arborist/reify.js#L257-274](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/reify.js#L257-L274) [workspaces/arborist/lib/arborist/reify.js#L417-431](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/reify.js#L417-L431)
- Clean install: CI.exec rejects global mode and CLI patch-relax flags → loadVirtual on one Arborist → buildIdealTree on another → script preflight → validate inventories, packageExtensions, and extension hash → clear workspace node_modules unless dry-run → root preinstall → reify → remaining root hooks → reifyFinish. — [lib/commands/ci.js#L41-71](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/ci.js#L41-L71) [lib/commands/ci.js#L74-113](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/ci.js#L74-L113) [lib/commands/ci.js#L116-149](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/ci.js#L116-L149) [lib/commands/ci.js#L151-164](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/ci.js#L151-L164)
- Login persistence: Login.exec chooses scoped registry unless CLI overrides it → getCredentialsByURI → auth.login → loginWeb or ENYI fallback to username/password and loginCouch through otplease → setCredentialsByURI → save('user') → print message. — [lib/commands/login.js#L15-46](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/login.js#L15-L46) [lib/utils/auth.js#L35-65](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/auth.js#L35-L65) [workspaces/config/lib/index.js#L868-896](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/config/lib/index.js#L868-L896)
- Explicit script: RunScript.exec → #run → normalize package → resolve requested/default event → handle missing script or if-present → construct pre/main/post events → await runScript for each; only the main event receives forwarded positional arguments. — [lib/commands/run.js#L42-47](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/run.js#L42-L47) [lib/commands/run.js#L87-120](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/run.js#L87-L120) [lib/commands/run.js#L122-145](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/run.js#L122-L145)
- Publish: exec → #publish → #getManifest → reject non-private packageExtensions → directory prepublishOnly → pack → reread manifest → pickRegistry → oidc → credential/version checks → libpub through otplease, or staged libpub without OTP → directory publish/postpublish hooks → output. — [lib/commands/publish.js#L43-51](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/publish.js#L43-L51) [lib/commands/publish.js#L95-129](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/publish.js#L95-L129) [lib/commands/publish.js#L145-216](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/publish.js#L145-L216) [lib/commands/publish.js#L228-255](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/publish.js#L228-L255)

## Testing signals

Tests and CI were inspected, not executed; test existence and configured coverage thresholds are not passing results. The inspected manifests and tests use TAP, correcting the inventory's Vitest tag for these surfaces. Coverage combines temporary-project integration tests, mocked registries and scripts, output assertions, and smoke tests. Inventory and test inspection were bounded, with explicit platform and live-integration limits.
- Root tests use tap ^16.3.9 and the test script is tap; docs and mock-globals also use TAP. CONTRIBUTING expects regression tests and describes a 100% coverage requirement, without establishing achieved coverage. — [package.json#L189-217](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/package.json#L189-L217) [docs/package.json#L7-16](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/docs/package.json#L7-L16) [mock-globals/package.json#L7-15](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/mock-globals/package.json#L7-L15) [CONTRIBUTING.md#L47-49](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/CONTRIBUTING.md#L47-L49)
- Root TAP excludes docs, smoke-tests, mock-globals, mock-registry, and workspaces from root coverage/test discovery; workspace suites therefore require separate execution rather than relying on root tests. — [package.json#L240-255](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/package.json#L240-L255) [.github/workflows/ci-npmcli-arborist.yml#L111-120](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/.github/workflows/ci-npmcli-arborist.yml#L111-L120)
- mock-npm breaks configuration-definition singleton caching, subclasses Npm, awaits background log cleanup, and reconstructs config.argv for direct exec calls; these deliberate test/runtime differences matter when reproducing dispatch bugs. — [test/fixtures/mock-npm.js#L51-94](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/test/fixtures/mock-npm.js#L51-L94)
- CLI entry tests assert process-title sanitization and redaction of registry URL passwords in both separate-value and equals-style arguments; these assertions cover specified examples rather than arbitrary secrets. — [test/lib/cli/entry.js#L71-105](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/test/lib/cli/entry.js#L71-L105)
- Install regression tests check preinstall before dependency presence, postinstall afterward, ignore-scripts suppression, and preinstall failure preventing dependency installation; the script runner is mocked rather than executing a real bootstrap command. — [test/lib/commands/install.js#L120-144](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/test/lib/commands/install.js#L120-L144) [test/lib/commands/install.js#L147-177](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/test/lib/commands/install.js#L147-L177) [test/lib/commands/install.js#L181-213](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/test/lib/commands/install.js#L181-L213)
- ci tests inspect real temporary node_modules changes with mocked tarball/advisory responses, verify dry-run preservation and repeated cleanup, reject stale packageExtensions state, and assert lifecycle ordering and failure behavior. — [test/lib/commands/ci.js#L52-92](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/test/lib/commands/ci.js#L52-L92) [test/lib/commands/ci.js#L95-139](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/test/lib/commands/ci.js#L95-L139) [test/lib/commands/ci.js#L251-288](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/test/lib/commands/ci.js#L251-L288) [test/lib/commands/ci.js#L324-356](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/test/lib/commands/ci.js#L324-L356)
- Login tests use mock globals and MockRegistry, then inspect persisted INI state for token replacement, preserved scoped email, and scoped registry selection; they do not demonstrate successful authentication against a live registry. — [test/lib/commands/login.js#L7-21](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/test/lib/commands/login.js#L7-L21) [test/lib/commands/login.js#L44-66](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/test/lib/commands/login.js#L44-L66) [test/lib/commands/login.js#L69-114](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/test/lib/commands/login.js#L69-L114)
- CI configures Linux, macOS, and Windows tests across Node 22/24/26, with Intel macOS combinations excluded; smoke/publish-dryrun jobs run on Linux, and the exec smoke case explicitly skips Windows. These workflow definitions were inspected, not run. — [.github/workflows/ci.yml#L62-100](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/.github/workflows/ci.yml#L62-L100) [.github/workflows/ci.yml#L158-198](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/.github/workflows/ci.yml#L158-L198) [.github/workflows/ci.yml#L207-247](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/.github/workflows/ci.yml#L207-L247) [smoke-tests/test/index.js#L368-388](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/smoke-tests/test/index.js#L368-L388)

## Risk map

These findings describe source-level trust boundaries and behavioral hazards, not confirmed vulnerabilities. Installation can execute project code, mutate configured filesystem locations, and consume registry metadata with credentials. Configuration and script-policy behavior have branches that comments alone do not fully explain. Mocked tests and unexecuted CI leave runtime and live-provider behavior unverified.
- NpmExtension.load imports or requires project-selected code in-process; cloning manifests and restricting returned fields constrain transformation results but do not sandbox module-level execution. — [workspaces/arborist/lib/npm-extension.js#L93-112](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/npm-extension.js#L93-L112) [workspaces/arborist/lib/npm-extension.js#L142-173](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/npm-extension.js#L142-L173) [lib/npm.js#L121-131](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/npm.js#L121-L131)
- Hypothesis requiring validation: discover checks extension-file containment using resolved path strings, then reads/imports that path; a symlink's real target may escape that lexical root boundary. This inspection does not establish exploitability. (inferred) — [workspaces/arborist/lib/npm-extension.js#L39-53](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/npm-extension.js#L39-L53) [workspaces/arborist/lib/npm-extension.js#L100-106](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/npm-extension.js#L100-L106)
- Bare install runs root preinstall before strictAllowScriptsPreflight; strict dependency-script checks therefore do not precede all root-owned code execution. — [lib/commands/install.js#L160-176](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/install.js#L160-L176) [lib/utils/strict-allow-scripts-preflight.js#L5-15](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/strict-allow-scripts-preflight.js#L5-L15)
- ci clears node_modules before root preinstall, so a failing bootstrap script can leave existing installations removed; dry-run guards cleanup but does not guard the root lifecycle calls. — [lib/commands/ci.js#L116-149](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/ci.js#L116-L149) [lib/commands/ci.js#L151-162](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/ci.js#L151-L162)
- Exec says its policy should consult user/global npmrc only, but resolveAllowScripts still probes project/user/global/builtin sources when skipProjectConfig is true; that flag skips package.json rather than the project npmrc source. — [lib/commands/exec.js#L81-86](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/exec.js#L81-L86) [lib/utils/resolve-allow-scripts.js#L107-110](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/resolve-allow-scripts.js#L107-L110) [lib/utils/resolve-allow-scripts.js#L127-138](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/resolve-allow-scripts.js#L127-L138) [lib/utils/resolve-allow-scripts.js#L174-175](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/resolve-allow-scripts.js#L174-L175)
- User credentials are serialized into a configured file, with passwords base64-encoded rather than encrypted and chmod applied after writing; Npm also creates configured caches/log directories and labels argv redaction best-effort. — [workspaces/config/lib/index.js#L884-896](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/config/lib/index.js#L884-L896) [workspaces/config/lib/index.js#L947-952](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/config/lib/index.js#L947-L952) [lib/npm.js#L134-160](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/npm.js#L134-L160)
- Publish dry-run suppresses libpub but still reaches directory lifecycle hooks, OIDC setup, and registry version checks; #registryVersions catches any fetch/parsing error and returns an empty version set. — [lib/commands/publish.js#L102-110](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/publish.js#L102-L110) [lib/commands/publish.js#L150-182](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/publish.js#L150-L182) [lib/commands/publish.js#L204-243](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/publish.js#L204-L243) [lib/commands/publish.js#L259-284](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/publish.js#L259-L284)
- Reify has staged rollback for retirement, sparse-tree creation, unpacking, and builds, but explicitly performs final trash removal without rollback; linked installs also temporarily swap tree representations and restore them in finally. — [workspaces/arborist/lib/arborist/reify.js#L120-159](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/reify.js#L120-L159) [workspaces/arborist/lib/arborist/reify.js#L328-369](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/reify.js#L328-L369)

## Extension points

Extension mechanisms range from internal command registration to project-controlled dependency policy. Command metadata integrates help, parsing, workspace behavior, and nested routing. Arborist mixes independently defined behaviors and supports both declarative and executable manifest repair. These extension points carry different trust and persistence contracts.
- A top-level command plugs into the alphabetically sorted commands table and corresponding lib/commands filename; aliases and abbreviations pass through deref before Npm.cmd loads the class. — [lib/utils/cmd-list.js#L3-6](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/cmd-list.js#L3-L6) [lib/utils/cmd-list.js#L76-113](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/cmd-list.js#L76-L113) [lib/utils/cmd-list.js#L144-172](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/cmd-list.js#L144-L172) [lib/npm.js#L20-29](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/npm.js#L20-L29)
- BaseCommand metadata provides name, description, params, definitions, subcommands, and positional limits; flags builds types/defaults/aliases from definitions and validates before returning parsed flags and positional arguments. — [lib/base-cmd.js#L5-18](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/base-cmd.js#L5-L18) [lib/base-cmd.js#L281-330](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/base-cmd.js#L281-L330) [lib/base-cmd.js#L332-364](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/base-cmd.js#L332-L364)
- Nested command families register classes through static subcommands objects, as stage and trust demonstrate; execCommandClass recursively removes consumed command names and adjusts flag-parser depth. — [lib/commands/stage/index.js#L7-14](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/stage/index.js#L7-L14) [lib/commands/trust/index.js#L8-14](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/trust/index.js#L8-L14) [lib/npm.js#L248-267](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/npm.js#L248-L267) [lib/npm.js#L297-305](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/npm.js#L297-L305)
- Global configuration extensions belong in definitions.js as Definition instances; definitions/index.js derives shorthand/default tables and invokes per-definition flatten handlers while preserving registry-scoped settings. — [workspaces/config/lib/definitions/definitions.js#L270-295](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/config/lib/definitions/definitions.js#L270-L295) [workspaces/config/lib/definitions/index.js#L12-32](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/config/lib/definitions/index.js#L12-L32)
- Arborist behavior is composed through a mixins array reduced over EventEmitter, providing a direct internal integration point for tree loading, resolution, rebuilding, and installation strategies. — [workspaces/arborist/lib/arborist/index.js#L24-27](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/index.js#L24-L27) [workspaces/arborist/lib/arborist/index.js#L39-50](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/index.js#L39-L50)
- Root packageExtensions rules match package names and semver ranges and may change only dependency/peer fields; normal dependencies are add-only, while peer ranges and peer metadata can be repaired. — [workspaces/arborist/lib/package-extensions.js#L9-15](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/package-extensions.js#L9-L15) [workspaces/arborist/lib/package-extensions.js#L23-61](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/package-extensions.js#L23-L61) [workspaces/arborist/lib/package-extensions.js#L115-150](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/package-extensions.js#L115-L150)
- Root .npm-extension.mjs/.cjs exports transformManifest(pkg,context); NpmExtension hashes the selected file, requires synchronous object results, memoizes by package identity, and returns cloned manifests with provenance. — [workspaces/arborist/lib/npm-extension.js#L15-19](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/npm-extension.js#L15-L19) [workspaces/arborist/lib/npm-extension.js#L64-90](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/npm-extension.js#L64-L90) [workspaces/arborist/lib/npm-extension.js#L115-138](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/npm-extension.js#L115-L138) [workspaces/arborist/lib/npm-extension.js#L142-186](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/npm-extension.js#L142-L186)
- Dependency patches integrate through patchedDependencies resolution during buildIdealTree and application immediately after extraction; patch commands provide edit/commit/update workflows and reject non-registry target specs. — [lib/commands/patch.js#L62-88](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/patch.js#L62-L88) [lib/commands/patch.js#L108-133](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/patch.js#L108-L133) [workspaces/arborist/lib/arborist/build-ideal-tree.js#L192-196](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/build-ideal-tree.js#L192-L196) [workspaces/arborist/lib/arborist/reify.js#L740-759](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/reify.js#L740-L759)

## Contributor handoff

Begin with the CLI coordinator, owning command, configuration definitions, and relevant workspace before changing behavior. Preserve source precedence, workspace boundaries, lifecycle ordering, and lockfile contracts. Tests and CI were inspected, not executed, and this inventory is bounded rather than exhaustive. Proposed checks below are handoff guidance for an execution-authorized task.
- Read package.json and CONTRIBUTING first; use node . <command> to invoke the checkout in an authorized development task, since index.js rejects programmatic import and installed npm may refer to another version. — [CONTRIBUTING.md#L51-69](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/CONTRIBUTING.md#L51-L69) [index.js#L1-5](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/index.js#L1-L5) [package.json#L264-266](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/package.json#L264-L266)
- For dispatch changes, read cmd-list.js, Npm.execCommandClass, and BaseCommand together; preserve aliases, nested command depth, help generation, legacy execution, and workspace capability checks. — [lib/utils/cmd-list.js#L144-172](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/utils/cmd-list.js#L144-L172) [lib/npm.js#L230-313](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/npm.js#L230-L313) [lib/base-cmd.js#L314-330](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/base-cmd.js#L314-L330)
- Keep compatibility-sensitive bootstrap files within the ES6 syntax and restricted-require rules in .eslintrc.local.js; npx currently has a documented exception because it imports the configuration definition graph. — [.eslintrc.local.js#L8-18](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/.eslintrc.local.js#L8-L18) [.eslintrc.local.js#L25-35](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/.eslintrc.local.js#L25-L35) [lib/cli/validate-engines.js#L15-42](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/cli/validate-engines.js#L15-L42)
- For configuration edits, check source precedence and flattening, plus validateCli's deferred validation; repair-oriented commands can bypass validation, and environment unknowns intentionally warn rather than error. — [workspaces/config/lib/index.js#L212-228](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/config/lib/index.js#L212-L228) [workspaces/config/lib/index.js#L704-716](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/config/lib/index.js#L704-L716) [lib/base-cmd.js#L367-430](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/base-cmd.js#L367-L430)
- For installation changes, preserve actual/virtual/ideal ownership and save semantics: ci forces save:false and ignoreExtension:true while validating extension hashes; update can still save lockfiles despite save:false. — [workspaces/arborist/lib/arborist/index.js#L1-22](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/index.js#L1-L22) [lib/commands/ci.js#L62-71](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/ci.js#L62-L71) [lib/commands/ci.js#L94-107](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/lib/commands/ci.js#L94-L107) [workspaces/arborist/lib/arborist/reify.js#L1775-1794](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/workspaces/arborist/lib/arborist/reify.js#L1775-L1794)
- Use existing mock-npm fixtures for command regression tests and explicitly account for reconstructed argv and awaited log cleanup; maintain install/ci tests that distinguish preinstall timing, script suppression, and bootstrap failure. — [test/fixtures/mock-npm.js#L62-94](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/test/fixtures/mock-npm.js#L62-L94) [test/lib/commands/install.js#L139-177](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/test/lib/commands/install.js#L139-L177) [test/lib/commands/ci.js#L283-321](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/test/lib/commands/ci.js#L283-L321)
- Tests and CI were inspected, not executed. When authorized, start with node . run test -- <relevant-test-file>, then the affected workspace suite and lint; root test-all and lint-all scripts exist, and root coverage excludes workspaces. — [CONTRIBUTING.md#L31-34](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/CONTRIBUTING.md#L31-L34) [package.json#L213-230](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/package.json#L213-L230) [package.json#L240-255](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/package.json#L240-L255) [.github/workflows/ci-npmcli-arborist.yml#L117-120](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/.github/workflows/ci-npmcli-arborist.yml#L117-L120)
- Keep edits focused on owning source, tests, and documentation: package.json is partially template-oss-managed, CI declares generated ownership, and CONTRIBUTING reserves dependency updates and tooling/automation maintenance for the core team. — [package.json#L257-261](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/package.json#L257-L261) [.github/workflows/ci.yml#L1-3](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/.github/workflows/ci.yml#L1-L3) [CONTRIBUTING.md#L76-84](https://github.com/npm/cli/blob/b317f16c80df02ea3628cfa77170d5ae9b59720c/CONTRIBUTING.md#L76-L84)

Source repository: https://github.com/npm/cli
Full evidence corpus: https://github.com/Codevetter/codevetter/tree/main/benchmarks/repo-unpacks/cli.json

## Public product links

- [CodeVetter](https://codevetter.com/)
- [Download](https://codevetter.com/download)
- [Documentation](https://codevetter.com/docs/)
- [Source](https://github.com/Codevetter/codevetter)
