#!/usr/bin/env node
import { Server } from "@modelcontextprotocol/sdk/server/index.js";
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
import { z } from "zod";
import Database from "better-sqlite3";
import { existsSync, mkdirSync } from "fs";
import { join, dirname } from "path";
import { execSync } from "child_process";
import { v4 as uuidv4 } from "uuid";
import { RefactoredFrameManager } from "../../core/context/refactored-frame-manager.js";
import { LinearTaskManager } from "../../features/tasks/linear-task-manager.js";
import { LinearAuthManager } from "../linear/auth.js";
import { LinearSyncEngine, DEFAULT_SYNC_CONFIG } from "../linear/sync.js";
import { BrowserMCPIntegration } from "../../features/browser/browser-mcp.js";
import { TraceDetector } from "../../core/trace/trace-detector.js";
import { LLMContextRetrieval } from "../../core/retrieval/index.js";
import { ConfigManager } from "../../core/config/config-manager.js";
import { logger } from "../../core/monitoring/logger.js";
import { MCPHandlerFactory } from "./handlers/index.js";
import { MCPToolDefinitions } from "./tool-definitions.js";
import { ToolScoringMiddleware } from "./middleware/tool-scoring.js";
function getEnv(key, defaultValue) {
  const value = process.env[key];
  if (value === void 0) {
    if (defaultValue !== void 0) return defaultValue;
    throw new Error(`Environment variable ${key} is required`);
  }
  return value;
}
function getOptionalEnv(key) {
  return process.env[key];
}
class RefactoredStackMemoryMCP {
  server;
  db;
  projectRoot;
  projectId;
  // Core components
  frameManager;
  taskStore;
  linearAuthManager;
  linearSync;
  browserMCP;
  traceDetector;
  contextRetrieval;
  configManager;
  toolScoringMiddleware;
  // Handler factory
  handlerFactory;
  toolDefinitions;
  constructor(config = {}) {
    this.projectRoot = this.findProjectRoot();
    this.projectId = this.getProjectId();
    this.initializeDatabase();
    this.initializeComponents(config);
    this.initializeServer();
    this.setupHandlers();
  }
  /**
   * Initialize database connection
   */
  initializeDatabase() {
    const dbDir = join(this.projectRoot, ".stackmemory");
    if (!existsSync(dbDir)) {
      mkdirSync(dbDir, { recursive: true });
    }
    const dbPath = join(dbDir, "context.db");
    this.db = new Database(dbPath);
    logger.info("Database initialized", { dbPath });
  }
  /**
   * Initialize core components
   */
  initializeComponents(config) {
    const configPath = join(this.projectRoot, ".stackmemory", "config.yaml");
    this.configManager = new ConfigManager(configPath);
    this.frameManager = new RefactoredFrameManager(this.db, this.projectId);
    this.taskStore = new LinearTaskManager(this.projectRoot, this.db);
    this.linearAuthManager = new LinearAuthManager(this.projectRoot);
    this.linearSync = new LinearSyncEngine(
      this.taskStore,
      this.linearAuthManager,
      DEFAULT_SYNC_CONFIG
    );
    if (config.enableBrowser !== false) {
      this.browserMCP = new BrowserMCPIntegration({
        headless: config.headless ?? process.env["BROWSER_HEADLESS"] !== "false",
        defaultViewport: {
          width: config.viewportWidth ?? 1280,
          height: config.viewportHeight ?? 720
        }
      });
    }
    if (config.enableTracing !== false) {
      this.traceDetector = new TraceDetector({}, this.configManager, this.db);
    }
    this.toolScoringMiddleware = new ToolScoringMiddleware(
      this.configManager,
      this.traceDetector,
      this.db
    );
    this.contextRetrieval = new LLMContextRetrieval(
      this.db,
      this.frameManager,
      this.projectId,
      {}
    );
    logger.info("Core components initialized");
  }
  /**
   * Initialize MCP server
   */
  initializeServer() {
    this.server = new Server(
      {
        name: "stackmemory-refactored",
        version: "0.2.0"
      },
      {
        capabilities: {
          tools: {}
        }
      }
    );
    logger.info("MCP server initialized");
  }
  /**
   * Setup MCP handlers
   */
  setupHandlers() {
    const dependencies = {
      frameManager: this.frameManager,
      contextRetrieval: this.contextRetrieval,
      taskStore: this.taskStore,
      projectId: this.projectId,
      linearAuthManager: this.linearAuthManager,
      linearSync: this.linearSync,
      traceDetector: this.traceDetector,
      browserMCP: this.browserMCP
    };
    this.handlerFactory = new MCPHandlerFactory(dependencies);
    this.toolDefinitions = new MCPToolDefinitions();
    this.setupToolListHandler();
    this.setupToolExecutionHandler();
    logger.info("MCP handlers configured");
  }
  /**
   * Setup tool listing handler
   */
  setupToolListHandler() {
    this.server.setRequestHandler(
      z.object({
        method: z.literal("tools/list")
      }),
      async () => {
        const tools = this.toolDefinitions.getAllToolDefinitions();
        logger.debug("Listed tools", { count: tools.length });
        return { tools };
      }
    );
  }
  /**
   * Setup tool execution handler
   */
  setupToolExecutionHandler() {
    this.server.setRequestHandler(
      z.object({
        method: z.literal("tools/call"),
        params: z.object({
          name: z.string(),
          arguments: z.record(z.unknown())
        })
      }),
      async (request) => {
        const { name, arguments: args } = request.params;
        const callId = uuidv4();
        const startTime = Date.now();
        logger.info("Tool call started", { toolName: name, callId });
        try {
          const currentFrameId = this.frameManager.getCurrentFrameId();
          if (currentFrameId) {
            this.frameManager.addEvent("tool_call", {
              tool_name: name,
              arguments: args,
              timestamp: startTime,
              call_id: callId
            });
          }
          if (!this.handlerFactory.hasHandler(name)) {
            throw new Error(`Unknown tool: ${name}`);
          }
          const handler = this.handlerFactory.getHandler(name);
          const result = await handler(args);
          const duration = Date.now() - startTime;
          const score = await this.toolScoringMiddleware.scoreToolCall(
            name,
            args,
            result,
            void 0
            // no error
          );
          if (currentFrameId) {
            this.frameManager.addEvent("tool_result", {
              tool_name: name,
              call_id: callId,
              duration,
              success: true,
              result_size: JSON.stringify(result).length,
              importance_score: score,
              profile: this.configManager.getConfig().profile || "default"
            });
          }
          if (this.traceDetector) {
            this.traceDetector.addToolCall({
              id: callId,
              tool: name,
              arguments: args,
              timestamp: startTime,
              result,
              duration
            });
          }
          logger.info("Tool call completed", {
            toolName: name,
            callId,
            duration
          });
          return result;
        } catch (error) {
          const duration = Date.now() - startTime;
          const errorMessage = error instanceof Error ? error.message : String(error);
          const score = await this.toolScoringMiddleware.scoreToolCall(
            name,
            args,
            void 0,
            errorMessage
          );
          const currentFrameId = this.frameManager.getCurrentFrameId();
          if (currentFrameId) {
            this.frameManager.addEvent("tool_result", {
              tool_name: name,
              call_id: callId,
              duration,
              success: false,
              error: errorMessage,
              importance_score: score,
              profile: this.configManager.getConfig().profile || "default"
            });
          }
          logger.error("Tool call failed", {
            toolName: name,
            callId,
            duration,
            error: errorMessage
          });
          return {
            content: [
              {
                type: "text",
                text: `Error executing ${name}: ${errorMessage}`
              }
            ],
            isError: true
          };
        }
      }
    );
  }
  /**
   * Start the MCP server
   */
  async start() {
    try {
      await this.frameManager.initialize();
      const transport = new StdioServerTransport();
      await this.server.connect(transport);
      logger.info("StackMemory MCP Server started", {
        projectRoot: this.projectRoot,
        projectId: this.projectId,
        availableTools: this.handlerFactory.getAvailableTools().length
      });
      this.setupCleanup();
    } catch (error) {
      logger.error("Failed to start MCP server", error instanceof Error ? error : new Error(String(error)));
      throw error;
    }
  }
  /**
   * Setup cleanup handlers
   */
  setupCleanup() {
    const cleanup = async () => {
      logger.info("Shutting down MCP server...");
      try {
        if (this.browserMCP) {
          await this.browserMCP.cleanup();
        }
        if (this.db) {
          this.db.close();
        }
        logger.info("MCP server shutdown complete");
      } catch (error) {
        logger.error("Error during cleanup", error instanceof Error ? error : new Error(String(error)));
      }
      process.exit(0);
    };
    process.on("SIGINT", cleanup);
    process.on("SIGTERM", cleanup);
    process.on("uncaughtException", (error) => {
      logger.error("Uncaught exception", error instanceof Error ? error : new Error(String(error)));
      cleanup();
    });
  }
  /**
   * Find project root directory
   */
  findProjectRoot() {
    let currentDir = process.cwd();
    const rootDir = "/";
    while (currentDir !== rootDir) {
      if (existsSync(join(currentDir, ".git"))) {
        return currentDir;
      }
      currentDir = dirname(currentDir);
    }
    return process.cwd();
  }
  /**
   * Get project ID from git remote or directory name
   */
  getProjectId() {
    try {
      const remoteUrl = execSync("git remote get-url origin", {
        cwd: this.projectRoot,
        encoding: "utf8"
      }).trim();
      const match = remoteUrl.match(/([^/]+\/[^/]+)(?:\.git)?$/);
      if (match) {
        return match[1];
      }
    } catch (error) {
      logger.debug("Could not get git remote URL", error);
    }
    return this.projectRoot.split("/").pop() || "unknown";
  }
}
async function main() {
  try {
    const config = {
      headless: process.env["BROWSER_HEADLESS"] !== "false",
      enableTracing: process.env["DISABLE_TRACING"] !== "true",
      enableBrowser: process.env["DISABLE_BROWSER"] !== "true"
    };
    const server = new RefactoredStackMemoryMCP(config);
    await server.start();
  } catch (error) {
    logger.error("Failed to start server", error instanceof Error ? error : new Error(String(error)));
    process.exit(1);
  }
}
if (import.meta.url === `file://${process.argv[1]}`) {
  main().catch((error) => {
    console.error("Fatal error:", error);
    process.exit(1);
  });
}
export {
  RefactoredStackMemoryMCP
};
//# sourceMappingURL=refactored-server.js.map
