/**
 * frameworkProcessSignals — per-framework predicates and grep needles
 * for finding agentic-CLI processes on the host.
 *
 * Provider-portability v1.0.0: before this module, OrphanProcessReaper
 * hardcoded Claude's binary patterns inline:
 *
 *   const claudeBinaryPattern = /(^|\/)claude(\s|$)/;
 *   const claudeNodePattern = /@anthropic-ai\/claude-code|claude-code\/cli/;
 *
 * That made the reaper blind to orphaned Codex processes — those would
 * accumulate forever, defeating the reaper's purpose. This module
 * exposes per-framework `binaryPattern`, `nodePattern`, exclusion list,
 * and `psGrepNeedle` (the bracket-escape pattern used in `ps … | grep`
 * to filter the process listing efficiently before parsing).
 *
 * The reaper iterates `listProcessSignals()` to scan EVERY known
 * framework on each poll — a user can have both Claude and Codex
 * installed and both can leak processes.
 */
const CLAUDE_CODE_SIGNAL = {
    framework: 'claude-code',
    displayName: 'Claude',
    psGrepNeedle: '[c]laude',
    binaryPattern: /(^|\/)claude(\s|$)/,
    nodePattern: /@anthropic-ai\/claude-code|claude-code\/cli/,
    exclusionSubstrings: [
        'claude-in-chrome',
        'claude-mcp',
        'playwright-mcp',
        'mcp-remote',
        'exa-mcp',
        'payments-mcp',
    ],
};
const CODEX_CLI_SIGNAL = {
    framework: 'codex-cli',
    displayName: 'Codex',
    psGrepNeedle: '[c]odex',
    binaryPattern: /(^|\/)codex(\s|$)/,
    // OpenAI's Codex CLI is published as @openai/codex-cli; older
    // experimental builds shipped under `codex-cli/` paths. Cover both.
    nodePattern: /@openai\/codex|codex-cli\/cli|codex-cli\/bin/,
    exclusionSubstrings: [
        'codex-mcp',
        // Common false-positive: VS Code "code" binary path can occur with
        // "x-codex" suffix in helper threads — covered by the binary-pattern
        // boundary, but explicit exclusion catches edge cases.
        'vscode-codex',
    ],
};
const GEMINI_CLI_SIGNAL = {
    framework: 'gemini-cli',
    displayName: 'Gemini',
    psGrepNeedle: '[g]emini',
    binaryPattern: /(^|\/)gemini(\s|$)/,
    // Gemini CLI is published as @google/gemini-cli; older/experimental builds
    // shipped under `gemini-cli/` paths. Cover both (node/npx-wrapped form).
    nodePattern: /@google\/gemini-cli|gemini-cli\/(cli|bin)/,
    exclusionSubstrings: [
        // `gemini mcp` server shares the prefix and must NOT be counted as a
        // framework session — the analog of codex's 'codex-mcp' exclusion.
        'gemini-mcp',
    ],
};
const PI_CLI_SIGNAL = {
    framework: 'pi-cli',
    displayName: 'Pi',
    // "pi" is a dangerously short token — the bracket-needle over-matches
    // (pip, pipx, api servers, …) but it is only a ps pre-filter; the
    // word-boundary binaryPattern below does the real discrimination, and the
    // exclusions catch the common short-prefix collisions explicitly.
    psGrepNeedle: '[p]i',
    binaryPattern: /(^|\/)pi(\s|$)/,
    // pi is published as @earendil-works/pi-coding-agent (formerly
    // @mariozechner/pi-coding-agent). Cover both node/npx-wrapped forms.
    nodePattern: /@earendil-works\/pi-coding-agent|@mariozechner\/pi-coding-agent|pi-coding-agent\/(dist|bin|cli)/,
    exclusionSubstrings: [
        // Python tooling shares the prefix and must never be counted as a
        // framework session.
        'pip ',
        'pipx ',
        // pi's own monorepo dev processes (pi-mono checkout scripts).
        'pi-mono',
    ],
};
const PROCESS_SIGNALS = {
    'claude-code': CLAUDE_CODE_SIGNAL,
    'codex-cli': CODEX_CLI_SIGNAL,
    'gemini-cli': GEMINI_CLI_SIGNAL,
    'pi-cli': PI_CLI_SIGNAL,
};
/** Process helpers that appear at the START of command lines and are NEVER framework binaries. */
const COMMON_HELPER_PROCESSES = [
    'cloudflared',
    'caffeinate',
    'tee',
    'tail',
    'cat',
    'grep',
    'awk',
    'sed',
];
/**
 * Decide whether `command` looks like one of the configured framework
 * binaries. Returns the matched signal or null. Centralizes the helper-
 * prefix check (`cloudflared`, `caffeinate`, etc.) so each framework
 * doesn't have to re-implement it.
 */
export function matchProcessSignal(command, signals = listProcessSignals()) {
    const trimmed = command.trimStart();
    for (const helper of COMMON_HELPER_PROCESSES) {
        if (trimmed.startsWith(helper))
            return null;
    }
    for (const signal of signals) {
        if (signal.binaryPattern.test(command) || signal.nodePattern.test(command)) {
            if (signal.exclusionSubstrings.some(e => command.includes(e)))
                continue;
            return signal;
        }
    }
    return null;
}
/**
 * Enumerate every known framework signal. Used by the reaper to
 * build the ps-grep pipeline and to scan against every framework.
 */
export function listProcessSignals() {
    return Object.keys(PROCESS_SIGNALS).map(f => PROCESS_SIGNALS[f]);
}
/**
 * Get the signal for a specific framework. Returns null when the
 * framework is unrecognized (typed shouldn't happen, but defensive).
 */
export function getProcessSignal(framework) {
    return PROCESS_SIGNALS[framework] ?? null;
}
/**
 * Common helper-process prefix list — exported for tests that want to
 * verify the reaper's helper-rejection logic without duplicating it.
 */
export function listCommonHelperProcesses() {
    return COMMON_HELPER_PROCESSES;
}
//# sourceMappingURL=frameworkProcessSignals.js.map