import { t as CONFIG_PATH, u as resolveGatewayPort } from "./paths-mmi2xb99.js";
import { E as danger, L as theme, c as defaultRuntime } from "./subsystem-D4e4nOE7.js";
import { i as displayPath } from "./utils-DLd4fFd2.js";
import "./boolean-Djq1Hgv8.js";
import "./env-Bdq5Y-tD.js";
import { a as readConfigFileSnapshot, l as validateConfigObjectWithPlugins, r as loadConfig, s as writeConfigFile } from "./config-C9wUwpYY.js";
import "./agent-scope-BcV171ci.js";
import { t as runCommandWithTimeout } from "./exec-B_ziy0Fn.js";
import "./edwinpai-root-BaNzp4sP.js";
import "./model-selection-ChysOie6.js";
import "./github-copilot-token-D-EydSr2.js";
import { t as formatCliCommand } from "./command-format-XQlUKdf6.js";
import "./manifest-registry-DThGPzHr.js";
import "./skills-B9WXNmn5.js";
import { t as formatDocsLink } from "./links-DlcX3SnL.js";
import { C as normalizeServePath, S as normalizeHooksPath, T as resolveGmailHookRuntimeConfig, _ as buildGwsWatchServeArgs, a as ensureTopic, b as generateHookToken, c as DEFAULT_GMAIL_LABEL, d as DEFAULT_GMAIL_SERVE_BIND, f as DEFAULT_GMAIL_SERVE_PATH, g as buildDefaultHookUrl, h as DEFAULT_GMAIL_TOPIC, i as ensureTailscaleEndpoint, l as DEFAULT_GMAIL_MAX_BYTES, m as DEFAULT_GMAIL_SUBSCRIPTION, n as ensureGcloudAuth, o as resolveProjectIdFromGwsCredentials, p as DEFAULT_GMAIL_SERVE_PORT, r as ensureSubscription, s as runGcloud, t as ensureDependency, u as DEFAULT_GMAIL_RENEW_MINUTES, v as buildGwsWatchStartArgs, w as parseTopicPath, x as mergeHookPresets, y as buildTopicPath } from "./gmail-setup-utils-CSYgXgtK.js";
import { spawn } from "node:child_process";

//#region ../../src/hooks/gmail-ops.ts
const DEFAULT_GMAIL_TOPIC_IAM_MEMBER = "serviceAccount:gmail-api-push@system.gserviceaccount.com";
async function runGmailSetup(opts) {
	await ensureDependency("gcloud", ["--cask", "gcloud-cli"]);
	await ensureDependency("gws", ["@googleworkspace/cli"]);
	if (opts.tailscale !== "off" && !opts.pushEndpoint) await ensureDependency("tailscale", ["tailscale"]);
	await ensureGcloudAuth();
	const configSnapshot = await readConfigFileSnapshot();
	if (!configSnapshot.valid) throw new Error(`Config invalid: ${CONFIG_PATH}`);
	const baseConfig = configSnapshot.config;
	const hooksPath = normalizeHooksPath(baseConfig.hooks?.path);
	const hookToken = opts.hookToken ?? baseConfig.hooks?.token ?? generateHookToken();
	const pushToken = opts.pushToken ?? baseConfig.hooks?.gmail?.pushToken ?? generateHookToken();
	const topicInput = opts.topic ?? baseConfig.hooks?.gmail?.topic ?? DEFAULT_GMAIL_TOPIC;
	const parsedTopic = parseTopicPath(topicInput);
	const topicName = parsedTopic?.topicName ?? topicInput;
	const projectId = opts.project ?? parsedTopic?.projectId ?? await resolveProjectIdFromGwsCredentials();
	if (!projectId) throw new Error("GCP project id required (use --project or ensure gws credentials are available)");
	const topicPath = buildTopicPath(projectId, topicName);
	const subscription = opts.subscription ?? DEFAULT_GMAIL_SUBSCRIPTION;
	const label = opts.label ?? DEFAULT_GMAIL_LABEL;
	const hookUrl = opts.hookUrl ?? baseConfig.hooks?.gmail?.hookUrl ?? buildDefaultHookUrl(hooksPath, resolveGatewayPort(baseConfig));
	const serveBind = opts.bind ?? DEFAULT_GMAIL_SERVE_BIND;
	const servePort = opts.port ?? DEFAULT_GMAIL_SERVE_PORT;
	const configuredServePath = opts.path ?? baseConfig.hooks?.gmail?.serve?.path;
	const configuredTailscaleTarget = opts.tailscaleTarget ?? baseConfig.hooks?.gmail?.tailscale?.target;
	const normalizedServePath = typeof configuredServePath === "string" && configuredServePath.trim().length > 0 ? normalizeServePath(configuredServePath) : DEFAULT_GMAIL_SERVE_PATH;
	const normalizedTailscaleTarget = typeof configuredTailscaleTarget === "string" && configuredTailscaleTarget.trim().length > 0 ? configuredTailscaleTarget.trim() : void 0;
	const includeBody = opts.includeBody ?? true;
	const maxBytes = opts.maxBytes ?? DEFAULT_GMAIL_MAX_BYTES;
	const renewEveryMinutes = opts.renewEveryMinutes ?? DEFAULT_GMAIL_RENEW_MINUTES;
	const tailscaleMode = opts.tailscale ?? "funnel";
	const servePath = normalizeServePath(tailscaleMode !== "off" && !normalizedTailscaleTarget ? "/" : normalizedServePath);
	const tailscalePath = normalizeServePath(opts.tailscalePath ?? baseConfig.hooks?.gmail?.tailscale?.path ?? (tailscaleMode !== "off" ? normalizedServePath : servePath));
	await runGcloud([
		"config",
		"set",
		"project",
		projectId,
		"--quiet"
	]);
	await runGcloud([
		"services",
		"enable",
		"gmail.googleapis.com",
		"pubsub.googleapis.com",
		"--project",
		projectId,
		"--quiet"
	]);
	await ensureTopic(projectId, topicName);
	await runGcloud([
		"pubsub",
		"topics",
		"add-iam-policy-binding",
		topicName,
		"--project",
		projectId,
		"--member",
		DEFAULT_GMAIL_TOPIC_IAM_MEMBER,
		"--role",
		"roles/pubsub.publisher",
		"--quiet"
	]);
	const pushEndpoint = opts.pushEndpoint ? opts.pushEndpoint : await ensureTailscaleEndpoint({
		mode: tailscaleMode,
		path: tailscalePath,
		port: servePort,
		target: normalizedTailscaleTarget,
		token: pushToken
	});
	if (!pushEndpoint) throw new Error("push endpoint required (set --push-endpoint)");
	await ensureSubscription(projectId, subscription, topicName, pushEndpoint);
	await startGmailWatch({
		account: opts.account,
		label,
		topic: topicPath
	}, true);
	const validated = validateConfigObjectWithPlugins({
		...baseConfig,
		hooks: {
			...baseConfig.hooks,
			enabled: true,
			path: hooksPath,
			token: hookToken,
			presets: mergeHookPresets(baseConfig.hooks?.presets, "gmail"),
			gmail: {
				...baseConfig.hooks?.gmail,
				account: opts.account,
				label,
				topic: topicPath,
				subscription,
				pushToken,
				hookUrl,
				includeBody,
				maxBytes,
				renewEveryMinutes,
				serve: {
					...baseConfig.hooks?.gmail?.serve,
					bind: serveBind,
					port: servePort,
					path: servePath
				},
				tailscale: {
					...baseConfig.hooks?.gmail?.tailscale,
					mode: tailscaleMode,
					path: tailscalePath,
					target: normalizedTailscaleTarget
				}
			}
		}
	});
	if (!validated.ok) throw new Error(`Config validation failed: ${validated.issues[0]?.message ?? "invalid"}`);
	await writeConfigFile(validated.config);
	const summary = {
		projectId,
		topic: topicPath,
		subscription,
		pushEndpoint,
		hookUrl,
		hookToken,
		pushToken,
		serve: {
			bind: serveBind,
			port: servePort,
			path: servePath
		}
	};
	if (opts.json) {
		defaultRuntime.log(JSON.stringify(summary, null, 2));
		return;
	}
	defaultRuntime.log("Gmail hooks configured:");
	defaultRuntime.log(`- project: ${projectId}`);
	defaultRuntime.log(`- topic: ${topicPath}`);
	defaultRuntime.log(`- subscription: ${subscription}`);
	defaultRuntime.log(`- push endpoint: ${pushEndpoint}`);
	defaultRuntime.log(`- hook url: ${hookUrl}`);
	defaultRuntime.log(`- config: ${displayPath(CONFIG_PATH)}`);
	defaultRuntime.log(`Next: ${formatCliCommand("edwinpai webhooks gmail run")}`);
}
async function runGmailService(opts) {
	await ensureDependency("gws", ["@googleworkspace/cli"]);
	const resolved = resolveGmailHookRuntimeConfig(loadConfig(), {
		account: opts.account,
		topic: opts.topic,
		subscription: opts.subscription,
		label: opts.label,
		hookToken: opts.hookToken,
		pushToken: opts.pushToken,
		hookUrl: opts.hookUrl,
		serveBind: opts.bind,
		servePort: opts.port,
		servePath: opts.path,
		includeBody: opts.includeBody,
		maxBytes: opts.maxBytes,
		renewEveryMinutes: opts.renewEveryMinutes,
		tailscaleMode: opts.tailscale,
		tailscalePath: opts.tailscalePath,
		tailscaleTarget: opts.tailscaleTarget
	});
	if (!resolved.ok) throw new Error(resolved.error);
	const runtimeConfig = resolved.value;
	if (runtimeConfig.tailscale.mode !== "off") {
		await ensureDependency("tailscale", ["tailscale"]);
		await ensureTailscaleEndpoint({
			mode: runtimeConfig.tailscale.mode,
			path: runtimeConfig.tailscale.path,
			port: runtimeConfig.serve.port,
			target: runtimeConfig.tailscale.target
		});
	}
	await startGmailWatch(runtimeConfig);
	let shuttingDown = false;
	let child = spawnGwsServe(runtimeConfig);
	const renewMs = runtimeConfig.renewEveryMinutes * 6e4;
	const renewTimer = setInterval(() => {
		startGmailWatch(runtimeConfig);
	}, renewMs);
	const shutdown = () => {
		if (shuttingDown) return;
		shuttingDown = true;
		clearInterval(renewTimer);
		child.kill("SIGTERM");
	};
	process.on("SIGINT", shutdown);
	process.on("SIGTERM", shutdown);
	child.on("exit", () => {
		if (shuttingDown) return;
		defaultRuntime.log("gws watch serve exited; restarting in 2s");
		setTimeout(() => {
			if (shuttingDown) return;
			child = spawnGwsServe(runtimeConfig);
		}, 2e3);
	});
}
function spawnGwsServe(cfg) {
	const args = buildGwsWatchServeArgs(cfg);
	defaultRuntime.log(`Starting gws ${args.join(" ")}`);
	return spawn("gws", args, { stdio: "inherit" });
}
async function startGmailWatch(cfg, fatal = false) {
	const result = await runCommandWithTimeout(["gws", ...buildGwsWatchStartArgs(cfg)], { timeoutMs: 12e4 });
	if (result.code !== 0) {
		const message = result.stderr || result.stdout || "gws watch start failed";
		if (fatal) throw new Error(message);
		defaultRuntime.error(message);
	}
}

//#endregion
//#region ../../src/cli/webhooks-cli.ts
function registerWebhooksCli(program) {
	const gmail = program.command("webhooks").description("Webhook helpers and integrations").addHelpText("after", () => `\n${theme.muted("Docs:")} ${formatDocsLink("/cli/webhooks", "docs.edwinpai.com/cli/webhooks")}\n`).command("gmail").description("Gmail Pub/Sub hooks (via gws)");
	gmail.command("setup").description("Configure Gmail watch + Pub/Sub + EdwinPAI hooks").requiredOption("--account <email>", "Gmail account to watch").option("--project <id>", "GCP project id (OAuth client owner)").option("--topic <name>", "Pub/Sub topic name", DEFAULT_GMAIL_TOPIC).option("--subscription <name>", "Pub/Sub subscription name", DEFAULT_GMAIL_SUBSCRIPTION).option("--label <label>", "Gmail label to watch", DEFAULT_GMAIL_LABEL).option("--hook-url <url>", "EdwinPAI hook URL").option("--hook-token <token>", "EdwinPAI hook token").option("--push-token <token>", "Push token for gws watch serve").option("--bind <host>", "gws watch serve bind host", DEFAULT_GMAIL_SERVE_BIND).option("--port <port>", "gws watch serve port", String(DEFAULT_GMAIL_SERVE_PORT)).option("--path <path>", "gws watch serve path", DEFAULT_GMAIL_SERVE_PATH).option("--include-body", "Include email body snippets", true).option("--max-bytes <n>", "Max bytes for body snippets", String(DEFAULT_GMAIL_MAX_BYTES)).option("--renew-minutes <n>", "Renew watch every N minutes", String(DEFAULT_GMAIL_RENEW_MINUTES)).option("--tailscale <mode>", "Expose push endpoint via tailscale (funnel|serve|off)", "funnel").option("--tailscale-path <path>", "Path for tailscale serve/funnel").option("--tailscale-target <target>", "Tailscale serve/funnel target (port, host:port, or URL)").option("--push-endpoint <url>", "Explicit Pub/Sub push endpoint").option("--json", "Output JSON summary", false).action(async (opts) => {
		try {
			await runGmailSetup(parseGmailSetupOptions(opts));
		} catch (err) {
			defaultRuntime.error(danger(String(err)));
			defaultRuntime.exit(1);
		}
	});
	gmail.command("run").description("Run gws gmail +watch + auto-renew loop").option("--account <email>", "Gmail account to watch").option("--topic <topic>", "Pub/Sub topic path (projects/.../topics/..)").option("--subscription <name>", "Pub/Sub subscription name").option("--label <label>", "Gmail label to watch").option("--hook-url <url>", "EdwinPAI hook URL").option("--hook-token <token>", "EdwinPAI hook token").option("--push-token <token>", "Push token for gws watch serve").option("--bind <host>", "gws watch serve bind host").option("--port <port>", "gws watch serve port").option("--path <path>", "gws watch serve path").option("--include-body", "Include email body snippets").option("--max-bytes <n>", "Max bytes for body snippets").option("--renew-minutes <n>", "Renew watch every N minutes").option("--tailscale <mode>", "Expose push endpoint via tailscale (funnel|serve|off)").option("--tailscale-path <path>", "Path for tailscale serve/funnel").option("--tailscale-target <target>", "Tailscale serve/funnel target (port, host:port, or URL)").action(async (opts) => {
		try {
			await runGmailService(parseGmailRunOptions(opts));
		} catch (err) {
			defaultRuntime.error(danger(String(err)));
			defaultRuntime.exit(1);
		}
	});
}
function parseGmailSetupOptions(raw) {
	const accountRaw = raw.account;
	const account = typeof accountRaw === "string" ? accountRaw.trim() : "";
	if (!account) throw new Error("--account is required");
	return {
		account,
		project: stringOption(raw.project),
		topic: stringOption(raw.topic),
		subscription: stringOption(raw.subscription),
		label: stringOption(raw.label),
		hookUrl: stringOption(raw.hookUrl),
		hookToken: stringOption(raw.hookToken),
		pushToken: stringOption(raw.pushToken),
		bind: stringOption(raw.bind),
		port: numberOption(raw.port),
		path: stringOption(raw.path),
		includeBody: booleanOption(raw.includeBody),
		maxBytes: numberOption(raw.maxBytes),
		renewEveryMinutes: numberOption(raw.renewMinutes),
		tailscale: stringOption(raw.tailscale),
		tailscalePath: stringOption(raw.tailscalePath),
		tailscaleTarget: stringOption(raw.tailscaleTarget),
		pushEndpoint: stringOption(raw.pushEndpoint),
		json: Boolean(raw.json)
	};
}
function parseGmailRunOptions(raw) {
	return {
		account: stringOption(raw.account),
		topic: stringOption(raw.topic),
		subscription: stringOption(raw.subscription),
		label: stringOption(raw.label),
		hookUrl: stringOption(raw.hookUrl),
		hookToken: stringOption(raw.hookToken),
		pushToken: stringOption(raw.pushToken),
		bind: stringOption(raw.bind),
		port: numberOption(raw.port),
		path: stringOption(raw.path),
		includeBody: booleanOption(raw.includeBody),
		maxBytes: numberOption(raw.maxBytes),
		renewEveryMinutes: numberOption(raw.renewMinutes),
		tailscale: stringOption(raw.tailscale),
		tailscalePath: stringOption(raw.tailscalePath),
		tailscaleTarget: stringOption(raw.tailscaleTarget)
	};
}
function stringOption(value) {
	if (typeof value !== "string") return;
	const trimmed = value.trim();
	return trimmed ? trimmed : void 0;
}
function numberOption(value) {
	if (value === void 0 || value === null) return;
	const n = typeof value === "number" ? value : Number(value);
	if (!Number.isFinite(n) || n <= 0) return;
	return Math.floor(n);
}
function booleanOption(value) {
	if (value === void 0 || value === null) return;
	return Boolean(value);
}

//#endregion
export { registerWebhooksCli };