Index: node_modules/@npmcli/fs/LICENSE.md
===================================================================
--- node_modules/@npmcli/fs/LICENSE.md	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/LICENSE.md	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,20 @@
+<!-- This file is automatically added by @npmcli/template-oss. Do not edit. -->
+
+ISC License
+
+Copyright npm, Inc.
+
+Permission to use, copy, modify, and/or distribute this
+software for any purpose with or without fee is hereby
+granted, provided that the above copyright notice and this
+permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND NPM DISCLAIMS ALL
+WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO
+EVENT SHALL NPM BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE
+USE OR PERFORMANCE OF THIS SOFTWARE.
Index: node_modules/@npmcli/fs/README.md
===================================================================
--- node_modules/@npmcli/fs/README.md	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/README.md	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,60 @@
+# @npmcli/fs
+
+polyfills, and extensions, of the core `fs` module.
+
+## Features
+
+- all exposed functions return promises
+- `fs.rm` polyfill for node versions < 14.14.0
+- `fs.mkdir` polyfill adding support for the `recursive` and `force` options in node versions < 10.12.0
+- `fs.copyFile` extended to accept an `owner` option
+- `fs.mkdir` extended to accept an `owner` option
+- `fs.mkdtemp` extended to accept an `owner` option
+- `fs.writeFile` extended to accept an `owner` option
+- `fs.withTempDir` added
+- `fs.cp` polyfill for node < 16.7.0
+
+## The `owner` option
+
+The `copyFile`, `mkdir`, `mkdtemp`, `writeFile`, and `withTempDir` functions
+all accept a new `owner` property in their options. It can be used in two ways:
+
+- `{ owner: { uid: 100, gid: 100 } }` - set the `uid` and `gid` explicitly
+- `{ owner: 100 }` - use one value, will set both `uid` and `gid` the same
+
+The special string `'inherit'` may be passed instead of a number, which will
+cause this module to automatically determine the correct `uid` and/or `gid`
+from the nearest existing parent directory of the target.
+
+## `fs.withTempDir(root, fn, options) -> Promise`
+
+### Parameters
+
+- `root`: the directory in which to create the temporary directory
+- `fn`: a function that will be called with the path to the temporary directory
+- `options`
+  - `tmpPrefix`: a prefix to be used in the generated directory name
+
+### Usage
+
+The `withTempDir` function creates a temporary directory, runs the provided
+function (`fn`), then removes the temporary directory and resolves or rejects
+based on the result of `fn`.
+
+```js
+const fs = require('@npmcli/fs')
+const os = require('os')
+
+// this function will be called with the full path to the temporary directory
+// it is called with `await` behind the scenes, so can be async if desired.
+const myFunction = async (tempPath) => {
+  return 'done!'
+}
+
+const main = async () => {
+  const result = await fs.withTempDir(os.tmpdir(), myFunction)
+  // result === 'done!'
+}
+
+main()
+```
Index: node_modules/@npmcli/fs/lib/common/file-url-to-path/index.js
===================================================================
--- node_modules/@npmcli/fs/lib/common/file-url-to-path/index.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/common/file-url-to-path/index.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,17 @@
+const url = require('url')
+
+const node = require('../node.js')
+const polyfill = require('./polyfill.js')
+
+const useNative = node.satisfies('>=10.12.0')
+
+const fileURLToPath = (path) => {
+  // the polyfill is tested separately from this module, no need to hack
+  // process.version to try to trigger it just for coverage
+  // istanbul ignore next
+  return useNative
+    ? url.fileURLToPath(path)
+    : polyfill(path)
+}
+
+module.exports = fileURLToPath
Index: node_modules/@npmcli/fs/lib/common/file-url-to-path/polyfill.js
===================================================================
--- node_modules/@npmcli/fs/lib/common/file-url-to-path/polyfill.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/common/file-url-to-path/polyfill.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,121 @@
+const { URL, domainToUnicode } = require('url')
+
+const CHAR_LOWERCASE_A = 97
+const CHAR_LOWERCASE_Z = 122
+
+const isWindows = process.platform === 'win32'
+
+class ERR_INVALID_FILE_URL_HOST extends TypeError {
+  constructor (platform) {
+    super(`File URL host must be "localhost" or empty on ${platform}`)
+    this.code = 'ERR_INVALID_FILE_URL_HOST'
+  }
+
+  toString () {
+    return `${this.name} [${this.code}]: ${this.message}`
+  }
+}
+
+class ERR_INVALID_FILE_URL_PATH extends TypeError {
+  constructor (msg) {
+    super(`File URL path ${msg}`)
+    this.code = 'ERR_INVALID_FILE_URL_PATH'
+  }
+
+  toString () {
+    return `${this.name} [${this.code}]: ${this.message}`
+  }
+}
+
+class ERR_INVALID_ARG_TYPE extends TypeError {
+  constructor (name, actual) {
+    super(`The "${name}" argument must be one of type string or an instance ` +
+      `of URL. Received type ${typeof actual} ${actual}`)
+    this.code = 'ERR_INVALID_ARG_TYPE'
+  }
+
+  toString () {
+    return `${this.name} [${this.code}]: ${this.message}`
+  }
+}
+
+class ERR_INVALID_URL_SCHEME extends TypeError {
+  constructor (expected) {
+    super(`The URL must be of scheme ${expected}`)
+    this.code = 'ERR_INVALID_URL_SCHEME'
+  }
+
+  toString () {
+    return `${this.name} [${this.code}]: ${this.message}`
+  }
+}
+
+const isURLInstance = (input) => {
+  return input != null && input.href && input.origin
+}
+
+const getPathFromURLWin32 = (url) => {
+  const hostname = url.hostname
+  let pathname = url.pathname
+  for (let n = 0; n < pathname.length; n++) {
+    if (pathname[n] === '%') {
+      const third = pathname.codePointAt(n + 2) | 0x20
+      if ((pathname[n + 1] === '2' && third === 102) ||
+        (pathname[n + 1] === '5' && third === 99)) {
+        throw new ERR_INVALID_FILE_URL_PATH('must not include encoded \\ or / characters')
+      }
+    }
+  }
+
+  pathname = pathname.replace(/\//g, '\\')
+  pathname = decodeURIComponent(pathname)
+  if (hostname !== '') {
+    return `\\\\${domainToUnicode(hostname)}${pathname}`
+  }
+
+  const letter = pathname.codePointAt(1) | 0x20
+  const sep = pathname[2]
+  if (letter < CHAR_LOWERCASE_A || letter > CHAR_LOWERCASE_Z ||
+    (sep !== ':')) {
+    throw new ERR_INVALID_FILE_URL_PATH('must be absolute')
+  }
+
+  return pathname.slice(1)
+}
+
+const getPathFromURLPosix = (url) => {
+  if (url.hostname !== '') {
+    throw new ERR_INVALID_FILE_URL_HOST(process.platform)
+  }
+
+  const pathname = url.pathname
+
+  for (let n = 0; n < pathname.length; n++) {
+    if (pathname[n] === '%') {
+      const third = pathname.codePointAt(n + 2) | 0x20
+      if (pathname[n + 1] === '2' && third === 102) {
+        throw new ERR_INVALID_FILE_URL_PATH('must not include encoded / characters')
+      }
+    }
+  }
+
+  return decodeURIComponent(pathname)
+}
+
+const fileURLToPath = (path) => {
+  if (typeof path === 'string') {
+    path = new URL(path)
+  } else if (!isURLInstance(path)) {
+    throw new ERR_INVALID_ARG_TYPE('path', ['string', 'URL'], path)
+  }
+
+  if (path.protocol !== 'file:') {
+    throw new ERR_INVALID_URL_SCHEME('file')
+  }
+
+  return isWindows
+    ? getPathFromURLWin32(path)
+    : getPathFromURLPosix(path)
+}
+
+module.exports = fileURLToPath
Index: node_modules/@npmcli/fs/lib/common/get-options.js
===================================================================
--- node_modules/@npmcli/fs/lib/common/get-options.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/common/get-options.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,20 @@
+// given an input that may or may not be an object, return an object that has
+// a copy of every defined property listed in 'copy'. if the input is not an
+// object, assign it to the property named by 'wrap'
+const getOptions = (input, { copy, wrap }) => {
+  const result = {}
+
+  if (input && typeof input === 'object') {
+    for (const prop of copy) {
+      if (input[prop] !== undefined) {
+        result[prop] = input[prop]
+      }
+    }
+  } else {
+    result[wrap] = input
+  }
+
+  return result
+}
+
+module.exports = getOptions
Index: node_modules/@npmcli/fs/lib/common/node.js
===================================================================
--- node_modules/@npmcli/fs/lib/common/node.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/common/node.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,9 @@
+const semver = require('semver')
+
+const satisfies = (range) => {
+  return semver.satisfies(process.version, range, { includePrerelease: true })
+}
+
+module.exports = {
+  satisfies,
+}
Index: node_modules/@npmcli/fs/lib/common/owner.js
===================================================================
--- node_modules/@npmcli/fs/lib/common/owner.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/common/owner.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,92 @@
+const { dirname, resolve } = require('path')
+
+const fileURLToPath = require('./file-url-to-path/index.js')
+const fs = require('../fs.js')
+
+// given a path, find the owner of the nearest parent
+const find = async (path) => {
+  // if we have no getuid, permissions are irrelevant on this platform
+  if (!process.getuid) {
+    return {}
+  }
+
+  // fs methods accept URL objects with a scheme of file: so we need to unwrap
+  // those into an actual path string before we can resolve it
+  const resolved = path != null && path.href && path.origin
+    ? resolve(fileURLToPath(path))
+    : resolve(path)
+
+  let stat
+
+  try {
+    stat = await fs.lstat(resolved)
+  } finally {
+    // if we got a stat, return its contents
+    if (stat) {
+      return { uid: stat.uid, gid: stat.gid }
+    }
+
+    // try the parent directory
+    if (resolved !== dirname(resolved)) {
+      return find(dirname(resolved))
+    }
+
+    // no more parents, never got a stat, just return an empty object
+    return {}
+  }
+}
+
+// given a path, uid, and gid update the ownership of the path if necessary
+const update = async (path, uid, gid) => {
+  // nothing to update, just exit
+  if (uid === undefined && gid === undefined) {
+    return
+  }
+
+  try {
+    // see if the permissions are already the same, if they are we don't
+    // need to do anything, so return early
+    const stat = await fs.stat(path)
+    if (uid === stat.uid && gid === stat.gid) {
+      return
+    }
+  } catch (err) {}
+
+  try {
+    await fs.chown(path, uid, gid)
+  } catch (err) {}
+}
+
+// accepts a `path` and the `owner` property of an options object and normalizes
+// it into an object with numerical `uid` and `gid`
+const validate = async (path, input) => {
+  let uid
+  let gid
+
+  if (typeof input === 'string' || typeof input === 'number') {
+    uid = input
+    gid = input
+  } else if (input && typeof input === 'object') {
+    uid = input.uid
+    gid = input.gid
+  }
+
+  if (uid === 'inherit' || gid === 'inherit') {
+    const owner = await find(path)
+    if (uid === 'inherit') {
+      uid = owner.uid
+    }
+
+    if (gid === 'inherit') {
+      gid = owner.gid
+    }
+  }
+
+  return { uid, gid }
+}
+
+module.exports = {
+  find,
+  update,
+  validate,
+}
Index: node_modules/@npmcli/fs/lib/copy-file.js
===================================================================
--- node_modules/@npmcli/fs/lib/copy-file.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/copy-file.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,22 @@
+const fs = require('./fs.js')
+const getOptions = require('./common/get-options.js')
+const owner = require('./common/owner.js')
+
+const copyFile = async (src, dest, opts) => {
+  const options = getOptions(opts, {
+    copy: ['mode', 'owner'],
+    wrap: 'mode',
+  })
+
+  const { uid, gid } = await owner.validate(dest, options.owner)
+
+  // the node core method as of 16.5.0 does not support the mode being in an
+  // object, so we have to pass the mode value directly
+  const result = await fs.copyFile(src, dest, options.mode)
+
+  await owner.update(dest, uid, gid)
+
+  return result
+}
+
+module.exports = copyFile
Index: node_modules/@npmcli/fs/lib/cp/LICENSE
===================================================================
--- node_modules/@npmcli/fs/lib/cp/LICENSE	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/cp/LICENSE	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,15 @@
+(The MIT License)
+
+Copyright (c) 2011-2017 JP Richardson
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files
+(the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify,
+ merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
+WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
+OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Index: node_modules/@npmcli/fs/lib/cp/index.js
===================================================================
--- node_modules/@npmcli/fs/lib/cp/index.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/cp/index.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,22 @@
+const fs = require('../fs.js')
+const getOptions = require('../common/get-options.js')
+const node = require('../common/node.js')
+const polyfill = require('./polyfill.js')
+
+// node 16.7.0 added fs.cp
+const useNative = node.satisfies('>=16.7.0')
+
+const cp = async (src, dest, opts) => {
+  const options = getOptions(opts, {
+    copy: ['dereference', 'errorOnExist', 'filter', 'force', 'preserveTimestamps', 'recursive'],
+  })
+
+  // the polyfill is tested separately from this module, no need to hack
+  // process.version to try to trigger it just for coverage
+  // istanbul ignore next
+  return useNative
+    ? fs.cp(src, dest, options)
+    : polyfill(src, dest, options)
+}
+
+module.exports = cp
Index: node_modules/@npmcli/fs/lib/cp/polyfill.js
===================================================================
--- node_modules/@npmcli/fs/lib/cp/polyfill.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/cp/polyfill.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,428 @@
+// this file is a modified version of the code in node 17.2.0
+// which is, in turn, a modified version of the fs-extra module on npm
+// node core changes:
+// - Use of the assert module has been replaced with core's error system.
+// - All code related to the glob dependency has been removed.
+// - Bring your own custom fs module is not currently supported.
+// - Some basic code cleanup.
+// changes here:
+// - remove all callback related code
+// - drop sync support
+// - change assertions back to non-internal methods (see options.js)
+// - throws ENOTDIR when rmdir gets an ENOENT for a path that exists in Windows
+'use strict'
+
+const {
+  ERR_FS_CP_DIR_TO_NON_DIR,
+  ERR_FS_CP_EEXIST,
+  ERR_FS_CP_EINVAL,
+  ERR_FS_CP_FIFO_PIPE,
+  ERR_FS_CP_NON_DIR_TO_DIR,
+  ERR_FS_CP_SOCKET,
+  ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY,
+  ERR_FS_CP_UNKNOWN,
+  ERR_FS_EISDIR,
+  ERR_INVALID_ARG_TYPE,
+} = require('../errors.js')
+const {
+  constants: {
+    errno: {
+      EEXIST,
+      EISDIR,
+      EINVAL,
+      ENOTDIR,
+    },
+  },
+} = require('os')
+const {
+  chmod,
+  copyFile,
+  lstat,
+  mkdir,
+  readdir,
+  readlink,
+  stat,
+  symlink,
+  unlink,
+  utimes,
+} = require('../fs.js')
+const {
+  dirname,
+  isAbsolute,
+  join,
+  parse,
+  resolve,
+  sep,
+  toNamespacedPath,
+} = require('path')
+const { fileURLToPath } = require('url')
+
+const defaultOptions = {
+  dereference: false,
+  errorOnExist: false,
+  filter: undefined,
+  force: true,
+  preserveTimestamps: false,
+  recursive: false,
+}
+
+async function cp (src, dest, opts) {
+  if (opts != null && typeof opts !== 'object') {
+    throw new ERR_INVALID_ARG_TYPE('options', ['Object'], opts)
+  }
+  return cpFn(
+    toNamespacedPath(getValidatedPath(src)),
+    toNamespacedPath(getValidatedPath(dest)),
+    { ...defaultOptions, ...opts })
+}
+
+function getValidatedPath (fileURLOrPath) {
+  const path = fileURLOrPath != null && fileURLOrPath.href
+      && fileURLOrPath.origin
+    ? fileURLToPath(fileURLOrPath)
+    : fileURLOrPath
+  return path
+}
+
+async function cpFn (src, dest, opts) {
+  // Warn about using preserveTimestamps on 32-bit node
+  // istanbul ignore next
+  if (opts.preserveTimestamps && process.arch === 'ia32') {
+    const warning = 'Using the preserveTimestamps option in 32-bit ' +
+      'node is not recommended'
+    process.emitWarning(warning, 'TimestampPrecisionWarning')
+  }
+  const stats = await checkPaths(src, dest, opts)
+  const { srcStat, destStat } = stats
+  await checkParentPaths(src, srcStat, dest)
+  if (opts.filter) {
+    return handleFilter(checkParentDir, destStat, src, dest, opts)
+  }
+  return checkParentDir(destStat, src, dest, opts)
+}
+
+async function checkPaths (src, dest, opts) {
+  const { 0: srcStat, 1: destStat } = await getStats(src, dest, opts)
+  if (destStat) {
+    if (areIdentical(srcStat, destStat)) {
+      throw new ERR_FS_CP_EINVAL({
+        message: 'src and dest cannot be the same',
+        path: dest,
+        syscall: 'cp',
+        errno: EINVAL,
+      })
+    }
+    if (srcStat.isDirectory() && !destStat.isDirectory()) {
+      throw new ERR_FS_CP_DIR_TO_NON_DIR({
+        message: `cannot overwrite directory ${src} ` +
+            `with non-directory ${dest}`,
+        path: dest,
+        syscall: 'cp',
+        errno: EISDIR,
+      })
+    }
+    if (!srcStat.isDirectory() && destStat.isDirectory()) {
+      throw new ERR_FS_CP_NON_DIR_TO_DIR({
+        message: `cannot overwrite non-directory ${src} ` +
+            `with directory ${dest}`,
+        path: dest,
+        syscall: 'cp',
+        errno: ENOTDIR,
+      })
+    }
+  }
+
+  if (srcStat.isDirectory() && isSrcSubdir(src, dest)) {
+    throw new ERR_FS_CP_EINVAL({
+      message: `cannot copy ${src} to a subdirectory of self ${dest}`,
+      path: dest,
+      syscall: 'cp',
+      errno: EINVAL,
+    })
+  }
+  return { srcStat, destStat }
+}
+
+function areIdentical (srcStat, destStat) {
+  return destStat.ino && destStat.dev && destStat.ino === srcStat.ino &&
+    destStat.dev === srcStat.dev
+}
+
+function getStats (src, dest, opts) {
+  const statFunc = opts.dereference ?
+    (file) => stat(file, { bigint: true }) :
+    (file) => lstat(file, { bigint: true })
+  return Promise.all([
+    statFunc(src),
+    statFunc(dest).catch((err) => {
+      // istanbul ignore next: unsure how to cover.
+      if (err.code === 'ENOENT') {
+        return null
+      }
+      // istanbul ignore next: unsure how to cover.
+      throw err
+    }),
+  ])
+}
+
+async function checkParentDir (destStat, src, dest, opts) {
+  const destParent = dirname(dest)
+  const dirExists = await pathExists(destParent)
+  if (dirExists) {
+    return getStatsForCopy(destStat, src, dest, opts)
+  }
+  await mkdir(destParent, { recursive: true })
+  return getStatsForCopy(destStat, src, dest, opts)
+}
+
+function pathExists (dest) {
+  return stat(dest).then(
+    () => true,
+    // istanbul ignore next: not sure when this would occur
+    (err) => (err.code === 'ENOENT' ? false : Promise.reject(err)))
+}
+
+// Recursively check if dest parent is a subdirectory of src.
+// It works for all file types including symlinks since it
+// checks the src and dest inodes. It starts from the deepest
+// parent and stops once it reaches the src parent or the root path.
+async function checkParentPaths (src, srcStat, dest) {
+  const srcParent = resolve(dirname(src))
+  const destParent = resolve(dirname(dest))
+  if (destParent === srcParent || destParent === parse(destParent).root) {
+    return
+  }
+  let destStat
+  try {
+    destStat = await stat(destParent, { bigint: true })
+  } catch (err) {
+    // istanbul ignore else: not sure when this would occur
+    if (err.code === 'ENOENT') {
+      return
+    }
+    // istanbul ignore next: not sure when this would occur
+    throw err
+  }
+  if (areIdentical(srcStat, destStat)) {
+    throw new ERR_FS_CP_EINVAL({
+      message: `cannot copy ${src} to a subdirectory of self ${dest}`,
+      path: dest,
+      syscall: 'cp',
+      errno: EINVAL,
+    })
+  }
+  return checkParentPaths(src, srcStat, destParent)
+}
+
+const normalizePathToArray = (path) =>
+  resolve(path).split(sep).filter(Boolean)
+
+// Return true if dest is a subdir of src, otherwise false.
+// It only checks the path strings.
+function isSrcSubdir (src, dest) {
+  const srcArr = normalizePathToArray(src)
+  const destArr = normalizePathToArray(dest)
+  return srcArr.every((cur, i) => destArr[i] === cur)
+}
+
+async function handleFilter (onInclude, destStat, src, dest, opts, cb) {
+  const include = await opts.filter(src, dest)
+  if (include) {
+    return onInclude(destStat, src, dest, opts, cb)
+  }
+}
+
+function startCopy (destStat, src, dest, opts) {
+  if (opts.filter) {
+    return handleFilter(getStatsForCopy, destStat, src, dest, opts)
+  }
+  return getStatsForCopy(destStat, src, dest, opts)
+}
+
+async function getStatsForCopy (destStat, src, dest, opts) {
+  const statFn = opts.dereference ? stat : lstat
+  const srcStat = await statFn(src)
+  // istanbul ignore else: can't portably test FIFO
+  if (srcStat.isDirectory() && opts.recursive) {
+    return onDir(srcStat, destStat, src, dest, opts)
+  } else if (srcStat.isDirectory()) {
+    throw new ERR_FS_EISDIR({
+      message: `${src} is a directory (not copied)`,
+      path: src,
+      syscall: 'cp',
+      errno: EINVAL,
+    })
+  } else if (srcStat.isFile() ||
+            srcStat.isCharacterDevice() ||
+            srcStat.isBlockDevice()) {
+    return onFile(srcStat, destStat, src, dest, opts)
+  } else if (srcStat.isSymbolicLink()) {
+    return onLink(destStat, src, dest)
+  } else if (srcStat.isSocket()) {
+    throw new ERR_FS_CP_SOCKET({
+      message: `cannot copy a socket file: ${dest}`,
+      path: dest,
+      syscall: 'cp',
+      errno: EINVAL,
+    })
+  } else if (srcStat.isFIFO()) {
+    throw new ERR_FS_CP_FIFO_PIPE({
+      message: `cannot copy a FIFO pipe: ${dest}`,
+      path: dest,
+      syscall: 'cp',
+      errno: EINVAL,
+    })
+  }
+  // istanbul ignore next: should be unreachable
+  throw new ERR_FS_CP_UNKNOWN({
+    message: `cannot copy an unknown file type: ${dest}`,
+    path: dest,
+    syscall: 'cp',
+    errno: EINVAL,
+  })
+}
+
+function onFile (srcStat, destStat, src, dest, opts) {
+  if (!destStat) {
+    return _copyFile(srcStat, src, dest, opts)
+  }
+  return mayCopyFile(srcStat, src, dest, opts)
+}
+
+async function mayCopyFile (srcStat, src, dest, opts) {
+  if (opts.force) {
+    await unlink(dest)
+    return _copyFile(srcStat, src, dest, opts)
+  } else if (opts.errorOnExist) {
+    throw new ERR_FS_CP_EEXIST({
+      message: `${dest} already exists`,
+      path: dest,
+      syscall: 'cp',
+      errno: EEXIST,
+    })
+  }
+}
+
+async function _copyFile (srcStat, src, dest, opts) {
+  await copyFile(src, dest)
+  if (opts.preserveTimestamps) {
+    return handleTimestampsAndMode(srcStat.mode, src, dest)
+  }
+  return setDestMode(dest, srcStat.mode)
+}
+
+async function handleTimestampsAndMode (srcMode, src, dest) {
+  // Make sure the file is writable before setting the timestamp
+  // otherwise open fails with EPERM when invoked with 'r+'
+  // (through utimes call)
+  if (fileIsNotWritable(srcMode)) {
+    await makeFileWritable(dest, srcMode)
+    return setDestTimestampsAndMode(srcMode, src, dest)
+  }
+  return setDestTimestampsAndMode(srcMode, src, dest)
+}
+
+function fileIsNotWritable (srcMode) {
+  return (srcMode & 0o200) === 0
+}
+
+function makeFileWritable (dest, srcMode) {
+  return setDestMode(dest, srcMode | 0o200)
+}
+
+async function setDestTimestampsAndMode (srcMode, src, dest) {
+  await setDestTimestamps(src, dest)
+  return setDestMode(dest, srcMode)
+}
+
+function setDestMode (dest, srcMode) {
+  return chmod(dest, srcMode)
+}
+
+async function setDestTimestamps (src, dest) {
+  // The initial srcStat.atime cannot be trusted
+  // because it is modified by the read(2) system call
+  // (See https://nodejs.org/api/fs.html#fs_stat_time_values)
+  const updatedSrcStat = await stat(src)
+  return utimes(dest, updatedSrcStat.atime, updatedSrcStat.mtime)
+}
+
+function onDir (srcStat, destStat, src, dest, opts) {
+  if (!destStat) {
+    return mkDirAndCopy(srcStat.mode, src, dest, opts)
+  }
+  return copyDir(src, dest, opts)
+}
+
+async function mkDirAndCopy (srcMode, src, dest, opts) {
+  await mkdir(dest)
+  await copyDir(src, dest, opts)
+  return setDestMode(dest, srcMode)
+}
+
+async function copyDir (src, dest, opts) {
+  const dir = await readdir(src)
+  for (let i = 0; i < dir.length; i++) {
+    const item = dir[i]
+    const srcItem = join(src, item)
+    const destItem = join(dest, item)
+    const { destStat } = await checkPaths(srcItem, destItem, opts)
+    await startCopy(destStat, srcItem, destItem, opts)
+  }
+}
+
+async function onLink (destStat, src, dest) {
+  let resolvedSrc = await readlink(src)
+  if (!isAbsolute(resolvedSrc)) {
+    resolvedSrc = resolve(dirname(src), resolvedSrc)
+  }
+  if (!destStat) {
+    return symlink(resolvedSrc, dest)
+  }
+  let resolvedDest
+  try {
+    resolvedDest = await readlink(dest)
+  } catch (err) {
+    // Dest exists and is a regular file or directory,
+    // Windows may throw UNKNOWN error. If dest already exists,
+    // fs throws error anyway, so no need to guard against it here.
+    // istanbul ignore next: can only test on windows
+    if (err.code === 'EINVAL' || err.code === 'UNKNOWN') {
+      return symlink(resolvedSrc, dest)
+    }
+    // istanbul ignore next: should not be possible
+    throw err
+  }
+  if (!isAbsolute(resolvedDest)) {
+    resolvedDest = resolve(dirname(dest), resolvedDest)
+  }
+  if (isSrcSubdir(resolvedSrc, resolvedDest)) {
+    throw new ERR_FS_CP_EINVAL({
+      message: `cannot copy ${resolvedSrc} to a subdirectory of self ` +
+            `${resolvedDest}`,
+      path: dest,
+      syscall: 'cp',
+      errno: EINVAL,
+    })
+  }
+  // Do not copy if src is a subdir of dest since unlinking
+  // dest in this case would result in removing src contents
+  // and therefore a broken symlink would be created.
+  const srcStat = await stat(src)
+  if (srcStat.isDirectory() && isSrcSubdir(resolvedDest, resolvedSrc)) {
+    throw new ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY({
+      message: `cannot overwrite ${resolvedDest} with ${resolvedSrc}`,
+      path: dest,
+      syscall: 'cp',
+      errno: EINVAL,
+    })
+  }
+  return copyLink(resolvedSrc, dest)
+}
+
+async function copyLink (resolvedSrc, dest) {
+  await unlink(dest)
+  return symlink(resolvedSrc, dest)
+}
+
+module.exports = cp
Index: node_modules/@npmcli/fs/lib/errors.js
===================================================================
--- node_modules/@npmcli/fs/lib/errors.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/errors.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,129 @@
+'use strict'
+const { inspect } = require('util')
+
+// adapted from node's internal/errors
+// https://github.com/nodejs/node/blob/c8a04049/lib/internal/errors.js
+
+// close copy of node's internal SystemError class.
+class SystemError {
+  constructor (code, prefix, context) {
+    // XXX context.code is undefined in all constructors used in cp/polyfill
+    // that may be a bug copied from node, maybe the constructor should use
+    // `code` not `errno`?  nodejs/node#41104
+    let message = `${prefix}: ${context.syscall} returned ` +
+                  `${context.code} (${context.message})`
+
+    if (context.path !== undefined) {
+      message += ` ${context.path}`
+    }
+    if (context.dest !== undefined) {
+      message += ` => ${context.dest}`
+    }
+
+    this.code = code
+    Object.defineProperties(this, {
+      name: {
+        value: 'SystemError',
+        enumerable: false,
+        writable: true,
+        configurable: true,
+      },
+      message: {
+        value: message,
+        enumerable: false,
+        writable: true,
+        configurable: true,
+      },
+      info: {
+        value: context,
+        enumerable: true,
+        configurable: true,
+        writable: false,
+      },
+      errno: {
+        get () {
+          return context.errno
+        },
+        set (value) {
+          context.errno = value
+        },
+        enumerable: true,
+        configurable: true,
+      },
+      syscall: {
+        get () {
+          return context.syscall
+        },
+        set (value) {
+          context.syscall = value
+        },
+        enumerable: true,
+        configurable: true,
+      },
+    })
+
+    if (context.path !== undefined) {
+      Object.defineProperty(this, 'path', {
+        get () {
+          return context.path
+        },
+        set (value) {
+          context.path = value
+        },
+        enumerable: true,
+        configurable: true,
+      })
+    }
+
+    if (context.dest !== undefined) {
+      Object.defineProperty(this, 'dest', {
+        get () {
+          return context.dest
+        },
+        set (value) {
+          context.dest = value
+        },
+        enumerable: true,
+        configurable: true,
+      })
+    }
+  }
+
+  toString () {
+    return `${this.name} [${this.code}]: ${this.message}`
+  }
+
+  [Symbol.for('nodejs.util.inspect.custom')] (_recurseTimes, ctx) {
+    return inspect(this, {
+      ...ctx,
+      getters: true,
+      customInspect: false,
+    })
+  }
+}
+
+function E (code, message) {
+  module.exports[code] = class NodeError extends SystemError {
+    constructor (ctx) {
+      super(code, message, ctx)
+    }
+  }
+}
+
+E('ERR_FS_CP_DIR_TO_NON_DIR', 'Cannot overwrite directory with non-directory')
+E('ERR_FS_CP_EEXIST', 'Target already exists')
+E('ERR_FS_CP_EINVAL', 'Invalid src or dest')
+E('ERR_FS_CP_FIFO_PIPE', 'Cannot copy a FIFO pipe')
+E('ERR_FS_CP_NON_DIR_TO_DIR', 'Cannot overwrite non-directory with directory')
+E('ERR_FS_CP_SOCKET', 'Cannot copy a socket file')
+E('ERR_FS_CP_SYMLINK_TO_SUBDIRECTORY', 'Cannot overwrite symlink in subdirectory of self')
+E('ERR_FS_CP_UNKNOWN', 'Cannot copy an unknown file type')
+E('ERR_FS_EISDIR', 'Path is a directory')
+
+module.exports.ERR_INVALID_ARG_TYPE = class ERR_INVALID_ARG_TYPE extends Error {
+  constructor (name, expected, actual) {
+    super()
+    this.code = 'ERR_INVALID_ARG_TYPE'
+    this.message = `The ${name} argument must be ${expected}. Received ${typeof actual}`
+  }
+}
Index: node_modules/@npmcli/fs/lib/fs.js
===================================================================
--- node_modules/@npmcli/fs/lib/fs.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/fs.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,8 @@
+const fs = require('fs')
+const promisify = require('@gar/promisify')
+
+// this module returns the core fs module wrapped in a proxy that promisifies
+// method calls within the getter. we keep it in a separate module so that the
+// overridden methods have a consistent way to get to promisified fs methods
+// without creating a circular dependency
+module.exports = promisify(fs)
Index: node_modules/@npmcli/fs/lib/index.js
===================================================================
--- node_modules/@npmcli/fs/lib/index.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/index.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,10 @@
+module.exports = {
+  ...require('./fs.js'),
+  copyFile: require('./copy-file.js'),
+  cp: require('./cp/index.js'),
+  mkdir: require('./mkdir/index.js'),
+  mkdtemp: require('./mkdtemp.js'),
+  rm: require('./rm/index.js'),
+  withTempDir: require('./with-temp-dir.js'),
+  writeFile: require('./write-file.js'),
+}
Index: node_modules/@npmcli/fs/lib/mkdir/index.js
===================================================================
--- node_modules/@npmcli/fs/lib/mkdir/index.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/mkdir/index.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,32 @@
+const fs = require('../fs.js')
+const getOptions = require('../common/get-options.js')
+const node = require('../common/node.js')
+const owner = require('../common/owner.js')
+
+const polyfill = require('./polyfill.js')
+
+// node 10.12.0 added the options parameter, which allows recursive and mode
+// properties to be passed
+const useNative = node.satisfies('>=10.12.0')
+
+// extends mkdir with the ability to specify an owner of the new dir
+const mkdir = async (path, opts) => {
+  const options = getOptions(opts, {
+    copy: ['mode', 'recursive', 'owner'],
+    wrap: 'mode',
+  })
+  const { uid, gid } = await owner.validate(path, options.owner)
+
+  // the polyfill is tested separately from this module, no need to hack
+  // process.version to try to trigger it just for coverage
+  // istanbul ignore next
+  const result = useNative
+    ? await fs.mkdir(path, options)
+    : await polyfill(path, options)
+
+  await owner.update(path, uid, gid)
+
+  return result
+}
+
+module.exports = mkdir
Index: node_modules/@npmcli/fs/lib/mkdir/polyfill.js
===================================================================
--- node_modules/@npmcli/fs/lib/mkdir/polyfill.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/mkdir/polyfill.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,81 @@
+const { dirname } = require('path')
+
+const fileURLToPath = require('../common/file-url-to-path/index.js')
+const fs = require('../fs.js')
+
+const defaultOptions = {
+  mode: 0o777,
+  recursive: false,
+}
+
+const mkdir = async (path, opts) => {
+  const options = { ...defaultOptions, ...opts }
+
+  // if we're not in recursive mode, just call the real mkdir with the path and
+  // the mode option only
+  if (!options.recursive) {
+    return fs.mkdir(path, options.mode)
+  }
+
+  const makeDirectory = async (dir, mode) => {
+    // we can't use dirname directly since these functions support URL
+    // objects with the file: protocol as the path input, so first we get a
+    // string path, then we can call dirname on that
+    const parent = dir != null && dir.href && dir.origin
+      ? dirname(fileURLToPath(dir))
+      : dirname(dir)
+
+    // if the parent is the dir itself, try to create it. anything but EISDIR
+    // should be rethrown
+    if (parent === dir) {
+      try {
+        await fs.mkdir(dir, opts)
+      } catch (err) {
+        if (err.code !== 'EISDIR') {
+          throw err
+        }
+      }
+      return undefined
+    }
+
+    try {
+      await fs.mkdir(dir, mode)
+      return dir
+    } catch (err) {
+      // ENOENT means the parent wasn't there, so create that
+      if (err.code === 'ENOENT') {
+        const made = await makeDirectory(parent, mode)
+        await makeDirectory(dir, mode)
+        // return the shallowest path we created, i.e. the result of creating
+        // the parent
+        return made
+      }
+
+      // an EEXIST means there's already something there
+      // an EROFS means we have a read-only filesystem and can't create a dir
+      // any other error is fatal and we should give up now
+      if (err.code !== 'EEXIST' && err.code !== 'EROFS') {
+        throw err
+      }
+
+      // stat the directory, if the result is a directory, then we successfully
+      // created this one so return its path. otherwise, we reject with the
+      // original error by ignoring the error in the catch
+      try {
+        const stat = await fs.stat(dir)
+        if (stat.isDirectory()) {
+          // if it already existed, we didn't create anything so return
+          // undefined
+          return undefined
+        }
+      } catch (_) {}
+
+      // if the thing that's there isn't a directory, then just re-throw
+      throw err
+    }
+  }
+
+  return makeDirectory(path, options.mode)
+}
+
+module.exports = mkdir
Index: node_modules/@npmcli/fs/lib/mkdtemp.js
===================================================================
--- node_modules/@npmcli/fs/lib/mkdtemp.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/mkdtemp.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,28 @@
+const { dirname, sep } = require('path')
+
+const fs = require('./fs.js')
+const getOptions = require('./common/get-options.js')
+const owner = require('./common/owner.js')
+
+const mkdtemp = async (prefix, opts) => {
+  const options = getOptions(opts, {
+    copy: ['encoding', 'owner'],
+    wrap: 'encoding',
+  })
+
+  // mkdtemp relies on the trailing path separator to indicate if it should
+  // create a directory inside of the prefix. if that's the case then the root
+  // we infer ownership from is the prefix itself, otherwise it's the dirname
+  // /tmp -> /tmpABCDEF, infers from /
+  // /tmp/ -> /tmp/ABCDEF, infers from /tmp
+  const root = prefix.endsWith(sep) ? prefix : dirname(prefix)
+  const { uid, gid } = await owner.validate(root, options.owner)
+
+  const result = await fs.mkdtemp(prefix, options)
+
+  await owner.update(result, uid, gid)
+
+  return result
+}
+
+module.exports = mkdtemp
Index: node_modules/@npmcli/fs/lib/rm/index.js
===================================================================
--- node_modules/@npmcli/fs/lib/rm/index.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/rm/index.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,22 @@
+const fs = require('../fs.js')
+const getOptions = require('../common/get-options.js')
+const node = require('../common/node.js')
+const polyfill = require('./polyfill.js')
+
+// node 14.14.0 added fs.rm, which allows both the force and recursive options
+const useNative = node.satisfies('>=14.14.0')
+
+const rm = async (path, opts) => {
+  const options = getOptions(opts, {
+    copy: ['retryDelay', 'maxRetries', 'recursive', 'force'],
+  })
+
+  // the polyfill is tested separately from this module, no need to hack
+  // process.version to try to trigger it just for coverage
+  // istanbul ignore next
+  return useNative
+    ? fs.rm(path, options)
+    : polyfill(path, options)
+}
+
+module.exports = rm
Index: node_modules/@npmcli/fs/lib/rm/polyfill.js
===================================================================
--- node_modules/@npmcli/fs/lib/rm/polyfill.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/rm/polyfill.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,239 @@
+// this file is a modified version of the code in node core >=14.14.0
+// which is, in turn, a modified version of the rimraf module on npm
+// node core changes:
+// - Use of the assert module has been replaced with core's error system.
+// - All code related to the glob dependency has been removed.
+// - Bring your own custom fs module is not currently supported.
+// - Some basic code cleanup.
+// changes here:
+// - remove all callback related code
+// - drop sync support
+// - change assertions back to non-internal methods (see options.js)
+// - throws ENOTDIR when rmdir gets an ENOENT for a path that exists in Windows
+const errnos = require('os').constants.errno
+const { join } = require('path')
+const fs = require('../fs.js')
+
+// error codes that mean we need to remove contents
+const notEmptyCodes = new Set([
+  'ENOTEMPTY',
+  'EEXIST',
+  'EPERM',
+])
+
+// error codes we can retry later
+const retryCodes = new Set([
+  'EBUSY',
+  'EMFILE',
+  'ENFILE',
+  'ENOTEMPTY',
+  'EPERM',
+])
+
+const isWindows = process.platform === 'win32'
+
+const defaultOptions = {
+  retryDelay: 100,
+  maxRetries: 0,
+  recursive: false,
+  force: false,
+}
+
+// this is drastically simplified, but should be roughly equivalent to what
+// node core throws
+class ERR_FS_EISDIR extends Error {
+  constructor (path) {
+    super()
+    this.info = {
+      code: 'EISDIR',
+      message: 'is a directory',
+      path,
+      syscall: 'rm',
+      errno: errnos.EISDIR,
+    }
+    this.name = 'SystemError'
+    this.code = 'ERR_FS_EISDIR'
+    this.errno = errnos.EISDIR
+    this.syscall = 'rm'
+    this.path = path
+    this.message = `Path is a directory: ${this.syscall} returned ` +
+      `${this.info.code} (is a directory) ${path}`
+  }
+
+  toString () {
+    return `${this.name} [${this.code}]: ${this.message}`
+  }
+}
+
+class ENOTDIR extends Error {
+  constructor (path) {
+    super()
+    this.name = 'Error'
+    this.code = 'ENOTDIR'
+    this.errno = errnos.ENOTDIR
+    this.syscall = 'rmdir'
+    this.path = path
+    this.message = `not a directory, ${this.syscall} '${this.path}'`
+  }
+
+  toString () {
+    return `${this.name}: ${this.code}: ${this.message}`
+  }
+}
+
+// force is passed separately here because we respect it for the first entry
+// into rimraf only, any further calls that are spawned as a result (i.e. to
+// delete content within the target) will ignore ENOENT errors
+const rimraf = async (path, options, isTop = false) => {
+  const force = isTop ? options.force : true
+  const stat = await fs.lstat(path)
+    .catch((err) => {
+      // we only ignore ENOENT if we're forcing this call
+      if (err.code === 'ENOENT' && force) {
+        return
+      }
+
+      if (isWindows && err.code === 'EPERM') {
+        return fixEPERM(path, options, err, isTop)
+      }
+
+      throw err
+    })
+
+  // no stat object here means either lstat threw an ENOENT, or lstat threw
+  // an EPERM and the fixPERM function took care of things. either way, we're
+  // already done, so return early
+  if (!stat) {
+    return
+  }
+
+  if (stat.isDirectory()) {
+    return rmdir(path, options, null, isTop)
+  }
+
+  return fs.unlink(path)
+    .catch((err) => {
+      if (err.code === 'ENOENT' && force) {
+        return
+      }
+
+      if (err.code === 'EISDIR') {
+        return rmdir(path, options, err, isTop)
+      }
+
+      if (err.code === 'EPERM') {
+        // in windows, we handle this through fixEPERM which will also try to
+        // delete things again. everywhere else since deleting the target as a
+        // file didn't work we go ahead and try to delete it as a directory
+        return isWindows
+          ? fixEPERM(path, options, err, isTop)
+          : rmdir(path, options, err, isTop)
+      }
+
+      throw err
+    })
+}
+
+const fixEPERM = async (path, options, originalErr, isTop) => {
+  const force = isTop ? options.force : true
+  const targetMissing = await fs.chmod(path, 0o666)
+    .catch((err) => {
+      if (err.code === 'ENOENT' && force) {
+        return true
+      }
+
+      throw originalErr
+    })
+
+  // got an ENOENT above, return now. no file = no problem
+  if (targetMissing) {
+    return
+  }
+
+  // this function does its own lstat rather than calling rimraf again to avoid
+  // infinite recursion for a repeating EPERM
+  const stat = await fs.lstat(path)
+    .catch((err) => {
+      if (err.code === 'ENOENT' && force) {
+        return
+      }
+
+      throw originalErr
+    })
+
+  if (!stat) {
+    return
+  }
+
+  if (stat.isDirectory()) {
+    return rmdir(path, options, originalErr, isTop)
+  }
+
+  return fs.unlink(path)
+}
+
+const rmdir = async (path, options, originalErr, isTop) => {
+  if (!options.recursive && isTop) {
+    throw originalErr || new ERR_FS_EISDIR(path)
+  }
+  const force = isTop ? options.force : true
+
+  return fs.rmdir(path)
+    .catch(async (err) => {
+      // in Windows, calling rmdir on a file path will fail with ENOENT rather
+      // than ENOTDIR. to determine if that's what happened, we have to do
+      // another lstat on the path. if the path isn't actually gone, we throw
+      // away the ENOENT and replace it with our own ENOTDIR
+      if (isWindows && err.code === 'ENOENT') {
+        const stillExists = await fs.lstat(path).then(() => true, () => false)
+        if (stillExists) {
+          err = new ENOTDIR(path)
+        }
+      }
+
+      // not there, not a problem
+      if (err.code === 'ENOENT' && force) {
+        return
+      }
+
+      // we may not have originalErr if lstat tells us our target is a
+      // directory but that changes before we actually remove it, so
+      // only throw it here if it's set
+      if (originalErr && err.code === 'ENOTDIR') {
+        throw originalErr
+      }
+
+      // the directory isn't empty, remove the contents and try again
+      if (notEmptyCodes.has(err.code)) {
+        const files = await fs.readdir(path)
+        await Promise.all(files.map((file) => {
+          const target = join(path, file)
+          return rimraf(target, options)
+        }))
+        return fs.rmdir(path)
+      }
+
+      throw err
+    })
+}
+
+const rm = async (path, opts) => {
+  const options = { ...defaultOptions, ...opts }
+  let retries = 0
+
+  const errHandler = async (err) => {
+    if (retryCodes.has(err.code) && ++retries < options.maxRetries) {
+      const delay = retries * options.retryDelay
+      await promiseTimeout(delay)
+      return rimraf(path, options, true).catch(errHandler)
+    }
+
+    throw err
+  }
+
+  return rimraf(path, options, true).catch(errHandler)
+}
+
+const promiseTimeout = (ms) => new Promise((r) => setTimeout(r, ms))
+
+module.exports = rm
Index: node_modules/@npmcli/fs/lib/with-temp-dir.js
===================================================================
--- node_modules/@npmcli/fs/lib/with-temp-dir.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/with-temp-dir.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,39 @@
+const { join, sep } = require('path')
+
+const getOptions = require('./common/get-options.js')
+const mkdir = require('./mkdir/index.js')
+const mkdtemp = require('./mkdtemp.js')
+const rm = require('./rm/index.js')
+
+// create a temp directory, ensure its permissions match its parent, then call
+// the supplied function passing it the path to the directory. clean up after
+// the function finishes, whether it throws or not
+const withTempDir = async (root, fn, opts) => {
+  const options = getOptions(opts, {
+    copy: ['tmpPrefix'],
+  })
+  // create the directory, and fix its ownership
+  await mkdir(root, { recursive: true, owner: 'inherit' })
+
+  const target = await mkdtemp(join(`${root}${sep}`, options.tmpPrefix || ''), { owner: 'inherit' })
+  let err
+  let result
+
+  try {
+    result = await fn(target)
+  } catch (_err) {
+    err = _err
+  }
+
+  try {
+    await rm(target, { force: true, recursive: true })
+  } catch (err) {}
+
+  if (err) {
+    throw err
+  }
+
+  return result
+}
+
+module.exports = withTempDir
Index: node_modules/@npmcli/fs/lib/write-file.js
===================================================================
--- node_modules/@npmcli/fs/lib/write-file.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/lib/write-file.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,19 @@
+const fs = require('./fs.js')
+const getOptions = require('./common/get-options.js')
+const owner = require('./common/owner.js')
+
+const writeFile = async (file, data, opts) => {
+  const options = getOptions(opts, {
+    copy: ['encoding', 'mode', 'flag', 'signal', 'owner'],
+    wrap: 'encoding',
+  })
+  const { uid, gid } = await owner.validate(file, options.owner)
+
+  const result = await fs.writeFile(file, data, options)
+
+  await owner.update(file, uid, gid)
+
+  return result
+}
+
+module.exports = writeFile
Index: node_modules/@npmcli/fs/package.json
===================================================================
--- node_modules/@npmcli/fs/package.json	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/fs/package.json	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,38 @@
+{
+  "name": "@npmcli/fs",
+  "version": "1.1.1",
+  "description": "filesystem utilities for the npm cli",
+  "main": "lib/index.js",
+  "files": [
+    "bin",
+    "lib"
+  ],
+  "scripts": {
+    "preversion": "npm test",
+    "postversion": "npm publish",
+    "prepublishOnly": "git push origin --follow-tags",
+    "snap": "tap",
+    "test": "tap",
+    "npmclilint": "npmcli-lint",
+    "lint": "eslint '**/*.js'",
+    "lintfix": "npm run lint -- --fix",
+    "posttest": "npm run lint",
+    "postsnap": "npm run lintfix --",
+    "postlint": "npm-template-check"
+  },
+  "keywords": [
+    "npm",
+    "oss"
+  ],
+  "author": "GitHub Inc.",
+  "license": "ISC",
+  "devDependencies": {
+    "@npmcli/template-oss": "^2.3.1",
+    "tap": "^15.0.9"
+  },
+  "dependencies": {
+    "@gar/promisify": "^1.0.1",
+    "semver": "^7.3.5"
+  },
+  "templateVersion": "2.3.1"
+}
Index: node_modules/@npmcli/move-file/LICENSE.md
===================================================================
--- node_modules/@npmcli/move-file/LICENSE.md	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/move-file/LICENSE.md	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,22 @@
+MIT License
+
+Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
+Copyright (c) npm, Inc.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
Index: node_modules/@npmcli/move-file/README.md
===================================================================
--- node_modules/@npmcli/move-file/README.md	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/move-file/README.md	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,69 @@
+# @npmcli/move-file
+
+A fork of [move-file](https://github.com/sindresorhus/move-file) with
+compatibility with all node 10.x versions.
+
+> Move a file (or directory)
+
+The built-in
+[`fs.rename()`](https://nodejs.org/api/fs.html#fs_fs_rename_oldpath_newpath_callback)
+is just a JavaScript wrapper for the C `rename(2)` function, which doesn't
+support moving files across partitions or devices. This module is what you
+would have expected `fs.rename()` to be.
+
+## Highlights
+
+- Promise API.
+- Supports moving a file across partitions and devices.
+- Optionally prevent overwriting an existing file.
+- Creates non-existent destination directories for you.
+- Support for Node versions that lack built-in recursive `fs.mkdir()`
+- Automatically recurses when source is a directory.
+
+## Install
+
+```
+$ npm install @npmcli/move-file
+```
+
+## Usage
+
+```js
+const moveFile = require('@npmcli/move-file');
+
+(async () => {
+	await moveFile('source/unicorn.png', 'destination/unicorn.png');
+	console.log('The file has been moved');
+})();
+```
+
+## API
+
+### moveFile(source, destination, options?)
+
+Returns a `Promise` that resolves when the file has been moved.
+
+### moveFile.sync(source, destination, options?)
+
+#### source
+
+Type: `string`
+
+File, or directory, you want to move.
+
+#### destination
+
+Type: `string`
+
+Where you want the file or directory moved.
+
+#### options
+
+Type: `object`
+
+##### overwrite
+
+Type: `boolean`\
+Default: `true`
+
+Overwrite existing destination file(s).
Index: node_modules/@npmcli/move-file/index.js
===================================================================
--- node_modules/@npmcli/move-file/index.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/move-file/index.js	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,162 @@
+const { dirname, join, resolve, relative, isAbsolute } = require('path')
+const rimraf_ = require('rimraf')
+const { promisify } = require('util')
+const {
+  access: access_,
+  accessSync,
+  copyFile: copyFile_,
+  copyFileSync,
+  unlink: unlink_,
+  unlinkSync,
+  readdir: readdir_,
+  readdirSync,
+  rename: rename_,
+  renameSync,
+  stat: stat_,
+  statSync,
+  lstat: lstat_,
+  lstatSync,
+  symlink: symlink_,
+  symlinkSync,
+  readlink: readlink_,
+  readlinkSync
+} = require('fs')
+
+const access = promisify(access_)
+const copyFile = promisify(copyFile_)
+const unlink = promisify(unlink_)
+const readdir = promisify(readdir_)
+const rename = promisify(rename_)
+const stat = promisify(stat_)
+const lstat = promisify(lstat_)
+const symlink = promisify(symlink_)
+const readlink = promisify(readlink_)
+const rimraf = promisify(rimraf_)
+const rimrafSync = rimraf_.sync
+
+const mkdirp = require('mkdirp')
+
+const pathExists = async path => {
+  try {
+    await access(path)
+    return true
+  } catch (er) {
+    return er.code !== 'ENOENT'
+  }
+}
+
+const pathExistsSync = path => {
+  try {
+    accessSync(path)
+    return true
+  } catch (er) {
+    return er.code !== 'ENOENT'
+  }
+}
+
+const moveFile = async (source, destination, options = {}, root = true, symlinks = []) => {
+  if (!source || !destination) {
+    throw new TypeError('`source` and `destination` file required')
+  }
+
+  options = {
+    overwrite: true,
+    ...options
+  }
+
+  if (!options.overwrite && await pathExists(destination)) {
+    throw new Error(`The destination file exists: ${destination}`)
+  }
+
+  await mkdirp(dirname(destination))
+
+  try {
+    await rename(source, destination)
+  } catch (error) {
+    if (error.code === 'EXDEV' || error.code === 'EPERM') {
+      const sourceStat = await lstat(source)
+      if (sourceStat.isDirectory()) {
+        const files = await readdir(source)
+        await Promise.all(files.map((file) => moveFile(join(source, file), join(destination, file), options, false, symlinks)))
+      } else if (sourceStat.isSymbolicLink()) {
+        symlinks.push({ source, destination })
+      } else {
+        await copyFile(source, destination)
+      }
+    } else {
+      throw error
+    }
+  }
+
+  if (root) {
+    await Promise.all(symlinks.map(async ({ source, destination }) => {
+      let target = await readlink(source)
+      // junction symlinks in windows will be absolute paths, so we need to make sure they point to the destination
+      if (isAbsolute(target))
+        target = resolve(destination, relative(source, target))
+      // try to determine what the actual file is so we can create the correct type of symlink in windows
+      let targetStat
+      try {
+        targetStat = await stat(resolve(dirname(source), target))
+      } catch (err) {}
+      await symlink(target, destination, targetStat && targetStat.isDirectory() ? 'junction' : 'file')
+    }))
+    await rimraf(source)
+  }
+}
+
+const moveFileSync = (source, destination, options = {}, root = true, symlinks = []) => {
+  if (!source || !destination) {
+    throw new TypeError('`source` and `destination` file required')
+  }
+
+  options = {
+    overwrite: true,
+    ...options
+  }
+
+  if (!options.overwrite && pathExistsSync(destination)) {
+    throw new Error(`The destination file exists: ${destination}`)
+  }
+
+  mkdirp.sync(dirname(destination))
+
+  try {
+    renameSync(source, destination)
+  } catch (error) {
+    if (error.code === 'EXDEV' || error.code === 'EPERM') {
+      const sourceStat = lstatSync(source)
+      if (sourceStat.isDirectory()) {
+        const files = readdirSync(source)
+        for (const file of files) {
+          moveFileSync(join(source, file), join(destination, file), options, false, symlinks)
+        }
+      } else if (sourceStat.isSymbolicLink()) {
+        symlinks.push({ source, destination })
+      } else {
+        copyFileSync(source, destination)
+      }
+    } else {
+      throw error
+    }
+  }
+
+  if (root) {
+    for (const { source, destination } of symlinks) {
+      let target = readlinkSync(source)
+      // junction symlinks in windows will be absolute paths, so we need to make sure they point to the destination
+      if (isAbsolute(target))
+        target = resolve(destination, relative(source, target))
+      // try to determine what the actual file is so we can create the correct type of symlink in windows
+      let targetStat
+      try {
+        targetStat = statSync(resolve(dirname(source), target))
+      } catch (err) {}
+      symlinkSync(target, destination, targetStat && targetStat.isDirectory() ? 'junction' : 'file')
+    }
+    rimrafSync(source)
+  }
+}
+
+module.exports = moveFile
+module.exports.sync = moveFileSync
Index: node_modules/@npmcli/move-file/package.json
===================================================================
--- node_modules/@npmcli/move-file/package.json	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
+++ node_modules/@npmcli/move-file/package.json	(revision 81bc7da776d8cda42939ef4ab350c88d13b4941f)
@@ -0,0 +1,34 @@
+{
+  "name": "@npmcli/move-file",
+  "version": "1.1.2",
+  "files": [
+    "index.js"
+  ],
+  "description": "move a file (fork of move-file)",
+  "dependencies": {
+    "mkdirp": "^1.0.4",
+    "rimraf": "^3.0.2"
+  },
+  "devDependencies": {
+    "require-inject": "^1.4.4",
+    "tap": "^14.10.7"
+  },
+  "scripts": {
+    "test": "tap",
+    "snap": "tap",
+    "preversion": "npm test",
+    "postversion": "npm publish",
+    "prepublishOnly": "git push origin --follow-tags"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/npm/move-file"
+  },
+  "tap": {
+    "check-coverage": true
+  },
+  "license": "MIT",
+  "engines": {
+    "node": ">=10"
+  }
+}
