const DEFAULT_KEEP_ALIVE = new Set(['chrome-devtools', 'mobile-mcp', 'playwright']);
const includeOverride = parseList(process.env.MCPORTER_KEEPALIVE);
const excludeOverride = parseList(process.env.MCPORTER_DISABLE_KEEPALIVE ?? process.env.MCPORTER_NO_KEEPALIVE);
const KEEP_ALIVE_COMMANDS = [
    { label: 'chrome-devtools', fragments: ['chrome-devtools-mcp'] },
    { label: 'mobile-mcp', fragments: ['@mobilenext/mobile-mcp', 'mobile-mcp'] },
    { label: 'playwright', fragments: ['@playwright/mcp', 'playwright/mcp'] },
];
const CHROME_DEVTOOLS_URL_PLACEHOLDERS = [String.raw `\${CHROME_DEVTOOLS_URL}`, '$env:CHROME_DEVTOOLS_URL'];
export function resolveLifecycle(name, rawLifecycle, command) {
    const normalizedName = name.toLowerCase();
    const canonicalName = canonicalKeepAliveName(command);
    const candidateNames = new Set([normalizedName]);
    if (canonicalName) {
        candidateNames.add(canonicalName);
    }
    const forcedDisable = excludeOverride.all || matchesOverride(excludeOverride.names, candidateNames);
    const forcedEnable = includeOverride.all || matchesOverride(includeOverride.names, candidateNames);
    if (forcedEnable) {
        return { mode: 'keep-alive' };
    }
    if (forcedDisable) {
        return undefined;
    }
    const lifecycle = rawLifecycle ? coerceLifecycle(rawLifecycle) : undefined;
    if (lifecycle) {
        return lifecycle;
    }
    if (commandRequiresDynamicChromePort(command)) {
        // Each Chrome DevTools MCP instance is tied to a specific Chrome port. Opt out of keep-alive so
        // the runtime (and daemon) relaunches the bridge whenever CHROME_DEVTOOLS_URL changes.
        return { mode: 'ephemeral' };
    }
    if (Array.from(candidateNames).some((candidate) => DEFAULT_KEEP_ALIVE.has(candidate))) {
        return { mode: 'keep-alive' };
    }
    return undefined;
}
export function canonicalKeepAliveName(command) {
    if (command.kind !== 'stdio') {
        return undefined;
    }
    const tokens = [command.command, ...command.args].map((token) => token.toLowerCase());
    const match = KEEP_ALIVE_COMMANDS.find((signature) => signature.fragments.some((fragment) => tokens.some((token) => token.includes(fragment))));
    return match?.label;
}
function commandRequiresDynamicChromePort(command) {
    if (command.kind !== 'stdio') {
        return false;
    }
    const tokens = [command.command, ...command.args];
    return tokens.some((token) => CHROME_DEVTOOLS_URL_PLACEHOLDERS.some((placeholder) => token.includes(placeholder)));
}
function parseList(value) {
    if (!value) {
        return { all: false, names: new Set() };
    }
    const names = value
        .split(',')
        .map((token) => token.trim().toLowerCase())
        .filter((token) => token.length > 0);
    if (names.includes('*')) {
        return { all: true, names: new Set() };
    }
    return { all: false, names: new Set(names) };
}
function matchesOverride(names, candidates) {
    for (const candidate of candidates) {
        if (names.has(candidate)) {
            return true;
        }
    }
    return false;
}
function coerceLifecycle(raw) {
    if (typeof raw === 'string') {
        if (raw === 'keep-alive') {
            return { mode: 'keep-alive' };
        }
        if (raw === 'ephemeral') {
            return { mode: 'ephemeral' };
        }
        return undefined;
    }
    if (raw.mode === 'keep-alive') {
        const timeout = typeof raw.idleTimeoutMs === 'number' && Number.isFinite(raw.idleTimeoutMs) && raw.idleTimeoutMs > 0
            ? Math.trunc(raw.idleTimeoutMs)
            : undefined;
        return timeout ? { mode: 'keep-alive', idleTimeoutMs: timeout } : { mode: 'keep-alive' };
    }
    if (raw.mode === 'ephemeral') {
        return { mode: 'ephemeral' };
    }
    return undefined;
}
export function isKeepAliveServer(definition) {
    return definition?.lifecycle?.mode === 'keep-alive';
}
export function keepAliveIdleTimeout(definition) {
    if (definition.lifecycle?.mode !== 'keep-alive') {
        return undefined;
    }
    return definition.lifecycle.idleTimeoutMs;
}
export { DEFAULT_KEEP_ALIVE };
//# sourceMappingURL=lifecycle.js.map