#!/usr/bin/env node
/**
 * Rule #5 — Memory write requires memory-sync coverage.
 *
 * PreToolUse hook on Edit / Write / MultiEdit. If the file_path looks like a
 * memory store .md (memory/*.md or MEMORY.md), require the last assistant
 * message to declare `coverage: direct:memory-sync` OR `coverage: skill:*` for
 * a memory-related skill. Otherwise block with a re-announce instruction.
 *
 * Override phrase: `memory dump` in user's last prompt suppresses this rule.
 *
 * Spec: docs/superpowers/specs/2026-05-25-enforce-hard-rules-design.md
 */

import {
  readStdin,
  parseEventJson,
  readTranscript,
  lastUserPromptText,
  lastAssistantText,
  parseCoverageLine,
  findOverride,
  logOverride,
  exitDecision,
  isMemoryPath,
} from './enforce-hook-helpers.mjs';

const RULE_KEY = 'memory-sync-coverage';

function isMemorySyncCoverage(cov) {
  if (!cov) return false;
  if (cov.channel === 'direct' && /memory-sync/i.test(cov.id)) return true;
  if (cov.channel === 'skill' && /memory/i.test(cov.id)) return true;
  return false;
}

export function decide({ toolName, filePath, transcriptEntries, override }) {
  if (!['Edit', 'Write', 'MultiEdit'].includes(toolName)) {
    return { block: false };
  }
  if (!isMemoryPath(filePath)) return { block: false };
  if (override) return { block: false };

  const assistantText = lastAssistantText(transcriptEntries);
  const cov = parseCoverageLine(assistantText);
  if (isMemorySyncCoverage(cov)) return { block: false };

  return {
    block: true,
    message: [
      `[enforce-memory-coverage] Write to memory path requires memory-sync coverage tag.`,
      `Detected coverage: ${cov ? cov.channel + ':' + cov.id : 'NONE'} (stale or absent).`,
      ``,
      `Re-announce on a fresh assistant turn first:`,
      `  coverage: direct:memory-sync`,
      `Then retry the Edit/Write.`,
    ].join('\n'),
  };
}

async function main() {
  try {
    const raw = await readStdin();
    const event = parseEventJson(raw);
    const toolName = event.tool_name || '';
    const filePath = (event.tool_input && (event.tool_input.file_path || event.tool_input.notebook_path)) || '';
    const transcript = readTranscript(event.transcript_path);
    const userPrompt = lastUserPromptText(transcript);
    const override = findOverride(userPrompt, RULE_KEY);
    if (override) logOverride(RULE_KEY, override, event.session_id);

    const result = decide({ toolName, filePath, transcriptEntries: transcript, override });
    exitDecision(result);
  } catch {
    // Fail-quiet on any internal error.
    exitDecision({ block: false });
  }
}

const isCli = process.argv[1] && process.argv[1].replace(/\\/g, '/').endsWith('/enforce-memory-coverage.mjs');
if (isCli) main();
