import { Type } from "@sinclair/typebox";
//#region src/agent/tools/cronjob-tool.ts
const CRON_THREAT_PATTERNS = [
	[/ignore\s+(previous|all|above)\s+instructions/i, "prompt_injection"],
	[/do\s+not\s+tell\s+the\s+user/i, "deception"],
	[/system\s+prompt\s+override/i, "sys_prompt_override"],
	[/curl\s+[^\n]*\$\{?\w*(KEY|TOKEN|SECRET|PASSWORD)/i, "exfil_curl"],
	[/cat\s+[^\n]*(\.env|credentials|\.netrc)/i, "read_secrets"],
	[/rm\s+-rf\s+\//i, "destructive_rm"]
];
function scanCronPrompt(prompt) {
	for (const [pattern, id] of CRON_THREAT_PATTERNS) if (pattern.test(prompt)) return `Blocked: prompt matches threat pattern '${id}'. Cron prompts must not contain injection or exfiltration payloads.`;
	return null;
}
const CronjobSchema = Type.Object({
	action: Type.Union([
		Type.Literal("list"),
		Type.Literal("create"),
		Type.Literal("update"),
		Type.Literal("remove"),
		Type.Literal("enable"),
		Type.Literal("disable"),
		Type.Literal("history")
	], { description: "Action to perform on cron jobs" }),
	name: Type.Optional(Type.String({ description: "Human-readable job name" })),
	schedule: Type.Optional(Type.String({ description: "Cron schedule expression. Examples:\n  \"0 9 * * *\" = every day at 9:00 AM\n  \"*/30 * * * *\" = every 30 minutes\n  \"0 9 * * 1-5\" = weekdays at 9:00 AM\n  \"0 0 1 * *\" = first day of each month" })),
	message: Type.Optional(Type.String({ description: "Instruction for the agent when the job runs (agentTurn payload; typically a fresh session)." })),
	timezone: Type.Optional(Type.String({ description: "IANA timezone (e.g. Asia/Shanghai, America/New_York). Must be one supported by the cron store." })),
	sessionTarget: Type.Optional(Type.Union([Type.Literal("main"), Type.Literal("isolated")], { description: "\"main\" uses the main session context; \"isolated\" (default on create) uses a separate session per run." })),
	agentId: Type.Optional(Type.String({ description: "Agent profile id for isolated jobs (session key). Omit to use the configured default agent (usually `main`)." })),
	workingDirectory: Type.Optional(Type.String({ description: "Absolute workspace path on the gateway host for isolated jobs. Omit to use the agent default workspace." })),
	jobId: Type.Optional(Type.String({ description: "Job ID (from list output)" }))
});
function textResult(text) {
	return {
		content: [{
			type: "text",
			text
		}],
		details: {}
	};
}
function formatJob(job) {
	const status = job.enabled ? "▶️ active" : "⏸️ disabled";
	const payloadText = job.payload.kind === "agentTurn" ? job.payload.message : job.payload.text;
	const truncatedPayload = payloadText.length > 100 ? `${payloadText.slice(0, 100)}...` : payloadText;
	return [
		`${status} ${job.name ?? "(unnamed)"} (${job.id})`,
		`  Schedule: ${job.schedule}${job.timezone ? ` (${job.timezone})` : ""}`,
		`  Type: ${job.payload.kind}`,
		`  Message: ${truncatedPayload}`,
		`  Next run: ${job.next_run ?? "N/A"}`,
		`  Session: ${job.sessionTarget ?? "main"}`,
		`  Agent: ${job.agentId?.trim() || "(default)"}`,
		`  Workspace: ${job.workingDirectory?.trim() || "(agent default)"}`
	].join("\n");
}
function formatExecution(exec) {
	const dur = exec.duration != null ? `${(exec.duration / 1e3).toFixed(1)}s` : "N/A";
	const lines = [`[${exec.status}] ${exec.startedAt} (${dur})`];
	if (exec.summary) lines.push(`  Summary: ${exec.summary.slice(0, 200)}`);
	if (exec.error) lines.push(`  Error: ${exec.error.slice(0, 200)}`);
	return lines.join("\n");
}
function createCronjobTool(deps) {
	return {
		name: "cronjob",
		label: "⏰ Cronjob",
		description: "Manage scheduled tasks (cron jobs) that run automatically.\n\nEach job has a cron schedule and a message the agent runs when triggered (agent turn).\n\nACTIONS:\n- list: Show all scheduled jobs with status and next run time\n- create: Create a job (requires schedule and message; optional name, timezone, sessionTarget, agentId, workingDirectory)\n- update: Change schedule, message, name, timezone, sessionTarget, agentId, or workingDirectory (requires jobId)\n- remove: Delete a job (requires jobId)\n- enable / disable: Toggle a job (requires jobId)\n- history: Recent executions for a job (requires jobId)",
		parameters: CronjobSchema,
		async execute(_toolCallId, params, _signal) {
			const cron = deps.getCronService();
			if (!cron) return textResult("Cron service is not available in this environment.");
			try {
				switch (params.action) {
					case "list": {
						const jobs = await cron.listJobs();
						if (jobs.length === 0) return textResult("No scheduled jobs.");
						return {
							content: [{
								type: "text",
								text: jobs.map(formatJob).join("\n\n")
							}],
							details: {}
						};
					}
					case "create": {
						if (!params.schedule?.trim() || !params.message?.trim()) return textResult("Error: create requires schedule and message.");
						const scanResult = scanCronPrompt(params.message);
						if (scanResult) return textResult(`Error: ${scanResult}`);
						const payload = {
							kind: "agentTurn",
							message: params.message.trim()
						};
						const result = await cron.addJob(params.schedule.trim(), {
							name: params.name?.trim() || void 0,
							timezone: params.timezone?.trim() || void 0,
							sessionTarget: params.sessionTarget ?? "isolated",
							...params.agentId?.trim() ? { agentId: params.agentId.trim() } : {},
							...params.workingDirectory?.trim() ? { workingDirectory: params.workingDirectory.trim() } : {},
							payload
						});
						return textResult(`Created job${params.name ? ` "${params.name.trim()}"` : ""} (${result.id})\nSchedule: ${result.schedule}`);
					}
					case "update": {
						if (!params.jobId?.trim()) return textResult("Error: update requires jobId.");
						const updates = {};
						if (params.schedule?.trim()) updates.schedule = params.schedule.trim();
						if (params.message != null && params.message.trim()) {
							const scanResult = scanCronPrompt(params.message);
							if (scanResult) return textResult(`Error: ${scanResult}`);
							updates.payload = {
								kind: "agentTurn",
								message: params.message.trim()
							};
						}
						if (params.timezone?.trim()) updates.timezone = params.timezone.trim();
						if (params.name !== void 0) updates.name = params.name.trim() || void 0;
						if (params.sessionTarget !== void 0) updates.sessionTarget = params.sessionTarget;
						if (params.agentId !== void 0) updates.agentId = params.agentId.trim() || null;
						if (params.workingDirectory !== void 0) updates.workingDirectory = params.workingDirectory.trim() || null;
						if (Object.keys(updates).length === 0) return textResult("Error: update requires at least one of schedule, message, name, timezone, sessionTarget, agentId, workingDirectory.");
						return textResult(await cron.updateJob(params.jobId.trim(), updates) ? `Updated job ${params.jobId.trim()}.` : `Job ${params.jobId.trim()} not found.`);
					}
					case "remove":
						if (!params.jobId?.trim()) return textResult("Error: remove requires jobId.");
						return textResult(await cron.removeJob(params.jobId.trim()) ? `Removed job ${params.jobId.trim()}.` : `Job ${params.jobId.trim()} not found.`);
					case "disable":
						if (!params.jobId?.trim()) return textResult("Error: disable requires jobId.");
						return textResult(await cron.toggleJob(params.jobId.trim(), false) ? `Disabled job ${params.jobId.trim()}.` : `Job ${params.jobId.trim()} not found.`);
					case "enable":
						if (!params.jobId?.trim()) return textResult("Error: enable requires jobId.");
						return textResult(await cron.toggleJob(params.jobId.trim(), true) ? `Enabled job ${params.jobId.trim()}.` : `Job ${params.jobId.trim()} not found.`);
					case "history": {
						if (!params.jobId?.trim()) return textResult("Error: history requires jobId.");
						const history = await cron.getJobHistory(params.jobId.trim(), 5);
						if (history.length === 0) return textResult(`No execution history for job ${params.jobId.trim()}.`);
						return textResult(history.map(formatExecution).join("\n\n"));
					}
				}
			} catch (error) {
				return textResult(`Error: ${error instanceof Error ? error.message : String(error)}`);
			}
		}
	};
}
//#endregion
export { createCronjobTool, scanCronPrompt };

//# sourceMappingURL=cronjob-tool.js.map