{
  "schemaVersion": 1,
  "run": {
    "id": "pnpm-glob-migration-r1-typelatch",
    "task": "pnpm-glob-migration",
    "repeat": 1,
    "arm": "typelatch",
    "status": "completed",
    "startedAt": "2026-11-06T21:58:34.584Z",
    "finishedAt": "2026-11-06T22:00:01.640Z",
    "fixtureSetupMs": 22513.663500000024,
    "providerSetupMs": 0.00229199999012053,
    "elapsedMs": 87054.829708,
    "teardownMs": 0.13895799999590963,
    "gradingMs": 19407.907624999993,
    "exitCode": 0,
    "timedOut": false,
    "processGroupStopped": true,
    "providerStopped": true,
    "correct": true,
    "capture": {
      "complete": true,
      "issues": [],
      "startupWarnings": [
        {
          "line": 2,
          "kind": "unstable-features",
          "messageSha256": "b7f966b81ed3d1a5878ecb513d7504e7f08289ae2bc88b0233f0794bf8f57666"
        }
      ],
      "turnStarts": 1,
      "turnCompletions": 1,
      "duplicateActions": 0,
      "duplicateCompletions": 0,
      "failedTurn": false
    },
    "usage": {
      "inputTokens": 352688,
      "cachedInputTokens": 320256,
      "cacheWriteInputTokens": 0,
      "outputTokens": 1939,
      "reasoningOutputTokens": 169,
      "totalTokens": 354627,
      "uncachedInputTokens": 32432
    },
    "counts": {
      "shellCalls": 8,
      "mcpCalls": 2,
      "mcpSucceeded": 2,
      "mcpFailed": 0,
      "fileEdits": 1,
      "grepShellCalls": 4,
      "contentSearchShellCalls": 4,
      "fileListingShellCalls": 1,
      "ambiguousSearchShellCalls": 0
    },
    "fixtureSha256": "beab5618d275e8bace8e27ff0d5e12305a73bf8946a353a66b21ca5dd103dbbe",
    "preparedSha256": "beab5618d275e8bace8e27ff0d5e12305a73bf8946a353a66b21ca5dd103dbbe",
    "promptSha256": "4206527b414c971ac94ae3906ee4309df3fa73d37842c7e7820f58e47cd50296",
    "recordingError": null,
    "rawSha256": "33f8a968c01af8c40b5e28a22017a2092cb1a249f6482af647e216b7e0b3343d",
    "nativeValidation": {
      "checks": [
        {
          "line": 6,
          "actionIdSha256": "6a9722cdf589a2a068832c955a8253b9df87983501c03dd92e95debae1f409da",
          "commandExitCode": 1,
          "individualCheckExitCode": null,
          "resultIndex": 0,
          "passed": false,
          "cases": 2,
          "expectedFinalCases": 7,
          "completePassingCheck": false,
          "outputSha256": "88d61a792e0fa27095dc104fe344d6df9b28657345e15bf36aed2039311d5c66"
        },
        {
          "line": 19,
          "actionIdSha256": "cfc5c391b5ba915c081c7d09c3edfc599f5369196d03ab00aa96b73369f89b5f",
          "commandExitCode": 1,
          "individualCheckExitCode": null,
          "resultIndex": 0,
          "passed": false,
          "cases": 7,
          "expectedFinalCases": 7,
          "completePassingCheck": false,
          "outputSha256": "e0995a80e82e5130a9aa4ea57d0fde72a84adafbdfdaa7e04ead7c3bcdcfb4d1"
        },
        {
          "line": 28,
          "actionIdSha256": "b40ee9c64c8028e7786be4b1266661a398dfa60613358262a0ce9e36bddd365d",
          "commandExitCode": 0,
          "individualCheckExitCode": null,
          "resultIndex": 0,
          "passed": true,
          "cases": 7,
          "expectedFinalCases": 7,
          "completePassingCheck": true,
          "outputSha256": "6739b558b05c7995effb058e0c18359bbd4aad508e64037b512a47f74f5d5360"
        }
      ],
      "failingThenLaterCheckObserved": true,
      "limitation": "A compiler failure may prevent runtime checks, so actual case counts are retained. Only a passing final response with the full expected count qualifies. Compound shell exit is aggregate, not a per-check exit. Independent action review must assess actual execution and edit ordering."
    },
    "providerCallObserved": true,
    "providerUsed": null,
    "workflowReviewed": null
  },
  "prompt": "The selected package dependencies have moved from fast-glob to tinyglobby. Complete the production migration across this workspace while preserving package discovery, metadata matching, executable discovery, patch contents and published archive behavior. Keep dependencies and configuration fixed. Run the supplied native validation before and after the change.\n\nBefore investigating implementation, run the supplied native validation command: npm run test:typelatch-benchmark. After making the requested change, run it again. Only existing production TypeScript source may change. Keep tests, dependencies, manifests and configuration fixed. Generated compiler outputs may be rebuilt.\n\nFor your first task-directed investigation, obtain relevant evidence through the advertised repository provider when present, otherwise through native tools. Provider startup instructions and harmless top-level metadata checks are separate. Then choose freely among all available tools. Native compiler, language service, package-manager filters and source reads are available in every condition. Prefer concise evidence and avoid redundant reads. Do not mistake package reachability for proven symbol impact or an incomplete result for absence.\n\nStay inside this project. Do not use the network, install packages, inspect repository history, read external files or delegate work. Supplied native validation commands may execute their configured external runner, but do not inspect that runner or other external files. Native source, installed declarations and project configuration inside the workspace remain available.\n\nRepository retrieval capability inventory for this session:\nProvider: typelatch\nTools: mcp__typelatch__workspace_search, mcp__typelatch__workspace_context, mcp__typelatch__workspace_validate, mcp__typelatch__library_search, mcp__typelatch__library_symbol, mcp__typelatch__library_feedback, mcp__typelatch__library_stats\nAdditional repository providers: none\nNative tools: available\nThis inventory is complete for the session. Built-in MCP resource and resource-template catalogs are not repository retrieval providers; do not call them to discover providers. Use tool search only if needed to load deferred definitions of the declared tools.",
  "actions": [
    {
      "type": "command_execution",
      "idSha256": "6a9722cdf589a2a068832c955a8253b9df87983501c03dd92e95debae1f409da",
      "status": "failed",
      "command": "/bin/zsh -c 'npm run test:typelatch-benchmark'",
      "outputBytes": 1083,
      "outputSha256": "88d61a792e0fa27095dc104fe344d6df9b28657345e15bf36aed2039311d5c66",
      "exitCode": 1,
      "search": {
        "search": false,
        "contentSearch": false,
        "fileListing": false,
        "ambiguous": false
      },
      "startedMs": 5402.587874999997,
      "completedMs": 12266.226083000016
    },
    {
      "type": "mcp_tool_call",
      "idSha256": "4a317b6972e2f1834050485420bd71fe6fc2d87cd25d572cb4b8b327b37bc030",
      "status": "completed",
      "server": "typelatch",
      "tool": "workspace_search",
      "arguments": {
        "workspaceRoot": "$WORKSPACE",
        "question": "fast-glob tinyglobby package discovery metadata matching executable discovery patch archive",
        "scope": "workspace",
        "detail": "source",
        "limit": 12
      },
      "hasError": false,
      "hasResult": true,
      "resultBytes": 178528,
      "resultSha256": "8577e238064e4e84488e6c6a0691c56033e3125eb17a4a46ce8366f85d49e091",
      "result": {
        "isError": false
      },
      "startedMs": 16087.619833000004,
      "completedMs": 19562.996542000008
    },
    {
      "type": "command_execution",
      "idSha256": "57dbfc296665f072254d15345fb3a2bbf457ae03cbb6ee8f6020e8f11d4b056b",
      "status": "completed",
      "command": "/bin/zsh -c \"rg -n 'fast-glob|fastGlob|tinyglobby' --glob '*.ts' --glob '\"'!**/test/**'\"' --glob '\"'!**/tests/**'\"'; rg --files -g AGENTS.md -g '\"'!node_modules'\"'; git status --short\"",
      "outputBytes": 963,
      "outputSha256": "631aae573409c6997588d0e0af12bf422b9648021c2a90a7e60977d4eb1abdb6",
      "exitCode": 0,
      "search": {
        "search": true,
        "contentSearch": true,
        "fileListing": true,
        "ambiguous": false
      },
      "startedMs": 22686.49775000001,
      "completedMs": 22702.106500000024
    },
    {
      "type": "command_execution",
      "idSha256": "9462965f2002ffb6e5ebf84d633936910b584441932a9dee26f8497eb9d82c75",
      "status": "failed",
      "command": "/bin/zsh -c \"cat AGENTS.md fs/find-packages/src/index.ts cache/api/src/cacheList.ts cache/api/src/cacheView.ts pkg-manager/package-bins/src/index.ts; rg -n -C 9 '\\\\b(glob|fg)\\\\b' patching/plugin-commands-patching/src/patchCommit.ts releasing/plugin-commands-publishing/src/pack.ts; cat fs/find-packages/node_modules/tinyglobby/dist/index.d.ts\"",
      "outputBytes": 19206,
      "outputSha256": "297bef8f08b4ebf64f4d0f5e2b5a574c8094a9fdc2ae24a7ee7a21b1a053cc07",
      "exitCode": 1,
      "search": {
        "search": true,
        "contentSearch": true,
        "fileListing": false,
        "ambiguous": false
      },
      "startedMs": 27047.784625,
      "completedMs": 27047.997625000018
    },
    {
      "type": "mcp_tool_call",
      "idSha256": "919299b8b8860441036a08b8ce4a6486ee1712366afaec2286c8579387359f27",
      "status": "completed",
      "server": "typelatch",
      "tool": "workspace_context",
      "arguments": {
        "config": "fs/find-packages/tsconfig.json",
        "file": "src/index.ts",
        "importSpecifier": "tinyglobby",
        "symbol": "glob",
        "limit": 3
      },
      "hasError": false,
      "hasResult": true,
      "resultBytes": 13699,
      "resultSha256": "8848189c9b9cb6e28d576c7b533de9d3481099128e0937151965fa847630d50b",
      "result": {
        "isError": false
      },
      "startedMs": 27049.750916999998,
      "completedMs": 28118.991750000016
    },
    {
      "type": "command_execution",
      "idSha256": "f4fdd034b54297294baf2c6977028dba2f4e8949c52e921b04118670cad8192e",
      "status": "completed",
      "command": "/bin/zsh -c \"cat node_modules/.pnpm/tinyglobby@0.2.15/node_modules/tinyglobby/dist/index.d.cts; rg -n 'tinyglobby|fast-glob' cache/api/package.json fs/find-packages/package.json pkg-manager/package-bins/package.json patching/plugin-commands-patching/package.json releasing/plugin-commands-publishing/package.json __utils__/scripts/package.json; rg -n 'normalize|negat|dot|symbolic|license|LICENSE|includeRoot' fs/find-packages/test/index.ts pkg-manager/package-bins/test/index.ts releasing/plugin-commands-publishing/src/pack.ts; rg -n -C 3 'expandDirectories|onlyFiles|followSymbolicLinks' node_modules/.pnpm/tinyglobby@0.2.15/node_modules/tinyglobby/dist/index.cjs\"",
      "outputBytes": 8155,
      "outputSha256": "230f72d3be7b151fbdc3ad3c088522d09dc3e36b4a409fe10adf9fffb35c6bd5",
      "exitCode": 0,
      "search": {
        "search": true,
        "contentSearch": true,
        "fileListing": false,
        "ambiguous": false
      },
      "startedMs": 35210.048500000004,
      "completedMs": 35210.048500000004
    },
    {
      "type": "command_execution",
      "idSha256": "cfc5c391b5ba915c081c7d09c3edfc599f5369196d03ab00aa96b73369f89b5f",
      "status": "failed",
      "command": "/bin/zsh -c \"python3 - <<'PY'\nfrom pathlib import Path\nfor filename in ['fs/find-packages/src/index.ts', 'cache/api/src/cacheList.ts', 'cache/api/src/cacheView.ts', 'pkg-manager/package-bins/src/index.ts']:\n    p = Path(filename)\n    s = p.read_text().replace(\\\"import fastGlob from 'fast-glob'\\\\n\\\", '').replace('fastGlob(', 'glob(')\n    i = s.index('\\\\n\\\\n')\n    s = s[:i] + \\\"\\\\nimport { glob } from 'tinyglobby'\\\" + s[i:]\n    if filename.startswith('fs/'):\n        s = s.replace('const globOpts = { ...opts, cwd: root }', 'const globOpts = { ...opts, cwd: root, expandDirectories: false }')\n    else:\n        s = s.replace('cwd: opts.cacheDir,', 'cwd: opts.cacheDir,\\\\n    expandDirectories: false,')\n        s = s.replace('cwd: dir,', 'cwd: dir,\\\\n      expandDirectories: false,').replace('      })', '    })')\n    p.write_text(s)\np = Path('patching/plugin-commands-patching/src/patchCommit.ts')\ns = p.read_text().replace(\\\"import glob from 'fast-glob'\\\", \\\"import { glob } from 'tinyglobby'\\\").replace('cwd: basePath,', 'cwd: basePath,\\\\n    expandDirectories: false,')\np.write_text(s)\np = Path('releasing/plugin-commands-publishing/src/pack.ts')\ns = p.read_text().replace(\\\"import fg from 'fast-glob'\\\", \\\"import { glob } from 'tinyglobby'\\\").replace(\\\"const findLicenses = fg.bind(fg, [LICENSE_GLOB]) as (opts: { cwd: string }) => Promise<string[]>\\\", \\\"const findLicenses = (opts: { cwd: string }): Promise<string[]> => glob([LICENSE_GLOB], { ...opts, expandDirectories: false })\\\")\np.write_text(s)\nPY\nnpm run test:typelatch-benchmark\"",
      "outputBytes": 1677,
      "outputSha256": "e0995a80e82e5130a9aa4ea57d0fde72a84adafbdfdaa7e04ead7c3bcdcfb4d1",
      "exitCode": 1,
      "search": {
        "search": false,
        "contentSearch": false,
        "fileListing": false,
        "ambiguous": false
      },
      "startedMs": 48613.809917000006,
      "completedMs": 59164.538
    },
    {
      "type": "command_execution",
      "idSha256": "a26c6de8780e4e792e8ad6df3fb6ac31fe229b7b2f8bc2aa29c602e8d647918c",
      "status": "completed",
      "command": "/bin/zsh -c 'git diff --stat; git diff --check; git diff -- fs/find-packages/src/index.ts cache/api/src/cacheList.ts cache/api/src/cacheView.ts pkg-manager/package-bins/src/index.ts patching/plugin-commands-patching/src/patchCommit.ts releasing/plugin-commands-publishing/src/pack.ts'",
      "outputBytes": 7222,
      "outputSha256": "9dcc3de0fa2d3f886eaf9647eb562d3443f676c844e6e20d813ec2f153d56d3e",
      "exitCode": 0,
      "search": {
        "search": false,
        "contentSearch": false,
        "fileListing": false,
        "ambiguous": false
      },
      "startedMs": 64023.622250000015,
      "completedMs": 64023.622250000015
    },
    {
      "type": "file_change",
      "idSha256": "fcf995ce3ce15e435101e7a49adbafdc79fcf9203eefbab40b5d124cae39b03f",
      "status": "completed",
      "changes": [
        {
          "path": "$WORKSPACE/fs/find-packages/src/index.ts",
          "kind": "update"
        }
      ],
      "startedMs": 71252.74979199999,
      "completedMs": 71277.84179199999
    },
    {
      "type": "command_execution",
      "idSha256": "9d348a4243d4ca091c5a70d9e547c9f8a44b7c9f9d9326ec2086feeee1e440b9",
      "status": "failed",
      "command": "/bin/zsh -c \"git diff --check; git status --short; rg -n 'fast-glob|fastGlob' cache/api/src fs/find-packages/src pkg-manager/package-bins/src patching/plugin-commands-patching/src releasing/plugin-commands-publishing/src\"",
      "outputBytes": 242,
      "outputSha256": "e48171bb6045c70820b6d2ab88d8136bc1afa6c8d9bbc03423fe0e63e2f897e3",
      "exitCode": 1,
      "search": {
        "search": true,
        "contentSearch": true,
        "fileListing": false,
        "ambiguous": false
      },
      "startedMs": 81293.525042,
      "completedMs": 81293.525042
    },
    {
      "type": "command_execution",
      "idSha256": "b40ee9c64c8028e7786be4b1266661a398dfa60613358262a0ce9e36bddd365d",
      "status": "completed",
      "command": "/bin/zsh -c 'npm run test:typelatch-benchmark'",
      "outputBytes": 1478,
      "outputSha256": "6739b558b05c7995effb058e0c18359bbd4aad508e64037b512a47f74f5d5360",
      "exitCode": 0,
      "search": {
        "search": false,
        "contentSearch": false,
        "fileListing": false,
        "ambiguous": false
      },
      "startedMs": 71435.04504200001,
      "completedMs": 81864.14900000003
    }
  ],
  "requestedConfig": {
    "model": "gpt-6.1-sol",
    "model_reasoning_effort": "medium",
    "approval_policy": "never",
    "project_doc_max_bytes": 0,
    "allow_login_shell": false,
    "skills.include_instructions": false,
    "skills.bundled.enabled": false,
    "features.skip_host_skill_discovery": true,
    "features.skill_search": false,
    "features.apps": false,
    "features.plugins": false,
    "features.multi_agent": false,
    "features.memories": false,
    "features.hooks": false,
    "web_search": "disabled",
    "history.persistence": "none",
    "shell_environment_policy.inherit": "core",
    "mcp_servers.typelatch.command": "$USER_HOME/.hermes/node/bin/node",
    "mcp_servers.typelatch.args": [
      "$REPOSITORY/artifacts/paired-agent/candidate/runtime/node_modules/typelatch/dist/mcp.js"
    ],
    "mcp_servers.typelatch.cwd": "$WORKSPACE",
    "mcp_servers.typelatch.startup_timeout_sec": 60,
    "mcp_servers.typelatch.tool_timeout_sec": 180,
    "mcp_servers.typelatch.env.TYPELATCH_HOME": "$PROVIDER_STATE/typelatch",
    "mcp_servers.typelatch.env.TYPELATCH_USAGE": "off",
    "mcp_servers.typelatch.required": true,
    "mcp_servers.typelatch.tools.workspace_search.approval_mode": "approve",
    "mcp_servers.typelatch.tools.workspace_context.approval_mode": "approve",
    "mcp_servers.typelatch.tools.workspace_validate.approval_mode": "approve",
    "mcp_servers.typelatch.tools.library_search.approval_mode": "approve",
    "mcp_servers.typelatch.tools.library_symbol.approval_mode": "approve",
    "mcp_servers.typelatch.tools.library_feedback.approval_mode": "approve",
    "mcp_servers.typelatch.tools.library_stats.approval_mode": "approve"
  },
  "grading": {
    "passed": true,
    "integrity": {
      "passed": true,
      "changed": [
        "cache/api/src/cacheList.ts",
        "cache/api/src/cacheView.ts",
        "fs/find-packages/src/index.ts",
        "patching/plugin-commands-patching/src/patchCommit.ts",
        "pkg-manager/package-bins/src/index.ts",
        "releasing/plugin-commands-publishing/src/pack.ts"
      ],
      "forbidden": [],
      "generatedChanged": [
        "__utils__/assert-project/tsconfig.tsbuildinfo",
        "__utils__/assert-store/tsconfig.tsbuildinfo",
        "__utils__/prepare-temp-dir/tsconfig.tsbuildinfo",
        "__utils__/prepare/tsconfig.tsbuildinfo",
        "__utils__/test-fixtures/tsconfig.tsbuildinfo",
        "__utils__/test-ipc-server/tsconfig.tsbuildinfo",
        "builder/policy/tsconfig.tsbuildinfo",
        "cache/api/lib/cacheDelete.d.ts",
        "cache/api/lib/cacheDelete.js",
        "cache/api/lib/cacheDelete.js.map",
        "cache/api/lib/cacheList.d.ts",
        "cache/api/lib/cacheList.js",
        "cache/api/lib/cacheList.js.map",
        "cache/api/lib/cacheView.d.ts",
        "cache/api/lib/cacheView.js",
        "cache/api/lib/cacheView.js.map",
        "cache/api/lib/index.d.ts",
        "cache/api/lib/index.js",
        "cache/api/lib/index.js.map",
        "cache/api/tsconfig.tsbuildinfo",
        "catalogs/config/tsconfig.tsbuildinfo",
        "catalogs/protocol-parser/tsconfig.tsbuildinfo",
        "catalogs/resolver/tsconfig.tsbuildinfo",
        "catalogs/types/tsconfig.tsbuildinfo",
        "cli/cli-meta/tsconfig.tsbuildinfo",
        "cli/cli-utils/tsconfig.tsbuildinfo",
        "cli/command/tsconfig.tsbuildinfo",
        "cli/common-cli-options-help/tsconfig.tsbuildinfo",
        "cli/default-reporter/tsconfig.tsbuildinfo",
        "config/config-writer/tsconfig.tsbuildinfo",
        "config/config/tsconfig.tsbuildinfo",
        "config/deps-installer/tsconfig.tsbuildinfo",
        "config/matcher/tsconfig.tsbuildinfo",
        "config/normalize-registries/tsconfig.tsbuildinfo",
        "config/package-is-installable/tsconfig.tsbuildinfo",
        "config/parse-overrides/tsconfig.tsbuildinfo",
        "config/pick-registry-for-package/tsconfig.tsbuildinfo",
        "config/version-policy/tsconfig.tsbuildinfo",
        "crypto/hash/tsconfig.tsbuildinfo",
        "crypto/object-hasher/tsconfig.tsbuildinfo",
        "crypto/polyfill/tsconfig.tsbuildinfo",
        "crypto/shasums-file/tsconfig.tsbuildinfo",
        "dedupe/check/tsconfig.tsbuildinfo",
        "dedupe/issues-renderer/tsconfig.tsbuildinfo",
        "dedupe/types/tsconfig.tsbuildinfo",
        "deps/graph-builder/tsconfig.tsbuildinfo",
        "deps/graph-sequencer/tsconfig.tsbuildinfo",
        "deps/status/tsconfig.tsbuildinfo",
        "env/node.fetcher/tsconfig.tsbuildinfo",
        "env/node.resolver/tsconfig.tsbuildinfo",
        "env/plugin-commands-env/tsconfig.tsbuildinfo",
        "env/system-node-version/tsconfig.tsbuildinfo",
        "exec/build-modules/tsconfig.tsbuildinfo",
        "exec/lifecycle/tsconfig.tsbuildinfo",
        "exec/pkg-requires-build/tsconfig.tsbuildinfo",
        "exec/plugin-commands-rebuild/tsconfig.tsbuildinfo",
        "exec/prepare-package/tsconfig.tsbuildinfo",
        "exec/run-npm/tsconfig.tsbuildinfo",
        "fetching/binary-fetcher/tsconfig.tsbuildinfo",
        "fetching/directory-fetcher/tsconfig.tsbuildinfo",
        "fetching/fetcher-base/tsconfig.tsbuildinfo",
        "fetching/git-fetcher/tsconfig.tsbuildinfo",
        "fetching/pick-fetcher/tsconfig.tsbuildinfo",
        "fetching/tarball-fetcher/tsconfig.tsbuildinfo",
        "fs/find-packages/lib/index.d.ts",
        "fs/find-packages/lib/index.js",
        "fs/find-packages/lib/index.js.map",
        "fs/find-packages/tsconfig.tsbuildinfo",
        "fs/graceful-fs/tsconfig.tsbuildinfo",
        "fs/hard-link-dir/tsconfig.tsbuildinfo",
        "fs/indexed-pkg-importer/tsconfig.tsbuildinfo",
        "fs/packlist/tsconfig.tsbuildinfo",
        "fs/read-modules-dir/tsconfig.tsbuildinfo",
        "fs/symlink-dependency/tsconfig.tsbuildinfo",
        "hooks/pnpmfile/tsconfig.tsbuildinfo",
        "hooks/read-package-hook/tsconfig.tsbuildinfo",
        "hooks/types/tsconfig.tsbuildinfo",
        "lockfile/filtering/tsconfig.tsbuildinfo",
        "lockfile/fs/tsconfig.tsbuildinfo",
        "lockfile/lockfile-to-pnp/tsconfig.tsbuildinfo",
        "lockfile/merger/tsconfig.tsbuildinfo",
        "lockfile/preferred-versions/tsconfig.tsbuildinfo",
        "lockfile/pruner/tsconfig.tsbuildinfo",
        "lockfile/settings-checker/tsconfig.tsbuildinfo",
        "lockfile/types/tsconfig.tsbuildinfo",
        "lockfile/utils/tsconfig.tsbuildinfo",
        "lockfile/verification/tsconfig.tsbuildinfo",
        "lockfile/walker/tsconfig.tsbuildinfo",
        "network/auth-header/tsconfig.tsbuildinfo",
        "network/fetch/tsconfig.tsbuildinfo",
        "network/fetching-types/tsconfig.tsbuildinfo",
        "object/key-sorting/tsconfig.tsbuildinfo",
        "packages/calc-dep-state/tsconfig.tsbuildinfo",
        "packages/constants/tsconfig.tsbuildinfo",
        "packages/core-loggers/tsconfig.tsbuildinfo",
        "packages/dependency-path/tsconfig.tsbuildinfo",
        "packages/error/tsconfig.tsbuildinfo",
        "packages/git-utils/tsconfig.tsbuildinfo",
        "packages/logger/tsconfig.tsbuildinfo",
        "packages/parse-wanted-dependency/tsconfig.tsbuildinfo",
        "packages/render-peer-issues/tsconfig.tsbuildinfo",
        "packages/types/tsconfig.tsbuildinfo",
        "patching/apply-patch/tsconfig.tsbuildinfo",
        "patching/config/tsconfig.tsbuildinfo",
        "patching/plugin-commands-patching/lib/getEditDirPath.d.ts",
        "patching/plugin-commands-patching/lib/getEditDirPath.js",
        "patching/plugin-commands-patching/lib/getEditDirPath.js.map",
        "patching/plugin-commands-patching/lib/getPatchedDependency.d.ts",
        "patching/plugin-commands-patching/lib/getPatchedDependency.js",
        "patching/plugin-commands-patching/lib/getPatchedDependency.js.map",
        "patching/plugin-commands-patching/lib/index.d.ts",
        "patching/plugin-commands-patching/lib/index.js",
        "patching/plugin-commands-patching/lib/index.js.map",
        "patching/plugin-commands-patching/lib/patch.d.ts",
        "patching/plugin-commands-patching/lib/patch.js",
        "patching/plugin-commands-patching/lib/patch.js.map",
        "patching/plugin-commands-patching/lib/patchCommit.d.ts",
        "patching/plugin-commands-patching/lib/patchCommit.js",
        "patching/plugin-commands-patching/lib/patchCommit.js.map",
        "patching/plugin-commands-patching/lib/patchRemove.d.ts",
        "patching/plugin-commands-patching/lib/patchRemove.js",
        "patching/plugin-commands-patching/lib/patchRemove.js.map",
        "patching/plugin-commands-patching/lib/stateFile.d.ts",
        "patching/plugin-commands-patching/lib/stateFile.js",
        "patching/plugin-commands-patching/lib/stateFile.js.map",
        "patching/plugin-commands-patching/lib/updatePatchedDependencies.d.ts",
        "patching/plugin-commands-patching/lib/updatePatchedDependencies.js",
        "patching/plugin-commands-patching/lib/updatePatchedDependencies.js.map",
        "patching/plugin-commands-patching/lib/writePackage.d.ts",
        "patching/plugin-commands-patching/lib/writePackage.js",
        "patching/plugin-commands-patching/lib/writePackage.js.map",
        "patching/plugin-commands-patching/tsconfig.tsbuildinfo",
        "patching/types/tsconfig.tsbuildinfo",
        "pkg-manager/client/tsconfig.tsbuildinfo",
        "pkg-manager/core/tsconfig.tsbuildinfo",
        "pkg-manager/direct-dep-linker/tsconfig.tsbuildinfo",
        "pkg-manager/get-context/tsconfig.tsbuildinfo",
        "pkg-manager/headless/tsconfig.tsbuildinfo",
        "pkg-manager/hoist/tsconfig.tsbuildinfo",
        "pkg-manager/link-bins/tsconfig.tsbuildinfo",
        "pkg-manager/modules-cleaner/tsconfig.tsbuildinfo",
        "pkg-manager/modules-yaml/tsconfig.tsbuildinfo",
        "pkg-manager/package-bins/lib/index.d.ts",
        "pkg-manager/package-bins/lib/index.js",
        "pkg-manager/package-bins/lib/index.js.map",
        "pkg-manager/package-bins/tsconfig.tsbuildinfo",
        "pkg-manager/package-requester/tsconfig.tsbuildinfo",
        "pkg-manager/plugin-commands-installation/tsconfig.tsbuildinfo",
        "pkg-manager/read-projects-context/tsconfig.tsbuildinfo",
        "pkg-manager/real-hoist/tsconfig.tsbuildinfo",
        "pkg-manager/remove-bins/tsconfig.tsbuildinfo",
        "pkg-manager/resolve-dependencies/tsconfig.tsbuildinfo",
        "pkg-manifest/exportable-manifest/tsconfig.tsbuildinfo",
        "pkg-manifest/manifest-utils/tsconfig.tsbuildinfo",
        "pkg-manifest/read-package-json/tsconfig.tsbuildinfo",
        "pkg-manifest/read-project-manifest/tsconfig.tsbuildinfo",
        "pkg-manifest/write-project-manifest/tsconfig.tsbuildinfo",
        "registry/pkg-metadata-filter/tsconfig.tsbuildinfo",
        "registry/types/tsconfig.tsbuildinfo",
        "releasing/plugin-commands-publishing/lib/index.d.ts",
        "releasing/plugin-commands-publishing/lib/index.js",
        "releasing/plugin-commands-publishing/lib/index.js.map",
        "releasing/plugin-commands-publishing/lib/pack.d.ts",
        "releasing/plugin-commands-publishing/lib/pack.js",
        "releasing/plugin-commands-publishing/lib/pack.js.map",
        "releasing/plugin-commands-publishing/lib/publish.d.ts",
        "releasing/plugin-commands-publishing/lib/publish.js",
        "releasing/plugin-commands-publishing/lib/publish.js.map",
        "releasing/plugin-commands-publishing/lib/recursivePublish.d.ts",
        "releasing/plugin-commands-publishing/lib/recursivePublish.js",
        "releasing/plugin-commands-publishing/lib/recursivePublish.js.map",
        "releasing/plugin-commands-publishing/tsconfig.tsbuildinfo",
        "resolving/bun-resolver/tsconfig.tsbuildinfo",
        "resolving/default-resolver/tsconfig.tsbuildinfo",
        "resolving/deno-resolver/tsconfig.tsbuildinfo",
        "resolving/git-resolver/tsconfig.tsbuildinfo",
        "resolving/jsr-specifier-parser/tsconfig.tsbuildinfo",
        "resolving/local-resolver/tsconfig.tsbuildinfo",
        "resolving/npm-resolver/tsconfig.tsbuildinfo",
        "resolving/resolver-base/tsconfig.tsbuildinfo",
        "resolving/tarball-resolver/tsconfig.tsbuildinfo",
        "reviewing/outdated/tsconfig.tsbuildinfo",
        "semver/peer-range/tsconfig.tsbuildinfo",
        "store/cafs-types/tsconfig.tsbuildinfo",
        "store/cafs/tsconfig.tsbuildinfo",
        "store/create-cafs-store/tsconfig.tsbuildinfo",
        "store/package-store/tsconfig.tsbuildinfo",
        "store/server/tsconfig.tsbuildinfo",
        "store/store-connection-manager/tsconfig.tsbuildinfo",
        "store/store-controller-types/tsconfig.tsbuildinfo",
        "store/store-path/tsconfig.tsbuildinfo",
        "testing/temp-store/tsconfig.tsbuildinfo",
        "text/comments-parser/tsconfig.tsbuildinfo",
        "text/tree-renderer/tsconfig.tsbuildinfo",
        "worker/tsconfig.tsbuildinfo",
        "workspace/filter-packages-from-dir/tsconfig.tsbuildinfo",
        "workspace/filter-workspace-packages/tsconfig.tsbuildinfo",
        "workspace/find-packages/tsconfig.tsbuildinfo",
        "workspace/find-workspace-dir/tsconfig.tsbuildinfo",
        "workspace/manifest-writer/tsconfig.tsbuildinfo",
        "workspace/pkgs-graph/tsconfig.tsbuildinfo",
        "workspace/read-manifest/tsconfig.tsbuildinfo",
        "workspace/resolve-workspace-range/tsconfig.tsbuildinfo",
        "workspace/sort-packages/tsconfig.tsbuildinfo",
        "workspace/spec-parser/tsconfig.tsbuildinfo",
        "workspace/state/tsconfig.tsbuildinfo",
        "yaml/document-sync/tsconfig.tsbuildinfo"
      ],
      "policy": "Only existing tracked production TypeScript source may change. Build outputs under declared project lib directories and tsconfig.tsbuildinfo are disposable and rebuilt from source before checks. Dependencies, manifests, tests and configuration are immutable."
    },
    "sourceStable": true,
    "checks": {
      "startedAt": "2026-11-06T22:00:06.239Z",
      "elapsedMs": 10217.942958,
      "exitCode": 0,
      "signal": null,
      "stdout": "{\"passed\":true,\"cases\":7,\"results\":[{\"id\":\"native-typescript-build-five-production-packages\",\"passed\":true,\"clean\":{\"exitCode\":0,\"signal\":null,\"elapsedMs\":696.438167,\"stdout\":\"\",\"stderr\":\"\",\"error\":null},\"build\":{\"exitCode\":0,\"signal\":null,\"elapsedMs\":8784.295375,\"stdout\":\"\",\"stderr\":\"\",\"error\":null}},{\"id\":\"cache-metadata-is-file-not-directory\",\"passed\":true},{\"id\":\"cache-view-excludes-directory-expansion\",\"passed\":true},{\"id\":\"workspace-patterns-root-ignore-and-manifest-formats\",\"passed\":true},{\"id\":\"bins-recursive-files-without-link-or-path-escape\",\"passed\":true},{\"id\":\"pack-inherits-license-file-without-directory-contents\",\"passed\":true},{\"id\":\"patch-comparison-ignores-unpublished-files\",\"passed\":true}],\"runtime\":{\"exitCode\":0,\"signal\":null,\"elapsedMs\":700.7855,\"stdout\":\"{\\\"passed\\\":true,\\\"cases\\\":6,\\\"results\\\":[{\\\"id\\\":\\\"cache-metadata-is-file-not-directory\\\",\\\"passed\\\":true},{\\\"id\\\":\\\"cache-view-excludes-directory-expansion\\\",\\\"passed\\\":true},{\\\"id\\\":\\\"workspace-patterns-root-ignore-and-manifest-formats\\\",\\\"passed\\\":true},{\\\"id\\\":\\\"bins-recursive-files-without-link-or-path-escape\\\",\\\"passed\\\":true},{\\\"id\\\":\\\"pack-inherits-license-file-without-directory-contents\\\",\\\"passed\\\":true},{\\\"id\\\":\\\"patch-comparison-ignores-unpublished-files\\\",\\\"passed\\\":true}]}\\n\",\"stderr\":\"\",\"error\":null}}\n",
      "stderr": "",
      "result": {
        "passed": true,
        "cases": 7,
        "results": [
          {
            "id": "native-typescript-build-five-production-packages",
            "passed": true,
            "clean": {
              "exitCode": 0,
              "signal": null,
              "elapsedMs": 696.438167,
              "stdout": "",
              "stderr": "",
              "error": null
            },
            "build": {
              "exitCode": 0,
              "signal": null,
              "elapsedMs": 8784.295375,
              "stdout": "",
              "stderr": "",
              "error": null
            }
          },
          {
            "id": "cache-metadata-is-file-not-directory",
            "passed": true
          },
          {
            "id": "cache-view-excludes-directory-expansion",
            "passed": true
          },
          {
            "id": "workspace-patterns-root-ignore-and-manifest-formats",
            "passed": true
          },
          {
            "id": "bins-recursive-files-without-link-or-path-escape",
            "passed": true
          },
          {
            "id": "pack-inherits-license-file-without-directory-contents",
            "passed": true
          },
          {
            "id": "patch-comparison-ignores-unpublished-files",
            "passed": true
          }
        ],
        "runtime": {
          "exitCode": 0,
          "signal": null,
          "elapsedMs": 700.7855,
          "stdout": "{\"passed\":true,\"cases\":6,\"results\":[{\"id\":\"cache-metadata-is-file-not-directory\",\"passed\":true},{\"id\":\"cache-view-excludes-directory-expansion\",\"passed\":true},{\"id\":\"workspace-patterns-root-ignore-and-manifest-formats\",\"passed\":true},{\"id\":\"bins-recursive-files-without-link-or-path-escape\",\"passed\":true},{\"id\":\"pack-inherits-license-file-without-directory-contents\",\"passed\":true},{\"id\":\"patch-comparison-ignores-unpublished-files\",\"passed\":true}]}\n",
          "stderr": "",
          "error": null
        }
      },
      "error": null
    },
    "scope": {
      "passed": true,
      "files": [
        {
          "path": "cache/api/src/cacheList.ts",
          "imports": [
            "fs",
            "encode-registry",
            "tinyglobby"
          ],
          "passed": true,
          "oldDependency": []
        },
        {
          "path": "cache/api/src/cacheView.ts",
          "imports": [
            "fs",
            "path",
            "@pnpm/store.cafs",
            "@pnpm/npm-resolver",
            "encode-registry",
            "tinyglobby"
          ],
          "passed": true,
          "oldDependency": []
        },
        {
          "path": "fs/find-packages/src/index.ts",
          "imports": [
            "fs",
            "path",
            "util",
            "@pnpm/read-project-manifest",
            "@pnpm/types",
            "@pnpm/util.lex-comparator",
            "p-filter",
            "tinyglobby"
          ],
          "passed": true,
          "oldDependency": []
        },
        {
          "path": "patching/plugin-commands-patching/src/patchCommit.ts",
          "imports": [
            "fs",
            "path",
            "@pnpm/cli-utils",
            "@pnpm/config",
            "@pnpm/crypto.hash",
            "@pnpm/error",
            "@pnpm/fs.packlist",
            "@pnpm/logger",
            "@pnpm/plugin-commands-installation",
            "@pnpm/read-package-json",
            "@pnpm/store-path",
            "@pnpm/types",
            "tinyglobby",
            "normalize-path",
            "ramda/src/pick",
            "ramda/src/equals",
            "safe-execa",
            "escape-string-regexp",
            "make-empty-dir",
            "render-help",
            "./writePackage.js",
            "@pnpm/parse-wanted-dependency",
            "./getPatchedDependency.js",
            "./stateFile.js",
            "./updatePatchedDependencies.js"
          ],
          "passed": true,
          "oldDependency": []
        },
        {
          "path": "pkg-manager/package-bins/src/index.ts",
          "imports": [
            "path",
            "@pnpm/types",
            "is-subdir",
            "tinyglobby"
          ],
          "passed": true,
          "oldDependency": []
        },
        {
          "path": "releasing/plugin-commands-publishing/src/pack.ts",
          "imports": [
            "fs",
            "path",
            "zlib",
            "@pnpm/catalogs.types",
            "@pnpm/error",
            "@pnpm/config",
            "@pnpm/cli-utils",
            "@pnpm/exportable-manifest",
            "@pnpm/fs.packlist",
            "@pnpm/package-bins",
            "@pnpm/pnpmfile",
            "@pnpm/types",
            "tinyglobby",
            "ramda/src/pick",
            "realpath-missing",
            "render-help",
            "tar-stream",
            "./publish.js",
            "chalk",
            "validate-npm-package-name",
            "p-limit",
            "@pnpm/common-cli-options-help",
            "@pnpm/sort-packages",
            "@pnpm/logger"
          ],
          "passed": true,
          "oldDependency": []
        }
      ],
      "boundary": "Scope conformance for six actual migrated source modules: statically declared import/export/require/dynamic-import dependencies. This is separate from runtime behavior, and is not a proof about arbitrary computed module specifiers."
    },
    "fixtureGitUnchanged": true
  },
  "changes": [
    {
      "path": "cache/api/src/cacheList.ts",
      "beforeSha256": "1f2565c2b63668369d6520d250ae4d8f95d127ac6cf438abd0086fdafb346f2b",
      "afterSha256": "0c26988e6d3a3722d86463a1b3e2d37471ac34f5764231bf616d56ffb98c8c65",
      "before": "import fs from 'fs'\nimport getRegistryName from 'encode-registry'\nimport fastGlob from 'fast-glob'\n\nexport async function cacheListRegistries (opts: { cacheDir: string, registry?: string, registries?: boolean }): Promise<string> {\n  return fs.readdirSync(opts.cacheDir).sort().join('\\n')\n}\n\nexport async function cacheList (opts: { cacheDir: string, registry?: string, registries?: boolean }, filter: string[]): Promise<string> {\n  const metaFiles = await findMetadataFiles(opts, filter)\n  return metaFiles.sort().join('\\n')\n}\n\nexport async function findMetadataFiles (opts: { cacheDir: string, registry?: string }, filter: string[]): Promise<string[]> {\n  const prefix = opts.registry ? `${getRegistryName(opts.registry)}` : '*'\n  const patterns = filter.length ? filter.map((filter) => `${prefix}/${filter}.json`) : [`${prefix}/**`]\n  const metaFiles = await fastGlob(patterns, {\n    cwd: opts.cacheDir,\n  })\n  return metaFiles\n}\n",
      "after": "import fs from 'fs'\nimport getRegistryName from 'encode-registry'\nimport { glob } from 'tinyglobby'\n\nexport async function cacheListRegistries (opts: { cacheDir: string, registry?: string, registries?: boolean }): Promise<string> {\n  return fs.readdirSync(opts.cacheDir).sort().join('\\n')\n}\n\nexport async function cacheList (opts: { cacheDir: string, registry?: string, registries?: boolean }, filter: string[]): Promise<string> {\n  const metaFiles = await findMetadataFiles(opts, filter)\n  return metaFiles.sort().join('\\n')\n}\n\nexport async function findMetadataFiles (opts: { cacheDir: string, registry?: string }, filter: string[]): Promise<string[]> {\n  const prefix = opts.registry ? `${getRegistryName(opts.registry)}` : '*'\n  const patterns = filter.length ? filter.map((filter) => `${prefix}/${filter}.json`) : [`${prefix}/**`]\n  const metaFiles = await glob(patterns, {\n    cwd: opts.cacheDir,\n    expandDirectories: false,\n  })\n  return metaFiles\n}\n"
    },
    {
      "path": "cache/api/src/cacheView.ts",
      "beforeSha256": "2d7baa297e099a2efb9481c8585351c564410e1daa4973e505f027aef9bdabdd",
      "afterSha256": "0088f73c31798e6ed518e14c8c6546d55dbb5ac63d4785a3310db5edbdd7d754",
      "before": "import fs from 'fs'\nimport path from 'path'\nimport fastGlob from 'fast-glob'\nimport { getIndexFilePathInCafs } from '@pnpm/store.cafs'\nimport { type PackageMeta } from '@pnpm/npm-resolver'\nimport getRegistryName from 'encode-registry'\n\ninterface CachedVersions {\n  cachedVersions: string[]\n  nonCachedVersions: string[]\n  cachedAt?: string\n  distTags: Record<string, string>\n}\n\nexport async function cacheView (opts: { cacheDir: string, storeDir: string, registry?: string }, packageName: string): Promise<string> {\n  const prefix = opts.registry ? `${getRegistryName(opts.registry)}` : '*'\n  const metaFilePaths = (await fastGlob(`${prefix}/${packageName}.json`, {\n    cwd: opts.cacheDir,\n  })).sort()\n  const metaFilesByPath: Record<string, CachedVersions> = {}\n  for (const filePath of metaFilePaths) {\n    const metaObject = JSON.parse(fs.readFileSync(path.join(opts.cacheDir, filePath), 'utf8')) as PackageMeta\n    const cachedVersions: string[] = []\n    const nonCachedVersions: string[] = []\n    for (const [version, manifest] of Object.entries(metaObject.versions)) {\n      if (!manifest.dist.integrity) continue\n      const indexFilePath = getIndexFilePathInCafs(opts.storeDir, manifest.dist.integrity, `${manifest.name}@${manifest.version}`)\n      if (fs.existsSync(indexFilePath)) {\n        cachedVersions.push(version)\n      } else {\n        nonCachedVersions.push(version)\n      }\n    }\n    let registryName = filePath\n    while (path.dirname(registryName) !== '.') {\n      registryName = path.dirname(registryName)\n    }\n    metaFilesByPath[registryName.replaceAll('+', ':')] = {\n      cachedVersions,\n      nonCachedVersions,\n      cachedAt: metaObject.cachedAt ? new Date(metaObject.cachedAt).toString() : undefined,\n      distTags: metaObject['dist-tags'],\n    }\n  }\n  return JSON.stringify(metaFilesByPath, null, 2)\n}\n",
      "after": "import fs from 'fs'\nimport path from 'path'\nimport { getIndexFilePathInCafs } from '@pnpm/store.cafs'\nimport { type PackageMeta } from '@pnpm/npm-resolver'\nimport getRegistryName from 'encode-registry'\nimport { glob } from 'tinyglobby'\n\ninterface CachedVersions {\n  cachedVersions: string[]\n  nonCachedVersions: string[]\n  cachedAt?: string\n  distTags: Record<string, string>\n}\n\nexport async function cacheView (opts: { cacheDir: string, storeDir: string, registry?: string }, packageName: string): Promise<string> {\n  const prefix = opts.registry ? `${getRegistryName(opts.registry)}` : '*'\n  const metaFilePaths = (await glob(`${prefix}/${packageName}.json`, {\n    cwd: opts.cacheDir,\n    expandDirectories: false,\n  })).sort()\n  const metaFilesByPath: Record<string, CachedVersions> = {}\n  for (const filePath of metaFilePaths) {\n    const metaObject = JSON.parse(fs.readFileSync(path.join(opts.cacheDir, filePath), 'utf8')) as PackageMeta\n    const cachedVersions: string[] = []\n    const nonCachedVersions: string[] = []\n    for (const [version, manifest] of Object.entries(metaObject.versions)) {\n      if (!manifest.dist.integrity) continue\n      const indexFilePath = getIndexFilePathInCafs(opts.storeDir, manifest.dist.integrity, `${manifest.name}@${manifest.version}`)\n      if (fs.existsSync(indexFilePath)) {\n        cachedVersions.push(version)\n      } else {\n        nonCachedVersions.push(version)\n      }\n    }\n    let registryName = filePath\n    while (path.dirname(registryName) !== '.') {\n      registryName = path.dirname(registryName)\n    }\n    metaFilesByPath[registryName.replaceAll('+', ':')] = {\n      cachedVersions,\n      nonCachedVersions,\n      cachedAt: metaObject.cachedAt ? new Date(metaObject.cachedAt).toString() : undefined,\n      distTags: metaObject['dist-tags'],\n    }\n  }\n  return JSON.stringify(metaFilesByPath, null, 2)\n}\n"
    },
    {
      "path": "fs/find-packages/src/index.ts",
      "beforeSha256": "528cd6e7e96ebd130b36c3ff7bdb08b124fda1ee52f69cefd16339f1ae48b8dd",
      "afterSha256": "b100b2caafaa08a04352acb6e4b942aeed6e001eae80d1430071c545d584f02c",
      "before": "import { promises as fs } from 'fs'\nimport path from 'path'\nimport util from 'util'\nimport { readExactProjectManifest } from '@pnpm/read-project-manifest'\nimport { type Project, type ProjectRootDir, type ProjectRootDirRealPath } from '@pnpm/types'\nimport { lexCompare } from '@pnpm/util.lex-comparator'\nimport fastGlob from 'fast-glob'\nimport pFilter from 'p-filter'\n\nconst DEFAULT_IGNORE = [\n  '**/node_modules/**',\n  '**/bower_components/**',\n  '**/test/**',\n  '**/tests/**',\n]\n\nexport interface Options {\n  ignore?: string[]\n  includeRoot?: boolean\n  patterns?: string[]\n}\n\nexport async function findPackages (root: string, opts?: Options): Promise<Project[]> {\n  opts = opts ?? {}\n  const globOpts = { ...opts, cwd: root }\n  globOpts.ignore = opts.ignore ?? DEFAULT_IGNORE\n  const patterns = normalizePatterns(opts.patterns ?? ['.', '**'])\n  const paths: string[] = await fastGlob(patterns, globOpts)\n\n  if (opts.includeRoot) {\n    // Always include the workspace root (https://github.com/pnpm/pnpm/issues/1986)\n    paths.push(...(await fastGlob(normalizePatterns(['.']), globOpts)))\n  }\n\n  return pFilter(\n    // `Array.from()` doesn't create an intermediate instance,\n    // unlike `array.map()`\n    Array.from(\n      // Remove duplicate paths using `Set`\n      new Set(\n        paths\n          .map(manifestPath => path.join(root, manifestPath))\n          .sort((path1, path2) =>\n            lexCompare(path.dirname(path1), path.dirname(path2))\n          )\n      ),\n      async manifestPath => {\n        try {\n          const rootDir = path.dirname(manifestPath) as ProjectRootDir\n          return {\n            rootDir,\n            rootDirRealPath: await fs.realpath(rootDir) as ProjectRootDirRealPath,\n            ...await readExactProjectManifest(manifestPath),\n          } as Project\n        } catch (err: unknown) {\n          if (util.types.isNativeError(err) && 'code' in err && err.code === 'ENOENT') {\n            return null!\n          }\n          throw err\n        }\n      }),\n    Boolean\n  )\n}\n\nfunction normalizePatterns (patterns: readonly string[]): string[] {\n  const normalizedPatterns: string[] = []\n  for (const pattern of patterns) {\n    normalizedPatterns.push(pattern.replace(/\\/?$/, '/package.{json,yaml,json5}'))\n  }\n  return normalizedPatterns\n}\n",
      "after": "import { promises as fs } from 'fs'\nimport path from 'path'\nimport util from 'util'\nimport { readExactProjectManifest } from '@pnpm/read-project-manifest'\nimport { type Project, type ProjectRootDir, type ProjectRootDirRealPath } from '@pnpm/types'\nimport { lexCompare } from '@pnpm/util.lex-comparator'\nimport pFilter from 'p-filter'\nimport { glob } from 'tinyglobby'\n\nconst DEFAULT_IGNORE = [\n  '**/node_modules/**',\n  '**/bower_components/**',\n  '**/test/**',\n  '**/tests/**',\n]\n\nexport interface Options {\n  ignore?: string[]\n  includeRoot?: boolean\n  patterns?: string[]\n}\n\nexport async function findPackages (root: string, opts?: Options): Promise<Project[]> {\n  opts = opts ?? {}\n  const globOpts = {\n    cwd: root,\n    expandDirectories: false,\n    ignore: opts.ignore ?? DEFAULT_IGNORE,\n  }\n  const patterns = normalizePatterns(opts.patterns ?? ['.', '**'])\n  const paths: string[] = await glob(patterns, globOpts)\n\n  if (opts.includeRoot) {\n    // Always include the workspace root (https://github.com/pnpm/pnpm/issues/1986)\n    paths.push(...(await glob(normalizePatterns(['.']), globOpts)))\n  }\n\n  return pFilter(\n    // `Array.from()` doesn't create an intermediate instance,\n    // unlike `array.map()`\n    Array.from(\n      // Remove duplicate paths using `Set`\n      new Set(\n        paths\n          .map(manifestPath => path.join(root, manifestPath))\n          .sort((path1, path2) =>\n            lexCompare(path.dirname(path1), path.dirname(path2))\n          )\n      ),\n      async manifestPath => {\n        try {\n          const rootDir = path.dirname(manifestPath) as ProjectRootDir\n          return {\n            rootDir,\n            rootDirRealPath: await fs.realpath(rootDir) as ProjectRootDirRealPath,\n            ...await readExactProjectManifest(manifestPath),\n          } as Project\n        } catch (err: unknown) {\n          if (util.types.isNativeError(err) && 'code' in err && err.code === 'ENOENT') {\n            return null!\n          }\n          throw err\n        }\n      }),\n    Boolean\n  )\n}\n\nfunction normalizePatterns (patterns: readonly string[]): string[] {\n  const normalizedPatterns: string[] = []\n  for (const pattern of patterns) {\n    normalizedPatterns.push(pattern.replace(/\\/?$/, '/package.{json,yaml,json5}'))\n  }\n  return normalizedPatterns\n}\n"
    },
    {
      "path": "patching/plugin-commands-patching/src/patchCommit.ts",
      "beforeSha256": "fd29b95aa19ccd774f0253c34f375d43ba93bc12a4de86119975fcc6bd3d31b0",
      "afterSha256": "96baaf9a0630d57b35918ba95ec4dc35a69c528ebe13f316fcb1ea446a28d4bc",
      "before": "import fs from 'fs'\nimport path from 'path'\nimport { docsUrl } from '@pnpm/cli-utils'\nimport { type Config, types as allTypes } from '@pnpm/config'\nimport { createShortHash } from '@pnpm/crypto.hash'\nimport { PnpmError } from '@pnpm/error'\nimport { packlist } from '@pnpm/fs.packlist'\nimport { globalWarn } from '@pnpm/logger'\nimport { install } from '@pnpm/plugin-commands-installation'\nimport { readPackageJsonFromDir } from '@pnpm/read-package-json'\nimport { getStorePath } from '@pnpm/store-path'\nimport { type ProjectRootDir } from '@pnpm/types'\nimport glob from 'fast-glob'\nimport normalizePath from 'normalize-path'\nimport pick from 'ramda/src/pick'\nimport equals from 'ramda/src/equals'\nimport execa from 'safe-execa'\nimport escapeStringRegexp from 'escape-string-regexp'\nimport makeEmptyDir from 'make-empty-dir'\nimport renderHelp from 'render-help'\nimport { type WritePackageOptions, writePackage } from './writePackage.js'\nimport { type ParseWantedDependencyResult, parseWantedDependency } from '@pnpm/parse-wanted-dependency'\nimport { type GetPatchedDependencyOptions, getVersionsFromLockfile } from './getPatchedDependency.js'\nimport { readEditDirState } from './stateFile.js'\nimport { updatePatchedDependencies } from './updatePatchedDependencies.js'\n\nexport const rcOptionsTypes = cliOptionsTypes\n\nexport function cliOptionsTypes (): Record<string, unknown> {\n  return pick(['patches-dir'], allTypes)\n}\n\nexport const commandNames = ['patch-commit']\n\nexport function help (): string {\n  return renderHelp({\n    description: 'Generate a patch out of a directory',\n    descriptionLists: [{\n      title: 'Options',\n      list: [\n        {\n          description: 'The generated patch file will be saved to this directory',\n          name: '--patches-dir',\n        },\n      ],\n    }],\n    url: docsUrl('patch-commit'),\n    usages: ['pnpm patch-commit <patchDir>'],\n  })\n}\n\ntype PatchCommitCommandOptions = install.InstallCommandOptions & Pick<Config, 'patchesDir' | 'rootProjectManifest' | 'rootProjectManifestDir' | 'patchedDependencies'>\n\nexport async function handler (opts: PatchCommitCommandOptions, params: string[]): Promise<string | undefined> {\n  const userDir = params[0]\n  const lockfileDir = (opts.lockfileDir ?? opts.dir ?? process.cwd()) as ProjectRootDir\n  const patchesDirName = normalizePath(path.normalize(opts.patchesDir ?? 'patches'))\n  const patchesDir = path.join(lockfileDir, patchesDirName)\n  const patchedPkgManifest = await readPackageJsonFromDir(userDir)\n  const editDir = path.resolve(opts.dir, userDir)\n  const stateValue = readEditDirState({\n    editDir,\n    modulesDir: path.join(lockfileDir, opts.modulesDir ?? 'node_modules'),\n  })\n  if (!stateValue) {\n    throw new PnpmError('INVALID_PATCH_DIR', `${userDir} is not a valid patch directory`, {\n      hint: 'A valid patch directory should be created by `pnpm patch`',\n    })\n  }\n  const { applyToAll } = stateValue\n  const nameAndVersion = `${patchedPkgManifest.name}@${patchedPkgManifest.version}`\n  const patchKey = applyToAll ? patchedPkgManifest.name : nameAndVersion\n  let gitTarballUrl: string | undefined\n  if (!applyToAll) {\n    gitTarballUrl = await getGitTarballUrlFromLockfile({\n      alias: patchedPkgManifest.name,\n      bareSpecifier: patchedPkgManifest.version || undefined,\n    }, {\n      lockfileDir,\n      modulesDir: opts.modulesDir,\n      virtualStoreDir: opts.virtualStoreDir,\n    })\n  }\n  const patchedPkg = parseWantedDependency(gitTarballUrl ? `${patchedPkgManifest.name}@${gitTarballUrl}` : nameAndVersion)\n  const patchedPkgDir = await preparePkgFilesForDiff(userDir)\n  const patchContent = await getPatchContent({\n    patchedPkg,\n    patchedPkgDir,\n    tmpName: createShortHash(editDir),\n  }, opts)\n  if (patchedPkgDir !== userDir) {\n    fs.rmSync(patchedPkgDir, { recursive: true })\n  }\n\n  if (!patchContent.length) {\n    return `No changes were found to the following directory: ${userDir}`\n  }\n  await fs.promises.mkdir(patchesDir, { recursive: true })\n\n  const patchFileName = patchKey.replace('/', '__')\n  await fs.promises.writeFile(path.join(patchesDir, `${patchFileName}.patch`), patchContent, 'utf8')\n\n  const patchedDependencies = {\n    ...opts.patchedDependencies,\n    [patchKey]: `${patchesDirName}/${patchFileName}.patch`,\n  }\n  await updatePatchedDependencies(patchedDependencies, {\n    ...opts,\n    workspaceDir: opts.workspaceDir ?? opts.rootProjectManifestDir,\n  })\n\n  return install.handler({\n    ...opts,\n    patchedDependencies,\n    rawLocalConfig: {\n      ...opts.rawLocalConfig,\n      'frozen-lockfile': false,\n    },\n  }) as Promise<undefined>\n}\n\ninterface GetPatchContentContext {\n  patchedPkg: ParseWantedDependencyResult\n  patchedPkgDir: string\n  tmpName: string\n}\n\ntype GetPatchContentOptions = Pick<PatchCommitCommandOptions, 'dir' | 'pnpmHomeDir' | 'storeDir'> & WritePackageOptions\n\nasync function getPatchContent (ctx: GetPatchContentContext, opts: GetPatchContentOptions): Promise<string> {\n  const storeDir = await getStorePath({\n    pkgRoot: opts.dir,\n    storePath: opts.storeDir,\n    pnpmHomeDir: opts.pnpmHomeDir,\n  })\n  const srcDir = path.join(storeDir, 'tmp', 'patch-commit', ctx.tmpName)\n  await writePackage(ctx.patchedPkg, srcDir, opts)\n  const patchContent = await diffFolders(srcDir, ctx.patchedPkgDir)\n  try {\n    fs.rmSync(srcDir, { recursive: true })\n  } catch (error) {\n    globalWarn(`Failed to clean up temporary directory at ${srcDir} with error: ${String(error)}`)\n  }\n  return patchContent\n}\n\nasync function diffFolders (folderA: string, folderB: string): Promise<string> {\n  const folderAN = folderA.replace(/\\\\/g, '/')\n  const folderBN = folderB.replace(/\\\\/g, '/')\n  let stdout!: string\n  let stderr!: string\n\n  try {\n    const result = await execa('git', ['-c', 'core.safecrlf=false', 'diff', '--src-prefix=a/', '--dst-prefix=b/', '--ignore-cr-at-eol', '--irreversible-delete', '--full-index', '--no-index', '--text', '--no-ext-diff', '--no-color', folderAN, folderBN], {\n      cwd: process.cwd(),\n      env: {\n        ...process.env,\n        // #region Predictable output\n        // These variables aim to ignore the global git config so we get predictable output\n        // https://git-scm.com/docs/git#Documentation/git.txt-codeGITCONFIGNOSYSTEMcode\n        GIT_CONFIG_NOSYSTEM: '1',\n        // Redirect the global git config to the null device instead of setting\n        // HOME to an empty string. An empty HOME causes git to resolve '~' as\n        // '/' (root), which triggers a \"Permission denied\" warning when git\n        // tries to access '/.config/git/attributes', making pnpm throw an\n        // error because any stderr output is treated as a failure.\n        // We do not set XDG_CONFIG_HOME to avoid the same issue: an empty\n        // value would make git resolve paths like /git/config and /git/attributes.\n        // Use '/dev/null' instead of os.devNull because git on Windows\n        // (Git for Windows / MSYS2) understands Unix-style '/dev/null' but\n        // cannot access the native Windows null device '\\\\.\\nul' as a file path.\n        GIT_CONFIG_GLOBAL: '/dev/null',\n        // #endregion\n      },\n      stripFinalNewline: false,\n    })\n    stdout = result.stdout\n    stderr = result.stderr\n  } catch (err: any) { // eslint-disable-line\n    stdout = err.stdout\n    stderr = err.stderr\n  }\n  // we cannot rely on exit code, because --no-index implies --exit-code\n  // i.e. git diff will exit with 1 if there were differences\n  if (stderr.length > 0)\n    throw new Error(`Unable to diff directories. Make sure you have a recent version of 'git' available in PATH.\\nThe following error was reported by 'git':\\n${stderr}`)\n\n  return stdout\n    .replace(new RegExp(`(a|b)(${escapeStringRegexp(`/${removeTrailingAndLeadingSlash(folderAN)}/`)})`, 'g'), '$1/')\n    .replace(new RegExp(`(a|b)${escapeStringRegexp(`/${removeTrailingAndLeadingSlash(folderBN)}/`)}`, 'g'), '$1/')\n    .replace(new RegExp(escapeStringRegexp(`${folderAN}/`), 'g'), '')\n    .replace(new RegExp(escapeStringRegexp(`${folderBN}/`), 'g'), '')\n    .replace(/\\n\\\\ No newline at end of file\\n$/, '\\n')\n    .replace(/^diff --git a\\/.*\\.DS_Store b\\/.*\\.DS_Store[\\s\\S]+?(?=^diff --git)/gm, '')\n    .replace(/^diff --git a\\/.*\\.DS_Store b\\/.*\\.DS_Store[\\s\\S]*$/gm, '')\n}\n\nfunction removeTrailingAndLeadingSlash (p: string): string {\n  if (p[0] === '/' || p.endsWith('/')) {\n    return p.replace(/^\\/|\\/$/g, '')\n  }\n  return p\n}\n\n/**\n * Link files from the source directory to a new temporary directory,\n * but only if not all files in the source directory should be included in the package.\n * If all files should be included, return the original source directory without creating any links.\n * This is required in order for the diff to not include files that are not part of the package.\n */\nasync function preparePkgFilesForDiff (src: string): Promise<string> {\n  const files = Array.from(new Set((await packlist(src)).map((f) => path.join(f))))\n  // If there are no extra files in the source directories, then there is no reason\n  // to copy.\n  if (await areAllFilesInPkg(files, src)) {\n    return src\n  }\n  const dest = `${src}_tmp`\n  await makeEmptyDir(dest)\n  await Promise.all(\n    files.map(async (file) => {\n      const srcFile = path.join(src, file)\n      const destFile = path.join(dest, file)\n      const destDir = path.dirname(destFile)\n      await fs.promises.mkdir(destDir, { recursive: true })\n      await fs.promises.link(srcFile, destFile)\n    })\n  )\n  return dest\n}\n\nasync function areAllFilesInPkg (files: string[], basePath: string): Promise<boolean> {\n  const allFiles = await glob('**', {\n    cwd: basePath,\n  })\n  return equals(allFiles.sort(), files.sort())\n}\n\nasync function getGitTarballUrlFromLockfile (dep: ParseWantedDependencyResult, opts: GetPatchedDependencyOptions): Promise<string | undefined> {\n  const { preferredVersions } = await getVersionsFromLockfile(dep, opts)\n  return preferredVersions[0]?.gitTarballUrl\n}\n",
      "after": "import fs from 'fs'\nimport path from 'path'\nimport { docsUrl } from '@pnpm/cli-utils'\nimport { type Config, types as allTypes } from '@pnpm/config'\nimport { createShortHash } from '@pnpm/crypto.hash'\nimport { PnpmError } from '@pnpm/error'\nimport { packlist } from '@pnpm/fs.packlist'\nimport { globalWarn } from '@pnpm/logger'\nimport { install } from '@pnpm/plugin-commands-installation'\nimport { readPackageJsonFromDir } from '@pnpm/read-package-json'\nimport { getStorePath } from '@pnpm/store-path'\nimport { type ProjectRootDir } from '@pnpm/types'\nimport { glob } from 'tinyglobby'\nimport normalizePath from 'normalize-path'\nimport pick from 'ramda/src/pick'\nimport equals from 'ramda/src/equals'\nimport execa from 'safe-execa'\nimport escapeStringRegexp from 'escape-string-regexp'\nimport makeEmptyDir from 'make-empty-dir'\nimport renderHelp from 'render-help'\nimport { type WritePackageOptions, writePackage } from './writePackage.js'\nimport { type ParseWantedDependencyResult, parseWantedDependency } from '@pnpm/parse-wanted-dependency'\nimport { type GetPatchedDependencyOptions, getVersionsFromLockfile } from './getPatchedDependency.js'\nimport { readEditDirState } from './stateFile.js'\nimport { updatePatchedDependencies } from './updatePatchedDependencies.js'\n\nexport const rcOptionsTypes = cliOptionsTypes\n\nexport function cliOptionsTypes (): Record<string, unknown> {\n  return pick(['patches-dir'], allTypes)\n}\n\nexport const commandNames = ['patch-commit']\n\nexport function help (): string {\n  return renderHelp({\n    description: 'Generate a patch out of a directory',\n    descriptionLists: [{\n      title: 'Options',\n      list: [\n        {\n          description: 'The generated patch file will be saved to this directory',\n          name: '--patches-dir',\n        },\n      ],\n    }],\n    url: docsUrl('patch-commit'),\n    usages: ['pnpm patch-commit <patchDir>'],\n  })\n}\n\ntype PatchCommitCommandOptions = install.InstallCommandOptions & Pick<Config, 'patchesDir' | 'rootProjectManifest' | 'rootProjectManifestDir' | 'patchedDependencies'>\n\nexport async function handler (opts: PatchCommitCommandOptions, params: string[]): Promise<string | undefined> {\n  const userDir = params[0]\n  const lockfileDir = (opts.lockfileDir ?? opts.dir ?? process.cwd()) as ProjectRootDir\n  const patchesDirName = normalizePath(path.normalize(opts.patchesDir ?? 'patches'))\n  const patchesDir = path.join(lockfileDir, patchesDirName)\n  const patchedPkgManifest = await readPackageJsonFromDir(userDir)\n  const editDir = path.resolve(opts.dir, userDir)\n  const stateValue = readEditDirState({\n    editDir,\n    modulesDir: path.join(lockfileDir, opts.modulesDir ?? 'node_modules'),\n  })\n  if (!stateValue) {\n    throw new PnpmError('INVALID_PATCH_DIR', `${userDir} is not a valid patch directory`, {\n      hint: 'A valid patch directory should be created by `pnpm patch`',\n    })\n  }\n  const { applyToAll } = stateValue\n  const nameAndVersion = `${patchedPkgManifest.name}@${patchedPkgManifest.version}`\n  const patchKey = applyToAll ? patchedPkgManifest.name : nameAndVersion\n  let gitTarballUrl: string | undefined\n  if (!applyToAll) {\n    gitTarballUrl = await getGitTarballUrlFromLockfile({\n      alias: patchedPkgManifest.name,\n      bareSpecifier: patchedPkgManifest.version || undefined,\n    }, {\n      lockfileDir,\n      modulesDir: opts.modulesDir,\n      virtualStoreDir: opts.virtualStoreDir,\n    })\n  }\n  const patchedPkg = parseWantedDependency(gitTarballUrl ? `${patchedPkgManifest.name}@${gitTarballUrl}` : nameAndVersion)\n  const patchedPkgDir = await preparePkgFilesForDiff(userDir)\n  const patchContent = await getPatchContent({\n    patchedPkg,\n    patchedPkgDir,\n    tmpName: createShortHash(editDir),\n  }, opts)\n  if (patchedPkgDir !== userDir) {\n    fs.rmSync(patchedPkgDir, { recursive: true })\n  }\n\n  if (!patchContent.length) {\n    return `No changes were found to the following directory: ${userDir}`\n  }\n  await fs.promises.mkdir(patchesDir, { recursive: true })\n\n  const patchFileName = patchKey.replace('/', '__')\n  await fs.promises.writeFile(path.join(patchesDir, `${patchFileName}.patch`), patchContent, 'utf8')\n\n  const patchedDependencies = {\n    ...opts.patchedDependencies,\n    [patchKey]: `${patchesDirName}/${patchFileName}.patch`,\n  }\n  await updatePatchedDependencies(patchedDependencies, {\n    ...opts,\n    workspaceDir: opts.workspaceDir ?? opts.rootProjectManifestDir,\n  })\n\n  return install.handler({\n    ...opts,\n    patchedDependencies,\n    rawLocalConfig: {\n      ...opts.rawLocalConfig,\n      'frozen-lockfile': false,\n    },\n  }) as Promise<undefined>\n}\n\ninterface GetPatchContentContext {\n  patchedPkg: ParseWantedDependencyResult\n  patchedPkgDir: string\n  tmpName: string\n}\n\ntype GetPatchContentOptions = Pick<PatchCommitCommandOptions, 'dir' | 'pnpmHomeDir' | 'storeDir'> & WritePackageOptions\n\nasync function getPatchContent (ctx: GetPatchContentContext, opts: GetPatchContentOptions): Promise<string> {\n  const storeDir = await getStorePath({\n    pkgRoot: opts.dir,\n    storePath: opts.storeDir,\n    pnpmHomeDir: opts.pnpmHomeDir,\n  })\n  const srcDir = path.join(storeDir, 'tmp', 'patch-commit', ctx.tmpName)\n  await writePackage(ctx.patchedPkg, srcDir, opts)\n  const patchContent = await diffFolders(srcDir, ctx.patchedPkgDir)\n  try {\n    fs.rmSync(srcDir, { recursive: true })\n  } catch (error) {\n    globalWarn(`Failed to clean up temporary directory at ${srcDir} with error: ${String(error)}`)\n  }\n  return patchContent\n}\n\nasync function diffFolders (folderA: string, folderB: string): Promise<string> {\n  const folderAN = folderA.replace(/\\\\/g, '/')\n  const folderBN = folderB.replace(/\\\\/g, '/')\n  let stdout!: string\n  let stderr!: string\n\n  try {\n    const result = await execa('git', ['-c', 'core.safecrlf=false', 'diff', '--src-prefix=a/', '--dst-prefix=b/', '--ignore-cr-at-eol', '--irreversible-delete', '--full-index', '--no-index', '--text', '--no-ext-diff', '--no-color', folderAN, folderBN], {\n      cwd: process.cwd(),\n      env: {\n        ...process.env,\n        // #region Predictable output\n        // These variables aim to ignore the global git config so we get predictable output\n        // https://git-scm.com/docs/git#Documentation/git.txt-codeGITCONFIGNOSYSTEMcode\n        GIT_CONFIG_NOSYSTEM: '1',\n        // Redirect the global git config to the null device instead of setting\n        // HOME to an empty string. An empty HOME causes git to resolve '~' as\n        // '/' (root), which triggers a \"Permission denied\" warning when git\n        // tries to access '/.config/git/attributes', making pnpm throw an\n        // error because any stderr output is treated as a failure.\n        // We do not set XDG_CONFIG_HOME to avoid the same issue: an empty\n        // value would make git resolve paths like /git/config and /git/attributes.\n        // Use '/dev/null' instead of os.devNull because git on Windows\n        // (Git for Windows / MSYS2) understands Unix-style '/dev/null' but\n        // cannot access the native Windows null device '\\\\.\\nul' as a file path.\n        GIT_CONFIG_GLOBAL: '/dev/null',\n        // #endregion\n      },\n      stripFinalNewline: false,\n    })\n    stdout = result.stdout\n    stderr = result.stderr\n  } catch (err: any) { // eslint-disable-line\n    stdout = err.stdout\n    stderr = err.stderr\n  }\n  // we cannot rely on exit code, because --no-index implies --exit-code\n  // i.e. git diff will exit with 1 if there were differences\n  if (stderr.length > 0)\n    throw new Error(`Unable to diff directories. Make sure you have a recent version of 'git' available in PATH.\\nThe following error was reported by 'git':\\n${stderr}`)\n\n  return stdout\n    .replace(new RegExp(`(a|b)(${escapeStringRegexp(`/${removeTrailingAndLeadingSlash(folderAN)}/`)})`, 'g'), '$1/')\n    .replace(new RegExp(`(a|b)${escapeStringRegexp(`/${removeTrailingAndLeadingSlash(folderBN)}/`)}`, 'g'), '$1/')\n    .replace(new RegExp(escapeStringRegexp(`${folderAN}/`), 'g'), '')\n    .replace(new RegExp(escapeStringRegexp(`${folderBN}/`), 'g'), '')\n    .replace(/\\n\\\\ No newline at end of file\\n$/, '\\n')\n    .replace(/^diff --git a\\/.*\\.DS_Store b\\/.*\\.DS_Store[\\s\\S]+?(?=^diff --git)/gm, '')\n    .replace(/^diff --git a\\/.*\\.DS_Store b\\/.*\\.DS_Store[\\s\\S]*$/gm, '')\n}\n\nfunction removeTrailingAndLeadingSlash (p: string): string {\n  if (p[0] === '/' || p.endsWith('/')) {\n    return p.replace(/^\\/|\\/$/g, '')\n  }\n  return p\n}\n\n/**\n * Link files from the source directory to a new temporary directory,\n * but only if not all files in the source directory should be included in the package.\n * If all files should be included, return the original source directory without creating any links.\n * This is required in order for the diff to not include files that are not part of the package.\n */\nasync function preparePkgFilesForDiff (src: string): Promise<string> {\n  const files = Array.from(new Set((await packlist(src)).map((f) => path.join(f))))\n  // If there are no extra files in the source directories, then there is no reason\n  // to copy.\n  if (await areAllFilesInPkg(files, src)) {\n    return src\n  }\n  const dest = `${src}_tmp`\n  await makeEmptyDir(dest)\n  await Promise.all(\n    files.map(async (file) => {\n      const srcFile = path.join(src, file)\n      const destFile = path.join(dest, file)\n      const destDir = path.dirname(destFile)\n      await fs.promises.mkdir(destDir, { recursive: true })\n      await fs.promises.link(srcFile, destFile)\n    })\n  )\n  return dest\n}\n\nasync function areAllFilesInPkg (files: string[], basePath: string): Promise<boolean> {\n  const allFiles = await glob('**', {\n    cwd: basePath,\n    expandDirectories: false,\n  })\n  return equals(allFiles.sort(), files.sort())\n}\n\nasync function getGitTarballUrlFromLockfile (dep: ParseWantedDependencyResult, opts: GetPatchedDependencyOptions): Promise<string | undefined> {\n  const { preferredVersions } = await getVersionsFromLockfile(dep, opts)\n  return preferredVersions[0]?.gitTarballUrl\n}\n"
    },
    {
      "path": "pkg-manager/package-bins/src/index.ts",
      "beforeSha256": "f40113305b60715971b68cdfbaa33c0bc1c5d146809d8e6a5e273ea56238bef4",
      "afterSha256": "5cab2cbd7e05cae4ef634020b13c1b31787db8dac3a93e6722f0921740f82ebe",
      "before": "import path from 'path'\nimport { type DependencyManifest, type PackageBin } from '@pnpm/types'\nimport fastGlob from 'fast-glob'\nimport isSubdir from 'is-subdir'\n\nexport interface Command {\n  name: string\n  path: string\n}\n\nexport async function getBinsFromPackageManifest (manifest: DependencyManifest, pkgPath: string): Promise<Command[]> {\n  if (manifest.bin) {\n    return commandsFromBin(manifest.bin, manifest.name, pkgPath)\n  }\n  if (manifest.directories?.bin) {\n    const binDir = path.join(pkgPath, manifest.directories.bin)\n    // Validate: directories.bin must be within the package root\n    if (!isSubdir(pkgPath, binDir)) {\n      return []\n    }\n    const files = await findFiles(binDir)\n    return files.map((file) => ({\n      name: path.basename(file),\n      path: path.join(binDir, file),\n    }))\n  }\n  return []\n}\n\nasync function findFiles (dir: string): Promise<string[]> {\n  try {\n    return await fastGlob('**', {\n      cwd: dir,\n      onlyFiles: true,\n      followSymbolicLinks: false,\n      })\n  } catch (err: any) { // eslint-disable-line\n    if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n      throw err\n    }\n    return []\n  }\n}\n\nfunction commandsFromBin (bin: PackageBin, pkgName: string, pkgPath: string): Command[] {\n  const cmds: Command[] = []\n  for (const [commandName, binRelativePath] of typeof bin === 'string' ? [[pkgName, bin]] : Object.entries(bin)) {\n    const binName = commandName[0] === '@'\n      ? commandName.slice(commandName.indexOf('/') + 1)\n      : commandName\n    // Validate: must be safe (no path traversal) - only allow URL-safe chars or $\n    if (binName !== encodeURIComponent(binName) && binName !== '$') {\n      continue\n    }\n    const binPath = path.join(pkgPath, binRelativePath)\n    if (!isSubdir(pkgPath, binPath)) {\n      continue\n    }\n    cmds.push({ name: binName, path: binPath })\n  }\n  return cmds\n}\n",
      "after": "import path from 'path'\nimport { type DependencyManifest, type PackageBin } from '@pnpm/types'\nimport isSubdir from 'is-subdir'\nimport { glob } from 'tinyglobby'\n\nexport interface Command {\n  name: string\n  path: string\n}\n\nexport async function getBinsFromPackageManifest (manifest: DependencyManifest, pkgPath: string): Promise<Command[]> {\n  if (manifest.bin) {\n    return commandsFromBin(manifest.bin, manifest.name, pkgPath)\n  }\n  if (manifest.directories?.bin) {\n    const binDir = path.join(pkgPath, manifest.directories.bin)\n    // Validate: directories.bin must be within the package root\n    if (!isSubdir(pkgPath, binDir)) {\n      return []\n    }\n    const files = await findFiles(binDir)\n    return files.map((file) => ({\n      name: path.basename(file),\n      path: path.join(binDir, file),\n    }))\n  }\n  return []\n}\n\nasync function findFiles (dir: string): Promise<string[]> {\n  try {\n    return await glob('**', {\n      cwd: dir,\n      expandDirectories: false,\n      onlyFiles: true,\n      followSymbolicLinks: false,\n    })\n  } catch (err: any) { // eslint-disable-line\n    if ((err as NodeJS.ErrnoException).code !== 'ENOENT') {\n      throw err\n    }\n    return []\n  }\n}\n\nfunction commandsFromBin (bin: PackageBin, pkgName: string, pkgPath: string): Command[] {\n  const cmds: Command[] = []\n  for (const [commandName, binRelativePath] of typeof bin === 'string' ? [[pkgName, bin]] : Object.entries(bin)) {\n    const binName = commandName[0] === '@'\n      ? commandName.slice(commandName.indexOf('/') + 1)\n      : commandName\n    // Validate: must be safe (no path traversal) - only allow URL-safe chars or $\n    if (binName !== encodeURIComponent(binName) && binName !== '$') {\n      continue\n    }\n    const binPath = path.join(pkgPath, binRelativePath)\n    if (!isSubdir(pkgPath, binPath)) {\n      continue\n    }\n    cmds.push({ name: binName, path: binPath })\n  }\n  return cmds\n}\n"
    },
    {
      "path": "releasing/plugin-commands-publishing/src/pack.ts",
      "beforeSha256": "7e179d302ae0feefa08cce4181cc2b52ebbae2a83486e2a75e3b52309b11ed79",
      "afterSha256": "a4cc436fa17b174a0cb6863ff4f6040ce36c532423cb67b6a85a6b427821d9ce",
      "before": "import fs from 'fs'\nimport path from 'path'\nimport { createGzip } from 'zlib'\nimport { type Catalogs } from '@pnpm/catalogs.types'\nimport { PnpmError } from '@pnpm/error'\nimport { types as allTypes, type UniversalOptions, type Config, getWorkspaceConcurrency, getDefaultWorkspaceConcurrency } from '@pnpm/config'\nimport { readProjectManifest } from '@pnpm/cli-utils'\nimport { createExportableManifest } from '@pnpm/exportable-manifest'\nimport { packlist } from '@pnpm/fs.packlist'\nimport { getBinsFromPackageManifest } from '@pnpm/package-bins'\nimport { type Hooks } from '@pnpm/pnpmfile'\nimport { type ProjectManifest, type Project, type ProjectRootDir, type ProjectsGraph, type DependencyManifest } from '@pnpm/types'\nimport fg from 'fast-glob'\nimport pick from 'ramda/src/pick'\nimport realpathMissing from 'realpath-missing'\nimport renderHelp from 'render-help'\nimport tar from 'tar-stream'\nimport { runScriptsIfPresent } from './publish.js'\nimport chalk from 'chalk'\nimport validateNpmPackageName from 'validate-npm-package-name'\nimport pLimit from 'p-limit'\nimport { FILTERING } from '@pnpm/common-cli-options-help'\nimport { sortPackages } from '@pnpm/sort-packages'\nimport { logger } from '@pnpm/logger'\n\nconst LICENSE_GLOB = 'LICEN{S,C}E{,.*}' // cspell:disable-line\nconst findLicenses = fg.bind(fg, [LICENSE_GLOB]) as (opts: { cwd: string }) => Promise<string[]>\n\nexport function rcOptionsTypes (): Record<string, unknown> {\n  return {\n    ...cliOptionsTypes(),\n    ...pick([\n      'npm-path',\n    ], allTypes),\n  }\n}\n\nexport function cliOptionsTypes (): Record<string, unknown> {\n  return {\n    out: String,\n    recursive: Boolean,\n    ...pick([\n      'dry-run',\n      'pack-destination',\n      'pack-gzip-level',\n      'json',\n      'workspace-concurrency',\n    ], allTypes),\n  }\n}\n\nexport const commandNames = ['pack']\n\nexport function help (): string {\n  return renderHelp({\n    description: 'Create a tarball from a package',\n    usages: ['pnpm pack'],\n    descriptionLists: [\n      {\n        title: 'Options',\n\n        list: [\n          {\n            description: 'Does everything `pnpm pack` would do except actually writing the tarball to disk.',\n            name: '--dry-run',\n          },\n          {\n            description: 'Directory in which `pnpm pack` will save tarballs. The default is the current working directory.',\n            name: '--pack-destination <dir>',\n          },\n          {\n            description: 'Prints the packed tarball and contents in the json format.',\n            name: '--json',\n          },\n          {\n            description: 'Customizes the output path for the tarball. Use `%s` and `%v` to include the package name and version, e.g., `%s.tgz` or `some-dir/%s-%v.tgz`. By default, the tarball is saved in the current working directory with the name `<package-name>-<version>.tgz`.',\n            name: '--out <path>',\n          },\n          {\n            description: 'Pack all packages from the workspace',\n            name: '--recursive',\n            shortAlias: '-r',\n          },\n          {\n            description: `Set the maximum number of concurrency. Default is ${getDefaultWorkspaceConcurrency()}. For unlimited concurrency use Infinity.`,\n            name: '--workspace-concurrency <number>',\n          },\n        ],\n      },\n      FILTERING,\n    ],\n  })\n}\n\nexport type PackOptions = Pick<UniversalOptions, 'dir'> & Pick<Config, 'catalogs'\n| 'ignoreScripts'\n| 'rawConfig'\n| 'embedReadme'\n| 'packGzipLevel'\n| 'nodeLinker'\n> & Partial<Pick<Config, 'extraBinPaths'\n| 'extraEnv'\n| 'hooks'\n| 'recursive'\n| 'selectedProjectsGraph'\n| 'workspaceConcurrency'\n| 'workspaceDir'\n>> & {\n  argv: {\n    original: string[]\n  }\n  dryRun?: boolean\n  engineStrict?: boolean\n  packDestination?: string\n  out?: string\n  json?: boolean\n  unicode?: boolean\n}\n\nexport interface PackResultJson {\n  name: string\n  version: string\n  filename: string\n  files: Array<{ path: string }>\n}\n\nexport async function handler (opts: PackOptions): Promise<string> {\n  const packedPackages: PackResultJson[] = []\n\n  if (opts.recursive) {\n    const selectedProjectsGraph = opts.selectedProjectsGraph as ProjectsGraph\n    const pkgsToPack: Project[] = []\n    for (const { package: pkg } of Object.values(selectedProjectsGraph)) {\n      if (pkg.manifest.name && pkg.manifest.version) {\n        pkgsToPack.push(pkg)\n      }\n    }\n    const packedPkgDirs = new Set<ProjectRootDir>(pkgsToPack.map(({ rootDir }) => rootDir))\n\n    if (packedPkgDirs.size === 0) {\n      logger.info({\n        message: 'There are no packages that should be packed',\n        prefix: opts.dir,\n      })\n    }\n\n    const chunks = sortPackages(selectedProjectsGraph)\n\n    const limitPack = pLimit(getWorkspaceConcurrency(opts.workspaceConcurrency))\n    const resolvedOpts = { ...opts }\n    if (opts.out) {\n      resolvedOpts.out = path.resolve(opts.dir, opts.out)\n    } else if (opts.packDestination) {\n      resolvedOpts.packDestination = path.resolve(opts.dir, opts.packDestination)\n    } else {\n      resolvedOpts.packDestination = path.resolve(opts.dir)\n    }\n    for (const chunk of chunks) {\n      // eslint-disable-next-line no-await-in-loop\n      await Promise.all(chunk.map(pkgDir =>\n        limitPack(async () => {\n          if (!packedPkgDirs.has(pkgDir)) return\n          const pkg = selectedProjectsGraph[pkgDir].package\n          const packResult = await api({\n            ...resolvedOpts,\n            dir: pkg.rootDir,\n          })\n          packedPackages.push(toPackResultJson(packResult))\n        })\n      ))\n    }\n  } else {\n    const packResult = await api(opts)\n    packedPackages.push(toPackResultJson(packResult))\n  }\n\n  if (opts.json) {\n    return JSON.stringify(packedPackages.length > 1 ? packedPackages : packedPackages[0], null, 2)\n  }\n\n  return packedPackages.map(\n    ({ name, version, filename, files }) => `${opts.unicode ? '📦 ' : 'package:'} ${name}@${version}\n${chalk.blueBright('Tarball Contents')}\n${files.map(({ path }) => path).join('\\n')}\n${chalk.blueBright('Tarball Details')}\n${filename}`\n  ).join('\\n\\n')\n}\n\nexport async function api (opts: PackOptions): Promise<PackResult> {\n  const { manifest: entryManifest, fileName: manifestFileName } = await readProjectManifest(opts.dir, opts)\n  preventBundledDependenciesWithoutHoistedNodeLinker(opts.nodeLinker, entryManifest)\n  const _runScriptsIfPresent = runScriptsIfPresent.bind(null, {\n    depPath: opts.dir,\n    extraBinPaths: opts.extraBinPaths,\n    extraEnv: opts.extraEnv,\n    pkgRoot: opts.dir,\n    rawConfig: opts.rawConfig,\n    rootModulesDir: await realpathMissing(path.join(opts.dir, 'node_modules')),\n    stdio: 'inherit',\n    unsafePerm: true, // when running scripts explicitly, assume that they're trusted.\n  })\n  if (!opts.ignoreScripts) {\n    await _runScriptsIfPresent([\n      'prepack',\n      'prepare',\n    ], entryManifest)\n  }\n  const dir = entryManifest.publishConfig?.directory\n    ? path.join(opts.dir, entryManifest.publishConfig.directory)\n    : opts.dir\n  // always read the latest manifest, as \"prepack\" or \"prepare\" script may modify package manifest.\n  const { manifest } = await readProjectManifest(dir, opts)\n  preventBundledDependenciesWithoutHoistedNodeLinker(opts.nodeLinker, manifest)\n  if (!manifest.name) {\n    throw new PnpmError('PACKAGE_NAME_NOT_FOUND', `Package name is not defined in the ${manifestFileName}.`)\n  }\n  if (!validateNpmPackageName(manifest.name).validForOldPackages) {\n    throw new PnpmError('INVALID_PACKAGE_NAME', `Invalid package name \"${manifest.name}\".`)\n  }\n  if (!manifest.version) {\n    throw new PnpmError('PACKAGE_VERSION_NOT_FOUND', `Package version is not defined in the ${manifestFileName}.`)\n  }\n  let tarballName: string\n  let packDestination: string | undefined\n  const normalizedName = manifest.name.replace('@', '').replace('/', '-')\n  if (opts.out) {\n    if (opts.packDestination) {\n      throw new PnpmError('INVALID_OPTION', 'Cannot use --pack-destination and --out together')\n    }\n    const preparedOut = opts.out.replaceAll('%s', normalizedName).replaceAll('%v', manifest.version)\n    const parsedOut = path.parse(preparedOut)\n    packDestination = parsedOut.dir ? parsedOut.dir : opts.packDestination\n    tarballName = parsedOut.base\n  } else {\n    tarballName = `${normalizedName}-${manifest.version}.tgz`\n    packDestination = opts.packDestination\n  }\n  const publishManifest = await createPublishManifest({\n    projectDir: dir,\n    modulesDir: path.join(opts.dir, 'node_modules'),\n    manifest,\n    embedReadme: opts.embedReadme,\n    catalogs: opts.catalogs ?? {},\n    hooks: opts.hooks,\n  })\n  const files = await packlist(dir, {\n    packageJsonCache: {\n      [path.join(dir, 'package.json')]: publishManifest as Record<string, unknown>,\n    },\n  })\n  const filesMap = Object.fromEntries(files.map((file) => [`package/${file}`, path.join(dir, file)]))\n  // cspell:disable-next-line\n  if (opts.workspaceDir != null && dir !== opts.workspaceDir && !files.some((file) => /LICEN[CS]E(?:\\..+)?/i.test(file))) {\n    const licenses = await findLicenses({ cwd: opts.workspaceDir })\n    for (const license of licenses) {\n      filesMap[`package/${license}`] = path.join(opts.workspaceDir, license)\n    }\n  }\n  const destDir = packDestination\n    ? (path.isAbsolute(packDestination) ? packDestination : path.join(dir, packDestination ?? '.'))\n    : dir\n  if (!opts.dryRun) {\n    await fs.promises.mkdir(destDir, { recursive: true })\n    await packPkg({\n      destFile: path.join(destDir, tarballName),\n      filesMap,\n      modulesDir: path.join(opts.dir, 'node_modules'),\n      packGzipLevel: opts.packGzipLevel,\n      manifest: publishManifest,\n      bins: [\n        ...(await getBinsFromPackageManifest(publishManifest as DependencyManifest, dir)).map(({ path }) => path),\n        ...(manifest.publishConfig?.executableFiles ?? [])\n          .map((executableFile) => path.join(dir, executableFile)),\n      ],\n    })\n    if (!opts.ignoreScripts) {\n      await _runScriptsIfPresent(['postpack'], entryManifest)\n    }\n  }\n  let packedTarballPath\n  if (opts.dir !== destDir) {\n    packedTarballPath = path.join(destDir, tarballName)\n  } else {\n    packedTarballPath = path.relative(opts.dir, path.join(dir, tarballName))\n  }\n  const packedContents = files.sort((a, b) => a.localeCompare(b, 'en'))\n  return {\n    publishedManifest: publishManifest,\n    contents: packedContents,\n    tarballPath: packedTarballPath,\n  }\n}\n\nexport interface PackResult {\n  publishedManifest: ProjectManifest\n  contents: string[]\n  tarballPath: string\n}\n\nfunction preventBundledDependenciesWithoutHoistedNodeLinker (nodeLinker: Config['nodeLinker'], manifest: ProjectManifest): void {\n  if (nodeLinker === 'hoisted') return\n  for (const key of ['bundledDependencies', 'bundleDependencies'] as const) {\n    const bundledDependencies = manifest[key]\n    if (bundledDependencies) {\n      throw new PnpmError('BUNDLED_DEPENDENCIES_WITHOUT_HOISTED', `${key} does not work with \"nodeLinker: ${nodeLinker}\"`, {\n        hint: `Add \"nodeLinker: hoisted\" to pnpm-workspace.yaml or delete ${key} from the root package.json to resolve this error`,\n      })\n    }\n  }\n}\n\nasync function readReadmeFile (projectDir: string): Promise<string | undefined> {\n  const files = await fs.promises.readdir(projectDir)\n  const readmePath = files.find(name => /readme\\.md$/i.test(name))\n  const readmeFile = readmePath ? await fs.promises.readFile(path.join(projectDir, readmePath), 'utf8') : undefined\n\n  return readmeFile\n}\n\nasync function packPkg (opts: {\n  destFile: string\n  filesMap: Record<string, string>\n  modulesDir: string\n  packGzipLevel?: number\n  bins: string[]\n  manifest: ProjectManifest\n}): Promise<void> {\n  const {\n    destFile,\n    filesMap,\n    bins,\n    manifest,\n  } = opts\n  const mtime = new Date('1985-10-26T08:15:00.000Z')\n  const pack = tar.pack()\n  await Promise.all(Object.entries(filesMap).map(async ([name, source]) => {\n    const isExecutable = bins.some((bin) => path.relative(bin, source) === '')\n    const mode = isExecutable ? 0o755 : 0o644\n    if (/^package\\/package\\.(?:json|json5|yaml)$/.test(name)) {\n      pack.entry({ mode, mtime, name: 'package/package.json' }, JSON.stringify(manifest, null, 2))\n      return\n    }\n    pack.entry({ mode, mtime, name }, fs.readFileSync(source))\n  }))\n  const tarball = fs.createWriteStream(destFile)\n  pack.pipe(createGzip({ level: opts.packGzipLevel })).pipe(tarball)\n  pack.finalize()\n  return new Promise((resolve, reject) => {\n    tarball.on('close', () => {\n      resolve()\n    }).on('error', reject)\n  })\n}\n\nasync function createPublishManifest (opts: {\n  projectDir: string\n  embedReadme?: boolean\n  modulesDir: string\n  manifest: ProjectManifest\n  catalogs: Catalogs\n  hooks?: Hooks\n}): Promise<ProjectManifest> {\n  const { projectDir, embedReadme, modulesDir, manifest, catalogs, hooks } = opts\n  const readmeFile = embedReadme ? await readReadmeFile(projectDir) : undefined\n  return createExportableManifest(projectDir, manifest, {\n    catalogs,\n    hooks,\n    readmeFile,\n    modulesDir,\n  })\n}\n\nfunction toPackResultJson (packResult: PackResult): PackResultJson {\n  const { publishedManifest, contents, tarballPath } = packResult\n  return {\n    name: publishedManifest.name as string,\n    version: publishedManifest.version as string,\n    filename: tarballPath,\n    files: contents.map((file) => ({ path: file })),\n  }\n}\n",
      "after": "import fs from 'fs'\nimport path from 'path'\nimport { createGzip } from 'zlib'\nimport { type Catalogs } from '@pnpm/catalogs.types'\nimport { PnpmError } from '@pnpm/error'\nimport { types as allTypes, type UniversalOptions, type Config, getWorkspaceConcurrency, getDefaultWorkspaceConcurrency } from '@pnpm/config'\nimport { readProjectManifest } from '@pnpm/cli-utils'\nimport { createExportableManifest } from '@pnpm/exportable-manifest'\nimport { packlist } from '@pnpm/fs.packlist'\nimport { getBinsFromPackageManifest } from '@pnpm/package-bins'\nimport { type Hooks } from '@pnpm/pnpmfile'\nimport { type ProjectManifest, type Project, type ProjectRootDir, type ProjectsGraph, type DependencyManifest } from '@pnpm/types'\nimport { glob } from 'tinyglobby'\nimport pick from 'ramda/src/pick'\nimport realpathMissing from 'realpath-missing'\nimport renderHelp from 'render-help'\nimport tar from 'tar-stream'\nimport { runScriptsIfPresent } from './publish.js'\nimport chalk from 'chalk'\nimport validateNpmPackageName from 'validate-npm-package-name'\nimport pLimit from 'p-limit'\nimport { FILTERING } from '@pnpm/common-cli-options-help'\nimport { sortPackages } from '@pnpm/sort-packages'\nimport { logger } from '@pnpm/logger'\n\nconst LICENSE_GLOB = 'LICEN{S,C}E{,.*}' // cspell:disable-line\nconst findLicenses = (opts: { cwd: string }): Promise<string[]> => glob([LICENSE_GLOB], { ...opts, expandDirectories: false })\n\nexport function rcOptionsTypes (): Record<string, unknown> {\n  return {\n    ...cliOptionsTypes(),\n    ...pick([\n      'npm-path',\n    ], allTypes),\n  }\n}\n\nexport function cliOptionsTypes (): Record<string, unknown> {\n  return {\n    out: String,\n    recursive: Boolean,\n    ...pick([\n      'dry-run',\n      'pack-destination',\n      'pack-gzip-level',\n      'json',\n      'workspace-concurrency',\n    ], allTypes),\n  }\n}\n\nexport const commandNames = ['pack']\n\nexport function help (): string {\n  return renderHelp({\n    description: 'Create a tarball from a package',\n    usages: ['pnpm pack'],\n    descriptionLists: [\n      {\n        title: 'Options',\n\n        list: [\n          {\n            description: 'Does everything `pnpm pack` would do except actually writing the tarball to disk.',\n            name: '--dry-run',\n          },\n          {\n            description: 'Directory in which `pnpm pack` will save tarballs. The default is the current working directory.',\n            name: '--pack-destination <dir>',\n          },\n          {\n            description: 'Prints the packed tarball and contents in the json format.',\n            name: '--json',\n          },\n          {\n            description: 'Customizes the output path for the tarball. Use `%s` and `%v` to include the package name and version, e.g., `%s.tgz` or `some-dir/%s-%v.tgz`. By default, the tarball is saved in the current working directory with the name `<package-name>-<version>.tgz`.',\n            name: '--out <path>',\n          },\n          {\n            description: 'Pack all packages from the workspace',\n            name: '--recursive',\n            shortAlias: '-r',\n          },\n          {\n            description: `Set the maximum number of concurrency. Default is ${getDefaultWorkspaceConcurrency()}. For unlimited concurrency use Infinity.`,\n            name: '--workspace-concurrency <number>',\n          },\n        ],\n      },\n      FILTERING,\n    ],\n  })\n}\n\nexport type PackOptions = Pick<UniversalOptions, 'dir'> & Pick<Config, 'catalogs'\n| 'ignoreScripts'\n| 'rawConfig'\n| 'embedReadme'\n| 'packGzipLevel'\n| 'nodeLinker'\n> & Partial<Pick<Config, 'extraBinPaths'\n| 'extraEnv'\n| 'hooks'\n| 'recursive'\n| 'selectedProjectsGraph'\n| 'workspaceConcurrency'\n| 'workspaceDir'\n>> & {\n  argv: {\n    original: string[]\n  }\n  dryRun?: boolean\n  engineStrict?: boolean\n  packDestination?: string\n  out?: string\n  json?: boolean\n  unicode?: boolean\n}\n\nexport interface PackResultJson {\n  name: string\n  version: string\n  filename: string\n  files: Array<{ path: string }>\n}\n\nexport async function handler (opts: PackOptions): Promise<string> {\n  const packedPackages: PackResultJson[] = []\n\n  if (opts.recursive) {\n    const selectedProjectsGraph = opts.selectedProjectsGraph as ProjectsGraph\n    const pkgsToPack: Project[] = []\n    for (const { package: pkg } of Object.values(selectedProjectsGraph)) {\n      if (pkg.manifest.name && pkg.manifest.version) {\n        pkgsToPack.push(pkg)\n      }\n    }\n    const packedPkgDirs = new Set<ProjectRootDir>(pkgsToPack.map(({ rootDir }) => rootDir))\n\n    if (packedPkgDirs.size === 0) {\n      logger.info({\n        message: 'There are no packages that should be packed',\n        prefix: opts.dir,\n      })\n    }\n\n    const chunks = sortPackages(selectedProjectsGraph)\n\n    const limitPack = pLimit(getWorkspaceConcurrency(opts.workspaceConcurrency))\n    const resolvedOpts = { ...opts }\n    if (opts.out) {\n      resolvedOpts.out = path.resolve(opts.dir, opts.out)\n    } else if (opts.packDestination) {\n      resolvedOpts.packDestination = path.resolve(opts.dir, opts.packDestination)\n    } else {\n      resolvedOpts.packDestination = path.resolve(opts.dir)\n    }\n    for (const chunk of chunks) {\n      // eslint-disable-next-line no-await-in-loop\n      await Promise.all(chunk.map(pkgDir =>\n        limitPack(async () => {\n          if (!packedPkgDirs.has(pkgDir)) return\n          const pkg = selectedProjectsGraph[pkgDir].package\n          const packResult = await api({\n            ...resolvedOpts,\n            dir: pkg.rootDir,\n          })\n          packedPackages.push(toPackResultJson(packResult))\n        })\n      ))\n    }\n  } else {\n    const packResult = await api(opts)\n    packedPackages.push(toPackResultJson(packResult))\n  }\n\n  if (opts.json) {\n    return JSON.stringify(packedPackages.length > 1 ? packedPackages : packedPackages[0], null, 2)\n  }\n\n  return packedPackages.map(\n    ({ name, version, filename, files }) => `${opts.unicode ? '📦 ' : 'package:'} ${name}@${version}\n${chalk.blueBright('Tarball Contents')}\n${files.map(({ path }) => path).join('\\n')}\n${chalk.blueBright('Tarball Details')}\n${filename}`\n  ).join('\\n\\n')\n}\n\nexport async function api (opts: PackOptions): Promise<PackResult> {\n  const { manifest: entryManifest, fileName: manifestFileName } = await readProjectManifest(opts.dir, opts)\n  preventBundledDependenciesWithoutHoistedNodeLinker(opts.nodeLinker, entryManifest)\n  const _runScriptsIfPresent = runScriptsIfPresent.bind(null, {\n    depPath: opts.dir,\n    extraBinPaths: opts.extraBinPaths,\n    extraEnv: opts.extraEnv,\n    pkgRoot: opts.dir,\n    rawConfig: opts.rawConfig,\n    rootModulesDir: await realpathMissing(path.join(opts.dir, 'node_modules')),\n    stdio: 'inherit',\n    unsafePerm: true, // when running scripts explicitly, assume that they're trusted.\n  })\n  if (!opts.ignoreScripts) {\n    await _runScriptsIfPresent([\n      'prepack',\n      'prepare',\n    ], entryManifest)\n  }\n  const dir = entryManifest.publishConfig?.directory\n    ? path.join(opts.dir, entryManifest.publishConfig.directory)\n    : opts.dir\n  // always read the latest manifest, as \"prepack\" or \"prepare\" script may modify package manifest.\n  const { manifest } = await readProjectManifest(dir, opts)\n  preventBundledDependenciesWithoutHoistedNodeLinker(opts.nodeLinker, manifest)\n  if (!manifest.name) {\n    throw new PnpmError('PACKAGE_NAME_NOT_FOUND', `Package name is not defined in the ${manifestFileName}.`)\n  }\n  if (!validateNpmPackageName(manifest.name).validForOldPackages) {\n    throw new PnpmError('INVALID_PACKAGE_NAME', `Invalid package name \"${manifest.name}\".`)\n  }\n  if (!manifest.version) {\n    throw new PnpmError('PACKAGE_VERSION_NOT_FOUND', `Package version is not defined in the ${manifestFileName}.`)\n  }\n  let tarballName: string\n  let packDestination: string | undefined\n  const normalizedName = manifest.name.replace('@', '').replace('/', '-')\n  if (opts.out) {\n    if (opts.packDestination) {\n      throw new PnpmError('INVALID_OPTION', 'Cannot use --pack-destination and --out together')\n    }\n    const preparedOut = opts.out.replaceAll('%s', normalizedName).replaceAll('%v', manifest.version)\n    const parsedOut = path.parse(preparedOut)\n    packDestination = parsedOut.dir ? parsedOut.dir : opts.packDestination\n    tarballName = parsedOut.base\n  } else {\n    tarballName = `${normalizedName}-${manifest.version}.tgz`\n    packDestination = opts.packDestination\n  }\n  const publishManifest = await createPublishManifest({\n    projectDir: dir,\n    modulesDir: path.join(opts.dir, 'node_modules'),\n    manifest,\n    embedReadme: opts.embedReadme,\n    catalogs: opts.catalogs ?? {},\n    hooks: opts.hooks,\n  })\n  const files = await packlist(dir, {\n    packageJsonCache: {\n      [path.join(dir, 'package.json')]: publishManifest as Record<string, unknown>,\n    },\n  })\n  const filesMap = Object.fromEntries(files.map((file) => [`package/${file}`, path.join(dir, file)]))\n  // cspell:disable-next-line\n  if (opts.workspaceDir != null && dir !== opts.workspaceDir && !files.some((file) => /LICEN[CS]E(?:\\..+)?/i.test(file))) {\n    const licenses = await findLicenses({ cwd: opts.workspaceDir })\n    for (const license of licenses) {\n      filesMap[`package/${license}`] = path.join(opts.workspaceDir, license)\n    }\n  }\n  const destDir = packDestination\n    ? (path.isAbsolute(packDestination) ? packDestination : path.join(dir, packDestination ?? '.'))\n    : dir\n  if (!opts.dryRun) {\n    await fs.promises.mkdir(destDir, { recursive: true })\n    await packPkg({\n      destFile: path.join(destDir, tarballName),\n      filesMap,\n      modulesDir: path.join(opts.dir, 'node_modules'),\n      packGzipLevel: opts.packGzipLevel,\n      manifest: publishManifest,\n      bins: [\n        ...(await getBinsFromPackageManifest(publishManifest as DependencyManifest, dir)).map(({ path }) => path),\n        ...(manifest.publishConfig?.executableFiles ?? [])\n          .map((executableFile) => path.join(dir, executableFile)),\n      ],\n    })\n    if (!opts.ignoreScripts) {\n      await _runScriptsIfPresent(['postpack'], entryManifest)\n    }\n  }\n  let packedTarballPath\n  if (opts.dir !== destDir) {\n    packedTarballPath = path.join(destDir, tarballName)\n  } else {\n    packedTarballPath = path.relative(opts.dir, path.join(dir, tarballName))\n  }\n  const packedContents = files.sort((a, b) => a.localeCompare(b, 'en'))\n  return {\n    publishedManifest: publishManifest,\n    contents: packedContents,\n    tarballPath: packedTarballPath,\n  }\n}\n\nexport interface PackResult {\n  publishedManifest: ProjectManifest\n  contents: string[]\n  tarballPath: string\n}\n\nfunction preventBundledDependenciesWithoutHoistedNodeLinker (nodeLinker: Config['nodeLinker'], manifest: ProjectManifest): void {\n  if (nodeLinker === 'hoisted') return\n  for (const key of ['bundledDependencies', 'bundleDependencies'] as const) {\n    const bundledDependencies = manifest[key]\n    if (bundledDependencies) {\n      throw new PnpmError('BUNDLED_DEPENDENCIES_WITHOUT_HOISTED', `${key} does not work with \"nodeLinker: ${nodeLinker}\"`, {\n        hint: `Add \"nodeLinker: hoisted\" to pnpm-workspace.yaml or delete ${key} from the root package.json to resolve this error`,\n      })\n    }\n  }\n}\n\nasync function readReadmeFile (projectDir: string): Promise<string | undefined> {\n  const files = await fs.promises.readdir(projectDir)\n  const readmePath = files.find(name => /readme\\.md$/i.test(name))\n  const readmeFile = readmePath ? await fs.promises.readFile(path.join(projectDir, readmePath), 'utf8') : undefined\n\n  return readmeFile\n}\n\nasync function packPkg (opts: {\n  destFile: string\n  filesMap: Record<string, string>\n  modulesDir: string\n  packGzipLevel?: number\n  bins: string[]\n  manifest: ProjectManifest\n}): Promise<void> {\n  const {\n    destFile,\n    filesMap,\n    bins,\n    manifest,\n  } = opts\n  const mtime = new Date('1985-10-26T08:15:00.000Z')\n  const pack = tar.pack()\n  await Promise.all(Object.entries(filesMap).map(async ([name, source]) => {\n    const isExecutable = bins.some((bin) => path.relative(bin, source) === '')\n    const mode = isExecutable ? 0o755 : 0o644\n    if (/^package\\/package\\.(?:json|json5|yaml)$/.test(name)) {\n      pack.entry({ mode, mtime, name: 'package/package.json' }, JSON.stringify(manifest, null, 2))\n      return\n    }\n    pack.entry({ mode, mtime, name }, fs.readFileSync(source))\n  }))\n  const tarball = fs.createWriteStream(destFile)\n  pack.pipe(createGzip({ level: opts.packGzipLevel })).pipe(tarball)\n  pack.finalize()\n  return new Promise((resolve, reject) => {\n    tarball.on('close', () => {\n      resolve()\n    }).on('error', reject)\n  })\n}\n\nasync function createPublishManifest (opts: {\n  projectDir: string\n  embedReadme?: boolean\n  modulesDir: string\n  manifest: ProjectManifest\n  catalogs: Catalogs\n  hooks?: Hooks\n}): Promise<ProjectManifest> {\n  const { projectDir, embedReadme, modulesDir, manifest, catalogs, hooks } = opts\n  const readmeFile = embedReadme ? await readReadmeFile(projectDir) : undefined\n  return createExportableManifest(projectDir, manifest, {\n    catalogs,\n    hooks,\n    readmeFile,\n    modulesDir,\n  })\n}\n\nfunction toPackResultJson (packResult: PackResult): PackResultJson {\n  const { publishedManifest, contents, tarballPath } = packResult\n  return {\n    name: publishedManifest.name as string,\n    version: publishedManifest.version as string,\n    filename: tarballPath,\n    files: contents.map((file) => ({ path: file })),\n  }\n}\n"
    }
  ],
  "taskArtifacts": [],
  "recording": "Allowlisted completed public actions, explicit requested task artifacts, independent grading, final changes and measured usage. No reasoning or assistant message bodies."
}
