"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadWorkflowTemplateCommandCatalog = loadWorkflowTemplateCommandCatalog;
exports.ensureWorkflowTemplateCatalogIsValid = ensureWorkflowTemplateCatalogIsValid;
exports.normalizeWorkflowTemplateCommandPath = normalizeWorkflowTemplateCommandPath;
exports.ensureWorkflowTemplateCreateTargetIsAvailable = ensureWorkflowTemplateCreateTargetIsAvailable;
exports.normalizeWorkflowTemplateDescription = normalizeWorkflowTemplateDescription;
exports.normalizeWorkflowTemplateRequiredSkills = normalizeWorkflowTemplateRequiredSkills;
exports.normalizeWorkflowTemplateRequiredMcp = normalizeWorkflowTemplateRequiredMcp;
exports.ensureWorkflowTemplateRequiredSkillsAreUsable = ensureWorkflowTemplateRequiredSkillsAreUsable;
exports.resolveWorkflowTemplateRequiredSkillInventory = resolveWorkflowTemplateRequiredSkillInventory;
exports.normalizeWorkflowTemplateTargets = normalizeWorkflowTemplateTargets;
exports.normalizeWorkflowTemplateAutoSelect = normalizeWorkflowTemplateAutoSelect;
exports.ensureWorkflowTemplateBodyDoesNotStartWithFrontmatter = ensureWorkflowTemplateBodyDoesNotStartWithFrontmatter;
exports.normalizeWorkflowTemplateContentSource = normalizeWorkflowTemplateContentSource;
exports.renderWorkflowTemplateSource = renderWorkflowTemplateSource;
exports.validateWorkflowTemplateCandidate = validateWorkflowTemplateCandidate;
exports.validateWorkflowTemplateCandidateSet = validateWorkflowTemplateCandidateSet;
exports.validateDeletedWorkflowTemplateReferencesRemoved = validateDeletedWorkflowTemplateReferencesRemoved;
exports.validateWorkflowTemplateCandidateRequiredSkills = validateWorkflowTemplateCandidateRequiredSkills;
exports.validateWorkflowTemplateCandidateRequiredMcp = validateWorkflowTemplateCandidateRequiredMcp;
exports.loadWorkflowTemplateBody = loadWorkflowTemplateBody;
exports.withWorkflowTemplateWriteLock = withWorkflowTemplateWriteLock;
exports.writeNewWorkflowTemplateSource = writeNewWorkflowTemplateSource;
exports.writeExistingWorkflowTemplateSource = writeExistingWorkflowTemplateSource;
exports.writeMovedWorkflowTemplateSource = writeMovedWorkflowTemplateSource;
exports.removeWorkflowTemplateSourceFile = removeWorkflowTemplateSourceFile;
// biome-ignore lint/nursery/noExcessiveLinesPerFile: Workflow template command validation stays grouped around one template contract.
const node_fs_1 = require("node:fs");
const promises_1 = require("node:fs/promises");
const node_os_1 = __importDefault(require("node:os"));
const node_path_1 = require("node:path");
const store_1 = require("../auth-profiles/store");
const control_plane_config_1 = require("../config/control-plane-config");
const branding_1 = require("../core/branding");
const fs_errors_1 = require("../core/fs-errors");
const catalog_1 = require("../i18n/catalog");
const required_skills_1 = require("../workflows/required-skills");
const required_mcp_1 = require("../workflows/required-mcp");
const required_capability_intersection_1 = require("../workflows/required-capability-intersection");
const workflow_template_required_skill_report_1 = require("./workflow-template-required-skill-report");
const skill_inventory_1 = require("../workflows/skill-inventory");
const template_registry_1 = require("../workflows/template-registry");
const template_reference_usages_1 = require("../workflows/template-reference-usages");
const types_1 = require("../workflows/types");
const validation_1 = require("../workflows/validation");
async function loadWorkflowTemplateCommandCatalog(workflowTemplatesDirectory, locale) {
    return (0, template_registry_1.loadWorkflowTemplates)(workflowTemplatesDirectory, locale).catch((error) => {
        throw new Error(error instanceof Error
            ? error.message
            : (0, catalog_1.translate)(locale, "workflow.runContext.catalogLoadFailed"));
    });
}
function ensureWorkflowTemplateCatalogIsValid(catalog, maxNestedWorkflowDepth, locale) {
    const diagnostics = (0, validation_1.validateWorkflowTemplateCatalog)({
        catalog,
        maxNestedWorkflowDepth,
    });
    if (diagnostics.length === 0) {
        return;
    }
    throw new Error((0, validation_1.formatWorkflowTemplateValidationSummary)({
        locale,
        diagnostics,
        includeLintHint: true,
    }));
}
function normalizeWorkflowTemplateCommandPath(value, locale) {
    const normalized = (0, types_1.normalizeWorkflowTemplatePath)(value);
    if (normalized === null) {
        throw new Error((0, catalog_1.translate)(locale, "workflow.command.template.invalidPath", { value }));
    }
    return normalized;
}
function ensureWorkflowTemplateCreateTargetIsAvailable(catalog, templatePath, locale) {
    if (catalog.templateByPath.has(templatePath)) {
        throw new Error((0, catalog_1.translate)(locale, "workflow.command.create.pathExists", {
            templatePath,
        }));
    }
}
function normalizeWorkflowTemplateDescription(description) {
    const normalized = description?.trim();
    return normalized && normalized.length > 0 ? normalized : null;
}
function normalizeWorkflowTemplateRequiredSkills(requiredSkills, locale) {
    const normalized = requiredSkills.map((skillRef) => skillRef.trim());
    for (const skillRef of normalized) {
        if (!(0, required_skills_1.isValidRequiredSkillRef)(skillRef)) {
            throw new Error((0, catalog_1.translate)(locale, "workflow.command.template.invalidRequiredSkill", {
                skillRef,
            }));
        }
    }
    return (0, required_skills_1.dedupeRequiredSkillRefs)(normalized);
}
function normalizeWorkflowTemplateRequiredMcp(requiredMcp, locale) {
    const normalized = requiredMcp.map((mcpRef) => mcpRef.trim());
    for (const mcpRef of normalized) {
        if (!(0, required_mcp_1.isValidRequiredMcpRef)(mcpRef)) {
            throw new Error((0, catalog_1.translate)(locale, "workflow.command.template.invalidRequiredMcp", {
                mcpRef,
            }));
        }
    }
    return (0, required_mcp_1.dedupeRequiredMcpRefs)(normalized);
}
function ensureWorkflowTemplateRequiredSkillsAreUsable(requiredSkills, skillInventory, locale) {
    const normalizedRequiredSkills = (0, required_skills_1.dedupeRequiredSkillRefs)(requiredSkills);
    if (normalizedRequiredSkills.length === 0) {
        return;
    }
    const workers = [
        ...new Set(skillInventory.map((skill) => skill.worker)),
    ].sort();
    const usableRefsByWorker = new Set(skillInventory
        .filter((skill) => skill.usableForRequiredSkills)
        .map((skill) => `${skill.worker}\0${skill.ref}`));
    for (const skillRef of normalizedRequiredSkills) {
        const satisfyingWorkers = workers.filter((worker) => (0, skill_inventory_1.requiredSkillRefCanRunOnWorker)(skillRef, worker) &&
            usableRefsByWorker.has(`${worker}\0${skillRef}`));
        if (satisfyingWorkers.length === 0) {
            throw new Error((0, catalog_1.translate)(locale, "workflow.command.template.unusableRequiredSkill", {
                skillRef,
            }));
        }
    }
    const runnableWorkers = workers.filter((worker) => normalizedRequiredSkills.every((skillRef) => (0, skill_inventory_1.requiredSkillRefCanRunOnWorker)(skillRef, worker) &&
        usableRefsByWorker.has(`${worker}\0${skillRef}`)));
    if (runnableWorkers.length === 0) {
        throw new Error((0, catalog_1.translate)(locale, "workflow.command.template.incompatibleRequiredSkills", {
            skillRefs: normalizedRequiredSkills.join(", "),
        }));
    }
}
async function resolveWorkflowTemplateRequiredSkillInventory(input) {
    if (input.config === null ||
        (0, control_plane_config_1.resolveWorkersForPurpose)(input.config, "thinking").length === 0) {
        return [];
    }
    const { profiles } = await (0, store_1.loadAuthProfiles)();
    const configuredWorkers = (0, control_plane_config_1.getConfiguredWorkerProviders)(input.config);
    return (await (0, skill_inventory_1.listAvailableSkills)({
        repoRoot: input.cwd,
        workers: configuredWorkers,
        configuredWorkers,
        authProfiles: profiles,
    })).items.map((item) => ({
        ref: item.ref,
        worker: item.worker,
        usableForRequiredSkills: item.usableForRequiredSkills,
    }));
}
function normalizeWorkflowTemplateTargets(targets, locale) {
    const normalized = targets ?? ["issue"];
    if (normalized.length === 0) {
        throw new Error((0, catalog_1.translate)(locale, "workflow.command.template.invalidTargets"));
    }
    const seen = new Set();
    for (const target of normalized) {
        if (target !== "issue" &&
            target !== "pull_request" &&
            target !== "unplanned" &&
            target !== "followup") {
            throw new Error((0, catalog_1.translate)(locale, "workflow.command.template.invalidTarget", {
                value: String(target),
            }));
        }
        if (seen.has(target)) {
            throw new Error((0, catalog_1.translate)(locale, "workflow.command.template.duplicateTarget", {
                value: target,
            }));
        }
        seen.add(target);
    }
    return [...seen];
}
function normalizeWorkflowTemplateAutoSelect(autoSelect) {
    return autoSelect ?? true;
}
function ensureWorkflowTemplateBodyDoesNotStartWithFrontmatter(body, locale) {
    const trimmed = body.trimStart();
    if (!trimmed.startsWith("---\n") && !trimmed.startsWith("---\r\n")) {
        return;
    }
    throw new Error((0, catalog_1.translate)(locale, "workflow.command.template.bodyFrontmatter"));
}
function normalizeWorkflowTemplateContentSource(content, locale, options = {}) {
    const bodyValidationOrder = options.bodyValidationOrder ?? "after-fields";
    if (bodyValidationOrder === "before-fields") {
        ensureWorkflowTemplateBodyDoesNotStartWithFrontmatter(content.body, locale);
    }
    const normalized = {
        description: normalizeWorkflowTemplateDescription(content.description ?? undefined),
        requiredSkills: normalizeWorkflowTemplateRequiredSkills(content.requiredSkills, locale),
        requiredMcp: normalizeWorkflowTemplateRequiredMcp(content.requiredMcp ?? [], locale),
        targets: normalizeWorkflowTemplateTargets(content.targets, locale),
        autoSelect: normalizeWorkflowTemplateAutoSelect(content.autoSelect),
        body: content.body,
    };
    if (bodyValidationOrder === "after-fields") {
        ensureWorkflowTemplateBodyDoesNotStartWithFrontmatter(content.body, locale);
    }
    return normalized;
}
function renderWorkflowTemplateSource(source) {
    const lines = [
        "---",
        ...(source.description !== null
            ? [`description: ${JSON.stringify(source.description)}`]
            : []),
        "targets:",
        ...source.targets.map((target) => `  - ${target}`),
        `autoSelect: ${source.autoSelect ? "true" : "false"}`,
        ...(source.updateMode !== undefined
            ? [`updateMode: ${source.updateMode}`]
            : []),
        "requires:",
        ...(source.requiredSkills.length > 0
            ? [
                "  skills:",
                ...source.requiredSkills.map((skillRef) => `    - ${skillRef}`),
            ]
            : ["  skills: []"]),
        ...(source.requiredMcp.length > 0
            ? ["  mcp:", ...source.requiredMcp.map((mcpRef) => `    - ${mcpRef}`)]
            : ["  mcp: []"]),
        "---",
        source.body.trimEnd(),
    ];
    return `${lines.join("\n")}\n`;
}
async function validateWorkflowTemplateCandidate(input) {
    const tempRoot = await (0, promises_1.mkdtemp)((0, node_path_1.join)(node_os_1.default.tmpdir(), `${branding_1.CLI_COMMAND_NAME}-workflow-template-`));
    const tempWorkflowTemplatesDirectory = (0, template_registry_1.getWorkflowTemplatesDirectoryPath)(tempRoot);
    try {
        await copyWorkflowTemplatesDirectory(input.workflowTemplatesDirectory, tempWorkflowTemplatesDirectory);
        await overlayWorkflowTemplateCandidates(tempWorkflowTemplatesDirectory, [
            {
                templatePath: input.templatePath,
                source: input.source,
                ...(input.replacedTemplatePath !== undefined
                    ? { replacedTemplatePath: input.replacedTemplatePath }
                    : {}),
            },
        ]);
        const catalog = await (0, template_registry_1.loadWorkflowTemplates)(tempWorkflowTemplatesDirectory, input.locale);
        const template = catalog.templateByPath.get(input.templatePath);
        if (!template) {
            throw new Error((0, catalog_1.translate)(input.locale, "workflow.command.template.validationMissing", {
                templatePath: input.templatePath,
            }));
        }
        const diagnostics = input.scope === "catalog"
            ? (0, validation_1.validateWorkflowTemplateCatalog)({
                catalog,
                maxNestedWorkflowDepth: input.maxNestedWorkflowDepth,
            })
            : (0, validation_1.validateWorkflowTemplateRecord)({
                catalog,
                rootTemplate: template,
                maxNestedWorkflowDepth: input.maxNestedWorkflowDepth,
            }).diagnostics;
        if (diagnostics.length > 0) {
            throw new Error((0, validation_1.formatWorkflowTemplateValidationReport)({
                locale: input.locale,
                diagnostics,
                templatePath: input.templatePath,
            }));
        }
    }
    finally {
        await (0, promises_1.rm)(tempRoot, { recursive: true, force: true });
    }
}
async function validateWorkflowTemplateCandidateSet(input) {
    const tempRoot = await (0, promises_1.mkdtemp)((0, node_path_1.join)(node_os_1.default.tmpdir(), `${branding_1.CLI_COMMAND_NAME}-workflow-template-set-`));
    const tempWorkflowTemplatesDirectory = (0, template_registry_1.getWorkflowTemplatesDirectoryPath)(tempRoot);
    try {
        await copyWorkflowTemplatesDirectory(input.workflowTemplatesDirectory, tempWorkflowTemplatesDirectory);
        await overlayWorkflowTemplateCandidates(tempWorkflowTemplatesDirectory, input.candidates, input.deletedTemplatePaths ?? []);
        const catalog = await (0, template_registry_1.loadWorkflowTemplates)(tempWorkflowTemplatesDirectory, input.locale);
        for (const candidate of input.candidates) {
            if (!catalog.templateByPath.has(candidate.templatePath)) {
                throw new Error((0, catalog_1.translate)(input.locale, "workflow.command.template.validationMissing", {
                    templatePath: candidate.templatePath,
                }));
            }
        }
        const diagnostics = (0, validation_1.validateWorkflowTemplateCatalog)({
            catalog,
            maxNestedWorkflowDepth: input.maxNestedWorkflowDepth,
        });
        if (diagnostics.length > 0) {
            throw new Error((0, validation_1.formatWorkflowTemplateValidationReport)({
                locale: input.locale,
                diagnostics,
            }));
        }
    }
    finally {
        await (0, promises_1.rm)(tempRoot, { recursive: true, force: true });
    }
}
async function validateDeletedWorkflowTemplateReferencesRemoved(input) {
    if (input.deletedTemplatePaths.length === 0) {
        return;
    }
    const tempRoot = await (0, promises_1.mkdtemp)((0, node_path_1.join)(node_os_1.default.tmpdir(), `${branding_1.CLI_COMMAND_NAME}-workflow-template-delete-`));
    const tempWorkflowTemplatesDirectory = (0, template_registry_1.getWorkflowTemplatesDirectoryPath)(tempRoot);
    try {
        await copyWorkflowTemplatesDirectory(input.workflowTemplatesDirectory, tempWorkflowTemplatesDirectory);
        await overlayWorkflowTemplateCandidates(tempWorkflowTemplatesDirectory, input.candidates, input.deletedTemplatePaths);
        const catalog = await (0, template_registry_1.loadWorkflowTemplates)(tempWorkflowTemplatesDirectory, input.locale);
        const remainingUsages = input.deletedTemplatePaths.flatMap((targetPath) => (0, template_reference_usages_1.collectWorkflowTemplateReferenceUsages)({
            catalog,
            targetPath,
            includeSystemSources: true,
            config: input.config,
        }));
        if (remainingUsages.length === 0) {
            return;
        }
        throw new Error([
            (0, catalog_1.translate)(input.locale, "workflow.command.delete.referencesBlocked", {
                templatePath: input.deletedTemplatePaths.join(", "),
            }),
            (0, template_reference_usages_1.formatWorkflowTemplateReferenceUsageTable)(remainingUsages),
        ].join("\n"));
    }
    finally {
        await (0, promises_1.rm)(tempRoot, { recursive: true, force: true });
    }
}
async function validateWorkflowTemplateCandidateRequiredSkills(input) {
    await validateWorkflowTemplateCandidateRequirements({
        workflowTemplatesDirectory: input.workflowTemplatesDirectory,
        candidates: input.candidates,
        maxNestedWorkflowDepth: input.maxNestedWorkflowDepth,
        locale: input.locale,
        tempPrefix: "workflow-template-skills",
    }, ({ catalog, rootTemplate }) => {
        ensureWorkflowTemplateRequiredSkillsAreUsable((0, required_skills_1.collectRequiredSkillsForWorkflowTree)({
            catalog,
            rootTemplate,
            maxNestedWorkflowDepth: input.maxNestedWorkflowDepth,
        }), input.skillInventory, input.locale);
    });
}
async function validateWorkflowTemplateCandidateRequiredMcp(input) {
    await validateWorkflowTemplateCandidateRequirements({
        workflowTemplatesDirectory: input.workflowTemplatesDirectory,
        candidates: input.candidates,
        maxNestedWorkflowDepth: input.maxNestedWorkflowDepth,
        locale: input.locale,
        tempPrefix: "workflow-template-mcp",
    }, async ({ catalog, rootTemplate }) => {
        const mcpRefs = (0, required_mcp_1.collectRequiredMcpForWorkflowTree)({
            catalog,
            rootTemplate,
            maxNestedWorkflowDepth: input.maxNestedWorkflowDepth,
        });
        if (mcpRefs.length === 0) {
            return;
        }
        const report = await (0, required_mcp_1.checkRequiredMcpAvailability)({
            repoRoot: input.repoRoot,
            workers: input.workers,
            mcpRefs,
        });
        if (!report.ok) {
            throw new Error((0, required_mcp_1.formatRequiredMcpAvailabilityReport)({
                report,
                locale: input.locale,
            }));
        }
        if (input.skillInventory !== undefined) {
            const skillReport = (0, workflow_template_required_skill_report_1.buildRequiredSkillAvailabilityReportFromInventory)({
                skillRefs: (0, required_skills_1.collectRequiredSkillsForWorkflowTree)({
                    catalog,
                    rootTemplate,
                    maxNestedWorkflowDepth: input.maxNestedWorkflowDepth,
                }),
                skillInventory: input.skillInventory,
            });
            const intersectionReport = (0, required_capability_intersection_1.checkRequiredCapabilityWorkerIntersection)({
                skillReport,
                mcpReport: report,
            });
            if (!intersectionReport.ok) {
                throw new Error((0, required_capability_intersection_1.formatRequiredCapabilityWorkerIntersectionReport)({
                    report: intersectionReport,
                    locale: input.locale,
                }));
            }
        }
    });
}
async function validateWorkflowTemplateCandidateRequirements(input, validate) {
    if (input.candidates.length === 0) {
        return;
    }
    const tempRoot = await (0, promises_1.mkdtemp)((0, node_path_1.join)(node_os_1.default.tmpdir(), `${branding_1.CLI_COMMAND_NAME}-${input.tempPrefix}-`));
    const tempWorkflowTemplatesDirectory = (0, template_registry_1.getWorkflowTemplatesDirectoryPath)(tempRoot);
    try {
        await copyWorkflowTemplatesDirectory(input.workflowTemplatesDirectory, tempWorkflowTemplatesDirectory);
        await overlayWorkflowTemplateCandidates(tempWorkflowTemplatesDirectory, input.candidates);
        const catalog = await (0, template_registry_1.loadWorkflowTemplates)(tempWorkflowTemplatesDirectory, input.locale);
        const rootPaths = collectRequiredValidationRootPaths({
            catalog,
            changedTemplatePaths: input.candidates.map((candidate) => candidate.templatePath),
            maxNestedWorkflowDepth: input.maxNestedWorkflowDepth,
        });
        for (const rootPath of rootPaths) {
            const rootTemplate = catalog.templateByPath.get(rootPath);
            if (rootTemplate === undefined) {
                throw new Error((0, catalog_1.translate)(input.locale, "workflow.command.template.validationMissing", {
                    templatePath: rootPath,
                }));
            }
            await validate({ catalog, rootTemplate });
        }
    }
    finally {
        await (0, promises_1.rm)(tempRoot, { recursive: true, force: true });
    }
}
async function overlayWorkflowTemplateCandidates(workflowTemplatesDirectory, candidates, deletedTemplatePaths = []) {
    for (const templatePath of deletedTemplatePaths) {
        await removeWorkflowTemplateSourceFile(workflowTemplatesDirectory, templatePath);
    }
    for (const candidate of candidates) {
        if (candidate.replacedTemplatePath === undefined ||
            candidate.replacedTemplatePath === candidate.templatePath) {
            continue;
        }
        await removeWorkflowTemplateSourceFile(workflowTemplatesDirectory, candidate.replacedTemplatePath);
    }
    for (const candidate of candidates) {
        const filePath = (0, node_path_1.join)(workflowTemplatesDirectory, candidate.templatePath);
        await (0, promises_1.mkdir)((0, node_path_1.dirname)(filePath), { recursive: true });
        await (0, promises_1.writeFile)(filePath, candidate.source, "utf8");
    }
}
function collectRequiredValidationRootPaths(input) {
    const changedPaths = new Set(input.changedTemplatePaths);
    const rootPaths = new Set(input.changedTemplatePaths);
    for (const template of input.catalog.templates) {
        if (workflowTemplateTreeReferencesChangedPath({
            catalog: input.catalog,
            rootTemplate: template,
            changedPaths,
            maxNestedWorkflowDepth: input.maxNestedWorkflowDepth,
        })) {
            rootPaths.add(template.templatePath);
        }
    }
    return [...rootPaths].sort();
}
function workflowTemplateTreeReferencesChangedPath(input) {
    const visitedTemplatePaths = new Set();
    const visit = (template, activeStack, depth) => {
        if (visitedTemplatePaths.has(template.templatePath)) {
            return false;
        }
        visitedTemplatePaths.add(template.templatePath);
        if (depth >= input.maxNestedWorkflowDepth) {
            return false;
        }
        const nextActiveStack = [...activeStack, template.templatePath];
        for (const { templateName: childPath } of (0, validation_1.scanWorkflowTemplateDirectives)(template).directives) {
            if (input.changedPaths.has(childPath)) {
                return true;
            }
            if (nextActiveStack.includes(childPath)) {
                continue;
            }
            const childTemplate = input.catalog.templateByPath.get(childPath);
            if (childTemplate !== undefined &&
                visit(childTemplate, nextActiveStack, depth + 1)) {
                return true;
            }
        }
        return false;
    };
    return visit(input.rootTemplate, [], 0);
}
async function loadWorkflowTemplateBody(body) {
    if (body.kind === "text") {
        return body.text;
    }
    if (body.path === "-") {
        return (0, node_fs_1.readFileSync)(0, "utf8");
    }
    return (0, promises_1.readFile)(body.path, "utf8");
}
async function withWorkflowTemplateWriteLock(workflowTemplatesDirectory, locale, callback) {
    await (0, promises_1.mkdir)(workflowTemplatesDirectory, { recursive: true });
    const lockPath = (0, node_path_1.join)(workflowTemplatesDirectory, ".write.lock");
    try {
        await (0, promises_1.writeFile)(lockPath, `${process.pid}\n`, {
            encoding: "utf8",
            flag: "wx",
        });
    }
    catch (error) {
        if ((0, fs_errors_1.isAlreadyExistsError)(error)) {
            throw new Error((0, catalog_1.translate)(locale, "workflow.command.template.lockBusy"));
        }
        throw error;
    }
    try {
        return await callback();
    }
    finally {
        await (0, promises_1.rm)(lockPath, { force: true });
    }
}
async function writeNewWorkflowTemplateSource(workflowTemplatesDirectory, templatePath, source, locale) {
    const filePath = (0, node_path_1.join)(workflowTemplatesDirectory, templatePath);
    await (0, promises_1.mkdir)((0, node_path_1.dirname)(filePath), { recursive: true });
    try {
        await (0, promises_1.writeFile)(filePath, source, {
            encoding: "utf8",
            flag: "wx",
        });
    }
    catch (error) {
        if ((0, fs_errors_1.isAlreadyExistsError)(error)) {
            throw new Error((0, catalog_1.translate)(locale, "workflow.command.create.pathExists", {
                templatePath,
            }));
        }
        throw error;
    }
}
async function writeExistingWorkflowTemplateSource(workflowTemplatesDirectory, templatePath, source) {
    const filePath = (0, node_path_1.join)(workflowTemplatesDirectory, templatePath);
    await (0, promises_1.mkdir)((0, node_path_1.dirname)(filePath), { recursive: true });
    const tempFilePath = (0, node_path_1.join)((0, node_path_1.dirname)(filePath), `.${templatePath.split("/").at(-1) ?? "workflow"}.${process.pid}.${Date.now()}.tmp`);
    try {
        await (0, promises_1.writeFile)(tempFilePath, source, "utf8");
        await (0, promises_1.rename)(tempFilePath, filePath);
    }
    finally {
        await (0, promises_1.rm)(tempFilePath, { force: true });
    }
}
async function writeMovedWorkflowTemplateSource(workflowTemplatesDirectory, sourceTemplatePath, targetTemplatePath, source, locale) {
    if (sourceTemplatePath === targetTemplatePath) {
        await writeExistingWorkflowTemplateSource(workflowTemplatesDirectory, targetTemplatePath, source);
        return;
    }
    const targetFilePath = (0, node_path_1.join)(workflowTemplatesDirectory, targetTemplatePath);
    await (0, promises_1.mkdir)((0, node_path_1.dirname)(targetFilePath), { recursive: true });
    try {
        await (0, promises_1.writeFile)(targetFilePath, source, {
            encoding: "utf8",
            flag: "wx",
        });
    }
    catch (error) {
        if ((0, fs_errors_1.isAlreadyExistsError)(error)) {
            throw new Error((0, catalog_1.translate)(locale, "workflow.command.create.pathExists", {
                templatePath: targetTemplatePath,
            }));
        }
        throw error;
    }
    await removeWorkflowTemplateSourceFile(workflowTemplatesDirectory, sourceTemplatePath);
}
async function removeWorkflowTemplateSourceFile(workflowTemplatesDirectory, templatePath) {
    const filePath = (0, node_path_1.join)(workflowTemplatesDirectory, templatePath);
    await (0, promises_1.rm)(filePath, { force: true });
    await removeEmptyWorkflowTemplateParentDirectories(workflowTemplatesDirectory, (0, node_path_1.dirname)(filePath));
}
async function removeEmptyWorkflowTemplateParentDirectories(workflowTemplatesDirectory, directoryPath) {
    let currentDirectory = directoryPath;
    while (currentDirectory !== workflowTemplatesDirectory &&
        !(0, node_path_1.relative)(workflowTemplatesDirectory, currentDirectory).startsWith("..")) {
        try {
            await (0, promises_1.rmdir)(currentDirectory);
        }
        catch {
            return;
        }
        currentDirectory = (0, node_path_1.dirname)(currentDirectory);
    }
}
async function copyWorkflowTemplatesDirectory(sourceDirectory, targetDirectory) {
    try {
        await (0, promises_1.cp)(sourceDirectory, targetDirectory, { recursive: true });
    }
    catch (error) {
        if (error instanceof Error &&
            "code" in error &&
            error.code === "ENOENT") {
            await (0, promises_1.mkdir)(targetDirectory, { recursive: true });
            return;
        }
        throw error;
    }
}
