import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
import { z } from "zod";
import { ensureValidJson } from "../json-utils.js";
import { AgentFeatureSchema, AgentPermissionRequestPayloadSchema, AgentListItemPayloadSchema, AgentPermissionResponseSchema, AgentSnapshotPayloadSchema, } from "../messages.js";
import { buildStoredAgentPayload, toAgentListItemPayload, toAgentPayload, } from "./agent-projections.js";
import { curateAgentActivity } from "./activity-curator.js";
import { selectItemsByProjectedLimit } from "./timeline-projection.js";
import { ensureAgentLoaded } from "./agent-loading.js";
import { isStoredAgentProviderAvailable } from "../persistence-hooks.js";
import { appendTimelineItemIfAgentKnown, emitLiveTimelineItemIfAgentKnown, } from "./timeline-append.js";
import { getPaseoWorktreesRoot } from "../../utils/worktree.js";
import { archivePaseoWorktree, killTerminalsUnderPath, } from "../paseo-worktree-archive-service.js";
import { WaitForAgentTracker } from "./wait-for-agent-tracker.js";
import { scheduleAgentMetadataGeneration } from "./agent-metadata-generator.js";
import { expandUserPath, isSameOrDescendantPath, resolvePathFromBase } from "../path-utils.js";
import { PARENT_AGENT_ID_LABEL } from "../../shared/agent-labels.js";
import { ScheduleSummarySchema, StoredScheduleSchema } from "../schedule/types.js";
import { getAgentProviderDefinition } from "./provider-manifest.js";
import { resolveAndValidateCreateAgentMode } from "./create-agent-mode.js";
import { resolveSnapshotCwd } from "./provider-snapshot-manager.js";
import { AgentModelSchema, AgentProviderEnum, AgentStatusEnum, ProviderSummarySchema, parseDurationString, resolveRequiredProviderModel, sanitizePermissionRequest, serializeSnapshotWithMetadata, toScheduleSummary, waitForAgentWithTimeout, } from "./mcp-shared.js";
import { sendPromptToAgent, setupFinishNotification, startAgentRun } from "./agent-prompt.js";
import { toWorktreeRequestError } from "../worktree-errors.js";
import { join } from "node:path";
const CLAUDE_TO_CODEX_MODE = {
    plan: "read-only",
    default: "auto",
    acceptEdits: "auto",
    bypassPermissions: "full-access",
};
const CODEX_TO_CLAUDE_MODE = {
    "read-only": "plan",
    auto: "default",
    "full-access": "bypassPermissions",
};
function mapModeAcrossProviders(sourceMode, sourceProvider, targetProvider) {
    if (sourceProvider === targetProvider) {
        return sourceMode;
    }
    if (sourceProvider === "claude" && targetProvider === "codex") {
        const mapped = CLAUDE_TO_CODEX_MODE[sourceMode];
        if (mapped) {
            return mapped;
        }
        return "auto";
    }
    if (sourceProvider === "codex" && targetProvider === "claude") {
        const mapped = CODEX_TO_CLAUDE_MODE[sourceMode];
        if (mapped) {
            return mapped;
        }
        return "default";
    }
    return sourceMode;
}
function parseTimestamp(value) {
    if (!value) {
        return 0;
    }
    const parsed = Date.parse(value);
    return Number.isNaN(parsed) ? 0 : parsed;
}
function resolveAgentListActivityTime(agent) {
    return Math.max(parseTimestamp(agent.updatedAt), parseTimestamp(agent.lastUserMessageAt), parseTimestamp(agent.attentionTimestamp), parseTimestamp(agent.archivedAt), parseTimestamp(agent.createdAt));
}
function resolveRegisteredProviderIds(agentManager, providerRegistry) {
    return providerRegistry ? Object.keys(providerRegistry) : agentManager.getRegisteredProviderIds();
}
async function resolveProviderSummary(provider, logger) {
    const base = {
        id: provider.id,
        label: provider.label,
        description: provider.description,
        modes: provider.modes,
    };
    if (!provider.enabled) {
        return { ...base, enabled: false, status: "unavailable" };
    }
    try {
        const available = await provider.createClient(logger).isAvailable();
        return { ...base, enabled: true, status: available ? "available" : "unavailable" };
    }
    catch (availabilityError) {
        return {
            ...base,
            enabled: true,
            status: "unavailable",
            error: availabilityError instanceof Error ? availabilityError.message : String(availabilityError),
        };
    }
}
function compareAgentListItems(a, b) {
    const attentionDelta = Number(b.requiresAttention ?? false) - Number(a.requiresAttention ?? false);
    if (attentionDelta !== 0) {
        return attentionDelta;
    }
    const statusOrder = {
        running: 0,
        initializing: 1,
        idle: 2,
        error: 3,
        closed: 4,
    };
    const statusDelta = (statusOrder[a.status] ?? 999) - (statusOrder[b.status] ?? 999);
    if (statusDelta !== 0) {
        return statusDelta;
    }
    return resolveAgentListActivityTime(b) - resolveAgentListActivityTime(a);
}
function resolveScheduleProviderAndModel(params) {
    const providerInput = params.provider?.trim() || params.defaultProvider;
    const slashIndex = providerInput.indexOf("/");
    if (slashIndex === -1) {
        return { provider: providerInput };
    }
    const provider = providerInput.slice(0, slashIndex).trim();
    const model = providerInput.slice(slashIndex + 1).trim();
    if (!provider || !model) {
        throw new Error("provider must be <provider> or <provider>/<model>");
    }
    return {
        provider: provider,
        model,
    };
}
function resolveChildAgentCwd(params) {
    const lockedCwd = params.lockedCwd?.trim();
    if (lockedCwd) {
        return expandUserPath(lockedCwd);
    }
    const requestedCwd = params.requestedCwd?.trim();
    if (!requestedCwd || !params.allowCustomCwd) {
        return params.parentCwd;
    }
    return resolvePathFromBase(params.parentCwd, requestedCwd);
}
const TerminalSummarySchema = z.object({
    id: z.string(),
    name: z.string(),
    cwd: z.string(),
});
const WorktreeSummarySchema = z.object({
    path: z.string(),
    createdAt: z.string(),
    branchName: z.string().optional(),
    head: z.string().optional(),
});
function resolveTerminalKeyToken(key, literal) {
    if (literal) {
        return key;
    }
    switch (key) {
        case "Enter":
            return "\r";
        case "Tab":
            return "\t";
        case "Escape":
            return "\u001b";
        case "Space":
            return " ";
        case "BSpace":
            return "\u007f";
        case "C-c":
            return "\u0003";
        case "C-d":
            return "\u0004";
        case "C-z":
            return "\u001a";
        case "C-l":
            return "\u000c";
        case "C-a":
            return "\u0001";
        case "C-e":
            return "\u0005";
        default:
            return key;
    }
}
export async function createAgentMcpServer(options) {
    const { agentManager, agentStorage, terminalManager, scheduleService, providerRegistry, callerAgentId, resolveSpeakHandler, resolveCallerContext, logger, } = options;
    const childLogger = logger.child({ module: "agent", component: "mcp-server" });
    const waitTracker = new WaitForAgentTracker(logger);
    const callerContext = callerAgentId ? (resolveCallerContext?.(callerAgentId) ?? null) : null;
    const server = new McpServer({
        name: "agent-mcp",
        version: "2.0.0",
    });
    const resolveCallerAgent = () => {
        if (!callerAgentId) {
            return null;
        }
        const parentAgent = agentManager.getAgent(callerAgentId);
        if (!parentAgent) {
            throw new Error(`Parent agent ${callerAgentId} not found`);
        }
        return parentAgent;
    };
    const resolveScopedCwd = (requestedCwd, opts) => {
        const callerAgent = resolveCallerAgent();
        if (callerAgent) {
            return resolveChildAgentCwd({
                parentCwd: callerAgent.cwd,
                requestedCwd,
                lockedCwd: callerContext?.lockedCwd,
                allowCustomCwd: callerContext?.allowCustomCwd ?? true,
            });
        }
        const trimmedCwd = requestedCwd?.trim();
        if (!trimmedCwd) {
            if (opts?.required) {
                throw new Error("cwd is required");
            }
            throw new Error("cwd is required when no caller agent is available");
        }
        return expandUserPath(trimmedCwd);
    };
    const buildCallerAgentScheduleConfigExtras = (callerAgent) => {
        return {
            ...(callerAgent.config.thinkingOptionId
                ? { thinkingOptionId: callerAgent.config.thinkingOptionId }
                : {}),
            ...(callerAgent.config.approvalPolicy
                ? { approvalPolicy: callerAgent.config.approvalPolicy }
                : {}),
            ...(callerAgent.config.sandboxMode ? { sandboxMode: callerAgent.config.sandboxMode } : {}),
            ...(typeof callerAgent.config.networkAccess === "boolean"
                ? { networkAccess: callerAgent.config.networkAccess }
                : {}),
            ...(typeof callerAgent.config.webSearch === "boolean"
                ? { webSearch: callerAgent.config.webSearch }
                : {}),
            ...(callerAgent.config.title ? { title: callerAgent.config.title } : {}),
            ...(callerAgent.config.extra ? { extra: callerAgent.config.extra } : {}),
            ...(callerAgent.config.systemPrompt ? { systemPrompt: callerAgent.config.systemPrompt } : {}),
            ...(callerAgent.config.mcpServers ? { mcpServers: callerAgent.config.mcpServers } : {}),
        };
    };
    const buildCallerAgentScheduleConfig = (callerAgent, params) => {
        const hasProviderOverride = params?.provider !== undefined;
        const resolvedProviderModel = hasProviderOverride
            ? resolveScheduleProviderAndModel({
                provider: params?.provider,
                defaultProvider: callerAgent.provider,
            })
            : null;
        const resolvedProvider = resolvedProviderModel?.provider ?? callerAgent.provider;
        let resolvedModel;
        if (resolvedProviderModel?.model) {
            resolvedModel = resolvedProviderModel.model;
        }
        else if (!hasProviderOverride && callerAgent.config.model) {
            resolvedModel = callerAgent.config.model;
        }
        return {
            provider: resolvedProvider,
            cwd: params?.cwd?.trim() ? expandUserPath(params.cwd) : callerAgent.cwd,
            ...(callerAgent.currentModeId
                ? {
                    modeId: mapModeAcrossProviders(callerAgent.currentModeId, callerAgent.provider, resolvedProvider),
                }
                : {}),
            ...(resolvedModel ? { model: resolvedModel } : {}),
            ...buildCallerAgentScheduleConfigExtras(callerAgent),
        };
    };
    const resolveNewAgentScheduleTarget = (params) => {
        if (!params?.provider?.trim()) {
            throw new Error("provider is required when target is new-agent");
        }
        const callerAgent = resolveCallerAgent();
        if (callerAgent) {
            return {
                type: "new-agent",
                config: buildCallerAgentScheduleConfig(callerAgent, params),
            };
        }
        const resolvedProviderModel = resolveScheduleProviderAndModel({
            provider: params?.provider,
            defaultProvider: params.provider,
        });
        return {
            type: "new-agent",
            config: {
                provider: resolvedProviderModel.provider,
                cwd: params?.cwd?.trim() ? expandUserPath(params.cwd) : process.cwd(),
                ...(resolvedProviderModel.model ? { model: resolvedProviderModel.model } : {}),
            },
        };
    };
    const ProviderModelInputSchema = AgentProviderEnum.trim()
        .refine((value) => value.includes("/"), {
        message: "provider must be provider/model, for example codex/gpt-5.4",
    })
        .refine((value) => {
        try {
            resolveRequiredProviderModel(value);
            return true;
        }
        catch {
            return false;
        }
    }, { message: "provider must be provider/model, for example codex/gpt-5.4" });
    const agentToAgentInputSchema = {
        cwd: z
            .string()
            .optional()
            .describe("Optional working directory. Defaults to the caller agent working directory."),
        title: z
            .string()
            .trim()
            .min(1, "Title is required")
            .max(60, "Title must be 60 characters or fewer")
            .describe("Short descriptive title (<= 60 chars) summarizing the agent's focus."),
        provider: ProviderModelInputSchema.describe("Required provider/model pair, for example codex/gpt-5.4."),
        thinking: z.string().optional().describe("Thinking option ID"),
        features: z
            .record(z.unknown())
            .optional()
            .describe("Provider-specific feature values, for example { fast_mode: true } for Codex."),
        labels: z.record(z.string(), z.string()).optional().describe("Labels to set on the agent"),
        initialPrompt: z
            .string()
            .trim()
            .min(1, "initialPrompt is required")
            .describe("Required first task to run immediately after creation."),
        mode: z
            .string()
            .optional()
            .describe("Optional session mode for the new agent. Required when the new agent uses a different provider than the caller agent."),
        background: z
            .boolean()
            .optional()
            .default(false)
            .describe("Run agent in background. If false (default), waits for completion or permission request. If true, returns immediately."),
        notifyOnFinish: z
            .boolean()
            .optional()
            .default(false)
            .describe("Send a notification prompt to the caller agent when this agent finishes, errors, or needs permission. Requires a caller agent context."),
    };
    const topLevelInputSchema = {
        cwd: z
            .string()
            .describe("Required working directory for the agent (absolute, relative, or ~)."),
        title: z
            .string()
            .trim()
            .min(1, "Title is required")
            .max(60, "Title must be 60 characters or fewer")
            .describe("Short descriptive title (<= 60 chars) summarizing the agent's focus."),
        provider: ProviderModelInputSchema.describe("Required provider/model pair, for example codex/gpt-5.4."),
        thinking: z.string().optional().describe("Thinking option ID"),
        features: z
            .record(z.unknown())
            .optional()
            .describe("Provider-specific feature values, for example { fast_mode: true } for Codex."),
        labels: z.record(z.string(), z.string()).optional().describe("Labels to set on the agent"),
        initialPrompt: z
            .string()
            .trim()
            .min(1, "initialPrompt is required")
            .describe("Required first task to run immediately after creation."),
        mode: z
            .string()
            .optional()
            .describe("Optional session mode to configure before the first run."),
        worktreeName: z
            .string()
            .optional()
            .describe("Optional git worktree branch name (lowercase alphanumerics + hyphen)."),
        baseBranch: z
            .string()
            .optional()
            .describe("Required when worktreeName is set: the base branch to diff/merge against."),
        refName: z.string().min(1).optional().describe("Optional source ref for worktree creation."),
        action: z
            .enum(["branch-off", "checkout"])
            .optional()
            .describe("Optional worktree creation action."),
        githubPrNumber: z
            .number()
            .int()
            .positive()
            .optional()
            .describe("Optional GitHub pull request number to checkout."),
        background: z
            .boolean()
            .optional()
            .default(false)
            .describe("Run agent in background. If false (default), waits for completion or permission request. If true, returns immediately."),
        notifyOnFinish: z
            .boolean()
            .optional()
            .default(false)
            .describe("Send a notification prompt to the caller agent when this agent finishes, errors, or needs permission. Requires a caller agent context."),
    };
    const createAgentInputSchema = callerAgentId ? agentToAgentInputSchema : topLevelInputSchema;
    const agentToAgentCreateAgentArgsSchema = z.object(agentToAgentInputSchema).strict();
    const topLevelCreateAgentArgsSchema = z.object(topLevelInputSchema).strict();
    const listProviderFeaturesInputSchema = {
        provider: AgentProviderEnum,
        cwd: z.string().describe("Working directory used to resolve provider feature availability."),
        modeId: z.string().optional(),
        model: z.string().optional(),
        thinkingOptionId: z.string().optional(),
        featureValues: z.record(z.unknown()).optional(),
    };
    if (options.voiceOnly || options.enableVoiceTools || callerContext?.enableVoiceTools) {
        server.registerTool("speak", {
            title: "Speak",
            description: "Speak text to the user via daemon-managed voice output. Blocks until playback completes.",
            inputSchema: {
                text: z
                    .string()
                    .trim()
                    .min(1, "text is required")
                    .max(4000, "text must be 4000 characters or fewer"),
            },
            outputSchema: {
                ok: z.boolean(),
            },
        }, async (args, context) => {
            if (!callerAgentId) {
                throw new Error("speak is only available to agent-scoped MCP sessions");
            }
            const handler = resolveSpeakHandler?.(callerAgentId) ?? null;
            if (!handler) {
                throw new Error(`No speak handler registered for caller agent '${callerAgentId}'`);
            }
            await handler({
                text: args.text,
                callerAgentId,
                signal: context?.signal,
            });
            return {
                content: [],
                structuredContent: ensureValidJson({ ok: true }),
            };
        });
    }
    if (options.voiceOnly) {
        return server;
    }
    const getProviderModes = (provider) => {
        const fromRegistry = providerRegistry?.[provider];
        if (fromRegistry) {
            return fromRegistry.modes;
        }
        try {
            return getAgentProviderDefinition(provider).modes;
        }
        catch {
            return undefined;
        }
    };
    const getAvailableModeIds = (provider) => {
        return getProviderModes(provider)?.map((mode) => mode.id);
    };
    const getUnattendedModeId = (provider) => {
        return getProviderModes(provider)?.find((mode) => mode.isUnattended)?.id;
    };
    const isParentInUnattendedMode = (provider, modeId) => {
        if (modeId === null)
            return false;
        const modes = getProviderModes(provider);
        if (!modes)
            return false;
        return modes.some((mode) => mode.id === modeId && mode.isUnattended === true);
    };
    const resolveCallerCreateAgentArgs = (args, parentAgentId) => {
        const callerArgs = agentToAgentCreateAgentArgsSchema.parse(args);
        const resolvedProviderModel = resolveRequiredProviderModel(callerArgs.provider);
        const parentAgent = agentManager.getAgent(parentAgentId);
        if (!parentAgent) {
            throw new Error(`Parent agent ${parentAgentId} not found`);
        }
        const provider = resolvedProviderModel.provider;
        const resolvedCwd = resolveChildAgentCwd({
            parentCwd: parentAgent.cwd,
            requestedCwd: callerArgs.cwd,
            lockedCwd: callerContext?.lockedCwd,
            allowCustomCwd: callerContext?.allowCustomCwd ?? true,
        });
        const resolvedMode = resolveAndValidateCreateAgentMode({
            requestedMode: callerArgs.mode,
            targetProvider: provider,
            parent: {
                provider: parentAgent.provider,
                modeId: parentAgent.currentModeId,
                isUnattended: isParentInUnattendedMode(parentAgent.provider, parentAgent.currentModeId),
            },
            availableModes: getAvailableModeIds(provider),
            targetUnattendedMode: getUnattendedModeId(provider),
        });
        return {
            provider,
            initialPrompt: callerArgs.initialPrompt,
            background: callerArgs.background ?? false,
            normalizedTitle: callerArgs.title.trim(),
            model: resolvedProviderModel.model,
            thinking: callerArgs.thinking,
            features: callerArgs.features,
            labels: callerArgs.labels,
            notifyOnFinish: callerArgs.notifyOnFinish ?? false,
            resolvedCwd,
            resolvedMode,
            setupContinuation: undefined,
        };
    };
    const resolveTopLevelCreateAgentArgs = async (args) => {
        const topLevelArgs = topLevelCreateAgentArgsSchema.parse(args);
        const resolvedProviderModel = resolveRequiredProviderModel(topLevelArgs.provider);
        const { cwd, mode, worktreeName, baseBranch, refName, action, githubPrNumber } = topLevelArgs;
        const resolvedMode = resolveAndValidateCreateAgentMode({
            requestedMode: mode,
            targetProvider: resolvedProviderModel.provider,
            parent: null,
            availableModes: getAvailableModeIds(resolvedProviderModel.provider),
            targetUnattendedMode: getUnattendedModeId(resolvedProviderModel.provider),
        });
        let resolvedCwd = expandUserPath(cwd);
        let setupContinuation;
        const shouldCreateWorktree = Boolean(worktreeName || refName || action || githubPrNumber);
        if (shouldCreateWorktree) {
            if (worktreeName && !baseBranch && !refName && !action && githubPrNumber === undefined) {
                throw new Error("baseBranch is required when creating a worktree");
            }
            const createdWorktree = await createMcpWorktree({
                input: {
                    cwd: resolvedCwd,
                    worktreeSlug: worktreeName,
                    refName,
                    action,
                    githubPrNumber,
                    ...(topLevelArgs.initialPrompt
                        ? { firstAgentContext: { prompt: topLevelArgs.initialPrompt } }
                        : {}),
                    runSetup: false,
                    paseoHome: options.paseoHome,
                },
                createPaseoWorktree: options.createPaseoWorktree,
                resolveDefaultBranch: baseBranch ? async () => baseBranch : undefined,
                setupContinuation: {
                    kind: "agent",
                    terminalManager: terminalManager ?? null,
                    appendTimelineItem: ({ agentId, item }) => appendTimelineItemIfAgentKnown({
                        agentManager,
                        agentId,
                        item,
                    }),
                    emitLiveTimelineItem: ({ agentId, item }) => emitLiveTimelineItemIfAgentKnown({
                        agentManager,
                        agentId,
                        item,
                    }),
                    logger: childLogger,
                },
            });
            resolvedCwd = createdWorktree.worktree.worktreePath;
            setupContinuation = createdWorktree.setupContinuation;
        }
        return {
            provider: resolvedProviderModel.provider,
            initialPrompt: topLevelArgs.initialPrompt,
            background: topLevelArgs.background ?? false,
            normalizedTitle: topLevelArgs.title.trim(),
            model: resolvedProviderModel.model,
            thinking: topLevelArgs.thinking,
            features: topLevelArgs.features,
            labels: topLevelArgs.labels,
            notifyOnFinish: topLevelArgs.notifyOnFinish ?? false,
            resolvedCwd,
            resolvedMode,
            setupContinuation,
        };
    };
    server.registerTool("create_agent", {
        title: "Create agent",
        description: "Create an agent tied to a working directory. Requires provider/model, for example codex/gpt-5.4. Do not guess; call list_providers and list_models first if uncertain. Optionally run an initial prompt immediately or create a git worktree for the agent.",
        inputSchema: createAgentInputSchema,
        outputSchema: {
            agentId: z.string(),
            type: AgentProviderEnum,
            status: AgentStatusEnum,
            cwd: z.string(),
            currentModeId: z.string().nullable(),
            availableModes: z.array(z.object({
                id: z.string(),
                label: z.string(),
                description: z.string().nullable().optional(),
            })),
            lastMessage: z.string().nullable().optional(),
            permission: AgentPermissionRequestPayloadSchema.nullable().optional(),
        },
    }, async (args) => {
        const resolved = callerAgentId
            ? resolveCallerCreateAgentArgs(args, callerAgentId)
            : await resolveTopLevelCreateAgentArgs(args);
        const { provider, initialPrompt, background, normalizedTitle, model, thinking, features, labels, notifyOnFinish, resolvedCwd, resolvedMode, setupContinuation, } = resolved;
        const childAgentDefaultLabels = callerContext?.childAgentDefaultLabels;
        const mergedLabels = {
            ...(callerAgentId ? { [PARENT_AGENT_ID_LABEL]: callerAgentId } : {}),
            ...childAgentDefaultLabels,
            ...labels,
        };
        const snapshot = await agentManager.createAgent({
            provider,
            cwd: resolvedCwd,
            modeId: resolvedMode,
            title: normalizedTitle ?? undefined,
            model,
            thinkingOptionId: thinking,
            featureValues: features,
        }, undefined, Object.keys(mergedLabels).length > 0 ? { labels: mergedLabels } : undefined);
        setupContinuation?.startAfterAgentCreate({
            agentId: snapshot.id,
        });
        const trimmedPrompt = initialPrompt.trim();
        scheduleAgentMetadataGeneration({
            agentManager,
            agentId: snapshot.id,
            cwd: snapshot.cwd,
            workspaceGitService: options.workspaceGitService,
            initialPrompt: trimmedPrompt,
            explicitTitle: snapshot.config.title,
            paseoHome: options.paseoHome,
            logger: childLogger,
        });
        try {
            agentManager.recordUserMessage(snapshot.id, trimmedPrompt, {
                emitState: false,
            });
        }
        catch (error) {
            childLogger.error({ err: error, agentId: snapshot.id }, "Failed to record initial prompt");
        }
        try {
            startAgentRun(agentManager, snapshot.id, trimmedPrompt, childLogger);
            if (notifyOnFinish && callerAgentId) {
                setupFinishNotification({
                    agentManager,
                    agentStorage,
                    childAgentId: snapshot.id,
                    callerAgentId,
                    logger: childLogger,
                });
            }
            // If not running in background, wait for completion
            if (!background) {
                const result = await waitForAgentWithTimeout(agentManager, snapshot.id, {
                    waitForActive: true,
                });
                const responseData = {
                    agentId: snapshot.id,
                    type: provider,
                    status: result.status,
                    cwd: snapshot.cwd,
                    currentModeId: snapshot.currentModeId,
                    availableModes: snapshot.availableModes,
                    lastMessage: result.lastMessage,
                    permission: sanitizePermissionRequest(result.permission),
                };
                const validJson = ensureValidJson(responseData);
                const response = {
                    content: [],
                    structuredContent: validJson,
                };
                return response;
            }
        }
        catch (error) {
            childLogger.error({ err: error, agentId: snapshot.id }, "Failed to run initial prompt");
        }
        // Return immediately if background=true
        const response = {
            content: [],
            structuredContent: ensureValidJson({
                agentId: snapshot.id,
                type: provider,
                status: snapshot.lifecycle,
                cwd: snapshot.cwd,
                currentModeId: snapshot.currentModeId,
                availableModes: snapshot.availableModes,
                lastMessage: null,
                permission: null,
            }),
        };
        return response;
    });
    server.registerTool("set_agent_feature", {
        title: "Set agent feature",
        description: "Set a provider-specific feature on an existing agent, such as Codex fast_mode.",
        inputSchema: {
            agentId: z.string(),
            featureId: z.string().trim().min(1),
            value: z.unknown(),
        },
        outputSchema: {
            success: z.boolean(),
        },
    }, async ({ agentId, featureId, value }) => {
        await agentManager.setAgentFeature(agentId, featureId, value);
        return {
            content: [],
            structuredContent: ensureValidJson({ success: true }),
        };
    });
    server.registerTool("wait_for_agent", {
        title: "Wait for agent",
        description: "Block until the agent requests permission or the current run completes. Returns the pending permission (if any) and recent activity summary.",
        inputSchema: {
            agentId: z.string().describe("Agent identifier returned by the create_agent tool"),
        },
        outputSchema: {
            agentId: z.string(),
            status: AgentStatusEnum,
            permission: AgentPermissionRequestPayloadSchema.nullable(),
            lastMessage: z.string().nullable(),
        },
    }, async ({ agentId }, { signal }) => {
        const abortController = new AbortController();
        const cleanupFns = [];
        const cleanup = () => {
            while (cleanupFns.length) {
                const fn = cleanupFns.pop();
                try {
                    fn?.();
                }
                catch {
                    // ignore cleanup errors
                }
            }
        };
        const forwardExternalAbort = () => {
            if (!abortController.signal.aborted) {
                const reason = signal?.reason ?? new Error("wait_for_agent aborted");
                abortController.abort(reason);
            }
        };
        if (signal) {
            if (signal.aborted) {
                forwardExternalAbort();
            }
            else {
                signal.addEventListener("abort", forwardExternalAbort, { once: true });
                cleanupFns.push(() => signal.removeEventListener("abort", forwardExternalAbort));
            }
        }
        const unregister = waitTracker.register(agentId, (reason) => {
            if (!abortController.signal.aborted) {
                abortController.abort(new Error(reason ?? "wait_for_agent cancelled"));
            }
        });
        cleanupFns.push(unregister);
        try {
            const result = await waitForAgentWithTimeout(agentManager, agentId, {
                signal: abortController.signal,
            });
            const validJson = ensureValidJson({
                agentId,
                status: result.status,
                permission: sanitizePermissionRequest(result.permission),
                lastMessage: result.lastMessage,
            });
            const response = {
                content: [],
                structuredContent: validJson,
            };
            return response;
        }
        finally {
            cleanup();
        }
    });
    server.registerTool("send_agent_prompt", {
        title: "Send agent prompt",
        description: "Send a task to a running agent. Returns immediately after the agent begins processing.",
        inputSchema: {
            agentId: z.string(),
            prompt: z.string(),
            sessionMode: z
                .string()
                .optional()
                .describe("Optional mode to set before running the prompt."),
            background: z
                .boolean()
                .optional()
                .default(false)
                .describe("Run agent in background. If false (default), waits for completion or permission request. If true, returns immediately."),
            notifyOnFinish: z
                .boolean()
                .optional()
                .default(false)
                .describe("Send a notification prompt to the caller agent when this agent finishes, errors, or needs permission."),
        },
        outputSchema: {
            success: z.boolean(),
            status: AgentStatusEnum,
            lastMessage: z.string().nullable().optional(),
            permission: AgentPermissionRequestPayloadSchema.nullable().optional(),
        },
    }, async ({ agentId, prompt, sessionMode, background = false, notifyOnFinish = false }) => {
        if (agentManager.hasInFlightRun(agentId)) {
            waitTracker.cancel(agentId, "Agent run interrupted by new prompt");
        }
        await sendPromptToAgent({
            agentManager,
            agentStorage,
            agentId,
            userMessageText: prompt,
            prompt,
            sessionMode,
            logger: childLogger,
        });
        if (notifyOnFinish && callerAgentId) {
            setupFinishNotification({
                agentManager,
                agentStorage,
                childAgentId: agentId,
                callerAgentId,
                logger: childLogger,
            });
        }
        // If not running in background, wait for completion
        if (!background) {
            const result = await waitForAgentWithTimeout(agentManager, agentId, {
                waitForActive: true,
            });
            const responseData = {
                success: true,
                status: result.status,
                lastMessage: result.lastMessage,
                permission: sanitizePermissionRequest(result.permission),
            };
            const validJson = ensureValidJson(responseData);
            const response = {
                content: [],
                structuredContent: validJson,
            };
            return response;
        }
        // Return immediately if background=true
        // Re-fetch snapshot since the state may have changed
        const currentSnapshot = agentManager.getAgent(agentId);
        const responseData = {
            success: true,
            status: currentSnapshot?.lifecycle ?? "idle",
            lastMessage: null,
            permission: null,
        };
        const validJson = ensureValidJson(responseData);
        const response = {
            content: [],
            structuredContent: validJson,
        };
        return response;
    });
    server.registerTool("get_agent_status", {
        title: "Get agent status",
        description: "Return the latest snapshot for an agent, including lifecycle state, capabilities, and pending permissions.",
        inputSchema: {
            agentId: z.string(),
        },
        outputSchema: {
            status: AgentStatusEnum,
            snapshot: AgentSnapshotPayloadSchema,
        },
    }, async ({ agentId }) => {
        const snapshot = agentManager.getAgent(agentId);
        if (snapshot) {
            const structuredSnapshot = await serializeSnapshotWithMetadata(agentStorage, snapshot, childLogger);
            return {
                content: [],
                structuredContent: ensureValidJson({
                    status: snapshot.lifecycle,
                    snapshot: structuredSnapshot,
                }),
            };
        }
        const record = await agentStorage.get(agentId);
        if (!record || record.internal) {
            throw new Error(`Agent ${agentId} not found`);
        }
        const structuredSnapshot = buildStoredAgentPayload(record, resolveRegisteredProviderIds(agentManager, providerRegistry));
        return {
            content: [],
            structuredContent: ensureValidJson({
                status: structuredSnapshot.status,
                snapshot: structuredSnapshot,
            }),
        };
    });
    server.registerTool("list_agents", {
        title: "List agents",
        description: "List recent agents as compact metadata.",
        inputSchema: {
            includeArchived: z.boolean().optional().default(false),
            cwd: z.string().optional(),
            sinceHours: z
                .number()
                .int()
                .positive()
                .max(24 * 30)
                .optional()
                .default(48),
            statuses: z.array(AgentStatusEnum).optional(),
            limit: z.number().int().positive().max(200).optional().default(50),
        },
        outputSchema: {
            agents: z.array(AgentListItemPayloadSchema),
        },
    }, async ({ includeArchived = false, cwd, sinceHours = 48, statuses, limit = 50 }) => {
        const callerCwd = callerAgentId ? resolveCallerAgent()?.cwd : undefined;
        const requestedCwd = cwd?.trim() ? expandUserPath(cwd) : callerCwd;
        const statusFilter = statuses && statuses.length > 0 ? new Set(statuses) : null;
        const sinceMs = Date.now() - sinceHours * 60 * 60 * 1000;
        const liveSnapshots = agentManager.listAgents();
        const liveAgents = await Promise.all(liveSnapshots.map((snapshot) => serializeSnapshotWithMetadata(agentStorage, snapshot, childLogger)));
        const liveIds = new Set(liveSnapshots.map((snapshot) => snapshot.id));
        const storedRecords = await agentStorage.list();
        const registeredProviderIds = resolveRegisteredProviderIds(agentManager, providerRegistry);
        const storedAgents = storedRecords
            .filter((record) => !record.internal && !liveIds.has(record.id))
            .filter((record) => includeArchived || !record.archivedAt)
            .filter((record) => includeArchived || isStoredAgentProviderAvailable(record, registeredProviderIds))
            .map((record) => buildStoredAgentPayload(record, registeredProviderIds));
        const agents = [...liveAgents, ...storedAgents]
            .map(toAgentListItemPayload)
            .filter((agent) => !requestedCwd || isSameOrDescendantPath(requestedCwd, agent.cwd))
            .filter((agent) => !statusFilter || statusFilter.has(agent.status))
            .filter((agent) => !agent.archivedAt || resolveAgentListActivityTime(agent) >= sinceMs)
            .sort(compareAgentListItems)
            .slice(0, limit);
        return {
            content: [],
            structuredContent: ensureValidJson({ agents }),
        };
    });
    server.registerTool("cancel_agent", {
        title: "Cancel agent run",
        description: "Abort the agent's current run but keep the agent alive for future tasks.",
        inputSchema: {
            agentId: z.string(),
        },
        outputSchema: {
            success: z.boolean(),
        },
    }, async ({ agentId }) => {
        const success = await agentManager.cancelAgentRun(agentId);
        if (success) {
            waitTracker.cancel(agentId, "Agent run cancelled");
        }
        return {
            content: [],
            structuredContent: ensureValidJson({ success }),
        };
    });
    server.registerTool("archive_agent", {
        title: "Archive agent",
        description: "Archive an agent (soft-delete). The agent is interrupted if running and removed from the active list.",
        inputSchema: {
            agentId: z.string(),
        },
        outputSchema: {
            success: z.boolean(),
        },
    }, async ({ agentId }) => {
        await agentManager.archiveAgent(agentId);
        waitTracker.cancel(agentId, "Agent archived");
        return {
            content: [],
            structuredContent: ensureValidJson({ success: true }),
        };
    });
    server.registerTool("kill_agent", {
        title: "Kill agent",
        description: "Terminate an agent session permanently.",
        inputSchema: {
            agentId: z.string(),
        },
        outputSchema: {
            success: z.boolean(),
        },
    }, async ({ agentId }) => {
        await agentManager.closeAgent(agentId);
        waitTracker.cancel(agentId, "Agent terminated");
        return {
            content: [],
            structuredContent: ensureValidJson({ success: true }),
        };
    });
    server.registerTool("update_agent", {
        title: "Update agent",
        description: "Update an agent name and/or labels.",
        inputSchema: {
            agentId: z.string(),
            name: z.string().optional(),
            labels: z.record(z.string(), z.string()).optional().describe("Labels to set on the agent"),
        },
        outputSchema: {
            success: z.boolean(),
        },
    }, async ({ agentId, name, labels }) => {
        const trimmedName = name?.trim();
        if (trimmedName) {
            const record = await agentStorage.get(agentId);
            if (!record) {
                throw new Error(`Agent ${agentId} not found`);
            }
            await agentStorage.upsert({
                ...record,
                title: trimmedName,
                updatedAt: new Date().toISOString(),
            });
            agentManager.notifyAgentState(agentId);
        }
        if (labels) {
            await agentManager.setLabels(agentId, labels);
        }
        return {
            content: [],
            structuredContent: ensureValidJson({ success: true }),
        };
    });
    server.registerTool("list_terminals", {
        title: "List terminals",
        description: "List terminals for a working directory or across all working directories.",
        inputSchema: {
            cwd: z
                .string()
                .optional()
                .describe("Optional working directory. Defaults to the caller agent cwd."),
            all: z.boolean().optional().describe("List terminals across all working directories."),
        },
        outputSchema: {
            terminals: z.array(TerminalSummarySchema),
        },
    }, async ({ cwd, all }) => {
        if (!terminalManager) {
            throw new Error("Terminal manager is not configured");
        }
        const terminals = all
            ? (await Promise.all(terminalManager.listDirectories().map(async (directory) => (await terminalManager.getTerminals(directory)).map((terminal) => ({
                id: terminal.id,
                name: terminal.name,
                cwd: terminal.cwd,
            }))))).flat()
            : (await terminalManager.getTerminals(resolveScopedCwd(cwd, { required: true }))).map((terminal) => ({
                id: terminal.id,
                name: terminal.name,
                cwd: terminal.cwd,
            }));
        return {
            content: [],
            structuredContent: ensureValidJson({ terminals }),
        };
    });
    server.registerTool("create_terminal", {
        title: "Create terminal",
        description: "Create a terminal session for a working directory.",
        inputSchema: {
            cwd: z
                .string()
                .optional()
                .describe("Optional working directory. Defaults to the caller agent cwd."),
            name: z.string().optional().describe("Optional terminal name."),
        },
        outputSchema: TerminalSummarySchema.shape,
    }, async ({ cwd, name }) => {
        if (!terminalManager) {
            throw new Error("Terminal manager is not configured");
        }
        const terminal = await terminalManager.createTerminal({
            cwd: resolveScopedCwd(cwd, { required: true }),
            ...(name?.trim() ? { name: name.trim() } : {}),
        });
        return {
            content: [],
            structuredContent: ensureValidJson({
                id: terminal.id,
                name: terminal.name,
                cwd: terminal.cwd,
            }),
        };
    });
    server.registerTool("kill_terminal", {
        title: "Kill terminal",
        description: "Kill an existing terminal session.",
        inputSchema: {
            terminalId: z.string(),
        },
        outputSchema: {
            success: z.boolean(),
        },
    }, async ({ terminalId }) => {
        if (!terminalManager) {
            throw new Error("Terminal manager is not configured");
        }
        const terminal = terminalManager.getTerminal(terminalId);
        if (!terminal) {
            throw new Error(`Terminal ${terminalId} not found`);
        }
        terminal.kill();
        return {
            content: [],
            structuredContent: ensureValidJson({ success: true }),
        };
    });
    server.registerTool("capture_terminal", {
        title: "Capture terminal",
        description: "Capture plain-text terminal output lines from a terminal session.",
        inputSchema: {
            terminalId: z.string(),
            start: z.number().optional(),
            end: z.number().optional(),
            scrollback: z.boolean().optional(),
            stripAnsi: z.boolean().optional().default(true),
        },
        outputSchema: {
            terminalId: z.string(),
            lines: z.array(z.string()),
            totalLines: z.number().int().nonnegative(),
        },
    }, async ({ terminalId, start, end, scrollback, stripAnsi = true }) => {
        if (!terminalManager) {
            throw new Error("Terminal manager is not configured");
        }
        if (!terminalManager.getTerminal(terminalId)) {
            throw new Error(`Terminal ${terminalId} not found`);
        }
        const capture = await terminalManager.captureTerminal(terminalId, {
            start: scrollback ? 0 : start,
            end,
            stripAnsi,
        });
        return {
            content: [],
            structuredContent: ensureValidJson({
                terminalId,
                lines: capture.lines,
                totalLines: capture.totalLines,
            }),
        };
    });
    server.registerTool("send_terminal_keys", {
        title: "Send terminal keys",
        description: "Send literal text or special key tokens to a terminal session.",
        inputSchema: {
            terminalId: z.string(),
            keys: z.string(),
            literal: z.boolean().optional(),
        },
        outputSchema: {
            success: z.boolean(),
        },
    }, async ({ terminalId, keys, literal = false }) => {
        if (!terminalManager) {
            throw new Error("Terminal manager is not configured");
        }
        const terminal = terminalManager.getTerminal(terminalId);
        if (!terminal) {
            throw new Error(`Terminal ${terminalId} not found`);
        }
        terminal.send({
            type: "input",
            data: resolveTerminalKeyToken(keys, literal),
        });
        return {
            content: [],
            structuredContent: ensureValidJson({ success: true }),
        };
    });
    server.registerTool("create_schedule", {
        title: "Create schedule",
        description: "Create a recurring schedule that runs on an agent or a new agent.",
        inputSchema: {
            prompt: z.string().trim().min(1, "prompt is required"),
            every: z.string().optional(),
            cron: z.string().optional(),
            name: z.string().optional(),
            target: z.enum(["self", "new-agent"]).optional(),
            provider: AgentProviderEnum.optional().describe("Provider, or provider/model (for example: codex or codex/gpt-5.4)."),
            cwd: z.string().optional(),
            maxRuns: z.number().int().positive().optional(),
            expiresIn: z.string().optional(),
        },
        outputSchema: ScheduleSummarySchema.shape,
    }, async ({ prompt, every, cron, name, target, provider, cwd, maxRuns, expiresIn }) => {
        if (!scheduleService) {
            throw new Error("Schedule service is not configured");
        }
        const cadenceCount = Number(every !== undefined) + Number(cron !== undefined);
        if (cadenceCount !== 1) {
            throw new Error("Specify exactly one of every or cron");
        }
        const scheduleTarget = target === "self"
            ? (() => {
                const callerAgent = resolveCallerAgent();
                if (!callerAgentId || !callerAgent) {
                    throw new Error("target=self requires a caller agent");
                }
                const trimmedCwd = cwd?.trim();
                if (trimmedCwd && expandUserPath(trimmedCwd) !== callerAgent.cwd) {
                    throw new Error("cwd can only differ from the caller agent when target=new-agent");
                }
                if (provider !== undefined) {
                    const resolved = resolveScheduleProviderAndModel({
                        provider,
                        defaultProvider: callerAgent.provider,
                    });
                    if (resolved.provider !== callerAgent.provider ||
                        (resolved.model !== undefined && resolved.model !== callerAgent.config.model)) {
                        throw new Error("provider can only differ from the caller agent when target=new-agent");
                    }
                }
                return { type: "agent", agentId: callerAgentId };
            })()
            : (() => {
                return resolveNewAgentScheduleTarget({ provider, cwd });
            })();
        const schedule = await scheduleService.create({
            prompt: prompt.trim(),
            cadence: every
                ? { type: "every", everyMs: parseDurationString(every) }
                : { type: "cron", expression: cron.trim() },
            target: scheduleTarget,
            ...(name?.trim() ? { name: name.trim() } : {}),
            ...(maxRuns === undefined ? {} : { maxRuns }),
            ...(expiresIn === undefined
                ? {}
                : { expiresAt: new Date(Date.now() + parseDurationString(expiresIn)).toISOString() }),
        });
        return {
            content: [],
            structuredContent: ensureValidJson(toScheduleSummary(schedule)),
        };
    });
    server.registerTool("list_schedules", {
        title: "List schedules",
        description: "List all schedules managed by the daemon.",
        inputSchema: {},
        outputSchema: {
            schedules: z.array(ScheduleSummarySchema),
        },
    }, async () => {
        if (!scheduleService) {
            throw new Error("Schedule service is not configured");
        }
        const schedules = (await scheduleService.list()).map((schedule) => toScheduleSummary(schedule));
        return {
            content: [],
            structuredContent: ensureValidJson({ schedules }),
        };
    });
    server.registerTool("inspect_schedule", {
        title: "Inspect schedule",
        description: "Inspect a schedule and its run history.",
        inputSchema: {
            id: z.string(),
        },
        outputSchema: StoredScheduleSchema.shape,
    }, async ({ id }) => {
        if (!scheduleService) {
            throw new Error("Schedule service is not configured");
        }
        const schedule = await scheduleService.inspect(id);
        return {
            content: [],
            structuredContent: ensureValidJson(schedule),
        };
    });
    server.registerTool("pause_schedule", {
        title: "Pause schedule",
        description: "Pause an active schedule.",
        inputSchema: {
            id: z.string(),
        },
        outputSchema: {
            success: z.boolean(),
        },
    }, async ({ id }) => {
        if (!scheduleService) {
            throw new Error("Schedule service is not configured");
        }
        await scheduleService.pause(id);
        return {
            content: [],
            structuredContent: ensureValidJson({ success: true }),
        };
    });
    server.registerTool("resume_schedule", {
        title: "Resume schedule",
        description: "Resume a paused schedule.",
        inputSchema: {
            id: z.string(),
        },
        outputSchema: {
            success: z.boolean(),
        },
    }, async ({ id }) => {
        if (!scheduleService) {
            throw new Error("Schedule service is not configured");
        }
        await scheduleService.resume(id);
        return {
            content: [],
            structuredContent: ensureValidJson({ success: true }),
        };
    });
    server.registerTool("delete_schedule", {
        title: "Delete schedule",
        description: "Delete a schedule permanently.",
        inputSchema: {
            id: z.string(),
        },
        outputSchema: {
            success: z.boolean(),
        },
    }, async ({ id }) => {
        if (!scheduleService) {
            throw new Error("Schedule service is not configured");
        }
        await scheduleService.delete(id);
        return {
            content: [],
            structuredContent: ensureValidJson({ success: true }),
        };
    });
    server.registerTool("list_providers", {
        title: "List providers",
        description: "List configured agent providers, availability, and their modes.",
        inputSchema: {},
        outputSchema: {
            providers: z.array(ProviderSummarySchema),
        },
    }, async () => {
        const providers = await Promise.all(Object.values(providerRegistry ?? {}).map((provider) => resolveProviderSummary(provider, childLogger)));
        return {
            content: [],
            structuredContent: ensureValidJson({ providers }),
        };
    });
    server.registerTool("list_models", {
        title: "List models",
        description: "List models for an agent provider.",
        inputSchema: {
            provider: AgentProviderEnum,
        },
        outputSchema: {
            provider: z.string(),
            models: z.array(AgentModelSchema),
        },
    }, async ({ provider }) => {
        if (!providerRegistry) {
            throw new Error("Provider registry is not configured");
        }
        const definition = providerRegistry[provider];
        if (!definition) {
            throw new Error(`Provider ${provider} is not configured`);
        }
        if (!definition.enabled) {
            throw new Error(`Provider '${provider}' is disabled`);
        }
        const models = await definition.fetchModels({ cwd: resolveSnapshotCwd(), force: false });
        return {
            content: [],
            structuredContent: ensureValidJson({
                provider,
                models,
            }),
        };
    });
    server.registerTool("list_provider_features", {
        title: "List provider features",
        description: "List provider-specific features available for a draft agent configuration, such as Codex fast_mode.",
        inputSchema: listProviderFeaturesInputSchema,
        outputSchema: {
            provider: AgentProviderEnum,
            features: z.array(AgentFeatureSchema),
        },
    }, async ({ provider, cwd, modeId, model, thinkingOptionId, featureValues }) => {
        const features = await agentManager.listDraftFeatures({
            provider,
            cwd: expandUserPath(cwd),
            ...(modeId ? { modeId } : {}),
            ...(model ? { model } : {}),
            ...(thinkingOptionId ? { thinkingOptionId } : {}),
            ...(featureValues ? { featureValues } : {}),
        });
        return {
            content: [],
            structuredContent: ensureValidJson({
                provider,
                features,
            }),
        };
    });
    server.registerTool("list_worktrees", {
        title: "List worktrees",
        description: "List Paseo-managed git worktrees for a repository.",
        inputSchema: {
            cwd: z
                .string()
                .optional()
                .describe("Optional repository cwd. Defaults to the caller agent cwd."),
        },
        outputSchema: {
            worktrees: z.array(WorktreeSummarySchema),
        },
    }, async ({ cwd }) => {
        const resolvedCwd = resolveScopedCwd(cwd, { required: true });
        if (!options.workspaceGitService) {
            throw new Error("WorkspaceGitService is required to list worktrees");
        }
        const worktrees = await options.workspaceGitService.listWorktrees(resolvedCwd, {
            reason: "mcp:list-worktrees",
        });
        return {
            content: [],
            structuredContent: ensureValidJson({ worktrees }),
        };
    });
    server.registerTool("create_worktree", {
        title: "Create worktree",
        description: "Create a Paseo-managed git worktree. Branch off a new branch, check out an existing branch, or check out a GitHub PR.",
        inputSchema: {
            cwd: z.string().optional().describe("Repository directory. Defaults to the agent's cwd."),
            target: z
                .discriminatedUnion("mode", [
                z
                    .object({
                    mode: z.literal("branch-off"),
                    newBranch: z.string().min(1).describe("Name for the new branch."),
                    base: z
                        .string()
                        .min(1)
                        .optional()
                        .describe("Base ref. Defaults to the repo's default branch."),
                })
                    .describe("Create a new branch off a base."),
                z
                    .object({
                    mode: z.literal("checkout-branch"),
                    branch: z.string().min(1).describe("Existing branch to check out."),
                })
                    .describe("Check out an existing branch."),
                z
                    .object({
                    mode: z.literal("checkout-pr"),
                    prNumber: z.number().int().positive().describe("Pull request number."),
                })
                    .describe("Check out a GitHub pull request."),
            ])
                .describe("What the worktree should contain."),
        },
        outputSchema: {
            branchName: z.string(),
            worktreePath: z.string(),
        },
    }, async ({ cwd, target }) => {
        const repoRoot = resolveScopedCwd(cwd, { required: true });
        const mcpInput = mcpCreateWorktreeInput(repoRoot, target, options.paseoHome);
        const createdWorktree = await createMcpWorktree({
            input: mcpInput.input,
            createPaseoWorktree: options.createPaseoWorktree,
            resolveDefaultBranch: mcpInput.resolveDefaultBranch,
        });
        const { worktree } = createdWorktree;
        await options.workspaceGitService?.listWorktrees?.(repoRoot, {
            force: true,
            reason: "mcp:create-worktree",
        });
        return {
            content: [],
            structuredContent: ensureValidJson({
                branchName: worktree.branchName,
                worktreePath: worktree.worktreePath,
            }),
        };
    });
    server.registerTool("archive_worktree", {
        title: "Archive worktree",
        description: "Delete a Paseo-managed git worktree.",
        inputSchema: {
            cwd: z
                .string()
                .optional()
                .describe("Optional repository cwd. Defaults to the caller agent cwd."),
            worktreePath: z.string().optional(),
            worktreeSlug: z.string().optional(),
        },
        outputSchema: {
            success: z.boolean(),
        },
    }, async ({ cwd, worktreePath, worktreeSlug }) => {
        const resolvedCwd = resolveScopedCwd(cwd, { required: true });
        if (!worktreePath && !worktreeSlug) {
            throw new Error("worktreePath or worktreeSlug is required");
        }
        if (!options.github) {
            throw new Error("GitHub service is required to archive worktrees");
        }
        if (!options.workspaceGitService) {
            throw new Error("WorkspaceGitService is required to archive worktrees");
        }
        if (!options.archiveWorkspaceRecord) {
            throw new Error("Workspace registry archiver is required to archive worktrees");
        }
        if (!options.emitWorkspaceUpdatesForWorkspaceIds) {
            throw new Error("Workspace update emitter is required to archive worktrees");
        }
        if (!options.markWorkspaceArchiving) {
            throw new Error("Workspace archiving marker is required to archive worktrees");
        }
        if (!options.clearWorkspaceArchiving) {
            throw new Error("Workspace archiving clearer is required to archive worktrees");
        }
        if (!options.emitSessionMessage) {
            throw new Error("Session message emitter is required to archive worktrees");
        }
        const repoRoot = await options.workspaceGitService.resolveRepoRoot(resolvedCwd);
        const targetPath = worktreePath ??
            join(await getPaseoWorktreesRoot(repoRoot, options.paseoHome), worktreeSlug);
        await archivePaseoWorktree({
            paseoHome: options.paseoHome,
            github: options.github,
            workspaceGitService: options.workspaceGitService,
            agentManager,
            agentStorage,
            archiveWorkspaceRecord: options.archiveWorkspaceRecord,
            emit: options.emitSessionMessage,
            emitWorkspaceUpdatesForWorkspaceIds: options.emitWorkspaceUpdatesForWorkspaceIds,
            markWorkspaceArchiving: options.markWorkspaceArchiving,
            clearWorkspaceArchiving: options.clearWorkspaceArchiving,
            isPathWithinRoot: isSameOrDescendantPath,
            killTerminalsUnderPath: (rootPath) => killTerminalsUnderPath({
                terminalManager: terminalManager ?? null,
                isPathWithinRoot: isSameOrDescendantPath,
                killTrackedTerminal: () => { },
                sessionLogger: childLogger,
            }, rootPath),
            sessionLogger: childLogger,
        }, {
            targetPath,
            repoRoot,
            requestId: "mcp:archive_worktree",
        });
        await options.workspaceGitService.listWorktrees(repoRoot, {
            force: true,
            reason: "mcp:archive-worktree",
        });
        return {
            content: [],
            structuredContent: ensureValidJson({ success: true }),
        };
    });
    server.registerTool("get_agent_activity", {
        title: "Get agent activity",
        description: "Return recent agent timeline entries as a curated summary.",
        inputSchema: {
            agentId: z.string(),
            limit: z
                .number()
                .optional()
                .describe("Optional limit for number of activities to include (most recent first)."),
        },
        outputSchema: {
            agentId: z.string(),
            updateCount: z.number(),
            currentModeId: z.string().nullable(),
            content: z.string(),
        },
    }, async ({ agentId, limit }) => {
        await ensureAgentLoaded(agentId, {
            agentManager,
            agentStorage,
            logger: childLogger,
        });
        const timeline = agentManager.getTimeline(agentId);
        const snapshot = agentManager.getAgent(agentId);
        const selection = selectItemsByProjectedLimit({
            items: timeline,
            direction: "tail",
            limit: limit ?? 0,
        });
        const curatedContent = curateAgentActivity(selection.items);
        const { totalProjected, shownProjected } = selection;
        const noun = totalProjected === 1 ? "activity" : "activities";
        const countHeader = limit && shownProjected < totalProjected
            ? `Showing ${shownProjected} of ${totalProjected} ${noun} (limited to ${limit})`
            : `Showing all ${totalProjected} ${noun}`;
        const contentWithCount = `${countHeader}\n\n${curatedContent}`;
        return {
            content: [],
            structuredContent: ensureValidJson({
                agentId,
                updateCount: timeline.length,
                currentModeId: snapshot?.currentModeId ?? null,
                content: contentWithCount,
            }),
        };
    });
    server.registerTool("set_agent_mode", {
        title: "Set agent session mode",
        description: "Switch the agent's session mode (plan, bypassPermissions, read-only, auto, etc.).",
        inputSchema: {
            agentId: z.string(),
            modeId: z.string(),
        },
        outputSchema: {
            success: z.boolean(),
            newMode: z.string(),
        },
    }, async ({ agentId, modeId }) => {
        await agentManager.setAgentMode(agentId, modeId);
        return {
            content: [],
            structuredContent: ensureValidJson({ success: true, newMode: modeId }),
        };
    });
    server.registerTool("list_pending_permissions", {
        title: "List pending permissions",
        description: "Return all pending permission requests across all agents with the normalized payloads.",
        inputSchema: {},
        outputSchema: {
            permissions: z.array(z.object({
                agentId: z.string(),
                status: AgentStatusEnum,
                request: AgentPermissionRequestPayloadSchema,
            })),
        },
    }, async () => {
        const permissions = agentManager.listAgents().flatMap((agent) => {
            const payload = toAgentPayload(agent);
            return payload.pendingPermissions.map((request) => ({
                agentId: agent.id,
                status: payload.status,
                request,
            }));
        });
        return {
            content: [],
            structuredContent: ensureValidJson({ permissions }),
        };
    });
    server.registerTool("respond_to_permission", {
        title: "Respond to permission",
        description: "Approve or deny a pending permission request with an AgentManager-compatible response payload.",
        inputSchema: {
            agentId: z.string(),
            requestId: z.string(),
            response: AgentPermissionResponseSchema,
        },
        outputSchema: {
            success: z.boolean(),
        },
    }, async ({ agentId, requestId, response }) => {
        await agentManager.respondToPermission(agentId, requestId, response);
        return {
            content: [],
            structuredContent: ensureValidJson({ success: true }),
        };
    });
    return server;
}
function mcpCreateWorktreeInput(repoRoot, target, paseoHome) {
    const base = { cwd: repoRoot, runSetup: false, paseoHome };
    switch (target.mode) {
        case "branch-off":
            return {
                input: {
                    ...base,
                    worktreeSlug: target.newBranch,
                    action: "branch-off",
                    ...(target.base ? { refName: target.base } : {}),
                },
            };
        case "checkout-branch":
            return {
                input: { ...base, action: "checkout", refName: target.branch },
            };
        case "checkout-pr":
            return {
                input: { ...base, action: "checkout", githubPrNumber: target.prNumber },
            };
        default:
            throw new Error("unreachable");
    }
}
async function createMcpWorktree(options) {
    try {
        if (!options.createPaseoWorktree) {
            throw new Error("Paseo worktree service is not configured");
        }
        const result = await options.createPaseoWorktree(options.input, {
            ...(options.resolveDefaultBranch
                ? { resolveDefaultBranch: options.resolveDefaultBranch }
                : {}),
            ...(options.setupContinuation ? { setupContinuation: options.setupContinuation } : {}),
        });
        return result;
    }
    catch (error) {
        throw toWorktreeRequestError(error);
    }
}
//# sourceMappingURL=mcp-server.js.map