diff --git a/deps/npm/AUTHORS b/deps/npm/AUTHORS index 4209517f2a0ff8..c0986e8be2bf90 100644 --- a/deps/npm/AUTHORS +++ b/deps/npm/AUTHORS @@ -730,3 +730,6 @@ Michele Azzolari foxxyz Dr Jan Tojnar +Jason Attwood +Vlad GURDIGA +Sébastien Puech diff --git a/deps/npm/CHANGELOG.md b/deps/npm/CHANGELOG.md index 49d44ab10a09e0..8cafde1158491d 100644 --- a/deps/npm/CHANGELOG.md +++ b/deps/npm/CHANGELOG.md @@ -1,3 +1,115 @@ +## 7.0.11 (2020-11-13) + +### DEPENDENCIES + +* [`629a667a9`](https://github.com/npm/cli/commit/629a667a9b30b0b870075da965606979622a5e2e) + `eslint@7.13.0` +* [`de9891bd2`](https://github.com/npm/cli/commit/de9891bd2a16fe890ff5cfb140c7b1209aeac0de) + `eslint-plugin-standard@4.1.0` +* [`c3e7aa31c`](https://github.com/npm/cli/commit/c3e7aa31c565dfe21cd1f55a8433bfbcf58aa289) + [#2123](https://github.com/npm/cli/issues/2123) + [#1957](https://github.com/npm/cli/issues/1957) + `@npmcli/arborist@1.0.11` + +### BUG FIXES + +* [`a8aa38513`](https://github.com/npm/cli/commit/a8aa38513ad5c4ad44e6bb3e1499bfc40c31e213) + [#2134](https://github.com/npm/cli/issues/2134) + [#2156](https://github.com/npm/cli/issues/2156) + Fix `cannot read property length of undefined` in `ERESOLVE` explanation code + ([@isaacs](https://github.com/isaacs)) +* [`1dbf0f9bb`](https://github.com/npm/cli/commit/1dbf0f9bb26ba70f4c6d0a807701d7652c31d7d4) + [#2150](https://github.com/npm/cli/issues/2150) + [#2155](https://github.com/npm/cli/issues/2155) + send json errors to stderr, not stdout + ([@isaacs](https://github.com/isaacs)) +* [`fd1d7a21b`](https://github.com/npm/cli/commit/fd1d7a21b247bb35d112c51ff8d8a06fd83c8b44) + [#1927](https://github.com/npm/cli/issues/1927) + [#2154](https://github.com/npm/cli/issues/2154) + Set process.title a bit more usefully + ([@isaacs](https://github.com/isaacs)) +* [`2a80c67ef`](https://github.com/npm/cli/commit/2a80c67ef8c12c3d9d254f5be6293a6461067d99) + [#2008](https://github.com/npm/cli/issues/2008) + [#2153](https://github.com/npm/cli/issues/2153) + Support legacy auth tokens for registries that use them + ([@ruyadorno](https://github.com/ruyadorno)) +* [`786e36404`](https://github.com/npm/cli/commit/786e36404068fd51657ddac766e066a98754edbf) + [#2017](https://github.com/npm/cli/issues/2017) + [#2159](https://github.com/npm/cli/issues/2159) + pass all options to Arborist for `npm ci` + ([@darcyclarke](https://github.com/darcyclarke)) +* [`b47ada7d1`](https://github.com/npm/cli/commit/b47ada7d1623e9ee586ee0cf781ee3ac5ea3c223) + [#2161](https://github.com/npm/cli/issues/2161) + fixed typo + ([@scarabedore](https://github.com/scarabedore)) + +## 7.0.10 (2020-11-10) + +### DOCUMENTATION + +* [`e48badb03`](https://github.com/npm/cli/commit/e48badb03058286a557584d7319db4143049cc6b) + [#2148](https://github.com/npm/cli/issues/2148) + Fix link in documentation + ([@gurdiga](https://github.com/gurdiga)) + +### BUG FIXES + +* [`8edbbdc70`](https://github.com/npm/cli/commit/8edbbdc706694fa32f52d0991c76ae9f207b7bbc) + [#1972](https://github.com/npm/cli/issues/1972) + Support exec auto pick bin when all bin is alias + ([@dr-js](https://github.com/dr-js)) + +### DEPENDENCIES + +* [`04a3e8c10`](https://github.com/npm/cli/commit/04a3e8c10c3f38e1c7a35976d77c2929bdc39868) + [#1962](https://github.com/npm/cli/issues/1962) + `@npmcli/arborist@1.0.10`: + * prevent self-assignment of parent/fsParent + * Support update options in global package space + +## 7.0.9 (2020-11-06) + +### BUG FIXES + +* [`96a0d2802`](https://github.com/npm/cli/commit/96a0d2802d3e619c6ea47290f5c460edfe94070a) + default the 'start' script when server.js present + ([@isaacs](https://github.com/isaacs)) +* [`7716e423e`](https://github.com/npm/cli/commit/7716e423ee92a81730c0dfe5b9ecb4bb41a3f947) + [#2075](https://github.com/npm/cli/issues/2075) + [#2071](https://github.com/npm/cli/issues/2071) print the registry when + using 'npm login' ([@Wicked7000](https://github.com/Wicked7000)) +* [`7046fe10c`](https://github.com/npm/cli/commit/7046fe10c5035ac57246a31ca8a6b09e3f5562bf) + [#2122](https://github.com/npm/cli/issues/2122) tests for `npm cache` + command ([@nlf](https://github.com/nlf)) + +### DEPENDENCIES + +* [`74325f53b`](https://github.com/npm/cli/commit/74325f53b9d813b0e42203c037189418fad2f64a) + [#2124](https://github.com/npm/cli/issues/2124) + `@npmcli/run-script@1.7.5`: + * Export the `isServerPackage` method + * Proxy signals to and from foreground child processes +* [`0e58e6f6b`](https://github.com/npm/cli/commit/0e58e6f6b8f0cd62294642a502c17561aaf46553) + [#1984](https://github.com/npm/cli/issues/1984) + [#2079](https://github.com/npm/cli/issues/2079) + [#1923](https://github.com/npm/cli/issues/1923) + [#606](https://github.com/npm/cli/issues/606) + [#2031](https://github.com/npm/cli/issues/2031) `@npmcli/arborist@1.0.9`: + * Process deps for all link nodes + * Use junctions instead of symlinks + * Use @npmcli/move-file instead of fs.rename +* [`1dad328a1`](https://github.com/npm/cli/commit/1dad328a17d93def7799545596b4eba9833b35aa) + [#1865](https://github.com/npm/cli/issues/1865) + [#2106](https://github.com/npm/cli/issues/2106) + [#2084](https://github.com/npm/cli/issues/2084) `pacote@11.1.13`: + * Properly set the installation command for `prepare` scripts when + installing git/dir deps +* [`e090d706c`](https://github.com/npm/cli/commit/e090d706ca637d4df96d28bff1660590aa3f3b62) + [#2097](https://github.com/npm/cli/issues/2097) `libnpmversion@1.0.7`: + * Do not crash when the package.json file lacks a 'version' field +* [`8fa541a10`](https://github.com/npm/cli/commit/8fa541a10dbdc09376175db7a378cc9b33e8b17b) + `cmark-gfm@0.8.4` + ## 7.0.8 (2020-11-03) ### DOCUMENTATION diff --git a/deps/npm/docs/content/commands/npm-exec.md b/deps/npm/docs/content/commands/npm-exec.md index 38fb1bf25af4be..c9de9933be3a55 100644 --- a/deps/npm/docs/content/commands/npm-exec.md +++ b/deps/npm/docs/content/commands/npm-exec.md @@ -54,7 +54,8 @@ the package specifier provided as the first positional argument according to the following heuristic: - If the package has a single entry in its `bin` field in `package.json`, - then that command will be used. + or if all entries are aliases of the same command, then that command + will be used. - If the package has multiple `bin` entries, and one of them matches the unscoped portion of the `name` field, then that command will be used. - If this does not result in exactly one option (either because there are diff --git a/deps/npm/docs/content/commands/npx.md b/deps/npm/docs/content/commands/npx.md index a5522c66e85aa4..625ac3d8cd6025 100644 --- a/deps/npm/docs/content/commands/npx.md +++ b/deps/npm/docs/content/commands/npx.md @@ -8,9 +8,9 @@ description: Run a command from a local or remote npm package ```bash npm exec -- [@] [args...] -npm exec -p [@] -- [args...] +npm exec --package=[@] -- [args...] npm exec -c ' [args...]' -npm exec -p foo -c ' [args...]' +npm exec --package=foo -c ' [args...]' npx [@] [args...] npx -p [@] [args...] @@ -19,7 +19,8 @@ npx -p [@] -c ' [args...]' alias: npm x, npx --p --package= (may be specified multiple times) +--package= (may be specified multiple times) +-p is a shorthand for --package only when using npx executable -c --call= (may not be mixed with positional arguments) ``` @@ -29,9 +30,9 @@ This command allows you to run an arbitrary command from an npm package (either one installed locally, or fetched remotely), in a similar context as running it via `npm run`. -Whatever packages are specified by the `--package` or `-p` option will be +Whatever packages are specified by the `--package` option will be provided in the `PATH` of the executed command, along with any locally -installed package executables. The `--package` or `-p` option may be +installed package executables. The `--package` option may be specified multiple times, to execute the supplied command in an environment where all specified packages are available. @@ -47,13 +48,14 @@ only be considered a match if they have the exact same name and version as the local dependency. If no `-c` or `--call` option is provided, then the positional arguments -are used to generate the command string. If no `-p` or `--package` options +are used to generate the command string. If no `--package` options are provided, then npm will attempt to determine the executable name from the package specifier provided as the first positional argument according to the following heuristic: - If the package has a single entry in its `bin` field in `package.json`, - then that command will be used. + or if all entries are aliases of the same command, then that command + will be used. - If the package has multiple `bin` entries, and one of them matches the unscoped portion of the `name` field, then that command will be used. - If this does not result in exactly one option (either because there are diff --git a/deps/npm/docs/content/using-npm/developers.md b/deps/npm/docs/content/using-npm/developers.md index d42c759d42cf1e..7e47b76f65aaf2 100644 --- a/deps/npm/docs/content/using-npm/developers.md +++ b/deps/npm/docs/content/using-npm/developers.md @@ -109,7 +109,7 @@ create an empty `.npmignore` file to override it. Like `git`, `npm` looks for `.npmignore` and `.gitignore` files in all subdirectories of your package, not only the root directory. -`.npmignore` files follow the [same pattern rules](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository#Ignoring-Files) +`.npmignore` files follow the [same pattern rules](https://git-scm.com/book/en/v2/Git-Basics-Recording-Changes-to-the-Repository#_ignoring) as `.gitignore` files: * Blank lines or lines starting with `#` are ignored. diff --git a/deps/npm/docs/content/using-npm/scripts.md b/deps/npm/docs/content/using-npm/scripts.md index f86f9e88bc9ddf..c111aa3f3ab533 100644 --- a/deps/npm/docs/content/using-npm/scripts.md +++ b/deps/npm/docs/content/using-npm/scripts.md @@ -6,7 +6,7 @@ description: How npm handles the "scripts" field ### Description -The `"scripts"` property of of your `package.json` file supports a number of built-in scripts and their preset life cycle events as well as arbitrary scripts. These all can be executed by running `npm run-script ` or `npm run ` for short. *Pre* and *post* commands with matching names will be run for those as well (e.g. `premyscript`, `myscript`, `postmyscript`). Scripts from dependencies can be run with `npm explore -- npm run `. +The `"scripts"` property of your `package.json` file supports a number of built-in scripts and their preset life cycle events as well as arbitrary scripts. These all can be executed by running `npm run-script ` or `npm run ` for short. *Pre* and *post* commands with matching names will be run for those as well (e.g. `premyscript`, `myscript`, `postmyscript`). Scripts from dependencies can be run with `npm explore -- npm run `. ### Pre & Post Scripts diff --git a/deps/npm/docs/output/commands/npm-exec.html b/deps/npm/docs/output/commands/npm-exec.html index 6bd59f7a8ed674..6e50a1cb9af9dd 100644 --- a/deps/npm/docs/output/commands/npm-exec.html +++ b/deps/npm/docs/output/commands/npm-exec.html @@ -186,7 +186,8 @@

Description

to the following heuristic:

  • If the package has a single entry in its bin field in package.json, -then that command will be used.
  • +or if all entries are aliases of the same command, then that command +will be used.
  • If the package has multiple bin entries, and one of them matches the unscoped portion of the name field, then that command will be used.
  • If this does not result in exactly one option (either because there are diff --git a/deps/npm/docs/output/commands/npm-ls.html b/deps/npm/docs/output/commands/npm-ls.html index 55722b8f1ce325..437f062c299e59 100644 --- a/deps/npm/docs/output/commands/npm-ls.html +++ b/deps/npm/docs/output/commands/npm-ls.html @@ -156,7 +156,7 @@

    Description

    limit the results to only the paths to the packages named. Note that nested packages will also show the paths to the specified packages. For example, running npm ls promzard in npm’s source tree will show:

    -
        npm@7.0.8 /path/to/npm
    +
        npm@7.0.11 /path/to/npm
         └─┬ init-package-json@0.0.4
           └── promzard@0.1.5
     
    diff --git a/deps/npm/docs/output/commands/npm.html b/deps/npm/docs/output/commands/npm.html index e3f5ce28afc480..77cf24a8fb1e12 100644 --- a/deps/npm/docs/output/commands/npm.html +++ b/deps/npm/docs/output/commands/npm.html @@ -148,7 +148,7 @@

    Table of contents

    npm <command> [args]
     

    Version

    -

    7.0.8

    +

    7.0.11

    Description

    npm is the package manager for the Node JavaScript platform. It puts modules in place so that node can find them, and manages dependency diff --git a/deps/npm/docs/output/commands/npx.html b/deps/npm/docs/output/commands/npx.html index 61194a0aa31f12..36aad9f701fe8e 100644 --- a/deps/npm/docs/output/commands/npx.html +++ b/deps/npm/docs/output/commands/npx.html @@ -146,9 +146,9 @@

    Table of contents

    Synopsis

    npm exec -- <pkg>[@<version>] [args...]
    -npm exec -p <pkg>[@<version>] -- <cmd> [args...]
    +npm exec --package=<pkg>[@<version>] -- <cmd> [args...]
     npm exec -c '<cmd> [args...]'
    -npm exec -p foo -c '<cmd> [args...]'
    +npm exec --package=foo -c '<cmd> [args...]'
     
     npx <pkg>[@<specifier>] [args...]
     npx -p <pkg>[@<specifier>] <cmd> [args...]
    @@ -157,16 +157,17 @@ 

    Table of contents

    alias: npm x, npx --p <pkg> --package=<pkg> (may be specified multiple times) +--package=<pkg> (may be specified multiple times) +-p is a shorthand for --package only when using npx executable -c <cmd> --call=<cmd> (may not be mixed with positional arguments)

    Description

    This command allows you to run an arbitrary command from an npm package (either one installed locally, or fetched remotely), in a similar context as running it via npm run.

    -

    Whatever packages are specified by the --package or -p option will be +

    Whatever packages are specified by the --package option will be provided in the PATH of the executed command, along with any locally -installed package executables. The --package or -p option may be +installed package executables. The --package option may be specified multiple times, to execute the supplied command in an environment where all specified packages are available.

    If any requested packages are not present in the local project @@ -179,13 +180,14 @@

    Description

    only be considered a match if they have the exact same name and version as the local dependency.

    If no -c or --call option is provided, then the positional arguments -are used to generate the command string. If no -p or --package options +are used to generate the command string. If no --package options are provided, then npm will attempt to determine the executable name from the package specifier provided as the first positional argument according to the following heuristic:

    • If the package has a single entry in its bin field in package.json, -then that command will be used.
    • +or if all entries are aliases of the same command, then that command +will be used.
    • If the package has multiple bin entries, and one of them matches the unscoped portion of the name field, then that command will be used.
    • If this does not result in exactly one option (either because there are diff --git a/deps/npm/docs/output/using-npm/developers.html b/deps/npm/docs/output/using-npm/developers.html index c0e7d4b95c558c..ae547d4f520ec5 100644 --- a/deps/npm/docs/output/using-npm/developers.html +++ b/deps/npm/docs/output/using-npm/developers.html @@ -238,7 +238,7 @@

      Keeping files out of your pa create an empty .npmignore file to override it. Like git, npm looks for .npmignore and .gitignore files in all subdirectories of your package, not only the root directory.

      -

      .npmignore files follow the same pattern rules +

      .npmignore files follow the same pattern rules as .gitignore files:

      • Blank lines or lines starting with # are ignored.
      • diff --git a/deps/npm/docs/output/using-npm/scripts.html b/deps/npm/docs/output/using-npm/scripts.html index dc9d952142dfd9..8d0ad5090789ef 100644 --- a/deps/npm/docs/output/using-npm/scripts.html +++ b/deps/npm/docs/output/using-npm/scripts.html @@ -145,7 +145,7 @@

        Table of contents

        Description

        -

        The "scripts" property of of your package.json file supports a number of built-in scripts and their preset life cycle events as well as arbitrary scripts. These all can be executed by running npm run-script <stage> or npm run <stage> for short. Pre and post commands with matching names will be run for those as well (e.g. premyscript, myscript, postmyscript). Scripts from dependencies can be run with npm explore <pkg> -- npm run <stage>.

        +

        The "scripts" property of your package.json file supports a number of built-in scripts and their preset life cycle events as well as arbitrary scripts. These all can be executed by running npm run-script <stage> or npm run <stage> for short. Pre and post commands with matching names will be run for those as well (e.g. premyscript, myscript, postmyscript). Scripts from dependencies can be run with npm explore <pkg> -- npm run <stage>.

        Pre & Post Scripts

        To create “pre” or “post” scripts for any scripts defined in the "scripts" section of the package.json, simply create another script with a matching name and add “pre” or “post” to the beginning of them.

        {
        diff --git a/deps/npm/lib/adduser.js b/deps/npm/lib/adduser.js
        index 895a677c019de3..5017f57a8ae906 100644
        --- a/deps/npm/lib/adduser.js
        +++ b/deps/npm/lib/adduser.js
        @@ -4,6 +4,7 @@ const log = require('npmlog')
         const npm = require('./npm.js')
         const output = require('./utils/output.js')
         const usageUtil = require('./utils/usage.js')
        +const replaceInfo = require('./utils/replace-info.js')
         const authTypes = {
           legacy: require('./auth/legacy.js'),
           oauth: require('./auth/oauth.js'),
        @@ -57,6 +58,8 @@ const adduser = async (args) => {
         
           log.disableProgress()
         
        +  log.notice('', `Log in on ${replaceInfo(registry)}`)
        +
           const { message, newCreds } = await auth({
             creds,
             registry,
        diff --git a/deps/npm/lib/cache.js b/deps/npm/lib/cache.js
        index bf788043ab6e68..30d6aef863ac29 100644
        --- a/deps/npm/lib/cache.js
        +++ b/deps/npm/lib/cache.js
        @@ -22,10 +22,11 @@ const usage = usageUtil('cache',
         const completion = (opts, cb) => {
           const argv = opts.conf.argv.remain
           if (argv.length === 2)
        -    return cb(null, ['add', 'clean'])
        +    return cb(null, ['add', 'clean', 'verify'])
         
           // TODO - eventually...
           switch (argv[2]) {
        +    case 'verify':
             case 'clean':
             case 'add':
               return cb(null, [])
        @@ -40,11 +41,11 @@ const cache = async (args) => {
             case 'rm': case 'clear': case 'clean':
               return await clean(args)
             case 'add':
        -      return await add(args, npm.prefix)
        +      return await add(args)
             case 'verify': case 'check':
               return await verify()
             default:
        -      throw usage
        +      throw Object.assign(new Error(usage), { code: 'EUSAGE' })
           }
         }
         
        @@ -77,22 +78,21 @@ with --force.`)
         // npm cache add  
         // npm cache add 
         // npm cache add 
        -const add = async (args, where) => {
        +const add = async (args) => {
           const usage = 'Usage:\n' +
             '    npm cache add \n' +
             '    npm cache add @\n' +
             '    npm cache add \n' +
             '    npm cache add \n'
           log.silly('cache add', 'args', args)
        -  const spec = args[0] +
        +  const spec = args[0] && args[0] +
             (args[1] === undefined || args[1] === null ? '' : `@${args[1]}`)
         
        -  log.verbose('cache add', 'spec', spec)
           if (!spec)
        -    throw new Error(usage)
        +    throw Object.assign(new Error(usage), { code: 'EUSAGE' })
         
        -  log.silly('cache add', 'parsed spec', spec)
        -  const opts = { ...npm.flatOptions, where }
        +  log.silly('cache add', 'spec', spec)
        +  const opts = { ...npm.flatOptions }
         
           // we ask pacote for the thing, and then just throw the data
           // away so that it tee-pipes it into the cache like it does
        @@ -109,7 +109,7 @@ const verify = async () => {
             ? `~${cache.substr(process.env.HOME.length)}`
             : cache
           const stats = await cacache.verify(cache)
        -  output(`Cache verified and compressed (${prefix}):`)
        +  output(`Cache verified and compressed (${prefix})`)
           output(`Content verified: ${stats.verifiedContent} (${stats.keptSize} bytes)`)
           stats.badContentCount && output(`Corrupted content removed: ${stats.badContentCount}`)
           stats.reclaimedCount && output(`Content garbage-collected: ${stats.reclaimedCount} (${stats.reclaimedSize} bytes)`)
        diff --git a/deps/npm/lib/ci.js b/deps/npm/lib/ci.js
        index a72e1c0cffba61..a1632e7e98064b 100644
        --- a/deps/npm/lib/ci.js
        +++ b/deps/npm/lib/ci.js
        @@ -34,7 +34,7 @@ const ci = async () => {
             rimraf(`${where}/node_modules/*`, { glob: { dot: true, nosort: true, silent: true } }),
           ])
           // npm ci should never modify the lockfile or package.json
        -  await arb.reify({ save: false })
        +  await arb.reify({ ...npm.flatOptions, save: false })
           reifyOutput(arb)
         }
         
        diff --git a/deps/npm/lib/cli.js b/deps/npm/lib/cli.js
        index f06abcd186f966..910b674eaa790f 100644
        --- a/deps/npm/lib/cli.js
        +++ b/deps/npm/lib/cli.js
        @@ -1,5 +1,7 @@
         // Separated out for easier unit testing
         module.exports = (process) => {
        +  // set it here so that regardless of what happens later, we don't
        +  // leak any private CLI configs to other programs
           process.title = 'npm'
         
           const {
        diff --git a/deps/npm/lib/exec.js b/deps/npm/lib/exec.js
        index 088a7c00eba314..6bcaf838ed327e 100644
        --- a/deps/npm/lib/exec.js
        +++ b/deps/npm/lib/exec.js
        @@ -226,15 +226,15 @@ const manifestMissing = (tree, mani) => {
         
         const getBinFromManifest = mani => {
           // if we have a bin matching (unscoped portion of) packagename, use that
        -  // otherwise if there's 1 bin, use that,
        +  // otherwise if there's 1 bin or all bin value is the same (alias), use that,
           // otherwise fail
        -  const bins = Object.entries(mani.bin || {})
        -  if (bins.length === 1)
        -    return bins[0][0]
        +  const bin = mani.bin || {}
        +  if (new Set(Object.values(bin)).size === 1)
        +    return Object.keys(bin)[0]
         
           // XXX probably a util to parse this better?
           const name = mani.name.replace(/^@[^/]+\//, '')
        -  if (mani.bin && mani.bin[name])
        +  if (bin[name])
             return name
         
           // XXX need better error message
        diff --git a/deps/npm/lib/npm.js b/deps/npm/lib/npm.js
        index d6eab9674fe186..4430b80539d031 100644
        --- a/deps/npm/lib/npm.js
        +++ b/deps/npm/lib/npm.js
        @@ -54,6 +54,7 @@ const _runCmd = Symbol('_runCmd')
         const _load = Symbol('_load')
         const _flatOptions = Symbol('_flatOptions')
         const _tmpFolder = Symbol('_tmpFolder')
        +const _title = Symbol('_title')
         const npm = module.exports = new class extends EventEmitter {
           constructor () {
             super()
        @@ -75,6 +76,7 @@ const npm = module.exports = new class extends EventEmitter {
               defaults,
               shorthands,
             })
        +    this[_title] = process.title
             this.updateNotification = null
           }
         
        @@ -156,6 +158,15 @@ const npm = module.exports = new class extends EventEmitter {
             return this.config.loaded
           }
         
        +  get title () {
        +    return this[_title]
        +  }
        +
        +  set title (t) {
        +    process.title = t
        +    this[_title] = t
        +  }
        +
           async [_load] () {
             const node = await which(process.argv[0]).catch(er => null)
             if (node && node.toUpperCase() !== process.execPath.toUpperCase()) {
        @@ -166,6 +177,15 @@ const npm = module.exports = new class extends EventEmitter {
         
             await this.config.load()
             this.argv = this.config.parsedArgv.remain
        +    // note: this MUST be shorter than the actual argv length, because it
        +    // uses the same memory, so node will truncate it if it's too long.
        +    // if it's a token revocation, then the argv contains a secret, so
        +    // don't show that.  (Regrettable historical choice to put it there.)
        +    // Any other secrets are configs only, so showing only the positional
        +    // args keeps those from being leaked.
        +    const tokrev = deref(this.argv[0]) === 'token' && this.argv[1] === 'revoke'
        +    this.title = tokrev ? 'npm token revoke' + (this.argv[2] ? ' ***' : '')
        +      : ['npm', ...this.argv].join(' ')
         
             this.color = setupLog(this.config, this)
             process.env.COLOR = this.color ? '1' : '0'
        diff --git a/deps/npm/lib/run-script.js b/deps/npm/lib/run-script.js
        index 4d27e8eed965e8..568a5712f6ac79 100644
        --- a/deps/npm/lib/run-script.js
        +++ b/deps/npm/lib/run-script.js
        @@ -1,4 +1,5 @@
         const run = require('@npmcli/run-script')
        +const { isServerPackage } = run
         const npm = require('./npm.js')
         const readJson = require('read-package-json-fast')
         const { resolve } = require('path')
        @@ -45,7 +46,7 @@ const runScript = async (args) => {
         
           pkg.scripts = scripts
         
        -  if (!scripts[event]) {
        +  if (!scripts[event] && !(event === 'start' && await isServerPackage(path))) {
             if (npm.config.get('if-present'))
               return
         
        diff --git a/deps/npm/lib/utils/config.js b/deps/npm/lib/utils/config.js
        index f9de6e9a79220c..6abb502e205724 100644
        --- a/deps/npm/lib/utils/config.js
        +++ b/deps/npm/lib/utils/config.js
        @@ -52,6 +52,7 @@ const defaults = {
           'always-auth': false,
           audit: true,
           'audit-level': null,
        +  _auth: null,
           'auth-type': 'legacy',
           before: null,
           'bin-links': true,
        @@ -191,6 +192,7 @@ const types = {
           all: Boolean,
           'allow-same-version': Boolean,
           also: [null, 'dev', 'development'],
        +  _auth: [null, String],
           'always-auth': Boolean,
           audit: Boolean,
           'audit-level': ['low', 'moderate', 'high', 'critical', 'none', null],
        diff --git a/deps/npm/lib/utils/error-handler.js b/deps/npm/lib/utils/error-handler.js
        index dc9e2a26bcfa59..476ca9e917b366 100644
        --- a/deps/npm/lib/utils/error-handler.js
        +++ b/deps/npm/lib/utils/error-handler.js
        @@ -182,7 +182,7 @@ const errorHandler = (er) => {
                 detail: messageText(msg.detail),
               },
             }
        -    console.log(JSON.stringify(error, null, 2))
        +    console.error(JSON.stringify(error, null, 2))
           }
         
           exit(typeof er.errno === 'number' ? er.errno : typeof er.code === 'number' ? er.code : 1)
        diff --git a/deps/npm/lib/utils/explain-dep.js b/deps/npm/lib/utils/explain-dep.js
        index 096df97edfda32..ed69a02c143c0b 100644
        --- a/deps/npm/lib/utils/explain-dep.js
        +++ b/deps/npm/lib/utils/explain-dep.js
        @@ -64,7 +64,7 @@ const explainDependents = ({ name, dependents }, depth, color) => {
             const maxLen = 50
             const showNames = []
             for (let i = max; i < dependents.length; i++) {
        -      const { from: { name } } = dependents[i]
        +      const { from: { name = 'the root project' } } = dependents[i]
               len += name.length
               if (len >= maxLen && i < dependents.length - 1) {
                 showNames.push('...')
        diff --git a/deps/npm/lib/utils/flat-options.js b/deps/npm/lib/utils/flat-options.js
        index be62c5a4cdb589..8b6864aa823ff7 100644
        --- a/deps/npm/lib/utils/flat-options.js
        +++ b/deps/npm/lib/utils/flat-options.js
        @@ -50,6 +50,7 @@ const flatten = obj => ({
           alwaysAuth: obj['always-auth'],
           audit: obj.audit,
           auditLevel: obj['audit-level'],
        +  _auth: obj._auth,
           authType: obj['auth-type'],
           ssoType: obj['sso-type'],
           ssoPollFrequency: obj['sso-poll-frequency'],
        diff --git a/deps/npm/man/man1/npm-exec.1 b/deps/npm/man/man1/npm-exec.1
        index 6048388fd6e262..17d436812edba9 100644
        --- a/deps/npm/man/man1/npm-exec.1
        +++ b/deps/npm/man/man1/npm-exec.1
        @@ -53,7 +53,8 @@ to the following heuristic:
         .RS 0
         .IP \(bu 2
         If the package has a single entry in its \fBbin\fP field in \fBpackage\.json\fP,
        -then that command will be used\.
        +or if all entries are aliases of the same command, then that command
        +will be used\.
         .IP \(bu 2
         If the package has multiple \fBbin\fP entries, and one of them matches the
         unscoped portion of the \fBname\fP field, then that command will be used\.
        diff --git a/deps/npm/man/man1/npm-ls.1 b/deps/npm/man/man1/npm-ls.1
        index afa7913b743853..67c5234ef446c0 100644
        --- a/deps/npm/man/man1/npm-ls.1
        +++ b/deps/npm/man/man1/npm-ls.1
        @@ -22,7 +22,7 @@ For example, running \fBnpm ls promzard\fP in npm's source tree will show:
         .P
         .RS 2
         .nf
        -    npm@7\.0\.8 /path/to/npm
        +    npm@7\.0\.11 /path/to/npm
             └─┬ init\-package\-json@0\.0\.4
               └── promzard@0\.1\.5
         .fi
        diff --git a/deps/npm/man/man1/npm.1 b/deps/npm/man/man1/npm.1
        index 9197f45f0ad022..32e4a5b4254ae4 100644
        --- a/deps/npm/man/man1/npm.1
        +++ b/deps/npm/man/man1/npm.1
        @@ -10,7 +10,7 @@ npm  [args]
         .RE
         .SS Version
         .P
        -7\.0\.8
        +7\.0\.11
         .SS Description
         .P
         npm is the package manager for the Node JavaScript platform\.  It puts
        diff --git a/deps/npm/man/man1/npx.1 b/deps/npm/man/man1/npx.1
        index 88b597de523502..d87c4a946d592c 100644
        --- a/deps/npm/man/man1/npx.1
        +++ b/deps/npm/man/man1/npx.1
        @@ -6,9 +6,9 @@
         .RS 2
         .nf
         npm exec \-\- [@] [args\.\.\.]
        -npm exec \-p [@] \-\-  [args\.\.\.]
        +npm exec \-\-package=[@] \-\-  [args\.\.\.]
         npm exec \-c ' [args\.\.\.]'
        -npm exec \-p foo \-c ' [args\.\.\.]'
        +npm exec \-\-package=foo \-c ' [args\.\.\.]'
         
         npx [@] [args\.\.\.]
         npx \-p [@]  [args\.\.\.]
        @@ -17,7 +17,8 @@ npx \-p [@] \-c ' [args\.\.\.]'
         
         alias: npm x, npx
         
        -\-p  \-\-package= (may be specified multiple times)
        +\-\-package= (may be specified multiple times)
        +\-p is a shorthand for \-\-package only when using npx executable
         \-c  \-\-call= (may not be mixed with positional arguments)
         .fi
         .RE
        @@ -27,9 +28,9 @@ This command allows you to run an arbitrary command from an npm package
         (either one installed locally, or fetched remotely), in a similar context
         as running it via \fBnpm run\fP\|\.
         .P
        -Whatever packages are specified by the \fB\-\-package\fP or \fB\-p\fP option will be
        +Whatever packages are specified by the \fB\-\-package\fP option will be
         provided in the \fBPATH\fP of the executed command, along with any locally
        -installed package executables\.  The \fB\-\-package\fP or \fB\-p\fP option may be
        +installed package executables\.  The \fB\-\-package\fP option may be
         specified multiple times, to execute the supplied command in an environment
         where all specified packages are available\.
         .P
        @@ -45,14 +46,15 @@ only be considered a match if they have the exact same name and version as
         the local dependency\.
         .P
         If no \fB\-c\fP or \fB\-\-call\fP option is provided, then the positional arguments
        -are used to generate the command string\.  If no \fB\-p\fP or \fB\-\-package\fP options
        +are used to generate the command string\.  If no \fB\-\-package\fP options
         are provided, then npm will attempt to determine the executable name from
         the package specifier provided as the first positional argument according
         to the following heuristic:
         .RS 0
         .IP \(bu 2
         If the package has a single entry in its \fBbin\fP field in \fBpackage\.json\fP,
        -then that command will be used\.
        +or if all entries are aliases of the same command, then that command
        +will be used\.
         .IP \(bu 2
         If the package has multiple \fBbin\fP entries, and one of them matches the
         unscoped portion of the \fBname\fP field, then that command will be used\.
        diff --git a/deps/npm/man/man7/developers.7 b/deps/npm/man/man7/developers.7
        index 9a34bf3edb0505..1af140b44233fb 100644
        --- a/deps/npm/man/man7/developers.7
        +++ b/deps/npm/man/man7/developers.7
        @@ -114,7 +114,7 @@ create an empty \fB\|\.npmignore\fP file to override it\. Like \fBgit\fP, \fBnpm
         for \fB\|\.npmignore\fP and \fB\|\.gitignore\fP files in all subdirectories of your
         package, not only the root directory\.
         .P
        -\fB\|\.npmignore\fP files follow the same pattern rules \fIhttps://git\-scm\.com/book/en/v2/Git\-Basics\-Recording\-Changes\-to\-the\-Repository#Ignoring\-Files\fR
        +\fB\|\.npmignore\fP files follow the same pattern rules \fIhttps://git\-scm\.com/book/en/v2/Git\-Basics\-Recording\-Changes\-to\-the\-Repository#_ignoring\fR
         as \fB\|\.gitignore\fP files:
         .RS 0
         .IP \(bu 2
        diff --git a/deps/npm/man/man7/scripts.7 b/deps/npm/man/man7/scripts.7
        index 522e32cb80e158..2067fe45d92383 100644
        --- a/deps/npm/man/man7/scripts.7
        +++ b/deps/npm/man/man7/scripts.7
        @@ -3,7 +3,7 @@
         \fBscripts\fR \- How npm handles the "scripts" field
         .SS Description
         .P
        -The \fB"scripts"\fP property of of your \fBpackage\.json\fP file supports a number of built\-in scripts and their preset life cycle events as well as arbitrary scripts\. These all can be executed by running \fBnpm run\-script \fP or \fBnpm run \fP for short\. \fIPre\fR and \fIpost\fR commands with matching names will be run for those as well (e\.g\. \fBpremyscript\fP, \fBmyscript\fP, \fBpostmyscript\fP)\. Scripts from dependencies can be run with \fBnpm explore  \-\- npm run \fP\|\.
        +The \fB"scripts"\fP property of your \fBpackage\.json\fP file supports a number of built\-in scripts and their preset life cycle events as well as arbitrary scripts\. These all can be executed by running \fBnpm run\-script \fP or \fBnpm run \fP for short\. \fIPre\fR and \fIpost\fR commands with matching names will be run for those as well (e\.g\. \fBpremyscript\fP, \fBmyscript\fP, \fBpostmyscript\fP)\. Scripts from dependencies can be run with \fBnpm explore  \-\- npm run \fP\|\.
         .SS Pre & Post Scripts
         .P
         To create "pre" or "post" scripts for any scripts defined in the \fB"scripts"\fP section of the \fBpackage\.json\fP, simply create another script \fIwith a matching name\fR and add "pre" or "post" to the beginning of them\.
        diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js
        index 54a6ff33751a1f..579d5740da4f75 100644
        --- a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js
        +++ b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/build-ideal-tree.js
        @@ -7,6 +7,10 @@ const semver = require('semver')
         const promiseCallLimit = require('promise-call-limit')
         const getPeerSet = require('../peer-set.js')
         const realpath = require('../../lib/realpath.js')
        +const walkUpPath = require('walk-up-path')
        +const { dirname, resolve } = require('path')
        +const { promisify } = require('util')
        +const readdir = promisify(require('readdir-scoped-modules'))
         
         const debug = require('../debug.js')
         const fromPath = require('../from-path.js')
        @@ -182,8 +186,10 @@ module.exports = cls => class IdealTreeBuilder extends cls {
         
             process.emit('time', 'idealTree')
         
        -    if (!options.add && !options.rm && this[_global])
        -      return Promise.reject(new Error('global requires an add or rm option'))
        +    if (!options.add && !options.rm && !options.update && this[_global]) {
        +      const er = new Error('global requires add, rm, or update option')
        +      return Promise.reject(er)
        +    }
         
             // first get the virtual tree, if possible.  If there's a lockfile, then
             // that defines the ideal tree, unless the root package.json is not
        @@ -305,7 +311,6 @@ module.exports = cls => class IdealTreeBuilder extends cls {
               // cases we don't use a lockfile anyway.
               // Load on a new Arborist object, so the Nodes aren't the same,
               // or else it'll get super confusing when we change them!
        -      // Only have to mapWorkspaces if we didn't get it from actual or virtual
               .then(async root => {
                 if (!this[_updateAll] && !this[_global] && !root.meta.loadedFromDisk)
                   await new this.constructor(this.options).loadActual({ root })
        @@ -322,10 +327,10 @@ module.exports = cls => class IdealTreeBuilder extends cls {
           }
         
           [_globalRootNode] () {
        -    const root = this[_rootNodeFromPackage]({})
        +    const root = this[_rootNodeFromPackage]({ dependencies: {} })
             // this is a gross kludge to handle the fact that we don't save
             // metadata on the root node in global installs, because the "root"
        -    // node is something like /usr/local/lib/node_modules.
        +    // node is something like /usr/local/lib.
             const meta = new Shrinkwrap({ path: this.path })
             meta.reset()
             root.meta = meta
        @@ -353,9 +358,19 @@ module.exports = cls => class IdealTreeBuilder extends cls {
             // If we have a list of package names to update, and we know it's
             // going to update them wherever they are, add any paths into those
             // named nodes to the buildIdealTree queue.
        -    if (this[_updateNames].length)
        +    if (!this[_global] && this[_updateNames].length)
               this[_queueNamedUpdates]()
         
        +    // global updates only update the globalTop nodes, but we need to know
        +    // that they're there, and not reinstall the world unnecessarily.
        +    if (this[_global] && (this[_updateAll] || this[_updateNames].length)) {
        +      const nm = resolve(this.path, 'node_modules')
        +      for (const name of await readdir(nm)) {
        +        if (this[_updateAll] || this[_updateNames].includes(name))
        +          this.idealTree.package.dependencies[name] = '*'
        +      }
        +    }
        +
             if (this.auditReport && this.auditReport.size > 0)
               this[_queueVulnDependents](options)
         
        @@ -563,7 +578,8 @@ module.exports = cls => class IdealTreeBuilder extends cls {
             const { meta, inventory } = this.idealTree
             const ancient = meta.ancientLockfile
             const old = meta.loadedFromDisk && !(meta.originalLockfileVersion >= 2)
        -    if (inventory.size === 0 || !(ancient || old && this[_complete]))
        +
        +    if (inventory.size === 0 || !ancient && !(old && this[_complete]))
               return
         
             // if the lockfile is from node v5 or earlier, then we'll have to reload
        @@ -604,6 +620,10 @@ This is a one-time fix-up, please be patient...
               })
             }
             await promiseCallLimit(queue)
        +    // yes, yes, this isn't the "original" version, but now that it's been
        +    // upgraded, we need to make sure we don't do the work to upgrade it
        +    // again, since it's now as new as can be.
        +    meta.originalLockfileVersion = 2
             this.finishTracker('idealTree:inflate')
             process.emit('timeEnd', 'idealTree:inflate')
           }
        @@ -790,6 +810,11 @@ This is a one-time fix-up, please be patient...
             }
             await Promise.all(promises)
         
        +    for (const { to } of node.edgesOut.values()) {
        +      if (to && to.isLink)
        +        this[_linkNodes].add(to)
        +    }
        +
             return this[_buildDepStep]()
           }
         
        @@ -1065,14 +1090,22 @@ This is a one-time fix-up, please be patient...
         
             let target
             let canPlace = null
        +    let isSource = false
        +    const source = this[_peerSetSource].get(dep)
             for (let check = start; check; check = check.resolveParent) {
        +      // we always give the FIRST place we possibly *can* put this a little
        +      // extra prioritization with peer dep overrides and deduping
        +      if (check === source)
        +        isSource = true
        +
               // if the current location has a peerDep on it, then we can't place here
               // this is pretty rare to hit, since we always prefer deduping peers.
               const checkEdge = check.edgesOut.get(edge.name)
               if (!check.isTop && checkEdge && checkEdge.peer)
                 continue
         
        -      const cp = this[_canPlaceDep](dep, check, edge, peerEntryEdge, peerPath)
        +      const cp = this[_canPlaceDep](dep, check, edge, peerEntryEdge, peerPath, isSource)
        +      isSource = false
         
               // anything other than a conflict is fine to proceed with
               if (cp !== CONFLICT) {
        @@ -1144,7 +1177,7 @@ This is a one-time fix-up, please be patient...
               const oldDeps = []
               for (const [name, edge] of oldChild.edgesOut.entries()) {
                 if (!newDep.edgesOut.has(name) && edge.to)
        -          oldDeps.push(edge.to)
        +          oldDeps.push(...gatherDepSet([edge.to], e => e.to !== edge.to))
               }
               newDep.replace(oldChild)
               this[_pruneForReplacement](newDep, oldDeps)
        @@ -1245,14 +1278,17 @@ This is a one-time fix-up, please be patient...
             // deps that the new node doesn't depend on but the old one did.
             const invalidDeps = new Set([...node.edgesOut.values()]
               .filter(e => e.to && !e.valid).map(e => e.to))
        -    for (const dep of oldDeps)
        -      invalidDeps.add(dep)
        +    for (const dep of oldDeps) {
        +      const set = gatherDepSet([dep], e => e.to !== dep && e.valid)
        +      for (const dep of set)
        +        invalidDeps.add(dep)
        +    }
         
             // ignore dependency edges from the node being replaced, but
             // otherwise filter the set down to just the set with no
             // dependencies from outside the set, except the node in question.
             const deps = gatherDepSet(invalidDeps, edge =>
        -      edge.from !== node && edge.to !== node)
        +      edge.from !== node && edge.to !== node && edge.valid)
         
             // now just delete whatever's left, because it's junk
             for (const dep of deps)
        @@ -1279,7 +1315,7 @@ This is a one-time fix-up, please be patient...
           // checking, because either we're leaving it alone, or it won't work anyway.
           // When we check peers, we pass along the peerEntryEdge to track the
           // original edge that caused us to load the family of peer dependencies.
        -  [_canPlaceDep] (dep, target, edge, peerEntryEdge = null, peerPath = []) {
        +  [_canPlaceDep] (dep, target, edge, peerEntryEdge = null, peerPath = [], isSource = false) {
             /* istanbul ignore next */
             debug(() => {
               if (!dep)
        @@ -1287,8 +1323,16 @@ This is a one-time fix-up, please be patient...
             })
             const entryEdge = peerEntryEdge || edge
             const source = this[_peerSetSource].get(dep)
        -    const isSource = target === source
        -    const { isRoot, isWorkspace } = source || {}
        +    isSource = isSource || target === source
        +    // if we're overriding the source, then we care if the *target* is
        +    // ours, even if it wasn't actually the original source, since we
        +    // are depending on something that has a dep that can't go in its own
        +    // folder.  for example, a -> b, b -> PEER(a).  Even though a is the
        +    // source, b has to be installed up a level, and if the root package
        +    // depends on a, and it has a conflict, it's our problem.  So, the root
        +    // (or whatever is bringing in a) becomes the "effective source" for
        +    // the purposes of this calculation.
        +    const { isRoot, isWorkspace } = isSource ? target : source || {}
             const isMine = isRoot || isWorkspace
         
             // Useful testing thingie right here.
        @@ -1313,7 +1357,7 @@ This is a one-time fix-up, please be patient...
               const { version: newVer } = dep
               const tryReplace = curVer && newVer && semver.gte(newVer, curVer)
               if (tryReplace && dep.canReplace(current)) {
        -        const res = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge, peerPath)
        +        const res = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge, peerPath, isSource)
                 /* istanbul ignore else - It's extremely rare that a replaceable
                  * node would be a conflict, if the current one wasn't a conflict,
                  * but it is theoretically possible if peer deps are pinned.  In
        @@ -1333,7 +1377,7 @@ This is a one-time fix-up, please be patient...
               // a bit harder to be singletons.
               const preferDedupe = this[_preferDedupe] || edge.peer
               if (preferDedupe && !tryReplace && dep.canReplace(current)) {
        -        const res = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge, peerPath)
        +        const res = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge, peerPath, isSource)
                 /* istanbul ignore else - It's extremely rare that a replaceable
                  * node would be a conflict, if the current one wasn't a conflict,
                  * but it is theoretically possible if peer deps are pinned.  In
        @@ -1401,7 +1445,7 @@ This is a one-time fix-up, please be patient...
                   }
                 }
                 if (canReplace) {
        -          const ret = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge, peerPath)
        +          const ret = this[_canPlacePeers](dep, target, edge, REPLACE, peerEntryEdge, peerPath, isSource)
                   /* istanbul ignore else - extremely rare that the peer set would
                    * conflict if we can replace the node in question, but theoretically
                    * possible, if peer deps are pinned aggressively. */
        @@ -1462,14 +1506,14 @@ This is a one-time fix-up, please be patient...
             }
         
             // no objections!  ok to place here
        -    return this[_canPlacePeers](dep, target, edge, OK, peerEntryEdge, peerPath)
        +    return this[_canPlacePeers](dep, target, edge, OK, peerEntryEdge, peerPath, isSource)
           }
         
           // make sure the family of peer deps can live here alongside it.
           // this doesn't guarantee that THIS solution will be the one we take,
           // but it does establish that SOME solution exists at this level in
           // the tree.
        -  [_canPlacePeers] (dep, target, edge, ret, peerEntryEdge, peerPath) {
        +  [_canPlacePeers] (dep, target, edge, ret, peerEntryEdge, peerPath, isSource) {
             // do not go in cycles when we're resolving a peer group
             if (!dep.parent || peerEntryEdge && peerPath.includes(dep))
               return ret
        @@ -1481,7 +1525,7 @@ This is a one-time fix-up, please be patient...
               if (!peerEdge.peer || !peerEdge.to)
                 continue
               const peer = peerEdge.to
        -      const canPlacePeer = this[_canPlaceDep](peer, target, peerEdge, entryEdge, peerPath)
        +      const canPlacePeer = this[_canPlaceDep](peer, target, peerEdge, entryEdge, peerPath, isSource)
               if (canPlacePeer !== CONFLICT)
                 continue
         
        @@ -1514,34 +1558,35 @@ This is a one-time fix-up, please be patient...
         
               const external = /^\.\.(\/|$)/.test(loc)
         
        -      if (external && !this[_follow]) {
        -        // outside the root, somebody else's problem, ignore it
        -        continue
        -      }
        -
               if (!link.target.parent && !link.target.fsParent) {
        -        // the fsParent MUST be some node in the tree, possibly the root.
        -        // find it by walking up.  Note that this is where its deps may
        -        // end up being installed, if possible.
        -        const parts = loc.split('/')
        -        for (let p = parts.length - 1; p > -1; p--) {
        -          const path = parts.slice(0, p).join('/')
        -          if (!path && external)
        -            break
        +        // the fsParent likely some node in the tree, possibly the root,
        +        // unless it is external.  find it by walking up.  Note that this
        +        // is where its deps may end up being installed, if possible.
        +        for (const p of walkUpPath(dirname(realpath))) {
        +          const path = relpath(this.path, p)
                   const node = !path ? this.idealTree
                     : this.idealTree.inventory.get(path)
                   if (node) {
                     link.target.fsParent = node
                     this.addTracker('idealTree', link.target.name, link.target.location)
                     this[_depsQueue].push(link.target)
        -            p = -1
        +            break
                   }
                 }
               }
         
        -      // didn't find a parent for it, but we're filling in external
        -      // link targets, so go ahead and process it.
        -      if (this[_follow] && !link.target.parent && !link.target.fsParent) {
        +      // outside the root, somebody else's problem, ignore it
        +      if (external && !this[_follow])
        +        continue
        +
        +      // didn't find a parent for it or it has not been seen yet
        +      // so go ahead and process it.
        +      const unseenLink = (link.target.parent || link.target.fsParent)
        +        && !this[_depsSeen].has(link.target)
        +      if (this[_follow]
        +        && !link.target.parent
        +        && !link.target.fsParent
        +        || unseenLink) {
                 this.addTracker('idealTree', link.target.name, link.target.location)
                 this[_depsQueue].push(link.target)
               }
        diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/load-virtual.js b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/load-virtual.js
        index 14c96092753fc9..e335bdadd45413 100644
        --- a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/load-virtual.js
        +++ b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/load-virtual.js
        @@ -185,12 +185,6 @@ module.exports = cls => class VirtualLoader extends cls {
           // links is the set of metadata, and nodes is the map of non-Link nodes
           // Set the targets to nodes in the set, if we have them (we might not)
           async [resolveLinks] (links, nodes) {
        -    // now we've loaded the root, and all real nodes
        -    // link up the links
        -    const {meta} = this.virtualTree
        -    const {loadedFromDisk, originalLockfileVersion} = meta
        -    const oldLockfile = loadedFromDisk && !(originalLockfileVersion >= 2)
        -
             for (const [location, meta] of links.entries()) {
               const targetPath = resolve(this.path, meta.resolved)
               const targetLoc = relpath(this.path, targetPath)
        @@ -198,27 +192,31 @@ module.exports = cls => class VirtualLoader extends cls {
               const link = this[loadLink](location, targetLoc, target, meta)
               nodes.set(location, link)
               nodes.set(targetLoc, link.target)
        -      // legacy shrinkwraps do not store all the info we need for the target.
        -      // if we're loading from disk, and have a link in place, we need to
        -      // look in that actual folder (or at least try to) in order to get
        -      // the dependencies of the link target and load it properly.
        -      if (oldLockfile) {
        -        const pj = link.realpath + '/package.json'
        -        const pkg = await rpj(pj).catch(() => null)
        -        if (pkg)
        -          link.target.package = pkg
        -      }
        +
        +      // we always need to read the package.json for link targets
        +      // because they can be changed by the local user
        +      const pj = link.realpath + '/package.json'
        +      const pkg = await rpj(pj).catch(() => null)
        +      if (pkg)
        +        link.target.package = pkg
             }
           }
         
           [assignParentage] (nodes) {
             for (const [location, node] of nodes) {
        +      // Skip assignment of parentage for the root package
        +      if (!location)
        +        continue
               const { path, name } = node
               for (const p of walkUp(dirname(path))) {
                 const ploc = relpath(this.path, p)
                 const parent = nodes.get(ploc)
                 if (!parent)
                   continue
        +        // Safety check: avoid self-assigning nodes as their own parents
        +        /* istanbul ignore if - should be obviated by parentage skip check */
        +        if (parent === node)
        +          continue
         
                 const locTest = `${ploc}/node_modules/${name}`.replace(/^\//, '')
                 const ptype = location === locTest
        diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js
        index 57ecf071fbaff6..92943554b474e5 100644
        --- a/deps/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js
        +++ b/deps/npm/node_modules/@npmcli/arborist/lib/arborist/reify.js
        @@ -10,10 +10,10 @@ const {dirname, resolve, relative} = require('path')
         const {depth: dfwalk} = require('treeverse')
         const fs = require('fs')
         const {promisify} = require('util')
        -const rename = promisify(fs.rename)
         const symlink = promisify(fs.symlink)
         const writeFile = promisify(fs.writeFile)
         const mkdirp = require('mkdirp-infer-owner')
        +const moveFile = require('@npmcli/move-file')
         const rimraf = promisify(require('rimraf'))
         const packageContents = require('@npmcli/installed-package-contents')
         
        @@ -60,6 +60,7 @@ const _rollbackRetireShallowNodes = Symbol.for('rollbackRetireShallowNodes')
         const _rollbackCreateSparseTree = Symbol.for('rollbackCreateSparseTree')
         const _rollbackMoveBackRetiredUnchanged = Symbol.for('rollbackMoveBackRetiredUnchanged')
         const _saveIdealTree = Symbol.for('saveIdealTree')
        +const _saveLockFile = Symbol('saveLockFile')
         const _copyIdealToActual = Symbol('copyIdealToActual')
         const _addOmitsToTrashList = Symbol('addOmitsToTrashList')
         const _packageLockOnly = Symbol('packageLockOnly')
        @@ -172,7 +173,7 @@ module.exports = cls => class Reifier extends cls {
               ignoreMissing: true,
               global: true,
               filter: (node, kid) => !node.isRoot ? true
        -      : this[_explicitRequests].has(kid),
        +      : (node.edgesOut.has(kid) || this[_explicitRequests].has(kid)),
             } : { ignoreMissing: true }
         
             if (!this[_global]) {
        @@ -182,7 +183,9 @@ module.exports = cls => class Reifier extends cls {
         
             // the global install space tends to have a lot of stuff in it.  don't
             // load all of it, just what we care about.  we won't be saving a
        -    // hidden lockfile in there anyway.
        +    // hidden lockfile in there anyway.  Note that we have to load ideal
        +    // BEFORE loading actual, so that the actualOpt can use the
        +    // explicitRequests which is set during buildIdealTree
             return this.buildIdealTree(bitOpt)
               .then(() => this.loadActual(actualOpt))
               .then(() => process.emit('timeEnd', 'reify:loadTrees'))
        @@ -251,7 +254,7 @@ module.exports = cls => class Reifier extends cls {
           }
         
           [_renamePath] (from, to, didMkdirp = false) {
        -    return rename(from, to)
        +    return moveFile(from, to)
               .catch(er => {
                 // Occasionally an expected bin file might not exist in the package,
                 // or a shim/symlink might have been moved aside.  If we've already
        @@ -261,7 +264,7 @@ module.exports = cls => class Reifier extends cls {
                   return didMkdirp ? null : mkdirp(dirname(to)).then(() =>
                     this[_renamePath](from, to, true))
                 } else if (er.code === 'EEXIST')
        -          return rimraf(to).then(() => rename(from, to))
        +          return rimraf(to).then(() => moveFile(from, to))
                 else
                   throw er
               })
        @@ -427,7 +430,7 @@ module.exports = cls => class Reifier extends cls {
             const dir = dirname(node.path)
             const target = node.realpath
             const rel = relative(dir, target)
        -    return symlink(rel, node.path, 'dir')
        +    return symlink(rel, node.path, 'junction')
           }
         
           [_warnDeprecated] (node) {
        @@ -436,23 +439,29 @@ module.exports = cls => class Reifier extends cls {
               this.log.warn('deprecated', `${_id}: ${deprecated}`)
           }
         
        -  [_loadAncientPackageDetails] (node) {
        +  async [_loadAncientPackageDetails] (node, forceReload = false) {
             // If we're loading from a v1 lockfile, load details from the package.json
             // that weren't recorded in the old format.
             const {meta} = this.idealTree
             const ancient = meta.ancientLockfile
             const old = meta.loadedFromDisk && !(meta.originalLockfileVersion >= 2)
        +
             // already replaced with the manifest if it's truly ancient
        -    if (old && !ancient) {
        +    if (node.path && (forceReload || (old && !ancient))) {
               // XXX should have a shared location where package.json is read,
               // so we don't ever read the same pj more than necessary.
        -      return rpj(node.path + '/package.json').then(pkg => {
        +      let pkg
        +      try {
        +        pkg = await rpj(node.path + '/package.json')
        +      } catch (err) {}
        +
        +      if (pkg) {
                 node.package.bin = pkg.bin
                 node.package.os = pkg.os
                 node.package.cpu = pkg.cpu
                 node.package.engines = pkg.engines
                 meta.add(node)
        -      })
        +      }
             }
           }
         
        @@ -839,12 +848,28 @@ module.exports = cls => class Reifier extends cls {
               format: (this[_formatPackageLock] && format) ? format
               : this[_formatPackageLock],
             }
        +
             return Promise.all([
        -      this[_usePackageLock] && this.idealTree.meta.save(saveOpt),
        +      this[_saveLockFile](saveOpt),
               writeFile(pj, json),
             ]).then(() => process.emit('timeEnd', 'reify:save'))
           }
         
        +  async [_saveLockFile] (saveOpt) {
        +    if (!this[_usePackageLock])
        +      return
        +
        +    const { meta } = this.idealTree
        +
        +    // might have to update metadata for bins and stuff that gets lost
        +    if (meta.loadedFromDisk && !(meta.originalLockfileVersion >= 2)) {
        +      for (const node of this.idealTree.inventory.values())
        +        await this[_loadAncientPackageDetails](node, true)
        +    }
        +
        +    return meta.save(saveOpt)
        +  }
        +
           [_copyIdealToActual] () {
             // save the ideal's meta as a hidden lockfile after we actualize it
             this.idealTree.meta.filename =
        diff --git a/deps/npm/node_modules/@npmcli/arborist/lib/node.js b/deps/npm/node_modules/@npmcli/arborist/lib/node.js
        index a783ce9c975722..e4ba3ac42bfc5f 100644
        --- a/deps/npm/node_modules/@npmcli/arborist/lib/node.js
        +++ b/deps/npm/node_modules/@npmcli/arborist/lib/node.js
        @@ -35,6 +35,7 @@ const {normalize} = require('read-package-json-fast')
         const {getPaths: getBinPaths} = require('bin-links')
         const npa = require('npm-package-arg')
         const debug = require('./debug.js')
        +const gatherDepSet = require('./gather-dep-set.js')
         
         const {resolve, relative, dirname, basename} = require('path')
         const _package = Symbol('_package')
        @@ -566,13 +567,32 @@ class Node {
             }
         
             debug(() => {
        -      if (!this.fsParent && this.realpath.indexOf(fsParent.realpath) !== 0)
        -        throw new Error('attempting to set fsParent improperly')
        +      if (fsParent === this)
        +        throw new Error('setting node to its own fsParent')
        +
        +      if (fsParent.realpath === this.realpath)
        +        throw new Error('setting fsParent to same path')
        +
        +      // the initial set MUST be an actual walk-up from the realpath
        +      // subsequent sets will re-root on the new fsParent's path.
        +      if (!this[_fsParent] && this.realpath.indexOf(fsParent.realpath) !== 0) {
        +        throw Object.assign(new Error('setting fsParent improperly'), {
        +          path: this.path,
        +          realpath: this.realpath,
        +          fsParent: {
        +            path: fsParent.path,
        +            realpath: fsParent.realpath,
        +          },
        +        })
        +      }
         
               if (fsParent.isLink)
        -        throw new Error('attempting to set fsParent to link node')
        +        throw new Error('setting fsParent to link node')
             })
         
        +    if (this === fsParent || fsParent.realpath === this.realpath)
        +      return
        +
             // prune off the original location, so we don't leave edges lying around
             if (current)
               this.fsParent = null
        @@ -621,8 +641,14 @@ class Node {
             if (node.name !== this.name)
               return false
         
        +    // gather up all the deps of this node and that are only depended
        +    // upon by deps of this node.  those ones don't count, since
        +    // they'll be replaced if this node is replaced anyway.
        +    const depSet = gatherDepSet([this], e => e.to !== this && e.valid)
        +
             for (const edge of this.edgesIn) {
        -      if (!edge.satisfiedBy(node))
        +      // only care about edges that don't originate from this node
        +      if (!depSet.has(edge.from) && !edge.satisfiedBy(node))
                 return false
             }
         
        @@ -731,6 +757,9 @@ class Node {
           set parent (parent) {
             const oldParent = this[_parent]
         
        +    if (this === parent)
        +      return
        +
             // link nodes can't contain children directly.
             // children go under the link target.
             if (parent) {
        diff --git a/deps/npm/node_modules/@npmcli/arborist/package.json b/deps/npm/node_modules/@npmcli/arborist/package.json
        index fe72f409c4a457..6dca9abe50110b 100644
        --- a/deps/npm/node_modules/@npmcli/arborist/package.json
        +++ b/deps/npm/node_modules/@npmcli/arborist/package.json
        @@ -1,11 +1,12 @@
         {
           "name": "@npmcli/arborist",
        -  "version": "1.0.8",
        +  "version": "1.0.11",
           "description": "Manage node_modules trees",
           "dependencies": {
             "@npmcli/installed-package-contents": "^1.0.5",
             "@npmcli/map-workspaces": "^1.0.1",
             "@npmcli/metavuln-calculator": "^1.0.0",
        +    "@npmcli/move-file": "^1.0.1",
             "@npmcli/name-from-folder": "^1.0.1",
             "@npmcli/node-gyp": "^1.0.0",
             "@npmcli/run-script": "^1.7.2",
        @@ -68,6 +69,7 @@
             "node-arg": [
               "--unhandled-rejections=strict"
             ],
        +    "after": "test/fixtures/cleanup.js",
             "coverage-map": "map.js",
             "esm": false,
             "timeout": "120"
        diff --git a/deps/npm/node_modules/@npmcli/run-script/lib/run-script-pkg.js b/deps/npm/node_modules/@npmcli/run-script/lib/run-script-pkg.js
        index 5980376f558f42..47f386304e4596 100644
        --- a/deps/npm/node_modules/@npmcli/run-script/lib/run-script-pkg.js
        +++ b/deps/npm/node_modules/@npmcli/run-script/lib/run-script-pkg.js
        @@ -20,6 +20,9 @@ const runScriptPkg = async options => {
             stdioString = false,
             // note: only used when stdio:inherit
             banner = true,
        +    // how long to wait for a process.kill signal
        +    // only exposed here so that we can make the test go a bit faster.
        +    signalTimeout = 500,
           } = options
         
           const {scripts = {}, gypfile} = pkg
        @@ -68,7 +71,17 @@ const runScriptPkg = async options => {
           if (p.stdin)
             p.stdin.end()
         
        -  return p
        +  return p.catch(er => {
        +    const { signal } = er
        +    if (stdio === 'inherit' && signal) {
        +      process.kill(process.pid, signal)
        +      // just in case we don't die, reject after 500ms
        +      // this also keeps the node process open long enough to actually
        +      // get the signal, rather than terminating gracefully.
        +      return new Promise((res, rej) => setTimeout(() => rej(er), signalTimeout))
        +    } else
        +      throw er
        +  })
         }
         
         module.exports = runScriptPkg
        diff --git a/deps/npm/node_modules/@npmcli/run-script/lib/run-script.js b/deps/npm/node_modules/@npmcli/run-script/lib/run-script.js
        index 3be39b0ba8076f..af33d2113f9ef0 100644
        --- a/deps/npm/node_modules/@npmcli/run-script/lib/run-script.js
        +++ b/deps/npm/node_modules/@npmcli/run-script/lib/run-script.js
        @@ -1,6 +1,7 @@
         const rpj = require('read-package-json-fast')
         const runScriptPkg = require('./run-script-pkg.js')
         const validateOptions = require('./validate-options.js')
        +const isServerPackage = require('./is-server-package.js')
         
         const runScript = options => {
           validateOptions(options)
        @@ -9,4 +10,4 @@ const runScript = options => {
             : rpj(path + '/package.json').then(pkg => runScriptPkg({...options, pkg}))
         }
         
        -module.exports = runScript
        +module.exports = Object.assign(runScript, { isServerPackage })
        diff --git a/deps/npm/node_modules/@npmcli/run-script/package.json b/deps/npm/node_modules/@npmcli/run-script/package.json
        index 5ec3bb5b66876e..c8a052f036763b 100644
        --- a/deps/npm/node_modules/@npmcli/run-script/package.json
        +++ b/deps/npm/node_modules/@npmcli/run-script/package.json
        @@ -1,6 +1,6 @@
         {
           "name": "@npmcli/run-script",
        -  "version": "1.7.4",
        +  "version": "1.7.5",
           "description": "Run a lifecycle script for a package (descendant of npm-lifecycle)",
           "author": "Isaac Z. Schlueter  (https://izs.me)",
           "license": "ISC",
        diff --git a/deps/npm/node_modules/libnpmversion/lib/version.js b/deps/npm/node_modules/libnpmversion/lib/version.js
        index ee02fb7ffb9d0a..309b9c2b9504f0 100644
        --- a/deps/npm/node_modules/libnpmversion/lib/version.js
        +++ b/deps/npm/node_modules/libnpmversion/lib/version.js
        @@ -34,7 +34,7 @@ module.exports = async (newversion, opts) => {
           } = opts
         
           const { valid, clean, inc } = semver
        -  const current = pkg.version
        +  const current = pkg.version || '0.0.0'
           const currentClean = clean(current)
         
           const newV = valid(newversion, { loose: true }) ? clean(newversion, { loose: true })
        diff --git a/deps/npm/node_modules/libnpmversion/package.json b/deps/npm/node_modules/libnpmversion/package.json
        index 856e36da6d564d..d7e8d5fa586476 100644
        --- a/deps/npm/node_modules/libnpmversion/package.json
        +++ b/deps/npm/node_modules/libnpmversion/package.json
        @@ -1,6 +1,6 @@
         {
           "name": "libnpmversion",
        -  "version": "1.0.6",
        +  "version": "1.0.7",
           "main": "lib/index.js",
           "files": [
             "lib/*.js"
        diff --git a/deps/npm/node_modules/pacote/lib/fetcher.js b/deps/npm/node_modules/pacote/lib/fetcher.js
        index 01058acb2bfef7..5142bb280a70c7 100644
        --- a/deps/npm/node_modules/pacote/lib/fetcher.js
        +++ b/deps/npm/node_modules/pacote/lib/fetcher.js
        @@ -91,18 +91,11 @@ class FetcherBase {
         
             // command to run 'prepare' scripts on directories and git dirs
             // To use pacote with yarn, for example, set npmBin to 'yarn'
        -    // and npmInstallCmd to ['add'], and npmCliConfig with yarn's equivalents.
        +    // and npmCliConfig with yarn's equivalents.
             this.npmBin = opts.npmBin || 'npm'
         
             // command to install deps for preparing
        -    this.npmInstallCmd = opts.npmInstallCmd || [
        -      'install',
        -      '--only=dev',
        -      '--prod',
        -      '--ignore-prepublish',
        -      '--no-progress',
        -      '--no-save',
        -    ]
        +    this.npmInstallCmd = opts.npmInstallCmd || [ 'install' ]
         
             // XXX fill more of this in based on what we know from this.opts
             // we explicitly DO NOT fill in --tag, though, since we are often
        @@ -113,7 +106,10 @@ class FetcherBase {
               `--prefer-offline=${!!this.preferOffline}`,
               `--prefer-online=${!!this.preferOnline}`,
               `--offline=${!!this.offline}`,
        -      `--before=${this.before ? this.before.toISOString() : ''}`,
        +      ...(this.before ? [`--before=${this.before.toISOString()}`] : []),
        +      '--no-progress',
        +      '--no-save',
        +      '--no-audit',
             ]
           }
         
        diff --git a/deps/npm/node_modules/pacote/package.json b/deps/npm/node_modules/pacote/package.json
        index 7f38a193f7cb94..bef19b66228a66 100644
        --- a/deps/npm/node_modules/pacote/package.json
        +++ b/deps/npm/node_modules/pacote/package.json
        @@ -1,6 +1,6 @@
         {
           "name": "pacote",
        -  "version": "11.1.12",
        +  "version": "11.1.13",
           "description": "JavaScript package downloader",
           "author": "Isaac Z. Schlueter  (https://izs.me)",
           "bin": {
        @@ -47,7 +47,7 @@
             "minipass": "^3.1.3",
             "mkdirp": "^1.0.3",
             "npm-package-arg": "^8.0.1",
        -    "npm-packlist": "^2.1.0",
        +    "npm-packlist": "^2.1.4",
             "npm-pick-manifest": "^6.0.0",
             "npm-registry-fetch": "^9.0.0",
             "promise-retry": "^1.1.1",
        diff --git a/deps/npm/package.json b/deps/npm/package.json
        index d0ca0bf91a7dd5..5dfcd6807f2653 100644
        --- a/deps/npm/package.json
        +++ b/deps/npm/package.json
        @@ -1,5 +1,5 @@
         {
        -  "version": "7.0.8",
        +  "version": "7.0.11",
           "name": "npm",
           "description": "a package manager for JavaScript",
           "keywords": [
        @@ -42,10 +42,10 @@
             "./package.json": "./package.json"
           },
           "dependencies": {
        -    "@npmcli/arborist": "^1.0.8",
        +    "@npmcli/arborist": "^1.0.11",
             "@npmcli/ci-detect": "^1.2.0",
             "@npmcli/config": "^1.2.1",
        -    "@npmcli/run-script": "^1.7.4",
        +    "@npmcli/run-script": "^1.7.5",
             "abbrev": "~1.1.1",
             "ansicolors": "~0.3.2",
             "ansistyles": "~0.1.3",
        @@ -76,7 +76,7 @@
             "libnpmpublish": "^4.0.0",
             "libnpmsearch": "^3.0.1",
             "libnpmteam": "^2.0.2",
        -    "libnpmversion": "^1.0.6",
        +    "libnpmversion": "^1.0.7",
             "make-fetch-happen": "^8.0.9",
             "mkdirp": "^1.0.4",
             "mkdirp-infer-owner": "^2.0.0",
        @@ -92,7 +92,7 @@
             "npm-user-validate": "^1.0.1",
             "npmlog": "~4.1.2",
             "opener": "^1.5.2",
        -    "pacote": "^11.1.12",
        +    "pacote": "^11.1.13",
             "parse-conflict-json": "^1.1.1",
             "qrcode-terminal": "^0.12.0",
             "read": "~1.0.7",
        @@ -180,12 +180,12 @@
             "write-file-atomic"
           ],
           "devDependencies": {
        -    "cmark-gfm": "^0.8.3",
        -    "eslint": "^7.12.1",
        +    "cmark-gfm": "^0.8.4",
        +    "eslint": "^7.13.0",
             "eslint-plugin-import": "^2.22.1",
             "eslint-plugin-node": "^11.1.0",
             "eslint-plugin-promise": "^4.2.1",
        -    "eslint-plugin-standard": "^4.0.2",
        +    "eslint-plugin-standard": "^4.1.0",
             "jsdom": "^16.4.0",
             "marked-man": "^0.7.0",
             "require-inject": "^1.4.4",
        diff --git a/deps/npm/scripts/install.sh b/deps/npm/scripts/install.sh
        index 7f66151daea033..4458de87faefbe 100755
        --- a/deps/npm/scripts/install.sh
        +++ b/deps/npm/scripts/install.sh
        @@ -8,7 +8,7 @@
         # shell living at /bin/sh.
         #
         # See this helpful document on writing portable shell scripts:
        -# https://www.gnu.org/s/hello/manual/autoconf/Portable-Shell.html
        +# http://www.gnu.org/s/hello/manual/autoconf/Portable-Shell.html
         #
         # The only shell it won't ever work on is cmd.exe.
         
        @@ -23,32 +23,27 @@ if [ "x$0" = "xsh" ]; then
           if [ $ret -eq 0 ]; then
             (exit 0)
           else
        -    echo "Uninstalling npm-install-$$.sh" >&2
             rm npm-install-$$.sh
        -    echo "Failed to download script" >&2
        +    echo "failed to download script" >&2
             exit $ret
           fi
           sh npm-install-$$.sh
           ret=$?
        -  echo "Uninstalling npm-install-$$.sh" >&2
           rm npm-install-$$.sh
           exit $ret
         fi
         
        -# See what "npm_config_*" things there are in the env,
        -# and make them permanent.
        -# If this fails, it's not such a big deal.
        -configures="`env | grep 'npm_config_' | sed -e 's|^npm_config_||g'`"
        -
        +debug=0
         npm_config_loglevel="error"
         if [ "x$npm_debug" = "x" ]; then
           (exit 0)
         else
        -  echo "Running in debug mode."
        -  echo "Note that this requires bash or zsh."
        +  echo "running in debug mode."
        +  echo "note that this requires bash or zsh."
           set -o xtrace
           set -o pipefail
           npm_config_loglevel="verbose"
        +  debug=1
         fi
         export npm_config_loglevel
         
        @@ -61,33 +56,20 @@ if [ $ret -ne 0 ]; then
           ret=$?
         fi
         if [ $ret -eq 0 ] && [ -x "$node" ]; then
        +  if [ $debug -eq 1 ]; then
        +    echo "found 'node' at: $node"
        +    echo -n "version: "
        +    $node --version
        +    echo ""
        +  fi
           (exit 0)
         else
           echo "npm cannot be installed without node.js." >&2
        -  echo "Install node first, and then try again." >&2
        +  echo "install node first, and then try again." >&2
           echo "" >&2
        -  echo "Maybe node is installed, but not in the PATH?" >&2
        -  echo "Note that running as sudo can change envs." >&2
        -  echo ""
        -  echo "PATH=$PATH" >&2
           exit $ret
         fi
         
        -# set the temp dir
        -TMP="${TMPDIR}"
        -if [ "x$TMP" = "x" ]; then
        -  TMP="/tmp"
        -fi
        -TMP="${TMP}/npm.$$"
        -rm -rf "$TMP" || true
        -mkdir "$TMP"
        -if [ $? -ne 0 ]; then
        -  echo "failed to mkdir $TMP" >&2
        -  exit 1
        -fi
        -
        -BACK="$PWD"
        -
         ret=0
         tar="${TAR}"
         if [ -z "$tar" ]; then
        @@ -99,10 +81,11 @@ if [ -z "$tar" ]; then
         fi
         
         if [ $ret -eq 0 ] && [ -x "$tar" ]; then
        -  echo "tar=$tar"
        -  if [ $tar --version > /dev/null 2>&1 ]; then
        -    echo "version:"
        +  if [ $debug -eq 1 ]; then
        +    echo "found 'tar' at: $tar"
        +    echo -n "version: "
             $tar --version
        +    echo ""
           fi
           ret=$?
         fi
        @@ -110,76 +93,43 @@ fi
         if [ $ret -eq 0 ]; then
           (exit 0)
         else
        -  echo "No suitable tar program found."
        +  echo "this script requires 'tar', please install it and try again."
           exit 1
         fi
         
        -
        -
        -# Try to find a suitable make
        -# If the MAKE environment var is set, use that.
        -# otherwise, try to find gmake, and then make.
        -# If no make is found, then just execute the necessary commands.
        -
        -# XXX For some reason, make is building all the docs every time.  This
        -# is an annoying source of bugs. Figure out why this happens.
        -MAKE=NOMAKE
        -
        -if [ "x$MAKE" = "x" ]; then
        -  make=`which gmake 2>&1`
        -  if [ $? -eq 0 ] && [ -x "$make" ]; then
        -    (exit 0)
        -  else
        -    make=`which make 2>&1`
        -    if [ $? -eq 0 ] && [ -x "$make" ]; then
        -      (exit 0)
        -    else
        -      make=NOMAKE
        -    fi
        +curl=`which curl 2>&1`
        +ret=$?
        +if [ $ret -eq 0 ]; then
        +  if [ $debug -eq 1 ]; then
        +    echo "found 'curl' at: $curl"
        +    echo -n "version: "
        +    $curl --version | head -n 1
        +    echo ""
           fi
        -else
        -  make="$MAKE"
        -fi
        -
        -if [ -x "$make" ]; then
           (exit 0)
         else
        -  # echo "Installing without make. This may fail." >&2
        -  make=NOMAKE
        +  echo "this script requires 'curl', please install it and try again."
        +  exit 1
         fi
         
        -# If there's no bash, then don't even try to clean
        -if [ -x "/bin/bash" ]; then
        -  (exit 0)
        -else
        -  clean="no"
        +# set the temp dir
        +TMP="${TMPDIR}"
        +if [ "x$TMP" = "x" ]; then
        +  TMP="/tmp"
         fi
        -
        -node_version=`"$node" --version 2>&1`
        -ret=$?
        -if [ $ret -ne 0 ]; then
        -  echo "You need node to run this program." >&2
        -  echo "node --version reports: $node_version" >&2
        -  echo "with exit code = $ret" >&2
        -  echo "Please install node before continuing." >&2
        -  exit $ret
        +TMP="${TMP}/npm.$$"
        +rm -rf "$TMP" || true
        +mkdir "$TMP"
        +if [ $? -ne 0 ]; then
        +  echo "failed to mkdir $TMP" >&2
        +  exit 1
         fi
         
        +BACK="$PWD"
        +
         t="${npm_install}"
         if [ -z "$t" ]; then
        -  # switch based on node version.
        -  # note that we can only use strict sh-compatible patterns here.
        -  case $node_version in
        -    0.[01234567].* | v0.[01234567].*)
        -      echo "You are using an outdated and unsupported version of" >&2
        -      echo "node ($node_version).  Please update node and try again." >&2
        -      exit 99
        -      ;;
        -    *)
        -      echo "install npm@latest"
        -      t="latest"
        -      ;;
        -  esac
        +  t="latest"
         fi
         
         # need to echo "" after, because Posix sed doesn't treat EOF
        @@ -201,7 +151,7 @@ if [ "x$url" = "x" ]; then
           fi
         fi
         if [ $ret -ne 0 ]; then
        -  echo "Failed to get tarball url for npm/$t" >&2
        +  echo "failed to get tarball url for npm/$t" >&2
           exit $ret
         fi
         
        @@ -209,37 +159,19 @@ fi
         echo "fetching: $url" >&2
         
         cd "$TMP" \
        -  && curl -SsL "$url" \
        -     | $tar -xzf - \
        -  && cd "$TMP"/* \
        -  && (ret=0
        -      if [ $ret -ne 0 ]; then
        -        echo "Aborted 0.x cleanup.  Exiting." >&2
        -        exit $ret
        -      fi) \
        -  && (if [ "x$configures" = "x" ]; then
        -        (exit 0)
        -      else
        -        echo "./configure $configures"
        -        echo "$configures" > npmrc
        -      fi) \
        -  && (if [ "$make" = "NOMAKE" ]; then
        -        (exit 0)
        -      elif "$make" uninstall install; then
        -        (exit 0)
        -      else
        -        make="NOMAKE"
        -      fi
        -      if [ "$make" = "NOMAKE" ]; then
        -        "$node" bin/npm-cli.js rm npm -gf
        -        "$node" bin/npm-cli.js install -gf $("$node" bin/npm-cli.js pack | tail -1)
        -      fi) \
        +  && curl -SsL -o npm.tgz "$url" \
        +  && $tar -xzf npm.tgz \
        +  && cd "$TMP"/package \
        +  && echo "removing existing npm" \
        +  && "$node" bin/npm-cli.js rm npm -gf --loglevel=silent \
        +  && echo "installing npm@$t" \
        +  && "$node" bin/npm-cli.js install -gf ../npm.tgz \
           && cd "$BACK" \
           && rm -rf "$TMP" \
        -  && echo "It worked"
        +  && echo "successfully installed npm@$t"
         
         ret=$?
         if [ $ret -ne 0 ]; then
        -  echo "It failed" >&2
        +  echo "failed!" >&2
         fi
         exit $ret
        diff --git a/deps/npm/tap-snapshots/test-lib-utils-config.js-TAP.test.js b/deps/npm/tap-snapshots/test-lib-utils-config.js-TAP.test.js
        index 5190a5604a2407..3bdf905d869e6a 100644
        --- a/deps/npm/tap-snapshots/test-lib-utils-config.js-TAP.test.js
        +++ b/deps/npm/tap-snapshots/test-lib-utils-config.js-TAP.test.js
        @@ -8,6 +8,7 @@
         exports[`test/lib/utils/config.js TAP no process.umask() method > must match snapshot 1`] = `
         Object {
           "defaults": Object {
        +    "_auth": null,
             "access": null,
             "all": false,
             "allow-same-version": false,
        @@ -267,6 +268,10 @@ Object {
             ],
           },
           "types": Object {
        +    "_auth": Array [
        +      null,
        +      "{String TYPE}",
        +    ],
             "access": Array [
               null,
               "restricted",
        @@ -537,6 +542,7 @@ Object {
         exports[`test/lib/utils/config.js TAP no working network interfaces, on windows > must match snapshot 1`] = `
         Object {
           "defaults": Object {
        +    "_auth": null,
             "access": null,
             "all": false,
             "allow-same-version": false,
        @@ -796,6 +802,10 @@ Object {
             ],
           },
           "types": Object {
        +    "_auth": Array [
        +      null,
        +      "{String TYPE}",
        +    ],
             "access": Array [
               null,
               "restricted",
        @@ -1066,6 +1076,7 @@ Object {
         exports[`test/lib/utils/config.js TAP working network interfaces, not windows > must match snapshot 1`] = `
         Object {
           "defaults": Object {
        +    "_auth": null,
             "access": null,
             "all": false,
             "allow-same-version": false,
        @@ -1325,6 +1336,10 @@ Object {
             ],
           },
           "types": Object {
        +    "_auth": Array [
        +      null,
        +      "{String TYPE}",
        +    ],
             "access": Array [
               null,
               "restricted",
        diff --git a/deps/npm/tap-snapshots/test-lib-utils-explain-dep.js-TAP.test.js b/deps/npm/tap-snapshots/test-lib-utils-explain-dep.js-TAP.test.js
        index 48f84e5111821f..54a77bc122b4db 100644
        --- a/deps/npm/tap-snapshots/test-lib-utils-explain-dep.js-TAP.test.js
        +++ b/deps/npm/tap-snapshots/test-lib-utils-explain-dep.js-TAP.test.js
        @@ -10,7 +10,7 @@ manydep@1.0.0
           manydep@"1.0.0" from prod-dep@1.2.3
           node_modules/prod-dep
             prod-dep@"1.x" from the root project
        -  6 more (optdep, extra-neos, deep-dev, peer, ...)
        +  7 more (optdep, extra-neos, deep-dev, peer, the root project, ...)
         `
         
         exports[`test/lib/utils/explain-dep.js TAP > ellipses test two 1`] = `
        @@ -18,7 +18,7 @@ manydep@1.0.0
           manydep@"1.0.0" from prod-dep@1.2.3
           node_modules/prod-dep
             prod-dep@"1.x" from the root project
        -  5 more (optdep, extra-neos, deep-dev, peer, a package with a pretty long name)
        +  6 more (optdep, extra-neos, deep-dev, peer, the root project, a package with a pretty long name)
         `
         
         exports[`test/lib/utils/explain-dep.js TAP deepDev > explain color deep 1`] = `
        @@ -90,6 +90,7 @@ exports[`test/lib/utils/explain-dep.js TAP manyDeps > explain color deep 1`] = `
           peer manydep@">1.0.0-beta <1.0.1" from peer@1.0.0 peer
           node_modules/peer
             peer peer@"1.0.0" from the root project
        +  manydep@">1.0.0-beta <1.0.1" from the root project
           manydep@"1" from a package with a pretty long name@1.2.3
           manydep@"1" from another package with a pretty long name@1.2.3
           manydep@"1" from yet another a package with a pretty long name@1.2.3
        @@ -100,7 +101,7 @@ manydep@1.0.0
           manydep@"1.0.0" from prod-dep@1.2.3
           node_modules/prod-dep
             prod-dep@"1.x" from the root project
        -  7 more (optdep, extra-neos, deep-dev, peer, ...)
        +  8 more (optdep, extra-neos, deep-dev, peer, the root project, ...)
         `
         
         exports[`test/lib/utils/explain-dep.js TAP manyDeps > print color 1`] = `
        diff --git a/deps/npm/tap-snapshots/test-lib-utils-flat-options.js-TAP.test.js b/deps/npm/tap-snapshots/test-lib-utils-flat-options.js-TAP.test.js
        index 0e6c053b2f452e..6890338a131115 100644
        --- a/deps/npm/tap-snapshots/test-lib-utils-flat-options.js-TAP.test.js
        +++ b/deps/npm/tap-snapshots/test-lib-utils-flat-options.js-TAP.test.js
        @@ -7,6 +7,7 @@
         'use strict'
         exports[`test/lib/utils/flat-options.js TAP basic > flat options 1`] = `
         Object {
        +  "_auth": undefined,
           "@scope:registry": "@scope:registry",
           "//nerf.dart:_authToken": "//nerf.dart:_authToken",
           "access": "access",
        diff --git a/deps/npm/test/lib/adduser.js b/deps/npm/test/lib/adduser.js
        index 4d2233b18ce6c0..22c7c49cfaeafd 100644
        --- a/deps/npm/test/lib/adduser.js
        +++ b/deps/npm/test/lib/adduser.js
        @@ -13,6 +13,7 @@ const _flatOptions = {
         
         let failSave = false
         let deletedConfig = {}
        +let registryOutput = ''
         let setConfig = {}
         const authDummy = () => Promise.resolve({
           message: 'success',
        @@ -32,7 +33,10 @@ const deleteMock = (key, where) => {
         }
         const adduser = requireInject('../../lib/adduser.js', {
           npmlog: {
        -    disableProgress: () => null
        +    disableProgress: () => null,
        +    notice: (_, msg) => {
        +      registryOutput = msg
        +    },
           },
           '../../lib/npm.js': {
             flatOptions: _flatOptions,
        @@ -69,6 +73,12 @@ test('simple login', (t) => {
           adduser([], (err) => {
             t.ifError(err, 'npm adduser')
         
        +    t.equal(
        +      registryOutput,
        +      'Log in on https://registry.npmjs.org/',
        +      'should have correct message result'
        +    )
        +
             t.deepEqual(
               deletedConfig,
               {
        @@ -102,6 +112,7 @@ test('simple login', (t) => {
               'should output auth success msg'
             )
         
        +    registryOutput = ''
             deletedConfig = {}
             setConfig = {}
             result = ''
        diff --git a/deps/npm/test/lib/cache.js b/deps/npm/test/lib/cache.js
        new file mode 100644
        index 00000000000000..9c27386ed8fe19
        --- /dev/null
        +++ b/deps/npm/test/lib/cache.js
        @@ -0,0 +1,232 @@
        +const t = require('tap')
        +const requireInject = require('require-inject')
        +const path = require('path')
        +
        +const usageUtil = () => 'usage instructions'
        +
        +const flatOptions = {
        +  force: false
        +}
        +
        +const npm = {
        +  flatOptions,
        +  cache: '/fake/path'
        +}
        +
        +let rimrafPath = ''
        +const rimraf = (path, cb) => {
        +  rimrafPath = path
        +  return cb()
        +}
        +
        +let logOutput = []
        +const npmlog = {
        +  silly: (...args) => {
        +    logOutput.push(['silly', ...args])
        +  }
        +}
        +
        +let tarballStreamSpec = ''
        +let tarballStreamOpts = {}
        +const pacote = {
        +  tarball: {
        +    stream: (spec, cb, opts) => {
        +      tarballStreamSpec = spec
        +      tarballStreamOpts = opts
        +      return cb({
        +        resume: () => {},
        +        promise: () => Promise.resolve()
        +      })
        +    }
        +  }
        +}
        +
        +let outputOutput = []
        +const output = (msg) => {
        +  outputOutput.push(msg)
        +}
        +
        +let cacacheVerifyPath = ''
        +const cacacheVerifyStats = {
        +  keptSize: 100,
        +  verifiedContent: 1,
        +  totalEntries: 1,
        +  runTime: { total: 2000 }
        +}
        +const cacache = {
        +  verify: (path) => {
        +    cacacheVerifyPath = path
        +    return cacacheVerifyStats
        +  }
        +}
        +
        +const mocks = {
        +  cacache,
        +  npmlog,
        +  pacote,
        +  rimraf,
        +  '../../lib/npm.js': npm,
        +  '../../lib/utils/output.js': output,
        +  '../../lib/utils/usage.js': usageUtil
        +}
        +
        +const cache = requireInject('../../lib/cache.js', mocks)
        +
        +t.test('cache no args', t => {
        +  cache([], err => {
        +    t.equal(err.message, 'usage instructions', 'should throw usage instructions')
        +    t.end()
        +  })
        +})
        +
        +t.test('cache clean', t => {
        +  cache(['clean'], err => {
        +    t.match(err.message, 'the npm cache self-heals', 'should throw warning')
        +    t.end()
        +  })
        +})
        +
        +t.test('cache clean (force)', t => {
        +  flatOptions.force = true
        +  t.teardown(() => {
        +    rimrafPath = ''
        +    flatOptions.force = false
        +  })
        +
        +  cache(['clear'], err => {
        +    t.ifError(err)
        +    t.equal(rimrafPath, path.join(npm.cache, '_cacache'))
        +    t.end()
        +  })
        +})
        +
        +t.test('cache clean with arg', t => {
        +  cache(['rm', 'pkg'], err => {
        +    t.match(err.message, 'does not accept arguments', 'should throw error')
        +    t.end()
        +  })
        +})
        +
        +t.test('cache add no arg', t => {
        +  t.teardown(() => {
        +    logOutput = []
        +  })
        +
        +  cache(['add'], err => {
        +    t.strictSame(logOutput, [
        +      ['silly', 'cache add', 'args', []],
        +    ], 'logs correctly')
        +    t.equal(err.code, 'EUSAGE', 'throws usage error')
        +    t.end()
        +  })
        +})
        +
        +t.test('cache add pkg only', t => {
        +  t.teardown(() => {
        +    logOutput = []
        +    tarballStreamSpec = ''
        +    tarballStreamOpts = {}
        +  })
        +
        +  cache(['add', 'mypkg'], err => {
        +    t.ifError(err)
        +    t.strictSame(logOutput, [
        +      ['silly', 'cache add', 'args', ['mypkg']],
        +      ['silly', 'cache add', 'spec', 'mypkg']
        +    ], 'logs correctly')
        +    t.equal(tarballStreamSpec, 'mypkg', 'passes the correct spec to pacote')
        +    t.same(tarballStreamOpts, flatOptions, 'passes the correct options to pacote')
        +    t.end()
        +  })
        +})
        +
        +t.test('cache add pkg w/ spec modifier', t => {
        +  t.teardown(() => {
        +    logOutput = []
        +    tarballStreamSpec = ''
        +    tarballStreamOpts = {}
        +  })
        +
        +  cache(['add', 'mypkg', 'latest'], err => {
        +    t.ifError(err)
        +    t.strictSame(logOutput, [
        +      ['silly', 'cache add', 'args', ['mypkg', 'latest']],
        +      ['silly', 'cache add', 'spec', 'mypkg@latest']
        +    ], 'logs correctly')
        +    t.equal(tarballStreamSpec, 'mypkg@latest', 'passes the correct spec to pacote')
        +    t.same(tarballStreamOpts, flatOptions, 'passes the correct options to pacote')
        +    t.end()
        +  })
        +})
        +
        +t.test('cache verify', t => {
        +  t.teardown(() => {
        +    outputOutput = []
        +    cacacheVerifyPath = ''
        +  })
        +
        +  cache(['verify'], err => {
        +    t.ifError(err)
        +    t.match(outputOutput, [
        +      `Cache verified and compressed (${path.join(npm.cache, '_cacache')})`,
        +      'Content verified: 1 (100 bytes)',
        +      'Index entries: 1',
        +      'Finished in 2s'
        +    ], 'prints correct output')
        +    t.end()
        +  })
        +})
        +
        +t.test('cache verify w/ extra output', t => {
        +  npm.cache = `${process.env.HOME}/fake/path`
        +  cacacheVerifyStats.badContentCount = 1
        +  cacacheVerifyStats.reclaimedCount = 2
        +  cacacheVerifyStats.reclaimedSize = 200
        +  cacacheVerifyStats.missingContent = 3
        +  t.teardown(() => {
        +    npm.cache = '/fake/path'
        +    outputOutput = []
        +    cacacheVerifyPath = ''
        +    delete cacacheVerifyStats.badContentCount
        +    delete cacacheVerifyStats.reclaimedCount
        +    delete cacacheVerifyStats.reclaimedSize
        +    delete cacacheVerifyStats.missingContent
        +  })
        +
        +  cache(['check'], err => {
        +    t.ifError(err)
        +    t.match(outputOutput, [
        +      `Cache verified and compressed (~${path.join('/fake/path', '_cacache')})`,
        +      'Content verified: 1 (100 bytes)',
        +      'Corrupted content removed: 1',
        +      'Content garbage-collected: 2 (200 bytes)',
        +      'Missing content: 3',
        +      'Index entries: 1',
        +      'Finished in 2s'
        +    ], 'prints correct output')
        +    t.end()
        +  })
        +})
        +
        +t.test('cache completion', t => {
        +  const { completion } = cache
        +
        +  const testComp = (argv, expect) => {
        +    completion({ conf: { argv: { remain: argv } } }, (err, res) => {
        +      t.ifError(err)
        +      t.strictSame(res, expect, argv.join(' '))
        +    })
        +  }
        +
        +  testComp(['npm', 'cache'], [
        +    'add',
        +    'clean',
        +    'verify'
        +  ])
        +
        +  testComp(['npm', 'cache', 'add'], [])
        +  testComp(['npm', 'cache', 'clean'], [])
        +  testComp(['npm', 'cache', 'verify'], [])
        +
        +  t.end()
        +})
        diff --git a/deps/npm/test/lib/ci.js b/deps/npm/test/lib/ci.js
        index 645fc6aed97e4f..43ad2783b02d76 100644
        --- a/deps/npm/test/lib/ci.js
        +++ b/deps/npm/test/lib/ci.js
        @@ -42,6 +42,25 @@ test('should use Arborist', (t) => {
           })
         })
         
        +test('should pass flatOptions to Arborist.reify', (t) => {
        +  const ci = requireInject('../../lib/ci.js', {
        +    '../../lib/npm.js': {
        +      prefix: 'foo',
        +      flatOptions: {
        +        production: true
        +      }
        +    },
        +    '@npmcli/arborist': function () {
        +      this.loadVirtual = () => Promise.resolve(true)
        +      this.reify = async (options) => {
        +        t.equal(options.production, true, 'should pass flatOptions to Arborist.reify')
        +        t.end()
        +      }
        +    }
        +  })
        +  ci(null, () => {})
        +})
        +
         test('should throw if package-lock.json or npm-shrinkwrap missing', (t) => {
           const testDir = t.testdir({
             'index.js': 'some contents',
        diff --git a/deps/npm/test/lib/exec.js b/deps/npm/test/lib/exec.js
        index fb89776b55eaf9..08592353ce36c2 100644
        --- a/deps/npm/test/lib/exec.js
        +++ b/deps/npm/test/lib/exec.js
        @@ -386,6 +386,75 @@ t.test('npm exec @foo/bar -- --some=arg, locally installed', async t => {
           }])
         })
         
        +t.test('npm exec @foo/bar, with same bin alias and no unscoped named bin, locally installed', async t => {
        +  const foobarManifest = {
        +    name: '@foo/bar',
        +    version: '1.2.3',
        +    bin: {
        +      baz: 'corge', // pick the first one
        +      qux: 'corge',
        +      quux: 'corge',
        +    }
        +  }
        +  const path = t.testdir({
        +    node_modules: {
        +      '@foo/bar': {
        +        'package.json': JSON.stringify(foobarManifest)
        +      }
        +    }
        +  })
        +  npm.localPrefix = path
        +  ARB_ACTUAL_TREE[path] = {
        +    children: new Map([['@foo/bar', { name: '@foo/bar', version: '1.2.3' }]])
        +  }
        +  MANIFESTS['@foo/bar'] = foobarManifest
        +  await exec(['@foo/bar'], er => {
        +    if (er) {
        +      throw er
        +    }
        +  })
        +  t.strictSame(MKDIRPS, [], 'no need to make any dirs')
        +  t.match(ARB_CTOR, [ { package: ['@foo/bar'], path } ])
        +  t.strictSame(ARB_REIFY, [], 'no need to reify anything')
        +  t.equal(PROGRESS_ENABLED, true, 'progress re-enabled')
        +  t.match(RUN_SCRIPTS, [{
        +    pkg: { scripts: { npx: 'baz' } },
        +    banner: false,
        +    path: process.cwd(),
        +    stdioString: true,
        +    event: 'npx',
        +    env: { PATH: process.env.PATH },
        +    stdio: 'inherit'
        +  }])
        +})
        +
        +t.test('npm exec @foo/bar, with different bin alias and no unscoped named bin, locally installed', t => {
        +  const path = t.testdir()
        +  npm.localPrefix = path
        +  ARB_ACTUAL_TREE[path] = {
        +    children: new Map([['@foo/bar', { name: '@foo/bar', version: '1.2.3' }]])
        +  }
        +  MANIFESTS['@foo/bar'] = {
        +    name: '@foo/bar',
        +    version: '1.2.3',
        +    bin: {
        +      foo: 'qux',
        +      corge: 'qux',
        +      baz: 'quux',
        +    },
        +    _from: 'foo@',
        +    _id: '@foo/bar@1.2.3'
        +  }
        +  return t.rejects(exec(['@foo/bar'], er => {
        +    if (er) {
        +      throw er
        +    }
        +  }), {
        +    message: 'could not determine executable to run',
        +    pkgid: '@foo/bar@1.2.3'
        +  })
        +})
        +
         t.test('run command with 2 packages, need install, verify sort', t => {
           // test both directions, should use same install dir both times
           // also test the read() call here, verify that the prompts match
        diff --git a/deps/npm/test/lib/npm.js b/deps/npm/test/lib/npm.js
        index b2be5543fa1ea6..f6a13b90fa5e3c 100644
        --- a/deps/npm/test/lib/npm.js
        +++ b/deps/npm/test/lib/npm.js
        @@ -256,7 +256,10 @@ t.test('npm.load', t => {
               '--prefix', dir,
               '--userconfig', `${dir}/.npmrc`,
               '--usage',
        -      '--scope=foo'
        +      '--scope=foo',
        +      'token',
        +      'revoke',
        +      'blergggg',
             ]
         
             freshConfig()
        @@ -353,3 +356,91 @@ t.test('loading as main will load the cli', t => {
             t.end()
           })
         })
        +
        +t.test('set process.title', t => {
        +  const { execPath, argv: processArgv } = process
        +  const { log } = console
        +  const titleDesc = Object.getOwnPropertyDescriptor(process, 'title')
        +  Object.defineProperty(process, 'title', {
        +    value: '',
        +    settable: true,
        +    enumerable: true,
        +    configurable: true,
        +  })
        +  const consoleLogs = []
        +  console.log = (...msg) => consoleLogs.push(msg)
        +
        +  t.teardown(() => {
        +    console.log = log
        +    process.argv = processArgv
        +    Object.defineProperty(process, 'title', titleDesc)
        +    freshConfig()
        +  })
        +
        +  t.afterEach(cb => {
        +    consoleLogs.length = 0
        +    cb()
        +  })
        +
        +  t.test('basic title setting', async t => {
        +    freshConfig({
        +      argv: [
        +        process.execPath,
        +        process.argv[1],
        +        '--metrics-registry', 'http://example.com',
        +        '--usage',
        +        '--scope=foo',
        +        'ls',
        +      ],
        +    })
        +    await npm.load(er => {
        +      if (er)
        +        throw er
        +      t.equal(npm.title, 'npm ls')
        +      t.equal(process.title, 'npm ls')
        +    })
        +  })
        +
        +  t.test('do not expose token being revoked', async t => {
        +    freshConfig({
        +      argv: [
        +        process.execPath,
        +        process.argv[1],
        +        '--metrics-registry', 'http://example.com',
        +        '--usage',
        +        '--scope=foo',
        +        'token',
        +        'revoke',
        +        'deadbeefcafebad',
        +      ],
        +    })
        +    await npm.load(er => {
        +      if (er)
        +        throw er
        +      t.equal(npm.title, 'npm token revoke ***')
        +      t.equal(process.title, 'npm token revoke ***')
        +    })
        +  })
        +
        +  t.test('do show *** unless a token is actually being revoked', async t => {
        +    freshConfig({
        +      argv: [
        +        process.execPath,
        +        process.argv[1],
        +        '--metrics-registry', 'http://example.com',
        +        '--usage',
        +        '--scope=foo',
        +        'token',
        +        'revoke',
        +      ],
        +    })
        +    await npm.load(er => {
        +      if (er)
        +        throw er
        +      t.equal(npm.title, 'npm token revoke')
        +      t.equal(process.title, 'npm token revoke')
        +    })
        +  })
        +
        +  t.end()
        +})
        diff --git a/deps/npm/test/lib/run-script.js b/deps/npm/test/lib/run-script.js
        index 7a034aff01561b..7ddb6ff6f63a56 100644
        --- a/deps/npm/test/lib/run-script.js
        +++ b/deps/npm/test/lib/run-script.js
        @@ -25,9 +25,11 @@ const output = []
         
         const npmlog = { level: 'warn' }
         const getRS = windows => requireInject('../../lib/run-script.js', {
        -  '@npmcli/run-script': async opts => {
        +  '@npmcli/run-script': Object.assign(async opts => {
             RUN_SCRIPTS.push(opts)
        -  },
        +  }, {
        +    isServerPackage: require('@npmcli/run-script').isServerPackage,
        +  }),
           npmlog,
           '../../lib/npm.js': npm,
           '../../lib/utils/is-windows-shell.js': windows,
        @@ -90,10 +92,29 @@ t.test('fail if no package.json', async t => {
           await runScript(['test'], er => t.match(er, { code: 'ENOENT' }))
         })
         
        -t.test('default env and restart scripts', async t => {
        +t.test('default env, start, and restart scripts', async t => {
           npm.localPrefix = t.testdir({
        -    'package.json': JSON.stringify({ name: 'x', version: '1.2.3' })
        +    'package.json': JSON.stringify({ name: 'x', version: '1.2.3' }),
        +    'server.js': 'console.log("hello, world")',
        +  })
        +
        +  await runScript(['start'], er => {
        +    if (er) {
        +      throw er
        +    }
        +    t.match(RUN_SCRIPTS, [
        +      {
        +        path: npm.localPrefix,
        +        args: [],
        +        scriptShell: undefined,
        +        stdio: 'inherit',
        +        stdioString: true,
        +        pkg: { name: 'x', version: '1.2.3', _id: 'x@1.2.3', scripts: {}},
        +        event: 'start'
        +      }
        +    ])
           })
        +  RUN_SCRIPTS.length = 0
         
           await runScript(['env'], er => {
             if (er) {
        diff --git a/deps/npm/test/lib/utils/error-handler.js b/deps/npm/test/lib/utils/error-handler.js
        index 840b3a35650313..9e32dfc5ff8dbf 100644
        --- a/deps/npm/test/lib/utils/error-handler.js
        +++ b/deps/npm/test/lib/utils/error-handler.js
        @@ -218,8 +218,8 @@ t.test('console.log output using --json', (t) => {
         
           config.values.json = true
         
        -  const _log = console.log
        -  console.log = (jsonOutput) => {
        +  const _error = console.error
        +  console.error = (jsonOutput) => {
             t.deepEqual(
               JSON.parse(jsonOutput),
               {
        @@ -236,7 +236,7 @@ t.test('console.log output using --json', (t) => {
           errorHandler(new Error('Error: EBADTHING Something happened'))
         
           t.teardown(() => {
        -    console.log = _log
        +    console.error = _error
             delete config.values.json
           })
         })
        diff --git a/deps/npm/test/lib/utils/explain-dep.js b/deps/npm/test/lib/utils/explain-dep.js
        index e0305348653af0..9a205e3c39ce27 100644
        --- a/deps/npm/test/lib/utils/explain-dep.js
        +++ b/deps/npm/test/lib/utils/explain-dep.js
        @@ -2,7 +2,7 @@ const t = require('tap')
         const requireInject = require('require-inject')
         const npm = {}
         const { explainNode, printNode } = requireInject('../../../lib/utils/explain-dep.js', {
        -  '../../../lib/npm.js': npm
        +  '../../../lib/npm.js': npm,
         })
         
         const cases = {
        @@ -16,10 +16,10 @@ const cases = {
                 name: 'prod-dep',
                 spec: '1.x',
                 from: {
        -          location: '/path/to/project'
        -        }
        -      }
        -    ]
        +          location: '/path/to/project',
        +        },
        +      },
        +    ],
           },
         
           deepDev: {
        @@ -51,16 +51,16 @@ const cases = {
                             name: 'topdev',
                             spec: '4.x',
                             from: {
        -                      location: '/path/to/project'
        -                    }
        -                  }
        -                ]
        -              }
        -            }
        -          ]
        -        }
        -      }
        -    ]
        +                      location: '/path/to/project',
        +                    },
        +                  },
        +                ],
        +              },
        +            },
        +          ],
        +        },
        +      },
        +    ],
           },
         
           optional: {
        @@ -74,10 +74,10 @@ const cases = {
                 name: 'optdep',
                 spec: '1.0.0',
                 from: {
        -          location: '/path/to/project'
        -        }
        -      }
        -    ]
        +          location: '/path/to/project',
        +        },
        +      },
        +    ],
           },
         
           peer: {
        @@ -91,10 +91,10 @@ const cases = {
                 name: 'peer',
                 spec: '1.0.0',
                 from: {
        -          location: '/path/to/project'
        -        }
        -      }
        -    ]
        +          location: '/path/to/project',
        +        },
        +      },
        +    ],
           },
         
           extraneous: {
        @@ -102,8 +102,8 @@ const cases = {
             version: '1337.420.69-lol',
             location: 'node_modules/extra-neos',
             dependents: [],
        -    extraneous: true
        -  }
        +    extraneous: true,
        +  },
         }
         
         cases.manyDeps = {
        @@ -114,31 +114,39 @@ cases.manyDeps = {
               type: 'prod',
               name: 'manydep',
               spec: '1.0.0',
        -      from: cases.prodDep
        +      from: cases.prodDep,
             },
             {
               type: 'optional',
               name: 'manydep',
               spec: '1.x',
        -      from: cases.optional
        +      from: cases.optional,
             },
             {
               type: 'prod',
               name: 'manydep',
               spec: '1.0.x',
        -      from: cases.extraneous
        +      from: cases.extraneous,
             },
             {
               type: 'dev',
               name: 'manydep',
               spec: '*',
        -      from: cases.deepDev
        +      from: cases.deepDev,
             },
             {
               type: 'peer',
               name: 'manydep',
               spec: '>1.0.0-beta <1.0.1',
        -      from: cases.peer
        +      from: cases.peer,
        +    },
        +    {
        +      type: 'prod',
        +      name: 'manydep',
        +      spec:'>1.0.0-beta <1.0.1',
        +      from: {
        +        location: '/path/to/project',
        +      },
             },
             {
               type: 'prod',
        @@ -148,9 +156,9 @@ cases.manyDeps = {
                 name: 'a package with a pretty long name',
                 version: '1.2.3',
                 dependents: {
        -          location: '/path/to/project'
        -        }
        -      }
        +          location: '/path/to/project',
        +        },
        +      },
             },
             {
               type: 'prod',
        @@ -160,9 +168,9 @@ cases.manyDeps = {
                 name: 'another package with a pretty long name',
                 version: '1.2.3',
                 dependents: {
        -          location: '/path/to/project'
        -        }
        -      }
        +          location: '/path/to/project',
        +        },
        +      },
             },
             {
               type: 'prod',
        @@ -172,14 +180,13 @@ cases.manyDeps = {
                 name: 'yet another a package with a pretty long name',
                 version: '1.2.3',
                 dependents: {
        -          location: '/path/to/project'
        -        }
        -      }
        +          location: '/path/to/project',
        +        },
        +      },
             },
        -  ]
        +  ],
         }
         
        -
         for (const [name, expl] of Object.entries(cases)) {
           t.test(name, t => {
             npm.color = true
        diff --git a/deps/npm/test/lib/utils/flat-options.js b/deps/npm/test/lib/utils/flat-options.js
        index d3b8b89bc865ab..7601c78d27a285 100644
        --- a/deps/npm/test/lib/utils/flat-options.js
        +++ b/deps/npm/test/lib/utils/flat-options.js
        @@ -291,6 +291,18 @@ t.test('various default values and falsey fallbacks', t => {
           t.end()
         })
         
        +t.test('legacy _auth token', t => {
        +  const npm = new Mocknpm({
        +    _auth: 'asdfasdf',
        +  })
        +  t.strictSame(
        +    flatOptions(npm)._auth,
        +    'asdfasdf',
        +    'should set legacy _auth token',
        +  )
        +  t.end()
        +})
        +
         t.test('save-type', t => {
           const base = {
             'save-optional': false,