"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_date = require('../primordials/date.js');
const require_primordials_json = require('../primordials/json.js');
const require_bin_which = require('../bin/which.js');
const require_errors_message = require('../errors/message.js');
const require_logger_default = require('../logger/default.js');
let node_fs = require("node:fs");
let node_fs_promises = require("node:fs/promises");
let node_path = require("node:path");
node_path = require_runtime.__toESM(node_path, 1);

//#region src/ai/discover.mts
/**
* @file Detect which AI agent CLIs are installed on PATH. Strategy:
*   which()-based lookup with a two-tier cache:
*
*   1. In-process Map — survives until the Node process exits.
*   2. On-disk JSON at `<repo>/.cache/agent-discovery.json`, TTL 1h — survives
*      across subprocess invocations (per-file ai-lint-fix batches) without
*      re-running which(). Cache invalidation: stale on-disk cache is detected
*      by mtime comparison; missing or expired → fresh which() pass + rewrite.
*      Why two tiers: hooks and skills spawn dozens of short-lived Node
*      processes per session. In-process alone misses the cross-process
*      speedup; on-disk alone hits the filesystem on every call. The
*      combination keeps repeated lookups under a millisecond after the
*      cold-start cost.
*/
const logger = require_logger_default.getDefaultLogger();
const KNOWN_AGENTS = [
	"claude",
	"codex",
	"gemini",
	"opencode"
];
/**
* Cache TTL in milliseconds (1 hour).
*/
const CACHE_TTL_MS = 3600 * 1e3;
let inProcessCache;
function cachePathFor(repoRoot) {
	return node_path.default.join(repoRoot, ".cache", "agent-discovery.json");
}
/**
* Discover which AI agent CLIs are installed.
*
* @param options.repoRoot - Where to read/write the on-disk cache. Defaults to
*   process.cwd(). Skill runners typically pass the target repo's root.
* @param options.refresh - When true, bypass both caches and re-run which().
*   Useful after `npm i -g <agent>` mid-session.
*
*   Returns a map of agent → absolute binary path. Agents that aren't installed
*   are absent from the map (not present-with-undefined), so callers can use
*   `'claude' in agents` for the existence check.
*/
async function discoverAiAgents(options = {}) {
	const { refresh = false, repoRoot = process.cwd() } = options;
	if (!refresh && inProcessCache) return inProcessCache;
	const cachePath = cachePathFor(repoRoot);
	if (!refresh) {
		const fromDisk = readDiskCache(cachePath);
		if (fromDisk) {
			inProcessCache = fromDisk;
			return fromDisk;
		}
	}
	const fresh = discoverFresh();
	inProcessCache = fresh;
	await writeDiskCache(cachePath, fresh);
	return fresh;
}
function discoverFresh() {
	const out = {};
	for (const name of KNOWN_AGENTS) {
		const found = require_bin_which.whichSync(name);
		if (typeof found === "string" && found) out[name] = found;
	}
	return out;
}
/**
* Synchronous in-process lookup. Skips disk cache + which(). Returns undefined
* if discoverAiAgents() hasn't been called yet in this process, OR returns the
* most recent discovery result.
*
* Useful in fast paths where the caller has already populated the cache and
* just wants to read it back.
*/
function getDiscoveredAiAgents() {
	return inProcessCache;
}
function readDiskCache(cachePath) {
	if (!(0, node_fs.existsSync)(cachePath)) return;
	try {
		const parsed = require_primordials_json.JSONParse((0, node_fs.readFileSync)(cachePath, "utf8"));
		if (typeof parsed !== "object" || parsed === null || typeof parsed.writtenAt !== "number" || require_primordials_date.DateNow() - parsed.writtenAt > CACHE_TTL_MS) return;
		return parsed.agents;
	} catch {
		return;
	}
}
/**
* Reset the in-process cache. Tests use this; production callers shouldn't need
* it (use `refresh: true` on discoverAiAgents()).
*/
function resetAiAgentDiscoveryCache() {
	inProcessCache = void 0;
}
async function writeDiskCache(cachePath, agents) {
	try {
		await (0, node_fs_promises.mkdir)(node_path.default.dirname(cachePath), { recursive: true });
		(0, node_fs.writeFileSync)(cachePath, require_primordials_json.JSONStringify({
			agents,
			writtenAt: require_primordials_date.DateNow()
		}, void 0, 2) + "\n");
	} catch (e) {
		logger.error(`discoverAiAgents: cache write failed (${require_errors_message.errorMessage(e)})`);
	}
}

//#endregion
exports.cachePathFor = cachePathFor;
exports.discoverAiAgents = discoverAiAgents;
exports.discoverFresh = discoverFresh;
exports.getDiscoveredAiAgents = getDiscoveredAiAgents;
exports.readDiskCache = readDiskCache;
exports.resetAiAgentDiscoveryCache = resetAiAgentDiscoveryCache;
exports.writeDiskCache = writeDiskCache;