// engine/host-tool-filter.ts — SPEC-972: Filter tool lists by host capability
import { readFileSync } from 'node:fs';
import { readFile } from 'node:fs/promises';
import { join, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
// ---------------------------------------------------------------------------
// Core AGENTS.md tool reference — curated list of key Planu tools
// ---------------------------------------------------------------------------
export const CORE_AGENTS_MD_TOOLS = [
    { name: 'create_spec', description: 'Create a new spec from a description' },
    { name: 'list_specs', description: 'List all specs and their status' },
    { name: 'update_status', description: 'Move a spec through workflow stages' },
    { name: 'validate', description: 'Check implementation against spec criteria' },
    { name: 'challenge_spec', description: 'Stress-test a spec for gaps before implementation' },
    { name: 'check_readiness', description: 'Verify spec has enough detail to implement' },
    { name: 'planu_status', description: 'Quick project health snapshot' },
    { name: 'facilitate', description: 'Universal entry point for SDD workflow' },
    { name: 'plan_mode', description: 'Preview implementation plan before writing code' },
    { name: 'generate_steering_file', description: 'Generate host-aware steering files' },
    { name: 'search_specs', description: 'Search specs with fuzzy text matching' },
    { name: 'spec_quality_score', description: 'Compute quality score for a spec' },
    { name: 'analyze_spec_size', description: 'Analyze if a spec should be split' },
    { name: 'decompose_spec', description: 'Decompose a spec into agent tasks' },
    { name: 'estimate', description: 'Estimate time and cost for a spec' },
    { name: 'session_checkpoint', description: 'Save session context' },
    { name: 'project_overview', description: 'Single-call project state query' },
    { name: 'scan_project', description: 'Scan project and generate specs' },
    { name: 'validate_workflow', description: 'Validate a workflow definition' },
    { name: 'tdd_scaffold', description: 'Generate TDD test stubs from spec criteria' },
    { name: 'coverage_gap_analyzer', description: 'Analyze untested acceptance criteria' },
    { name: 'security_scan', description: 'Scan dependencies for vulnerabilities' },
    { name: 'bootstrap_skills', description: 'Auto-install skills for detected stack' },
    { name: 'manage_drift', description: 'Detect and resolve spec drift' },
    { name: 'sync_spec_state', description: 'Sync spec status between frontmatter and store' },
    { name: 'health_check_all', description: 'Run health check on all specs' },
    { name: 'tokens', description: 'Token usage dashboard' },
    { name: 'configure_workers', description: 'Configure background analysis workers' },
    {
        name: 'approve_spec',
        description: 'Record that a reviewer has approved a spec — requires reviewer token',
    },
    { name: 'lock_spec', description: 'Acquire exclusive lock on a spec' },
    { name: 'register_api_surface', description: 'Register API surfaces exposed by a spec' },
    { name: 'analyze_breaking_changes', description: 'Analyze specs impacted by API changes' },
    { name: 'track_tech_debt', description: 'Track a new tech debt item' },
    { name: 'capture_idea', description: 'Capture a lightweight idea' },
    { name: 'log_lesson', description: 'Log a lesson learned' },
    { name: 'semantic_search', description: 'Search project knowledge by meaning' },
    { name: 'render_spec_for_provider', description: 'Render spec for target LLM provider' },
    { name: 'convert_to_bdd', description: 'Convert spec criteria to BDD format' },
    { name: 'generate_e2e_tests', description: 'Generate E2E tests from spec criteria' },
    { name: 'run_spec_lint', description: 'Run custom lint rules against specs' },
    { name: 'suggest_criteria', description: 'Suggest missing best-practice criteria' },
    { name: 'check_compliance', description: 'Unified compliance tool' },
    { name: 'create_release', description: 'Create a GitHub Release' },
    { name: 'generate_changelog', description: 'Generate changelog from merged PRs' },
    { name: 'create_pr_from_spec', description: 'Create a PR from a spec' },
    { name: 'onboarding_progress', description: 'View onboarding progress' },
    { name: 'list_templates', description: 'Browse spec template catalog' },
    { name: 'generate_docs_site', description: 'Generate static HTML docs site' },
    { name: 'plan_team_distribution', description: 'Distribute specs across agents' },
    { name: 'optimize_spec_scheduling', description: 'Minimize agent idle time' },
    { name: 'context_window_status', description: 'Estimate token consumption' },
    { name: 'archive_spec_context', description: 'Archive a spec to free tokens' },
    { name: 'workspace_overview', description: 'Get overview of all projects' },
    { name: 'search_all_projects', description: 'Search specs across all projects' },
];
// ---------------------------------------------------------------------------
// Interactive detection heuristics
// ---------------------------------------------------------------------------
const INTERACTIVE_KEYWORDS = [
    'interactive',
    'askuserquestion',
    'ask_user_question',
    'clarifying question',
    'interactive question',
    'reviewer token',
    'planner token',
    'multi-teammate',
    'multi_teammate',
    'live prompt',
    'human review',
    'approval gate',
    'checkpoint approval',
    'requires approval',
];
/** Check if a tool description suggests it needs interactive features. */
function requiresInteractivity(tool) {
    const text = `${tool.name} ${tool.description}`.toLowerCase();
    return INTERACTIVE_KEYWORDS.some((kw) => text.includes(kw.toLowerCase()));
}
// ---------------------------------------------------------------------------
// Registry loader
// ---------------------------------------------------------------------------
/** Resolve the path to a host capability registry JSON file. */
function resolveRegistryPath(hostId) {
    const baseDir = dirname(fileURLToPath(import.meta.url));
    return join(baseDir, '../config/registries/hosts', `${hostId}.json`);
}
/** Load a host capability registry from disk. */
export async function loadHostRegistry(hostId) {
    try {
        const path = resolveRegistryPath(hostId);
        const raw = await readFile(path, 'utf-8');
        return JSON.parse(raw);
    }
    catch {
        return null;
    }
}
/** Synchronous version for contexts where async is not available. */
export function loadHostRegistrySync(hostId) {
    try {
        const path = resolveRegistryPath(hostId);
        const raw = readFileSync(path, 'utf-8');
        return JSON.parse(raw);
    }
    catch {
        return null;
    }
}
// ---------------------------------------------------------------------------
// Filtering logic
// ---------------------------------------------------------------------------
/**
 * Filter a list of tools by host capability.
 *
 * Rules (in precedence order):
 *   1. unsupportedTools  → exclude entirely
 *   2. restrictedTools   → include with warning comment
 *   3. Auto-detect interactive tools when host lacks interactiveUI → exclude
 *   4. Everything else   → include
 *
 * If hostId is omitted or registry not found, all tools are included (default).
 */
export function filterToolsByHost(tools, hostId, registry) {
    // Default: no host specified → include everything
    if (!hostId || hostId === 'universal') {
        return { included: tools.map((t) => ({ ...t })), restricted: [], excluded: [] };
    }
    const reg = registry ?? null;
    if (!reg) {
        // Registry not found for this host — default to include all (safe fallback)
        return { included: tools.map((t) => ({ ...t })), restricted: [], excluded: [] };
    }
    const included = [];
    const restricted = [];
    const excluded = [];
    for (const tool of tools) {
        // 1. Explicitly unsupported
        if (reg.unsupportedTools.includes(tool.name)) {
            excluded.push({ ...tool });
            continue;
        }
        // 2. Restricted — include with warning
        const restrictionReason = reg.restrictedTools[tool.name];
        if (restrictionReason !== undefined) {
            restricted.push({ ...tool, reason: restrictionReason });
            continue;
        }
        // 3. Auto-detect interactive tools if host lacks interactiveUI
        if (!reg.capabilities.interactiveUI && requiresInteractivity(tool)) {
            excluded.push({ ...tool });
            continue;
        }
        // 4. Include by default
        included.push({ ...tool });
    }
    return { included, restricted, excluded };
}
/**
 * Build a markdown table or list of tools for AGENTS.md, including
 * warning comments for restricted tools.
 */
export function formatToolsForAgentsMd(result, opts = {}) {
    const { prefix = 'mcp__planu__', tableFormat = true } = opts;
    const lines = [];
    if (tableFormat) {
        lines.push('| Tool | Purpose |');
        lines.push('|------|---------|');
    }
    for (const tool of result.included) {
        const command = `${prefix}${tool.name}`;
        if (tableFormat) {
            lines.push(`| \`${command}\` | ${tool.description} |`);
        }
        else {
            lines.push(`- \`${command}\` — ${tool.description}`);
        }
    }
    for (const tool of result.restricted) {
        const command = `${prefix}${tool.name}`;
        if (tableFormat) {
            lines.push(`| \`${command}\` | ${tool.description} ⚠️ *${tool.reason}* |`);
        }
        else {
            lines.push(`- \`${command}\` — ${tool.description}`);
            lines.push(`  > ⚠️ **Restricted:** ${tool.reason}`);
        }
    }
    return lines.join('\n');
}
//# sourceMappingURL=host-tool-filter.js.map