"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildSetupStatusResponse = buildSetupStatusResponse;
exports.buildSetupFileResponse = buildSetupFileResponse;
exports.handleWriteShellEnv = handleWriteShellEnv;
exports.handleWriteTeamYaml = handleWriteTeamYaml;
exports.handleWriteRtwsLlmYaml = handleWriteRtwsLlmYaml;
const fs_1 = __importDefault(require("fs"));
const promises_1 = __importDefault(require("fs/promises"));
const os_1 = __importDefault(require("os"));
const path_1 = __importDefault(require("path"));
const yaml_1 = __importDefault(require("yaml"));
const client_1 = require("../llm/client");
const log_1 = require("../log");
const team_config_updates_1 = require("../team-config-updates");
const log = (0, log_1.createLogger)('setup-routes');
const TEAM_YAML_PATH = path_1.default.join('.minds', 'team.yaml');
const RTWS_LLM_YAML_PATH = path_1.default.join('.minds', 'llm.yaml');
const RTWS_ENV_LOCAL_PATH = '.env.local';
const DOMINDS_ENV_BLOCK_START = '# >>> dominds env >>>';
const DOMINDS_ENV_BLOCK_END = '# <<< dominds env <<<';
async function buildSetupStatusResponse() {
    const builtin = await loadBuiltinProviders();
    const merged = await client_1.LlmConfig.load();
    const shellPlatform = resolveSetupPlatform(process.platform);
    const shellEnv = typeof process.env.SHELL === 'string' ? process.env.SHELL : null;
    const shellKind = resolveShellKind(shellEnv);
    const envLocal = await statRcFile(RTWS_ENV_LOCAL_PATH);
    const home = os_1.default.homedir();
    const bashrcPath = path_1.default.join(home, '.bashrc');
    const zshrcPath = path_1.default.join(home, '.zshrc');
    const rc = {
        bashrc: await statRcFile(bashrcPath),
        zshrc: await statRcFile(zshrcPath),
    };
    const teamYaml = await readTeamYamlMemberDefaults();
    const requirement = await resolveSetupRequirement({
        teamYaml,
        llmProviders: merged.providers,
    });
    const rtwsLlmYaml = await readRtwsLlmYamlProviderKeys();
    if (builtin.kind === 'error') {
        return {
            success: false,
            requirement,
            shell: {
                platform: shellPlatform,
                env: shellEnv,
                kind: shellKind,
                defaultRc: shellKindToDefaultRc(shellKind),
            },
            envLocal,
            rc,
            teamYaml,
            rtwsLlmYaml,
            providers: [],
            error: builtin.errorText,
        };
    }
    const providerKeysInOrder = mergeProviderKeysInOrder(rtwsLlmYaml.providerKeys ?? [], builtin.providerKeysInOrder, merged.providers);
    const providers = await buildProviderSummaries(merged.providers, providerKeysInOrder, {
        envLocalPath: RTWS_ENV_LOCAL_PATH,
        bashrcPath,
        zshrcPath,
    });
    return {
        success: true,
        requirement,
        shell: {
            platform: shellPlatform,
            env: shellEnv,
            kind: shellKind,
            defaultRc: shellKindToDefaultRc(shellKind),
        },
        envLocal,
        rc,
        teamYaml,
        rtwsLlmYaml,
        providers,
    };
}
async function buildSetupFileResponse(kind) {
    if (kind === 'defaults_yaml') {
        const builtinDefaultsYamlPath = (0, client_1.getBuiltinDefaultsYamlPath)();
        try {
            const raw = await (0, client_1.readBuiltinDefaultsYamlRaw)();
            return { success: true, kind, path: builtinDefaultsYamlPath, raw };
        }
        catch {
            return {
                success: false,
                kind,
                path: builtinDefaultsYamlPath,
                error: 'Failed to read defaults.yaml',
            };
        }
    }
    if (kind === 'rtws_llm_yaml') {
        const p = RTWS_LLM_YAML_PATH;
        const exists = await fileExists(p);
        if (!exists) {
            return { success: false, kind, path: p, error: 'Missing .minds/llm.yaml' };
        }
        try {
            const raw = await promises_1.default.readFile(p, 'utf-8');
            return { success: true, kind, path: p, raw };
        }
        catch {
            return { success: false, kind, path: p, error: 'Failed to read .minds/llm.yaml' };
        }
    }
    const _exhaustive = kind;
    return { success: false, kind: _exhaustive, path: '', error: 'Unsupported kind' };
}
async function handleWriteShellEnv(rawBody) {
    let parsed;
    try {
        parsed = rawBody ? JSON.parse(rawBody) : {};
    }
    catch {
        return { kind: 'bad_request', errorText: 'Invalid JSON body' };
    }
    const req = parseWriteShellEnvRequest(parsed);
    if (!req) {
        return { kind: 'bad_request', errorText: 'Invalid request body' };
    }
    const allowed = await buildAllowedEnvVarSet();
    if (!allowed.has(req.envVar)) {
        return { kind: 'bad_request', errorText: `Unsupported env var: ${req.envVar}` };
    }
    try {
        // Apply to the current backend process immediately so setup can proceed without a restart.
        process.env[req.envVar] = req.value;
        let filePath;
        let result;
        if (req.target === 'env_local') {
            filePath = RTWS_ENV_LOCAL_PATH;
            result = await upsertEnvVarIntoDotenvFile(filePath, req.envVar, req.value);
        }
        else {
            if (!isPosixSetupPlatform(process.platform)) {
                return {
                    kind: 'bad_request',
                    errorText: `Unsupported target on this platform: ${req.target}`,
                };
            }
            const home = os_1.default.homedir();
            filePath = path_1.default.join(home, req.target === 'bashrc' ? '.bashrc' : '.zshrc');
            result = await upsertEnvVarIntoRcFile(filePath, req.envVar, req.value);
        }
        return {
            kind: 'ok',
            response: { success: true, outcome: { target: req.target, path: filePath, result } },
        };
    }
    catch (error) {
        log.error('Failed to write shell env vars', error);
        return { kind: 'error', errorText: 'Failed to write shell env vars' };
    }
}
async function handleWriteTeamYaml(rawBody) {
    const outPath = TEAM_YAML_PATH;
    let parsed;
    try {
        parsed = rawBody ? JSON.parse(rawBody) : {};
    }
    catch {
        return { kind: 'bad_request', errorText: 'Invalid JSON body', path: outPath };
    }
    const req = parseWriteTeamYamlRequest(parsed);
    if (!req) {
        return { kind: 'bad_request', errorText: 'Invalid request body', path: outPath };
    }
    const llmCfg = await client_1.LlmConfig.load();
    const providerCfg = llmCfg.providers[req.provider];
    if (!providerCfg) {
        return { kind: 'bad_request', errorText: `Unknown provider: ${req.provider}`, path: outPath };
    }
    const models = providerCfg.models ?? {};
    if (!Object.prototype.hasOwnProperty.call(models, req.model)) {
        return {
            kind: 'bad_request',
            errorText: `Unknown model for provider ${req.provider}: ${req.model}`,
            path: outPath,
        };
    }
    const exists = await fileExists(outPath);
    if (exists && req.overwrite !== true) {
        return { kind: 'conflict', errorText: 'team.yaml already exists', path: outPath };
    }
    try {
        await promises_1.default.mkdir(path_1.default.dirname(outPath), { recursive: true });
        const content = buildMinimalTeamYaml(req);
        await promises_1.default.writeFile(outPath, content, 'utf-8');
        (0, team_config_updates_1.notifyTeamConfigUpdated)(`setup.write_team_yaml/${exists ? 'overwritten' : 'created'}`);
        return {
            kind: 'ok',
            response: {
                success: true,
                path: outPath,
                action: exists ? 'overwritten' : 'created',
            },
        };
    }
    catch (error) {
        log.error('Failed to write team.yaml', error);
        return { kind: 'error', errorText: 'Failed to write team.yaml', path: outPath };
    }
}
async function handleWriteRtwsLlmYaml(rawBody) {
    const outPath = RTWS_LLM_YAML_PATH;
    let parsed;
    try {
        parsed = rawBody ? JSON.parse(rawBody) : {};
    }
    catch {
        return { kind: 'bad_request', errorText: 'Invalid JSON body', path: outPath };
    }
    const req = parseWriteRtwsLlmYamlRequest(parsed);
    if (!req) {
        return { kind: 'bad_request', errorText: 'Invalid request body', path: outPath };
    }
    // Guardrails: ensure it is valid YAML and has a providers object.
    try {
        const parsedYaml = yaml_1.default.parse(req.raw);
        if (!isRecord(parsedYaml) || !isRecord(parsedYaml['providers'])) {
            return {
                kind: 'bad_request',
                errorText: 'Invalid llm.yaml: expected a top-level providers object',
                path: outPath,
            };
        }
    }
    catch {
        return { kind: 'bad_request', errorText: 'Invalid YAML content', path: outPath };
    }
    const exists = await fileExists(outPath);
    if (exists && req.overwrite !== true) {
        return { kind: 'conflict', errorText: 'llm.yaml already exists', path: outPath };
    }
    try {
        await promises_1.default.mkdir(path_1.default.dirname(outPath), { recursive: true });
        await promises_1.default.writeFile(outPath, req.raw.endsWith('\n') ? req.raw : `${req.raw}\n`, 'utf-8');
        return {
            kind: 'ok',
            response: {
                success: true,
                path: outPath,
                action: exists ? 'overwritten' : 'created',
            },
        };
    }
    catch (error) {
        log.error('Failed to write llm.yaml', error);
        return { kind: 'error', errorText: 'Failed to write llm.yaml', path: outPath };
    }
}
async function loadBuiltinProviders() {
    try {
        const raw = await (0, client_1.readBuiltinDefaultsYamlRaw)();
        const doc = yaml_1.default.parseDocument(raw);
        const parsed = doc.toJS();
        if (!isRecord(parsed) || !isRecord(parsed.providers)) {
            return { kind: 'error', errorText: 'Invalid defaults.yaml: expected providers object' };
        }
        const providerKeysInOrder = extractProvidersKeysFromYamlDoc(doc);
        return {
            kind: 'ok',
            providers: parsed.providers,
            providerKeysInOrder,
        };
    }
    catch (error) {
        return { kind: 'error', errorText: 'Failed to load defaults.yaml' };
    }
}
async function buildAllowedEnvVarSet() {
    const out = new Set();
    const builtin = await loadBuiltinProviders();
    if (builtin.kind === 'ok') {
        for (const provider of Object.values(builtin.providers)) {
            if (typeof provider.apiKeyEnvVar === 'string')
                out.add(provider.apiKeyEnvVar);
        }
    }
    const merged = await client_1.LlmConfig.load();
    for (const provider of Object.values(merged.providers)) {
        if (typeof provider.apiKeyEnvVar === 'string')
            out.add(provider.apiKeyEnvVar);
    }
    return out;
}
async function buildProviderSummaries(providers, providerKeysInOrder, paths) {
    const envSet = [];
    const envMissing = [];
    for (const [providerKey, cfg] of orderedProviderEntries(providers, providerKeysInOrder)) {
        const envVar = cfg.apiKeyEnvVar;
        const envVarIsSet = typeof process.env[envVar] === 'string' && process.env[envVar] !== '';
        const envLocalHas = await fileHasEnvVar(paths.envLocalPath, envVar);
        const bashrcHas = await fileHasEnvVar(paths.bashrcPath, envVar);
        const zshrcHas = await fileHasEnvVar(paths.zshrcPath, envVar);
        const models = Object.entries(cfg.models ?? {}).map(([modelKey, modelInfo]) => {
            const info = isRecord(modelInfo) ? modelInfo : {};
            const name = typeof info.name === 'string' ? info.name : undefined;
            const contextWindow = typeof info.context_window === 'string' ? info.context_window : undefined;
            const contextLength = typeof info.context_length === 'number' ? info.context_length : undefined;
            const inputLength = typeof info.input_length === 'number' ? info.input_length : undefined;
            const outputLength = typeof info.output_length === 'number' ? info.output_length : undefined;
            return {
                key: modelKey,
                name,
                contextWindow,
                contextLength,
                inputLength,
                outputLength,
                verified: envVarIsSet,
            };
        });
        const prominent = extractProminentModelParams(cfg.model_param_options);
        const summary = {
            providerKey,
            name: cfg.name,
            apiType: cfg.apiType,
            baseUrl: cfg.baseUrl,
            apiKeyEnvVar: envVar,
            techSpecUrl: cfg.tech_spec_url,
            apiMgmtUrl: cfg.api_mgmt_url,
            envVar: { isSet: envVarIsSet, envLocalHas, bashrcHas, zshrcHas },
            models,
            ...(prominent.length > 0 ? { prominentModelParams: prominent } : {}),
        };
        // Keep YAML order stable, but list env-var-ready providers first.
        if (envVarIsSet) {
            envSet.push(summary);
        }
        else {
            envMissing.push(summary);
        }
    }
    return [...envSet, ...envMissing];
}
function extractProminentModelParams(modelParamOptions) {
    if (!modelParamOptions)
        return [];
    const out = [];
    const sections = [];
    const addSection = (namespace, section) => {
        if (section && typeof section === 'object') {
            sections.push([namespace, section]);
        }
    };
    addSection('codex', modelParamOptions.codex);
    addSection('openai', modelParamOptions.openai);
    addSection('openai-compatible', modelParamOptions['openai-compatible']);
    addSection('anthropic', modelParamOptions.anthropic);
    addSection('anthropic-compatible', modelParamOptions['anthropic-compatible']);
    for (const [namespace, section] of sections) {
        for (const [key, optUnknown] of Object.entries(section)) {
            if (!optUnknown || typeof optUnknown !== 'object')
                continue;
            const opt = optUnknown;
            if (opt.prominent !== true)
                continue;
            if (typeof opt.description !== 'string')
                continue;
            if (opt.type === 'boolean' || opt.type === 'boolean|object') {
                out.push({
                    kind: 'boolean',
                    namespace,
                    key,
                    description: opt.description,
                    ...(typeof opt.default === 'boolean' ? { defaultValue: opt.default } : {}),
                });
                continue;
            }
            if (opt.type !== 'enum')
                continue;
            if (!Array.isArray(opt.values) || !opt.values.every((v) => typeof v === 'string'))
                continue;
            const defaultValue = typeof opt.default === 'string' && opt.values.includes(opt.default)
                ? opt.default
                : undefined;
            const rawValueLabels = opt.value_labels;
            let valueLabels;
            if (rawValueLabels && typeof rawValueLabels === 'object' && !Array.isArray(rawValueLabels)) {
                const next = {};
                for (const [rawKey, rawLabel] of Object.entries(rawValueLabels)) {
                    if (!opt.values.includes(rawKey))
                        continue;
                    if (typeof rawLabel !== 'string' || rawLabel.length === 0)
                        continue;
                    next[rawKey] = rawLabel;
                }
                if (Object.keys(next).length > 0)
                    valueLabels = next;
            }
            out.push({
                kind: 'enum',
                namespace,
                key,
                description: opt.description,
                values: opt.values,
                ...(valueLabels ? { valueLabels } : {}),
                ...(defaultValue ? { defaultValue } : {}),
            });
        }
    }
    return out;
}
function orderedProviderEntries(providers, providerKeysInOrder) {
    const out = [];
    const seen = new Set();
    for (const k of providerKeysInOrder) {
        const cfg = providers[k];
        if (!cfg)
            continue;
        out.push([k, cfg]);
        seen.add(k);
    }
    // Any providers not present in the YAML map (should be rare) are appended.
    for (const [k, cfg] of Object.entries(providers)) {
        if (seen.has(k))
            continue;
        out.push([k, cfg]);
    }
    return out;
}
function mergeProviderKeysInOrder(preferredProviderKeysInOrder, secondaryProviderKeysInOrder, providers) {
    const out = [];
    const seen = new Set();
    const appendKey = (providerKey) => {
        if (providerKey === '' || seen.has(providerKey))
            return;
        if (!Object.prototype.hasOwnProperty.call(providers, providerKey))
            return;
        out.push(providerKey);
        seen.add(providerKey);
    };
    for (const providerKey of preferredProviderKeysInOrder)
        appendKey(providerKey);
    for (const providerKey of secondaryProviderKeysInOrder)
        appendKey(providerKey);
    for (const providerKey of Object.keys(providers))
        appendKey(providerKey);
    return out;
}
function extractYamlMapStringKeys(value) {
    if (!yaml_1.default.isMap(value))
        return [];
    const out = [];
    for (const pair of value.items) {
        if (!yaml_1.default.isPair(pair))
            continue;
        const keyNode = pair.key;
        if (!yaml_1.default.isScalar(keyNode))
            continue;
        const keyValue = keyNode.value;
        if (typeof keyValue !== 'string' || keyValue === '')
            continue;
        out.push(keyValue);
    }
    return out;
}
function extractProvidersKeysFromYamlDoc(doc) {
    const root = doc.contents;
    if (!yaml_1.default.isMap(root))
        return [];
    for (const pair of root.items) {
        if (!yaml_1.default.isPair(pair))
            continue;
        const keyNode = pair.key;
        if (!yaml_1.default.isScalar(keyNode))
            continue;
        if (keyNode.value !== 'providers')
            continue;
        const valNode = pair.value;
        return extractYamlMapStringKeys(valNode);
    }
    return [];
}
async function statRcFile(filePath) {
    const exists = await fileExists(filePath);
    const writable = exists ? await isWritable(filePath) : await isWritable(path_1.default.dirname(filePath));
    return { path: filePath, exists, writable };
}
async function readTeamYamlMemberDefaults() {
    const exists = await fileExists(TEAM_YAML_PATH);
    if (!exists)
        return { path: TEAM_YAML_PATH, exists: false };
    try {
        const raw = await promises_1.default.readFile(TEAM_YAML_PATH, 'utf-8');
        const parsed = yaml_1.default.parse(raw);
        if (!isRecord(parsed)) {
            return {
                path: TEAM_YAML_PATH,
                exists: true,
                parseError: 'Invalid team.yaml (not an object)',
            };
        }
        const memberDefaultsUnknown = parsed['member_defaults'];
        if (!isRecord(memberDefaultsUnknown)) {
            return {
                path: TEAM_YAML_PATH,
                exists: true,
                parseError: 'Invalid team.yaml (missing member_defaults object)',
            };
        }
        const provider = typeof memberDefaultsUnknown['provider'] === 'string'
            ? memberDefaultsUnknown['provider']
            : undefined;
        const model = typeof memberDefaultsUnknown['model'] === 'string'
            ? memberDefaultsUnknown['model']
            : undefined;
        return { path: TEAM_YAML_PATH, exists: true, memberDefaults: { provider, model } };
    }
    catch (error) {
        return { path: TEAM_YAML_PATH, exists: true, parseError: 'Failed to parse team.yaml' };
    }
}
async function readRtwsLlmYamlProviderKeys() {
    const exists = await fileExists(RTWS_LLM_YAML_PATH);
    if (!exists)
        return { path: RTWS_LLM_YAML_PATH, exists: false };
    try {
        const raw = await promises_1.default.readFile(RTWS_LLM_YAML_PATH, 'utf-8');
        const doc = yaml_1.default.parseDocument(raw);
        const parsed = doc.toJS();
        if (!isRecord(parsed)) {
            return {
                path: RTWS_LLM_YAML_PATH,
                exists: true,
                parseError: 'Invalid llm.yaml (not an object)',
            };
        }
        const providersUnknown = parsed['providers'];
        if (!isRecord(providersUnknown)) {
            return {
                path: RTWS_LLM_YAML_PATH,
                exists: true,
                parseError: 'Invalid llm.yaml (missing providers object)',
            };
        }
        return {
            path: RTWS_LLM_YAML_PATH,
            exists: true,
            providerKeys: extractProvidersKeysFromYamlDoc(doc),
        };
    }
    catch (error) {
        return { path: RTWS_LLM_YAML_PATH, exists: true, parseError: 'Failed to parse llm.yaml' };
    }
}
async function resolveSetupRequirement(params) {
    const ty = params.teamYaml;
    if (!ty.exists) {
        return { kind: 'missing_team_yaml', teamYamlPath: ty.path };
    }
    if (typeof ty.parseError === 'string') {
        return { kind: 'invalid_team_yaml', teamYamlPath: ty.path, errorText: ty.parseError };
    }
    const md = ty.memberDefaults;
    if (!md ||
        typeof md.provider !== 'string' ||
        md.provider === '' ||
        typeof md.model !== 'string' ||
        md.model === '') {
        const missing = [];
        if (!md || typeof md.provider !== 'string' || md.provider === '')
            missing.push('provider');
        if (!md || typeof md.model !== 'string' || md.model === '')
            missing.push('model');
        return { kind: 'missing_member_defaults_fields', teamYamlPath: ty.path, missing };
    }
    const providerKey = md.provider;
    const modelKey = md.model;
    const providerCfg = params.llmProviders[providerKey];
    if (!providerCfg) {
        return { kind: 'unknown_provider', provider: providerKey };
    }
    const models = providerCfg.models ?? {};
    if (!Object.prototype.hasOwnProperty.call(models, modelKey)) {
        return { kind: 'unknown_model', provider: providerKey, model: modelKey };
    }
    const envVar = providerCfg.apiKeyEnvVar;
    const rawEnv = process.env[envVar];
    const envSet = typeof rawEnv === 'string' && rawEnv !== '';
    if (!envSet) {
        return { kind: 'missing_provider_env', provider: providerKey, envVar };
    }
    return { kind: 'ok' };
}
function resolveSetupPlatform(platform) {
    if (platform === 'win32')
        return 'windows';
    if (platform === 'darwin')
        return 'macos';
    if (platform === 'linux')
        return 'linux';
    return 'other';
}
function isPosixSetupPlatform(platform) {
    return platform === 'darwin' || platform === 'linux';
}
function resolveShellKind(shellEnv) {
    if (!shellEnv)
        return 'other';
    const base = path_1.default.basename(shellEnv);
    if (base === 'zsh')
        return 'zsh';
    if (base === 'bash')
        return 'bash';
    return 'other';
}
function shellKindToDefaultRc(kind) {
    if (kind === 'bash')
        return 'bashrc';
    if (kind === 'zsh')
        return 'zshrc';
    return 'unknown';
}
function parseWriteShellEnvRequest(value) {
    if (!isRecord(value))
        return null;
    const envVar = value['envVar'];
    const rawVal = value['value'];
    const target = value['target'];
    if (typeof envVar !== 'string' || !isSafeEnvVarName(envVar))
        return null;
    if (typeof rawVal !== 'string')
        return null;
    if (target !== 'env_local' && target !== 'bashrc' && target !== 'zshrc')
        return null;
    return { envVar, value: rawVal, target };
}
function parseWriteTeamYamlRequest(value) {
    if (!isRecord(value))
        return null;
    const provider = value['provider'];
    const model = value['model'];
    const overwrite = value['overwrite'];
    if (typeof provider !== 'string' || provider === '')
        return null;
    if (typeof model !== 'string' || model === '')
        return null;
    if (typeof overwrite !== 'boolean')
        return null;
    const modelParamsUnknown = value['modelParams'];
    const modelParams = parseOptionalTeamModelParams(modelParamsUnknown);
    if (modelParamsUnknown !== undefined && !modelParams)
        return null;
    return modelParams ? { provider, model, overwrite, modelParams } : { provider, model, overwrite };
}
function parseWriteRtwsLlmYamlRequest(value) {
    if (!isRecord(value))
        return null;
    const raw = value['raw'];
    const overwrite = value['overwrite'];
    if (typeof raw !== 'string')
        return null;
    if (typeof overwrite !== 'boolean')
        return null;
    return { raw, overwrite };
}
function buildMinimalTeamYaml(req) {
    // Minimal config, intentionally no members.
    const memberDefaults = {
        provider: req.provider,
        model: req.model,
    };
    if (req.modelParams && Object.keys(req.modelParams).length > 0) {
        memberDefaults['model_params'] = req.modelParams;
    }
    const doc = { member_defaults: memberDefaults };
    return yaml_1.default.stringify(doc);
}
function parseOptionalTeamModelParams(value) {
    if (value === undefined)
        return null;
    if (!isRecord(value))
        return null;
    const out = {};
    for (const [namespace, nsUnknown] of Object.entries(value)) {
        if (namespace !== 'codex' &&
            namespace !== 'openai' &&
            namespace !== 'openai-compatible' &&
            namespace !== 'anthropic' &&
            namespace !== 'anthropic-compatible')
            return null;
        if (!isRecord(nsUnknown))
            return null;
        const nsOut = {};
        for (const [k, v] of Object.entries(nsUnknown)) {
            if (typeof v !== 'string' && typeof v !== 'boolean')
                return null;
            if (v === '')
                continue;
            nsOut[k] = v;
        }
        if (Object.keys(nsOut).length > 0)
            out[namespace] = nsOut;
    }
    return Object.keys(out).length > 0 ? out : {};
}
function isSafeEnvVarName(name) {
    return /^[A-Z_][A-Z0-9_]*$/.test(name);
}
async function fileExists(filePath) {
    try {
        await promises_1.default.access(filePath, fs_1.default.constants.F_OK);
        return true;
    }
    catch {
        return false;
    }
}
async function isWritable(filePath) {
    try {
        await promises_1.default.access(filePath, fs_1.default.constants.W_OK);
        return true;
    }
    catch {
        return false;
    }
}
async function fileHasEnvVar(filePath, envVar) {
    try {
        const raw = await promises_1.default.readFile(filePath, 'utf-8');
        const re = new RegExp(`(^|\\n)\\s*(?:export\\s+)?${escapeRegExp(envVar)}\\s*=`, 'm');
        return re.test(raw);
    }
    catch {
        return false;
    }
}
function escapeRegExp(value) {
    return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function shellQuoteSingle(value) {
    // Safe POSIX shell single-quoted string: close quote, escape single quote, reopen.
    return `'${value.replace(/'/g, "'\\''")}'`;
}
function dotenvQuoteDouble(value) {
    const escaped = value
        .replace(/\\/g, '\\\\')
        .replace(/\n/g, '\\n')
        .replace(/\r/g, '\\r')
        .replace(/\t/g, '\\t')
        .replace(/"/g, '\\"');
    return `"${escaped}"`;
}
async function upsertEnvVarIntoDotenvFile(filePath, envVar, value) {
    const line = `${envVar}=${dotenvQuoteDouble(value)}`;
    const exists = await fileExists(filePath);
    const original = exists ? await promises_1.default.readFile(filePath, 'utf-8') : '';
    const normalized = original.replace(/\r\n/g, '\n');
    const lines = normalized === '' ? [] : normalized.split('\n');
    const nextLines = upsertDotenvLine(lines, envVar, line);
    let next = nextLines.join('\n');
    if (!next.endsWith('\n'))
        next += '\n';
    await promises_1.default.writeFile(filePath, next, 'utf-8');
    return exists ? 'updated' : 'created';
}
async function upsertEnvVarIntoRcFile(filePath, envVar, value) {
    const exportLine = `export ${envVar}=${shellQuoteSingle(value)}`;
    const exists = await fileExists(filePath);
    const original = exists ? await promises_1.default.readFile(filePath, 'utf-8') : '';
    const normalized = original.replace(/\r\n/g, '\n');
    const lines = normalized === '' ? [] : normalized.split('\n');
    const startIdx = lines.findIndex((l) => l.trim() === DOMINDS_ENV_BLOCK_START);
    const endIdx = lines.findIndex((l) => l.trim() === DOMINDS_ENV_BLOCK_END);
    let nextLines = lines;
    if (startIdx >= 0 && endIdx > startIdx) {
        const blockLines = lines.slice(startIdx + 1, endIdx);
        const updatedBlock = upsertExportLine(blockLines, envVar, exportLine);
        nextLines = [...lines.slice(0, startIdx + 1), ...updatedBlock, ...lines.slice(endIdx)];
    }
    else {
        // Append a new managed block.
        const block = [DOMINDS_ENV_BLOCK_START, exportLine, DOMINDS_ENV_BLOCK_END];
        const joiner = nextLines.length > 0 ? [''] : [];
        nextLines = [...nextLines, ...joiner, ...block];
    }
    // Ensure file ends with newline for friendliness.
    let next = nextLines.join('\n');
    if (!next.endsWith('\n'))
        next += '\n';
    await promises_1.default.writeFile(filePath, next, 'utf-8');
    return exists ? 'updated' : 'created';
}
function upsertDotenvLine(lines, envVar, envLine) {
    const re = new RegExp(`^\\s*(?:export\\s+)?${escapeRegExp(envVar)}\\s*=`);
    const idx = lines.findIndex((l) => re.test(l));
    if (idx >= 0) {
        const copy = [...lines];
        copy[idx] = envLine;
        return copy;
    }
    return [...lines, envLine];
}
function upsertExportLine(lines, envVar, exportLine) {
    const re = new RegExp(`^\\s*export\\s+${escapeRegExp(envVar)}=`);
    const idx = lines.findIndex((l) => re.test(l));
    if (idx >= 0) {
        const copy = [...lines];
        copy[idx] = exportLine;
        return copy;
    }
    return [...lines, exportLine];
}
function isRecord(value) {
    return typeof value === 'object' && value !== null;
}
