#!/usr/bin/env node
/**
 * Guard 5: Tool Trace Guard
 * Inventories tool call sites and checks for trace/log coverage.
 * 
 * → Architecture Freeze v2 (PR-1): docs/architecture-freeze-v2.md
 * → Future: PR-10 Trace Model enforcement
 * 
 * SOFT GUARD — Trace model not yet implemented (PR-10).
 * Currently inventories tool call entry points and reports gaps.
 * No hard failure at this stage.
 */

import { readdirSync, readFileSync, existsSync } from "node:fs";
import { join } from "node:path";
import { execSync } from "node:child_process";

const OPENCLAW_HOME = process.env.OPENCLAW_HOME || "/opt/homebrew/lib/node_modules/openclaw";
const DIST_DIR = join(OPENCLAW_HOME, "dist");

function guardToolTrace() {
  const issues = [];
  const toolSites = [];
  let totalToolCallSites = 0;
  let sitesWithTrace = 0;

  // Search for tool call patterns in dist
  const searchTerms = [
    "tool_call",
    "toolCall", 
    "tool.call",
    "tool_exec",
    "toolExec",
    "invokeTool",
    "runTool",
  ];

  try {
    const grepResult = execSync(
      `grep -rln -E "(tool_call|toolCall|tool\\.call|tool_exec|toolExec|executeTool|invokeTool|runTool)" "${DIST_DIR}" 2>/dev/null | grep -v ".d.ts$" | grep -v "node_modules" | grep ".js$" | head -30`,
      { timeout: 30000, encoding: "utf8", maxBuffer: 10 * 1024 * 1024 }
    ).trim();

    if (grepResult) {
      const files = grepResult.split("\n").filter(Boolean);
      totalToolCallSites = files.length;

      for (const file of files) {
        const relativePath = file.replace(DIST_DIR + "/", "");
        
        // Check if this file has trace/log instrumentation
        try {
          const content = readFileSync(file, "utf8");
          const hasTrace = 
            content.includes("trace") || 
            content.includes("Trace") ||
            content.includes("span") ||
            content.includes("log") ||
            content.includes("event") ||
            content.includes("audit") ||
            content.includes("diagnostics");
          
          if (hasTrace) sitesWithTrace++;

          toolSites.push({
            file: relativePath,
            hasTrace,
            module: relativePath.split("/")[0] || "unknown",
          });
        } catch {
          toolSites.push({
            file: relativePath,
            hasTrace: false,
            module: relativePath.split("/")[0] || "unknown",
          });
        }
      }
    }
  } catch (e) {
    if (e.status !== 1) {
      console.log(`  Warning: grep failed: ${e.message}`);
    }
  }

  const sitesWithoutTrace = toolSites.filter(s => !s.hasTrace);

  console.log("");
  console.log("═══════════════════════════════════════");
  console.log("  Guard 5: Tool Trace Guard");
  console.log("═══════════════════════════════════════");
  console.log("");

  console.log(`  Tool call entry points found: ${totalToolCallSites}`);
  console.log(`  Sites with trace/log:         ${sitesWithTrace}`);
  console.log(`  Sites without trace:          ${sitesWithoutTrace.length}`);

  // Group by module
  const moduleSummary = {};
  for (const s of toolSites) {
    if (!moduleSummary[s.module]) {
      moduleSummary[s.module] = { total: 0, traced: 0 };
    }
    moduleSummary[s.module].total++;
    if (s.hasTrace) moduleSummary[s.module].traced++;
  }

  if (Object.keys(moduleSummary).length > 0) {
    console.log("\n  Trace coverage by module:");
    for (const [mod, stats] of Object.entries(moduleSummary)) {
      const pct = stats.total > 0 ? Math.round(stats.traced / stats.total * 100) : 0;
      const bar = "█".repeat(Math.round(pct / 10)) + "░".repeat(10 - Math.round(pct / 10));
      console.log(`    ${bar} ${mod}: ${stats.traced}/${stats.total} (${pct}%)`);
    }
  }

  if (sitesWithoutTrace.length > 0 && sitesWithoutTrace.length <= 10) {
    console.log("\n  Sites without trace:");
    for (const s of sitesWithoutTrace) {
      console.log(`    • ${s.file}`);
    }
  }

  console.log("");
  console.log("  ⚠ WARN: Trace model not yet enforced");
  console.log(`    Current coverage: ${sitesWithTrace}/${totalToolCallSites} sites have tracing`);
  console.log("    After PR-10 (Trace Model), all tool calls will require trace spans.");

  // No hard fail — soft guard
  process.exit(0);
}

guardToolTrace();
