#!/usr/bin/env ruby
# encoding: UTF-8
# frozen_string_literal: true

# PreToolUse links gate (intent 192): denies an Edit/Write whose payload
# changes a REAL ## Links section to anything other than exactly what
# LinksProjection would emit for the file's own frontmatter. This is the
# write-time belt for the PLASTIC.md ## Links contract; scripts/project-links
# is the safe-repair path this gate always leaves open (it runs via Bash, a
# tool this gate does not intercept).
#
# Reads the PreToolUse payload as JSON on STDIN:
#   { "tool_input": { "file_path":, "content": | "old_string"/"new_string"/"replace_all": } }
# Exit 0 = allow (including every "cannot judge" case). Exit 2 = deny (message
# on stderr).
#
# Thin CLI wrapper (intent 244): the gate logic itself lives in
# scripts/lib/edit_gates.rb, shared with the merged Claude dispatcher
# (scripts/hook-edit-gates) and, since intent 251, the merged Codex dispatcher
# (scripts/lib/codex_edit_gates.rb). This wrapper has no production caller on
# either harness anymore; it remains as the per-gate isolation surface for the
# hook test suite.

require "json"
require_relative "lib/edit_gates"

begin
  raw = begin
    $stdin.read
  rescue StandardError
    nil
  end
  exit 0 if raw.nil? || raw.strip.empty?

  payload = begin
    JSON.parse(raw)
  rescue StandardError
    nil
  end
  exit 0 unless payload.is_a?(Hash)

  outcome = EditGates.links_gate(EditGates.context_from(payload))
  exit 0 unless outcome
  outcome.lines.each { |line| $stderr.puts line }
  exit 2
rescue => e
  # Hook-internal failure only: do NOT impersonate a user-deny. Log and fail open
  # here so a gate bug (an unreadable UNRELATED store dir, a resolver crash, or
  # anything else) never bricks editing; mirrors hook-lock-gate's own top-level
  # rescue (ruling: the gate must fail open, never closed, on a computation it
  # cannot complete).
  $stderr.puts "plastic links-gate error: #{e.message}"
  exit 0
end
