import "./paths-D4_LjrY7.js";
import "./utils-BnlaT0eO.js";
import "./theme-CG-K7m8u.js";
import "./subsystem-ocBR131w.js";
import "./runtime-CRvfzclG.js";
import { u as normalizeAgentId } from "./session-key-DIUsVZjU.js";
import { n as runExec, t as runCommandWithTimeout } from "./exec-CZr_EJHt.js";
import "./agent-scope-CVnlY0oG.js";
import "./model-selection-p6J3l4qF.js";
import "./github-copilot-token-CjSKohyA.js";
import "./emitter-oHo8y9ow.js";
import "./sqlite-wYNyDR1B.js";
import "./reliability-Dl7hbRzF.js";
import "./boolean-DGGu1sGA.js";
import "./env-CvUd308i.js";
import "./validation-p1IK70TM.js";
import { d as writeConfigFile, l as readConfigFileSnapshotForWrite, o as loadConfig } from "./config-DJ3A5x_1.js";
import "./manifest-registry-U2EDFVP4.js";
import "./message-channel-DSU96OKy.js";
import "./client-DNPnFy4E.js";
import "./call-C206Z-zx.js";
import "./progress-WmzCxxhb.js";
import { n as callGatewayFromCli, t as addGatewayClientOptions } from "./gateway-rpc-C7FuCd9c.js";
import { existsSync, writeFileSync } from "node:fs";
import { resolve } from "node:path";

//#region src/cli/tools-cli.install.ts
async function hasBin(bin) {
	try {
		await runExec("which", [bin], 5e3);
		return true;
	} catch {
		return false;
	}
}
async function detectPackageManager() {
	if (await hasBin("brew")) return "brew";
	if (await hasBin("apt-get")) return "apt";
	if (await hasBin("npm")) return "npm";
}
async function installTool(instructions) {
	const pm = await detectPackageManager();
	if (!pm) return {
		installed: false,
		message: "No supported package manager found (brew, apt, npm)."
	};
	const match = instructions.find((i) => {
		if (i.kind === pm) return true;
		if (i.kind === "homebrew" && pm === "brew") return true;
		if (i.kind === "brew" && pm === "brew") return true;
		return false;
	});
	if (!match) return {
		installed: false,
		message: `No install instruction for ${pm}. Available: ${instructions.map((i) => i.kind).join(", ")}`
	};
	const target = match.formula ?? match.bins?.[0] ?? "";
	if (!target) return {
		installed: false,
		message: `Install instruction for ${pm} has no formula or bin.`
	};
	let argv;
	switch (pm) {
		case "brew":
			argv = [
				"brew",
				"install",
				target
			];
			break;
		case "apt":
			argv = [
				"sudo",
				"apt-get",
				"install",
				"-y",
				target
			];
			break;
		case "npm":
			argv = [
				"npm",
				"install",
				"-g",
				target
			];
			break;
		default: return {
			installed: false,
			message: `Unsupported package manager: ${pm}`
		};
	}
	console.log(`Running: ${argv.join(" ")}`);
	const result = await runCommandWithTimeout(argv, { timeoutMs: 12e4 });
	if (result.code !== 0) return {
		installed: false,
		message: `Install command failed (exit ${result.code})`
	};
	const bins = match.bins ?? [];
	for (const bin of bins) if (!await hasBin(bin)) return {
		installed: false,
		message: `Binary not found after install: ${bin}`
	};
	return {
		installed: true,
		message: `Installed successfully via ${pm}`
	};
}

//#endregion
//#region src/cli/tools-cli.scaffold.ts
function toSnakeCase(name) {
	return name.replace(/-/g, "_");
}
function toPascalCase(name) {
	return name.split("-").map((s) => s.charAt(0).toUpperCase() + s.slice(1)).join("");
}
function scaffoldTool(opts) {
	const { name, groups, toolsDir } = opts;
	const id = toSnakeCase(name);
	const pascal = toPascalCase(name);
	const factoryName = `create${pascal}Tool`;
	const schemaName = `${pascal}Schema`;
	const filePrefix = `${name}-tool`;
	const metaPath = resolve(toolsDir, `${filePrefix}.meta.ts`);
	const implPath = resolve(toolsDir, `${filePrefix}.ts`);
	if (existsSync(metaPath) || existsSync(implPath)) throw new Error(`Tool files already exist: ${filePrefix}.ts / ${filePrefix}.meta.ts`);
	const metaContent = `import type { ToolMeta } from "../tool-meta.js";

export const meta: ToolMeta = {
  id: "${id}",
  factory: "${factoryName}",
  groups: [${groups.map((g) => `"${g}"`).join(", ")}],
};
`;
	const implContent = `import { Type } from "@sinclair/typebox";
import type { AnyAgentTool } from "./common.js";
import { jsonResult } from "./common.js";

const ${schemaName} = Type.Object({
  // TODO: define parameters
});

export function ${factoryName}(): AnyAgentTool {
  return {
    label: "${pascal}",
    name: "${id}",
    description: "TODO: describe what this tool does",
    parameters: ${schemaName},
    execute: async (_toolCallId, args) => {
      // TODO: implement
      return jsonResult({ status: "ok" });
    },
  };
}
`;
	writeFileSync(metaPath, metaContent, "utf-8");
	writeFileSync(implPath, implContent, "utf-8");
	return {
		metaPath,
		implPath
	};
}
async function runCodegen(projectRoot) {
	const result = await runCommandWithTimeout(["pnpm", "generate:tools"], {
		timeoutMs: 3e4,
		cwd: projectRoot
	});
	if (result.code !== 0) throw new Error(`Codegen failed (exit ${result.code}): ${result.stderr}`);
}

//#endregion
//#region src/cli/tools-cli.ts
async function fetchToolsStatus(opts, agentId) {
	return await callGatewayFromCli("tools.status", opts, agentId ? { agentId } : {}, { progress: true });
}
function resolveToolsConfig(cfg, agentId) {
	if (!agentId) {
		const mutable = cfg;
		mutable.tools = mutable.tools ?? {};
		return {
			tools: mutable.tools,
			path: "tools"
		};
	}
	const normalized = normalizeAgentId(agentId);
	const mutable = cfg;
	mutable.agents = mutable.agents ?? {};
	mutable.agents.list = mutable.agents.list ?? [];
	let agent = mutable.agents.list.find((a) => normalizeAgentId(a.id) === normalized);
	if (!agent) {
		agent = { id: agentId };
		mutable.agents.list.push(agent);
	}
	agent.tools = agent.tools ?? {};
	return {
		tools: agent.tools,
		path: `agents[${agentId}].tools`
	};
}
function removeFromArray(arr, value) {
	if (!arr) return [];
	return arr.filter((v) => v !== value);
}
async function writeConfigAndReload(cfg, writeResult, opts) {
	await writeConfigFile(cfg, {
		envSnapshotForRestore: writeResult.writeOptions.envSnapshotForRestore,
		expectedConfigPath: writeResult.writeOptions.expectedConfigPath
	});
	try {
		await callGatewayFromCli("tools.reload", opts, {}, { progress: false });
	} catch {}
}
function registerToolsCli(program) {
	const tools = program.command("tools").description("Manage tool policies, status, and scaffolding");
	addGatewayClientOptions(tools);
	tools.command("list").description("List all tools with enabled/disabled state").option("--agent <id>", "Scope to agent").option("--group <name>", "Filter by group (e.g. gog, web, sessions)").option("--json", "JSON output").action(async (opts) => {
		const data = await fetchToolsStatus({
			...tools.opts(),
			...opts
		}, opts.agent);
		let entries = data.tools;
		if (opts.group) {
			const groupKey = opts.group.startsWith("group:") ? opts.group : `group:${opts.group}`;
			const groupTools = new Set(data.groups[groupKey] ?? []);
			entries = entries.filter((t) => groupTools.has(t.id));
		}
		if (opts.json) {
			console.log(JSON.stringify({
				profile: data.profile,
				tools: entries
			}, null, 2));
			return;
		}
		console.log(`Profile: ${data.profile}\n`);
		const maxId = Math.max(4, ...entries.map((t) => t.id.length));
		console.log(`${"TOOL".padEnd(maxId)}  ENABLED  GROUPS`);
		console.log(`${"─".repeat(maxId)}  ───────  ──────`);
		for (const t of entries) {
			const status = t.enabled ? "  yes  " : "  no   ";
			const groups = t.groups.map((g) => g.replace("group:", "")).join(", ");
			console.log(`${t.id.padEnd(maxId)}  ${status}  ${groups}`);
		}
	});
	tools.command("status").description("Show detailed status for a single tool").argument("<tool-id>", "Tool identifier").option("--agent <id>", "Scope to agent").option("--json", "JSON output").action(async (toolId, opts) => {
		const data = await fetchToolsStatus({
			...tools.opts(),
			...opts
		}, opts.agent);
		const tool = data.tools.find((t) => t.id === toolId);
		if (!tool) {
			console.error(`Unknown tool: ${toolId}`);
			console.error(`Available: ${data.tools.map((t) => t.id).join(", ")}`);
			process.exit(1);
		}
		if (opts.json) {
			console.log(JSON.stringify(tool, null, 2));
			return;
		}
		console.log(`Tool:      ${tool.id}`);
		console.log(`Enabled:   ${tool.enabled ? "yes" : "no"}`);
		console.log(`Groups:    ${tool.groups.map((g) => g.replace("group:", "")).join(", ") || "(none)"}`);
		if (tool.requires?.bins?.length) console.log(`Requires:  ${tool.requires.bins.join(", ")}`);
		if (tool.requires?.env?.length) console.log(`Env vars:  ${tool.requires.env.join(", ")}`);
		if (tool.condition) console.log(`Condition: ${tool.condition}`);
		if (tool.install?.length) {
			console.log(`Install:`);
			for (const inst of tool.install) console.log(`  ${inst.label ?? inst.kind}: ${inst.formula ?? inst.bins?.join(", ") ?? ""}`);
		}
	});
	tools.command("groups").description("List all tool groups and their members").option("--json", "JSON output").action(async (opts) => {
		const data = await fetchToolsStatus({
			...tools.opts(),
			...opts
		});
		if (opts.json) {
			console.log(JSON.stringify(data.groups, null, 2));
			return;
		}
		for (const [group, members] of Object.entries(data.groups)) {
			console.log(`${group.replace("group:", "")}:`);
			for (const member of members) console.log(`  ${member}`);
			console.log();
		}
	});
	tools.command("reload").description("Reload tool policies from config (no gateway restart needed)").action(async () => {
		const parentOpts = tools.opts();
		try {
			const data = await callGatewayFromCli("tools.reload", parentOpts, {}, { progress: true });
			console.log(`Config reloaded. Active profile: ${data.profile}`);
		} catch (err) {
			console.error(`Reload failed: ${String(err)}`);
			process.exit(1);
		}
	});
	tools.command("enable").description("Enable a tool or group (adds to alsoAllow, removes from deny)").argument("<name>", "Tool ID or group:name").option("--agent <id>", "Scope to specific agent").action(async (name, opts) => {
		const parentOpts = tools.opts();
		const writeResult = await readConfigFileSnapshotForWrite();
		const cfg = loadConfig();
		const { tools: toolsCfg } = resolveToolsConfig(cfg, opts.agent);
		toolsCfg.deny = removeFromArray(toolsCfg.deny, name);
		if (toolsCfg.deny.length === 0) delete toolsCfg.deny;
		if (Array.isArray(toolsCfg.allow)) {
			if (!toolsCfg.allow.includes(name)) toolsCfg.allow.push(name);
		} else {
			toolsCfg.alsoAllow = toolsCfg.alsoAllow ?? [];
			if (!toolsCfg.alsoAllow.includes(name)) toolsCfg.alsoAllow.push(name);
		}
		await writeConfigAndReload(cfg, writeResult, parentOpts);
		console.log(`Enabled ${name}${opts.agent ? ` for agent ${opts.agent}` : " (global)"}`);
	});
	tools.command("disable").description("Disable a tool or group (adds to deny, removes from alsoAllow)").argument("<name>", "Tool ID or group:name").option("--agent <id>", "Scope to specific agent").action(async (name, opts) => {
		const parentOpts = tools.opts();
		const writeResult = await readConfigFileSnapshotForWrite();
		const cfg = loadConfig();
		const { tools: toolsCfg } = resolveToolsConfig(cfg, opts.agent);
		toolsCfg.alsoAllow = removeFromArray(toolsCfg.alsoAllow, name);
		if (toolsCfg.alsoAllow.length === 0) delete toolsCfg.alsoAllow;
		if (Array.isArray(toolsCfg.allow)) {
			toolsCfg.allow = removeFromArray(toolsCfg.allow, name);
			if (toolsCfg.allow.length === 0) delete toolsCfg.allow;
		}
		toolsCfg.deny = toolsCfg.deny ?? [];
		if (!toolsCfg.deny.includes(name)) toolsCfg.deny.push(name);
		await writeConfigAndReload(cfg, writeResult, parentOpts);
		console.log(`Disabled ${name}${opts.agent ? ` for agent ${opts.agent}` : " (global)"}`);
	});
	tools.command("profile").description("Set the tool profile (minimal, coding, messaging, full)").argument("<profile>", "Profile ID").option("--agent <id>", "Scope to specific agent").action(async (profile, opts) => {
		const valid = [
			"minimal",
			"coding",
			"messaging",
			"full"
		];
		if (!valid.includes(profile)) {
			console.error(`Invalid profile: ${profile}. Valid: ${valid.join(", ")}`);
			process.exit(1);
		}
		const parentOpts = tools.opts();
		const writeResult = await readConfigFileSnapshotForWrite();
		const cfg = loadConfig();
		const { tools: toolsCfg } = resolveToolsConfig(cfg, opts.agent);
		toolsCfg.profile = profile;
		await writeConfigAndReload(cfg, writeResult, parentOpts);
		console.log(`Profile set to ${profile}${opts.agent ? ` for agent ${opts.agent}` : " (global)"}`);
	});
	tools.command("create").description("Scaffold a new tool (meta.ts + implementation)").argument("<name>", "Tool name in kebab-case (e.g. my-tool)").option("--group <name>", "Group to add tool to (repeatable)", (v, prev) => {
		const g = v.startsWith("group:") ? v : `group:${v}`;
		return [...prev, g];
	}, []).action(async (name, opts) => {
		const groups = opts.group.length > 0 ? opts.group : ["group:minion"];
		const toolsDir = resolve(process.cwd(), "src/agents/tools");
		try {
			const { metaPath, implPath } = scaffoldTool({
				name,
				groups,
				toolsDir
			});
			console.log(`Created: ${metaPath}`);
			console.log(`Created: ${implPath}`);
			console.log("\nRunning codegen...");
			await runCodegen(process.cwd());
			console.log("\nNext steps:");
			console.log("  1. Implement the tool in the generated .ts file");
			console.log("  2. If the tool needs options from the context bag:");
			console.log("     - Add contextKeys to the meta.ts file");
			console.log("     - Add a case to buildToolOptions() in openclaw-tools.ts");
			console.log("  3. If tool ordering matters, add to TOOL_ORDER in openclaw-tools.ts");
		} catch (err) {
			console.error(String(err));
			process.exit(1);
		}
	});
	tools.command("install").description("Install dependencies for a tool").argument("<tool-id>", "Tool identifier").action(async (toolId) => {
		const tool = (await fetchToolsStatus(tools.opts())).tools.find((t) => t.id === toolId);
		if (!tool) {
			console.error(`Unknown tool: ${toolId}`);
			process.exit(1);
		}
		if (!tool.install || tool.install.length === 0) {
			console.log(`Tool ${toolId} has no install instructions.`);
			if (tool.requires?.bins?.length) console.log(`Required binaries: ${tool.requires.bins.join(", ")}`);
			return;
		}
		const result = await installTool(tool.install);
		console.log(result.message);
		if (!result.installed) process.exit(1);
	});
}

//#endregion
export { registerToolsCli };