function createSubprocess(args, done, opts = {}) {
  let output = '';

  if (opts === 'pipe') {
    opts = {stdio: ['inherit', 'pipe', 'pipe']};
  }

  const env = {...process.env};
  // prevent DEBUG from borking STDERR when piping, unless explicitly set via `opts`
  delete env.DEBUG;

  opts = {
    cwd: process.cwd(),
    stdio: ['inherit', 'pipe', 'inherit'],
    env,
    ...opts
  };

  /**
   * @type {import('child_process').ChildProcess}
   */
  let mocha;
  if (opts.fork) {
    const {fork} = require('node:child_process');
    // to use ipc, we need a fourth item in `stdio` array.
    // opts.stdio is usually an array of length 3, but it could be smaller
    // (pad with `null`)
    for (let i = opts.stdio.length; i < 4; i++) {
      opts.stdio.push(i === 3 ? 'ipc' : null);
    }
    debug('forking: %s', args.join(' '));
    mocha = fork(args[0], args.slice(1), opts);
  } else {
    const {spawn} = require('node:child_process');
    debug('spawning: %s', [process.execPath].concat(args).join(' '));
    mocha = spawn(process.execPath, args, opts);
  }

  const listener = data => {
    output += data;
  };

  mocha.stdout.on('data', listener);
  if (mocha.stderr) {
    mocha.stderr.on('data', listener);
  }
  mocha.on('error', done);

  mocha.on('close', code => {
    done(null, {
      output,
      code,
      args,
      command: args.join(' ')
    });
  });

  /**
   * Emulate node's exit code for fatal signal. Allows tests to see the same
   * exit code as the mocha cli.
   */
  mocha.on('exit', (code, signal) => {
    if (signal) {
      mocha.exitCode =
        SIGNAL_OFFSET +
        (typeof signal == 'string' ? os.constants.signals[signal] : signal);
    }
  });

  return mocha;
}
Creates a subprocess and calls callback `done` when it has exited.

This is the most low-level function and should _not_ be exported.

@param {string[]} args - Path to executable and arguments
@param {RawResultCallback} done - Callback
@param {Object|string} [opts] - Options to `child_process` or 'pipe' for shortcut to `{stdio: pipe}`
@param {boolean} [opts.fork] - If `true`, use `child_process.fork` instead
@returns {import('child_process').ChildProcess}