
!function(){try{var e="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof globalThis?globalThis:"undefined"!=typeof self?self:{},n=(new e.Error).stack;n&&(e._sentryDebugIds=e._sentryDebugIds||{},e._sentryDebugIds[n]="e7947896-b67a-5456-a1e6-f56c5a04e416")}catch(e){}}();
import { access, readFile } from "node:fs/promises";
import { join } from "node:path";
import { pathToFileURL } from "node:url";
import { buildKanbanCommandParts } from "../core/kanban-command.js";
import { quoteShellArg } from "../core/shell.js";
import { lockedFileSystem } from "../fs/locked-file-system.js";
import { resolveHomeAgentAppendSystemPrompt } from "../prompts/append-system-prompt.js";
import { getRuntimeHomePath } from "../state/workspace-state.js";
import { createHookRuntimeEnv } from "./hook-runtime-context.js";
import { getOpenCodeAuthPathCandidates, getOpenCodeConfigPathCandidates, getOpenCodeModelStatePathCandidates, } from "./opencode-paths.js";
import { stripAnsi } from "./output-utils.js";
import { prepareTaskPromptWithImages } from "./task-image-prompt.js";
function escapeForTemplateLiteral(value) {
    return value.replaceAll("\\", "\\\\").replaceAll("`", "\\`");
}
function powerShellQuote(value) {
    return `"${value.replaceAll("`", "``").replaceAll('"', '`"')}"`;
}
function resolveHookContext(input) {
    const workspaceId = input.workspaceId?.trim();
    if (!workspaceId) {
        return null;
    }
    return {
        taskId: input.taskId,
        workspaceId,
    };
}
function buildHookCommand(event, metadata) {
    const parts = buildHooksCommandParts(["ingest", "--event", event]);
    if (metadata?.source) {
        parts.push("--source", metadata.source);
    }
    if (metadata?.activityText) {
        parts.push("--activity-text", metadata.activityText);
    }
    if (metadata?.hookEventName) {
        parts.push("--hook-event-name", metadata.hookEventName);
    }
    if (metadata?.notificationType) {
        parts.push("--notification-type", metadata.notificationType);
    }
    return parts.map(quoteShellArg).join(" ");
}
function buildHooksCommandParts(args) {
    return buildKanbanCommandParts(["hooks", ...args]);
}
function buildHooksCommand(args) {
    return buildHooksCommandParts(args).map(quoteShellArg).join(" ");
}
function hasCliOption(args, optionName) {
    for (let i = 0; i < args.length; i += 1) {
        const arg = args[i];
        if (arg === optionName || arg.startsWith(`${optionName}=`)) {
            return true;
        }
    }
    return false;
}
function hasCodexConfigOverride(args, key) {
    for (let i = 0; i < args.length; i += 1) {
        const arg = args[i];
        if (arg === "-c" || arg === "--config") {
            const next = args[i + 1];
            if (typeof next === "string" && next.startsWith(`${key}=`)) {
                return true;
            }
            i += 1;
            continue;
        }
        if (arg.startsWith(`-c${key}=`) || arg.startsWith(`--config=${key}=`)) {
            return true;
        }
    }
    return false;
}
function getClineHookScriptPath(hooksDir, hookName) {
    if (process.platform === "win32") {
        return join(hooksDir, `${hookName}.ps1`);
    }
    return join(hooksDir, hookName);
}
function buildClineHookScriptContent(event) {
    const commandParts = buildHooksCommandParts(["notify", "--event", event, "--source", "cline"]);
    if (process.platform === "win32") {
        const command = commandParts.map(powerShellQuote).join(" ");
        return `$inputText = [Console]::In.ReadToEnd()
try {
  $inputText | & ${command} | Out-Null
} catch {
}
Write-Output '{"cancel":false}'
exit 0
`;
    }
    const command = commandParts.map(quoteShellArg).join(" ");
    return `#!/usr/bin/env bash
INPUT="$(cat || true)"
printf '%s' "$INPUT" | ${command} >/dev/null 2>&1 || true
echo '{"cancel":false}'
`;
}
function buildClineNotificationHookScriptContent() {
    const commandParts = buildHooksCommandParts(["notify", "--event", "to_review", "--source", "cline"]);
    if (process.platform === "win32") {
        const command = commandParts.map(powerShellQuote).join(" ");
        return `$inputText = [Console]::In.ReadToEnd()
if (
  $inputText -match '"event"\\s*:\\s*"user_attention"' -and
  $inputText -notmatch '"source"\\s*:\\s*"completion_result"'
) {
  try {
    $inputText | & ${command} | Out-Null
  } catch {
  }
}
Write-Output '{"cancel":false}'
exit 0
`;
    }
    const command = commandParts.map(quoteShellArg).join(" ");
    return `#!/usr/bin/env bash
INPUT="$(cat || true)"
if printf '%s' "$INPUT" | grep -Eq '"event"[[:space:]]*:[[:space:]]*"user_attention"' &&
  ! printf '%s' "$INPUT" | grep -Eq '"source"[[:space:]]*:[[:space:]]*"completion_result"'; then
  printf '%s' "$INPUT" | ${command} >/dev/null 2>&1 || true
fi
echo '{"cancel":false}'
`;
}
function buildClinePreToolUseHookScriptContent() {
    const activityCommand = buildHooksCommandParts(["notify", "--event", "activity", "--source", "cline"]);
    const reviewCommand = buildHooksCommandParts(["notify", "--event", "to_review", "--source", "cline"]);
    const inProgressCommand = buildHooksCommandParts(["notify", "--event", "to_in_progress", "--source", "cline"]);
    if (process.platform === "win32") {
        const activity = activityCommand.map(powerShellQuote).join(" ");
        const review = reviewCommand.map(powerShellQuote).join(" ");
        const inProgress = inProgressCommand.map(powerShellQuote).join(" ");
        return `$inputText = [Console]::In.ReadToEnd()
$isUserQuestionTool = $inputText -match '"(toolName|tool)"\\s*:\\s*"(ask_followup_question|plan_mode_respond)"'
try {
  $inputText | & ${activity} | Out-Null
} catch {
}
if ($isUserQuestionTool) {
  try {
    $inputText | & ${review} | Out-Null
  } catch {
  }
} else {
  try {
    $inputText | & ${inProgress} | Out-Null
  } catch {
  }
}
Write-Output '{"cancel":false}'
exit 0
`;
    }
    const activity = activityCommand.map(quoteShellArg).join(" ");
    const review = reviewCommand.map(quoteShellArg).join(" ");
    const inProgress = inProgressCommand.map(quoteShellArg).join(" ");
    return `#!/usr/bin/env bash
INPUT="$(cat || true)"
printf '%s' "$INPUT" | ${activity} >/dev/null 2>&1 || true
if printf '%s' "$INPUT" | grep -Eq '"(toolName|tool)"[[:space:]]*:[[:space:]]*"(ask_followup_question|plan_mode_respond)"'; then
  printf '%s' "$INPUT" | ${review} >/dev/null 2>&1 || true
else
  printf '%s' "$INPUT" | ${inProgress} >/dev/null 2>&1 || true
fi
echo '{"cancel":false}'
`;
}
function buildClinePostToolUseHookScriptContent() {
    const activityCommand = buildHooksCommandParts(["notify", "--event", "activity", "--source", "cline"]);
    const inProgressCommand = buildHooksCommandParts(["notify", "--event", "to_in_progress", "--source", "cline"]);
    if (process.platform === "win32") {
        const activity = activityCommand.map(powerShellQuote).join(" ");
        const inProgress = inProgressCommand.map(powerShellQuote).join(" ");
        return `$inputText = [Console]::In.ReadToEnd()
$isUserQuestionTool = $inputText -match '"(toolName|tool)"\\s*:\\s*"(ask_followup_question|plan_mode_respond)"'
try {
  $inputText | & ${activity} | Out-Null
} catch {
}
if ($isUserQuestionTool) {
  try {
    $inputText | & ${inProgress} | Out-Null
  } catch {
  }
}
Write-Output '{"cancel":false}'
exit 0
`;
    }
    const activity = activityCommand.map(quoteShellArg).join(" ");
    const inProgress = inProgressCommand.map(quoteShellArg).join(" ");
    return `#!/usr/bin/env bash
INPUT="$(cat || true)"
printf '%s' "$INPUT" | ${activity} >/dev/null 2>&1 || true
if printf '%s' "$INPUT" | grep -Eq '"(toolName|tool)"[[:space:]]*:[[:space:]]*"(ask_followup_question|plan_mode_respond)"'; then
  printf '%s' "$INPUT" | ${inProgress} >/dev/null 2>&1 || true
fi
echo '{"cancel":false}'
`;
}
function buildOpenCodePluginContent(reviewCommand, toInProgressCommand, activityCommand) {
    const reviewCmd = escapeForTemplateLiteral(reviewCommand);
    const toInProgressCmd = escapeForTemplateLiteral(toInProgressCommand);
    const activityCmd = escapeForTemplateLiteral(activityCommand);
    return `export const KanbanPlugin = async ({ $, client }) => {
  if (globalThis.__kanbanOpencodePluginV3) return {};
  globalThis.__kanbanOpencodePluginV3 = true;

  if (!process?.env?.KANBAN_HOOK_TASK_ID) return {};

  let currentState = "idle";
  let rootSessionID = null;
  const childSessionCache = new Map();
  const messageRoleByID = new Map();
  const assistantTextByMessageID = new Map();
  const latestAssistantBySessionID = new Map();
  const toolInputByCallID = new Map();

  const asRecord = (value) => {
    if (!value || typeof value !== "object" || Array.isArray(value)) {
      return null;
    }
    return value;
  };

  const getMessageKey = (sessionID, messageID) => String(sessionID) + ":" + String(messageID);
  const getToolCallKey = (sessionID, callID) => String(sessionID) + ":" + String(callID);

  const encodePayload = (payload) => {
    if (!payload || typeof payload !== "object") {
      return "";
    }
    try {
      return Buffer.from(JSON.stringify(payload), "utf8").toString("base64");
    } catch {
      return "";
    }
  };

	const notify = async (kind, payload) => {
		try {
			const encoded = encodePayload(payload);
			if (kind === "review") {
				if (encoded) {
					await $\`${reviewCmd} --metadata-base64 \${encoded}\`;
				} else {
					await $\`${reviewCmd}\`;
				}
				return;
			}
			if (kind === "in_progress") {
				if (encoded) {
					await $\`${toInProgressCmd} --metadata-base64 \${encoded}\`;
				} else {
					await $\`${toInProgressCmd}\`;
				}
				return;
			}
			if (encoded) {
				await $\`${activityCmd} --metadata-base64 \${encoded}\`;
			} else {
				await $\`${activityCmd}\`;
			}
		} catch {
			// Best effort: hook errors should never break OpenCode event handling.
		}
	};

  const notifyReview = async (sessionID, payload = {}) => {
    const mergedPayload = {
      ...payload,
      last_assistant_message:
        typeof payload.last_assistant_message === "string"
          ? payload.last_assistant_message
          : (latestAssistantBySessionID.get(sessionID) ?? undefined),
    };
		await notify("review", mergedPayload);
  };

  const notifyInProgress = async (payload = {}) => {
		await notify("in_progress", payload);
  };

  const notifyActivity = async (payload = {}) => {
		await notify("activity", payload);
  };

  const isChildSession = async (sessionID) => {
    if (!sessionID) return true;
    if (!client?.session?.list) return true;
    if (childSessionCache.has(sessionID)) {
      return childSessionCache.get(sessionID);
    }
    try {
      const sessions = await client.session.list();
      const session = sessions.data?.find((candidate) => candidate.id === sessionID);
      const isChild = !!session?.parentID;
      childSessionCache.set(sessionID, isChild);
      return isChild;
    } catch {
      return true;
    }
  };

  const handleBusy = async (sessionID) => {
    if (!sessionID) {
      return;
    }
    if (!rootSessionID) {
      rootSessionID = sessionID;
    }
    if (sessionID !== rootSessionID) {
      return;
    }
    if (currentState === "idle") {
      currentState = "busy";
      await notifyInProgress({
        hook_event_name: "session.status",
      });
    }
  };

  const handleReview = async (sessionID, payload = {}, force = false) => {
    if (!sessionID) {
      return;
    }
    if (!rootSessionID) {
      rootSessionID = sessionID;
    }
    if (rootSessionID && sessionID !== rootSessionID) {
      return;
    }

    const shouldNotify = force || currentState === "busy";
    if (shouldNotify) {
      currentState = "idle";
      await notifyReview(sessionID, payload);
      rootSessionID = null;
    }
  };

  return {
    event: async ({ event }) => {
      if (event.type === "message.updated") {
        const info = asRecord(event.properties?.info);
        const sessionID = typeof info?.sessionID === "string" ? info.sessionID : null;
        if (await isChildSession(sessionID)) {
          return;
        }

        const messageID = typeof info?.id === "string" ? info.id : null;
        const role = typeof info?.role === "string" ? info.role : null;
        if (messageID && role) {
          messageRoleByID.set(getMessageKey(sessionID, messageID), role);
          if (role === "assistant" && !assistantTextByMessageID.has(getMessageKey(sessionID, messageID))) {
            assistantTextByMessageID.set(getMessageKey(sessionID, messageID), "");
          }
        }
        return;
      }

      if (event.type === "message.part.updated") {
        const part = asRecord(event.properties?.part);
        if (!part) {
          return;
        }

        const sessionID = typeof part.sessionID === "string" ? part.sessionID : null;
        if (await isChildSession(sessionID)) {
          return;
        }

        if (part.type !== "text") {
          return;
        }

        const messageID = typeof part.messageID === "string" ? part.messageID : null;
        if (!messageID) {
          return;
        }

        const messageKey = getMessageKey(sessionID, messageID);
        if (messageRoleByID.get(messageKey) !== "assistant") {
          return;
        }

        const delta = typeof event.properties?.delta === "string" ? event.properties.delta : "";
        const fullText = typeof part.text === "string" ? part.text : "";
        const previousText = assistantTextByMessageID.get(messageKey) ?? "";
        const nextText = delta ? previousText + delta : (fullText || previousText);
        const normalized = nextText.trim();
        if (!normalized) {
          return;
        }

        assistantTextByMessageID.set(messageKey, normalized);
        latestAssistantBySessionID.set(sessionID, normalized);
        return;
      }

      const sessionID = event.properties?.sessionID;
      if (await isChildSession(sessionID)) {
        return;
      }

      if (event.type === "session.status") {
        const status = event.properties?.status;
        if (status?.type === "busy") {
          await handleBusy(sessionID);
        } else if (status?.type === "idle") {
          await handleReview(sessionID, {
            hook_event_name: "session.status",
          });
        }
      }

      if (event.type === "session.busy") {
        await handleBusy(sessionID);
      }
      if (event.type === "session.idle") {
        await handleReview(sessionID, {
          hook_event_name: "session.idle",
        });
      }
      if (event.type === "session.error") {
        await handleReview(
          sessionID,
          {
            hook_event_name: "session.error",
          },
          true,
        );
      }
    },
    "tool.execute.before": async (input, output) => {
      const sessionID = typeof input?.sessionID === "string" ? input.sessionID : null;
      if (await isChildSession(sessionID)) {
        return;
      }

      await handleBusy(sessionID);

      const toolName = typeof input?.tool === "string" ? input.tool : undefined;
      const callID = typeof input?.callID === "string" ? input.callID : "";
      const toolInput = asRecord(output?.args);
      if (callID) {
        toolInputByCallID.set(getToolCallKey(sessionID, callID), toolInput);
      }

      await notifyActivity({
        hook_event_name: "BeforeTool",
        tool_name: toolName,
        tool_input: toolInput ?? undefined,
      });
    },
    "tool.execute.after": async (input) => {
      const sessionID = typeof input?.sessionID === "string" ? input.sessionID : null;
      if (await isChildSession(sessionID)) {
        return;
      }

      const toolName = typeof input?.tool === "string" ? input.tool : undefined;
      const callID = typeof input?.callID === "string" ? input.callID : "";
      const toolInput = callID ? toolInputByCallID.get(getToolCallKey(sessionID, callID)) : null;
      if (callID) {
        toolInputByCallID.delete(getToolCallKey(sessionID, callID));
      }

      await notifyActivity({
        hook_event_name: "AfterTool",
        tool_name: toolName,
        tool_input: toolInput ?? undefined,
      });
    },
    "permission.ask": async (_permission, output) => {
      if (output?.status === "ask") {
        const sessionID = typeof _permission?.sessionID === "string" ? _permission.sessionID : null;
        if (await isChildSession(sessionID)) {
          return;
        }
        await handleReview(
          sessionID,
          {
            hook_event_name: "PermissionRequest",
            notification_type: "permission.asked",
          },
          true,
        );
      }
    },
  };
};
`;
}
function getHookAgentDirectory(agentId) {
    return join(getRuntimeHomePath(), "hooks", agentId);
}
async function ensureTextFile(filePath, content, executable = false) {
    await lockedFileSystem.writeTextFileAtomic(filePath, content, {
        executable,
    });
}
function withPrompt(args, prompt, mode, flag) {
    const trimmed = prompt.trim();
    if (!trimmed) {
        return {
            args,
            env: {},
        };
    }
    if (mode === "flag" && flag) {
        args.push(flag, trimmed);
    }
    else {
        args.push(trimmed);
    }
    return {
        args,
        env: {},
    };
}
const claudeAdapter = {
    async prepare(input) {
        const args = [...input.args];
        const env = {};
        const appendedSystemPrompt = resolveHomeAgentAppendSystemPrompt(input.taskId);
        if (input.autonomousModeEnabled &&
            !input.startInPlanMode &&
            !hasCliOption(args, "--dangerously-skip-permissions")) {
            args.push("--dangerously-skip-permissions");
        }
        if (input.resumeFromTrash && !hasCliOption(args, "--continue")) {
            args.push("--continue");
        }
        if (input.startInPlanMode) {
            const withoutImmediateBypass = args.filter((arg) => arg !== "--dangerously-skip-permissions");
            args.length = 0;
            args.push(...withoutImmediateBypass);
            if (!hasCliOption(args, "--allow-dangerously-skip-permissions")) {
                args.push("--allow-dangerously-skip-permissions");
            }
            args.push("--permission-mode", "plan");
        }
        const hooks = resolveHookContext(input);
        if (hooks) {
            const settingsPath = join(getHookAgentDirectory("claude"), "settings.json");
            const hooksSettings = {
                hooks: {
                    Stop: [{ hooks: [{ type: "command", command: buildHookCommand("to_review", { source: "claude" }) }] }],
                    SubagentStop: [
                        { hooks: [{ type: "command", command: buildHookCommand("activity", { source: "claude" }) }] },
                    ],
                    PreToolUse: [
                        {
                            matcher: "*",
                            hooks: [{ type: "command", command: buildHookCommand("activity", { source: "claude" }) }],
                        },
                    ],
                    PermissionRequest: [
                        {
                            matcher: "*",
                            hooks: [{ type: "command", command: buildHookCommand("to_review", { source: "claude" }) }],
                        },
                    ],
                    PostToolUse: [
                        {
                            matcher: "*",
                            hooks: [{ type: "command", command: buildHookCommand("to_in_progress", { source: "claude" }) }],
                        },
                    ],
                    PostToolUseFailure: [
                        {
                            matcher: "*",
                            hooks: [{ type: "command", command: buildHookCommand("to_in_progress", { source: "claude" }) }],
                        },
                    ],
                    Notification: [
                        {
                            matcher: "permission_prompt",
                            hooks: [{ type: "command", command: buildHookCommand("to_review", { source: "claude" }) }],
                        },
                        {
                            matcher: "*",
                            hooks: [{ type: "command", command: buildHookCommand("activity", { source: "claude" }) }],
                        },
                    ],
                    UserPromptSubmit: [
                        {
                            hooks: [{ type: "command", command: buildHookCommand("to_in_progress", { source: "claude" }) }],
                        },
                    ],
                },
            };
            await ensureTextFile(settingsPath, JSON.stringify(hooksSettings, null, 2));
            args.push("--settings", settingsPath);
            Object.assign(env, createHookRuntimeEnv({
                taskId: hooks.taskId,
                workspaceId: hooks.workspaceId,
            }));
        }
        if (appendedSystemPrompt &&
            !hasCliOption(args, "--append-system-prompt") &&
            !hasCliOption(args, "--system-prompt")) {
            args.push("--append-system-prompt", appendedSystemPrompt);
        }
        const withPromptLaunch = withPrompt(args, input.prompt, "append");
        return {
            ...withPromptLaunch,
            env: {
                ...withPromptLaunch.env,
                ...env,
            },
        };
    },
};
function codexPromptDetector(data, summary) {
    if (summary.state !== "awaiting_review") {
        return null;
    }
    if (summary.reviewReason !== "attention" && summary.reviewReason !== "hook") {
        return null;
    }
    const stripped = stripAnsi(data);
    if (/(?:^|\n)\s*›/.test(stripped)) {
        return { type: "agent.prompt-ready" };
    }
    return null;
}
function shouldInspectCodexOutputForTransition(summary) {
    return (summary.state === "awaiting_review" &&
        (summary.reviewReason === "attention" ||
            summary.reviewReason === "hook" ||
            summary.reviewReason === "error"));
}
const codexAdapter = {
    async prepare(input) {
        const codexArgs = [...input.args];
        const env = {};
        let binary = input.binary;
        const appendedSystemPrompt = resolveHomeAgentAppendSystemPrompt(input.taskId);
        if (input.autonomousModeEnabled && !hasCliOption(codexArgs, "--dangerously-bypass-approvals-and-sandbox")) {
            codexArgs.push("--dangerously-bypass-approvals-and-sandbox");
        }
        if (input.resumeFromTrash) {
            if (!codexArgs.includes("resume")) {
                codexArgs.push("resume");
            }
            if (!hasCliOption(codexArgs, "--last")) {
                codexArgs.push("--last");
            }
        }
        if (appendedSystemPrompt && !hasCodexConfigOverride(codexArgs, "developer_instructions")) {
            codexArgs.push("-c", `developer_instructions=${JSON.stringify(appendedSystemPrompt)}`);
        }
        const hooks = resolveHookContext(input);
        if (hooks) {
            Object.assign(env, createHookRuntimeEnv({
                taskId: hooks.taskId,
                workspaceId: hooks.workspaceId,
            }));
        }
        const trimmed = input.prompt.trim();
        if (trimmed) {
            const initialPrompt = input.startInPlanMode ? `/plan\n${trimmed}` : trimmed;
            codexArgs.push(initialPrompt);
        }
        if (hooks) {
            const wrapperParts = buildHooksCommandParts([
                "codex-wrapper",
                "--real-binary",
                input.binary ?? "codex",
                "--",
                ...codexArgs,
            ]);
            binary = wrapperParts[0];
            const args = wrapperParts.slice(1);
            return {
                binary,
                args,
                env,
                detectOutputTransition: codexPromptDetector,
                shouldInspectOutputForTransition: shouldInspectCodexOutputForTransition,
            };
        }
        return {
            binary,
            args: codexArgs,
            env,
            detectOutputTransition: codexPromptDetector,
            shouldInspectOutputForTransition: shouldInspectCodexOutputForTransition,
        };
    },
};
const geminiAdapter = {
    async prepare(input) {
        const args = [...input.args];
        const env = {};
        if (input.autonomousModeEnabled && !hasCliOption(args, "--yolo")) {
            args.push("--yolo");
        }
        if (input.resumeFromTrash && !hasCliOption(args, "--resume")) {
            args.push("--resume", "latest");
        }
        if (input.startInPlanMode) {
            args.push("--approval-mode=plan");
        }
        const hooks = resolveHookContext(input);
        if (hooks) {
            const configPath = join(getHookAgentDirectory("gemini"), "settings.json");
            const geminiHookCommand = buildHooksCommand(["gemini-hook"]);
            const config = {
                hooks: {
                    BeforeTool: [
                        {
                            hooks: [{ type: "command", command: geminiHookCommand }],
                        },
                    ],
                    AfterTool: [
                        {
                            hooks: [{ type: "command", command: geminiHookCommand }],
                        },
                    ],
                    AfterAgent: [
                        {
                            hooks: [{ type: "command", command: geminiHookCommand }],
                        },
                    ],
                    BeforeAgent: [
                        {
                            hooks: [{ type: "command", command: geminiHookCommand }],
                        },
                    ],
                    Notification: [
                        {
                            hooks: [{ type: "command", command: geminiHookCommand }],
                        },
                    ],
                },
            };
            await ensureTextFile(configPath, JSON.stringify(config, null, 2));
            Object.assign(env, createHookRuntimeEnv({
                taskId: hooks.taskId,
                workspaceId: hooks.workspaceId,
            }));
            env.GEMINI_CLI_SYSTEM_SETTINGS_PATH = configPath;
        }
        const trimmed = input.prompt.trim();
        if (trimmed) {
            args.push("-i", trimmed);
            return {
                args,
                env,
            };
        }
        return {
            args,
            env,
        };
    },
};
async function resolveOpenCodeBaseConfigPath(explicitPath) {
    const candidates = getOpenCodeConfigPathCandidates({ explicitPath });
    for (const candidate of candidates) {
        try {
            await access(candidate);
            return candidate;
        }
        catch {
            // Keep searching.
        }
    }
    return null;
}
function hasOpenCodeModelArg(args) {
    for (const arg of args) {
        if (arg === "--model" || arg === "-m") {
            return true;
        }
        if (arg.startsWith("--model=") || arg.startsWith("-m=")) {
            return true;
        }
    }
    return false;
}
function hasOpenCodeAgentArg(args) {
    for (const arg of args) {
        if (arg === "--agent") {
            return true;
        }
        if (arg.startsWith("--agent=")) {
            return true;
        }
    }
    return false;
}
function normalizeOpenCodeModel(providerId, modelId) {
    if (modelId.startsWith(`${providerId}/`)) {
        return modelId;
    }
    return `${providerId}/${modelId}`;
}
function stripJsonComments(input) {
    let output = "";
    let inString = false;
    let escaped = false;
    let inLineComment = false;
    let inBlockComment = false;
    for (let i = 0; i < input.length; i += 1) {
        const current = input[i];
        const next = i + 1 < input.length ? input[i + 1] : "";
        if (inLineComment) {
            if (current === "\n") {
                inLineComment = false;
                output += current;
            }
            continue;
        }
        if (inBlockComment) {
            if (current === "*" && next === "/") {
                inBlockComment = false;
                i += 1;
            }
            continue;
        }
        if (!inString && current === "/" && next === "/") {
            inLineComment = true;
            i += 1;
            continue;
        }
        if (!inString && current === "/" && next === "*") {
            inBlockComment = true;
            i += 1;
            continue;
        }
        output += current;
        if (inString) {
            if (escaped) {
                escaped = false;
            }
            else if (current === "\\") {
                escaped = true;
            }
            else if (current === '"') {
                inString = false;
            }
            continue;
        }
        if (current === '"') {
            inString = true;
        }
    }
    return output;
}
function tryExtractOpenCodeModelFromConfig(rawConfig) {
    let parsed;
    try {
        parsed = JSON.parse(rawConfig);
    }
    catch {
        try {
            parsed = JSON.parse(stripJsonComments(rawConfig));
        }
        catch {
            return null;
        }
    }
    if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) {
        return null;
    }
    const root = parsed;
    const directModel = root.model;
    if (typeof directModel === "string" && directModel.trim()) {
        return directModel.trim();
    }
    const mode = root.mode;
    if (mode && typeof mode === "object" && !Array.isArray(mode)) {
        const build = mode.build;
        if (build && typeof build === "object" && !Array.isArray(build)) {
            const model = build.model;
            if (typeof model === "string" && model.trim()) {
                return model.trim();
            }
        }
    }
    const agent = root.agent;
    if (agent && typeof agent === "object" && !Array.isArray(agent)) {
        const build = agent.build;
        if (build && typeof build === "object" && !Array.isArray(build)) {
            const model = build.model;
            if (typeof model === "string" && model.trim()) {
                return model.trim();
            }
        }
    }
    return null;
}
async function resolveOpenCodePreferredModelArg(configPath) {
    if (configPath) {
        try {
            const rawConfig = await readFile(configPath, "utf8");
            const modelFromConfig = tryExtractOpenCodeModelFromConfig(rawConfig);
            if (modelFromConfig) {
                return modelFromConfig;
            }
        }
        catch {
            // Fall through to state-based fallback.
        }
    }
    const modelStateCandidates = getOpenCodeModelStatePathCandidates();
    let recentModels = [];
    for (const modelStatePath of modelStateCandidates) {
        try {
            const raw = await readFile(modelStatePath, "utf8");
            const parsed = JSON.parse(raw);
            if (Array.isArray(parsed.recent)) {
                recentModels = parsed.recent;
                break;
            }
        }
        catch {
            // Keep searching through candidate state paths.
        }
    }
    if (recentModels.length === 0) {
        return null;
    }
    const configuredProviders = new Set();
    for (const authPath of getOpenCodeAuthPathCandidates()) {
        try {
            const raw = await readFile(authPath, "utf8");
            const parsed = JSON.parse(raw);
            for (const [provider, value] of Object.entries(parsed)) {
                if (!value || typeof value !== "object" || Array.isArray(value)) {
                    continue;
                }
                const key = value.key;
                if (typeof key === "string" && key.trim()) {
                    configuredProviders.add(provider);
                }
            }
            break;
        }
        catch {
            // Keep searching through candidate auth paths.
        }
    }
    const candidates = [];
    for (const entry of recentModels) {
        const providerId = typeof entry.providerID === "string" ? entry.providerID.trim() : "";
        const modelId = typeof entry.modelID === "string" ? entry.modelID.trim() : "";
        if (!providerId || !modelId) {
            continue;
        }
        candidates.push({ providerId, model: normalizeOpenCodeModel(providerId, modelId) });
    }
    if (candidates.length === 0) {
        return null;
    }
    const preferredProviderOrder = ["openrouter", "anthropic", "openai", "opencode", "google", "amazon-bedrock"];
    for (const providerId of preferredProviderOrder) {
        const match = candidates.find((candidate) => candidate.providerId === providerId);
        if (!match) {
            continue;
        }
        if (configuredProviders.size === 0 || configuredProviders.has(providerId)) {
            return match.model;
        }
    }
    const configuredMatch = candidates.find((candidate) => configuredProviders.has(candidate.providerId));
    if (configuredMatch) {
        return configuredMatch.model;
    }
    return candidates[0].model;
}
const opencodeAdapter = {
    async prepare(input) {
        const args = [...input.args];
        const env = {};
        const baseConfigPath = await resolveOpenCodeBaseConfigPath(input.env?.OPENCODE_CONFIG);
        if (input.resumeFromTrash && !hasCliOption(args, "--continue")) {
            args.push("--continue");
        }
        if (input.startInPlanMode) {
            env.OPENCODE_EXPERIMENTAL_PLAN_MODE = "true";
            if (!hasOpenCodeAgentArg(args)) {
                args.push("--agent", "plan");
            }
        }
        const hooks = resolveHookContext(input);
        if (hooks) {
            const pluginPath = join(getHookAgentDirectory("opencode"), "kanban.js");
            const configPath = join(getHookAgentDirectory("opencode"), "opencode.json");
            const pluginContent = buildOpenCodePluginContent(buildHookCommand("to_review", { source: "opencode" }), buildHookCommand("to_in_progress", { source: "opencode" }), buildHookCommand("activity", { source: "opencode" }));
            await ensureTextFile(pluginPath, pluginContent);
            const pluginFileUrl = pathToFileURL(pluginPath).href;
            const config = {
                plugin: [pluginFileUrl],
            };
            await ensureTextFile(configPath, JSON.stringify(config));
            Object.assign(env, createHookRuntimeEnv({
                taskId: hooks.taskId,
                workspaceId: hooks.workspaceId,
            }));
            env.OPENCODE_CONFIG = configPath;
        }
        // Workaround: with --prompt, OpenCode can pick an unexpected provider/model.
        // Explicitly pass the user's preferred model so prompt runs stay on their usual provider.
        if (!hasOpenCodeModelArg(args)) {
            const preferredModel = await resolveOpenCodePreferredModelArg(baseConfigPath);
            if (preferredModel) {
                args.push("--model", preferredModel);
            }
        }
        const trimmed = input.prompt.trim();
        if (trimmed) {
            args.push("--prompt", trimmed);
            return {
                args,
                env,
            };
        }
        return {
            args,
            env,
        };
    },
};
const droidAdapter = {
    async prepare(input) {
        const args = [...input.args];
        const env = {};
        if (input.resumeFromTrash && !hasCliOption(args, "--resume") && !hasCliOption(args, "-r")) {
            args.push("--resume");
        }
        const hooks = resolveHookContext(input);
        const shouldWriteSettings = Boolean(hooks) || input.startInPlanMode || input.autonomousModeEnabled !== undefined;
        if (shouldWriteSettings) {
            const settingsPath = join(getHookAgentDirectory("droid"), "settings.json");
            const settings = {
                autonomyMode: input.startInPlanMode ? "spec" : input.autonomousModeEnabled ? "auto-high" : "normal",
            };
            if (hooks) {
                const droidActiveToolMatcher = "Read|Grep|Glob|FetchUrl|WebSearch|Execute|Task|Edit|Create";
                const reviewNotifyCommand = buildHooksCommand(["notify", "--event", "to_review", "--source", "droid"]);
                const inProgressNotifyCommand = buildHooksCommand([
                    "notify",
                    "--event",
                    "to_in_progress",
                    "--source",
                    "droid",
                ]);
                const activityNotifyCommand = buildHooksCommand(["notify", "--event", "activity", "--source", "droid"]);
                settings.hooks = {
                    Stop: [{ hooks: [{ type: "command", command: reviewNotifyCommand }] }],
                    Notification: [
                        { hooks: [{ type: "command", command: activityNotifyCommand }] },
                        { hooks: [{ type: "command", command: reviewNotifyCommand }] },
                    ],
                    PreToolUse: [
                        { matcher: "*", hooks: [{ type: "command", command: activityNotifyCommand }] },
                        { matcher: droidActiveToolMatcher, hooks: [{ type: "command", command: inProgressNotifyCommand }] },
                        { matcher: "AskUser", hooks: [{ type: "command", command: reviewNotifyCommand }] },
                    ],
                    PostToolUse: [
                        { matcher: "*", hooks: [{ type: "command", command: activityNotifyCommand }] },
                        { matcher: "AskUser", hooks: [{ type: "command", command: inProgressNotifyCommand }] },
                    ],
                    PostToolUseFailure: [{ matcher: "*", hooks: [{ type: "command", command: activityNotifyCommand }] }],
                    UserPromptSubmit: [{ hooks: [{ type: "command", command: inProgressNotifyCommand }] }],
                };
                Object.assign(env, createHookRuntimeEnv({
                    taskId: hooks.taskId,
                    workspaceId: hooks.workspaceId,
                }));
            }
            await ensureTextFile(settingsPath, JSON.stringify(settings, null, 2));
            if (!hasCliOption(args, "--settings")) {
                args.push("--settings", settingsPath);
            }
        }
        const withPromptLaunch = withPrompt(args, input.prompt, "append");
        return {
            ...withPromptLaunch,
            env: {
                ...withPromptLaunch.env,
                ...env,
            },
        };
    },
};
const clineAdapter = {
    async prepare(input) {
        const args = [...input.args];
        const env = {};
        if (input.autonomousModeEnabled && !hasCliOption(args, "--auto-approve-all")) {
            args.push("--auto-approve-all");
        }
        if (input.resumeFromTrash && !hasCliOption(args, "--continue")) {
            args.push("--continue");
        }
        if (input.startInPlanMode) {
            args.push("--plan");
        }
        const hooks = resolveHookContext(input);
        if (hooks) {
            const hooksDir = getHookAgentDirectory("cline");
            const notificationHookPath = getClineHookScriptPath(hooksDir, "Notification");
            const taskCompleteHookPath = getClineHookScriptPath(hooksDir, "TaskComplete");
            const userPromptSubmitHookPath = getClineHookScriptPath(hooksDir, "UserPromptSubmit");
            const preToolUseHookPath = getClineHookScriptPath(hooksDir, "PreToolUse");
            const postToolUseHookPath = getClineHookScriptPath(hooksDir, "PostToolUse");
            const executable = process.platform !== "win32";
            await ensureTextFile(notificationHookPath, buildClineNotificationHookScriptContent(), executable);
            await ensureTextFile(taskCompleteHookPath, buildClineHookScriptContent("to_review"), executable);
            await ensureTextFile(userPromptSubmitHookPath, buildClineHookScriptContent("to_in_progress"), executable);
            await ensureTextFile(preToolUseHookPath, buildClinePreToolUseHookScriptContent(), executable);
            await ensureTextFile(postToolUseHookPath, buildClinePostToolUseHookScriptContent(), executable);
            if (!hasCliOption(args, "--hooks-dir")) {
                args.push("--hooks-dir", hooksDir);
            }
            Object.assign(env, createHookRuntimeEnv({
                taskId: hooks.taskId,
                workspaceId: hooks.workspaceId,
            }));
        }
        const withPromptLaunch = withPrompt(args, input.prompt, "append");
        return {
            ...withPromptLaunch,
            env: {
                ...withPromptLaunch.env,
                ...env,
            },
        };
    },
};
const ADAPTERS = {
    claude: claudeAdapter,
    codex: codexAdapter,
    gemini: geminiAdapter,
    opencode: opencodeAdapter,
    droid: droidAdapter,
    cline: clineAdapter,
};
export async function prepareAgentLaunch(input) {
    const preparedPrompt = await prepareTaskPromptWithImages({
        prompt: input.prompt,
        images: input.images,
    });
    return await ADAPTERS[input.agentId].prepare({
        ...input,
        prompt: preparedPrompt,
    });
}
//# sourceMappingURL=agent-session-adapters.js.map
//# debugId=e7947896-b67a-5456-a1e6-f56c5a04e416
