"use strict";
/* Socket Lib - Built with rolldown */
Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
const require_primordials_error = require('../primordials/error.js');
const require_primordials_date = require('../primordials/date.js');
const require_primordials_object = require('../primordials/object.js');
const require_errors_message = require('../errors/message.js');
const require_ai_discover = require('./discover.js');
const require_process_spawn_errors = require('../process/spawn/errors.js');
const require_process_spawn_child = require('../process/spawn/child.js');
const require_primordials_promise = require('../primordials/promise.js');

//#region src/ai/spawn.mts
/**
* @file Locked-down spawn for AI agent CLIs (Claude / Codex / Gemini /
*   OpenCode). Per the CLAUDE.md "Programmatic Claude calls" rule: every
*   headless invocation MUST set the four lockdown flags (tools / disallow /
*   permissionMode / no-session-persistence). The helper enforces this at the
*   type level (`SpawnAiAgentOptions` requires the relevant fields) AND at the
*   spawn site (per-agent flag translator). Why CLI subprocess instead of an
*   SDK call: the fleet's contract matches what the local user sees when
*   invoking the CLI — same auth config, same model availability, same tool
*   permissions. SDK calls would diverge on auth handling and force per-agent
*   SDK installs. Retry: 3 attempts on overload (HTTP 529 / "Overloaded"), exp.
*   backoff (5s / 15s / 45s). Each retry is a fresh subprocess.
*/
const MAX_ATTEMPTS = 3;
const BACKOFF_BASE_MS = 5e3;
function backoffFor(attempt) {
	return BACKOFF_BASE_MS * 3 ** (attempt - 1);
}
/**
* Build CLI arg list for a given agent. The flag names differ across agents but
* the conceptual surface is the same: "here are the allowed tools, here are the
* denied tools, here is the permission mode, do not persist a session." This
* translator is the single source of truth for how each agent's flags map.
*
* Update sites (when an agent changes its flag surface): 1. The relevant case
* below. 2. The agent's docs link (cited inline).
*/
function buildArgs(agent, opts) {
	const allAllowed = [...opts.tools, ...opts.allow ?? []];
	switch (agent) {
		case "claude": {
			const args = [
				"--print",
				"--no-session-persistence",
				"--permission-mode",
				opts.permissionMode,
				"--add-dir",
				opts.cwd
			];
			for (const dir of opts.addDirs ?? []) args.push("--add-dir", dir);
			if (opts.model) args.push("--model", opts.model);
			if (allAllowed.length > 0) args.push("--allowedTools", ...allAllowed);
			if (opts.disallow.length > 0) args.push("--disallowedTools", ...opts.disallow);
			if (opts.extraArgs) args.push(...opts.extraArgs);
			return args;
		}
		case "codex": {
			const args = ["--print"];
			if (opts.permissionMode === "plan") args.push("--read-only");
			if (opts.model) args.push("--model", opts.model);
			if (allAllowed.length > 0) args.push("--tools", allAllowed.join(","));
			if (opts.disallow.length > 0) args.push("--disallow-tools", opts.disallow.join(","));
			args.push("--cwd", opts.cwd);
			if (opts.extraArgs) args.push(...opts.extraArgs);
			return args;
		}
		case "gemini": {
			const args = [
				"--no-interactive",
				"--workspace",
				opts.cwd
			];
			if (opts.model) args.push("--model", opts.model);
			if (allAllowed.length > 0) args.push("--allowed-tools", allAllowed.join(","));
			if (opts.disallow.length > 0) args.push("--denied-tools", opts.disallow.join(","));
			if (opts.permissionMode === "plan") args.push("--read-only");
			if (opts.extraArgs) args.push(...opts.extraArgs);
			return args;
		}
		case "opencode": {
			const args = [
				"--print",
				"--cwd",
				opts.cwd
			];
			if (opts.model) args.push("--model", opts.model);
			if (allAllowed.length > 0) args.push("--tools", allAllowed.join(","));
			if (opts.disallow.length > 0) args.push("--no-tools", opts.disallow.join(","));
			if (opts.extraArgs) args.push(...opts.extraArgs);
			return args;
		}
	}
}
function isOverloaded(stdout, stderr) {
	const re = /API Error: 529|Overloaded/i;
	return re.test(stdout) || re.test(stderr);
}
async function pickAgent(requested, cwd) {
	const discovered = await require_ai_discover.discoverAiAgents({ repoRoot: cwd });
	if (requested) {
		if (!(requested in discovered)) throw new require_primordials_error.ErrorCtor(`spawnAiAgent: requested agent "${requested}" is not on PATH. Install the CLI or pass a different agent. Discovered: ${require_primordials_object.ObjectKeys(discovered).join(", ") || "(none)"}`);
		return requested;
	}
	if ("claude" in discovered) return "claude";
	for (const candidate of [
		"codex",
		"opencode",
		"gemini"
	]) if (candidate in discovered) return candidate;
	throw new require_primordials_error.ErrorCtor("spawnAiAgent: no AI agent CLI on PATH. Install one of: claude, codex, opencode, gemini.");
}
/**
* Spawn an AI agent CLI subprocess with the locked-down flag set.
*
* @example
*   ```ts
*   import { AI_PROFILE } from '@socketsecurity/lib/ai/profiles'
*   import { spawnAiAgent } from '@socketsecurity/lib/ai/spawn'
*
*   const result = await spawnAiAgent({
*   ...AI_PROFILE.edit,
*   prompt: 'Fix the lint findings in src/foo.ts',
*   cwd: process.cwd(),
*   model: 'claude-sonnet-4-6',
*   timeoutMs: 5 * 60 * 1000,
*   })
*   if (result.exitCode !== 0) { ... }
*   ```
*
*   Throws when the requested agent isn't on PATH (or, when no agent
*   is requested, when none of the known agents are on PATH).
*/
async function spawnAiAgent(opts) {
	const agent = await pickAgent(opts.agent, opts.cwd);
	const args = buildArgs(agent, opts);
	let stdout = "";
	let stderr = "";
	let exitCode = 0;
	let attempts = 0;
	const start = require_primordials_date.DateNow();
	while (attempts < MAX_ATTEMPTS) {
		attempts += 1;
		stdout = "";
		stderr = "";
		exitCode = 0;
		try {
			const child = require_process_spawn_child.spawn(agent, args, {
				cwd: opts.cwd,
				stdio: "pipe",
				stdioString: true,
				timeout: opts.timeoutMs
			});
			child.stdin?.end(opts.prompt);
			const result = await child;
			stdout = String(result.stdout ?? "");
			stderr = String(result.stderr ?? "");
			exitCode = result.code ?? 0;
		} catch (e) {
			if (/* @__PURE__ */ require_process_spawn_errors.isSpawnError(e)) {
				stdout = String(e.stdout ?? "");
				stderr = String(e.stderr ?? "");
				exitCode = e.code ?? 1;
			} else {
				stderr = require_errors_message.errorMessage(e);
				exitCode = 1;
			}
		}
		if (!isOverloaded(stdout, stderr) || attempts >= MAX_ATTEMPTS) break;
		await new require_primordials_promise.PromiseCtor((resolve) => setTimeout(resolve, backoffFor(attempts)));
	}
	return {
		attempts,
		durationMs: require_primordials_date.DateNow() - start,
		exitCode,
		stderr,
		stdout
	};
}

//#endregion
exports.backoffFor = backoffFor;
exports.buildArgs = buildArgs;
exports.isOverloaded = isOverloaded;
exports.pickAgent = pickAgent;
exports.spawnAiAgent = spawnAiAgent;