#!/usr/bin/env node
"use strict";
// Claude Code hook → Claude Pet
// 讀 stdin 的 hook JSON，POST 到本機的寵物 app。任何失敗都靜默結束（exit 0），絕不阻塞 Claude Code。

const http = require("node:http");

const PORT = Number(process.env.CLAUDE_PET_PORT || 17333);
const TIMEOUT_MS = 800;

function trim(value, max) {
  if (typeof value !== "string") return undefined;
  return value.length > max ? `${value.slice(0, max)}…` : value;
}

function readStdin() {
  return new Promise((resolve) => {
    if (process.stdin.isTTY) return resolve({});
    let data = "";
    const timer = setTimeout(() => resolve(parse(data)), TIMEOUT_MS);
    process.stdin.setEncoding("utf8");
    process.stdin.on("data", (chunk) => { data += chunk; });
    process.stdin.on("end", () => { clearTimeout(timer); resolve(parse(data)); });
    process.stdin.on("error", () => { clearTimeout(timer); resolve(parse(data)); });
  });
}

function parse(text) {
  try { return text.trim() ? JSON.parse(text) : {}; } catch { return {}; }
}

// 從 tool_input 挑一個最有資訊量的欄位當成「正在對什麼做事」。
// 整包 tool_input 可能很大（例如 Write 帶整份檔案內容），只取一小段。
const TARGET_KEYS = ["command", "file_path", "pattern", "path", "url", "query", "notebook_path", "description", "prompt"];

function toolTarget(toolInput) {
  if (!toolInput || typeof toolInput !== "object") return undefined;
  for (const key of TARGET_KEYS) {
    const v = toolInput[key];
    if (typeof v === "string" && v.trim()) return trim(v.trim().replace(/\s+/g, " "), 160);
  }
  return undefined;
}

function buildPayload(input) {
  const error = typeof input.error === "string" ? input.error : input.error?.message;
  return {
    event: input.hook_event_name || process.argv[2] || "Unknown",
    sessionId: input.session_id ?? null,
    cwd: input.cwd ?? null,
    permissionMode: input.permission_mode ?? null,
    toolName: input.tool_name ?? null,
    toolTarget: toolTarget(input.tool_input),
    agentType: input.agent_type ?? null,
    // 助理的說明文字要從 transcript 撈；寵物那邊才讀，hook 只負責把路徑帶過去
    transcriptPath: input.transcript_path ?? null,
    notificationType: input.notification_type ?? null,
    title: trim(input.title, 160),
    message: trim(input.message, 240),
    error: trim(error, 240),
    source: input.source ?? null,
    reason: input.reason ?? null,
    trigger: input.trigger ?? null,
    stopHookActive: input.stop_hook_active ?? null,
    lastAssistantMessage: trim(input.last_assistant_message, 300),
    prompt: trim(input.prompt, 120),
    ts: Date.now(),
  };
}

function post(payload) {
  return new Promise((resolve) => {
    const body = Buffer.from(JSON.stringify(payload), "utf8");
    const req = http.request(
      {
        host: "127.0.0.1",
        port: PORT,
        method: "POST",
        path: "/event",
        headers: { "content-type": "application/json", "content-length": body.length },
      },
      (res) => { res.resume(); res.on("end", resolve); res.on("error", resolve); },
    );
    req.setTimeout(TIMEOUT_MS, () => req.destroy());
    req.on("error", resolve);
    req.end(body);
  });
}

(async () => {
  const guard = setTimeout(() => process.exit(0), TIMEOUT_MS * 2 + 500);
  guard.unref();
  try {
    const input = await readStdin();
    await post(buildPayload(input));
  } catch {
    // ignore
  }
  process.exit(0);
})();
