// tools/reconcile-interactive-question-hooks.ts — SPEC-584: Install PostToolUse hook
// Installs planu-force-ask-user-question.sh into .claude/hooks/ and registers the
// PostToolUse matcher in .claude/settings.json. Idempotent.
import { readFile, writeFile, mkdir, chmod } from 'node:fs/promises';
import { existsSync } from 'node:fs';
import { join, dirname, resolve } from 'node:path';
import { fileURLToPath } from 'node:url';
import { compactResult } from './output-formatter.js';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const HOOK_TEMPLATE_PATH = resolve(__dirname, '../config/hook-templates/planu-force-ask-user-question.sh');
const HOOK_RELATIVE_PATH = '.claude/hooks/planu-force-ask-user-question.sh';
const SETTINGS_PATH = '.claude/settings.json';
const PLANU_MATCHER = 'mcp__planu__.*';
const PLANU_POSTTOOLUSE_ENTRY = {
    matcher: PLANU_MATCHER,
    hooks: [{ type: 'command', command: 'bash .claude/hooks/planu-force-ask-user-question.sh' }],
};
async function readSettings(projectPath) {
    const settingsFile = join(projectPath, SETTINGS_PATH);
    try {
        const raw = await readFile(settingsFile, 'utf-8');
        return JSON.parse(raw);
    }
    catch {
        return {};
    }
}
async function writeSettings(projectPath, data) {
    const settingsFile = join(projectPath, SETTINGS_PATH);
    await mkdir(dirname(settingsFile), { recursive: true });
    await writeFile(settingsFile, JSON.stringify(data, null, 2) + '\n', 'utf-8');
}
async function installHookFile(projectPath) {
    const hookDest = join(projectPath, HOOK_RELATIVE_PATH);
    const alreadyExists = existsSync(hookDest);
    let templateContent;
    try {
        templateContent = await readFile(HOOK_TEMPLATE_PATH, 'utf-8');
    }
    catch {
        // Fall back to inline content when running from compiled dist
        templateContent =
            [
                '#!/usr/bin/env bash',
                '# PostToolUse hook — forces AskUserQuestion relay when Planu returns interactiveQuestions.',
                'set -euo pipefail',
                '',
                'payload="$(cat)"',
                'questions="$(jq -r \'.tool_response.structuredContent.interactiveQuestions // empty\' <<<"$payload" 2>/dev/null || true)"',
                '',
                'if [[ -z "$questions" || "$questions" == "null" ]]; then',
                '  exit 0',
                'fi',
                '',
                "cat <<'MANDATE'",
                '{"hookSpecificOutput":{"hookEventName":"PostToolUse","additionalContext":"PLANU_MANDATE: the previous Planu tool returned interactiveQuestions. You MUST call AskUserQuestion as your very next tool. Any other tool call is a protocol violation. After collecting the user\'s answers, retry the previous tool with clarificationAnswers: { <questionKey>: <optionValue>, ... }."}}',
                'MANDATE',
            ].join('\n') + '\n';
    }
    await mkdir(dirname(hookDest), { recursive: true });
    await writeFile(hookDest, templateContent, 'utf-8');
    await chmod(hookDest, 0o755);
    return !alreadyExists;
}
function matcherAlreadyPresent(settings) {
    const postToolUse = settings.hooks?.PostToolUse;
    if (!Array.isArray(postToolUse)) {
        return false;
    }
    return postToolUse.some((entry) => entry.matcher === PLANU_MATCHER);
}
async function mergeSettings(projectPath) {
    const settings = await readSettings(projectPath);
    if (matcherAlreadyPresent(settings)) {
        return false;
    }
    const existingPostToolUse = Array.isArray(settings.hooks?.PostToolUse)
        ? settings.hooks.PostToolUse
        : [];
    const updated = {
        ...settings,
        hooks: {
            ...(settings.hooks ?? {}),
            PostToolUse: [...existingPostToolUse, PLANU_POSTTOOLUSE_ENTRY],
        },
    };
    await writeSettings(projectPath, updated);
    return true;
}
export async function reconcileInteractiveQuestionHooks(projectPath) {
    const resolved = resolve(projectPath);
    const hookInstalled = await installHookFile(resolved);
    const settingsUpdated = await mergeSettings(resolved);
    const alreadyPresent = !hookInstalled && !settingsUpdated;
    const humanSummary = alreadyPresent
        ? 'Hook already present — no changes needed.'
        : `Hook installed. Changes: hook file ${hookInstalled ? 'created' : 'already existed'}, settings.json ${settingsUpdated ? 'updated' : 'already configured'}.`;
    return { hookInstalled, settingsUpdated, humanSummary };
}
export async function handleReconcileInteractiveQuestionHooks(args) {
    const { projectPath } = args;
    if (!projectPath || typeof projectPath !== 'string') {
        return {
            content: [
                {
                    type: 'text',
                    text: 'projectPath is required. Provide the absolute path to the client project.',
                },
            ],
            isError: true,
        };
    }
    try {
        const result = await reconcileInteractiveQuestionHooks(projectPath);
        return compactResult(result.humanSummary);
    }
    catch (err) {
        const message = err instanceof Error ? err.message : String(err);
        return {
            content: [
                {
                    type: 'text',
                    text: `Failed to install hook: ${message}. Check that the projectPath exists and is writable.`,
                },
            ],
            isError: true,
        };
    }
}
//# sourceMappingURL=reconcile-interactive-question-hooks.js.map