"use strict";
/**
 * Module: tools/ctrl
 *
 * Intrinsic dialog control tools.
 *
 * These tools are injected by runtime according to dialog scope without needing
 * to be explicitly listed in team.yaml toolsets or tools configuration. Reminder
 * and course-control tools are available in all dialog scopes; Taskdoc mutation
 * tools are only exposed in Main Dialogs.
 *
 * INTRINSIC TOOLS:
 * - add_reminder: Add a reminder
 * - delete_reminder: Delete a reminder by id
 * - update_reminder: Update reminder content
 * - clear_mind: Start a new course, optionally add a reminder
 * - do_mind: Main Dialog only; create a new `.tsk/` Taskdoc section without starting a new course
 * - change_mind: Main Dialog only; update a `.tsk/` Taskdoc section without starting a new course
 * - mind_more: Main Dialog only; append entries to a `.tsk/` Taskdoc section without starting a new course
 * - never_mind: Main Dialog only; delete a `.tsk/` Taskdoc section file without starting a new course
 * - recall_taskdoc: Read a Taskdoc section from `*.tsk/` by selector and optional category
 *
 * USAGE CONTEXT:
 * Can both be triggered by an agent autonomously, or by human with role='user' msg,
 * both ways treated the same
 *
 * reminder items with `echoback !== false` are injected into llm input;
 * virtual reminders are UI-only and do not appear in reminder_id-targeted operations
 * agents should see hints of reminder manip syntax
 * humans should better have clickable UI widgets to draft reminder manips
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.recallTaskdocTool = exports.mindMoreTool = exports.neverMindTool = exports.doMindTool = exports.changeMindTool = exports.clearMindTool = exports.updateReminderTool = exports.addReminderTool = exports.deleteReminderTool = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const dialog_1 = require("../dialog");
const rtws_1 = require("../rtws");
const driver_messages_1 = require("../runtime/driver-messages");
const tool_result_messages_1 = require("../runtime/tool-result-messages");
const work_language_1 = require("../runtime/work-language");
const shared_reminders_1 = require("../shared-reminders");
const tool_1 = require("../tool");
const task_package_1 = require("../utils/task-package");
function isRecord(value) {
    return typeof value === 'object' && value !== null && !Array.isArray(value);
}
function isJsonValue(value) {
    if (value === null ||
        typeof value === 'string' ||
        typeof value === 'number' ||
        typeof value === 'boolean') {
        return true;
    }
    if (Array.isArray(value)) {
        return value.every((item) => isJsonValue(item));
    }
    if (!isRecord(value)) {
        return false;
    }
    return Object.values(value).every((item) => isJsonValue(item));
}
function isJsonObject(value) {
    return isRecord(value) && Object.values(value).every((item) => isJsonValue(item));
}
function isPathWithinDirectory(childPath, parentDir) {
    const relative = path.relative(parentDir, childPath);
    return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative));
}
function getManagerTool(meta) {
    if (!isRecord(meta)) {
        return undefined;
    }
    const manager = meta['manager'];
    if (!isRecord(manager)) {
        return undefined;
    }
    const tool = manager['tool'];
    return typeof tool === 'string' && tool.trim().length > 0 ? tool.trim() : undefined;
}
function getDeleteAltInstruction(meta) {
    if (!isRecord(meta)) {
        return undefined;
    }
    const deleteValue = meta['delete'];
    if (!isRecord(deleteValue)) {
        return undefined;
    }
    const altInstruction = deleteValue['altInstruction'];
    return typeof altInstruction === 'string' && altInstruction.trim().length > 0
        ? altInstruction.trim()
        : undefined;
}
function getUpdateAltInstruction(meta) {
    if (!isRecord(meta)) {
        return undefined;
    }
    const updateValue = meta['update'];
    if (!isRecord(updateValue)) {
        return undefined;
    }
    const altInstruction = updateValue['altInstruction'];
    return typeof altInstruction === 'string' && altInstruction.trim().length > 0
        ? altInstruction.trim()
        : undefined;
}
function formatManualDeleteBlockedError(language, altInstruction) {
    return language === 'zh'
        ? `错误：该提醒项不能用 delete_reminder 删除；请改为执行：${altInstruction}`
        : `Error: This reminder cannot be deleted via delete_reminder. Use instead: ${altInstruction}`;
}
function formatManualUpdateBlockedError(language, altInstruction) {
    return language === 'zh'
        ? `错误：该提醒项不能用 update_reminder 修改；请改按此处理：${altInstruction}`
        : `Error: This reminder cannot be edited via update_reminder. Follow instead: ${altInstruction}`;
}
function parseReminderRenderMode(value) {
    if (value === undefined)
        return 'markdown';
    return value === 'plain' || value === 'markdown' ? value : null;
}
function getContinuationPackageContextHealthLevel(snapshot) {
    if (snapshot?.kind !== 'available') {
        return undefined;
    }
    if (snapshot.level === 'caution' || snapshot.level === 'critical') {
        return snapshot.level;
    }
    return undefined;
}
function buildContinuationPackageReminderMeta(args) {
    const baseMeta = {
        kind: 'continuation_package',
        createdBy: args.createdBy,
        ...(args.contextHealthLevel === undefined
            ? {}
            : { contextHealthLevel: args.contextHealthLevel }),
    };
    if (!isJsonObject(args.existingMeta)) {
        return baseMeta;
    }
    if (args.existingMeta['kind'] === 'continuation_package') {
        const preservedCreatedBy = args.existingMeta['createdBy'] === 'clear_mind' ||
            args.existingMeta['createdBy'] === 'context_health'
            ? args.existingMeta['createdBy']
            : args.createdBy;
        const nextMeta = {
            ...args.existingMeta,
            kind: 'continuation_package',
            createdBy: preservedCreatedBy,
            ...(args.contextHealthLevel === undefined
                ? {}
                : { contextHealthLevel: args.contextHealthLevel }),
        };
        return nextMeta;
    }
    const nextMeta = { ...args.existingMeta, ...baseMeta };
    return nextMeta;
}
function removeContinuationPackageReminderMeta(existingMeta) {
    if (!isJsonObject(existingMeta) || existingMeta['kind'] !== 'continuation_package') {
        return { changed: false };
    }
    const nextMeta = {};
    for (const [key, value] of Object.entries(existingMeta)) {
        if (key === 'kind' || key === 'createdBy' || key === 'contextHealthLevel') {
            continue;
        }
        nextMeta[key] = value;
    }
    if (Object.keys(nextMeta).length === 0) {
        return { changed: true, nextMeta: null };
    }
    return { changed: true, nextMeta };
}
async function resolveReminderTarget(dlg, reminderIdRaw) {
    const reminderId = typeof reminderIdRaw === 'string' ? reminderIdRaw.trim() : '';
    if (reminderId === '') {
        return { ok: false, reminderId: String(reminderIdRaw ?? '') };
    }
    const target = await dlg.resolveReminderTargetById(reminderId);
    if (!target) {
        return { ok: false, reminderId };
    }
    return { ok: true, target };
}
function runReminderIndexMutation(mutation) {
    try {
        mutation();
        return true;
    }
    catch (error) {
        if (error instanceof dialog_1.InvalidReminderIndexError) {
            return false;
        }
        throw error;
    }
}
function findReminderIndexById(sourceLabel, reminders, reminderId) {
    let foundIndex = null;
    for (let index = 0; index < reminders.length; index += 1) {
        const reminder = reminders[index];
        if (reminder?.id !== reminderId)
            continue;
        if (foundIndex !== null) {
            throw new Error(`Duplicate ${sourceLabel} reminder_id detected: ${reminderId}`);
        }
        foundIndex = index;
    }
    return foundIndex;
}
async function deleteSharedReminderById(target, reminderId) {
    return (0, shared_reminders_1.mutateSharedReminders)(target, (reminders) => {
        const index = findReminderIndexById('shared', reminders, reminderId);
        if (index === null)
            return false;
        reminders.splice(index, 1);
        return true;
    });
}
async function updateSharedReminderById(target, reminderId, updateReminder) {
    return (0, shared_reminders_1.mutateSharedReminders)(target, (reminders) => {
        const index = findReminderIndexById('shared', reminders, reminderId);
        if (index === null)
            return false;
        const reminder = reminders[index];
        if (reminder === undefined) {
            throw new Error(`Shared reminder index ${index} disappeared while updating reminder_id ${reminderId}`);
        }
        reminders[index] = updateReminder(reminder);
        return true;
    });
}
function replaceReminderContent(reminder, content, meta, renderMode) {
    return (0, tool_1.materializeReminder)({
        id: reminder.id,
        content,
        owner: reminder.owner,
        meta: meta !== undefined ? meta : reminder.meta,
        echoback: reminder.echoback,
        scope: reminder.scope,
        createdAt: reminder.createdAt,
        priority: reminder.priority,
        renderMode: renderMode ?? reminder.renderMode,
    });
}
async function deleteResolvedReminderTarget(dlg, target) {
    switch (target.source) {
        case 'dialog': {
            const index = findReminderIndexById('dialog', dlg.reminders, target.reminder.id);
            if (index === null)
                return false;
            return runReminderIndexMutation(() => {
                dlg.deleteReminder(index);
            });
        }
        case 'runtime': {
            const deleted = await deleteSharedReminderById(target.target, target.reminder.id);
            if (deleted)
                dlg.touchReminders();
            return deleted;
        }
    }
    const _exhaustive = target;
    return _exhaustive;
}
async function updateResolvedReminderTarget(dlg, target, content, meta, renderMode) {
    switch (target.source) {
        case 'dialog': {
            const index = findReminderIndexById('dialog', dlg.reminders, target.reminder.id);
            if (index === null)
                return false;
            return runReminderIndexMutation(() => {
                dlg.updateReminder(index, content, meta, { renderMode });
            });
        }
        case 'runtime': {
            const updated = await updateSharedReminderById(target.target, target.reminder.id, (current) => replaceReminderContent(current, content, meta, renderMode));
            if (updated)
                dlg.touchReminders();
            return updated;
        }
    }
    const _exhaustive = target;
    return _exhaustive;
}
function getCtrlMessages(language) {
    if (language === 'zh') {
        return {
            invalidFormatDelete: '参数格式不对。用法：delete_reminder({ reminder_id: string })',
            reminderDoesNotExist: (reminderId) => `提醒项 '${reminderId}' 不存在。`,
            reminderTargetChanged: '错误：提醒项列表已变化，这条提醒项当前不在可见列表中。请重新查看提醒项列表后，用当前的 reminder_id 重试。',
            invalidFormatAdd: '参数格式不对。用法：add_reminder({ content: string, scope?: "dialog" | "task" | "agent" })（省略 scope 表示 task）',
            reminderContentEmpty: '提醒内容不能为空',
            invalidFormatUpdate: '参数格式不对。用法：update_reminder({ reminder_id: string, content: string })',
            invalidFormatDoMind: '参数格式不对。用法：do_mind({ selector: string, category?: string, content: string })',
            invalidFormatChangeMind: '参数格式不对。用法：change_mind({ selector: string, category?: string, content: string, previous_content_hash: string })',
            tooManyArgsChangeMind: '参数格式不对。用法：change_mind({ selector: string, category?: string, content: string, previous_content_hash: string })',
            taskDocPreviousContentHashRequired: '错误：change_mind 需要 previous_content_hash。请先调用 recall_taskdoc 显式取得当前章节的 content_hash，合并原有内容后再整段替换；没有把握时用 mind_more 追加小条目。',
            taskDocPreviousContentHashInvalid: '错误：previous_content_hash 格式无效。它必须是 recall_taskdoc 返回的 crc32:<8位十六进制> content_hash。',
            taskDocContentHashMismatch: (relativePath, currentContentHash) => `错误：${relativePath} 的内容哈希不匹配，说明该章节已变化或你没有基于当前内容改写。\n` +
                `当前 content_hash：${currentContentHash}\n\n` +
                `请重新读取/回顾当前章节内容，并只在已充分合并原有内容后重试。若新内容会冲掉、删除或实质替换原有内容，必须满足其一：\n` +
                `- 获得人类对该替换的直接、针对性确认；或\n` +
                `- 依据人类认可的明确 SOP/验收标准，已经充分考虑原有内容且该替换合规。\n` +
                `否则不要覆盖；优先使用 mind_more 追加或向人类确认。`,
            invalidFormatMindMore: '参数格式不对。用法：mind_more({ items: string[], sep?: string, selector?: string, category?: string })（selector 默认 progress）',
            invalidFormatNeverMind: '参数格式不对。用法：never_mind({ selector: string, category?: string })',
            mindMoreItemsRequired: '需要提供要追加的条目（items），且每一项都必须是非空字符串。\n' +
                '示例：mind_more({"items":["- 下一步：复核验证结果（详见 <文档路径>#<章节>）","- 阻塞：等待 API 验收口径确认"]})',
            invalidFormatRecallTaskdoc: '参数格式不对。用法：recall_taskdoc({ selector: string, category?: string })',
            taskDocContentRequired: '需要提供差遣牒内容（content）。\n' +
                '示例：\n' +
                '```json\n' +
                '{\n' +
                '  "selector": "progress",\n' +
                '  "content": "- 关键决策：...\\n- 下一步：..."\n' +
                '}\n' +
                '```',
            noTaskDocPathConfigured: '此对话未配置差遣牒路径',
            pathMustBeWithinWorkspace: '路径必须位于 rtws（运行时工作区）内',
            invalidTaskDocPath: (taskDocPath) => `差遣牒路径 '${taskDocPath}' 无效。应为 *.tsk/ 目录。`,
            selectorRequired: '需要提供选择器（selector）。',
            invalidSelector: (selector) => `选择器 '${selector}' 无效。可用：顶层 goals | constraints | progress；bearinmind 下 contracts | acceptance | grants | runbook | decisions | risks；或任意标识符（如 ux.checklist）。`,
            invalidCategory: (category) => `目录名 '${category}' 无效。需匹配 ^[a-zA-Z][a-zA-Z0-9_-]*(\\.[a-zA-Z0-9_-]*)*$。`,
            invalidCategorySelector: (selector) => `选择器 '${selector}' 无效。需匹配 ^[a-zA-Z][a-zA-Z0-9_-]*(\\.[a-zA-Z0-9_-]*)*$。`,
            topLevelSelectorRequiresNoCategory: (category, selector) => `选择器 '${selector}' 是顶层保留分段（goals/constraints/progress），不能与 category='${category}' 一起用。`,
            bearInMindSelectorRequiresBearInMindCategory: (category, selector) => `选择器 '${selector}' 只能在 category='bearinmind' 下用（当前 category='${category}'）。`,
            taskDocSectionAlreadyExists: (relativePath) => `无法新增：${relativePath} 已存在。若确有把握要改写已有章节，请先用 recall_taskdoc 取得当前 content_hash，再使用 change_mind({"selector":"<selector>","content":"...","previous_content_hash":"crc32:..."})。`,
            taskDocSectionChangeMissing: (relativePath) => `无法修改：${relativePath} 不存在。若要新增章节，请使用 do_mind({ ... })。`,
            taskDocSectionMissing: (relativePath) => `未找到：${relativePath}。\n\n新增章节请使用 do_mind；已有章节追加小条目用 mind_more；改写已有章节时先用 recall_taskdoc 取得当前 content_hash，再用 change_mind 带上它：\n- do_mind({"category":"<category>","selector":"<selector>","content":"..."})\n- mind_more({"category":"<category>","selector":"<selector>","items":["..."]})\n- recall_taskdoc({"category":"<category>","selector":"<selector>"})\n- change_mind({"category":"<category>","selector":"<selector>","content":"...","previous_content_hash":"crc32:..."})`,
            taskDocSectionDeleteMissing: (relativePath) => `无法删除：${relativePath} 不存在。请先确认要删除的差遣牒章节。`,
            clearedCoursePrompt: (nextCourse) => (0, driver_messages_1.formatNewCourseStartPrompt)('zh', { nextCourse, source: 'clear_mind' }),
        };
    }
    return {
        invalidFormatDelete: 'Error: Invalid args. Use: delete_reminder({ reminder_id: string })',
        reminderDoesNotExist: (reminderId) => `Error: Reminder '${reminderId}' does not exist.`,
        reminderTargetChanged: 'Error: The reminder list changed, and this reminder is no longer visible. Refresh the reminders and retry with the current reminder_id.',
        invalidFormatAdd: 'Error: Invalid args. Use: add_reminder({ content: string, scope?: "dialog" | "task" | "agent" }) (omitting scope means task).',
        reminderContentEmpty: 'Error: Reminder content cannot be empty',
        invalidFormatUpdate: 'Error: Invalid args. Use: update_reminder({ reminder_id: string, content: string })',
        invalidFormatDoMind: 'Error: Invalid args. Use: do_mind({ selector: string, category?: string, content: string })',
        invalidFormatChangeMind: 'Error: Invalid args. Use: change_mind({ selector: string, category?: string, content: string, previous_content_hash: string })',
        tooManyArgsChangeMind: 'Error: Invalid args. Use: change_mind({ selector: string, category?: string, content: string, previous_content_hash: string })',
        taskDocPreviousContentHashRequired: 'Error: change_mind requires previous_content_hash. Call recall_taskdoc first to get the current section content_hash, merge the existing content, then replace the full section. If unsure, use mind_more for small append-only updates.',
        taskDocPreviousContentHashInvalid: 'Error: invalid previous_content_hash. It must be the crc32:<8 hex chars> content_hash returned by recall_taskdoc.',
        taskDocContentHashMismatch: (relativePath, currentContentHash) => `Error: content hash mismatch for \`${relativePath}\`; the section changed or your replacement was not based on the current content.\n` +
            `Current content_hash: ${currentContentHash}\n\n` +
            `Re-read/review the current section and retry only after fully merging existing content. If the new content would overwrite, delete, or materially replace existing content, one of these must be true:\n` +
            `- A human gave direct, targeted confirmation for this replacement; or\n` +
            `- A human-approved explicit SOP/acceptance standard authorizes the replacement, and you have considered the existing content under that standard.\n` +
            `Otherwise do not overwrite; prefer mind_more or ask the human to confirm.`,
        invalidFormatMindMore: 'Error: Invalid args. Use: mind_more({ items: string[], sep?: string, selector?: string, category?: string }) (selector defaults to progress).',
        invalidFormatNeverMind: 'Error: Invalid args. Use: never_mind({ selector: string, category?: string })',
        mindMoreItemsRequired: 'Error: items are required, and every item must be a non-empty string.\n' +
            'Example: mind_more({"items":["- Next: review verification results (details: <doc-path>#<section>)","- Blocker: API acceptance criteria pending"]})',
        invalidFormatRecallTaskdoc: 'Error: Invalid args. Use: recall_taskdoc({ selector: string, category?: string })',
        taskDocContentRequired: 'Error: Taskdoc content is required (content).\n' +
            'Copy/paste example:\n' +
            '```json\n' +
            '{\n' +
            '  "selector": "progress",\n' +
            '  "content": "- Key decisions: ...\\n- Next steps: ..."\n' +
            '}\n' +
            '```',
        noTaskDocPathConfigured: 'Error: No Taskdoc path configured for this dialog',
        pathMustBeWithinWorkspace: 'Error: Path must be within rtws (runtime workspace)',
        invalidTaskDocPath: (taskDocPath) => `Error: Invalid Taskdoc path '${taskDocPath}'. Expected a \`*.tsk/\` directory.`,
        selectorRequired: 'Error: selector is required.',
        invalidSelector: (selector) => `Error: Invalid selector '${selector}'. Use: top-level goals|constraints|progress; under bearinmind: contracts|acceptance|grants|runbook|decisions|risks; or any identifier (e.g. \`ux.checklist\`).`,
        invalidCategory: (category) => `Error: Invalid category '${category}'. Must match \`^[a-zA-Z][a-zA-Z0-9_-]*(\\.[a-zA-Z0-9_-]+)*$\`.`,
        invalidCategorySelector: (selector) => `Error: Invalid category selector '${selector}'. Must match \`^[a-zA-Z][a-zA-Z0-9_-]*(\\.[a-zA-Z0-9_-]+)*$\`.`,
        topLevelSelectorRequiresNoCategory: (category, selector) => `Error: Selector '${selector}' is reserved for top-level sections (goals/constraints/progress) and must not be used with category='${category}'.`,
        bearInMindSelectorRequiresBearInMindCategory: (category, selector) => `Error: Selector '${selector}' is only valid under category='bearinmind' (got category='${category}').`,
        taskDocSectionAlreadyExists: (relativePath) => `Cannot add: \`${relativePath}\` already exists. If you are sure you need to rewrite an existing section, call \`recall_taskdoc\` for the current content_hash first, then use \`change_mind({"selector":"<selector>","content":"...","previous_content_hash":"crc32:..."})\`.`,
        taskDocSectionChangeMissing: (relativePath) => `Cannot change: \`${relativePath}\` does not exist. To create a new section, use \`do_mind({ ... })\`.`,
        taskDocSectionMissing: (relativePath) => `Not found: \`${relativePath}\`.\n\nUse \`do_mind\` to create a section, \`mind_more\` for small append-only updates to existing sections, and \`recall_taskdoc\` then \`change_mind\` with the current content_hash to rewrite existing sections:\n- \`do_mind({\"category\":\"<category>\",\"selector\":\"<selector>\",\"content\":\"...\"})\`\n- \`mind_more({\"category\":\"<category>\",\"selector\":\"<selector>\",\"items\":[\"...\"]})\`\n- \`recall_taskdoc({\"category\":\"<category>\",\"selector\":\"<selector>\"})\`\n- \`change_mind({\"category\":\"<category>\",\"selector\":\"<selector>\",\"content\":\"...\",\"previous_content_hash\":\"crc32:...\"})\``,
        taskDocSectionDeleteMissing: (relativePath) => `Cannot delete: \`${relativePath}\` does not exist. Check the Taskdoc section target first.`,
        clearedCoursePrompt: (nextCourse) => (0, driver_messages_1.formatNewCourseStartPrompt)('en', { nextCourse, source: 'clear_mind' }),
    };
}
exports.deleteReminderTool = {
    type: 'func',
    name: 'delete_reminder',
    description: 'Delete a reminder by its reminder_id.',
    descriptionI18n: {
        en: 'Delete a reminder by its reminder_id.',
        zh: '按 reminder_id 删除提醒。',
    },
    parameters: {
        type: 'object',
        additionalProperties: false,
        required: ['reminder_id'],
        properties: {
            reminder_id: { type: 'string', description: 'Stable reminder id.' },
        },
    },
    argsValidation: 'dominds',
    async call(dlg, _caller, args) {
        const language = (0, work_language_1.getWorkLanguage)();
        const t = getCtrlMessages(language);
        const resolved = await resolveReminderTarget(dlg, args['reminder_id']);
        if (!resolved.ok) {
            const reminderId = resolved.reminderId.trim();
            if (reminderId === '')
                return (0, tool_1.toolFailure)(t.invalidFormatDelete);
            return (0, tool_1.toolFailure)(t.reminderDoesNotExist(reminderId));
        }
        const targetReminder = resolved.target.reminder;
        const deleteAltInstruction = getDeleteAltInstruction(targetReminder.meta);
        if (deleteAltInstruction !== undefined) {
            return (0, tool_1.toolFailure)(formatManualDeleteBlockedError(language, deleteAltInstruction));
        }
        const deleted = await deleteResolvedReminderTarget(dlg, resolved.target);
        if (!deleted)
            return (0, tool_1.toolFailure)(t.reminderTargetChanged);
        return (0, tool_result_messages_1.formatToolActionResult)(language, 'deleted');
    },
};
exports.addReminderTool = {
    type: 'func',
    name: 'add_reminder',
    description: 'Add a manually maintained reminder for current work. Scope defaults to task so the reminder survives continuing the same Taskdoc in another dialog; dialog is only for truly dialog-local notes; agent is visible to this agent across dialogs and should be reserved for urgent short-lived global cues. Do not manually record runtime-maintained environment state such as background process status or in-flight background asks.',
    descriptionI18n: {
        en: 'Add a manually maintained reminder for current work. Scope defaults to task so the reminder survives continuing the same Taskdoc in another dialog; dialog is only for truly dialog-local notes; agent is visible to this agent across dialogs and should be reserved for urgent short-lived global cues. Do not manually record runtime-maintained environment state such as background process status or in-flight background asks.',
        zh: '添加手工维护的手头工作提醒。scope 默认 task，以便同一差遣牒任务换新对话继续时仍可见；dialog 只用于真正对话局部的事项；agent 会在本智能体所有对话中可见，仅用于紧急、短期、全局刺眼提醒。不要手工记录后台进程状态、后台进行中诉请等 runtime 会自动维护的环境状态。',
    },
    parameters: {
        type: 'object',
        additionalProperties: false,
        required: ['content'],
        properties: {
            content: { type: 'string', description: 'Reminder content.' },
            scope: {
                type: 'string',
                enum: ['dialog', 'task', 'agent'],
                description: 'Reminder visibility scope. Defaults to task.',
            },
            render_mode: {
                type: 'string',
                enum: ['markdown', 'plain'],
                description: 'How the reminder should render in WebUI. Defaults to markdown.',
            },
        },
    },
    argsValidation: 'dominds',
    async call(dlg, _caller, args) {
        const language = (0, work_language_1.getWorkLanguage)();
        const t = getCtrlMessages(language);
        const contentValue = args['content'];
        const reminderContent = typeof contentValue === 'string' ? contentValue.trim() : '';
        if (!reminderContent)
            return (0, tool_1.toolFailure)(t.reminderContentEmpty);
        const scopeValue = args['scope'];
        const reminderScope = scopeValue === undefined
            ? 'task'
            : scopeValue === 'dialog' || scopeValue === 'task' || scopeValue === 'agent'
                ? scopeValue
                : null;
        if (reminderScope === null) {
            return (0, tool_1.toolFailure)(t.invalidFormatAdd);
        }
        const reminderRenderMode = parseReminderRenderMode(args['render_mode']);
        if (reminderRenderMode === null) {
            return (0, tool_1.toolFailure)(t.invalidFormatAdd);
        }
        const contextHealthLevel = getContinuationPackageContextHealthLevel(dlg.getLastContextHealth());
        const reminderMeta = contextHealthLevel === undefined
            ? undefined
            : buildContinuationPackageReminderMeta({
                createdBy: 'context_health',
                contextHealthLevel,
            });
        if (reminderScope === 'dialog') {
            dlg.addReminder(reminderContent, undefined, reminderMeta, undefined, {
                scope: 'dialog',
                renderMode: reminderRenderMode,
            });
            return (0, tool_result_messages_1.formatToolActionResult)(language, 'added');
        }
        const sharedTarget = reminderScope === 'task'
            ? { kind: 'task', agentId: dlg.agentId, taskDocPath: dlg.taskDocPath }
            : { kind: 'agent', agentId: dlg.agentId };
        await (0, shared_reminders_1.mutateSharedReminders)(sharedTarget, (reminders) => {
            const reminder = (0, tool_1.materializeReminder)({
                content: reminderContent,
                meta: reminderMeta,
                scope: reminderScope,
                renderMode: reminderRenderMode,
            });
            reminders.push(reminder);
        });
        dlg.touchReminders();
        return (0, tool_result_messages_1.formatToolActionResult)(language, 'added');
    },
};
exports.updateReminderTool = {
    type: 'func',
    name: 'update_reminder',
    description: 'Update a manually maintained reminder by its reminder_id. Do not manually record runtime-maintained environment state such as background process status or in-flight background asks.',
    descriptionI18n: {
        en: 'Update a manually maintained reminder by its reminder_id. Do not manually record runtime-maintained environment state such as background process status or in-flight background asks.',
        zh: '按 reminder_id 更新手工维护的提醒内容。不要手工记录后台进程状态、后台进行中诉请等 runtime 会自动维护的环境状态。',
    },
    parameters: {
        type: 'object',
        additionalProperties: false,
        required: ['reminder_id', 'content'],
        properties: {
            reminder_id: { type: 'string', description: 'Stable reminder id.' },
            content: { type: 'string', description: 'New reminder content.' },
            render_mode: {
                type: 'string',
                enum: ['markdown', 'plain'],
                description: 'Optional render mode override. Defaults to preserving current mode.',
            },
        },
    },
    argsValidation: 'dominds',
    async call(dlg, _caller, args) {
        const language = (0, work_language_1.getWorkLanguage)();
        const t = getCtrlMessages(language);
        const resolved = await resolveReminderTarget(dlg, args['reminder_id']);
        if (!resolved.ok) {
            const reminderId = resolved.reminderId.trim();
            if (reminderId === '')
                return (0, tool_1.toolFailure)(t.invalidFormatUpdate);
            return (0, tool_1.toolFailure)(t.reminderDoesNotExist(reminderId));
        }
        const reminder = resolved.target.reminder;
        // `reminder.meta` is persisted JSON. Runtime shape checks are unavoidable here because tools
        // may attach arbitrary metadata for reminder ownership/management.
        const meta = reminder?.meta;
        const updateAltInstruction = getUpdateAltInstruction(meta);
        if (updateAltInstruction !== undefined) {
            return (0, tool_1.toolFailure)(formatManualUpdateBlockedError(language, updateAltInstruction));
        }
        const managerTool = getManagerTool(meta);
        if (managerTool !== undefined) {
            return (0, tool_1.toolFailure)(language === 'zh'
                ? `错误：该提醒项由工具 ${managerTool} 管理，不能用 update_reminder 修改；请使用 ${managerTool} 更新。`
                : `Error: This reminder is managed by tool ${managerTool}. Do not edit it via update_reminder; use ${managerTool} instead.`);
        }
        const contentValue = args['content'];
        const reminderContent = typeof contentValue === 'string' ? contentValue.trim() : '';
        if (!reminderContent)
            return (0, tool_1.toolFailure)(t.reminderContentEmpty);
        const requestedRenderMode = args['render_mode'];
        const reminderRenderMode = requestedRenderMode === undefined
            ? reminder.renderMode
            : parseReminderRenderMode(requestedRenderMode);
        if (reminderRenderMode === null) {
            return (0, tool_1.toolFailure)(t.invalidFormatUpdate);
        }
        const contextHealthLevel = getContinuationPackageContextHealthLevel(dlg.getLastContextHealth());
        if (contextHealthLevel === undefined) {
            const stripResult = removeContinuationPackageReminderMeta(reminder?.meta);
            if (stripResult.changed) {
                const updated = await updateResolvedReminderTarget(dlg, resolved.target, reminderContent, stripResult.nextMeta, reminderRenderMode);
                if (!updated)
                    return (0, tool_1.toolFailure)(t.reminderTargetChanged);
                return (0, tool_result_messages_1.formatToolActionResult)(language, 'updated');
            }
            const updated = await updateResolvedReminderTarget(dlg, resolved.target, reminderContent, undefined, reminderRenderMode);
            if (!updated)
                return (0, tool_1.toolFailure)(t.reminderTargetChanged);
            return (0, tool_result_messages_1.formatToolActionResult)(language, 'updated');
        }
        const reminderMeta = buildContinuationPackageReminderMeta({
            existingMeta: reminder?.meta,
            createdBy: 'context_health',
            contextHealthLevel,
        });
        const updated = await updateResolvedReminderTarget(dlg, resolved.target, reminderContent, reminderMeta, reminderRenderMode);
        if (!updated)
            return (0, tool_1.toolFailure)(t.reminderTargetChanged);
        return (0, tool_result_messages_1.formatToolActionResult)(language, 'updated');
    },
};
exports.clearMindTool = {
    type: 'func',
    name: 'clear_mind',
    followupMode: 'deferred',
    description: 'Start a new dialog course, optionally carrying one extra continuation reminder.',
    descriptionI18n: {
        en: 'Start a new dialog course, optionally carrying one extra continuation reminder.',
        zh: '开启新一程对话；必要时可额外带一条接续提醒。',
    },
    parameters: {
        type: 'object',
        additionalProperties: false,
        properties: {
            reminder_content: {
                type: 'string',
                description: 'Optional extra continuation note not already captured in existing reminders.',
            },
        },
    },
    argsValidation: 'dominds',
    async call(dlg, _caller, args) {
        const language = (0, work_language_1.getWorkLanguage)();
        const t = getCtrlMessages(language);
        const reminderValue = args['reminder_content'];
        const reminderContent = typeof reminderValue === 'string' ? reminderValue.trim() : '';
        if (reminderContent) {
            const contextHealthLevel = getContinuationPackageContextHealthLevel(dlg.getLastContextHealth());
            const continuationMeta = buildContinuationPackageReminderMeta({
                createdBy: 'clear_mind',
                contextHealthLevel,
            });
            dlg.addReminder(reminderContent, undefined, continuationMeta);
        }
        await dlg.startNewCourse(t.clearedCoursePrompt(dlg.currentCourse + 1));
        // Context health snapshot is inherently tied to the previous prompt/context.
        // After clearing, invalidate it so the next generation can recompute without
        // stale remediation based on the old (large) context.
        dlg.setLastContextHealth({ kind: 'unavailable', reason: 'usage_unavailable' });
        return (0, tool_result_messages_1.formatToolActionResult)(language, 'mindCleared');
    },
};
exports.changeMindTool = {
    type: 'func',
    name: 'change_mind',
    description: 'Replace one existing shared Taskdoc section in the Main Dialog.',
    descriptionI18n: {
        en: 'Replace one existing shared Taskdoc section in the Main Dialog.',
        zh: '在主线对话中替换一段已存在的共享差遣牒章节。',
    },
    parameters: {
        type: 'object',
        additionalProperties: false,
        required: ['selector', 'content', 'previous_content_hash'],
        properties: {
            selector: {
                type: 'string',
                description: 'Target section selector. Top-level: goals|constraints|progress. Under category="bearinmind": contracts|acceptance|grants|runbook|decisions|risks. For other categories: any identifier.',
            },
            category: {
                type: 'string',
                description: 'Optional category directory within the Taskdoc package. When present, selector targets <category>/<selector>.md.',
            },
            content: { type: 'string', description: 'New section content.' },
            previous_content_hash: {
                type: 'string',
                description: 'Content hash of the current section being replaced. Call recall_taskdoc first and use the returned content_hash.',
            },
        },
    },
    argsValidation: 'dominds',
    async call(dlg, caller, args) {
        const language = (0, work_language_1.getWorkLanguage)();
        const t = getCtrlMessages(language);
        if (dlg.askerDialog !== undefined) {
            const maintainerId = dlg instanceof dialog_1.SideDialog ? dlg.mainDialog.agentId : dlg.agentId;
            if (language === 'zh') {
                return (0, tool_1.toolFailure)(`错误：\`change_mind\` 仅允许在主线对话中使用（支线对话中不可用）。\n` +
                    `请诉请差遣牒维护人 @${maintainerId} 在其对话中执行 \`do_mind\` / \`mind_more\` / \`change_mind\` / \`never_mind\`，并提供要新增的章节、要追加的条目、已合并好的“分段全文替换稿”或要删除的章节（禁止覆盖/抹掉他人条目）。`);
            }
            return (0, tool_1.toolFailure)(`Error: \`change_mind\` is only available in the Main Dialog (not in Side Dialogs).\n` +
                `Ask the Taskdoc maintainer @${maintainerId} to run \`do_mind\` / \`mind_more\` / \`change_mind\` / \`never_mind\` with the new section to create, entries to append, a fully merged full-section replacement draft, or the section to delete (do not overwrite/delete other contributors).`);
        }
        const selectorValue = args['selector'];
        const selector = typeof selectorValue === 'string' ? selectorValue.trim() : '';
        if (!selector)
            return (0, tool_1.toolFailure)(t.selectorRequired);
        const categoryValue = args['category'];
        if (categoryValue !== undefined && typeof categoryValue !== 'string') {
            return (0, tool_1.toolFailure)(t.invalidFormatChangeMind);
        }
        const category = typeof categoryValue === 'string' ? categoryValue.trim() : undefined;
        const contentValue = args['content'];
        const newTaskDocContent = typeof contentValue === 'string' ? contentValue.trim() : '';
        if (!newTaskDocContent)
            return (0, tool_1.toolFailure)(t.taskDocContentRequired);
        const previousContentHashValue = args['previous_content_hash'];
        const previousContentHash = typeof previousContentHashValue === 'string' ? previousContentHashValue.trim() : '';
        if (!previousContentHash)
            return (0, tool_1.toolFailure)(t.taskDocPreviousContentHashRequired);
        if (!/^crc32:[0-9a-f]{8}$/u.test(previousContentHash)) {
            return (0, tool_1.toolFailure)(t.taskDocPreviousContentHashInvalid);
        }
        // Taskdoc path is immutable for the dialog lifecycle.
        const taskDocPath = dlg.taskDocPath;
        if (!taskDocPath)
            return (0, tool_1.toolFailure)(t.noTaskDocPathConfigured);
        const workspaceRoot = (0, rtws_1.domindsRtwsRootAbs)();
        const fullPath = path.resolve(workspaceRoot, taskDocPath);
        if (!isPathWithinDirectory(fullPath, workspaceRoot)) {
            return (0, tool_1.toolFailure)(t.pathMustBeWithinWorkspace);
        }
        if (!(0, task_package_1.isTaskPackagePath)(taskDocPath))
            return (0, tool_1.toolFailure)(t.invalidTaskDocPath(taskDocPath));
        const parsed = (0, task_package_1.parseTaskPackageChangeMindTarget)({ selector, category });
        if (parsed.kind !== 'ok') {
            const e = parsed.error;
            switch (e.kind) {
                case 'selector_required':
                    return (0, tool_1.toolFailure)(t.selectorRequired);
                case 'invalid_category_name':
                    return (0, tool_1.toolFailure)(t.invalidCategory(e.category));
                case 'invalid_category_selector':
                    return (0, tool_1.toolFailure)(t.invalidCategorySelector(e.selector));
                case 'invalid_top_level_selector':
                    return (0, tool_1.toolFailure)(t.invalidSelector(e.selector));
                case 'invalid_bearinmind_selector':
                    return (0, tool_1.toolFailure)(t.invalidSelector(e.selector));
                case 'top_level_selector_requires_no_category':
                    return (0, tool_1.toolFailure)(t.topLevelSelectorRequiresNoCategory(e.category, e.selector));
                case 'bearinmind_selector_requires_bearinmind_category':
                    return (0, tool_1.toolFailure)(t.bearInMindSelectorRequiresBearInMindCategory(e.category, e.selector));
                default: {
                    const _exhaustive = e;
                    return (0, tool_1.toolFailure)(String(_exhaustive));
                }
            }
        }
        const result = await (0, task_package_1.updateTaskPackageByChangeMindTarget)({
            taskPackageDirFullPath: fullPath,
            target: parsed.target,
            content: newTaskDocContent,
            previousContentHash,
            updatedBy: caller.id,
        });
        switch (result.kind) {
            case 'updated':
                return (0, tool_result_messages_1.formatToolActionResult)(language, 'mindChanged');
            case 'missing':
                return (0, tool_1.toolFailure)(t.taskDocSectionChangeMissing((0, task_package_1.taskPackageRelativePathForChangeMindTarget)(parsed.target)));
            case 'content_hash_mismatch':
                return (0, tool_1.toolFailure)(t.taskDocContentHashMismatch((0, task_package_1.taskPackageRelativePathForChangeMindTarget)(parsed.target), result.currentContentHash));
            default: {
                const _exhaustive = result;
                return _exhaustive;
            }
        }
    },
};
exports.doMindTool = {
    type: 'func',
    name: 'do_mind',
    description: 'Create one new shared Taskdoc section in the Main Dialog.',
    descriptionI18n: {
        en: 'Create one new shared Taskdoc section in the Main Dialog.',
        zh: '在主线对话中新增一段共享差遣牒章节。',
    },
    parameters: {
        type: 'object',
        additionalProperties: false,
        required: ['selector', 'content'],
        properties: {
            selector: {
                type: 'string',
                description: 'Target section selector. Top-level: goals|constraints|progress. Under category="bearinmind": contracts|acceptance|grants|runbook|decisions|risks. For other categories: any identifier.',
            },
            category: {
                type: 'string',
                description: 'Optional category directory within the Taskdoc package. When present, selector targets <category>/<selector>.md.',
            },
            content: { type: 'string', description: 'New section content.' },
        },
    },
    argsValidation: 'dominds',
    async call(dlg, caller, args) {
        const language = (0, work_language_1.getWorkLanguage)();
        const t = getCtrlMessages(language);
        if (dlg.askerDialog !== undefined) {
            const maintainerId = dlg instanceof dialog_1.SideDialog ? dlg.mainDialog.agentId : dlg.agentId;
            if (language === 'zh') {
                return (0, tool_1.toolFailure)(`错误：\`do_mind\` 仅允许在主线对话中使用（支线对话中不可用）。\n` +
                    `请诉请差遣牒维护人 @${maintainerId} 在其对话中执行 \`do_mind\` / \`mind_more\` / \`change_mind\` / \`never_mind\`，并提供要新增的章节、要追加的条目、已合并好的“分段全文替换稿”或要删除的章节（禁止覆盖/抹掉他人条目）。`);
            }
            return (0, tool_1.toolFailure)(`Error: \`do_mind\` is only available in the Main Dialog (not in Side Dialogs).\n` +
                `Ask the Taskdoc maintainer @${maintainerId} to run \`do_mind\` / \`mind_more\` / \`change_mind\` / \`never_mind\` with the new section to create, entries to append, a fully merged full-section replacement draft, or the section to delete (do not overwrite/delete other contributors).`);
        }
        const selectorValue = args['selector'];
        const selector = typeof selectorValue === 'string' ? selectorValue.trim() : '';
        if (!selector)
            return (0, tool_1.toolFailure)(t.selectorRequired);
        const categoryValue = args['category'];
        if (categoryValue !== undefined && typeof categoryValue !== 'string') {
            return (0, tool_1.toolFailure)(t.invalidFormatDoMind);
        }
        const category = typeof categoryValue === 'string' ? categoryValue.trim() : undefined;
        const contentValue = args['content'];
        const newTaskDocContent = typeof contentValue === 'string' ? contentValue.trim() : '';
        if (!newTaskDocContent)
            return (0, tool_1.toolFailure)(t.taskDocContentRequired);
        // Taskdoc path is immutable for the dialog lifecycle.
        const taskDocPath = dlg.taskDocPath;
        if (!taskDocPath)
            return (0, tool_1.toolFailure)(t.noTaskDocPathConfigured);
        const workspaceRoot = (0, rtws_1.domindsRtwsRootAbs)();
        const fullPath = path.resolve(workspaceRoot, taskDocPath);
        if (!isPathWithinDirectory(fullPath, workspaceRoot)) {
            return (0, tool_1.toolFailure)(t.pathMustBeWithinWorkspace);
        }
        if (!(0, task_package_1.isTaskPackagePath)(taskDocPath))
            return (0, tool_1.toolFailure)(t.invalidTaskDocPath(taskDocPath));
        const parsed = (0, task_package_1.parseTaskPackageChangeMindTarget)({ selector, category });
        if (parsed.kind !== 'ok') {
            const e = parsed.error;
            switch (e.kind) {
                case 'selector_required':
                    return (0, tool_1.toolFailure)(t.selectorRequired);
                case 'invalid_category_name':
                    return (0, tool_1.toolFailure)(t.invalidCategory(e.category));
                case 'invalid_category_selector':
                    return (0, tool_1.toolFailure)(t.invalidCategorySelector(e.selector));
                case 'invalid_top_level_selector':
                    return (0, tool_1.toolFailure)(t.invalidSelector(e.selector));
                case 'invalid_bearinmind_selector':
                    return (0, tool_1.toolFailure)(t.invalidSelector(e.selector));
                case 'top_level_selector_requires_no_category':
                    return (0, tool_1.toolFailure)(t.topLevelSelectorRequiresNoCategory(e.category, e.selector));
                case 'bearinmind_selector_requires_bearinmind_category':
                    return (0, tool_1.toolFailure)(t.bearInMindSelectorRequiresBearInMindCategory(e.category, e.selector));
                default: {
                    const _exhaustive = e;
                    return (0, tool_1.toolFailure)(String(_exhaustive));
                }
            }
        }
        const result = await (0, task_package_1.createTaskPackageByChangeMindTarget)({
            taskPackageDirFullPath: fullPath,
            target: parsed.target,
            content: newTaskDocContent,
            updatedBy: caller.id,
        });
        switch (result.kind) {
            case 'created':
                return (0, tool_result_messages_1.formatToolActionResult)(language, 'mindChanged');
            case 'exists':
                return (0, tool_1.toolFailure)(t.taskDocSectionAlreadyExists((0, task_package_1.taskPackageRelativePathForChangeMindTarget)(parsed.target)));
            default: {
                const _exhaustive = result;
                return _exhaustive;
            }
        }
    },
};
exports.neverMindTool = {
    type: 'func',
    name: 'never_mind',
    description: 'Delete one shared Taskdoc section file in the Main Dialog.',
    descriptionI18n: {
        en: 'Delete one shared Taskdoc section file in the Main Dialog.',
        zh: '在主线对话中删除一段共享差遣牒章节文件。',
    },
    parameters: {
        type: 'object',
        additionalProperties: false,
        required: ['selector'],
        properties: {
            selector: {
                type: 'string',
                description: 'Target section selector. Top-level: goals|constraints|progress. Under category="bearinmind": contracts|acceptance|grants|runbook|decisions|risks. For other categories: any identifier.',
            },
            category: {
                type: 'string',
                description: 'Optional category directory within the Taskdoc package. When present, selector targets <category>/<selector>.md.',
            },
        },
    },
    argsValidation: 'dominds',
    async call(dlg, _caller, args) {
        const language = (0, work_language_1.getWorkLanguage)();
        const t = getCtrlMessages(language);
        if (dlg.askerDialog !== undefined) {
            const maintainerId = dlg instanceof dialog_1.SideDialog ? dlg.mainDialog.agentId : dlg.agentId;
            if (language === 'zh') {
                return (0, tool_1.toolFailure)(`错误：\`never_mind\` 仅允许在主线对话中使用（支线对话中不可用）。\n` +
                    `请诉请差遣牒维护人 @${maintainerId} 在其对话中执行 \`do_mind\` / \`mind_more\` / \`change_mind\` / \`never_mind\`，并提供要新增的章节、要追加的条目、已合并好的“分段全文替换稿”或要删除的章节（禁止覆盖/抹掉他人条目）。`);
            }
            return (0, tool_1.toolFailure)(`Error: \`never_mind\` is only available in the Main Dialog (not in Side Dialogs).\n` +
                `Ask the Taskdoc maintainer @${maintainerId} to run \`do_mind\` / \`mind_more\` / \`change_mind\` / \`never_mind\` with the new section to create, entries to append, a fully merged full-section replacement draft, or the section to delete (do not overwrite/delete other contributors).`);
        }
        const selectorValue = args['selector'];
        const selector = typeof selectorValue === 'string' ? selectorValue.trim() : '';
        if (!selector)
            return (0, tool_1.toolFailure)(t.selectorRequired);
        const categoryValue = args['category'];
        if (categoryValue !== undefined && typeof categoryValue !== 'string') {
            return (0, tool_1.toolFailure)(t.invalidFormatNeverMind);
        }
        const category = typeof categoryValue === 'string' ? categoryValue.trim() : undefined;
        // Taskdoc path is immutable for the dialog lifecycle.
        const taskDocPath = dlg.taskDocPath;
        if (!taskDocPath)
            return (0, tool_1.toolFailure)(t.noTaskDocPathConfigured);
        const workspaceRoot = (0, rtws_1.domindsRtwsRootAbs)();
        const fullPath = path.resolve(workspaceRoot, taskDocPath);
        if (!isPathWithinDirectory(fullPath, workspaceRoot)) {
            return (0, tool_1.toolFailure)(t.pathMustBeWithinWorkspace);
        }
        if (!(0, task_package_1.isTaskPackagePath)(taskDocPath))
            return (0, tool_1.toolFailure)(t.invalidTaskDocPath(taskDocPath));
        const parsed = (0, task_package_1.parseTaskPackageChangeMindTarget)({ selector, category });
        if (parsed.kind !== 'ok') {
            const e = parsed.error;
            switch (e.kind) {
                case 'selector_required':
                    return (0, tool_1.toolFailure)(t.selectorRequired);
                case 'invalid_category_name':
                    return (0, tool_1.toolFailure)(t.invalidCategory(e.category));
                case 'invalid_category_selector':
                    return (0, tool_1.toolFailure)(t.invalidCategorySelector(e.selector));
                case 'invalid_top_level_selector':
                    return (0, tool_1.toolFailure)(t.invalidSelector(e.selector));
                case 'invalid_bearinmind_selector':
                    return (0, tool_1.toolFailure)(t.invalidSelector(e.selector));
                case 'top_level_selector_requires_no_category':
                    return (0, tool_1.toolFailure)(t.topLevelSelectorRequiresNoCategory(e.category, e.selector));
                case 'bearinmind_selector_requires_bearinmind_category':
                    return (0, tool_1.toolFailure)(t.bearInMindSelectorRequiresBearInMindCategory(e.category, e.selector));
                default: {
                    const _exhaustive = e;
                    return (0, tool_1.toolFailure)(String(_exhaustive));
                }
            }
        }
        const result = await (0, task_package_1.deleteTaskPackageByChangeMindTarget)({
            taskPackageDirFullPath: fullPath,
            target: parsed.target,
        });
        switch (result.kind) {
            case 'deleted':
                return (0, tool_result_messages_1.formatToolActionResult)(language, 'deleted');
            case 'missing': {
                return (0, tool_1.toolFailure)(t.taskDocSectionDeleteMissing((0, task_package_1.taskPackageRelativePathForChangeMindTarget)(parsed.target)));
            }
            default: {
                const _exhaustive = result;
                return _exhaustive;
            }
        }
    },
};
exports.mindMoreTool = {
    type: 'func',
    name: 'mind_more',
    description: 'Append entries to one shared Taskdoc section in the Main Dialog.',
    descriptionI18n: {
        en: 'Append entries to one shared Taskdoc section in the Main Dialog.',
        zh: '在主线对话中向一段共享差遣牒章节追加条目。',
    },
    parameters: {
        type: 'object',
        additionalProperties: false,
        required: ['items'],
        properties: {
            items: {
                type: 'array',
                description: 'Entries to append. Each entry must be a non-empty string.',
                items: { type: 'string' },
            },
            sep: {
                type: 'string',
                description: 'Separator inserted between existing content and new entries, and between entries. Defaults to "\\n".',
            },
            selector: {
                type: 'string',
                description: 'Target section selector. Defaults to progress. Top-level: goals|constraints|progress. Under category="bearinmind": contracts|acceptance|grants|runbook|decisions|risks. For other categories: any identifier.',
            },
            category: {
                type: 'string',
                description: 'Optional category directory within the Taskdoc package. When present, selector targets <category>/<selector>.md.',
            },
        },
    },
    argsValidation: 'dominds',
    async call(dlg, caller, args) {
        const language = (0, work_language_1.getWorkLanguage)();
        const t = getCtrlMessages(language);
        if (dlg.askerDialog !== undefined) {
            const maintainerId = dlg instanceof dialog_1.SideDialog ? dlg.mainDialog.agentId : dlg.agentId;
            if (language === 'zh') {
                return (0, tool_1.toolFailure)(`错误：\`mind_more\` 仅允许在主线对话中使用（支线对话中不可用）。\n` +
                    `请诉请差遣牒维护人 @${maintainerId} 在其对话中执行 \`do_mind\` / \`mind_more\` / \`change_mind\` / \`never_mind\`，并提供要新增的章节、要追加的条目、已合并好的“分段全文替换稿”或要删除的章节（禁止覆盖/抹掉他人条目）。`);
            }
            return (0, tool_1.toolFailure)(`Error: \`mind_more\` is only available in the Main Dialog (not in Side Dialogs).\n` +
                `Ask the Taskdoc maintainer @${maintainerId} to run \`do_mind\` / \`mind_more\` / \`change_mind\` / \`never_mind\` with the new section to create, entries to append, a merged full-section replacement draft, or the section to delete (do not overwrite/delete other contributors).`);
        }
        const rawItems = args['items'];
        if (!Array.isArray(rawItems) || rawItems.length === 0) {
            return (0, tool_1.toolFailure)(t.mindMoreItemsRequired);
        }
        const items = [];
        for (const item of rawItems) {
            if (typeof item !== 'string')
                return (0, tool_1.toolFailure)(t.mindMoreItemsRequired);
            const normalized = item.trim();
            if (!normalized)
                return (0, tool_1.toolFailure)(t.mindMoreItemsRequired);
            items.push(normalized);
        }
        const sepValue = args['sep'];
        const sep = sepValue === undefined ? '\n' : typeof sepValue === 'string' ? sepValue : null;
        if (sep === null)
            return (0, tool_1.toolFailure)(t.invalidFormatMindMore);
        const selectorValue = args['selector'];
        const selector = selectorValue === undefined
            ? 'progress'
            : typeof selectorValue === 'string'
                ? selectorValue.trim()
                : '';
        if (!selector)
            return (0, tool_1.toolFailure)(t.selectorRequired);
        const categoryValue = args['category'];
        if (categoryValue !== undefined && typeof categoryValue !== 'string') {
            return (0, tool_1.toolFailure)(t.invalidFormatMindMore);
        }
        const category = typeof categoryValue === 'string' ? categoryValue.trim() : undefined;
        // Taskdoc path is immutable for the dialog lifecycle.
        const taskDocPath = dlg.taskDocPath;
        if (!taskDocPath)
            return (0, tool_1.toolFailure)(t.noTaskDocPathConfigured);
        const workspaceRoot = (0, rtws_1.domindsRtwsRootAbs)();
        const fullPath = path.resolve(workspaceRoot, taskDocPath);
        if (!isPathWithinDirectory(fullPath, workspaceRoot)) {
            return (0, tool_1.toolFailure)(t.pathMustBeWithinWorkspace);
        }
        if (!(0, task_package_1.isTaskPackagePath)(taskDocPath))
            return (0, tool_1.toolFailure)(t.invalidTaskDocPath(taskDocPath));
        const parsed = (0, task_package_1.parseTaskPackageChangeMindTarget)({ selector, category });
        if (parsed.kind !== 'ok') {
            const e = parsed.error;
            switch (e.kind) {
                case 'selector_required':
                    return (0, tool_1.toolFailure)(t.selectorRequired);
                case 'invalid_category_name':
                    return (0, tool_1.toolFailure)(t.invalidCategory(e.category));
                case 'invalid_category_selector':
                    return (0, tool_1.toolFailure)(t.invalidCategorySelector(e.selector));
                case 'invalid_top_level_selector':
                    return (0, tool_1.toolFailure)(t.invalidSelector(e.selector));
                case 'invalid_bearinmind_selector':
                    return (0, tool_1.toolFailure)(t.invalidSelector(e.selector));
                case 'top_level_selector_requires_no_category':
                    return (0, tool_1.toolFailure)(t.topLevelSelectorRequiresNoCategory(e.category, e.selector));
                case 'bearinmind_selector_requires_bearinmind_category':
                    return (0, tool_1.toolFailure)(t.bearInMindSelectorRequiresBearInMindCategory(e.category, e.selector));
                default: {
                    const _exhaustive = e;
                    return (0, tool_1.toolFailure)(String(_exhaustive));
                }
            }
        }
        await (0, task_package_1.appendTaskPackageByChangeMindTarget)({
            taskPackageDirFullPath: fullPath,
            target: parsed.target,
            content: items.join(sep),
            sep,
            updatedBy: caller.id,
        });
        return (0, tool_result_messages_1.formatToolActionResult)(language, 'mindChanged');
    },
};
exports.recallTaskdocTool = {
    type: 'func',
    name: 'recall_taskdoc',
    description: 'Read one Taskdoc section and return its content_hash.',
    descriptionI18n: {
        en: 'Read one Taskdoc section and return its content_hash.',
        zh: '读取一段差遣牒章节并返回 content_hash。',
    },
    parameters: {
        type: 'object',
        additionalProperties: false,
        required: ['selector'],
        properties: {
            category: {
                type: 'string',
                description: 'Optional category directory within the Taskdoc. Omit for top-level goals|constraints|progress.',
            },
            selector: {
                type: 'string',
                description: 'Section selector. Top-level: goals|constraints|progress. With category: selector within that category.',
            },
        },
    },
    argsValidation: 'dominds',
    async call(dlg, _caller, args) {
        const language = (0, work_language_1.getWorkLanguage)();
        const t = getCtrlMessages(language);
        const categoryValue = args['category'];
        if (categoryValue !== undefined && typeof categoryValue !== 'string') {
            return (0, tool_1.toolFailure)(t.invalidFormatRecallTaskdoc);
        }
        const category = typeof categoryValue === 'string' ? categoryValue.trim() : undefined;
        const selectorValue = args['selector'];
        const selector = typeof selectorValue === 'string' ? selectorValue.trim() : '';
        if (selector === '')
            return (0, tool_1.toolFailure)(t.selectorRequired);
        // Taskdoc path is immutable for the dialog lifecycle.
        const taskDocPath = dlg.taskDocPath;
        if (!taskDocPath)
            return (0, tool_1.toolFailure)(t.noTaskDocPathConfigured);
        const workspaceRoot = (0, rtws_1.domindsRtwsRootAbs)();
        const fullPath = path.resolve(workspaceRoot, taskDocPath);
        if (!isPathWithinDirectory(fullPath, workspaceRoot)) {
            return (0, tool_1.toolFailure)(t.pathMustBeWithinWorkspace);
        }
        if (!(0, task_package_1.isTaskPackagePath)(taskDocPath))
            return (0, tool_1.toolFailure)(t.invalidTaskDocPath(taskDocPath));
        const parsed = (0, task_package_1.parseTaskPackageChangeMindTarget)({ selector, category });
        if (parsed.kind !== 'ok') {
            const e = parsed.error;
            switch (e.kind) {
                case 'selector_required':
                    return (0, tool_1.toolFailure)(t.selectorRequired);
                case 'invalid_category_name':
                    return (0, tool_1.toolFailure)(t.invalidCategory(e.category));
                case 'invalid_category_selector':
                    return (0, tool_1.toolFailure)(t.invalidCategorySelector(e.selector));
                case 'invalid_top_level_selector':
                    return (0, tool_1.toolFailure)(t.invalidSelector(e.selector));
                case 'invalid_bearinmind_selector':
                    return (0, tool_1.toolFailure)(t.invalidSelector(e.selector));
                case 'top_level_selector_requires_no_category':
                    return (0, tool_1.toolFailure)(t.topLevelSelectorRequiresNoCategory(e.category, e.selector));
                case 'bearinmind_selector_requires_bearinmind_category':
                    return (0, tool_1.toolFailure)(t.bearInMindSelectorRequiresBearInMindCategory(e.category, e.selector));
                default: {
                    const _exhaustive = e;
                    return (0, tool_1.toolFailure)(String(_exhaustive));
                }
            }
        }
        const target = parsed.target;
        const relPath = (0, task_package_1.taskPackageRelativePathForChangeMindTarget)(target);
        const sectionPath = path.resolve(fullPath, relPath);
        if (!isPathWithinDirectory(sectionPath, fullPath)) {
            return (0, tool_1.toolFailure)(t.pathMustBeWithinWorkspace);
        }
        try {
            const st = await fs.promises.stat(sectionPath);
            if (!st.isFile()) {
                return (0, tool_1.toolFailure)(t.taskDocSectionMissing(relPath));
            }
        }
        catch (err) {
            if (typeof err === 'object' &&
                err !== null &&
                'code' in err &&
                err.code === 'ENOENT') {
                return (0, tool_1.toolFailure)(t.taskDocSectionMissing(relPath));
            }
            throw err;
        }
        const current = await (0, task_package_1.readTaskPackageByChangeMindTarget)({
            taskPackageDirFullPath: fullPath,
            target,
        });
        if (current.kind === 'missing') {
            return (0, tool_1.toolFailure)(t.taskDocSectionMissing(relPath));
        }
        const content = current.content;
        const bytes = Buffer.byteLength(content, 'utf8');
        const maxSize = 100 * 1024;
        const clipped = bytes > maxSize ? content.slice(0, maxSize) : content;
        const note = bytes > maxSize
            ? language === 'zh'
                ? `\n\n⚠️ 已截断：内容过大（${bytes} bytes），仅回显前 ${maxSize} bytes。`
                : `\n\n⚠️ Truncated: content is too large (${bytes} bytes); showing first ${maxSize} bytes.`
            : '';
        const closingSeparatorPrefix = clipped.endsWith('\n') ? '' : '\n';
        return (0, tool_1.toolSuccess)(`**recall_taskdoc:** \`${relPath}\`\ncontent_hash: \`${current.contentHash}\`\n\n---\n${clipped}${closingSeparatorPrefix}---${note}`);
    },
};
