#!/usr/bin/env node
// stop-gate — Stop hook: block a stop while the last TodoWrite still holds
// pending/in_progress items. Fires at most once per stop chain (stop_hook_active
// guard): agent either finishes the items or states in one line why stopping is
// correct, then the second stop passes. Fail-open on any error.
import fs from 'node:fs';

function main() {
  let inp = {};
  try {
    inp = JSON.parse(fs.readFileSync(0, 'utf8'));
  } catch {
    return;
  }
  if (inp.stop_hook_active) return;
  const tp = inp.transcript_path;
  if (!tp || !fs.existsSync(tp)) return;

  let todos = null;
  try {
    for (const line of fs.readFileSync(tp, 'utf8').split('\n')) {
      if (!line || !line.includes('TodoWrite')) continue;
      let o;
      try {
        o = JSON.parse(line);
      } catch {
        continue;
      }
      const content = o?.message?.content;
      if (o.type !== 'assistant' || !Array.isArray(content)) continue;
      for (const c of content)
        if (c?.type === 'tool_use' && c.name === 'TodoWrite' && Array.isArray(c.input?.todos))
          todos = c.input.todos;
    }
  } catch {
    return;
  }
  if (!Array.isArray(todos)) return;

  const open = todos.filter((t) => t && t.status !== 'completed');
  if (!open.length) return;

  const list = open.slice(0, 8).map((t) => `${t.status}: ${(t.content || '').slice(0, 80)}`).join('; ');
  console.log(
    JSON.stringify({
      decision: 'block',
      reason:
        `stop-gate: ${open.length} todo item(s) not completed — ${list}. ` +
        `Finish them now, or state in ONE line why stopping here is correct, then stop again.`,
    })
  );
}

main();
process.exit(0);
