import { resolve } from "node:path";
import { z } from "zod";
import { listProviders, loadModelResolver, } from "../models/catalog.js";
import { formatPersonaReference, parsePersonaReference } from "../persona_reference.js";
import { parseSubagentLaunchModelList } from "../subagents/launch_model.js";
import { REASONING_LEVELS, RiskLevelSchema } from "../types.js";
import { normalizeModelNoticeKey, parseModelNoticeKey } from "../utils/model_notices.js";
import { parseBashCommands } from "./bash_commands.js";
import { parseDiffToolConfig, resolveDiffToolConfig } from "./diff_tool.js";
import { resolveConfigLevels } from "./paths.js";
import { getVirtualConfigDefaults } from "./virtual_defaults.js";
export const DEFAULT_AUTO_COMPACT_CONFIG = {
    enabled: true,
    reserveTokens: 16384,
    keepRecentTokens: 20000,
};
export function normalizeAutoCompactConfig(config) {
    return { ...DEFAULT_AUTO_COMPACT_CONFIG, ...config };
}
const BUILT_IN_DIFF_TOOL_CODE_THEMES = new Set([
    "andromeeda",
    "aurora-x",
    "ayu-dark",
    "ayu-mirage",
    "catppuccin-frappe",
    "catppuccin-macchiato",
    "catppuccin-mocha",
    "dark-plus",
    "dracula",
    "dracula-soft",
    "everforest-dark",
    "github-dark",
    "github-dark-default",
    "github-dark-dimmed",
    "github-dark-high-contrast",
    "gruvbox-dark-hard",
    "gruvbox-dark-medium",
    "gruvbox-dark-soft",
    "horizon",
    "horizon-bright",
    "houston",
    "kanagawa-dragon",
    "kanagawa-wave",
    "laserwave",
    "material-theme",
    "material-theme-darker",
    "material-theme-ocean",
    "material-theme-palenight",
    "min-dark",
    "monokai",
    "night-owl",
    "nord",
    "one-dark-pro",
    "plastic",
    "poimandres",
    "red",
    "rose-pine",
    "rose-pine-moon",
    "slack-dark",
    "solarized-dark",
    "synthwave-84",
    "tokyo-night",
    "vesper",
    "vitesse-black",
    "vitesse-dark",
]);
const BuiltInDiffToolSchema = z
    .object({
    codeTheme: z.string().trim().min(1).optional(),
})
    .passthrough();
const KNOWN_TOP_LEVEL_CONFIG_KEYS = new Set([
    "apiKeys",
    "defaultPersona",
    "defaultRisk",
    "disableBuiltinPersonas",
    "disableBuiltinThemes",
    "defaultTheme",
    "bashCommands",
    "diffTool",
    "builtInDiffTool",
    "agentContextFiles",
    "subagents",
    "autoCompact",
    "modelSystemNotices",
    "async",
]);
const NonEmptyStringSchema = z.string().trim().min(1);
const BooleanSchema = z.boolean();
const AgentContextFilesSchema = z.array(NonEmptyStringSchema);
const ApiKeyProviderSchema = z.string();
const ApiKeysSchema = z.object({}).catchall(z.unknown());
const SubagentsConfigSchema = z
    .object({
    defaultLaunchModels: z.array(z.string()).optional(),
})
    .passthrough();
const StringRecordSchema = z.object({}).catchall(z.unknown());
const PositiveIntegerSchema = z.number().int().finite().gt(0);
const AutoCompactConfigSchema = z
    .object({
    enabled: BooleanSchema.optional(),
    reserveTokens: PositiveIntegerSchema.optional(),
    keepRecentTokens: PositiveIntegerSchema.optional(),
})
    .strict();
const AsyncClientTargetSchema = z.object({
    url: NonEmptyStringSchema.optional(),
    token: NonEmptyStringSchema.optional(),
    timeoutMs: PositiveIntegerSchema.optional(),
});
function parseOptionalFields(data, sourceLabel, specs) {
    const values = {};
    const errors = [];
    for (const [key, schema, errorMessage] of specs) {
        const value = data[key];
        if (value === undefined) {
            continue;
        }
        const parsed = schema.safeParse(value);
        if (!parsed.success) {
            errors.push(`${sourceLabel}: ${errorMessage}`);
            continue;
        }
        values[key] = parsed.data;
    }
    return { values, errors };
}
function assignParsedConfigValue(config, errors, key, value, parseErrors) {
    if (value !== undefined) {
        config[key] = value;
    }
    errors.push(...parseErrors);
}
function parseConfigJson(content, sourceLabel) {
    try {
        return { data: JSON.parse(content), errors: [] };
    }
    catch (err) {
        return {
            errors: [
                `${sourceLabel}: failed to parse json: ${err instanceof Error ? err.message : String(err)}`,
            ],
        };
    }
}
function parseApiKeysConfig(raw, sourceLabel) {
    if (raw === undefined) {
        return { errors: [] };
    }
    const parsed = ApiKeysSchema.safeParse(raw);
    if (!parsed.success) {
        return { errors: [`${sourceLabel}: 'apiKeys' must be an object.`] };
    }
    const apiKeys = {};
    const errors = [];
    for (const [rawProvider, rawValue] of Object.entries(parsed.data)) {
        const provider = rawProvider.trim();
        if (!provider) {
            errors.push(`${sourceLabel}: apiKeys keys must be non-empty strings.`);
            continue;
        }
        const parsedValue = ApiKeyProviderSchema.safeParse(rawValue);
        if (!parsedValue.success) {
            errors.push(`${sourceLabel}: apiKeys.${provider} must be a string.`);
            continue;
        }
        apiKeys[provider] = parsedValue.data;
    }
    if (Object.keys(apiKeys).length === 0) {
        return { errors };
    }
    return { config: apiKeys, errors };
}
function parseDefaultPersona(raw, sourceLabel) {
    if (raw === undefined) {
        return { errors: [] };
    }
    const parsedPersona = z.string().safeParse(raw);
    if (!parsedPersona.success) {
        return { errors: [`${sourceLabel}: 'defaultPersona' must be a string.`] };
    }
    const ref = parsePersonaReference(parsedPersona.data);
    if (ref.personaId && !ref.error) {
        return {
            defaultPersona: formatPersonaReference({
                personaId: ref.personaId,
                reasoning: ref.reasoning,
            }),
            errors: [],
        };
    }
    if (ref.error === "empty-persona") {
        return { errors: [`${sourceLabel}: 'defaultPersona' must be a non-empty string.`] };
    }
    if (ref.error === "missing-reasoning") {
        return {
            errors: [`${sourceLabel}: 'defaultPersona' is missing a reasoning level after ':'.`],
        };
    }
    if (ref.error === "invalid-reasoning") {
        return {
            errors: [
                `${sourceLabel}: 'defaultPersona' has invalid reasoning level '${ref.rawReasoning}'. allowed levels: ${REASONING_LEVELS.join(", ")}.`,
            ],
        };
    }
    return { errors: [] };
}
function validateConfigData(raw, sourceLabel, options) {
    if (typeof raw !== "object" || raw === null) {
        return { config: {}, errors: [`${sourceLabel}: config must be an object.`] };
    }
    const data = raw;
    const config = {};
    const errors = [];
    const unknownKeys = Object.keys(data).filter((key) => !KNOWN_TOP_LEVEL_CONFIG_KEYS.has(key));
    if (unknownKeys.length > 0) {
        const keyLabel = unknownKeys.length === 1 ? "key" : "keys";
        errors.push(`${sourceLabel}: unknown ${keyLabel} in config: ${unknownKeys.sort().join(", ")}.`);
    }
    const apiKeysResult = parseApiKeysConfig(data.apiKeys, sourceLabel);
    assignParsedConfigValue(config, errors, "apiKeys", apiKeysResult.config, apiKeysResult.errors);
    const defaultPersonaResult = parseDefaultPersona(data.defaultPersona, sourceLabel);
    assignParsedConfigValue(config, errors, "defaultPersona", defaultPersonaResult.defaultPersona, defaultPersonaResult.errors);
    const scalarResult = parseOptionalFields(data, sourceLabel, [
        ["defaultRisk", RiskLevelSchema, "'defaultRisk' must be a valid risk level."],
        ["disableBuiltinPersonas", BooleanSchema, "'disableBuiltinPersonas' must be a boolean."],
        ["disableBuiltinThemes", BooleanSchema, "'disableBuiltinThemes' must be a boolean."],
        ["defaultTheme", NonEmptyStringSchema, "'defaultTheme' must be a non-empty string."],
    ]);
    Object.assign(config, scalarResult.values);
    errors.push(...scalarResult.errors);
    const bashResult = parseBashCommands(data.bashCommands, sourceLabel);
    assignParsedConfigValue(config, errors, "bashCommands", bashResult.commands.length > 0 ? bashResult.commands : undefined, bashResult.errors);
    const diffToolResult = parseDiffToolConfig(data.diffTool, sourceLabel);
    assignParsedConfigValue(config, errors, "diffTool", diffToolResult.config, diffToolResult.errors);
    const builtInDiffToolResult = parseBuiltInDiffToolConfig(data.builtInDiffTool, sourceLabel);
    assignParsedConfigValue(config, errors, "builtInDiffTool", builtInDiffToolResult.config, builtInDiffToolResult.errors);
    const agentResult = parseAgentContextFiles(data.agentContextFiles, sourceLabel);
    assignParsedConfigValue(config, errors, "agentContextFiles", agentResult.paths.length > 0 ? agentResult.paths : undefined, agentResult.errors);
    const subagentsResult = parseSubagentsConfig(data.subagents, sourceLabel, options.resolveModel);
    assignParsedConfigValue(config, errors, "subagents", subagentsResult.config, subagentsResult.errors);
    const autoCompactResult = parseAutoCompactConfig(data.autoCompact, sourceLabel);
    assignParsedConfigValue(config, errors, "autoCompact", autoCompactResult.config, autoCompactResult.errors);
    const modelSystemNoticesResult = parseModelSystemNotices(data.modelSystemNotices, sourceLabel, options.resolveConfiguredModel);
    assignParsedConfigValue(config, errors, "modelSystemNotices", modelSystemNoticesResult.notices, modelSystemNoticesResult.errors);
    const asyncResult = parseAsyncConfig(data.async, sourceLabel);
    assignParsedConfigValue(config, errors, "async", asyncResult.config, asyncResult.errors);
    return { config, errors };
}
function parseAgentContextFiles(raw, sourceLabel) {
    if (raw === undefined) {
        return { paths: [], errors: [] };
    }
    const parsed = AgentContextFilesSchema.safeParse(raw);
    if (!parsed.success) {
        return {
            paths: [],
            errors: [`${sourceLabel}: 'agentContextFiles' must be a string array.`],
        };
    }
    return { paths: parsed.data, errors: [] };
}
function parseBuiltInDiffToolConfig(raw, sourceLabel) {
    if (raw === undefined) {
        return { errors: [] };
    }
    const parsed = BuiltInDiffToolSchema.safeParse(raw);
    if (!parsed.success) {
        return { errors: [`${sourceLabel}: 'builtInDiffTool' must be an object.`] };
    }
    const config = {};
    const codeTheme = parsed.data.codeTheme;
    if (codeTheme !== undefined) {
        if (!BUILT_IN_DIFF_TOOL_CODE_THEMES.has(codeTheme)) {
            return { errors: [`${sourceLabel}: builtInDiffTool.codeTheme is not supported.`] };
        }
        config.codeTheme = codeTheme;
    }
    return { config: Object.keys(config).length > 0 ? config : undefined, errors: [] };
}
function parseSubagentsConfig(raw, sourceLabel, modelResolver) {
    if (raw === undefined) {
        return { errors: [] };
    }
    const parsed = SubagentsConfigSchema.safeParse(raw);
    if (!parsed.success) {
        if (parsed.error.issues.some((issue) => issue.path[0] === "defaultLaunchModels")) {
            return { errors: [`${sourceLabel}: subagents.defaultLaunchModels must be a string array.`] };
        }
        return { errors: [`${sourceLabel}: 'subagents' must be an object.`] };
    }
    const { defaultLaunchModels } = parsed.data;
    if (defaultLaunchModels === undefined) {
        return { errors: [] };
    }
    const launchModelsResult = parseSubagentLaunchModelList(defaultLaunchModels, {
        resolveModel: modelResolver,
    });
    if (launchModelsResult.error) {
        return {
            errors: [
                `${sourceLabel}: subagents.defaultLaunchModels ${launchModelsResult.error}. expected <provider>/<model>:<effort>.`,
            ],
        };
    }
    return {
        config: {
            defaultLaunchModels: launchModelsResult.launchModels,
        },
        errors: [],
    };
}
function parseAutoCompactConfig(raw, sourceLabel) {
    if (raw === undefined) {
        return { errors: [] };
    }
    const parsed = AutoCompactConfigSchema.safeParse(raw);
    if (!parsed.success) {
        const errors = new Set();
        if (parsed.error.issues.some((issue) => issue.path[0] === "enabled")) {
            errors.add(`${sourceLabel}: autoCompact.enabled must be a boolean.`);
        }
        if (parsed.error.issues.some((issue) => issue.path[0] === "reserveTokens")) {
            errors.add(`${sourceLabel}: autoCompact.reserveTokens must be a positive integer.`);
        }
        if (parsed.error.issues.some((issue) => issue.path[0] === "keepRecentTokens")) {
            errors.add(`${sourceLabel}: autoCompact.keepRecentTokens must be a positive integer.`);
        }
        for (const issue of parsed.error.issues) {
            if (issue.code === "unrecognized_keys") {
                const keyLabel = issue.keys.length === 1 ? "key" : "keys";
                errors.add(`${sourceLabel}: unknown ${keyLabel} in autoCompact: ${issue.keys.sort().join(", ")}.`);
            }
        }
        if (errors.size === 0) {
            errors.add(`${sourceLabel}: 'autoCompact' must be an object.`);
        }
        return { errors: [...errors] };
    }
    if (Object.keys(parsed.data).length === 0) {
        return { errors: [] };
    }
    return { config: parsed.data, errors: [] };
}
function parseModelNoticeTarget(rawKey, modelResolver) {
    const parsedKey = parseModelNoticeKey(rawKey);
    if (!parsedKey) {
        return { error: "must use keys in format '<provider>/<model>'" };
    }
    const provider = parsedKey.provider;
    if (!listProviders().includes(provider)) {
        return { error: `unknown provider '${parsedKey.provider}'` };
    }
    const model = modelResolver(provider, parsedKey.modelId);
    if (!model) {
        return {
            error: `unknown model '${parsedKey.provider}/${parsedKey.modelId}'`,
        };
    }
    return {
        normalizedKey: normalizeModelNoticeKey(provider, model.id),
    };
}
function parseModelSystemNotices(raw, sourceLabel, modelResolver) {
    if (raw === undefined) {
        return { errors: [] };
    }
    const parsedRecord = StringRecordSchema.safeParse(raw);
    if (!parsedRecord.success) {
        return { errors: [`${sourceLabel}: 'modelSystemNotices' must be an object.`] };
    }
    const notices = {};
    const errors = [];
    for (const [rawKey, rawValue] of Object.entries(parsedRecord.data)) {
        const parsedKey = parseModelNoticeTarget(rawKey, modelResolver);
        if (parsedKey.error || !parsedKey.normalizedKey) {
            errors.push(`${sourceLabel}: modelSystemNotices.${rawKey} ${parsedKey.error ?? "is invalid"}.`);
            continue;
        }
        const parsedNotice = NonEmptyStringSchema.safeParse(rawValue);
        if (!parsedNotice.success) {
            errors.push(`${sourceLabel}: modelSystemNotices.${rawKey} must be a non-empty string notice.`);
            continue;
        }
        notices[parsedKey.normalizedKey] = parsedNotice.data;
    }
    if (Object.keys(notices).length === 0) {
        return { errors };
    }
    return { notices, errors };
}
function parseAsyncClientTarget(raw, sourceLabel, key) {
    const parsedRecord = StringRecordSchema.safeParse(raw);
    if (!parsedRecord.success) {
        return { errors: [`${sourceLabel}: async.client.targets.${key} must be an object.`] };
    }
    const parsedTarget = AsyncClientTargetSchema.safeParse(parsedRecord.data);
    if (parsedTarget.success) {
        return { config: parsedTarget.data, errors: [] };
    }
    const errors = new Set();
    for (const issue of parsedTarget.error.issues) {
        switch (issue.path[0]) {
            case "url":
                errors.add(`${sourceLabel}: async.client.targets.${key}.url must be a non-empty string.`);
                break;
            case "token":
                errors.add(`${sourceLabel}: async.client.targets.${key}.token must be a non-empty string.`);
                break;
            case "timeoutMs":
                errors.add(`${sourceLabel}: async.client.targets.${key}.timeoutMs must be a positive integer.`);
                break;
            default:
                break;
        }
    }
    return { errors: [...errors] };
}
function parseAsyncClientConfig(raw, sourceLabel) {
    if (raw === undefined) {
        return { errors: [] };
    }
    const parsedRecord = StringRecordSchema.safeParse(raw);
    if (!parsedRecord.success) {
        return { errors: [`${sourceLabel}: async.client must be an object.`] };
    }
    const data = parsedRecord.data;
    const config = {};
    const scalarResult = parseOptionalFields(data, sourceLabel, [
        [
            "defaultTarget",
            NonEmptyStringSchema,
            "async.client.defaultTarget must be a non-empty string.",
        ],
        [
            "defaultProjectId",
            NonEmptyStringSchema,
            "async.client.defaultProjectId must be a non-empty string.",
        ],
    ]);
    Object.assign(config, scalarResult.values);
    const errors = [...scalarResult.errors];
    if (data.targets !== undefined) {
        const parsedTargetsRecord = StringRecordSchema.safeParse(data.targets);
        if (!parsedTargetsRecord.success) {
            errors.push(`${sourceLabel}: async.client.targets must be an object.`);
        }
        else {
            const targets = {};
            for (const [key, value] of Object.entries(parsedTargetsRecord.data)) {
                const parsedTargetKey = NonEmptyStringSchema.safeParse(key);
                if (!parsedTargetKey.success) {
                    errors.push(`${sourceLabel}: async.client.targets keys must be non-empty.`);
                    continue;
                }
                const parsedTarget = parseAsyncClientTarget(value, sourceLabel, key);
                if (parsedTarget.config) {
                    targets[key] = parsedTarget.config;
                }
                errors.push(...parsedTarget.errors);
            }
            if (Object.keys(targets).length > 0) {
                config.targets = targets;
            }
        }
    }
    if (Object.keys(config).length === 0) {
        return { errors };
    }
    return { config, errors };
}
function parseAsyncConfig(raw, sourceLabel) {
    if (raw === undefined) {
        return { errors: [] };
    }
    const parsedRecord = StringRecordSchema.safeParse(raw);
    if (!parsedRecord.success) {
        return { errors: [`${sourceLabel}: 'async' must be an object.`] };
    }
    const data = parsedRecord.data;
    const config = {};
    const errors = [];
    const clientResult = parseAsyncClientConfig(data.client, sourceLabel);
    if (clientResult.config) {
        config.client = clientResult.config;
    }
    errors.push(...clientResult.errors);
    const movedAsyncFields = ["server", "projects"];
    for (const field of movedAsyncFields) {
        if (data[field] === undefined) {
            continue;
        }
        errors.push(`${sourceLabel}: async.${field} was moved to daemon config file. use 'tau async daemon --config-file <path>'.`);
    }
    if (Object.keys(config).length === 0) {
        return { errors };
    }
    return { config, errors };
}
function loadConfigFile(level, deps, sourceLabel, options) {
    try {
        if (!deps.fs.exists(level.configPath)) {
            return { config: {}, errors: [] };
        }
        const content = deps.fs.readFile(level.configPath);
        const parsed = parseConfigJson(content, sourceLabel);
        if (parsed.data === undefined) {
            return { config: {}, errors: parsed.errors };
        }
        const validated = validateConfigData(parsed.data, sourceLabel, options);
        return { config: validated.config, errors: [...parsed.errors, ...validated.errors] };
    }
    catch (err) {
        return {
            config: {},
            errors: [
                `${sourceLabel}: failed to read config: ${err instanceof Error ? err.message : String(err)}`,
            ],
        };
    }
}
function mergeOptionalObject(target, overlay) {
    if (!target && !overlay) {
        return undefined;
    }
    return {
        ...(target ?? {}),
        ...(overlay ?? {}),
    };
}
function mergeSubagentsConfig(target, overlay) {
    if (!target && !overlay) {
        return undefined;
    }
    const merged = {
        ...(target ?? {}),
    };
    if (overlay?.defaultLaunchModels !== undefined) {
        merged.defaultLaunchModels = [...overlay.defaultLaunchModels];
    }
    return merged;
}
function mergeAsyncClientConfig(target, overlay) {
    if (!target && !overlay) {
        return undefined;
    }
    const merged = {
        ...(target ?? {}),
    };
    if (overlay?.defaultTarget !== undefined) {
        merged.defaultTarget = overlay.defaultTarget;
    }
    if (overlay?.defaultProjectId !== undefined) {
        merged.defaultProjectId = overlay.defaultProjectId;
    }
    if (target?.targets || overlay?.targets) {
        const targets = new Map();
        for (const [key, value] of Object.entries(target?.targets ?? {})) {
            targets.set(key, { ...value });
        }
        for (const [key, value] of Object.entries(overlay?.targets ?? {})) {
            targets.set(key, mergeOptionalObject(targets.get(key), value) ?? value);
        }
        if (targets.size > 0) {
            merged.targets = Object.fromEntries(targets.entries());
        }
    }
    return merged;
}
function mergeAsyncConfig(target, overlay) {
    if (!target && !overlay) {
        return undefined;
    }
    const merged = {
        ...(target ?? {}),
        ...(overlay ?? {}),
        client: mergeAsyncClientConfig(target?.client, overlay?.client),
    };
    return merged;
}
function resolveAgentContextPaths(level, rawPaths) {
    const root = level.levelRoot;
    return rawPaths.map((entry) => resolve(root, entry));
}
function resolveBashCommands(level, commands) {
    const root = level.levelRoot;
    return commands.map((cmd) => ({ ...cmd, cwd: root }));
}
function dedupePaths(paths) {
    const seen = new Set();
    const unique = [];
    for (const path of paths) {
        if (seen.has(path))
            continue;
        seen.add(path);
        unique.push(path);
    }
    return unique;
}
function mergeConfigLevels(levels, configs) {
    const merged = getVirtualConfigDefaults();
    let apiKeys;
    let diffTool;
    let builtInDiffTool;
    let subagents;
    let modelSystemNotices;
    let asyncConfig;
    const bashCommands = new Map();
    const agentContextFiles = [];
    for (let i = 0; i < levels.length; i += 1) {
        const level = levels[i];
        const config = configs[i] ?? {};
        apiKeys = mergeOptionalObject(apiKeys, config.apiKeys);
        if (config.diffTool !== undefined) {
            diffTool = resolveDiffToolConfig(level, config.diffTool);
        }
        if (config.builtInDiffTool !== undefined) {
            builtInDiffTool = { ...config.builtInDiffTool };
        }
        subagents = mergeSubagentsConfig(subagents, config.subagents);
        if (config.autoCompact !== undefined) {
            merged.autoCompact = mergeOptionalObject(merged.autoCompact, config.autoCompact);
        }
        modelSystemNotices = mergeOptionalObject(modelSystemNotices, config.modelSystemNotices);
        asyncConfig = mergeAsyncConfig(asyncConfig, config.async);
        if (config.defaultPersona !== undefined) {
            merged.defaultPersona = config.defaultPersona;
        }
        if (config.defaultRisk !== undefined) {
            merged.defaultRisk = config.defaultRisk;
        }
        if (config.disableBuiltinPersonas !== undefined) {
            merged.disableBuiltinPersonas = config.disableBuiltinPersonas;
        }
        if (config.disableBuiltinThemes !== undefined) {
            merged.disableBuiltinThemes = config.disableBuiltinThemes;
        }
        if (config.defaultTheme !== undefined) {
            merged.defaultTheme = config.defaultTheme;
        }
        if (config.bashCommands) {
            for (const cmd of resolveBashCommands(level, config.bashCommands)) {
                bashCommands.set(cmd.id.toLowerCase(), cmd);
            }
        }
        if (config.agentContextFiles) {
            agentContextFiles.push(...resolveAgentContextPaths(level, config.agentContextFiles));
        }
    }
    if (apiKeys && Object.keys(apiKeys).length > 0) {
        merged.apiKeys = apiKeys;
    }
    if (diffTool) {
        merged.diffTool = diffTool;
    }
    if (builtInDiffTool) {
        merged.builtInDiffTool = builtInDiffTool;
    }
    if (subagents && Object.keys(subagents).length > 0) {
        merged.subagents = subagents;
    }
    if (modelSystemNotices && Object.keys(modelSystemNotices).length > 0) {
        merged.modelSystemNotices = modelSystemNotices;
    }
    if (asyncConfig && Object.keys(asyncConfig).length > 0) {
        merged.async = asyncConfig;
    }
    if (bashCommands.size > 0) {
        merged.bashCommands = Array.from(bashCommands.values());
    }
    if (agentContextFiles.length > 0) {
        merged.agentContextFiles = dedupePaths(agentContextFiles);
    }
    return merged;
}
export function loadConfigWithDiagnostics(deps, options) {
    const modelResolverResult = options.modelResolver;
    const results = options.levels.map((level) => loadConfigFile(level, deps, level.configPath, {
        resolveModel: modelResolverResult.resolveModel,
        resolveConfiguredModel: modelResolverResult.resolveConfiguredModel,
    }));
    return {
        config: mergeConfigLevels(options.levels, results.map((result) => result.config)),
        errors: [...modelResolverResult.errors, ...results.flatMap((result) => result.errors)],
    };
}
export function loadConfig(cwd, deps) {
    const levels = resolveConfigLevels(deps, { cwd });
    const modelResolver = loadModelResolver({ deps, levels });
    return loadConfigWithDiagnostics(deps, { levels, modelResolver }).config;
}
export function getApiKeyForProvider(config, provider) {
    const apiKeys = config.apiKeys;
    if (!apiKeys) {
        return undefined;
    }
    const key = apiKeys[provider];
    if (typeof key !== "string") {
        return undefined;
    }
    const trimmed = key.trim();
    return trimmed || undefined;
}
function getTrimmedEnvValue(key, env) {
    const source = env ?? process.env;
    const value = source[key];
    if (typeof value !== "string") {
        return undefined;
    }
    const trimmed = value.trim();
    return trimmed || undefined;
}
export function getParallelApiKey(config, env) {
    const envKey = getTrimmedEnvValue("PARALLEL_API_KEY", env);
    if (envKey) {
        return envKey;
    }
    const configKey = config.apiKeys?.parallel?.trim();
    return configKey || undefined;
}
export function getMistralApiKey(config, env) {
    const envKey = getTrimmedEnvValue("MISTRAL_API_KEY", env);
    if (envKey) {
        return envKey;
    }
    const configKey = config.apiKeys?.mistral?.trim();
    return configKey || undefined;
}
//# sourceMappingURL=schema.js.map