"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.readSkillTool = exports.movePersonalSkillTool = exports.dropPersonalSkillTool = exports.importPersonalSkillFromFileTool = exports.replacePersonalSkillTool = exports.addPersonalSkillTool = void 0;
/**
 * Module: tools/skills
 *
 * Personal skill management tools scoped to `.minds/skills/individual/<member-id>`.
 * Skills capture reusable prompt guidance (procedures, checklists, triggers, boundaries);
 * workspace-coupled facts and indexes belong in memory/env instead.
 */
const fs_1 = __importDefault(require("fs"));
const path_1 = __importDefault(require("path"));
const yaml_1 = __importDefault(require("yaml"));
const access_control_1 = require("../access-control");
const frontmatter_1 = require("../markdown/frontmatter");
const rtws_1 = require("../rtws");
const tool_result_messages_1 = require("../runtime/tool-result-messages");
const work_language_1 = require("../runtime/work-language");
const load_1 = require("../skills/load");
const team_1 = require("../team");
const tool_1 = require("../tool");
async function listVisibleMcpServerIds(caller, taskDocPath) {
    const dynamicToolsetNames = await team_1.Team.listDynamicToolsetNamesForMember({
        member: caller,
        taskDocPath,
    });
    const declared = await team_1.Team.readMcpDeclaredToolsets();
    const declaredMcpToolsetNames = declared.kind === 'loaded' ? declared.declaredServerIds : undefined;
    const invalidMcpToolsetNames = declared.kind === 'loaded' ? declared.invalidServerIds : undefined;
    return new Set(caller
        .listResolvedToolsetNames({
        onMissing: 'silent',
        dynamicToolsetNames,
        declaredMcpToolsetNames,
        invalidMcpToolsetNames,
    })
        .filter((toolsetName) => declaredMcpToolsetNames?.has(toolsetName)));
}
function localizedError(language, zh, en) {
    return language === 'zh' ? `错误：${zh}` : `Error: ${en}`;
}
function parseSkillVariant(raw) {
    if (raw === undefined)
        return 'neutral';
    if (raw === 'cn' || raw === 'en' || raw === 'neutral')
        return raw;
    throw new Error('Invalid variant (expected "cn", "en", or "neutral").');
}
function validatePathSegment(params) {
    const value = params.rawValue.trim();
    if (value === '') {
        return {
            kind: 'invalid_path',
            message: localizedError(params.language, `需要提供 ${params.label}。`, `${params.label} is required.`),
        };
    }
    if (path_1.default.isAbsolute(value) || value.includes('/') || value.includes('\\')) {
        return {
            kind: 'invalid_path',
            message: localizedError(params.language, `${params.label} 必须是单段相对标识，不能包含路径分隔符。`, `${params.label} must be one relative path segment and must not contain path separators.`),
        };
    }
    if (value === '.' || value === '..' || value.includes('..')) {
        return {
            kind: 'invalid_path',
            message: localizedError(params.language, `${params.label} 不允许包含 \`..\`。`, `${params.label} must not contain \`..\`.`),
        };
    }
    if (!/^[A-Za-z0-9_-]+$/.test(value)) {
        return {
            kind: 'invalid_path',
            message: localizedError(params.language, `${params.label} 只能包含字母、数字、下划线和连字符。`, `${params.label} may only contain letters, numbers, underscores, and hyphens.`),
        };
    }
    return { kind: 'ok', value };
}
function validateSkillId(language, rawSkillId) {
    const validated = validatePathSegment({ language, label: 'skill_id', rawValue: rawSkillId });
    if (validated.kind === 'invalid_path')
        return validated;
    const skillId = validated.value;
    const rel = path_1.default.join('.minds', 'skills', 'individual', '<member>', skillId);
    return { kind: 'ok', skillId, rel, abs: rel };
}
function getPersonalSkillPackagePath(params) {
    const validated = validateSkillId(params.language, params.skillId);
    if (validated.kind === 'invalid_path')
        return validated;
    const memberId = validatePathSegment({
        language: params.language,
        label: 'member_id',
        rawValue: params.caller.id,
    });
    if (memberId.kind === 'invalid_path')
        return memberId;
    const rel = path_1.default.join('.minds', 'skills', 'individual', memberId.value, validated.skillId);
    const abs = path_1.default.resolve(process.cwd(), rel);
    return { kind: 'ok', skillId: validated.skillId, rel, abs };
}
function skillFileName(variant) {
    if (variant === 'cn')
        return 'SKILL.cn.md';
    if (variant === 'en')
        return 'SKILL.en.md';
    return 'SKILL.md';
}
function isPathInsideRtws(absPath) {
    const cwd = (0, rtws_1.domindsRtwsRootAbs)();
    const relative = path_1.default.relative(cwd, absPath);
    return relative === '' || (!relative.startsWith('..') && !path_1.default.isAbsolute(relative));
}
function readPersonalSkillPackageState(abs) {
    let stat;
    try {
        stat = fs_1.default.lstatSync(abs);
    }
    catch (error) {
        if (typeof error === 'object' &&
            error !== null &&
            'code' in error &&
            error.code === 'ENOENT') {
            return { kind: 'missing' };
        }
        throw error;
    }
    if (stat.isSymbolicLink())
        return { kind: 'symlink' };
    if (stat.isDirectory())
        return { kind: 'directory' };
    return { kind: 'not_directory' };
}
function pathExistsNoFollow(abs) {
    try {
        fs_1.default.lstatSync(abs);
        return true;
    }
    catch (error) {
        if (typeof error === 'object' &&
            error !== null &&
            'code' in error &&
            error.code === 'ENOENT') {
            return false;
        }
        throw error;
    }
}
function lstatOrNull(abs) {
    try {
        return fs_1.default.lstatSync(abs);
    }
    catch (error) {
        if (typeof error === 'object' &&
            error !== null &&
            'code' in error &&
            error.code === 'ENOENT') {
            return null;
        }
        throw error;
    }
}
function rejectPersonalSkillNonDirectory(language, skillId) {
    return (0, tool_1.toolFailure)(language === 'zh'
        ? `错误：个人 skill '${skillId}' 的路径已存在但不是目录包。`
        : `Error: Personal skill '${skillId}' path already exists but is not a directory package.`);
}
function copyDirectoryRecursiveSync(sourceAbs, targetAbs, visitedRealDirs = new Set()) {
    const sourceRealAbs = fs_1.default.realpathSync(sourceAbs);
    if (visitedRealDirs.has(sourceRealAbs)) {
        throw new Error(`Symlink cycle detected while materializing linked skill package: ${sourceAbs}`);
    }
    const childVisitedRealDirs = new Set(visitedRealDirs);
    childVisitedRealDirs.add(sourceRealAbs);
    fs_1.default.mkdirSync(targetAbs, { recursive: true });
    for (const entry of fs_1.default.readdirSync(sourceAbs, { withFileTypes: true })) {
        const sourceEntryAbs = path_1.default.join(sourceAbs, entry.name);
        const targetEntryAbs = path_1.default.join(targetAbs, entry.name);
        if (entry.isDirectory()) {
            copyDirectoryRecursiveSync(sourceEntryAbs, targetEntryAbs, childVisitedRealDirs);
            continue;
        }
        if (entry.isSymbolicLink()) {
            const targetStat = fs_1.default.statSync(sourceEntryAbs);
            if (targetStat.isDirectory()) {
                copyDirectoryRecursiveSync(sourceEntryAbs, targetEntryAbs, childVisitedRealDirs);
                continue;
            }
            if (targetStat.isFile()) {
                fs_1.default.copyFileSync(sourceEntryAbs, targetEntryAbs);
                continue;
            }
            throw new Error(`Unsupported symlink target inside linked skill package: ${sourceEntryAbs}`);
        }
        if (entry.isFile()) {
            fs_1.default.copyFileSync(sourceEntryAbs, targetEntryAbs);
            continue;
        }
        const sourceStat = fs_1.default.statSync(sourceEntryAbs);
        if (sourceStat.isFile()) {
            fs_1.default.copyFileSync(sourceEntryAbs, targetEntryAbs);
            continue;
        }
        if (sourceStat.isDirectory()) {
            copyDirectoryRecursiveSync(sourceEntryAbs, targetEntryAbs, childVisitedRealDirs);
            continue;
        }
        throw new Error(`Unsupported entry inside linked skill package: ${sourceEntryAbs}`);
    }
}
function materializeLinkedPersonalSkillPackage(params) {
    const tempAbs = `${params.packageAbs}.cow-${process.pid}-${Date.now()}`;
    let originalSymlinkTarget;
    try {
        originalSymlinkTarget = fs_1.default.readlinkSync(params.packageAbs);
        const targetStat = fs_1.default.statSync(params.packageAbs);
        if (!targetStat.isDirectory()) {
            return {
                kind: 'failure',
                output: (0, tool_1.toolFailure)(params.language === 'zh'
                    ? `错误：个人 skill '${params.skillId}' 的链接目标不是目录包。`
                    : `Error: Personal skill '${params.skillId}' link target is not a directory package.`),
            };
        }
        copyDirectoryRecursiveSync(params.packageAbs, tempAbs);
        fs_1.default.unlinkSync(params.packageAbs);
        fs_1.default.renameSync(tempAbs, params.packageAbs);
        return { kind: 'ok' };
    }
    catch (error) {
        if (fs_1.default.existsSync(tempAbs)) {
            fs_1.default.rmSync(tempAbs, { recursive: true, force: true });
        }
        let restoreFailure;
        if (originalSymlinkTarget !== undefined && !pathExistsNoFollow(params.packageAbs)) {
            try {
                fs_1.default.symlinkSync(originalSymlinkTarget, params.packageAbs, 'dir');
            }
            catch (restoreError) {
                restoreFailure =
                    restoreError instanceof Error ? restoreError.message : String(restoreError);
            }
        }
        const baseMsg = error instanceof Error ? error.message : String(error);
        const msg = restoreFailure === undefined
            ? baseMsg
            : `${baseMsg}; failed to restore original symlink: ${restoreFailure}`;
        return {
            kind: 'failure',
            output: (0, tool_1.toolFailure)(params.language === 'zh'
                ? `错误：个人 skill '${params.skillId}' copy-on-write 失败：${msg}`
                : `Error: Personal skill '${params.skillId}' copy-on-write failed: ${msg}`),
        };
    }
}
function buildSkillMarkdown(params) {
    const frontmatter = {
        name: params.name,
        description: params.description,
    };
    if (params.allowedTools !== undefined) {
        frontmatter['allowed-tools'] = [...params.allowedTools];
    }
    if (params.userInvocable !== undefined) {
        frontmatter['user-invocable'] = params.userInvocable;
    }
    if (params.disableModelInvocation !== undefined) {
        frontmatter['disable-model-invocation'] = params.disableModelInvocation;
    }
    const frontmatterText = yaml_1.default.stringify(frontmatter).trimEnd();
    return `---\n${frontmatterText}\n---\n\n${params.body.trimEnd()}\n`;
}
function validateSkillMarkdownContent(language, content) {
    try {
        const { body, frontmatter } = (0, frontmatter_1.parseMarkdownFrontmatter)(content, 'personal skill');
        const nameValue = frontmatter['name'];
        if (typeof nameValue !== 'string' || nameValue.trim() === '') {
            return {
                kind: 'invalid',
                message: localizedError(language, 'SKILL frontmatter 必须包含非空 name。', "SKILL frontmatter must include a non-empty 'name'."),
            };
        }
        const descriptionValue = frontmatter['description'];
        if (typeof descriptionValue !== 'string' || descriptionValue.trim() === '') {
            return {
                kind: 'invalid',
                message: localizedError(language, 'SKILL frontmatter 必须包含非空 description。', "SKILL frontmatter must include a non-empty 'description'."),
            };
        }
        const allowedToolsValue = frontmatter['allowed-tools'];
        if (allowedToolsValue !== undefined) {
            if (typeof allowedToolsValue === 'string') {
                const values = allowedToolsValue
                    .split(',')
                    .map((item) => item.trim())
                    .filter((item) => item !== '');
                if (values.length === 0) {
                    return {
                        kind: 'invalid',
                        message: localizedError(language, 'allowed-tools 字符串不能为空。', 'allowed-tools string must not be empty.'),
                    };
                }
            }
            else if (!Array.isArray(allowedToolsValue) ||
                !allowedToolsValue.every((item) => typeof item === 'string' && item.trim() !== '')) {
                return {
                    kind: 'invalid',
                    message: localizedError(language, 'allowed-tools 必须是非空字符串或非空字符串数组。', 'allowed-tools must be a non-empty string or an array of non-empty strings.'),
                };
            }
        }
        const userInvocableValue = frontmatter['user-invocable'];
        if (userInvocableValue !== undefined && typeof userInvocableValue !== 'boolean') {
            return {
                kind: 'invalid',
                message: localizedError(language, 'user-invocable 必须是 boolean。', 'user-invocable must be boolean.'),
            };
        }
        const disableModelInvocationValue = frontmatter['disable-model-invocation'];
        if (disableModelInvocationValue !== undefined &&
            typeof disableModelInvocationValue !== 'boolean') {
            return {
                kind: 'invalid',
                message: localizedError(language, 'disable-model-invocation 必须是 boolean。', 'disable-model-invocation must be boolean.'),
            };
        }
        for (const key of Object.keys(frontmatter)) {
            if (key !== 'name' &&
                key !== 'description' &&
                key !== 'allowed-tools' &&
                key !== 'user-invocable' &&
                key !== 'disable-model-invocation') {
                return {
                    kind: 'invalid',
                    message: localizedError(language, `SKILL frontmatter 包含不支持的字段 '${key}'。`, `SKILL frontmatter contains unsupported key '${key}'.`),
                };
            }
        }
        if (body.trim() === '') {
            return {
                kind: 'invalid',
                message: localizedError(language, 'SKILL 正文不能为空。', 'SKILL markdown body must not be empty.'),
            };
        }
        return { kind: 'ok', content };
    }
    catch (error) {
        const msg = error instanceof Error ? error.message : String(error);
        return { kind: 'invalid', message: localizedError(language, msg, msg) };
    }
}
function parseOptionalStringArg(args, key) {
    const value = args[key];
    if (value === undefined)
        return undefined;
    if (typeof value !== 'string')
        throw new Error(`Invalid ${key} (expected string).`);
    return value;
}
function parseOptionalBooleanArg(args, key) {
    const value = args[key];
    if (value === undefined)
        return undefined;
    if (typeof value !== 'boolean')
        throw new Error(`Invalid ${key} (expected boolean).`);
    return value;
}
function parseAllowedToolsArg(args) {
    const value = args['allowed_tools'];
    if (value === undefined)
        return undefined;
    if (!Array.isArray(value))
        throw new Error('Invalid allowed_tools (expected string[]).');
    const out = [];
    for (let index = 0; index < value.length; index += 1) {
        const item = value[index];
        if (typeof item !== 'string' || item.trim() === '') {
            throw new Error(`Invalid allowed_tools[${String(index)}] (expected non-empty string).`);
        }
        out.push(item.trim());
    }
    if (out.length === 0)
        throw new Error('Invalid allowed_tools (must not be empty).');
    return out;
}
function parseSkillContentArgs(language, args, mode) {
    try {
        const contentValue = parseOptionalStringArg(args, 'content');
        if (contentValue !== undefined) {
            if (contentValue.trim() === '') {
                return {
                    kind: 'invalid',
                    message: localizedError(language, 'content 不能为空。', 'content must not be empty.'),
                };
            }
            const normalizedContent = contentValue.endsWith('\n') ? contentValue : `${contentValue}\n`;
            const validatedContent = validateSkillMarkdownContent(language, normalizedContent);
            if (validatedContent.kind === 'invalid')
                return validatedContent;
            return {
                kind: 'ok',
                content: validatedContent.content,
            };
        }
        const name = parseOptionalStringArg(args, 'name')?.trim();
        const description = parseOptionalStringArg(args, 'description')?.trim();
        const body = parseOptionalStringArg(args, 'body')?.trimEnd();
        if (!name || !description || !body) {
            const zh = mode === 'add'
                ? '需要提供 content，或同时提供 name / description / body 来创建 skill。'
                : '需要提供 content，或同时提供 name / description / body 来替换 skill。';
            const en = mode === 'add'
                ? 'Provide content, or provide name / description / body together to create the skill.'
                : 'Provide content, or provide name / description / body together to replace the skill.';
            return { kind: 'invalid', message: localizedError(language, zh, en) };
        }
        const allowedTools = parseAllowedToolsArg(args);
        const userInvocable = parseOptionalBooleanArg(args, 'user_invocable');
        const disableModelInvocation = parseOptionalBooleanArg(args, 'disable_model_invocation');
        const generated = buildSkillMarkdown({
            name,
            description,
            body,
            allowedTools,
            userInvocable,
            disableModelInvocation,
        });
        return validateSkillMarkdownContent(language, generated);
    }
    catch (error) {
        const msg = error instanceof Error ? error.message : String(error);
        return { kind: 'invalid', message: localizedError(language, msg, msg) };
    }
}
function stripMarkdownFrontmatterForImport(raw) {
    const normalized = (0, frontmatter_1.normalizeMarkdownText)(raw);
    if (!normalized.startsWith('---\n'))
        return normalized;
    const endWithBody = normalized.indexOf('\n---\n', 4);
    const endAtEof = normalized.endsWith('\n---') ? normalized.length - '\n---'.length : -1;
    const end = endWithBody >= 0 ? endWithBody : endAtEof;
    if (end < 0)
        return normalized;
    return endWithBody >= 0
        ? normalized.slice(end + '\n---\n'.length)
        : normalized.slice(end + '\n---'.length);
}
function parseImportSkillContentArgs(language, sourceContent, args) {
    try {
        const replaceFrontmatterValue = args['replace_frontmatter'];
        if (replaceFrontmatterValue !== undefined && typeof replaceFrontmatterValue !== 'boolean') {
            return {
                kind: 'invalid',
                message: localizedError(language, 'replace_frontmatter 必须是 boolean。', 'replace_frontmatter must be boolean.'),
            };
        }
        if (replaceFrontmatterValue !== true) {
            const normalizedContent = sourceContent.endsWith('\n') ? sourceContent : `${sourceContent}\n`;
            const validatedContent = validateSkillMarkdownContent(language, normalizedContent);
            if (validatedContent.kind === 'invalid')
                return validatedContent;
            return { kind: 'ok', content: validatedContent.content };
        }
        const name = parseOptionalStringArg(args, 'name')?.trim();
        const description = parseOptionalStringArg(args, 'description')?.trim();
        if (!name || !description) {
            return {
                kind: 'invalid',
                message: localizedError(language, 'replace_frontmatter=true 时必须提供 name 和 description。', 'When replace_frontmatter=true, provide name and description.'),
            };
        }
        const body = stripMarkdownFrontmatterForImport(sourceContent).trimEnd();
        if (!body) {
            return {
                kind: 'invalid',
                message: localizedError(language, '源文件正文不能为空。', 'Source file markdown body must not be empty.'),
            };
        }
        const allowedTools = parseAllowedToolsArg(args);
        const userInvocable = parseOptionalBooleanArg(args, 'user_invocable');
        const disableModelInvocation = parseOptionalBooleanArg(args, 'disable_model_invocation');
        const generated = buildSkillMarkdown({
            name,
            description,
            body,
            allowedTools,
            userInvocable,
            disableModelInvocation,
        });
        return validateSkillMarkdownContent(language, generated);
    }
    catch (error) {
        const msg = error instanceof Error ? error.message : String(error);
        return { kind: 'invalid', message: localizedError(language, msg, msg) };
    }
}
function skillContentProperties() {
    return {
        skill_id: {
            type: 'string',
            description: 'One-segment personal skill identifier under your own skill store.',
        },
        variant: {
            type: 'string',
            enum: ['cn', 'en', 'neutral'],
            description: 'Language variant to write. Defaults to neutral (SKILL.md).',
        },
        content: {
            type: 'string',
            description: 'Full SKILL markdown content, including YAML frontmatter. If omitted, provide name/description/body.',
        },
        name: { type: 'string', description: 'Skill frontmatter name.' },
        description: { type: 'string', description: 'Skill frontmatter description.' },
        body: { type: 'string', description: 'Skill markdown body.' },
        allowed_tools: {
            type: 'array',
            items: { type: 'string' },
            description: 'Advisory upstream allowed-tools metadata; does not grant Dominds tools.',
        },
        user_invocable: {
            type: 'boolean',
            description: 'Compatibility metadata for public skill formats.',
        },
        disable_model_invocation: {
            type: 'boolean',
            description: 'Compatibility metadata for public skill formats.',
        },
    };
}
function parseSkillTarget(language, caller, args) {
    const skillIdValue = args['skill_id'];
    const skillId = typeof skillIdValue === 'string' ? skillIdValue : '';
    return getPersonalSkillPackagePath({ language, caller, skillId });
}
function parsePersonalSkillWriteMode(raw) {
    if (raw === undefined)
        return 'add';
    if (raw === 'add' || raw === 'replace')
        return raw;
    throw new Error('Invalid import_mode (expected "add" or "replace").');
}
function preparePersonalSkillPackageForWrite(params) {
    const packageState = readPersonalSkillPackageState(params.target.abs);
    if (packageState.kind === 'symlink') {
        const materialized = materializeLinkedPersonalSkillPackage({
            language: params.language,
            skillId: params.target.skillId,
            packageAbs: params.target.abs,
        });
        if (materialized.kind === 'failure')
            return materialized;
    }
    if (packageState.kind === 'not_directory') {
        return {
            kind: 'failure',
            output: rejectPersonalSkillNonDirectory(params.language, params.target.skillId),
        };
    }
    return { kind: 'ok' };
}
function writePersonalSkillVariant(params) {
    const prepared = preparePersonalSkillPackageForWrite({
        language: params.language,
        target: params.target,
    });
    if (prepared.kind === 'failure')
        return prepared.output;
    const fileName = skillFileName(params.variant);
    const fullPath = path_1.default.join(params.target.abs, fileName);
    const existingFileStat = lstatOrNull(fullPath);
    const exists = existingFileStat !== null;
    if (params.mode === 'add' && exists) {
        return (0, tool_1.toolFailure)(params.language === 'zh'
            ? `错误：个人 skill '${params.target.skillId}' 的 ${fileName} 已存在。请使用 replace_personal_skill 更新它。`
            : `Error: Personal skill '${params.target.skillId}' ${fileName} already exists. Use replace_personal_skill to update it.`);
    }
    if (params.mode === 'replace' && !exists) {
        return (0, tool_1.toolFailure)(params.language === 'zh'
            ? `错误：个人 skill '${params.target.skillId}' 的 ${fileName} 不存在。请使用 add_personal_skill 创建它。`
            : `Error: Personal skill '${params.target.skillId}' ${fileName} does not exist. Use add_personal_skill to create it.`);
    }
    if (existingFileStat && !existingFileStat.isFile() && !existingFileStat.isSymbolicLink()) {
        return (0, tool_1.toolFailure)(params.language === 'zh'
            ? `错误：个人 skill '${params.target.skillId}' 的 ${fileName} 已存在但不是文件。`
            : `Error: Personal skill '${params.target.skillId}' ${fileName} already exists but is not a file.`);
    }
    fs_1.default.mkdirSync(params.target.abs, { recursive: true });
    if (existingFileStat?.isSymbolicLink()) {
        fs_1.default.unlinkSync(fullPath);
    }
    fs_1.default.writeFileSync(fullPath, params.content, 'utf8');
    return (0, tool_result_messages_1.formatToolActionResult)(params.language, params.mode === 'add' ? 'added' : 'updated');
}
exports.addPersonalSkillTool = {
    type: 'func',
    name: 'add_personal_skill',
    description: 'Create a new personal skill package for the current agent.',
    descriptionI18n: {
        en: 'Create a new personal skill package for the current agent.',
        zh: '为当前智能体创建新的个人 skill 包。',
    },
    parameters: {
        type: 'object',
        additionalProperties: false,
        required: ['skill_id'],
        properties: skillContentProperties(),
    },
    argsValidation: 'dominds',
    async call(_dlg, caller, args) {
        const language = (0, work_language_1.getWorkLanguage)();
        const target = parseSkillTarget(language, caller, args);
        if (target.kind === 'invalid_path')
            return (0, tool_1.toolFailure)(target.message);
        let variant;
        try {
            variant = parseSkillVariant(args['variant']);
        }
        catch (error) {
            const msg = error instanceof Error ? error.message : String(error);
            return (0, tool_1.toolFailure)(localizedError(language, msg, msg));
        }
        const content = parseSkillContentArgs(language, args, 'add');
        if (content.kind === 'invalid')
            return (0, tool_1.toolFailure)(content.message);
        return writePersonalSkillVariant({
            language,
            target,
            variant,
            content: content.content,
            mode: 'add',
        });
    },
};
exports.replacePersonalSkillTool = {
    type: 'func',
    name: 'replace_personal_skill',
    description: 'Replace an existing personal skill variant for the current agent.',
    descriptionI18n: {
        en: 'Replace an existing personal skill variant for the current agent.',
        zh: '替换当前智能体已有个人 skill 的指定语言变体。',
    },
    parameters: {
        type: 'object',
        additionalProperties: false,
        required: ['skill_id'],
        properties: skillContentProperties(),
    },
    argsValidation: 'dominds',
    async call(_dlg, caller, args) {
        const language = (0, work_language_1.getWorkLanguage)();
        const target = parseSkillTarget(language, caller, args);
        if (target.kind === 'invalid_path')
            return (0, tool_1.toolFailure)(target.message);
        let variant;
        try {
            variant = parseSkillVariant(args['variant']);
        }
        catch (error) {
            const msg = error instanceof Error ? error.message : String(error);
            return (0, tool_1.toolFailure)(localizedError(language, msg, msg));
        }
        const content = parseSkillContentArgs(language, args, 'replace');
        if (content.kind === 'invalid')
            return (0, tool_1.toolFailure)(content.message);
        return writePersonalSkillVariant({
            language,
            target,
            variant,
            content: content.content,
            mode: 'replace',
        });
    },
};
exports.importPersonalSkillFromFileTool = {
    type: 'func',
    name: 'import_personal_skill_from_file',
    description: 'Import a personal skill variant from an rtws markdown file.',
    descriptionI18n: {
        en: 'Import a personal skill variant from an rtws markdown file.',
        zh: '从 rtws markdown 文件导入当前智能体的个人 skill 变体。',
    },
    parameters: {
        type: 'object',
        additionalProperties: false,
        required: ['skill_id', 'source_path'],
        properties: {
            skill_id: {
                type: 'string',
                description: 'One-segment personal skill identifier under your own skill store.',
            },
            source_path: {
                type: 'string',
                description: 'rtws-relative markdown file path to import. The file is read directly, so long skill bodies do not need to be copied into tool arguments.',
            },
            import_mode: {
                type: 'string',
                enum: ['add', 'replace'],
                description: 'Defaults to add. Use replace to overwrite an existing variant.',
            },
            variant: {
                type: 'string',
                enum: ['cn', 'en', 'neutral'],
                description: 'Language variant to write. Defaults to neutral (SKILL.md).',
            },
            replace_frontmatter: {
                type: 'boolean',
                description: 'When true, strip source frontmatter and rebuild it from name/description and optional metadata args.',
            },
            name: { type: 'string', description: 'Required when replace_frontmatter=true.' },
            description: {
                type: 'string',
                description: 'Required when replace_frontmatter=true.',
            },
            allowed_tools: {
                type: 'array',
                items: { type: 'string' },
                description: 'Advisory upstream allowed-tools metadata; does not grant Dominds tools.',
            },
            user_invocable: {
                type: 'boolean',
                description: 'Compatibility metadata for public skill formats.',
            },
            disable_model_invocation: {
                type: 'boolean',
                description: 'Compatibility metadata for public skill formats.',
            },
        },
    },
    argsValidation: 'dominds',
    async call(_dlg, caller, args) {
        const language = (0, work_language_1.getWorkLanguage)();
        const target = parseSkillTarget(language, caller, args);
        if (target.kind === 'invalid_path')
            return (0, tool_1.toolFailure)(target.message);
        let variant;
        let importMode;
        try {
            variant = parseSkillVariant(args['variant']);
            importMode = parsePersonalSkillWriteMode(args['import_mode']);
        }
        catch (error) {
            const msg = error instanceof Error ? error.message : String(error);
            return (0, tool_1.toolFailure)(localizedError(language, msg, msg));
        }
        const sourcePathValue = args['source_path'];
        const sourceRel = typeof sourcePathValue === 'string' ? sourcePathValue.trim() : '';
        if (!sourceRel) {
            return (0, tool_1.toolFailure)(localizedError(language, 'source_path 不能为空。', 'source_path is required.'));
        }
        const sourceAbs = path_1.default.resolve(process.cwd(), sourceRel);
        if (!isPathInsideRtws(sourceAbs)) {
            return (0, tool_1.toolFailure)(localizedError(language, 'source_path 必须位于 rtws（运行时工作区）内。', 'source_path must be within rtws (runtime workspace).'));
        }
        if (!(0, access_control_1.hasReadAccess)(caller, sourceRel)) {
            return (0, tool_1.toolFailure)((0, access_control_1.getAccessDeniedMessage)('read', sourceRel, language));
        }
        let sourceStat;
        let sourceContent;
        try {
            sourceStat = fs_1.default.statSync(sourceAbs);
            if (!sourceStat.isFile()) {
                return (0, tool_1.toolFailure)(localizedError(language, 'source_path 必须是文件。', 'source_path must be a file.'));
            }
            sourceContent = fs_1.default.readFileSync(sourceAbs, 'utf8');
        }
        catch (error) {
            const msg = error instanceof Error ? error.message : String(error);
            return (0, tool_1.toolFailure)(localizedError(language, msg, msg));
        }
        const content = parseImportSkillContentArgs(language, sourceContent, args);
        if (content.kind === 'invalid')
            return (0, tool_1.toolFailure)(content.message);
        return writePersonalSkillVariant({
            language,
            target,
            variant,
            content: content.content,
            mode: importMode,
        });
    },
};
exports.dropPersonalSkillTool = {
    type: 'func',
    name: 'drop_personal_skill',
    description: 'Remove one personal skill package or one variant from the current agent.',
    descriptionI18n: {
        en: 'Remove one personal skill package or one variant from the current agent.',
        zh: '删除当前智能体的一个个人 skill 包，或删除其中一个语言变体。',
    },
    parameters: {
        type: 'object',
        additionalProperties: false,
        required: ['skill_id'],
        properties: {
            skill_id: {
                type: 'string',
                description: 'One-segment personal skill identifier under your own skill store.',
            },
            variant: {
                type: 'string',
                enum: ['cn', 'en', 'neutral'],
                description: 'When provided, remove only this variant. Otherwise remove the package.',
            },
        },
    },
    argsValidation: 'dominds',
    async call(_dlg, caller, args) {
        const language = (0, work_language_1.getWorkLanguage)();
        const target = parseSkillTarget(language, caller, args);
        if (target.kind === 'invalid_path')
            return (0, tool_1.toolFailure)(target.message);
        const packageState = readPersonalSkillPackageState(target.abs);
        if (packageState.kind === 'not_directory') {
            return rejectPersonalSkillNonDirectory(language, target.skillId);
        }
        if (packageState.kind === 'symlink' && args['variant'] === undefined) {
            fs_1.default.unlinkSync(target.abs);
            return (0, tool_result_messages_1.formatToolActionResult)(language, 'deleted');
        }
        if (args['variant'] !== undefined) {
            let variant;
            try {
                variant = parseSkillVariant(args['variant']);
            }
            catch (error) {
                const msg = error instanceof Error ? error.message : String(error);
                return (0, tool_1.toolFailure)(localizedError(language, msg, msg));
            }
            const fullPath = path_1.default.join(target.abs, skillFileName(variant));
            const fileStat = lstatOrNull(fullPath);
            if (fileStat === null) {
                return (0, tool_1.toolFailure)(language === 'zh'
                    ? `错误：个人 skill '${target.skillId}' 的 ${skillFileName(variant)} 不存在。`
                    : `Error: Personal skill '${target.skillId}' ${skillFileName(variant)} does not exist.`);
            }
            if (!fileStat.isFile() && !fileStat.isSymbolicLink()) {
                return (0, tool_1.toolFailure)(language === 'zh'
                    ? `错误：个人 skill '${target.skillId}' 的 ${skillFileName(variant)} 已存在但不是文件。`
                    : `Error: Personal skill '${target.skillId}' ${skillFileName(variant)} already exists but is not a file.`);
            }
            fs_1.default.unlinkSync(fullPath);
            return (0, tool_result_messages_1.formatToolActionResult)(language, 'deleted');
        }
        if (packageState.kind === 'missing') {
            return (0, tool_1.toolFailure)(language === 'zh'
                ? `错误：个人 skill '${target.skillId}' 不存在。`
                : `Error: Personal skill '${target.skillId}' does not exist.`);
        }
        fs_1.default.rmSync(target.abs, { recursive: true, force: false });
        return (0, tool_result_messages_1.formatToolActionResult)(language, 'deleted');
    },
};
exports.movePersonalSkillTool = {
    type: 'func',
    name: 'move_personal_skill',
    description: 'Move one personal skill package to a new skill_id for the current agent.',
    descriptionI18n: {
        en: 'Move one personal skill package to a new skill_id for the current agent.',
        zh: '把当前智能体的一个个人 skill 包移动到新的 skill_id。',
    },
    parameters: {
        type: 'object',
        additionalProperties: false,
        required: ['from_skill_id', 'to_skill_id'],
        properties: {
            from_skill_id: {
                type: 'string',
                description: 'Existing one-segment personal skill identifier under your own skill store.',
            },
            to_skill_id: {
                type: 'string',
                description: 'New one-segment personal skill identifier under your own skill store.',
            },
        },
    },
    argsValidation: 'dominds',
    async call(_dlg, caller, args) {
        const language = (0, work_language_1.getWorkLanguage)();
        const fromSkillIdValue = args['from_skill_id'];
        const toSkillIdValue = args['to_skill_id'];
        const fromSkillId = typeof fromSkillIdValue === 'string' ? fromSkillIdValue : '';
        const toSkillId = typeof toSkillIdValue === 'string' ? toSkillIdValue : '';
        const fromTarget = getPersonalSkillPackagePath({ language, caller, skillId: fromSkillId });
        if (fromTarget.kind === 'invalid_path')
            return (0, tool_1.toolFailure)(fromTarget.message);
        const toTarget = getPersonalSkillPackagePath({ language, caller, skillId: toSkillId });
        if (toTarget.kind === 'invalid_path')
            return (0, tool_1.toolFailure)(toTarget.message);
        if (fromTarget.skillId === toTarget.skillId) {
            return (0, tool_1.toolFailure)(language === 'zh'
                ? `错误：from_skill_id 和 to_skill_id 不能相同。`
                : `Error: from_skill_id and to_skill_id must be different.`);
        }
        const fromPackageState = readPersonalSkillPackageState(fromTarget.abs);
        if (fromPackageState.kind === 'missing') {
            return (0, tool_1.toolFailure)(language === 'zh'
                ? `错误：个人 skill '${fromTarget.skillId}' 不存在。`
                : `Error: Personal skill '${fromTarget.skillId}' does not exist.`);
        }
        if (fromPackageState.kind === 'not_directory') {
            return rejectPersonalSkillNonDirectory(language, fromTarget.skillId);
        }
        const toPackageState = readPersonalSkillPackageState(toTarget.abs);
        if (toPackageState.kind !== 'missing') {
            return (0, tool_1.toolFailure)(language === 'zh'
                ? `错误：目标个人 skill '${toTarget.skillId}' 已存在。`
                : `Error: Target personal skill '${toTarget.skillId}' already exists.`);
        }
        try {
            fs_1.default.renameSync(fromTarget.abs, toTarget.abs);
        }
        catch (error) {
            const msg = error instanceof Error ? error.message : String(error);
            return (0, tool_1.toolFailure)(language === 'zh'
                ? `错误：移动个人 skill '${fromTarget.skillId}' 到 '${toTarget.skillId}' 失败：${msg}`
                : `Error: Failed to move personal skill '${fromTarget.skillId}' to '${toTarget.skillId}': ${msg}`);
        }
        return (0, tool_1.toolSuccess)(language === 'zh'
            ? [
                '已移动',
                `from_skill_id: ${fromTarget.skillId}`,
                `to_skill_id: ${toTarget.skillId}`,
                '提示：skill_id 已改变；SKILL frontmatter name 不会自动修改。',
            ].join('\n')
            : [
                'Moved',
                `from_skill_id: ${fromTarget.skillId}`,
                `to_skill_id: ${toTarget.skillId}`,
                'Note: skill_id changed; SKILL frontmatter name was not modified automatically.',
            ].join('\n'));
    },
};
exports.readSkillTool = {
    type: 'func',
    name: 'read_skill',
    description: 'Read the full body of one available skill by skill_id. Use this after inspecting the Skills index in the system prompt.',
    descriptionI18n: {
        en: 'Read the full body of one available skill by skill_id. Use this after inspecting the Skills index in the system prompt.',
        zh: '按 skill_id 读取一个可用 skill 的完整正文。先查看系统提示中的 Skills 索引，再按需调用。',
    },
    parameters: {
        type: 'object',
        additionalProperties: false,
        required: ['skill_id'],
        properties: {
            skill_id: {
                type: 'string',
                description: 'One skill ID from the Skills index.',
            },
        },
    },
    argsValidation: 'dominds',
    async call(_dlg, caller, args) {
        const language = typeof _dlg?.getLastUserLanguageCode === 'function'
            ? _dlg.getLastUserLanguageCode()
            : (0, work_language_1.getWorkLanguage)();
        const rawSkillId = args['skill_id'];
        const skillId = typeof rawSkillId === 'string' ? rawSkillId.trim() : '';
        if (skillId === '') {
            return (0, tool_1.toolFailure)(language === 'zh' ? '错误：需要提供 skill_id。' : 'Error: skill_id is required.');
        }
        const skill = await (0, load_1.readWorkspaceSkill)({
            rtwsRootAbs: (0, rtws_1.domindsRtwsRootAbs)(),
            memberId: caller.id,
            language,
            skillId,
            visibleMcpServerIds: await listVisibleMcpServerIds(caller, _dlg.taskDocPath),
        });
        if (!skill) {
            return (0, tool_1.toolFailure)(language === 'zh'
                ? `错误：未找到可用 skill '${skillId}'。`
                : `Error: available skill '${skillId}' was not found.`);
        }
        const idLabel = language === 'zh' ? 'ID' : 'ID';
        const scopeLabel = language === 'zh' ? '作用域' : 'Scope';
        const sourceLabel = language === 'zh' ? '来源' : 'Source';
        const descriptionLabel = language === 'zh' ? '说明' : 'Description';
        const allowedToolsLabel = language === 'zh' ? '上游 allowed-tools' : 'Upstream allowed-tools';
        const allowedTools = skill.declaredAllowedTools && skill.declaredAllowedTools.length > 0
            ? `\n- ${allowedToolsLabel}: ${skill.declaredAllowedTools.join(', ')}`
            : '';
        return (0, tool_1.toolSuccess)([
            `# ${skill.title}`,
            '',
            `- ${idLabel}: ${skill.id}`,
            `- ${scopeLabel}: ${skill.scope}`,
            `- ${sourceLabel}: ${skill.sourcePathRel}`,
            `- ${descriptionLabel}: ${skill.description}${allowedTools}`,
            '',
            skill.body.trim(),
        ].join('\n'));
    },
};
