"use strict";
/* Socket Lib - Built with rolldown */
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_runtime = require('../../_virtual/_rolldown/runtime.js');
const require_primordials_regexp = require('../../primordials/regexp.js');
const require_paths_predicates = require('../../paths/predicates.js');
const require_node_fs = require('../../node/fs.js');
const require_node_path = require('../../node/path.js');
const require_bin_which = require('../../bin/which.js');
const require_process_abort = require('../abort.js');
const require_node_child_process = require('../../node/child-process.js');
const require_objects_inspect = require('../../objects/inspect.js');
const require_spinner_default = require('../../spinner/default.js');
const require_process_spawn__internal = require('./_internal.js');
const require_process_spawn_errors = require('./errors.js');
const require_process_spawn_stdio = require('./stdio.js');
let node_process = require("node:process");
node_process = require_runtime.__toESM(node_process);

//#region src/process/spawn/child.ts
/**
* @file Child process spawning utilities with cross-platform support. Provides
*   enhanced spawn functionality with stdio handling and error management.
*   SECURITY: Array-Based Arguments Prevent Command Injection This module uses
*   array-based arguments for all command execution, which is the PRIMARY
*   DEFENSE against command injection attacks. When you pass arguments as an
*   array to spawn(): spawn('npx', ['sfw', tool, ...args], { shell: true })
*   Node.js handles escaping automatically. Each argument is passed directly to
*   the OS without shell interpretation. Shell metacharacters like ; | & $ ( )
*   ` are treated as LITERAL STRINGS, not as commands. This approach is secure
*   even when shell: true is used on Windows for .cmd/.bat file resolution.
*   UNSAFE ALTERNATIVE (not used in this codebase): spawn(`npx sfw ${tool}
*   ${args.join(' ')}`, { shell: true }) // ✖ VULNERABLE String concatenation
*   allows injection. For example, if tool = "foo; rm -rf /", the shell would
*   execute both commands. Array-based arguments prevent this. References:
*
*   - https://nodejs.org/api/child_process.html#child_processspawncommand-args-options
*   - https://cheatsheetseries.owasp.org/cheatsheets/Nodejs_Security_Cheat_Sheet.html
*/
const abortSignal = require_process_abort.getAbortSignal();
const spinner = require_spinner_default.getDefaultSpinner();
function spawn(cmd, args, options, extra) {
	const { spinner: optionsSpinner = spinner, stripAnsi: shouldStripAnsi = true, ...rawSpawnOptions } = {
		__proto__: null,
		...options
	};
	const spinnerInstance = optionsSpinner;
	const spawnOptions = {
		__proto__: null,
		...rawSpawnOptions
	};
	const { env, shell, stdio, stdioString = true } = spawnOptions;
	const cwd = spawnOptions.cwd ? String(spawnOptions.cwd) : void 0;
	let actualCmd = cmd;
	if (!/* @__PURE__ */ require_paths_predicates.isPath(cmd)) {
		const fs = /* @__PURE__ */ require_node_fs.getNodeFs();
		const cached = require_process_spawn__internal.spawnBinPathCache.get(cmd);
		/* c8 ignore start */
		if (cached) if (fs.existsSync(cached)) actualCmd = cached;
		else require_process_spawn__internal.spawnBinPathCache.delete(cmd);
		if (actualCmd === cmd) {
			const resolved = require_bin_which.whichSync(cmd, {
				cwd,
				nothrow: true
			});
			if (resolved && typeof resolved === "string") {
				actualCmd = resolved;
				require_process_spawn__internal.spawnBinPathCache.set(cmd, resolved);
			}
		}
	}
	/* c8 ignore start - Windows-only cmd.exe extension stripping for
	.cmd/.bat/.ps1 shell-true execution. Tested on Windows runners. */
	if (node_process.default.platform === "win32" && shell && require_primordials_regexp.RegExpPrototypeTest(require_process_spawn__internal.windowsScriptExtRegExp, actualCmd)) {
		if (!/* @__PURE__ */ require_paths_predicates.isPath(actualCmd)) actualCmd = (/* @__PURE__ */ require_node_path.getNodePath()).basename(actualCmd, (/* @__PURE__ */ require_node_path.getNodePath()).extname(actualCmd));
	}
	const shouldStopSpinner = !!spinnerInstance?.isSpinning && !/* @__PURE__ */ require_process_spawn_stdio.isStdioType(stdio, "ignore") && !/* @__PURE__ */ require_process_spawn_stdio.isStdioType(stdio, "pipe");
	const shouldRestartSpinner = shouldStopSpinner;
	if (shouldStopSpinner) spinnerInstance.stop();
	const envToUse = env ? {
		__proto__: null,
		...node_process.default.env,
		...env
	} : node_process.default.env;
	const promiseSpawnOpts = {
		__proto__: null,
		cwd: typeof spawnOptions.cwd === "string" ? spawnOptions.cwd : void 0,
		env: envToUse,
		signal: abortSignal,
		stdio: spawnOptions.stdio,
		stdioString,
		shell: spawnOptions.shell,
		windowsVerbatimArguments: spawnOptions.windowsVerbatimArguments,
		timeout: spawnOptions.timeout,
		uid: spawnOptions.uid,
		gid: spawnOptions.gid
	};
	const spawnPromise = (/* @__PURE__ */ require_process_spawn__internal.getNpmCliPromiseSpawn())(actualCmd, args ? [...args] : [], promiseSpawnOpts, extra);
	/* c8 ignore stop */
	const oldSpawnPromise = spawnPromise;
	/* c8 ignore start */
	let newSpawnPromise;
	if (shouldStripAnsi && stdioString) newSpawnPromise = (async () => {
		try {
			const strippedResult = /* @__PURE__ */ require_process_spawn__internal.stripAnsiFromSpawnResult(await spawnPromise);
			if ("code" in strippedResult) strippedResult.exitCode = strippedResult.code;
			return strippedResult;
		} catch (error) {
			throw /* @__PURE__ */ require_process_spawn_errors.enhanceSpawnError(/* @__PURE__ */ require_process_spawn__internal.stripAnsiFromSpawnResult(error));
		}
	})();
	else newSpawnPromise = (async () => {
		try {
			const result = await spawnPromise;
			if (result !== null && typeof result === "object" && "code" in result) {
				const res = result;
				res.exitCode = res.code;
				return res;
			}
			return result;
		} catch (error) {
			throw /* @__PURE__ */ require_process_spawn_errors.enhanceSpawnError(error);
		}
	})();
	/* c8 ignore stop */
	if (shouldRestartSpinner) {
		const prevPromise = newSpawnPromise;
		newSpawnPromise = (async () => {
			try {
				return await prevPromise;
			} finally {
				spinnerInstance.start();
			}
		})();
	}
	newSpawnPromise.process = oldSpawnPromise.process;
	newSpawnPromise.stdin = oldSpawnPromise.stdin;
	return newSpawnPromise;
}
function spawnSync(cmd, args, options) {
	let actualCmd = cmd;
	if (!/* @__PURE__ */ require_paths_predicates.isPath(cmd)) {
		const resolved = require_bin_which.whichSync(cmd, {
			cwd: /* @__PURE__ */ require_objects_inspect.getOwn(options, "cwd"),
			nothrow: true
		});
		if (resolved && typeof resolved === "string") actualCmd = resolved;
	}
	const shell = /* @__PURE__ */ require_objects_inspect.getOwn(options, "shell");
	/* c8 ignore start - Windows-only cmd.exe extension stripping for
	.cmd/.bat/.ps1 shell-true execution. Tested on Windows runners. */
	if (node_process.default.platform === "win32" && shell && require_primordials_regexp.RegExpPrototypeTest(require_process_spawn__internal.windowsScriptExtRegExp, actualCmd)) {
		if (!/* @__PURE__ */ require_paths_predicates.isPath(actualCmd)) actualCmd = (/* @__PURE__ */ require_node_path.getNodePath()).basename(actualCmd, (/* @__PURE__ */ require_node_path.getNodePath()).extname(actualCmd));
	}
	/* c8 ignore stop */
	const { stripAnsi: shouldStripAnsi = true, ...rawSpawnOptions } = {
		__proto__: null,
		...options
	};
	const { stdioString: rawStdioString = true } = rawSpawnOptions;
	const spawnOptions = {
		encoding: rawStdioString ? "utf8" : "buffer",
		...rawSpawnOptions
	};
	const stdioString = spawnOptions.encoding !== "buffer";
	const result = (/* @__PURE__ */ require_node_child_process.getNodeChildProcess()).spawnSync(actualCmd, args, spawnOptions);
	if (stdioString) {
		const { stderr, stdout } = result;
		if (stdout) result.stdout = stdout.toString().trim();
		if (stderr) result.stderr = stderr.toString().trim();
	}
	return shouldStripAnsi && stdioString ? /* @__PURE__ */ require_process_spawn__internal.stripAnsiFromSpawnResult(result) : result;
}

//#endregion
exports.spawn = spawn;
exports.spawnSync = spawnSync;