import { t as createSubsystemLogger } from "./subsystem-Ci61Iebe.js";
import { u as DEFAULT_OAUTH_CALLBACK_PORT } from "./paths-aMBPuCJR.js";
import "./auth-profiles-CRqdowVc.js";
import "./env-3oW17BWM.js";
import "./exec-B5OgjUV4.js";
import "./agent-scope-CCFV2dzL.js";
import "./github-copilot-token-sMZoP3ZH.js";
import "./reliability-B6TVU4OW.js";
import "./sqlite-CbyDDiup.js";
import "./tokens-Bvij_SSC.js";
import "./heartbeat-Bf1PpFld.js";
import "./accounts-TaYXhwSR.js";
import "./dock-BRgbOpqS.js";
import "./normalize-Dz9m5w2g.js";
import "./bindings-jC2ZutIF.js";
import "./plugins-6aUfx6Yt.js";
import "./message-channel-BCPYwYUJ.js";
import "./route-reply-CPe3B4Ho.js";
import "./image-ops-DfgorOBP.js";
import "./pi-embedded-helpers-8wQWhTJQ.js";
import "./config-i4b9k_EZ.js";
import "./manifest-registry-BPLS_vpk.js";
import "./chrome-B-E9VvdE.js";
import "./server-context-CECTgnwt.js";
import "./skills-CIrNKatf.js";
import "./redact-BXcZFg1V.js";
import "./errors-CGLTQpIl.js";
import "./ssrf-Clw7QAxV.js";
import { c as updateSessionStore } from "./sessions-N3tZC0jA.js";
import { t as resolveDefaultSessionStorePath } from "./paths-a4Li8t1f.js";
import "./tool-images-D39TNWEi.js";
import "./thinking-B4KYQMkY.js";
import "./chat-trace-YVp5bEfe.js";
import "./response-prefix-template-CpJqwkyc.js";
import { a as jsonResult, u as readStringParam } from "./common-BkBiFnII.js";
import { a as getGoogleClientType, i as getGoogleClientSecret, n as getCredentialsDir, o as getLegacyCredentialsDir, r as getGoogleClientId, t as buildCredentialFilename, u as syncToGogKeyring } from "./gog-credentials-CmQKyfSF.js";
import path from "node:path";
import { Type } from "@sinclair/typebox";
import fs from "node:fs";
import fs$1 from "fs/promises";
import path$1 from "path";
import crypto from "crypto";

//#region src/hooks/gog-oauth-types.ts
/**
* Google OAuth scope mappings
*/
const GOOGLE_SERVICE_SCOPES = {
	gmail: [
		"https://www.googleapis.com/auth/gmail.readonly",
		"https://www.googleapis.com/auth/gmail.send",
		"https://www.googleapis.com/auth/gmail.modify",
		"https://www.googleapis.com/auth/gmail.labels"
	],
	calendar: ["https://www.googleapis.com/auth/calendar.readonly", "https://www.googleapis.com/auth/calendar.events"],
	drive: ["https://www.googleapis.com/auth/drive.readonly", "https://www.googleapis.com/auth/drive.file"],
	contacts: ["https://www.googleapis.com/auth/contacts.readonly"],
	docs: ["https://www.googleapis.com/auth/documents.readonly", "https://www.googleapis.com/auth/documents"],
	sheets: ["https://www.googleapis.com/auth/spreadsheets.readonly", "https://www.googleapis.com/auth/spreadsheets"]
};
/**
* Get OAuth scopes for requested services
*/
function getScopesForServices(services) {
	const scopes = /* @__PURE__ */ new Set();
	for (const service of services) {
		const serviceScopes = GOOGLE_SERVICE_SCOPES[service];
		if (serviceScopes) for (const scope of serviceScopes) scopes.add(scope);
	}
	return Array.from(scopes);
}

//#endregion
//#region src/auth/google/google-auth-provider.ts
/**
* Google OAuth provider implementation.
* Implements the AuthProvider interface for Google OAuth flows.
*
* Extracts Google-specific logic (URL building, token exchange, scope mapping,
* credential storage) behind the provider abstraction so future providers
* (Microsoft, GitHub) can implement the same interface.
*/
const log$2 = createSubsystemLogger("google-auth-provider");
/**
* Create a Google OAuth provider instance.
* Uses factory function pattern per codebase convention.
*/
function createGoogleAuthProvider() {
	return {
		id: "google",
		displayName: "Google",
		buildAuthUrl(params) {
			const clientId = getGoogleClientId();
			const scopes = getScopesForServices(params.services);
			const authUrl = new URL("https://accounts.google.com/o/oauth2/v2/auth");
			authUrl.searchParams.set("client_id", clientId);
			authUrl.searchParams.set("redirect_uri", params.redirectUri);
			authUrl.searchParams.set("response_type", "code");
			authUrl.searchParams.set("scope", scopes.join(" "));
			authUrl.searchParams.set("state", params.state);
			authUrl.searchParams.set("access_type", "offline");
			authUrl.searchParams.set("prompt", "consent");
			authUrl.searchParams.set("login_hint", params.email);
			return authUrl.toString();
		},
		async exchangeCode(code, redirectUri) {
			const clientId = getGoogleClientId();
			const clientSecret = getGoogleClientSecret();
			const response = await fetch("https://oauth2.googleapis.com/token", {
				method: "POST",
				headers: { "Content-Type": "application/x-www-form-urlencoded" },
				body: new URLSearchParams({
					code,
					client_id: clientId,
					client_secret: clientSecret,
					redirect_uri: redirectUri,
					grant_type: "authorization_code"
				})
			});
			if (!response.ok) {
				const error = await response.text();
				throw new Error(`Token exchange failed (${response.status}): ${error}`);
			}
			return await response.json();
		},
		getScopesForServices(services) {
			return getScopesForServices(services);
		},
		getSupportedServices() {
			return Object.keys(GOOGLE_SERVICE_SCOPES);
		},
		async storeCredentials(params) {
			const dir = getCredentialsDir(params.agentId);
			await fs$1.mkdir(dir, {
				recursive: true,
				mode: 448
			});
			const filename = buildCredentialFilename(params.sessionKey, params.email);
			const credPath = path$1.join(dir, filename);
			const credentials = {
				email: params.email,
				accessToken: params.tokens.access_token,
				refreshToken: params.tokens.refresh_token ?? "",
				expiresAt: Date.now() + params.tokens.expires_in * 1e3,
				createdAt: Date.now(),
				sessionKey: params.sessionKey,
				agentId: params.agentId,
				services: params.services,
				filePath: credPath
			};
			await fs$1.writeFile(credPath, JSON.stringify(credentials, null, 2), { mode: 384 });
			await syncToGogKeyring(credentials);
			return credPath;
		},
		async loadCredentials(agentId, sessionKey, email) {
			const filename = buildCredentialFilename(sessionKey, email);
			const newDir = getCredentialsDir(agentId);
			const newPath = path$1.join(newDir, filename);
			try {
				const data = await fs$1.readFile(newPath, "utf-8");
				const creds = JSON.parse(data);
				creds.filePath = newPath;
				return creds;
			} catch {}
			const oldDir = getLegacyCredentialsDir(agentId);
			const oldPath = path$1.join(oldDir, filename);
			try {
				const data = await fs$1.readFile(oldPath, "utf-8");
				const creds = JSON.parse(data);
				log$2.info(`Migrating credentials from gog-credentials/ to auth-credentials/google/ for ${email}`);
				await fs$1.mkdir(newDir, {
					recursive: true,
					mode: 448
				});
				await fs$1.writeFile(newPath, data, { mode: 384 });
				try {
					await fs$1.access(newPath);
					await fs$1.unlink(oldPath);
					log$2.info(`Migration complete: deleted legacy credential at ${oldPath}`);
				} catch {
					log$2.warn(`Migration: new file written but could not delete old file at ${oldPath}`);
				}
				creds.filePath = newPath;
				return creds;
			} catch {}
			return null;
		}
	};
}

//#endregion
//#region src/hooks/gog-oauth-notifications.ts
const log$1 = createSubsystemLogger("gog-oauth/notifications");

//#endregion
//#region src/hooks/gog-oauth-server.ts
/**
* OAuth callback server for non-blocking Google authentication
* Handles localhost OAuth redirects and delegates token exchange
* and credential storage to the AuthProvider.
*/
const log = createSubsystemLogger("gog-oauth");
/**
* Default OAuth server configuration
*/
const DEFAULT_CONFIG = {
	enabled: true,
	port: DEFAULT_OAUTH_CALLBACK_PORT,
	bind: "127.0.0.1",
	callbackPath: "/oauth-callback",
	timeoutMinutes: 5
};
/**
* In-memory storage for pending OAuth flows
* Key: state token, Value: flow data
*/
const pendingFlows = /* @__PURE__ */ new Map();
let actualPort = null;
let configuredExternalRedirectUri;
/**
* Get the redirect URI for OAuth flows.
* Desktop ("installed") clients only support localhost redirects -- Google rejects
* external URIs with redirect_uri_mismatch. When a Desktop client is detected,
* we always return the localhost URI regardless of env/config settings.
* For "web" or "unknown" clients: env var > config > localhost fallback.
*/
function getRedirectUri() {
	const localhostUri = `http://localhost:${actualPort ?? DEFAULT_CONFIG.port}${DEFAULT_CONFIG.callbackPath}`;
	if (getGoogleClientType() === "installed") {
		const externalUri = process.env.MINION_GOG_OAUTH_REDIRECT_URI || configuredExternalRedirectUri;
		if (externalUri) log.warn(`Desktop client detected — ignoring external redirect URI "${externalUri}" (installed clients only support localhost redirects). Using: ${localhostUri}`);
		return localhostUri;
	}
	const envUri = process.env.MINION_GOG_OAUTH_REDIRECT_URI;
	if (envUri) return envUri;
	if (configuredExternalRedirectUri) return configuredExternalRedirectUri;
	return localhostUri;
}
/**
* Generate cryptographic state token for CSRF protection
*/
function generateState() {
	return crypto.randomBytes(32).toString("hex");
}
/**
* Add a pending OAuth flow.
* Cancels any existing flow for the same session to enforce one-at-a-time.
*/
function addPendingFlow(flow) {
	for (const [state, existing] of pendingFlows.entries()) if (existing.sessionKey === flow.sessionKey) {
		log.info(`Cancelling previous auth flow for session ${flow.sessionKey} (state=${state})`);
		pendingFlows.delete(state);
	}
	pendingFlows.set(flow.state, flow);
}
/**
* Get the current server port (if running)
*/
function getServerPort() {
	return actualPort;
}

//#endregion
//#region src/agents/tools/auth/gog-auth-start-tool.ts
/**
* gog_auth_start tool - Start non-blocking Google OAuth flow
*
* Delegates URL building and scope resolution to GoogleAuthProvider.
* Tool name kept as "gog_auth_start" for backward compatibility.
*/
function createGogAuthStartTool(opts) {
	const provider = createGoogleAuthProvider();
	const serviceLiterals = provider.getSupportedServices().map((s) => Type.Literal(s));
	return {
		label: "Google Auth Start",
		name: "gog_auth_start",
		description: "Start non-blocking Google OAuth flow for Gmail, Calendar, Drive, and other Google services. Returns an authorization URL for the user to visit. The agent remains responsive while waiting for authorization. IMPORTANT: Always use the default services (gmail, calendar, drive) unless the user explicitly requests only specific services. Do NOT narrow to a single service — users expect all Google services to work once authenticated.",
		parameters: Type.Object({
			email: Type.String({
				description: "Google account email address",
				minLength: 1
			}),
			services: Type.Optional(Type.Array(Type.Union(serviceLiterals), { description: "Google services to authorize (default: gmail, calendar, drive)" }))
		}),
		execute: async (_toolCallId, args) => {
			const params = args;
			const email = readStringParam(params, "email", { required: true });
			let services = params.services || [
				"gmail",
				"calendar",
				"drive"
			];
			if (opts?.agentId && opts?.sessionKey) {
				const existing = await provider.loadCredentials(opts.agentId, opts.sessionKey, email);
				if (existing?.services?.length) services = [...new Set([...existing.services, ...services])];
			}
			if (!email.includes("@")) return jsonResult({ error: "Invalid email address format" });
			if (!getServerPort()) return jsonResult({ error: "OAuth server is not running. Please contact the administrator." });
			if (!opts?.agentId || !opts?.agentDir || !opts?.sessionKey) return jsonResult({ error: "Missing agent context (agentId, agentDir, or sessionKey)" });
			const state = generateState();
			const now = Date.now();
			const expiresAt = now + 300 * 1e3;
			const redirectUri = getRedirectUri();
			let authUrl;
			try {
				authUrl = provider.buildAuthUrl({
					email,
					services,
					redirectUri,
					state
				});
			} catch {
				return jsonResult({ error: "Google OAuth client ID not configured. Options (checked in order):\n  1. Set hooks.gogOAuth.googleClientCredentialsFile in minion.json (path to downloaded Google client_secret JSON)\n  2. Set GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET environment variables\n  3. Place gog CLI credentials in ~/.config/gogcli/credentials.json" });
			}
			addPendingFlow({
				state,
				sessionKey: opts.sessionKey,
				agentId: opts.agentId,
				email,
				services,
				requestedAt: now,
				expiresAt,
				authUrl,
				providerId: provider.id
			});
			await updateSessionStore(resolveDefaultSessionStorePath(opts.agentId), (store) => {
				const session = store[opts.sessionKey];
				if (session) {
					session.gogAuthPending = {
						state,
						requestedAt: now,
						expiresAt,
						email,
						services
					};
					session.updatedAt = Date.now();
				}
			});
			return jsonResult({
				authUrl,
				state,
				expiresIn: 300,
				instructions: `IMPORTANT: You MUST paste the full authUrl as plain text in your response — do NOT wrap it in markdown link format like [text](url) or [url](url). The messaging platform auto-links plain URLs; markdown formatting breaks the URL and causes auth errors. Just paste the raw URL on its own line. The user will visit this link to authorize access to their Google account (${services.join(", ")}). You'll be notified when authentication completes (or if it times out after 5 minutes).`
			});
		}
	};
}

//#endregion
export { createGogAuthStartTool };