diff --git a/docs/architecture.md b/docs/architecture.md index f1fefd986..f16981504 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -97,6 +97,12 @@ Plugin switch reconciliation treats `cordis.patch.yml` as structured user config Plugin Manager calls the optional, side-effect-free `profileBundlePackageBackend.validateSwitch` hook after its bundle/protected-manager checks and before saving selection, including unchanged selections. Existing backends without this hook retain their behavior. The normal `switched` callback still commits afterward and revalidates current input; preflight is not a cross-process transaction or proof of recovery from every I/O interruption. This preserves user configuration on explicit toggles; it does not establish the cause of a reported bulk bundle reset or repair already-corrupted rows. Remove the matching Plugin Manager patch hunks when upstream supplies this preflight boundary. +## Plugin metadata queries + +The packaged pnpm runner sends `view` / `info` / `show` / `v` to an installation-owned npm CLI using the existing Electron Node executable. pnpm 10 otherwise forwards these commands to PATH `npm`, which is absent on clean Desktop installations. Resolve npm from the packaged pnpm entry, including when the runner is staged under `.desktop-bin`; never from the Profile or caller cwd. npm preserves registry selection, scoped authentication, proxy and certificate configuration; translate pnpm `--config.*` arguments to npm flags. Mutation commands keep their pnpm path. Missing query resources fail explicitly instead of falling back to a system npm. + +The pinned npm package adds JavaScript dependencies (about 13 MB unpacked before packaging filters), not another Node runtime or native addon. Keep it until the bundled pnpm supplies equivalent native metadata queries. The after-pack Harness gate exercises a local-registry query with no system tools on PATH; the common and Windows suites cover authenticated scoped queries and nonzero registry errors. + ## Mobile access boundary Harness itself stays on a random loopback port. Phone access is provided by a separate bridge: diff --git a/package-lock.json b/package-lock.json index 426e12fd5..392125b08 100644 --- a/package-lock.json +++ b/package-lock.json @@ -249,6 +249,7 @@ "dsh-ppt": "file:packages/ppt-runtime/core", "dsh-ppt-composer": "file:packages/ppt-runtime/adapter", "electron-updater": "^6.8.9", + "npm": "11.21.1", "pnpm": "10.34.5", "qrcode": "^1.5.4", "react": "18.3.1", @@ -14497,6 +14498,160 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/npm": { + "version": "11.21.1", + "resolved": "https://registry.npmmirror.com/npm/-/npm-11.21.1.tgz", + "integrity": "sha512-YTzL6QBEJXyHcTu0JiUc7RKMp+mzlJtl7rGLmERaXUQeFHIMc9atdr6G9M9C8vDWbv40epoTQAzNL2/PtZVDhQ==", + "bundleDependencies": [ + "@isaacs/string-locale-compare", + "@npmcli/arborist", + "@npmcli/config", + "@npmcli/fs", + "@npmcli/map-workspaces", + "@npmcli/metavuln-calculator", + "@npmcli/package-json", + "@npmcli/promise-spawn", + "@npmcli/redact", + "@npmcli/run-script", + "@sigstore/tuf", + "abbrev", + "archy", + "cacache", + "chalk", + "ci-info", + "fastest-levenshtein", + "fs-minipass", + "glob", + "graceful-fs", + "hosted-git-info", + "ini", + "init-package-json", + "is-cidr", + "json-parse-even-better-errors", + "libnpmaccess", + "libnpmdiff", + "libnpmexec", + "libnpmfund", + "libnpmorg", + "libnpmpack", + "libnpmpublish", + "libnpmsearch", + "libnpmteam", + "libnpmversion", + "make-fetch-happen", + "minimatch", + "minipass", + "minipass-pipeline", + "ms", + "node-gyp", + "nopt", + "npm-audit-report", + "npm-install-checks", + "npm-package-arg", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "p-map", + "pacote", + "parse-conflict-json", + "proc-log", + "qrcode-terminal", + "read", + "semver", + "spdx-expression-parse", + "ssri", + "supports-color", + "tar", + "text-table", + "tiny-relative-date", + "treeverse", + "validate-npm-package-name", + "which" + ], + "license": "Artistic-2.0", + "workspaces": [ + "docs", + "smoke-tests", + "mock-globals", + "mock-registry", + "workspaces/*" + ], + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^9.9.3", + "@npmcli/config": "^10.14.0", + "@npmcli/fs": "^5.0.0", + "@npmcli/map-workspaces": "^5.0.3", + "@npmcli/metavuln-calculator": "^9.0.3", + "@npmcli/package-json": "^7.0.5", + "@npmcli/promise-spawn": "^9.0.1", + "@npmcli/redact": "^4.0.0", + "@npmcli/run-script": "^10.0.4", + "@sigstore/tuf": "^4.0.2", + "abbrev": "^4.0.0", + "archy": "~1.0.0", + "cacache": "^20.0.4", + "chalk": "^5.6.2", + "ci-info": "^4.4.0", + "fastest-levenshtein": "^1.0.16", + "fs-minipass": "^3.0.3", + "glob": "^13.0.6", + "graceful-fs": "^4.2.11", + "hosted-git-info": "^9.0.3", + "ini": "^6.0.0", + "init-package-json": "^8.2.5", + "is-cidr": "^6.0.4", + "json-parse-even-better-errors": "^5.0.0", + "libnpmaccess": "^10.0.3", + "libnpmdiff": "^8.1.14", + "libnpmexec": "^10.3.4", + "libnpmfund": "^7.0.28", + "libnpmorg": "^8.0.1", + "libnpmpack": "^9.1.15", + "libnpmpublish": "^11.2.1", + "libnpmsearch": "^9.0.1", + "libnpmteam": "^8.0.2", + "libnpmversion": "^8.0.4", + "make-fetch-happen": "^15.0.6", + "minimatch": "^10.2.5", + "minipass": "^7.1.3", + "minipass-pipeline": "^1.2.4", + "ms": "^2.1.2", + "node-gyp": "^12.4.0", + "nopt": "^9.0.0", + "npm-audit-report": "^7.0.0", + "npm-install-checks": "^8.0.0", + "npm-package-arg": "^13.0.2", + "npm-pick-manifest": "^11.0.3", + "npm-profile": "^12.0.2", + "npm-registry-fetch": "^19.1.1", + "npm-user-validate": "^4.0.0", + "p-map": "^7.0.4", + "pacote": "^21.5.1", + "parse-conflict-json": "^5.0.1", + "proc-log": "^6.1.0", + "qrcode-terminal": "^0.12.0", + "read": "^5.0.1", + "semver": "^7.8.5", + "spdx-expression-parse": "^4.0.0", + "ssri": "^13.0.1", + "supports-color": "^10.2.2", + "tar": "^7.5.22", + "text-table": "~0.2.0", + "tiny-relative-date": "^2.0.2", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^7.0.2", + "which": "^6.0.1" + }, + "bin": { + "npm": "bin/npm-cli.js", + "npx": "bin/npx-cli.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, "node_modules/npm-run-path": { "version": "6.0.0", "resolved": "https://registry.npmmirror.com/npm-run-path/-/npm-run-path-6.0.0.tgz", @@ -14525,6 +14680,1615 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/npm/node_modules/@gar/promise-retry": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/npm/node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/@npmcli/agent": { + "version": "4.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^11.2.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/arborist": { + "version": "9.9.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^5.0.0", + "@npmcli/installed-package-contents": "^4.0.0", + "@npmcli/map-workspaces": "^5.0.0", + "@npmcli/metavuln-calculator": "^9.0.2", + "@npmcli/name-from-folder": "^4.0.0", + "@npmcli/node-gyp": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/query": "^5.0.0", + "@npmcli/redact": "^4.0.0", + "@npmcli/run-script": "^10.0.0", + "bin-links": "^6.0.0", + "cacache": "^20.0.1", + "common-ancestor-path": "^2.0.0", + "hosted-git-info": "^9.0.0", + "json-stringify-nice": "^1.1.4", + "lru-cache": "^11.2.1", + "minimatch": "^10.0.3", + "nopt": "^9.0.0", + "npm-install-checks": "^8.0.0", + "npm-package-arg": "^13.0.0", + "npm-pick-manifest": "^11.0.1", + "npm-registry-fetch": "^19.0.0", + "pacote": "^21.0.2", + "parse-conflict-json": "^5.0.1", + "proc-log": "^6.0.0", + "proggy": "^4.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^3.0.1", + "semver": "^7.3.7", + "ssri": "^13.0.0", + "treeverse": "^3.0.0", + "walk-up-path": "^4.0.0" + }, + "bin": { + "arborist": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/config": { + "version": "10.14.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/map-workspaces": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "ci-info": "^4.0.0", + "ini": "^6.0.0", + "nopt": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "walk-up-path": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/fs": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/git": { + "version": "7.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "ini": "^6.0.0", + "lru-cache": "^11.2.1", + "npm-pick-manifest": "^11.0.1", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "which": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/installed-package-contents": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^5.0.0", + "npm-normalize-package-bin": "^5.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/map-workspaces": { + "version": "5.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/name-from-folder": "^4.0.0", + "@npmcli/package-json": "^7.0.0", + "glob": "^13.0.0", + "minimatch": "^10.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { + "version": "9.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "cacache": "^20.0.0", + "json-parse-even-better-errors": "^5.0.0", + "pacote": "^21.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/name-from-folder": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/node-gyp": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/package-json": { + "version": "7.0.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^7.0.0", + "glob": "^13.0.0", + "hosted-git-info": "^9.0.0", + "json-parse-even-better-errors": "^5.0.0", + "proc-log": "^6.0.0", + "semver": "^7.5.3", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/promise-spawn": { + "version": "9.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "which": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/query": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/redact": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@npmcli/run-script": { + "version": "10.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/node-gyp": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "node-gyp": "^12.1.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/bundle": { + "version": "4.0.0", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.5.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/core": { + "version": "3.2.1", + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/protobuf-specs": { + "version": "0.5.1", + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, + "node_modules/npm/node_modules/@sigstore/sign": { + "version": "4.1.1", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@gar/promise-retry": "^1.0.2", + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.2.0", + "@sigstore/protobuf-specs": "^0.5.0", + "make-fetch-happen": "^15.0.4", + "proc-log": "^6.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/tuf": { + "version": "4.0.2", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.5.0", + "tuf-js": "^4.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@sigstore/verify": { + "version": "3.1.1", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.2.1", + "@sigstore/protobuf-specs": "^0.5.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@tufjs/models": { + "version": "4.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^10.1.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/abbrev": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/agent-base": { + "version": "7.1.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/aproba": { + "version": "2.1.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/archy": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/balanced-match": { + "version": "4.0.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/npm/node_modules/bin-links": { + "version": "6.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "cmd-shim": "^8.0.0", + "npm-normalize-package-bin": "^5.0.0", + "proc-log": "^6.0.0", + "read-cmd-shim": "^6.0.0", + "write-file-atomic": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/binary-extensions": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=18.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/brace-expansion": { + "version": "5.0.12", + "inBundle": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/npm/node_modules/cacache": { + "version": "20.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/fs": "^5.0.0", + "fs-minipass": "^3.0.0", + "glob": "^13.0.0", + "lru-cache": "^11.1.0", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^7.0.2", + "ssri": "^13.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/chalk": { + "version": "5.6.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm/node_modules/chownr": { + "version": "3.0.0", + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/ci-info": { + "version": "4.4.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/cidr-regex": { + "version": "5.0.5", + "inBundle": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/npm/node_modules/cmd-shim": { + "version": "8.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/common-ancestor-path": { + "version": "2.0.0", + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">= 18" + } + }, + "node_modules/npm/node_modules/cssesc": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/debug": { + "version": "4.4.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/diff": { + "version": "8.0.4", + "inBundle": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/npm/node_modules/env-paths": { + "version": "2.2.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/npm/node_modules/exponential-backoff": { + "version": "3.1.3", + "inBundle": true, + "license": "Apache-2.0" + }, + "node_modules/npm/node_modules/fastest-levenshtein": { + "version": "1.0.16", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 4.9.1" + } + }, + "node_modules/npm/node_modules/fs-minipass": { + "version": "3.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/glob": { + "version": "13.0.6", + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/graceful-fs": { + "version": "4.2.11", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/hosted-git-info": { + "version": "9.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "lru-cache": "^11.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/http-cache-semantics": { + "version": "4.3.0", + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npm/node_modules/http-proxy-agent": { + "version": "7.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/https-proxy-agent": { + "version": "7.0.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/iconv-lite": { + "version": "0.7.2", + "inBundle": true, + "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/npm/node_modules/ignore-walk": { + "version": "8.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minimatch": "^10.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/ini": { + "version": "6.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/init-package-json": { + "version": "8.2.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/package-json": "^7.0.0", + "npm-package-arg": "^13.0.0", + "promzard": "^3.0.1", + "read": "^5.0.1", + "semver": "^7.7.2", + "validate-npm-package-name": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/ip-address": { + "version": "10.7.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/npm/node_modules/is-cidr": { + "version": "6.0.4", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "cidr-regex": "^5.0.4" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/npm/node_modules/isexe": { + "version": "4.0.0", + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/npm/node_modules/json-parse-even-better-errors": { + "version": "5.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/json-stringify-nice": { + "version": "1.1.4", + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/jsonparse": { + "version": "1.3.1", + "engines": [ + "node >= 0.2.0" + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff": { + "version": "6.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/just-diff-apply": { + "version": "5.5.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/libnpmaccess": { + "version": "10.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-package-arg": "^13.0.0", + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmdiff": { + "version": "8.1.14", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^9.9.3", + "@npmcli/installed-package-contents": "^4.0.0", + "binary-extensions": "^3.0.0", + "diff": "^8.0.2", + "minimatch": "^10.0.3", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2", + "tar": "^7.5.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmexec": { + "version": "10.3.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/arborist": "^9.9.3", + "@npmcli/package-json": "^7.0.0", + "@npmcli/run-script": "^10.0.0", + "ci-info": "^4.0.0", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2", + "proc-log": "^6.0.0", + "read": "^5.0.1", + "semver": "^7.3.7", + "signal-exit": "^4.1.0", + "walk-up-path": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmfund": { + "version": "7.0.28", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^9.9.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmorg": { + "version": "8.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmpack": { + "version": "9.1.15", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^9.9.3", + "@npmcli/run-script": "^10.0.0", + "npm-package-arg": "^13.0.0", + "pacote": "^21.0.2" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmpublish": { + "version": "11.2.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/package-json": "^7.0.0", + "ci-info": "^4.0.0", + "npm-package-arg": "^13.0.0", + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.7", + "sigstore": "^4.0.0", + "ssri": "^13.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmsearch": { + "version": "9.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmteam": { + "version": "8.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^19.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/libnpmversion": { + "version": "8.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^7.0.0", + "@npmcli/run-script": "^10.0.0", + "json-parse-even-better-errors": "^5.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.7" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/lru-cache": { + "version": "11.5.1", + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/npm/node_modules/make-fetch-happen": { + "version": "15.0.6", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/agent": "^4.0.0", + "@npmcli/redact": "^4.0.0", + "cacache": "^20.0.1", + "http-cache-semantics": "^4.1.1", + "minipass": "^7.0.2", + "minipass-fetch": "^5.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^1.0.0", + "proc-log": "^6.0.0", + "ssri": "^13.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/minimatch": { + "version": "10.2.5", + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/minipass": { + "version": "7.1.3", + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-collect": { + "version": "2.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-fetch": { + "version": "5.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^2.0.0", + "minizlib": "^3.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + }, + "optionalDependencies": { + "iconv-lite": "^0.7.2" + } + }, + "node_modules/npm/node_modules/minipass-flush": { + "version": "1.0.6", + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minipass": "^7.1.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/npm/node_modules/minipass-pipeline": { + "version": "1.2.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "inBundle": true, + "license": "ISC", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minipass-pipeline/node_modules/yallist": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/npm/node_modules/minipass-sized": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/minizlib": { + "version": "3.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "minipass": "^7.1.2" + }, + "engines": { + "node": ">= 18" + } + }, + "node_modules/npm/node_modules/ms": { + "version": "2.1.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/mute-stream": { + "version": "3.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/negotiator": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/npm/node_modules/node-gyp": { + "version": "12.4.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "graceful-fs": "^4.2.6", + "nopt": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "tar": "^7.5.4", + "tinyglobby": "^0.2.12", + "undici": "^6.25.0", + "which": "^6.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/nopt": { + "version": "9.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "abbrev": "^4.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-audit-report": { + "version": "7.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-bundled": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-normalize-package-bin": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-install-checks": { + "version": "8.0.0", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-normalize-package-bin": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-package-arg": { + "version": "13.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "hosted-git-info": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^7.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-packlist": { + "version": "10.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "ignore-walk": "^8.0.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-pick-manifest": { + "version": "11.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-install-checks": "^8.0.0", + "npm-normalize-package-bin": "^5.0.0", + "npm-package-arg": "^13.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-profile": { + "version": "12.0.2", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.1.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-registry-fetch": { + "version": "19.1.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/redact": "^4.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^15.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^5.0.0", + "minizlib": "^3.0.1", + "npm-package-arg": "^13.0.0", + "proc-log": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/npm-user-validate": { + "version": "4.0.0", + "inBundle": true, + "license": "BSD-2-Clause", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/p-map": { + "version": "7.0.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm/node_modules/pacote": { + "version": "21.5.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/git": "^7.0.0", + "@npmcli/installed-package-contents": "^4.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "@npmcli/run-script": "^10.0.0", + "cacache": "^20.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^13.0.0", + "npm-packlist": "^10.0.1", + "npm-pick-manifest": "^11.0.1", + "npm-registry-fetch": "^19.0.0", + "proc-log": "^6.0.0", + "sigstore": "^4.0.0", + "ssri": "^13.0.0", + "tar": "^7.4.3" + }, + "bin": { + "pacote": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/parse-conflict-json": { + "version": "5.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^5.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/path-scurry": { + "version": "2.0.2", + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/postcss-selector-parser": { + "version": "7.1.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/proc-log": { + "version": "6.1.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/proggy": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/promise-all-reject-late": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promise-call-limit": { + "version": "3.0.2", + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/promzard": { + "version": "3.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "read": "^5.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/qrcode-terminal": { + "version": "0.12.0", + "inBundle": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/npm/node_modules/read": { + "version": "5.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "mute-stream": "^3.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/read-cmd-shim": { + "version": "6.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/safer-buffer": { + "version": "2.1.2", + "inBundle": true, + "license": "MIT", + "optional": true + }, + "node_modules/npm/node_modules/semver": { + "version": "7.8.5", + "inBundle": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm/node_modules/signal-exit": { + "version": "4.1.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/npm/node_modules/sigstore": { + "version": "4.1.1", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/bundle": "^4.0.0", + "@sigstore/core": "^3.2.1", + "@sigstore/protobuf-specs": "^0.5.0", + "@sigstore/sign": "^4.1.1", + "@sigstore/tuf": "^4.0.2", + "@sigstore/verify": "^3.1.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/smart-buffer": { + "version": "4.2.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks": { + "version": "2.8.9", + "inBundle": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/npm/node_modules/socks-proxy-agent": { + "version": "8.0.5", + "inBundle": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "^4.3.4", + "socks": "^2.8.3" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/npm/node_modules/spdx-exceptions": { + "version": "2.5.0", + "inBundle": true, + "license": "CC-BY-3.0" + }, + "node_modules/npm/node_modules/spdx-expression-parse": { + "version": "4.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/npm/node_modules/spdx-license-ids": { + "version": "3.0.23", + "inBundle": true, + "license": "CC0-1.0" + }, + "node_modules/npm/node_modules/ssri": { + "version": "13.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/supports-color": { + "version": "10.2.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/npm/node_modules/tar": { + "version": "7.5.22", + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/npm/node_modules/text-table": { + "version": "0.2.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tiny-relative-date": { + "version": "2.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/tinyglobby": { + "version": "0.2.17", + "inBundle": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/npm/node_modules/tinyglobby/node_modules/fdir": { + "version": "6.5.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/npm/node_modules/tinyglobby/node_modules/picomatch": { + "version": "4.0.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/npm/node_modules/treeverse": { + "version": "3.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/tuf-js": { + "version": "4.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "@tufjs/models": "4.1.0", + "debug": "^4.4.3", + "make-fetch-happen": "^15.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/undici": { + "version": "6.29.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=18.17" + } + }, + "node_modules/npm/node_modules/util-deprecate": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/validate-npm-package-name": { + "version": "7.0.2", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/walk-up-path": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/npm/node_modules/which": { + "version": "6.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/write-file-atomic": { + "version": "7.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "signal-exit": "^4.0.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/npm/node_modules/yallist": { + "version": "5.0.0", + "inBundle": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz", @@ -17613,6 +19377,7 @@ "version": "0.1.0", "license": "MIT", "dependencies": { + "npm": "11.21.1", "pnpm": "10.34.5", "semver": "7.8.5", "yaml": "2.9.0" diff --git a/package.json b/package.json index 504096c38..d345b7c05 100644 --- a/package.json +++ b/package.json @@ -286,6 +286,7 @@ "dsh-ppt": "file:packages/ppt-runtime/core", "dsh-ppt-composer": "file:packages/ppt-runtime/adapter", "electron-updater": "^6.8.9", + "npm": "11.21.1", "pnpm": "10.34.5", "qrcode": "^1.5.4", "react": "18.3.1", diff --git a/packages/dsh-desktop-market-installer/package.json b/packages/dsh-desktop-market-installer/package.json index a0bf9bb7c..0c10a1a71 100644 --- a/packages/dsh-desktop-market-installer/package.json +++ b/packages/dsh-desktop-market-installer/package.json @@ -54,6 +54,7 @@ "@deepseek-ai/dsh-host-webserver": "^0.1.5-rc.1 || ^0.1.6-alpha.1 || ^0.1.7-rc.1 || ^0.1.7-rc.2 || ^0.2.0-rc.1 || ^0.2.1-rc.1" }, "dependencies": { + "npm": "11.21.1", "pnpm": "10.34.5", "semver": "7.8.5", "yaml": "2.9.0" diff --git a/packages/dsh-desktop-market-installer/pnpm-runner.mjs b/packages/dsh-desktop-market-installer/pnpm-runner.mjs index b8a237829..52724eb0c 100644 --- a/packages/dsh-desktop-market-installer/pnpm-runner.mjs +++ b/packages/dsh-desktop-market-installer/pnpm-runner.mjs @@ -27,7 +27,8 @@ import { spawn } from 'node:child_process' import { existsSync, realpathSync, watch } from 'node:fs' import { readFile, readdir, rename, rm, writeFile } from 'node:fs/promises' -import { join } from 'node:path' +import { dirname, join } from 'node:path' +import { createRequire } from 'node:module' import { fileURLToPath } from 'node:url' import { hideConsoleImportArguments } from './windows-hide-console.mjs' @@ -310,17 +311,35 @@ export async function suspendGenerationProjectionForPnpm(profileDirectory) { } /** - * Arguments for one pnpm process. On Windows the console-hide bootstrap is - * loaded first, so `pnpm view`'s passthrough to `npm.cmd` inherits a hidden - * console. The path is read from this process, not the child environment: - * the shim restores it after Harness scrubs `DSH_*` names. + * Arguments for a packaged package-manager process. pnpm 10 forwards metadata + * queries to PATH npm, which a Desktop installation does not supply. Run the + * installation-owned npm CLI with the same Node executable instead, retaining + * npm's registry/auth/proxy configuration and JSON/error semantics. The pnpm + * entry is the installation anchor even when this runner is staged in a Profile. + * Other commands retain pnpm's mutation and recovery behavior. + * On Windows the shim restores the console-hide bootstrap after env scrubbing. * @param {readonly string[]} args - pnpm entry and its own arguments. * @param {NodeJS.ProcessEnv} [env] * @param {NodeJS.Platform} [platform] * @returns {string[]} */ export function pnpmLaunchArguments(args, env = process.env, platform = process.platform) { - return [...hideConsoleImportArguments(env, platform), ...args] + const [pnpmEntry, command, ...queryArgs] = args + if (!['view', 'info', 'show', 'v'].includes(command)) { + return [...hideConsoleImportArguments(env, platform), ...args] + } + let npmEntry + try { + const manifest = createRequire(pnpmEntry).resolve('npm/package.json') + npmEntry = join(dirname(manifest), 'bin', 'npm-cli.js') + if (!existsSync(npmEntry)) throw new Error('npm CLI entry is missing') + } catch (cause) { + throw new Error('Desktop bundled npm query runtime is unavailable; repair or reinstall the application.', { cause }) + } + // Harness passes pnpm's --config.fetch-retries=0 spelling. npm uses the + // unprefixed key; keep all other values and arguments as separate argv items. + const translated = queryArgs.map(argument => argument.replace(/^--config\./u, '--')) + return [...hideConsoleImportArguments(env, platform), npmEntry, command, ...translated] } /** diff --git a/scripts/verify-packaged-harness.cjs b/scripts/verify-packaged-harness.cjs index 45bdff171..35447e7d2 100644 --- a/scripts/verify-packaged-harness.cjs +++ b/scripts/verify-packaged-harness.cjs @@ -2,6 +2,7 @@ const fs = require('node:fs') const fsp = require('node:fs/promises') const path = require('node:path') const os = require('node:os') +const { createServer } = require('node:http') const { createRequire } = require('node:module') const { execFile, spawn } = require('node:child_process') const { promisify } = require('node:util') @@ -135,8 +136,52 @@ async function verifyHarness(appRoot, resources, executable) { } } +/** Exercise the installed query closure without a system npm, node, or registry. */ +async function verifyPackageQuery(appRoot, executable) { + const home = await fsp.realpath(await fsp.mkdtemp(path.join(os.tmpdir(), 'dsh packaged query '))) + const server = createServer((request, response) => { + if (request.url !== '/dsh-packaged-query-probe') { + response.writeHead(404, { 'content-type': 'application/json' }) + response.end(JSON.stringify({ error: 'not_found' })) + return + } + response.setHeader('content-type', 'application/json') + response.end(JSON.stringify({ name: 'dsh-packaged-query-probe', 'dist-tags': { latest: '1.2.3' }, + versions: { '1.2.3': { name: 'dsh-packaged-query-probe', version: '1.2.3' } } })) + }) + try { + await new Promise((resolve, reject) => { + server.once('error', reject) + server.listen(0, '127.0.0.1', resolve) + }) + const registry = 'http://127.0.0.1:' + const address = server.address() + if (address === null || typeof address === 'string') throw new Error('Package query registry did not bind') + const userconfig = path.join(home, 'user.npmrc') + const globalconfig = path.join(home, 'global.npmrc') + await fsp.writeFile(userconfig, '') + await fsp.writeFile(globalconfig, '') + const env = Object.fromEntries(Object.entries(process.env).filter(([key]) => + !/^(path|node_options|node_path|corepack_.*|npm_config_.*|pnpm_.*|.*_proxy)$/iu.test(key))) + Object.assign(env, { PATH: home, ELECTRON_RUN_AS_NODE: '1', HOME: home, USERPROFILE: home, + NPM_CONFIG_USERCONFIG: userconfig, NPM_CONFIG_GLOBALCONFIG: globalconfig, + NPM_CONFIG_CACHE: path.join(home, 'cache'), NPM_CONFIG_UPDATE_NOTIFIER: 'false' }) + const runner = path.join(appRoot, 'node_modules', 'dsh-desktop-market-installer', 'pnpm-runner.mjs') + const pnpm = path.join(appRoot, 'node_modules', 'pnpm', 'bin', 'pnpm.cjs') + const { stdout } = await promisify(execFile)(executable, [runner, pnpm, 'view', + 'dsh-packaged-query-probe', 'version', '--json', '--registry=' + registry + address.port, + '--config.fetch-retries=0'], { cwd: home, env, windowsHide: true, timeout: 20_000 }) + if (JSON.parse(stdout) !== '1.2.3') throw new Error('Packaged plugin query returned unexpected metadata') + } finally { + server.closeAllConnections() + await new Promise(resolve => server.close(resolve)) + await fsp.rm(home, { recursive: true, force: true, maxRetries: 5, retryDelay: 100 }) + } +} + async function verifyRuntime(appRoot, resources, executable) { const count = verifyDependencyClosure(appRoot) + await verifyPackageQuery(appRoot, executable) await verifyTerminal(appRoot) await verifyHarness(appRoot, resources, executable) console.log(`Packaged Harness, bootstrap, native modules, terminal and ${count} dependency manifests passed`) @@ -162,7 +207,7 @@ async function verifyPackagedHarness(context) { throw error } } -module.exports = { verifyDependencyClosure, verifyTerminal, verifyHarness, verifyPackagedHarness } +module.exports = { verifyDependencyClosure, verifyPackageQuery, verifyTerminal, verifyHarness, verifyPackagedHarness } if (require.main === module && process.argv[2] === '--verify-runtime') { const [appRoot, resources, ...executableParts] = process.argv.slice(3) const executable = executableParts.length ? executableParts.join(' ') : process.execPath diff --git a/test/packaged-plugin-query.test.mjs b/test/packaged-plugin-query.test.mjs new file mode 100644 index 000000000..6f386efdd --- /dev/null +++ b/test/packaged-plugin-query.test.mjs @@ -0,0 +1,184 @@ +import { spawn } from 'node:child_process' +import { once } from 'node:events' +import { copyFile, mkdir, mkdtemp, realpath, rm, writeFile } from 'node:fs/promises' +import { createServer } from 'node:http' +import { createRequire } from 'node:module' +import { tmpdir } from 'node:os' +import { dirname, join } from 'node:path' +import { fileURLToPath } from 'node:url' +import { describe, expect, it } from 'vitest' +import { pnpmLaunchArguments } from '../packages/dsh-desktop-market-installer/pnpm-runner.mjs' + +const require = createRequire(import.meta.url) +const pnpmEntry = join(dirname(require.resolve('pnpm')), 'bin', 'pnpm.cjs') +const npmEntry = join(dirname(createRequire(pnpmEntry).resolve('npm/package.json')), 'bin', 'npm-cli.js') +const runner = fileURLToPath(new URL('../packages/dsh-desktop-market-installer/pnpm-runner.mjs', import.meta.url)) +const packageName = '@query-fixture/plugin' +const fixtureToken = 'local-registry-fixture-token' + +function isolatedEnvironment(root) { + // Windows treats env keys case-insensitively. Remove every spelling before + // supplying our own paths so no developer config, credential or npm shim leaks in. + const env = Object.fromEntries(Object.entries(process.env).filter(([key]) => + !/^(?:path|node_options|node_path|home|userprofile|appdata|localappdata|xdg_config_home|npm_config_.*|pnpm_.*|corepack_.*|.*_proxy|dsh_desktop_.*)$/iu.test(key))) + return { + ...env, + PATH: '', + HOME: join(root, 'home'), + USERPROFILE: join(root, 'home'), + APPDATA: join(root, 'home'), + LOCALAPPDATA: join(root, 'home'), + XDG_CONFIG_HOME: join(root, 'home'), + npm_config_userconfig: join(root, 'home', '.npmrc'), + npm_config_globalconfig: join(root, 'global.npmrc'), + npm_config_cache: join(root, 'cache'), + npm_config_update_notifier: 'false', + npm_config_audit: 'false', + npm_config_fund: 'false', + // Electron is also a supported Desktop Node executable. + ELECTRON_RUN_AS_NODE: '1' + } +} + +function runChild(args, cwd, env) { + // Keep the event loop free: this same process serves the fake registry. + return new Promise((resolve, reject) => { + const child = spawn(process.execPath, args, { + cwd, env, windowsHide: true, stdio: ['ignore', 'pipe', 'pipe'], timeout: 20_000 + }) + let stdout = '' + let stderr = '' + child.stdout.setEncoding('utf8').on('data', chunk => { stdout += chunk }) + child.stderr.setEncoding('utf8').on('data', chunk => { stderr += chunk }) + child.once('error', reject) + child.once('close', (code, signal) => resolve({ code, signal, stdout, stderr })) + }) +} + +describe('packaged plugin metadata queries', () => { + it.each(['view', 'info', 'show', 'v'])('dispatches %s to installation-owned npm and translates config flags', command => { + const query = [packageName, 'peerDependencies', '--json', '--config.fetch-retries=0', + '--config.registry=http://127.0.0.1:12345/registry/', '--config.tag=tag=with=equals'] + const original = [pnpmEntry, command, ...query] + expect(pnpmLaunchArguments(original, {}, 'linux')).toEqual([ + npmEntry, command, packageName, 'peerDependencies', '--json', '--fetch-retries=0', + '--registry=http://127.0.0.1:12345/registry/', '--tag=tag=with=equals' + ]) + expect(original).toEqual([pnpmEntry, command, ...query]) + }) + + it('keeps add and its pnpm-specific arguments unchanged on every platform', () => { + const args = [pnpmEntry, 'add', `${packageName}@^1.0.0`, '--config.fetch-retries=0', '--ignore-scripts'] + for (const platform of ['linux', 'darwin', 'win32']) { + expect(pnpmLaunchArguments(args, {}, platform)).toEqual(args) + } + }) + + it('reports missing installation-owned npm instead of falling back to the system', async () => { + const root = await mkdtemp(join(tmpdir(), 'dsh missing query runtime ')) + try { + const missingPnpm = join(root, 'node_modules', 'pnpm', 'bin', 'pnpm.cjs') + expect(() => pnpmLaunchArguments([missingPnpm, 'view', 'dshmarket'], {}, 'win32')) + .toThrow('Desktop bundled npm query runtime is unavailable') + } finally { await rm(root, { recursive: true, force: true }) } + }) + + it('queries a local authenticated scoped registry without PATH npm, preserving JSON and errors', async () => { + const root = await realpath(await mkdtemp(join(tmpdir(), 'dsh packaged query '))) + const requests = [] + const versions = Object.fromEntries(['1.0.0', '1.2.0', '2.0.0'].map(version => [version, { + name: packageName, version, + description: 'Local plugin metadata fixture', + peerDependencies: { '@deepseek-ai/dsh': '^0.2.0' }, + dsh: { bundle: { patch: 'cordis.patch.yml' } } + }])) + const packument = { + name: packageName, 'dist-tags': { latest: '2.0.0' }, versions + } + const server = createServer((request, response) => { + const path = decodeURIComponent(new URL(request.url, 'http://127.0.0.1').pathname) + requests.push({ path, authorization: request.headers.authorization }) + response.setHeader('content-type', 'application/json') + if (path === `/scoped/${packageName}`) { + if (request.headers.authorization !== `Bearer ${fixtureToken}`) { + response.writeHead(401) + response.end(JSON.stringify({ error: 'Fixture authentication required' })) + return + } + response.end(JSON.stringify(packument)) + } else { + response.writeHead(404) + response.end(JSON.stringify({ error: 'Fixture package not found' })) + } + }) + try { + server.listen(0, '127.0.0.1') + await once(server, 'listening') + const registry = `http://127.0.0.1:${server.address().port}` + await mkdir(join(root, 'home')) + await writeFile(join(root, 'package.json'), '{}') + await writeFile(join(root, 'global.npmrc'), '') + await writeFile(join(root, 'home', '.npmrc'), [ + `registry=${registry}/default/`, + `@query-fixture:registry=${registry}/scoped/`, + `//127.0.0.1:${server.address().port}/scoped/:_authToken=${fixtureToken}`, + '' + ].join('\n')) + // The real shim runs a staged copy. A Profile-owned npm must not shadow + // the query runtime beside the installation's absolute pnpm entry. + const staged = join(root, '.desktop-bin') + await mkdir(staged) + for (const file of ['pnpm-runner.mjs', 'windows-hide-console.mjs']) { + await copyFile(join(dirname(runner), file), join(staged, file)) + } + const profileNpm = join(root, 'node_modules', 'npm') + await mkdir(join(profileNpm, 'bin'), { recursive: true }) + await writeFile(join(profileNpm, 'package.json'), JSON.stringify({ name: 'npm', exports: { './package.json': './package.json' } })) + await writeFile(join(profileNpm, 'bin', 'npm-cli.js'), 'throw new Error("Profile npm must not execute")') + const env = isolatedEnvironment(root) + const config = [`--config.registry=${registry}/default/`, '--config.fetch-retries=0', + '--config.fetch-timeout=5000', '--config.update-notifier=false'] + const query = args => runChild([join(staged, 'pnpm-runner.mjs'), pnpmEntry, ...args, ...config], root, env) + + // Negative control reproduces pnpm 10's delegation to an absent PATH npm, + // under exactly the environment and arguments the fixed runner handles. + const legacy = await runChild([pnpmEntry, 'view', `${packageName}@1.2.0`, '--json', ...config], root, env) + expect(legacy.signal).toBeNull() + expect(legacy.code).not.toBe(0) + expect(`${legacy.stdout}\n${legacy.stderr}`).toMatch(/spawn(?:Sync)? npm(?:\.cmd)? ENOENT/iu) + expect(requests).toEqual([]) + + const full = await query(['view', `${packageName}@1.2.0`, '--json']) + expect(full.signal).toBeNull() + expect(full.code, full.stderr).toBe(0) + expect(JSON.parse(full.stdout)).toMatchObject(versions['1.2.0']) + + const fields = await query(['info', `${packageName}@1.2.0`, 'version', 'peerDependencies', 'dsh', '--json']) + expect(fields.code, fields.stderr).toBe(0) + expect(JSON.parse(fields.stdout)).toEqual({ + version: '1.2.0', peerDependencies: versions['1.2.0'].peerDependencies, dsh: versions['1.2.0'].dsh + }) + + const range = await query(['show', `${packageName}@^1.0.0`, 'version', '--json']) + expect(range.code, range.stderr).toBe(0) + expect(JSON.parse(range.stdout)).toEqual(['1.0.0', '1.2.0']) + + const latest = await query(['v', packageName, 'version', '--json']) + expect(latest.code, latest.stderr).toBe(0) + expect(JSON.parse(latest.stdout)).toBe('2.0.0') + + const missing = await query(['view', '@query-fixture/missing', '--json']) + expect(missing.signal).toBeNull() + expect(missing.code).not.toBe(0) + expect(JSON.parse(missing.stdout).error.code).toBe('E404') + expect(missing.stderr).toContain('E404') + expect(requests.length).toBeGreaterThanOrEqual(5) + expect(requests.every(request => request.path.startsWith('/scoped/@query-fixture/'))).toBe(true) + expect(requests.every(request => request.authorization === `Bearer ${fixtureToken}`)).toBe(true) + expect(requests.some(request => request.path === '/scoped/@query-fixture/missing')).toBe(true) + } finally { + await new Promise((resolve, reject) => server.close(error => error ? reject(error) : resolve())) + await rm(root, { recursive: true, force: true }) + } + }, 60_000) +}) diff --git a/test/windows-hide-console.test.ts b/test/windows-hide-console.test.ts index 859effa74..28b3c21dc 100644 --- a/test/windows-hide-console.test.ts +++ b/test/windows-hide-console.test.ts @@ -2,7 +2,7 @@ import { spawnSync } from 'node:child_process' import { mkdtempSync, writeFileSync } from 'node:fs' import { createRequire } from 'node:module' import { tmpdir } from 'node:os' -import { join } from 'node:path' +import { dirname, join } from 'node:path' import { pathToFileURL } from 'node:url' import { describe, expect, it } from 'vitest' import { installPnpmArguments } from 'dsh-desktop-market-installer/generations/installer' @@ -31,16 +31,19 @@ describe('windows console hide launch arguments', () => { ) }) - it('loads the bootstrap through a file URL before pnpm on Windows', () => { + it('loads the bootstrap through a file URL before the bundled metadata CLI on Windows', () => { const dir = mkdtempSync(join(tmpdir(), 'dsh-console-hide-')) const path = join(dir, 'windows-hide-console-import.mjs') writeFileSync(path, '') const env = { [HIDE_CONSOLE_BOOTSTRAP_ENV]: path } expect(hideConsoleImportArguments(env, 'win32')).toEqual(['--import', pathToFileURL(path).href]) - expect(pnpmLaunchArguments(['pnpm.cjs', 'view', 'dshmarket@^1.65.1'], env, 'win32')).toEqual([ + const require = createRequire(import.meta.url) + const pnpm = join(dirname(require.resolve('pnpm')), 'bin', 'pnpm.cjs') + const npm = join(dirname(require.resolve('npm/package.json')), 'bin', 'npm-cli.js') + expect(pnpmLaunchArguments([pnpm, 'view', 'dshmarket@^1.65.1'], env, 'win32')).toEqual([ '--import', pathToFileURL(path).href, - 'pnpm.cjs', + npm, 'view', 'dshmarket@^1.65.1' ]) diff --git a/vitest.windows.config.ts b/vitest.windows.config.ts index e3b4e2aa7..3a9deb5bd 100644 --- a/vitest.windows.config.ts +++ b/vitest.windows.config.ts @@ -32,6 +32,7 @@ export default defineConfig({ 'test/migration-failure-paths.test.ts', 'test/legacy-preset-migration.test.ts', 'test/pnpm-runner.test.js', + 'test/packaged-plugin-query.test.mjs', 'test/local-path-links.test.ts', 'test/office-engine-resolution.test.ts', 'test/remove-tree.test.ts',