#!/usr/bin/env node
/**
 * Guard 4: MEMORY.md Direct Write Guard
 * Prevents new code from writing directly to MEMORY.md.
 * 
 * → Architecture Freeze v2 (PR-1): docs/architecture-freeze-v2.md
 * → Forbidden Addition §6.6: 禁止直接写 MEMORY.md
 * 
 * Only allowed writers (whitelisted):
 *   - session-memory hook (bundled/session-memory)
 *   - memory-core dreaming (extensions/memory-core)
 *   - memory-core manager (extensions/memory-core)
 *   - openclaw CLI (memory promote/write)
 * 
 * FAIL: new code path writes to MEMORY.md
 */

import { readdirSync, readFileSync, existsSync } from "node:fs";
import { join } from "node:path";
import { homedir } from "node:os";
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");
const WORKSPACE = join(homedir(), ".openclaw", "workspace");

// Known/allowed MEMORY.md writers
const ALLOWED_MEMORY_MD_WRITERS = new Set([
  "memory-core",
  "memory-wiki",
  "active-memory",  // writes to prompt, not MEMORY.md directly
]);

function guardMemoryDirectWrite() {
  const issues = [];
  const foundWriters = [];

  // Search JS files in dist for MEMORY.md write references
  // We grep for patterns that write to MEMORY.md
  const searchPatterns = [
    "MEMORY.md",
    "'MEMORY.md'",
    '"MEMORY.md"',
  ];

  try {
    // Use grep to find references to MEMORY.md in dist JS files
    const grepResult = execSync(
      `grep -rl "MEMORY.md" "${DIST_DIR}" 2>/dev/null | grep -v ".d.ts$" | grep -v "node_modules" | grep -v ".json$" | head -50`,
      { timeout: 30000, encoding: "utf8", maxBuffer: 10 * 1024 * 1024 }
    ).trim();

    if (grepResult) {
      const files = grepResult.split("\n").filter(Boolean);
      for (const file of files) {
        const relativePath = file.replace(DIST_DIR + "/", "");
        
        // Determine which module this belongs to
        let module = "unknown";
        if (relativePath.includes("memory-core")) module = "memory-core";
        else if (relativePath.includes("memory-wiki")) module = "memory-wiki";
        else if (relativePath.includes("memory-lancedb")) module = "memory-lancedb";
        else if (relativePath.includes("active-memory")) module = "active-memory";
        else if (relativePath.includes("bundled/session-memory")) module = "bundled/session-memory";
        else if (relativePath.includes("bundle")) module = "bundled";
        else if (relativePath.includes("cli")) module = "cli";
        else module = relativePath.split("/")[0] || "unknown";

        foundWriters.push({ file: relativePath, module });
      }
    }
  } catch (e) {
    // grep returns exit 1 if no matches found — that's OK
    if (e.status !== 1) {
      issues.push({ level: "WARN", msg: `grep error: ${e.message}` });
    }
  }

  // Group by module
  const moduleGroups = {};
  for (const w of foundWriters) {
    if (!moduleGroups[w.module]) moduleGroups[w.module] = [];
    moduleGroups[w.module].push(w.file);
  }

  const knownModules = new Set(Object.keys(moduleGroups));

  console.log("");
  console.log("═══════════════════════════════════════");
  console.log("  Guard 4: MEMORY.md Direct Write Guard");
  console.log("═══════════════════════════════════════");
  console.log("");

  console.log(`  Modules referencing MEMORY.md: ${knownModules.size}`);
  for (const [mod, files] of Object.entries(moduleGroups)) {
    const status = ALLOWED_MEMORY_MD_WRITERS.has(mod) ? "✓ allowed" : "⚠ unknown";
    console.log(`    ${status} ${mod} (${files.length} files)`);
    if (files.length <= 3) {
      for (const f of files) {
        console.log(`      - ${f}`);
      }
    }
  }

  // Check for unexpected writers
  const unexpectedModules = [...knownModules].filter(m => !ALLOWED_MEMORY_MD_WRITERS.has(m));
  
  if (unexpectedModules.length > 0) {
    console.log("");
    for (const mod of unexpectedModules) {
      // some modules like "bundled" are expected to reference MEMORY.md for reading
      // Only flag as WARN if they might be writing
      issues.push({
        level: "WARN",
        msg: `Module "${mod}" references MEMORY.md — verify it's read-only`
      });
    }
  }

  console.log("");
  const failIssues = issues.filter(i => i.level === "FAIL");
  const warnIssues = issues.filter(i => i.level === "WARN");
  
  if (failIssues.length > 0) {
    for (const issue of failIssues) {
      console.log(`  [FAIL] ${issue.msg}`);
    }
    console.log("  ✗ FAIL: new direct MEMORY.md writer(s) detected");
    process.exit(1);
  } else {
    if (warnIssues.length > 0) {
      for (const issue of warnIssues) {
        console.log(`  [WARN] ${issue.msg}`);
      }
    }
    console.log("  ✓ PASS: MEMORY.md direct write paths unchanged");
    process.exit(0);
  }
}

guardMemoryDirectWrite();
