#!/usr/bin/env node
/**
 * Guard 1: Memory Backend Guard
 * Prevents proliferation beyond the allowed memory backends.
 * 
 * → Architecture Freeze v2 (PR-1): docs/architecture-freeze-v2.md
 * → Core: memory-core | Legacy: memory-wiki
 * 
 * Allowed plugins (kind="memory" or has memory tools):
 *   - memory-core      (primary — Core §2)
 *   - active-memory    (recall injector — Core §2)
 *   - memory-wiki      (legacy, allowed for now — Legacy §4)
 *   - Builtin/QMD      (internal engine, not a plugin)
 * 
 * FAIL: any new memory plugin appears
 * PASS: within allowed list
 */

import { readdirSync, readFileSync, existsSync } from "node:fs";
import { join } from "node:path";
import { homedir } from "node:os";

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

// Allowed memory plugin IDs
const ALLOWED_MEMORY_PLUGINS = new Set([
  "memory-core",
  "active-memory",
  "memory-wiki",
]);

// Plugin IDs that have memory contracts but are not "kind: memory"
const KNOWN_MEMORY_RELATED = new Set([
  "memory-lancedb",   // legacy, being deprecated
]);

function guardMemoryBackends() {
  const issues = [];
  const found = [];
  
  if (!existsSync(EXTENSIONS_DIR)) {
    issues.push({ level: "ERROR", msg: `Extensions dir not found: ${EXTENSIONS_DIR}` });
    return { pass: false, found, issues };
  }

  const extDirs = readdirSync(EXTENSIONS_DIR, { withFileTypes: true })
    .filter(d => d.isDirectory())
    .map(d => d.name);

  for (const extDir of extDirs) {
    const pluginJsonPath = join(EXTENSIONS_DIR, extDir, "openclaw.plugin.json");
    if (!existsSync(pluginJsonPath)) continue;

    try {
      const plugin = JSON.parse(readFileSync(pluginJsonPath, "utf8"));
      const pluginId = plugin.id || extDir;
      const kind = plugin.kind || "";
      const contracts = plugin.contracts || {};
      const tools = contracts.tools || [];
      const memoryTools = tools.filter(t => t.startsWith("memory_") || t.startsWith("wiki_"));
      
      const isMemoryPlugin = 
        kind === "memory" ||
        tools.includes("memory_search") ||
        tools.includes("memory_get") ||
        memoryTools.length >= 2;

      if (isMemoryPlugin) {
        found.push({ id: pluginId, kind, memoryTools });
        
        if (!ALLOWED_MEMORY_PLUGINS.has(pluginId) && !KNOWN_MEMORY_RELATED.has(pluginId)) {
          issues.push({
            level: "FAIL",
            msg: `UNEXPECTED memory plugin: ${pluginId} (kind=${kind}, tools=${memoryTools.join(",")})`
          });
        }
      }
    } catch (e) {
      issues.push({ level: "WARN", msg: `Could not parse ${pluginJsonPath}: ${e.message}` });
    }
  }

  const pass = issues.filter(i => i.level === "FAIL").length === 0;
  return { pass, found, issues };
}

// Run
const result = guardMemoryBackends();

console.log("");
console.log("═══════════════════════════════════════");
console.log("  Guard 1: Memory Backend Guard");
console.log("═══════════════════════════════════════");
console.log("");

if (result.found.length === 0) {
  console.log("  No memory plugins found.");
} else {
  console.log(`  Memory plugins found: ${result.found.length}`);
  for (const f of result.found) {
    const status = ALLOWED_MEMORY_PLUGINS.has(f.id) ? "✓" : 
                   KNOWN_MEMORY_RELATED.has(f.id) ? "⚠ (legacy)" : "✗ UNEXPECTED";
    console.log(`    ${status} ${f.id} (kind="${f.kind}", tools: ${f.memoryTools.join(", ")})`);
  }
}

for (const issue of result.issues) {
  console.log(`  [${issue.level}] ${issue.msg}`);
}

if (result.pass) {
  console.log("");
  console.log("  ✓ PASS: memory backend count within allowed list");
  process.exit(0);
} else {
  console.log("");
  console.log("  ✗ FAIL: unexpected memory backend(s) detected");
  process.exit(1);
}
