@pnpm/installing.commands 1100.9.0 → 1100.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/add.js CHANGED
@@ -49,6 +49,8 @@ export function rcOptionsTypes() {
49
49
  'lockfile',
50
50
  'modules-dir',
51
51
  'network-concurrency',
52
+ 'node-experimental-package-map',
53
+ 'node-package-map-type',
52
54
  'node-linker',
53
55
  'noproxy',
54
56
  'npm-path',
@@ -275,21 +277,26 @@ export async function handler(opts, params, commands) {
275
277
  for (const pkg of opts.allowBuild) {
276
278
  mergedAllowBuilds[pkg] = true;
277
279
  }
278
- return installDeps({
280
+ await installDeps({
279
281
  ...opts,
280
282
  allowBuilds: mergedAllowBuilds,
281
283
  rebuildHandler: commands?.rebuild,
282
284
  fetchFullMetadata: getFetchFullMetadata(opts),
283
285
  include,
284
286
  includeDirect: include,
287
+ // `--dry-run` is an `install`-only preview; never let a config-level
288
+ // `dry-run` turn `add` into a no-op check.
289
+ dryRun: false,
285
290
  }, params);
291
+ return;
286
292
  }
287
- return installDeps({
293
+ await installDeps({
288
294
  ...opts,
289
295
  rebuildHandler: commands?.rebuild,
290
296
  fetchFullMetadata: getFetchFullMetadata(opts),
291
297
  include,
292
298
  includeDirect: include,
299
+ dryRun: false,
293
300
  }, params);
294
301
  }
295
302
  //# sourceMappingURL=add.js.map
package/lib/dedupe.js CHANGED
@@ -49,13 +49,15 @@ export async function handler(opts, _params, commands) {
49
49
  devDependencies: opts.dev !== false,
50
50
  optionalDependencies: opts.optional !== false,
51
51
  };
52
- return installDeps({
52
+ await installDeps({
53
53
  ...opts,
54
54
  rebuildHandler: commands?.rebuild,
55
55
  dedupe: true,
56
56
  include,
57
57
  includeDirect: include,
58
58
  lockfileCheck: opts.check ? dedupeDiffCheck : undefined,
59
+ // `--dry-run` is an `install`-only preview; `dedupe` has its own `--check`.
60
+ dryRun: false,
59
61
  }, []);
60
62
  }
61
63
  //# sourceMappingURL=dedupe.js.map
@@ -1,6 +1,7 @@
1
1
  import type { IgnoredBuilds } from '@pnpm/types';
2
2
  export interface HandleIgnoredBuildsOpts {
3
3
  allowBuilds?: Record<string, boolean | string>;
4
+ ignoreWorkspace?: boolean;
4
5
  rootProjectManifestDir?: string;
5
6
  workspaceDir?: string;
6
7
  strictDepBuilds?: boolean;
@@ -5,7 +5,9 @@ import { lexCompare } from '@pnpm/util.lex-comparator';
5
5
  export async function handleIgnoredBuilds(opts, ignoredBuilds) {
6
6
  if (!ignoredBuilds?.size)
7
7
  return;
8
- await writeIgnoredBuildsToAllowBuilds(opts, ignoredBuilds);
8
+ if (!opts.ignoreWorkspace) {
9
+ await writeIgnoredBuildsToAllowBuilds(opts, ignoredBuilds);
10
+ }
9
11
  if (opts.strictDepBuilds) {
10
12
  throw new IgnoredBuildsError(ignoredBuilds);
11
13
  }
@@ -12,8 +12,8 @@ import { findWorkspaceProjects } from '@pnpm/workspace.projects-reader';
12
12
  import { sequenceGraph } from '@pnpm/workspace.projects-sorter';
13
13
  import * as structUtils from '@yarnpkg/core/structUtils';
14
14
  import { parse as parseYarnLockfile } from '@yarnpkg/lockfile';
15
- import { parseSyml } from '@yarnpkg/parsers';
16
15
  import { rimraf } from '@zkochan/rimraf';
16
+ import yaml from 'js-yaml';
17
17
  import { loadJsonFile } from 'load-json-file';
18
18
  import { map as mapValues } from 'ramda';
19
19
  import { renderHelp } from 'render-help';
@@ -135,7 +135,7 @@ async function readYarnLockFile(dir) {
135
135
  throw new PnpmError('YARN_LOCKFILE_NOT_FOUND', 'No yarn.lock found');
136
136
  }
137
137
  function parseYarn2Lock(lockFileContents) {
138
- const parseYarnLock = parseSyml(lockFileContents);
138
+ const parseYarnLock = parseYarn2Yaml(lockFileContents);
139
139
  delete parseYarnLock.__metadata;
140
140
  const dependencies = {};
141
141
  const { parseDescriptor, parseRange } = structUtils;
@@ -151,6 +151,18 @@ function parseYarn2Lock(lockFileContents) {
151
151
  type: YarnLockType.yarn2,
152
152
  };
153
153
  }
154
+ function parseYarn2Yaml(lockFileContents) {
155
+ const parseYarnLock = yaml.load(lockFileContents, {
156
+ schema: yaml.FAILSAFE_SCHEMA,
157
+ json: true,
158
+ });
159
+ if (parseYarnLock == null)
160
+ return {};
161
+ if (typeof parseYarnLock !== 'object' || Array.isArray(parseYarnLock)) {
162
+ throw new PnpmError('YARN_LOCKFILE_PARSE_FAILED', `Expected an indexed object, got ${Array.isArray(parseYarnLock) ? 'an array' : `a ${typeof parseYarnLock}`} instead. Does your file follow YAML's rules?`);
163
+ }
164
+ return parseYarnLock;
165
+ }
154
166
  async function readNpmLockfile(dir) {
155
167
  try {
156
168
  return await loadJsonFile(path.join(dir, 'package-lock.json'));
package/lib/install.d.ts CHANGED
@@ -7,7 +7,7 @@ export declare const shorthands: Record<string, string>;
7
7
  export declare const commandNames: string[];
8
8
  export declare const recursiveByDefault = true;
9
9
  export declare function help(): string;
10
- export type InstallCommandOptions = Pick<Config, 'autoInstallPeers' | 'bail' | 'bin' | 'catalogs' | 'configDependencies' | 'dedupeInjectedDeps' | 'dedupeDirectDeps' | 'dedupePeerDependents' | 'dedupePeers' | 'deployAllFiles' | 'depth' | 'dev' | 'enableGlobalVirtualStore' | 'engineStrict' | 'excludeLinksFromLockfile' | 'frozenLockfile' | 'global' | 'globalPnpmfile' | 'hoistPattern' | 'hoistingLimits' | 'publicHoistPattern' | 'ignorePnpmfile' | 'ignoreScripts' | 'injectWorkspacePackages' | 'linkWorkspacePackages' | 'lockfileDir' | 'lockfileOnly' | 'optimisticRepeatInstall' | 'modulesDir' | 'nodeLinker' | 'patchedDependencies' | 'preferFrozenLockfile' | 'preferWorkspacePackages' | 'production' | 'registries' | 'save' | 'saveDev' | 'saveExact' | 'saveOptional' | 'savePeer' | 'savePrefix' | 'saveProd' | 'saveCatalogName' | 'saveWorkspaceProtocol' | 'lockfileIncludeTarballUrl' | 'sideEffectsCache' | 'sideEffectsCacheReadonly' | 'sort' | 'sharedWorkspaceLockfile' | 'tag' | 'trustLockfile' | 'allowBuilds' | 'optional' | 'virtualStoreDir' | 'workspaceConcurrency' | 'workspaceDir' | 'workspacePackagePatterns' | 'extraEnv' | 'resolutionMode' | 'ignoreWorkspaceCycles' | 'disallowWorkspaceCycles' | 'updateConfig' | 'overrides' | 'packageExtensions' | 'pnprServer' | 'supportedArchitectures' | 'packageConfigs'> & Pick<ConfigContext, 'allProjects' | 'cliOptions' | 'hooks' | 'rootProjectManifest' | 'rootProjectManifestDir' | 'allProjectsGraph' | 'selectedProjectsGraph'> & CreateStoreControllerOptions & Partial<Pick<Config, 'globalPkgDir'>> & {
10
+ export type InstallCommandOptions = Pick<Config, 'autoInstallPeers' | 'bail' | 'bin' | 'catalogs' | 'configDependencies' | 'dedupeInjectedDeps' | 'dedupeDirectDeps' | 'dedupePeerDependents' | 'dedupePeers' | 'deployAllFiles' | 'depth' | 'dev' | 'dryRun' | 'enableGlobalVirtualStore' | 'engineStrict' | 'excludeLinksFromLockfile' | 'frozenLockfile' | 'global' | 'globalPnpmfile' | 'hoistPattern' | 'hoistingLimits' | 'publicHoistPattern' | 'ignorePnpmfile' | 'ignoreScripts' | 'injectWorkspacePackages' | 'linkWorkspacePackages' | 'lockfileDir' | 'lockfileOnly' | 'optimisticRepeatInstall' | 'modulesDir' | 'nodeLinker' | 'patchedDependencies' | 'preferFrozenLockfile' | 'preferWorkspacePackages' | 'production' | 'registries' | 'save' | 'saveDev' | 'saveExact' | 'saveOptional' | 'savePeer' | 'savePrefix' | 'saveProd' | 'saveCatalogName' | 'saveWorkspaceProtocol' | 'lockfileIncludeTarballUrl' | 'sideEffectsCache' | 'sideEffectsCacheReadonly' | 'sort' | 'sharedWorkspaceLockfile' | 'tag' | 'trustLockfile' | 'allowBuilds' | 'optional' | 'virtualStoreDir' | 'workspaceConcurrency' | 'workspaceDir' | 'workspacePackagePatterns' | 'extraEnv' | 'resolutionMode' | 'ignoreWorkspaceCycles' | 'disallowWorkspaceCycles' | 'updateConfig' | 'overrides' | 'packageExtensions' | 'pnprServer' | 'supportedArchitectures' | 'packageConfigs'> & Pick<ConfigContext, 'allProjects' | 'cliOptions' | 'hooks' | 'rootProjectManifest' | 'rootProjectManifestDir' | 'allProjectsGraph' | 'selectedProjectsGraph'> & CreateStoreControllerOptions & Partial<Pick<Config, 'globalPkgDir'>> & {
11
11
  argv: {
12
12
  cooked?: string[];
13
13
  original: string[];
@@ -30,4 +30,4 @@ export type InstallCommandOptions = Pick<Config, 'autoInstallPeers' | 'bail' | '
30
30
  } & Partial<Pick<Config, 'ci' | 'modulesCacheMaxAge' | 'pnpmHomeDir' | 'preferWorkspacePackages' | 'strictDepBuilds' | 'useLockfile' | 'symlink'>>;
31
31
  export declare function handler(opts: InstallCommandOptions & {
32
32
  _calledFromLink?: boolean;
33
- }, _params?: string[], commands?: CommandHandlerMap): Promise<void>;
33
+ }, _params?: string[], commands?: CommandHandlerMap): Promise<void | string>;
package/lib/install.js CHANGED
@@ -3,6 +3,8 @@ import { docsUrl } from '@pnpm/cli.utils';
3
3
  import { types as allTypes } from '@pnpm/config.reader';
4
4
  import { WANTED_LOCKFILE } from '@pnpm/constants';
5
5
  import { PnpmError } from '@pnpm/error';
6
+ import { calcDedupeCheckIssues, countDedupeCheckIssues } from '@pnpm/installing.dedupe.check';
7
+ import { renderDedupeCheckIssues } from '@pnpm/installing.dedupe.issues-renderer';
6
8
  import { pick } from 'ramda';
7
9
  import { renderHelp } from 'render-help';
8
10
  import { getFetchFullMetadata } from './getFetchFullMetadata.js';
@@ -41,6 +43,8 @@ export function rcOptionsTypes() {
41
43
  'merge-git-branch-lockfiles-branch-pattern',
42
44
  'modules-dir',
43
45
  'network-concurrency',
46
+ 'node-experimental-package-map',
47
+ 'node-package-map-type',
44
48
  'node-linker',
45
49
  'noproxy',
46
50
  'package-import-method',
@@ -79,6 +83,7 @@ export function rcOptionsTypes() {
79
83
  export const cliOptionsTypes = () => ({
80
84
  ...rcOptionsTypes(),
81
85
  ...pick(['force'], allTypes),
86
+ 'dry-run': Boolean,
82
87
  'fix-lockfile': Boolean,
83
88
  'update-checksums': Boolean,
84
89
  'resolution-only': Boolean,
@@ -128,6 +133,10 @@ For options that may be used with `-r`, see "pnpm help recursive"',
128
133
  description: 'Skip reinstall if the workspace state is up-to-date',
129
134
  name: '--optimistic-repeat-install',
130
135
  },
136
+ {
137
+ description: 'Report what an install would change without writing anything to disk (no lockfile, no node_modules). Resolution still runs against the registry.',
138
+ name: '--dry-run',
139
+ },
131
140
  {
132
141
  description: '`optionalDependencies` are not installed',
133
142
  name: '--no-optional',
@@ -270,6 +279,18 @@ Install all optionalDependencies even when they don\'t satisfy the current envir
270
279
  description: 'Re-runs resolution: useful for printing out peer dependency issues',
271
280
  name: '--resolution-only',
272
281
  },
282
+ {
283
+ description: 'Override CPU architecture of native modules to install. Acceptable values are the same as the `cpu` field of `package.json` (from `process.arch`)',
284
+ name: '--cpu <arch>',
285
+ },
286
+ {
287
+ description: 'Override OS of native modules to install. Acceptable values are the same as the `os` field of `package.json` (from `process.platform`)',
288
+ name: '--os <os>',
289
+ },
290
+ {
291
+ description: 'Override libc of native modules to install. Acceptable values are the same as the `libc` field of `package.json`',
292
+ name: '--libc <libc>',
293
+ },
273
294
  ...UNIVERSAL_OPTIONS,
274
295
  ],
275
296
  },
@@ -304,6 +325,48 @@ export async function handler(opts, _params, commands) {
304
325
  installDepsOptions.lockfileOnly = true;
305
326
  installDepsOptions.forceFullResolution = true;
306
327
  }
307
- return installDeps(installDepsOptions, []);
328
+ if (opts.dryRun) {
329
+ return dryRunInstall(installDepsOptions, opts);
330
+ }
331
+ await installDeps(installDepsOptions, []);
332
+ }
333
+ /**
334
+ * Runs a full resolution but writes nothing to disk (no lockfile, no
335
+ * `node_modules`), then reports what a real install would change. Exits
336
+ * successfully regardless of whether changes were found — mirroring the
337
+ * preview semantics of `npm install --dry-run`.
338
+ */
339
+ async function dryRunInstall(installDepsOptions, opts) {
340
+ if (opts.pnprServer) {
341
+ throw new PnpmError('CONFIG_CONFLICT_DRY_RUN_WITH_PNPR_SERVER', 'Cannot use --dry-run with a configured pnpr server because the pnpr install path resolves and links through the server');
342
+ }
343
+ // `dryRun` makes the installer resolve fully and return the before/after
344
+ // wanted lockfile without writing anything. `lockfileOnly` keeps it from
345
+ // materializing `node_modules` and skips the metadata cache (resolution
346
+ // skips fetching). The optimistic fast path is disabled so resolution
347
+ // always runs.
348
+ installDepsOptions.optimisticRepeatInstall = false;
349
+ installDepsOptions.lockfileOnly = true;
350
+ installDepsOptions.dryRun = true;
351
+ const dryRunResult = await installDeps(installDepsOptions, []);
352
+ if (dryRunResult == null) {
353
+ // No comparison was produced — this install configuration's resolve path
354
+ // doesn't surface the dry-run lockfiles (e.g. a workspace without a
355
+ // shared lockfile). Report that explicitly instead of claiming "up to
356
+ // date", but keep `--dry-run`'s exit-0 contract.
357
+ return 'Dry run complete. Could not compute the changes for this install configuration (no shared lockfile to compare).';
358
+ }
359
+ return renderDryRunReport(dryRunResult);
360
+ }
361
+ function renderDryRunReport(dryRunResult) {
362
+ const issues = calcDedupeCheckIssues(dryRunResult.originalLockfile, dryRunResult.wantedLockfile, { includeImporterSpecifiers: true });
363
+ if (countDedupeCheckIssues(issues) === 0) {
364
+ return `Dry run complete. ${WANTED_LOCKFILE} is up to date; a real install would make no changes.`;
365
+ }
366
+ return [
367
+ 'Dry run complete. A real install would make the following changes (nothing was written to disk):',
368
+ '',
369
+ renderDedupeCheckIssues(issues),
370
+ ].join('\n');
308
371
  }
309
372
  //# sourceMappingURL=install.js.map
@@ -1,10 +1,10 @@
1
1
  import type { CommandHandler } from '@pnpm/cli.command';
2
2
  import type { Config, ConfigContext } from '@pnpm/config.reader';
3
- import { type UpdateMatchingFunction } from '@pnpm/installing.deps-installer';
3
+ import { type DryRunInstallResult, type UpdateMatchingFunction } from '@pnpm/installing.deps-installer';
4
4
  import type { LockfileObject } from '@pnpm/lockfile.types';
5
5
  import { type CreateStoreControllerOptions } from '@pnpm/store.connection-manager';
6
6
  import type { IncludedDependencies, PackageVulnerabilityAudit } from '@pnpm/types';
7
- export type InstallDepsOptions = Pick<Config, 'autoInstallPeers' | 'bail' | 'bin' | 'catalogs' | 'catalogMode' | 'cleanupUnusedCatalogs' | 'dedupePeerDependents' | 'dedupePeers' | 'depth' | 'dev' | 'enableGlobalVirtualStore' | 'virtualStoreOnly' | 'engineStrict' | 'excludeLinksFromLockfile' | 'global' | 'globalPnpmfile' | 'ignoreCurrentSpecifiers' | 'ignorePnpmfile' | 'ignoreScripts' | 'optimisticRepeatInstall' | 'linkWorkspacePackages' | 'lockfileDir' | 'lockfileOnly' | 'pnprServer' | 'production' | 'preferWorkspacePackages' | 'registries' | 'runtime' | 'runtimeOnFail' | 'save' | 'saveDev' | 'saveExact' | 'saveOptional' | 'savePeer' | 'savePrefix' | 'saveProd' | 'saveWorkspaceProtocol' | 'lockfileIncludeTarballUrl' | 'scriptsPrependNodePath' | 'scriptShell' | 'sideEffectsCache' | 'sideEffectsCacheReadonly' | 'sort' | 'sharedWorkspaceLockfile' | 'shellEmulator' | 'tag' | 'trustLockfile' | 'allowBuilds' | 'optional' | 'workspaceConcurrency' | 'workspaceDir' | 'workspacePackagePatterns' | 'extraEnv' | 'ignoreWorkspaceCycles' | 'disallowWorkspaceCycles' | 'configDependencies' | 'packageExtensions' | 'updateConfig' | 'virtualStoreDirMaxLength'> & Pick<ConfigContext, 'allProjects' | 'allProjectsGraph' | 'cliOptions' | 'hooks' | 'rootProjectManifestDir' | 'rootProjectManifest' | 'selectedProjectsGraph'> & Partial<Pick<Config, 'ci'>> & CreateStoreControllerOptions & {
7
+ export type InstallDepsOptions = Pick<Config, 'autoInstallPeers' | 'bail' | 'bin' | 'catalogs' | 'catalogMode' | 'cleanupUnusedCatalogs' | 'dedupePeerDependents' | 'dedupePeers' | 'depth' | 'dev' | 'enableGlobalVirtualStore' | 'virtualStoreOnly' | 'engineStrict' | 'excludeLinksFromLockfile' | 'global' | 'globalPnpmfile' | 'ignoreCurrentSpecifiers' | 'ignorePnpmfile' | 'ignoreScripts' | 'optimisticRepeatInstall' | 'linkWorkspacePackages' | 'lockfileDir' | 'lockfileOnly' | 'pnprServer' | 'production' | 'preferWorkspacePackages' | 'registries' | 'runtime' | 'runtimeOnFail' | 'save' | 'saveDev' | 'saveExact' | 'saveOptional' | 'savePeer' | 'savePrefix' | 'saveProd' | 'saveWorkspaceProtocol' | 'lockfileIncludeTarballUrl' | 'scriptsPrependNodePath' | 'scriptShell' | 'sideEffectsCache' | 'sideEffectsCacheReadonly' | 'sort' | 'sharedWorkspaceLockfile' | 'shellEmulator' | 'tag' | 'trustLockfile' | 'allowBuilds' | 'optional' | 'workspaceConcurrency' | 'workspaceDir' | 'workspacePackagePatterns' | 'extraEnv' | 'ignoreWorkspace' | 'ignoreWorkspaceCycles' | 'disallowWorkspaceCycles' | 'configDependencies' | 'packageExtensions' | 'updateConfig' | 'virtualStoreDirMaxLength'> & Pick<ConfigContext, 'allProjects' | 'allProjectsGraph' | 'cliOptions' | 'hooks' | 'rootProjectManifestDir' | 'rootProjectManifest' | 'selectedProjectsGraph'> & Partial<Pick<Config, 'ci'>> & CreateStoreControllerOptions & {
8
8
  argv: {
9
9
  cooked?: string[];
10
10
  original: string[];
@@ -48,5 +48,5 @@ export type InstallDepsOptions = Pick<Config, 'autoInstallPeers' | 'bail' | 'bin
48
48
  * subcommand — see `runPacquet.ts`'s `noRuntime` opt.
49
49
  */
50
50
  isInstallCommand?: boolean;
51
- } & Partial<Pick<Config, 'pnpmHomeDir' | 'strictDepBuilds' | 'useLockfile' | 'useGitBranchLockfile'>>;
52
- export declare function installDeps(opts: InstallDepsOptions, params: string[]): Promise<void>;
51
+ } & Partial<Pick<Config, 'dryRun' | 'pnpmHomeDir' | 'strictDepBuilds' | 'useLockfile' | 'useGitBranchLockfile' | 'mergeGitBranchLockfiles'>>;
52
+ export declare function installDeps(opts: InstallDepsOptions, params: string[]): Promise<DryRunInstallResult | undefined>;
@@ -1,5 +1,6 @@
1
1
  import path from 'node:path';
2
2
  import { buildProjects } from '@pnpm/building.after-install';
3
+ import { mergeCatalogs } from '@pnpm/catalogs.config';
3
4
  import { readProjectManifestOnly, tryReadProjectManifest, } from '@pnpm/cli.utils';
4
5
  import { checkDepsStatus } from '@pnpm/deps.status';
5
6
  import { PnpmError } from '@pnpm/error';
@@ -32,6 +33,7 @@ export async function installDeps(opts, params) {
32
33
  const { upToDate, wantedLockfileToRestore } = await checkDepsStatus({
33
34
  ...opts,
34
35
  ignoreFilteredInstallCache: true,
36
+ treatLocalFileDepsAsOutdated: true,
35
37
  });
36
38
  if (upToDate && await restoreWantedLockfileIfMissing(wantedLockfileToRestore, opts)) {
37
39
  if (opts.hooks?.customResolvers?.some(r => r.shouldRefreshResolution)) {
@@ -131,7 +133,7 @@ export async function installDeps(opts, params) {
131
133
  const allProjectsGraph = opts.allProjectsGraph ?? createProjectsGraph(allProjects, {
132
134
  linkWorkspacePackages: Boolean(opts.linkWorkspacePackages),
133
135
  }).graph;
134
- await recursiveInstallThenUpdateWorkspaceState(allProjects, params, {
136
+ return recursiveInstallThenUpdateWorkspaceState(allProjects, params, {
135
137
  ...opts,
136
138
  preferredVersions: opts.packageVulnerabilityAudit ? preferNonvulnerablePackageVersions(opts.packageVulnerabilityAudit) : undefined,
137
139
  allProjectsGraph,
@@ -140,7 +142,6 @@ export async function installDeps(opts, params) {
140
142
  workspaceDir: opts.workspaceDir,
141
143
  runPacquet,
142
144
  }, opts.update ? 'update' : (params.length === 0 ? 'install' : 'add'));
143
- return;
144
145
  }
145
146
  }
146
147
  // `pnpm install ""` is going to be just `pnpm install`
@@ -241,8 +242,8 @@ export async function installDeps(opts, params) {
241
242
  rootDir: opts.dir,
242
243
  targetDependenciesField: getSaveType(opts),
243
244
  };
244
- const { updatedCatalogs, updatedProject, ignoredBuilds, resolutionPolicyViolations } = await mutateModulesInSingleProject(mutatedProject, installOpts);
245
- if (opts.save !== false) {
245
+ const { updatedCatalogs, updatedProject, ignoredBuilds, resolutionPolicyViolations, dryRunResult } = await mutateModulesInSingleProject(mutatedProject, installOpts);
246
+ if (opts.save !== false && !opts.dryRun) {
246
247
  // Only pick entries when we'll actually persist. Otherwise the
247
248
  // info log would claim we added entries the workspace manifest
248
249
  // never saw, and the next install would re-prompt or fail
@@ -261,7 +262,7 @@ export async function installDeps(opts, params) {
261
262
  if (!opts.lockfileOnly) {
262
263
  await updateWorkspaceState({
263
264
  allProjects,
264
- settings: opts,
265
+ settings: withUpdatedCatalogs(opts, updatedCatalogs),
265
266
  workspaceDir: opts.workspaceDir ?? opts.lockfileDir ?? opts.dir,
266
267
  pnpmfiles: opts.pnpmfile,
267
268
  filteredInstall: allProjects.length !== Object.keys(opts.selectedProjectsGraph ?? {}).length,
@@ -269,9 +270,9 @@ export async function installDeps(opts, params) {
269
270
  });
270
271
  }
271
272
  await handleIgnoredBuilds(opts, ignoredBuilds);
272
- return;
273
+ return dryRunResult;
273
274
  }
274
- const { updatedCatalogs, updatedManifest, ignoredBuilds, resolutionPolicyViolations } = await install(manifest, {
275
+ const { updatedCatalogs, updatedManifest, ignoredBuilds, resolutionPolicyViolations, dryRunResult } = await install(manifest, {
275
276
  ...installOpts,
276
277
  updatePackageManifest,
277
278
  updateMatching,
@@ -280,7 +281,7 @@ export async function installDeps(opts, params) {
280
281
  // from this install" — both package.json and the workspace manifest.
281
282
  // Skip the pick so the info log doesn't claim entries were added that
282
283
  // were never written; the next install will resurface them.
283
- if (opts.save !== false) {
284
+ if (opts.save !== false && !opts.dryRun) {
284
285
  const policyUpdates = policyHandlers?.pickManifestUpdates(resolutionPolicyViolations);
285
286
  if (opts.update === true) {
286
287
  await Promise.all([
@@ -319,7 +320,7 @@ export async function installDeps(opts, params) {
319
320
  selectedProjectsGraph,
320
321
  workspaceDir: opts.workspaceDir, // Otherwise TypeScript doesn't understand that is not undefined
321
322
  runPacquet,
322
- }, 'install');
323
+ }, 'install', updatedCatalogs);
323
324
  if (opts.ignoreScripts)
324
325
  return;
325
326
  await buildProjects([
@@ -340,7 +341,7 @@ export async function installDeps(opts, params) {
340
341
  if (!opts.lockfileOnly) {
341
342
  await updateWorkspaceState({
342
343
  allProjects,
343
- settings: opts,
344
+ settings: withUpdatedCatalogs(opts, updatedCatalogs),
344
345
  workspaceDir: opts.workspaceDir ?? opts.lockfileDir ?? opts.dir,
345
346
  pnpmfiles: opts.pnpmfile,
346
347
  filteredInstall: allProjects.length !== Object.keys(opts.selectedProjectsGraph ?? {}).length,
@@ -348,6 +349,7 @@ export async function installDeps(opts, params) {
348
349
  });
349
350
  }
350
351
  }
352
+ return dryRunResult;
351
353
  }
352
354
  function selectProjectByDir(projects, searchedDir) {
353
355
  const project = projects.find(({ rootDir }) => path.relative(rootDir, searchedDir) === '');
@@ -355,19 +357,31 @@ function selectProjectByDir(projects, searchedDir) {
355
357
  return undefined;
356
358
  return { [project.rootDir]: { dependencies: [], package: project } };
357
359
  }
358
- async function recursiveInstallThenUpdateWorkspaceState(allProjects, params, opts, cmdFullName) {
360
+ async function recursiveInstallThenUpdateWorkspaceState(allProjects, params, opts, cmdFullName, updatedCatalogs) {
359
361
  const recursiveResult = await recursive(allProjects, params, opts, cmdFullName);
360
362
  if (!opts.lockfileOnly) {
361
363
  await updateWorkspaceState({
362
364
  allProjects,
363
- settings: opts,
365
+ settings: withUpdatedCatalogs(opts, updatedCatalogs, recursiveResult.updatedCatalogs),
364
366
  workspaceDir: opts.workspaceDir,
365
367
  pnpmfiles: opts.pnpmfile,
366
368
  filteredInstall: allProjects.length !== Object.keys(opts.selectedProjectsGraph ?? {}).length,
367
369
  configDependencies: opts.configDependencies,
368
370
  });
369
371
  }
370
- return recursiveResult;
372
+ return recursiveResult.dryRunResult;
373
+ }
374
+ /**
375
+ * Folds the catalog entries written to `pnpm-workspace.yaml` during this
376
+ * install into the catalogs read at startup. The workspace state cache records
377
+ * these so a later install detects when a catalog entry was reverted; without
378
+ * this, the cache would keep the stale pre-install catalogs and report
379
+ * "Already up to date" even though the manifest changed.
380
+ */
381
+ function withUpdatedCatalogs(settings, ...updatedCatalogs) {
382
+ if (updatedCatalogs.every((catalogs) => catalogs == null))
383
+ return settings;
384
+ return { ...settings, catalogs: mergeCatalogs(settings.catalogs, ...updatedCatalogs) };
371
385
  }
372
386
  function severityStringToNumber(severity) {
373
387
  switch (severity) {
@@ -1,4 +1,5 @@
1
1
  import { confirm } from '@inquirer/prompts';
2
+ import { mergePackageVersionSpecs } from '@pnpm/config.version-policy';
2
3
  import { PnpmError } from '@pnpm/error';
3
4
  import { globalInfo } from '@pnpm/logger';
4
5
  import { MINIMUM_RELEASE_AGE_VIOLATION_CODE } from '@pnpm/resolving.npm-resolver';
@@ -120,7 +121,12 @@ function pickImmatureEntries(violations, promptRequired) {
120
121
  const immature = filterImmatureViolations(violations);
121
122
  if (immature.length === 0)
122
123
  return undefined;
123
- const sorted = [...new Set(immature.map((v) => `${v.name}@${v.version}`))].sort();
124
+ // Combine into the canonical per-package form the workspace writer
125
+ // persists (`name@v1 || v2`), so the logged count and list match the
126
+ // entries that actually land in pnpm-workspace.yaml even when multiple
127
+ // immature versions belong to the same package. The pre-sort keeps the
128
+ // cross-package order stable regardless of resolution order.
129
+ const entries = mergePackageVersionSpecs(immature.map((v) => `${v.name}@${v.version}`).sort());
124
130
  // Strict-mode picks already passed through the approval prompt, so
125
131
  // the log here only confirms what was persisted. Loose-mode picks
126
132
  // haven't been announced anywhere else, so the same log doubles as
@@ -128,9 +134,9 @@ function pickImmatureEntries(violations, promptRequired) {
128
134
  const reason = promptRequired
129
135
  ? '(approved at the prompt)'
130
136
  : '(set minimumReleaseAgeStrict to true to gate these updates with a prompt)';
131
- globalInfo(`Added ${sorted.length} ${sorted.length === 1 ? 'entry' : 'entries'} to minimumReleaseAgeExclude in pnpm-workspace.yaml ` +
132
- `${reason}:\n ${sorted.join('\n ')}`);
133
- return sorted;
137
+ globalInfo(`Added ${entries.length} ${entries.length === 1 ? 'entry' : 'entries'} to minimumReleaseAgeExclude in pnpm-workspace.yaml ` +
138
+ `${reason}:\n ${entries.join('\n ')}`);
139
+ return entries;
134
140
  }
135
141
  function failOnImmature(immature) {
136
142
  const sorted = [...immature].sort((a, b) => `${a.name}@${a.version}`.localeCompare(`${b.name}@${b.version}`));
package/lib/prune.js CHANGED
@@ -39,7 +39,7 @@ export function help() {
39
39
  });
40
40
  }
41
41
  export async function handler(opts) {
42
- return install.handler({
42
+ await install.handler({
43
43
  ...opts,
44
44
  modulesCacheMaxAge: 0,
45
45
  pruneDirectDependencies: true,
@@ -1,12 +1,13 @@
1
+ import type { Catalogs } from '@pnpm/catalogs.types';
1
2
  import type { CommandHandler } from '@pnpm/cli.command';
2
3
  import { type Config, type ConfigContext } from '@pnpm/config.reader';
3
- import { type UpdateMatchingFunction } from '@pnpm/installing.deps-installer';
4
+ import { type DryRunInstallResult, type UpdateMatchingFunction } from '@pnpm/installing.deps-installer';
4
5
  import type { PreferredVersions } from '@pnpm/resolving.resolver-base';
5
6
  import type { ResolutionVerifier } from '@pnpm/resolving.resolver-base';
6
7
  import { type CreateStoreControllerOptions } from '@pnpm/store.connection-manager';
7
8
  import type { StoreController } from '@pnpm/store.controller';
8
9
  import type { IncludedDependencies, Project, ProjectManifest, ProjectsGraph } from '@pnpm/types';
9
- export type RecursiveOptions = CreateStoreControllerOptions & Pick<Config, 'bail' | 'configDependencies' | 'dedupePeerDependents' | 'dedupePeers' | 'depth' | 'globalPnpmfile' | 'hoistPattern' | 'hoistingLimits' | 'ignorePnpmfile' | 'ignoreScripts' | 'linkWorkspacePackages' | 'lockfileDir' | 'lockfileOnly' | 'modulesDir' | 'pnprServer' | 'allowBuilds' | 'registries' | 'runtime' | 'save' | 'saveCatalogName' | 'saveDev' | 'saveExact' | 'saveOptional' | 'savePeer' | 'savePrefix' | 'saveProd' | 'saveWorkspaceProtocol' | 'lockfileIncludeTarballUrl' | 'sharedWorkspaceLockfile' | 'tag' | 'trustLockfile' | 'cleanupUnusedCatalogs' | 'packageConfigs' | 'updateConfig'> & Pick<ConfigContext, 'hooks' | 'rootProjectManifest' | 'rootProjectManifestDir'> & {
10
+ export type RecursiveOptions = CreateStoreControllerOptions & Pick<Config, 'bail' | 'configDependencies' | 'dedupePeerDependents' | 'dedupePeers' | 'depth' | 'dryRun' | 'globalPnpmfile' | 'hoistPattern' | 'hoistingLimits' | 'ignorePnpmfile' | 'ignoreScripts' | 'linkWorkspacePackages' | 'lockfileDir' | 'lockfileOnly' | 'modulesDir' | 'pnprServer' | 'allowBuilds' | 'registries' | 'runtime' | 'save' | 'saveCatalogName' | 'saveDev' | 'saveExact' | 'saveOptional' | 'savePeer' | 'savePrefix' | 'saveProd' | 'saveWorkspaceProtocol' | 'lockfileIncludeTarballUrl' | 'sharedWorkspaceLockfile' | 'tag' | 'trustLockfile' | 'cleanupUnusedCatalogs' | 'packageConfigs' | 'updateConfig'> & Pick<ConfigContext, 'hooks' | 'rootProjectManifest' | 'rootProjectManifestDir'> & {
10
11
  rebuildHandler?: CommandHandler;
11
12
  include?: IncludedDependencies;
12
13
  includeDirect?: IncludedDependencies;
@@ -45,7 +46,21 @@ export type RecursiveOptions = CreateStoreControllerOptions & Pick<Config, 'bail
45
46
  };
46
47
  } & Partial<Pick<Config, 'ci' | 'sort' | 'strictDepBuilds' | 'workspaceConcurrency'>> & Required<Pick<Config, 'workspaceDir'>>;
47
48
  export type CommandFullName = 'install' | 'add' | 'remove' | 'update' | 'import';
48
- export declare function recursive(allProjects: Project[], params: string[], opts: RecursiveOptions, cmdFullName: CommandFullName): Promise<boolean | string>;
49
+ export interface RecursiveResult {
50
+ passed: boolean | string;
51
+ /**
52
+ * Catalog entries written to `pnpm-workspace.yaml` during this install.
53
+ * The caller folds these into the catalogs recorded in the workspace state
54
+ * cache so that reverting a catalog entry is detected as an outdated state.
55
+ */
56
+ updatedCatalogs?: Catalogs;
57
+ /**
58
+ * Present only for a `dryRun` install over a shared workspace lockfile:
59
+ * the before/after wanted lockfiles for the caller to diff.
60
+ */
61
+ dryRunResult?: DryRunInstallResult;
62
+ }
63
+ export declare function recursive(allProjects: Project[], params: string[], opts: RecursiveOptions, cmdFullName: CommandFullName): Promise<RecursiveResult>;
49
64
  export declare function matchDependencies(match: (input: string) => string | null, manifest: ProjectManifest, include: IncludedDependencies): string[];
50
65
  export type UpdateDepsMatcher = (input: string) => string | null;
51
66
  export declare function createMatcher(params: string[]): UpdateDepsMatcher;
package/lib/recursive.js CHANGED
@@ -1,5 +1,6 @@
1
1
  import { promises as fs } from 'node:fs';
2
2
  import path from 'node:path';
3
+ import { mergeCatalogs } from '@pnpm/catalogs.config';
3
4
  import { throwOnCommandFail, } from '@pnpm/cli.utils';
4
5
  import { createMatcherWithIndex } from '@pnpm/config.matcher';
5
6
  import { createProjectConfigRecord, getWorkspaceConcurrency, } from '@pnpm/config.reader';
@@ -23,11 +24,11 @@ import { createWorkspaceSpecs, updateToWorkspacePackagesFromManifest } from './u
23
24
  export async function recursive(allProjects, params, opts, cmdFullName) {
24
25
  if (allProjects.length === 0) {
25
26
  // It might make sense to throw an exception in this case
26
- return false;
27
+ return { passed: false };
27
28
  }
28
29
  const pkgs = Object.values(opts.selectedProjectsGraph).map((wsPkg) => wsPkg.package);
29
30
  if (pkgs.length === 0) {
30
- return false;
31
+ return { passed: false };
31
32
  }
32
33
  const manifestsByPath = getManifestsByPath(allProjects);
33
34
  const throwOnFail = throwOnCommandFail.bind(null, `pnpm recursive ${cmdFullName}`);
@@ -88,7 +89,7 @@ export async function recursive(allProjects, params, opts, cmdFullName) {
88
89
  const isFromWorkspace = isSubdir.bind(null, calculatedRepositoryRoot);
89
90
  importers = await pFilter(importers, async ({ rootDirRealPath }) => isFromWorkspace(rootDirRealPath));
90
91
  if (importers.length === 0)
91
- return true;
92
+ return { passed: true };
92
93
  let mutation;
93
94
  switch (cmdFullName) {
94
95
  case 'remove':
@@ -176,12 +177,12 @@ export async function recursive(allProjects, params, opts, cmdFullName) {
176
177
  if ((mutatedImporters.length === 0) && cmdFullName === 'update' && opts.depth === 0) {
177
178
  throw new PnpmError('NO_PACKAGE_IN_DEPENDENCIES', 'None of the specified packages were found in the dependencies of any of the projects.');
178
179
  }
179
- const { updatedCatalogs, updatedProjects: mutatedPkgs, ignoredBuilds, resolutionPolicyViolations, } = await mutateModules(mutatedImporters, {
180
+ const { updatedCatalogs, updatedProjects: mutatedPkgs, ignoredBuilds, resolutionPolicyViolations, dryRunResult, } = await mutateModules(mutatedImporters, {
180
181
  ...installOpts,
181
182
  storeController: store.ctrl,
182
183
  resolutionVerifiers: store.resolutionVerifiers,
183
184
  });
184
- if (opts.save !== false) {
185
+ if (opts.save !== false && !opts.dryRun) {
185
186
  // Only pick entries when we'll actually persist. Otherwise the
186
187
  // info log would claim entries were added that the workspace
187
188
  // manifest never saw, and the next install would re-prompt or
@@ -199,7 +200,7 @@ export async function recursive(allProjects, params, opts, cmdFullName) {
199
200
  await Promise.all(promises);
200
201
  }
201
202
  await handleIgnoredBuilds(opts, ignoredBuilds);
202
- return true;
203
+ return { passed: true, updatedCatalogs, dryRunResult };
203
204
  }
204
205
  const pkgPaths = Object.keys(opts.selectedProjectsGraph).sort();
205
206
  let updatedCatalogs;
@@ -289,8 +290,10 @@ export async function recursive(allProjects, params, opts, cmdFullName) {
289
290
  if (opts.save !== false) {
290
291
  await writeProjectManifest(newManifest);
291
292
  if (newCatalogsAddition) {
292
- updatedCatalogs ??= {};
293
- Object.assign(updatedCatalogs, newCatalogsAddition);
293
+ // Per-project additions are partial maps keyed by catalog name then
294
+ // dependency. Merge at the dependency level so two projects updating
295
+ // different entries of the same catalog don't clobber each other.
296
+ updatedCatalogs = mergeCatalogs(updatedCatalogs, newCatalogsAddition);
294
297
  }
295
298
  }
296
299
  if (ignoredBuilds?.size) {
@@ -346,7 +349,7 @@ export async function recursive(allProjects, params, opts, cmdFullName) {
346
349
  if (!Object.values(result).filter(({ status }) => status === 'passed').length && cmdFullName === 'update' && opts.depth === 0) {
347
350
  throw new PnpmError('NO_PACKAGE_IN_DEPENDENCIES', 'None of the specified packages were found in the dependencies of any of the projects.');
348
351
  }
349
- return true;
352
+ return { passed: true, updatedCatalogs };
350
353
  }
351
354
  function calculateRepositoryRoot(workspaceDir, projectDirs) {
352
355
  // assume repo root is workspace dir
package/lib/remove.js CHANGED
@@ -39,6 +39,8 @@ export function rcOptionsTypes() {
39
39
  'lockfile-dir',
40
40
  'lockfile-only',
41
41
  'lockfile',
42
+ 'node-experimental-package-map',
43
+ 'node-package-map-type',
42
44
  'node-linker',
43
45
  'package-import-method',
44
46
  'pnpmfile',
@@ -137,6 +139,9 @@ export async function handler(opts, params) {
137
139
  storeDir: store.dir,
138
140
  resolutionVerifiers: store.resolutionVerifiers,
139
141
  include,
142
+ // `--dry-run` is an `install`-only preview; never let a config-level
143
+ // `dry-run` turn `remove` into a no-op check.
144
+ dryRun: false,
140
145
  });
141
146
  const allProjects = opts.allProjects ?? (opts.workspaceDir
142
147
  ? await findWorkspaceProjects(opts.workspaceDir, { ...opts, patterns: opts.workspacePackagePatterns })
@@ -38,6 +38,8 @@ export function rcOptionsTypes() {
38
38
  'lockfile',
39
39
  'lockfile-include-tarball-url',
40
40
  'network-concurrency',
41
+ 'node-experimental-package-map',
42
+ 'node-package-map-type',
41
43
  'noproxy',
42
44
  'npm-path',
43
45
  'offline',
@@ -135,6 +137,10 @@ dependencies is not found inside the workspace',
135
137
  name: '--interactive',
136
138
  shortAlias: '-i',
137
139
  },
140
+ {
141
+ description: 'Don\'t update the ranges in package.json.',
142
+ name: '--no-save',
143
+ },
138
144
  OPTIONS.globalDir,
139
145
  ...UNIVERSAL_OPTIONS,
140
146
  ],
@@ -276,7 +282,7 @@ async function update(dependencies, opts, rebuildHandler) {
276
282
  else if ((dependencies.length > 0) && dependencies.every(dep => !dep.substring(1).includes('@')) && depth > 0 && !opts.latest) {
277
283
  updateMatching = createMatcher(dependencies);
278
284
  }
279
- return installDeps({
285
+ await installDeps({
280
286
  ...opts,
281
287
  rebuildHandler,
282
288
  allowNew: false,
@@ -289,6 +295,9 @@ async function update(dependencies, opts, rebuildHandler) {
289
295
  updateMatching,
290
296
  updatePackageManifest: opts.save !== false,
291
297
  resolutionMode: opts.save === false ? 'highest' : opts.resolutionMode,
298
+ // `--dry-run` is an `install`-only preview; never let a config-level
299
+ // `dry-run` turn `update` into a no-op check.
300
+ dryRun: false,
292
301
  }, dependencies);
293
302
  }
294
303
  function makeIncludeDependenciesFromCLI(opts) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pnpm/installing.commands",
3
- "version": "1100.9.0",
3
+ "version": "1100.10.1",
4
4
  "description": "Commands for installation",
5
5
  "keywords": [
6
6
  "pnpm",
@@ -10,9 +10,9 @@
10
10
  "funding": "https://opencollective.com/pnpm",
11
11
  "repository": {
12
12
  "type": "git",
13
- "url": "https://github.com/pnpm/pnpm/tree/main/installing/commands"
13
+ "url": "https://github.com/pnpm/pnpm/tree/main/pnpm11/installing/commands"
14
14
  },
15
- "homepage": "https://github.com/pnpm/pnpm/tree/main/installing/commands#readme",
15
+ "homepage": "https://github.com/pnpm/pnpm/tree/main/pnpm11/installing/commands#readme",
16
16
  "bugs": {
17
17
  "url": "https://github.com/pnpm/pnpm/issues"
18
18
  },
@@ -33,14 +33,13 @@
33
33
  "@pnpm/util.lex-comparator": "^4.0.1",
34
34
  "@yarnpkg/core": "4.8.0",
35
35
  "@yarnpkg/lockfile": "^1.1.0",
36
- "@yarnpkg/parsers": "3.0.3",
37
36
  "@zkochan/rimraf": "^4.0.0",
38
37
  "@zkochan/table": "^2.0.1",
39
38
  "chalk": "^5.6.2",
40
39
  "ci-info": "^4.4.0",
41
40
  "detect-libc": "^2.1.2",
42
- "get-npm-tarball-url": "^2.1.0",
43
41
  "is-subdir": "^2.0.0",
42
+ "js-yaml": "npm:@zkochan/js-yaml@0.0.11",
44
43
  "load-json-file": "^7.0.1",
45
44
  "normalize-path": "^3.0.0",
46
45
  "p-filter": "^4.1.0",
@@ -48,57 +47,61 @@
48
47
  "ramda": "npm:@pnpm/ramda@0.28.1",
49
48
  "render-help": "^2.0.0",
50
49
  "version-selector-type": "^3.0.0",
51
- "@pnpm/building.after-install": "1102.0.0",
52
- "@pnpm/building.policy": "1100.0.10",
50
+ "@pnpm/building.policy": "1100.0.11",
53
51
  "@pnpm/catalogs.types": "1100.0.0",
54
- "@pnpm/cli.utils": "1101.0.12",
55
- "@pnpm/cli.common-cli-options-help": "1100.0.2",
52
+ "@pnpm/catalogs.config": "1100.0.2",
56
53
  "@pnpm/cli.command": "1100.0.1",
57
- "@pnpm/config.matcher": "1100.0.1",
54
+ "@pnpm/cli.utils": "1101.0.13",
58
55
  "@pnpm/config.pick-registry-for-package": "1100.0.9",
59
- "@pnpm/config.reader": "1101.9.0",
60
- "@pnpm/config.writer": "1100.0.13",
56
+ "@pnpm/cli.common-cli-options-help": "1100.0.2",
57
+ "@pnpm/config.reader": "1101.10.1",
58
+ "@pnpm/building.after-install": "1102.0.2",
59
+ "@pnpm/config.writer": "1100.0.14",
61
60
  "@pnpm/constants": "1100.0.0",
62
- "@pnpm/deps.inspection.outdated": "1100.1.8",
61
+ "@pnpm/config.version-policy": "1100.1.6",
62
+ "@pnpm/deps.inspection.outdated": "1100.1.10",
63
+ "@pnpm/config.matcher": "1100.0.1",
63
64
  "@pnpm/deps.path": "1100.0.8",
64
- "@pnpm/deps.security.signatures": "1101.2.2",
65
- "@pnpm/deps.status": "1100.1.1",
66
- "@pnpm/error": "1100.0.0",
67
- "@pnpm/fs.read-modules-dir": "1100.0.1",
65
+ "@pnpm/error": "1100.0.1",
66
+ "@pnpm/deps.security.signatures": "1101.2.3",
68
67
  "@pnpm/fs.graceful-fs": "1100.1.0",
69
- "@pnpm/global.commands": "1100.0.28",
70
- "@pnpm/hooks.pnpmfile": "1100.0.15",
71
- "@pnpm/installing.dedupe.check": "1100.0.11",
72
- "@pnpm/installing.context": "1100.0.18",
73
- "@pnpm/installing.env-installer": "1102.0.0",
74
- "@pnpm/lockfile.types": "1100.0.11",
75
- "@pnpm/installing.deps-installer": "1102.0.0",
76
- "@pnpm/network.fetch": "1100.1.3",
77
- "@pnpm/lockfile.fs": "1100.1.5",
78
- "@pnpm/network.auth-header": "1101.1.2",
79
- "@pnpm/pkg-manifest.reader": "1100.0.8",
80
- "@pnpm/resolving.npm-resolver": "1102.0.0",
68
+ "@pnpm/global.commands": "1100.0.30",
69
+ "@pnpm/deps.status": "1100.1.3",
70
+ "@pnpm/hooks.pnpmfile": "1100.0.16",
71
+ "@pnpm/installing.context": "1100.0.20",
72
+ "@pnpm/installing.dedupe.check": "1100.1.1",
73
+ "@pnpm/installing.deps-installer": "1102.1.1",
74
+ "@pnpm/installing.dedupe.issues-renderer": "1100.0.1",
75
+ "@pnpm/lockfile.types": "1100.0.12",
76
+ "@pnpm/lockfile.fs": "1100.1.7",
77
+ "@pnpm/network.fetch": "1100.1.4",
78
+ "@pnpm/network.auth-header": "1101.1.3",
79
+ "@pnpm/pkg-manifest.reader": "1100.0.9",
80
+ "@pnpm/installing.env-installer": "1102.0.2",
81
+ "@pnpm/pkg-manifest.utils": "1100.2.6",
81
82
  "@pnpm/resolving.parse-wanted-dependency": "1100.0.1",
82
- "@pnpm/pkg-manifest.utils": "1100.2.5",
83
- "@pnpm/store.connection-manager": "1100.3.0",
84
- "@pnpm/resolving.resolver-base": "1100.4.2",
85
- "@pnpm/store.controller": "1102.0.0",
83
+ "@pnpm/store.controller": "1102.0.2",
84
+ "@pnpm/resolving.npm-resolver": "1102.1.0",
85
+ "@pnpm/store.connection-manager": "1100.3.2",
86
+ "@pnpm/resolving.resolver-base": "1100.5.0",
86
87
  "@pnpm/types": "1101.3.2",
87
- "@pnpm/workspace.project-manifest-reader": "1100.0.13",
88
+ "@pnpm/fs.read-modules-dir": "1100.0.1",
88
89
  "@pnpm/workspace.project-manifest-writer": "1100.0.8",
89
- "@pnpm/workspace.projects-filter": "1100.0.21",
90
- "@pnpm/workspace.projects-reader": "1101.0.12",
91
- "@pnpm/workspace.projects-graph": "1100.0.18",
90
+ "@pnpm/workspace.projects-filter": "1100.0.23",
91
+ "@pnpm/workspace.project-manifest-reader": "1100.0.14",
92
+ "@pnpm/workspace.projects-reader": "1101.0.13",
93
+ "@pnpm/workspace.projects-graph": "1100.0.20",
94
+ "@pnpm/workspace.state": "1100.0.24",
92
95
  "@pnpm/workspace.projects-sorter": "1100.0.7",
93
- "@pnpm/workspace.root-finder": "1100.0.1",
94
- "@pnpm/workspace.state": "1100.0.22",
95
- "@pnpm/workspace.workspace-manifest-writer": "1100.0.13"
96
+ "@pnpm/workspace.root-finder": "1100.0.3",
97
+ "@pnpm/workspace.workspace-manifest-writer": "1100.0.14"
96
98
  },
97
99
  "peerDependencies": {
98
100
  "@pnpm/logger": "^1100.0.0"
99
101
  },
100
102
  "devDependencies": {
101
103
  "@jest/globals": "30.4.1",
104
+ "@types/js-yaml": "^4.0.9",
102
105
  "@types/normalize-path": "^3.0.2",
103
106
  "@types/proxyquire": "^1.3.31",
104
107
  "@types/ramda": "0.31.1",
@@ -114,19 +117,19 @@
114
117
  "write-json-file": "^7.0.0",
115
118
  "write-package": "7.2.0",
116
119
  "write-yaml-file": "^6.0.0",
117
- "@pnpm/installing.commands": "1100.9.0",
118
- "@pnpm/assert-project": "1100.0.16",
119
120
  "@pnpm/installing.modules-yaml": "1100.0.9",
121
+ "@pnpm/installing.commands": "1100.10.1",
122
+ "@pnpm/assert-project": "1100.0.17",
123
+ "@pnpm/store.index": "1100.2.1",
120
124
  "@pnpm/logger": "1100.0.0",
121
- "@pnpm/prepare": "1100.0.16",
125
+ "@pnpm/prepare": "1100.0.17",
122
126
  "@pnpm/test-fixtures": "1100.0.0",
123
127
  "@pnpm/test-ipc-server": "1100.0.0",
124
- "@pnpm/testing.command-defaults": "1100.0.6",
125
- "@pnpm/testing.mock-agent": "1101.0.3",
126
- "@pnpm/testing.registry-mock": "1100.0.6",
127
- "@pnpm/store.index": "1100.2.0",
128
- "@pnpm/worker": "1100.2.0",
129
- "@pnpm/workspace.projects-filter": "1100.0.21"
128
+ "@pnpm/testing.mock-agent": "1101.0.4",
129
+ "@pnpm/testing.registry-mock": "1100.0.7",
130
+ "@pnpm/testing.command-defaults": "1100.0.7",
131
+ "@pnpm/workspace.projects-filter": "1100.0.23",
132
+ "@pnpm/worker": "1100.2.2"
130
133
  },
131
134
  "engines": {
132
135
  "node": ">=22.13"