/**
 * Capability gate for agent features.
 *
 * Every install path that touches an agent-version (hooks, plugins, MCP,
 * skills, commands) calls `supports(agent, cap, version?)` before writing to
 * the version's config dir. When the capability is unsupported or the version
 * is below `since`, the install path skips the write and surfaces a clear
 * reason instead of silently corrupting an older binary's settings file.
 */
import { AGENTS, MANAGED_AGENT_IDS } from './agents.js';
// agent-spec/primitives is a leaf module — importing it creates no cycle, and it
// is the only compareVersions that honors OpenClaw's `-N` rebuild suffix.
import { compareVersions } from './agent-spec/primitives.js';
function getCapability(agent, cap) {
    // Guard against unknown agent ids (e.g. a caller passing "claude@2.1.168"
    // instead of "claude"). Without this, AGENTS[agent] is undefined and the
    // property access throws an opaque TypeError instead of reporting false.
    const def = AGENTS[agent];
    if (!def)
        return false;
    return def.capabilities[cap];
}
/**
 * True when the agent supports the capability on at least some version.
 * Useful for filtering UI lists; does not check installed version.
 */
export function isCapable(agent, cap) {
    if (AGENTS[agent]?.deprecated?.hard)
        return false;
    const c = getCapability(agent, cap);
    return c !== false;
}
/**
 * Check whether the given agent (optionally pinned to a specific installed
 * version) supports `cap`. Pass `version` whenever you know it -- omitting it
 * only checks the agent-level flag, which is fine for "is this agent ever
 * capable" filters but NOT for install-time gating.
 */
export function supports(agent, cap, version) {
    if (AGENTS[agent]?.deprecated?.hard)
        return { ok: false, reason: 'unsupported' };
    const c = getCapability(agent, cap);
    if (c === false)
        return { ok: false, reason: 'unsupported' };
    if (c === true || c === undefined)
        return { ok: true };
    if ('file' in c)
        return { ok: true };
    if (!version)
        return { ok: true };
    if (c.since && compareVersions(version, c.since) < 0) {
        return { ok: false, reason: 'too_old', need: `>= ${c.since}` };
    }
    if (c.until && compareVersions(version, c.until) >= 0) {
        return { ok: false, reason: 'too_new', need: `< ${c.until}` };
    }
    return { ok: true };
}
/**
 * Human-readable explanation for skipping an install. Stable shape so callers
 * can either log it or push it onto an `errors[]` collector.
 */
export function explainSkip(agent, cap, result, version) {
    if (result.ok)
        return '';
    const tag = version ? `${agent}@${version}` : agent;
    if (result.reason === 'unsupported')
        return `${tag}: ${cap} not supported`;
    return `${tag}: ${cap} requires ${result.need}`;
}
/** All agents whose `capabilities[cap]` is anything other than `false`. */
export function capableAgents(cap) {
    return MANAGED_AGENT_IDS.filter((id) => isCapable(id, cap));
}
