import { existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
import { join } from "node:path";
//#region extensions/crypto/src/services/user-tool-service.ts
/**
* User-Defined Tool Service — CRUD for user-created tools with persistence.
*
* Users define tools in plain English or structured JSON. The service:
* 1. Stores tool definitions to disk (~/.openclawnch/user-tools/)
* 2. Compiles definitions into executable AnyAgentTool-compatible objects
* 3. Manages lifecycle: create, update, disable, delete, list
* 4. Provides a registry that the plugin can query for dynamic tool loading
*
* Tool types:
* - api_connector: wraps an HTTP API endpoint as a tool
* - composed: chains existing tools into a higher-level operation
* - custom: user-defined logic via natural language description (LLM-interpreted)
*
* All user tools run through the SandboxRuntime for safety.
*/
const RESERVED_PREFIXES = [
	"defi_",
	"clawnch",
	"bankr_",
	"compound_",
	"agent_",
	"skill_",
	"session_",
	"fiat_",
	"market_",
	"herd_",
	"crypto_",
	"watch_",
	"manage_"
];
const RESERVED_NAMES = new Set([
	"transfer",
	"bridge",
	"permit2",
	"cost_basis",
	"analytics",
	"block_explorer",
	"liquidity",
	"wayfinder",
	"molten",
	"hummingbot",
	"privacy",
	"browser",
	"governance",
	"farcaster",
	"safe",
	"airdrop",
	"nft",
	"yield",
	"approvals"
]);
function isNameReserved(name) {
	if (RESERVED_NAMES.has(name)) return true;
	for (const prefix of RESERVED_PREFIXES) if (name.startsWith(prefix)) return true;
	return false;
}
function isValidToolName(name) {
	return /^[a-z][a-z0-9_]{2,40}$/.test(name);
}
var UserToolService = class {
	tools = /* @__PURE__ */ new Map();
	stateDir;
	constructor(opts) {
		this.stateDir = opts?.stateDir ?? join(process.env.HOME ?? "", ".openclawnch", "user-tools");
		this.loadState();
	}
	/** Create a new user-defined tool. */
	create(params) {
		if (!isValidToolName(params.name)) throw new UserToolError(`Invalid tool name "${params.name}". Must be 3-40 chars, lowercase alphanumeric + underscores, starting with a letter.`);
		if (isNameReserved(params.name)) throw new UserToolError(`Tool name "${params.name}" conflicts with a built-in tool or reserved prefix.`);
		if (this.getByName(params.name)) throw new UserToolError(`A user tool named "${params.name}" already exists.`);
		this.validateDefinition(params.definition);
		const id = `ut_${Date.now()}_${Math.random().toString(36).slice(2, 8)}`;
		const now = Date.now();
		const tool = {
			id,
			name: params.name,
			label: params.label,
			description: params.description,
			createdBy: params.createdBy,
			params: params.params,
			definition: params.definition,
			isWrite: params.isWrite ?? false,
			enabled: true,
			usageCount: 0,
			maxBudgetUsd: params.maxBudgetUsd ?? 1,
			tags: params.tags ?? [],
			createdAt: now,
			updatedAt: now
		};
		this.tools.set(id, tool);
		this.saveState();
		return tool;
	}
	/** Update an existing user tool. */
	update(id, updates) {
		const tool = this.tools.get(id);
		if (!tool) return null;
		if (updates.definition) this.validateDefinition(updates.definition);
		Object.assign(tool, updates, { updatedAt: Date.now() });
		this.saveState();
		return tool;
	}
	/** Delete a user tool. */
	delete(id) {
		const existed = this.tools.delete(id);
		if (existed) this.saveState();
		return existed;
	}
	/** Get a user tool by ID. */
	get(id) {
		return this.tools.get(id) ?? null;
	}
	/** Get a user tool by name. */
	getByName(name) {
		for (const t of this.tools.values()) if (t.name === name) return t;
		return null;
	}
	/** List all user tools, optionally filtered. */
	list(opts) {
		let all = Array.from(this.tools.values());
		if (opts?.createdBy) all = all.filter((t) => t.createdBy === opts.createdBy);
		if (opts?.enabled !== void 0) all = all.filter((t) => t.enabled === opts.enabled);
		if (opts?.type) all = all.filter((t) => t.definition.type === opts.type);
		return all.sort((a, b) => b.updatedAt - a.updatedAt);
	}
	/** Get all enabled user tools (for runtime registration). */
	getEnabledTools() {
		return Array.from(this.tools.values()).filter((t) => t.enabled);
	}
	/** Increment usage count after a tool execution. */
	recordUsage(id) {
		const tool = this.tools.get(id);
		if (tool) {
			tool.usageCount += 1;
			tool.updatedAt = Date.now();
			this.saveState();
		}
	}
	/** Check if a name is available for a new tool. */
	isNameAvailable(name) {
		if (!isValidToolName(name)) return {
			available: false,
			reason: "Invalid format. Must be 3-40 chars, lowercase alphanumeric + underscores."
		};
		if (isNameReserved(name)) return {
			available: false,
			reason: "Conflicts with a built-in tool or reserved prefix."
		};
		if (this.getByName(name)) return {
			available: false,
			reason: "A user tool with this name already exists."
		};
		return { available: true };
	}
	/** Clear all state (for testing). */
	clear() {
		this.tools.clear();
	}
	validateDefinition(def) {
		switch (def.type) {
			case "api_connector":
				if (!def.baseUrl) throw new UserToolError("API connector requires a baseUrl.");
				if (!def.path) throw new UserToolError("API connector requires a path.");
				if (!def.method) throw new UserToolError("API connector requires a method.");
				try {
					new URL(def.baseUrl);
				} catch {
					throw new UserToolError(`Invalid baseUrl: "${def.baseUrl}".`);
				}
				break;
			case "composed":
				if (!def.steps || def.steps.length === 0) throw new UserToolError("Composed tool requires at least one step.");
				if (def.steps.length > 10) throw new UserToolError("Composed tool cannot have more than 10 steps.");
				for (const step of def.steps) if (!step.tool) throw new UserToolError(`Step "${step.label}" requires a tool name.`);
				break;
			case "custom":
				if (!def.behavior || def.behavior.length < 10) throw new UserToolError("Custom tool requires a behavior description (at least 10 chars).");
				if (!def.allowedTools || def.allowedTools.length === 0) throw new UserToolError("Custom tool requires at least one allowed tool.");
				if ((def.maxCalls ?? 5) > 20) throw new UserToolError("Custom tool maxCalls cannot exceed 20.");
				break;
			default: throw new UserToolError(`Unknown tool type: ${def.type}`);
		}
	}
	loadState() {
		try {
			const filePath = join(this.stateDir, "tools.json");
			if (existsSync(filePath)) {
				const data = JSON.parse(readFileSync(filePath, "utf8"));
				for (const t of data) this.tools.set(t.id, t);
			}
		} catch {}
	}
	saveState() {
		try {
			if (!existsSync(this.stateDir)) mkdirSync(this.stateDir, { recursive: true });
			writeFileSync(join(this.stateDir, "tools.json"), JSON.stringify(Array.from(this.tools.values()), null, 2), "utf8");
		} catch {}
	}
};
var UserToolError = class extends Error {
	constructor(message) {
		super(message);
		this.name = "UserToolError";
	}
};
let instance = null;
function getUserToolService(opts) {
	if (!instance) instance = new UserToolService(opts);
	return instance;
}
function resetUserToolService() {
	instance?.clear();
	instance = null;
}
//#endregion
export { UserToolError, UserToolService, getUserToolService, resetUserToolService };

//# sourceMappingURL=user-tool-service.mjs.map