import { buildSkillMarkdown, createAuditEvent, ensurePermissions, ensureRealExecutionAllowed, failure, isInsideAllowedRoots, isRecord, isSafeSkillDirectoryName, joinPath, relativeSkillPath, stringArrayValue, stringValue, } from "../_shared/skillCore.js";
export const skillGenerateDescriptor = {
    toolId: "skill.generate",
    capability: "generate-skill",
    defaultDryRun: true,
    permissionsRequired: ["skill:write", "filesystem:write"],
    defaultFiles: [{ path: "SKILL.md", kind: "instruction" }],
    maxRequestedFiles: 32,
};
const supportedFileKinds = new Set(["instruction", "script", "template", "example", "metadata", "reference", "asset"]);
function normalizeFile(value) {
    if (!isRecord(value))
        return undefined;
    const filePath = stringValue(value.path);
    const kind = stringValue(value.kind) ?? "instruction";
    if (filePath === undefined || !relativeSkillPath(filePath) || !supportedFileKinds.has(kind))
        return undefined;
    return {
        path: filePath,
        kind: kind,
        purpose: stringValue(value.purpose),
        content: typeof value.content === "string" ? value.content : undefined,
    };
}
function normalizeTarget(target, context) {
    if (!isRecord(target))
        return failure("skill.generate", "MISSING_SKILL_NAME", "skill.generate requires target.skillName", "input", context);
    const skillName = stringValue(target.skillName);
    if (skillName === undefined)
        return failure("skill.generate", "MISSING_SKILL_NAME", "skill.generate requires target.skillName", "input", context);
    if (!isSafeSkillDirectoryName(skillName)) {
        return failure("skill.generate", "INVALID_SKILL_NAME", "skill.generate target.skillName must be a safe lowercase skill directory name", "input", context, skillName);
    }
    const purpose = stringValue(target.purpose);
    if (purpose === undefined)
        return failure("skill.generate", "MISSING_PURPOSE", "skill.generate requires target.purpose", "input", context, skillName);
    const destinationRoot = stringValue(target.destinationRoot);
    if (destinationRoot === undefined)
        return failure("skill.generate", "MISSING_DESTINATION_ROOT", "skill.generate requires target.destinationRoot", "input", context, skillName);
    if (!isInsideAllowedRoots(destinationRoot, context?.allowedRoots)) {
        return failure("skill.generate", "SKILL_ROOT_OUTSIDE_SCOPE", "skill.generate destinationRoot is outside allowed roots", "scope", context, skillName);
    }
    const rawFiles = Array.isArray(target.files) ? target.files : skillGenerateDescriptor.defaultFiles;
    if (rawFiles.length > skillGenerateDescriptor.maxRequestedFiles) {
        return failure("skill.generate", "TOO_MANY_FILES", "skill.generate requested too many files", "resource", context, skillName);
    }
    const files = rawFiles.map(normalizeFile);
    if (files.some((file) => file === undefined)) {
        return failure("skill.generate", "INVALID_REQUESTED_FILE", "skill.generate files must use safe relative paths and supported kinds", "input", context, skillName);
    }
    const normalizedFiles = files;
    if (!normalizedFiles.some((file) => file.path === "SKILL.md")) {
        normalizedFiles.unshift({ path: "SKILL.md", kind: "instruction", purpose: "entrypoint" });
    }
    return {
        skillName,
        purpose,
        destinationRoot,
        description: stringValue(target.description),
        files: normalizedFiles,
        tags: stringArrayValue(target.tags) ?? [],
    };
}
function contentForFile(target, file) {
    if (file.content !== undefined)
        return file.content;
    if (file.path === "SKILL.md") {
        return buildSkillMarkdown(target.skillName, target.description ?? target.purpose, target.purpose, target.tags);
    }
    return `# ${file.path}\n\n${file.purpose ?? "Generated skill support file."}\n`;
}
export async function executeSkillGenerate(request = {}) {
    const context = request.context;
    const target = normalizeTarget(request.target, context);
    if (!("skillName" in target))
        return target;
    const skillDirectory = joinPath(target.destinationRoot, target.skillName);
    const wouldWriteFiles = target.files.map((file) => joinPath(skillDirectory, file.path));
    const realExecutionFailure = ensureRealExecutionAllowed("skill.generate", context, target.skillName);
    if (realExecutionFailure !== undefined)
        return realExecutionFailure;
    const permissionFailure = ensurePermissions("skill.generate", skillGenerateDescriptor.permissionsRequired, context, target.skillName);
    if (permissionFailure !== undefined)
        return permissionFailure;
    if (context?.dryRun !== false) {
        return {
            ok: true,
            toolId: "skill.generate",
            output: {
                kind: "agentCore.basicTool.skill.generate.output",
                target,
                runtimeEntry: { port: "BaseToolExecutorPort.filesystem.writeText", runtimeOwnsFilesystem: true },
                generationEnvelope: { scaffoldVersion: "skill-scaffold-v1", skillDirectory, fileCount: target.files.length, wouldWriteFiles },
                dryRun: true,
                executionBlocked: true,
                permissionsRequired: skillGenerateDescriptor.permissionsRequired,
                unsafeSideEffects: true,
            },
            audit: [createAuditEvent("skill.generate", "agentCore.basicTool.skill.generate.dryRun", context, target.skillName)],
            events: ["basicTool.skill.generate.dryRun"],
        };
    }
    if (request.provider?.writeText === undefined) {
        return failure("skill.generate", "PROVIDER_UNAVAILABLE", "skill.generate requires runtime filesystem.writeText for real execution", "provider", context, target.skillName);
    }
    try {
        const writtenFiles = [];
        for (const file of target.files) {
            const targetPath = joinPath(skillDirectory, file.path);
            await request.provider.writeText({ path: targetPath, content: contentForFile(target, file), encoding: "utf8" });
            writtenFiles.push(targetPath);
        }
        return {
            ok: true,
            toolId: "skill.generate",
            output: {
                kind: "agentCore.basicTool.skill.generate.output",
                target,
                runtimeEntry: { port: "BaseToolExecutorPort.filesystem.writeText", runtimeOwnsFilesystem: true },
                generationEnvelope: { scaffoldVersion: "skill-scaffold-v1", skillDirectory, fileCount: target.files.length, wouldWriteFiles, writtenFiles },
                dryRun: false,
                executionBlocked: false,
                permissionsRequired: skillGenerateDescriptor.permissionsRequired,
                unsafeSideEffects: true,
            },
            audit: [createAuditEvent("skill.generate", "agentCore.basicTool.skill.generate.executed", context, target.skillName, { writtenFiles })],
            events: ["basicTool.skill.generate.executed"],
        };
    }
    catch (error) {
        const reason = error instanceof Error && error.message.trim().length > 0 ? `: ${error.message}` : "";
        return failure("skill.generate", "PROVIDER_REJECTED", `skill.generate provider failed while writing skill files${reason}`, "provider", context, target.skillName);
    }
}
export const planSkillGeneration = executeSkillGenerate;
