"use strict";
/**
 * Module: tools/mcp
 *
 * Local MCP supervisor control tools for testing and operations.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.mcpLeaseReminderOwner = exports.mcpDisableTool = exports.mcpReleaseTool = exports.mcpRestartTool = void 0;
const log_1 = require("../log");
const supervisor_1 = require("../mcp/supervisor");
const driver_messages_1 = require("../runtime/driver-messages");
const work_language_1 = require("../runtime/work-language");
const tool_1 = require("../tool");
const tool_availability_updates_1 = require("../tool-availability-updates");
const log = (0, log_1.createLogger)('tools/mcp');
function parseMcpRestartArgs(args) {
    const serverId = args.serverId;
    if (typeof serverId !== 'string' || !serverId.trim()) {
        throw new Error(`mcp_restart.serverId must be a non-empty string`);
    }
    return { serverId };
}
function parseMcpReleaseArgs(args) {
    const serverId = args.serverId;
    if (typeof serverId !== 'string' || !serverId.trim()) {
        throw new Error(`mcp_release.serverId must be a non-empty string`);
    }
    return { serverId };
}
function parseMcpDisableArgs(args) {
    const serverId = args.serverId;
    if (typeof serverId !== 'string' || !serverId.trim()) {
        throw new Error(`mcp_disable.serverId must be a non-empty string`);
    }
    return { serverId };
}
function isMcpLeaseReminderMeta(value) {
    if (!isRecord(value) || Array.isArray(value))
        return false;
    if (value.kind !== 'mcp_lease')
        return false;
    return typeof value.serverId === 'string' && value.serverId.trim().length > 0;
}
const mcpRestartSchema = {
    type: 'object',
    properties: {
        serverId: {
            type: 'string',
            description: "MCP server id from `.minds/mcp.yaml` (e.g., 'sdk_stdio'). Enables the server if needed, then restarts this server only.",
        },
    },
    required: ['serverId'],
    additionalProperties: false,
};
const mcpReleaseSchema = {
    type: 'object',
    properties: {
        serverId: {
            type: 'string',
            description: "MCP server id from `.minds/mcp.yaml` (e.g., 'playwright'). Releases this dialog's current leased MCP connection/process for that server.",
        },
    },
    required: ['serverId'],
    additionalProperties: false,
};
const mcpDisableSchema = {
    type: 'object',
    properties: {
        serverId: {
            type: 'string',
            description: "MCP server id from `.minds/mcp.yaml` (e.g., 'playwright'). Stops any loaded MCP connection/leases and writes servers.<id>.enabled=false.",
        },
    },
    required: ['serverId'],
    additionalProperties: false,
};
exports.mcpRestartTool = {
    type: 'func',
    name: 'mcp_restart',
    description: 'Enable a configured MCP server if needed, then restart it using the current `.minds/mcp.yaml` config.',
    descriptionI18n: {
        en: 'Enable a configured MCP server if needed, then restart it using the current `.minds/mcp.yaml` config.',
        zh: '按需启用指定 MCP 服务器，然后使用当前 `.minds/mcp.yaml` 配置重启它。',
    },
    parameters: mcpRestartSchema,
    argsValidation: 'dominds',
    call: async (_dlg, caller, args) => {
        const parsed = parseMcpRestartArgs(args);
        const res = await (0, supervisor_1.requestMcpServerRestart)(parsed.serverId);
        if (res.ok) {
            log.debug('mcp_restart', undefined, {
                caller: caller.id,
                serverId: parsed.serverId,
                ok: true,
            });
        }
        else {
            log.warn('mcp_restart failed', undefined, {
                caller: caller.id,
                serverId: parsed.serverId,
                ok: false,
                errorText: res.errorText,
            });
            return (0, tool_1.toolFailure)(`error: ${res.errorText}`);
        }
        return (0, tool_1.toolSuccess)(`ok: restarted ${parsed.serverId}`);
    },
};
exports.mcpReleaseTool = {
    type: 'func',
    name: 'mcp_release',
    description: "Release this dialog's current leased MCP connection/process for a server.",
    descriptionI18n: {
        en: "Release this dialog's current leased MCP connection/process for a server.",
        zh: '释放当前对话为某个 server 持有的 MCP 连接/进程。',
    },
    parameters: mcpReleaseSchema,
    argsValidation: 'dominds',
    call: async (dlg, caller, args) => {
        const parsed = parseMcpReleaseArgs(args);
        const dialogKey = dlg.id.key();
        const res = (0, supervisor_1.releaseMcpToolsetLeaseForDialog)(parsed.serverId, dialogKey);
        if (res.ok) {
            log.debug('mcp_release', undefined, {
                caller: caller.id,
                serverId: parsed.serverId,
                ok: true,
                released: res.released,
            });
        }
        else {
            log.warn('mcp_release failed', undefined, {
                caller: caller.id,
                serverId: parsed.serverId,
                ok: false,
                errorText: res.errorText,
            });
            return (0, tool_1.toolFailure)(`error: ${res.errorText}`);
        }
        if (!res.released) {
            return (0, tool_1.toolSuccess)(`ok: no active lease for ${parsed.serverId} (or server is truely-stateless)`);
        }
        (0, tool_availability_updates_1.notifyToolAvailabilityRuntimeLeaseChanged)(`mcp_release:${parsed.serverId}:${dialogKey}`);
        return (0, tool_1.toolSuccess)(`ok: released ${parsed.serverId} for dialog ${dialogKey}`);
    },
};
exports.mcpDisableTool = {
    type: 'func',
    name: 'mcp_disable',
    description: 'Disable a configured MCP server, clear its loaded MCP connection/leases, and persist enabled=false in `.minds/mcp.yaml`.',
    descriptionI18n: {
        en: 'Disable a configured MCP server, clear its loaded MCP connection/leases, and persist enabled=false in `.minds/mcp.yaml`.',
        zh: '禁用指定 MCP 服务器，清理其已加载 MCP 连接/租约，并在 `.minds/mcp.yaml` 中持久写入 enabled=false。',
    },
    parameters: mcpDisableSchema,
    argsValidation: 'dominds',
    call: async (_dlg, caller, args) => {
        const parsed = parseMcpDisableArgs(args);
        const res = await (0, supervisor_1.requestMcpServerDisable)(parsed.serverId);
        if (res.ok) {
            log.info('mcp_disable', undefined, {
                caller: caller.id,
                serverId: parsed.serverId,
                ok: true,
            });
        }
        else {
            log.warn('mcp_disable failed', undefined, {
                caller: caller.id,
                serverId: parsed.serverId,
                ok: false,
                errorText: res.errorText,
            });
            return (0, tool_1.toolFailure)(`error: ${res.errorText}`);
        }
        return (0, tool_1.toolSuccess)(`ok: disabled ${parsed.serverId} and set enabled=false`);
    },
};
exports.mcpLeaseReminderOwner = {
    name: 'mcpLease',
    async updateReminder(dlg, reminder) {
        if (reminder.owner !== exports.mcpLeaseReminderOwner)
            return { treatment: 'keep' };
        if (!isMcpLeaseReminderMeta(reminder.meta))
            return { treatment: 'keep' };
        const dialogKey = dlg.id.key();
        const leased = (0, supervisor_1.isMcpToolsetLeasedToDialog)(reminder.meta.serverId, dialogKey);
        if (!leased) {
            return { treatment: 'drop' };
        }
        return { treatment: 'keep' };
    },
    async renderReminder(dlg, reminder) {
        const workLanguage = (0, work_language_1.getWorkLanguage)();
        const prefix = (0, driver_messages_1.formatSystemNoticePrefix)(workLanguage);
        if (reminder.owner !== exports.mcpLeaseReminderOwner || !isMcpLeaseReminderMeta(reminder.meta)) {
            return {
                type: 'environment_msg',
                role: 'user',
                content: workLanguage === 'zh'
                    ? `${prefix} MCP 工具集租约提醒 [${reminder.id}]\n这是系统自动维护的 MCP 租约状态，不是你自己写的工作便签。${(0, driver_messages_1.formatAutoMaintainedReminderManualMirrorBan)(workLanguage)}\n\n${reminder.content}`
                    : `${prefix} MCP toolset lease reminder [${reminder.id}]\nThis is system-maintained MCP lease state, not a work note you wrote. ${(0, driver_messages_1.formatAutoMaintainedReminderManualMirrorBan)(workLanguage)}\n\n${reminder.content}`,
            };
        }
        const serverId = reminder.meta.serverId;
        return {
            type: 'environment_msg',
            role: 'user',
            content: workLanguage === 'zh'
                ? [
                    `${prefix} MCP 工具集租约 [${reminder.id}]: \`${serverId}\``,
                    '',
                    `你当前看到的是系统维护的 MCP 租约状态。该 MCP server 被视为非“真正无状态”；当前对话持有一个 MCP 连接/进程（HTTP 连接或 stdio 进程）。`,
                    (0, driver_messages_1.formatAutoMaintainedReminderManualMirrorBan)(workLanguage),
                    '',
                    `该提醒项只说明当前对话持有的连接/进程；它不决定该 server 的全局工具注册/可见性。`,
                ].join('\n')
                : [
                    `${prefix} MCP toolset lease [${reminder.id}]: \`${serverId}\``,
                    '',
                    `You are looking at system-maintained MCP lease state. This MCP server is treated as non-stateless, and the current dialog holds one MCP connection/process for it (an HTTP connection or stdio process).`,
                    (0, driver_messages_1.formatAutoMaintainedReminderManualMirrorBan)(workLanguage),
                    '',
                    `This reminder only describes the connection/process held by the current dialog; it does not determine global tool registration/visibility for that server.`,
                ].join('\n'),
        };
    },
};
function isRecord(value) {
    return typeof value === 'object' && value !== null;
}
