#!/usr/bin/env node
import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
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 { readFileSync, existsSync, mkdirSync } from "fs";
import { join, dirname } from "path";
import { execSync } from "child_process";
import { FrameManager } from "../../core/context/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 { logger } from "../../core/monitoring/logger.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 { DiscoveryHandlers } from "./handlers/discovery-handlers.js";
import { v4 as uuidv4 } from "uuid";
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 LocalStackMemoryMCP {
  server;
  db;
  projectRoot;
  frameManager;
  taskStore;
  linearAuthManager;
  linearSync;
  projectId;
  contexts = /* @__PURE__ */ new Map();
  browserMCP;
  traceDetector;
  contextRetrieval;
  discoveryHandlers;
  constructor() {
    this.projectRoot = this.findProjectRoot();
    this.projectId = this.getProjectId();
    const dbDir = join(this.projectRoot, ".stackmemory");
    if (!existsSync(dbDir)) {
      mkdirSync(dbDir, { recursive: true });
    }
    const dbPath = join(dbDir, "context.db");
    this.db = new Database(dbPath);
    this.initDB();
    this.frameManager = new FrameManager(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
    );
    this.server = new Server(
      {
        name: "stackmemory-local",
        version: "0.1.0"
      },
      {
        capabilities: {
          tools: {}
        }
      }
    );
    this.browserMCP = new BrowserMCPIntegration({
      headless: process.env["BROWSER_HEADLESS"] !== "false",
      defaultViewport: { width: 1280, height: 720 }
    });
    this.traceDetector = new TraceDetector({}, void 0, this.db);
    this.contextRetrieval = new LLMContextRetrieval(
      this.db,
      this.frameManager,
      this.projectId
    );
    this.discoveryHandlers = new DiscoveryHandlers({
      frameManager: this.frameManager,
      contextRetrieval: this.contextRetrieval,
      db: this.db,
      projectRoot: this.projectRoot
    });
    this.setupHandlers();
    this.loadInitialContext();
    this.browserMCP.initialize(this.server).catch((error) => {
      logger.error("Failed to initialize Browser MCP", error);
    });
    logger.info("StackMemory MCP Server initialized", {
      projectRoot: this.projectRoot,
      projectId: this.projectId
    });
  }
  findProjectRoot() {
    let dir = process.cwd();
    while (dir !== "/") {
      if (existsSync(join(dir, ".git"))) {
        return dir;
      }
      dir = dirname(dir);
    }
    return process.cwd();
  }
  initDB() {
    this.db.exec(`
      CREATE TABLE IF NOT EXISTS contexts (
        id TEXT PRIMARY KEY,
        type TEXT NOT NULL,
        content TEXT NOT NULL,
        importance REAL DEFAULT 0.5,
        created_at INTEGER DEFAULT (unixepoch()),
        last_accessed INTEGER DEFAULT (unixepoch()),
        access_count INTEGER DEFAULT 1
      );

      CREATE TABLE IF NOT EXISTS attention_log (
        id INTEGER PRIMARY KEY AUTOINCREMENT,
        context_id TEXT,
        query TEXT,
        response TEXT,
        influence_score REAL,
        timestamp INTEGER DEFAULT (unixepoch())
      );
    `);
  }
  loadInitialContext() {
    const projectInfo = this.getProjectInfo();
    this.addContext(
      "project",
      `Project: ${projectInfo.name}
Path: ${projectInfo.path}`,
      0.9
    );
    try {
      const recentCommits = execSync("git log --oneline -10", {
        cwd: this.projectRoot
      }).toString();
      this.addContext("git_history", `Recent commits:
${recentCommits}`, 0.6);
    } catch {
    }
    const readmePath = join(this.projectRoot, "README.md");
    if (existsSync(readmePath)) {
      const readme = readFileSync(readmePath, "utf-8");
      const summary = readme.substring(0, 500);
      this.addContext("readme", `Project README:
${summary}...`, 0.8);
    }
    this.loadStoredContexts();
  }
  getProjectId() {
    let identifier;
    try {
      identifier = execSync("git config --get remote.origin.url", {
        cwd: this.projectRoot,
        stdio: "pipe",
        timeout: 5e3
      }).toString().trim();
    } catch {
      identifier = this.projectRoot;
    }
    const cleaned = identifier.replace(/\.git$/, "").replace(/[^a-zA-Z0-9-]/g, "-").toLowerCase();
    return cleaned.substring(cleaned.length - 50) || "unknown";
  }
  getProjectInfo() {
    const packageJsonPath = join(this.projectRoot, "package.json");
    if (existsSync(packageJsonPath)) {
      const pkg = JSON.parse(readFileSync(packageJsonPath, "utf-8"));
      return {
        name: pkg.name || "unknown",
        path: this.projectRoot
      };
    }
    return {
      name: this.projectRoot.split("/").pop() || "unknown",
      path: this.projectRoot
    };
  }
  addContext(type, content, importance = 0.5) {
    const id = `${type}_${Date.now()}`;
    this.db.prepare(
      `
      INSERT OR REPLACE INTO contexts (id, type, content, importance)
      VALUES (?, ?, ?, ?)
    `
    ).run(id, type, content, importance);
    this.contexts.set(id, { type, content, importance });
    return id;
  }
  loadStoredContexts() {
    const stored = this.db.prepare(
      `
      SELECT * FROM contexts 
      ORDER BY importance DESC, last_accessed DESC
      LIMIT 50
    `
    ).all();
    stored.forEach((ctx) => {
      this.contexts.set(ctx.id, ctx);
    });
  }
  setupHandlers() {
    this.server.setRequestHandler(
      z.object({
        method: z.literal("tools/list")
      }),
      async () => {
        return {
          tools: [
            {
              name: "get_context",
              description: "Get current project context",
              inputSchema: {
                type: "object",
                properties: {
                  query: {
                    type: "string",
                    description: "What you want to know"
                  },
                  limit: {
                    type: "number",
                    description: "Max contexts to return"
                  }
                }
              }
            },
            {
              name: "add_decision",
              description: "Record a decision or important information",
              inputSchema: {
                type: "object",
                properties: {
                  content: {
                    type: "string",
                    description: "The decision or information"
                  },
                  type: {
                    type: "string",
                    enum: ["decision", "constraint", "learning"]
                  }
                },
                required: ["content", "type"]
              }
            },
            {
              name: "start_frame",
              description: "Start a new frame (task/subtask) on the call stack",
              inputSchema: {
                type: "object",
                properties: {
                  name: { type: "string", description: "Frame name/goal" },
                  type: {
                    type: "string",
                    enum: [
                      "task",
                      "subtask",
                      "tool_scope",
                      "review",
                      "write",
                      "debug"
                    ],
                    description: "Frame type"
                  },
                  constraints: {
                    type: "array",
                    items: { type: "string" },
                    description: "Constraints for this frame"
                  }
                },
                required: ["name", "type"]
              }
            },
            {
              name: "close_frame",
              description: "Close current frame and generate digest",
              inputSchema: {
                type: "object",
                properties: {
                  result: {
                    type: "string",
                    description: "Frame completion result"
                  },
                  outputs: {
                    type: "object",
                    description: "Final outputs from frame"
                  }
                }
              }
            },
            {
              name: "add_anchor",
              description: "Add anchored fact/decision/constraint to current frame",
              inputSchema: {
                type: "object",
                properties: {
                  type: {
                    type: "string",
                    enum: [
                      "FACT",
                      "DECISION",
                      "CONSTRAINT",
                      "INTERFACE_CONTRACT",
                      "TODO",
                      "RISK"
                    ],
                    description: "Anchor type"
                  },
                  text: { type: "string", description: "Anchor content" },
                  priority: {
                    type: "number",
                    description: "Priority (0-10)",
                    minimum: 0,
                    maximum: 10
                  }
                },
                required: ["type", "text"]
              }
            },
            {
              name: "get_hot_stack",
              description: "Get current active frames and context",
              inputSchema: {
                type: "object",
                properties: {
                  maxEvents: {
                    type: "number",
                    description: "Max recent events per frame",
                    default: 20
                  }
                }
              }
            },
            {
              name: "create_task",
              description: "Create a new task in git-tracked JSONL storage",
              inputSchema: {
                type: "object",
                properties: {
                  title: { type: "string", description: "Task title" },
                  description: {
                    type: "string",
                    description: "Task description"
                  },
                  priority: {
                    type: "string",
                    enum: ["low", "medium", "high", "urgent"],
                    description: "Task priority"
                  },
                  estimatedEffort: {
                    type: "number",
                    description: "Estimated effort in minutes"
                  },
                  dependsOn: {
                    type: "array",
                    items: { type: "string" },
                    description: "Task IDs this depends on"
                  },
                  tags: {
                    type: "array",
                    items: { type: "string" },
                    description: "Tags for categorization"
                  }
                },
                required: ["title"]
              }
            },
            {
              name: "update_task_status",
              description: "Update task status with automatic time tracking",
              inputSchema: {
                type: "object",
                properties: {
                  taskId: { type: "string", description: "Task ID to update" },
                  status: {
                    type: "string",
                    enum: [
                      "pending",
                      "in_progress",
                      "completed",
                      "blocked",
                      "cancelled"
                    ],
                    description: "New status"
                  },
                  reason: {
                    type: "string",
                    description: "Reason for status change (especially for blocked)"
                  }
                },
                required: ["taskId", "status"]
              }
            },
            {
              name: "get_active_tasks",
              description: "Get currently active tasks synced from Linear",
              inputSchema: {
                type: "object",
                properties: {
                  frameId: {
                    type: "string",
                    description: "Filter by specific frame ID"
                  },
                  status: {
                    type: "string",
                    enum: [
                      "pending",
                      "in_progress",
                      "completed",
                      "blocked",
                      "cancelled"
                    ],
                    description: "Filter by status"
                  },
                  priority: {
                    type: "string",
                    enum: ["low", "medium", "high", "urgent"],
                    description: "Filter by priority"
                  },
                  search: {
                    type: "string",
                    description: "Search in task title or description"
                  },
                  limit: {
                    type: "number",
                    description: "Max number of tasks to return (default: 20)"
                  }
                }
              }
            },
            {
              name: "get_task_metrics",
              description: "Get project task metrics and analytics",
              inputSchema: {
                type: "object",
                properties: {}
              }
            },
            {
              name: "add_task_dependency",
              description: "Add dependency relationship between tasks",
              inputSchema: {
                type: "object",
                properties: {
                  taskId: {
                    type: "string",
                    description: "Task that depends on another"
                  },
                  dependsOnId: {
                    type: "string",
                    description: "Task ID that this depends on"
                  }
                },
                required: ["taskId", "dependsOnId"]
              }
            },
            {
              name: "linear_sync",
              description: "Sync tasks with Linear",
              inputSchema: {
                type: "object",
                properties: {
                  direction: {
                    type: "string",
                    enum: ["bidirectional", "to_linear", "from_linear"],
                    description: "Sync direction"
                  }
                }
              }
            },
            {
              name: "linear_update_task",
              description: "Update a Linear task status",
              inputSchema: {
                type: "object",
                properties: {
                  issueId: {
                    type: "string",
                    description: "Linear issue ID or identifier (e.g., STA-34)"
                  },
                  status: {
                    type: "string",
                    enum: ["todo", "in-progress", "done", "canceled"],
                    description: "New status for the task"
                  },
                  title: {
                    type: "string",
                    description: "Update task title (optional)"
                  },
                  description: {
                    type: "string",
                    description: "Update task description (optional)"
                  },
                  priority: {
                    type: "number",
                    enum: [1, 2, 3, 4],
                    description: "Priority (1=urgent, 2=high, 3=medium, 4=low)"
                  }
                },
                required: ["issueId"]
              }
            },
            {
              name: "linear_get_tasks",
              description: "Get Linear tasks",
              inputSchema: {
                type: "object",
                properties: {
                  status: {
                    type: "string",
                    enum: ["todo", "in-progress", "done", "all"],
                    description: "Filter by status"
                  },
                  limit: {
                    type: "number",
                    description: "Maximum number of tasks to return"
                  }
                }
              }
            },
            {
              name: "linear_status",
              description: "Get Linear integration status",
              inputSchema: {
                type: "object",
                properties: {}
              }
            },
            {
              name: "get_traces",
              description: "Get detected traces (bundled tool call sequences)",
              inputSchema: {
                type: "object",
                properties: {
                  type: {
                    type: "string",
                    enum: [
                      "search_driven",
                      "error_recovery",
                      "feature_implementation",
                      "refactoring",
                      "testing",
                      "exploration",
                      "debugging",
                      "documentation",
                      "build_deploy",
                      "unknown"
                    ],
                    description: "Filter by trace type"
                  },
                  minScore: {
                    type: "number",
                    description: "Minimum importance score (0-1)"
                  },
                  limit: {
                    type: "number",
                    description: "Maximum number of traces to return"
                  }
                }
              }
            },
            {
              name: "get_trace_statistics",
              description: "Get statistics about detected traces",
              inputSchema: {
                type: "object",
                properties: {}
              }
            },
            {
              name: "flush_traces",
              description: "Flush any pending trace and finalize detection",
              inputSchema: {
                type: "object",
                properties: {}
              }
            },
            {
              name: "compress_old_traces",
              description: "Compress traces older than specified hours",
              inputSchema: {
                type: "object",
                properties: {
                  ageHours: {
                    type: "number",
                    description: "Age threshold in hours (default: 24)"
                  }
                }
              }
            },
            {
              name: "smart_context",
              description: "LLM-driven context retrieval - intelligently selects relevant frames based on query",
              inputSchema: {
                type: "object",
                properties: {
                  query: {
                    type: "string",
                    description: "Natural language query describing what context you need"
                  },
                  tokenBudget: {
                    type: "number",
                    description: "Maximum tokens to use for context (default: 4000)"
                  },
                  forceRefresh: {
                    type: "boolean",
                    description: "Force refresh of cached summaries"
                  }
                },
                required: ["query"]
              }
            },
            {
              name: "get_summary",
              description: "Get compressed summary of project memory for analysis",
              inputSchema: {
                type: "object",
                properties: {
                  forceRefresh: {
                    type: "boolean",
                    description: "Force refresh of cached summary"
                  }
                }
              }
            },
            // Discovery tools
            {
              name: "sm_discover",
              description: "Discover relevant files based on current context. Extracts keywords from active frames and searches codebase.",
              inputSchema: {
                type: "object",
                properties: {
                  query: {
                    type: "string",
                    description: "Optional query to focus the discovery"
                  },
                  depth: {
                    type: "string",
                    enum: ["shallow", "medium", "deep"],
                    description: "Search depth"
                  },
                  maxFiles: {
                    type: "number",
                    description: "Maximum files to return"
                  }
                }
              }
            },
            {
              name: "sm_related_files",
              description: "Find files related to a specific file or concept",
              inputSchema: {
                type: "object",
                properties: {
                  file: {
                    type: "string",
                    description: "File path to find related files for"
                  },
                  concept: {
                    type: "string",
                    description: "Concept to search for"
                  },
                  maxFiles: {
                    type: "number",
                    description: "Maximum files to return"
                  }
                }
              }
            },
            {
              name: "sm_session_summary",
              description: "Get summary of current session with active tasks, files, and decisions",
              inputSchema: {
                type: "object",
                properties: {
                  includeFiles: {
                    type: "boolean",
                    description: "Include recently accessed files"
                  },
                  includeDecisions: {
                    type: "boolean",
                    description: "Include recent decisions"
                  }
                }
              }
            },
            {
              name: "sm_search",
              description: "Search across StackMemory - frames, events, decisions, tasks",
              inputSchema: {
                type: "object",
                properties: {
                  query: {
                    type: "string",
                    description: "Search query"
                  },
                  scope: {
                    type: "string",
                    enum: ["all", "frames", "events", "decisions", "tasks"],
                    description: "Scope of search"
                  },
                  limit: {
                    type: "number",
                    description: "Maximum results"
                  }
                },
                required: ["query"]
              }
            }
          ]
        };
      }
    );
    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();
        const currentFrameId = this.frameManager.getCurrentFrameId();
        if (currentFrameId) {
          this.frameManager.addEvent("tool_call", {
            tool_name: name,
            arguments: args,
            timestamp: startTime
          });
        }
        const toolCall = {
          id: callId,
          tool: name,
          arguments: args,
          timestamp: startTime
        };
        let result;
        let error;
        try {
          switch (name) {
            case "get_context":
              result = await this.handleGetContext(args);
              break;
            case "add_decision":
              result = await this.handleAddDecision(args);
              break;
            case "start_frame":
              result = await this.handleStartFrame(args);
              break;
            case "close_frame":
              result = await this.handleCloseFrame(args);
              break;
            case "add_anchor":
              result = await this.handleAddAnchor(args);
              break;
            case "get_hot_stack":
              result = await this.handleGetHotStack(args);
              break;
            case "create_task":
              result = await this.handleCreateTask(args);
              break;
            case "update_task_status":
              result = await this.handleUpdateTaskStatus(args);
              break;
            case "get_active_tasks":
              result = await this.handleGetActiveTasks(args);
              break;
            case "get_task_metrics":
              result = await this.handleGetTaskMetrics(args);
              break;
            case "add_task_dependency":
              result = await this.handleAddTaskDependency(args);
              break;
            case "linear_sync":
              result = await this.handleLinearSync(args);
              break;
            case "linear_update_task":
              result = await this.handleLinearUpdateTask(args);
              break;
            case "linear_get_tasks":
              result = await this.handleLinearGetTasks(args);
              break;
            case "linear_status":
              result = await this.handleLinearStatus(args);
              break;
            case "get_traces":
              result = await this.handleGetTraces(args);
              break;
            case "get_trace_statistics":
              result = await this.handleGetTraceStatistics(args);
              break;
            case "flush_traces":
              result = await this.handleFlushTraces(args);
              break;
            case "compress_old_traces":
              result = await this.handleCompressOldTraces(args);
              break;
            case "smart_context":
              result = await this.handleSmartContext(args);
              break;
            case "get_summary":
              result = await this.handleGetSummary(args);
              break;
            // Discovery tools
            case "sm_discover":
              result = await this.handleSmDiscover(args);
              break;
            case "sm_related_files":
              result = await this.handleSmRelatedFiles(args);
              break;
            case "sm_session_summary":
              result = await this.handleSmSessionSummary(args);
              break;
            case "sm_search":
              result = await this.handleSmSearch(args);
              break;
            default:
              throw new Error(`Unknown tool: ${name}`);
          }
        } catch (err) {
          error = err instanceof Error ? err : new Error(String(err));
          toolCall.error = error.message;
          throw err;
        } finally {
          const endTime = Date.now();
          if (currentFrameId && name !== "close_frame") {
            try {
              this.frameManager.addEvent("tool_result", {
                tool_name: name,
                success: !error,
                result: error ? { error: error.message } : result,
                timestamp: endTime
              });
            } catch {
            }
          }
          toolCall.result = error ? void 0 : result;
          toolCall.duration = endTime - startTime;
          if (args.file_path || args.path) {
            toolCall.filesAffected = [args.file_path || args.path].filter(
              Boolean
            );
          } else if (result?.files) {
            const files = result.files;
            toolCall.filesAffected = Array.isArray(files) ? files : [files];
          }
          this.traceDetector.addToolCall(toolCall);
        }
        return result;
      }
    );
  }
  async handleGetContext(args) {
    const { query = "", limit = 10 } = args;
    const contexts = Array.from(this.contexts.values()).sort((a, b) => b.importance - a.importance).slice(0, limit);
    contexts.forEach((ctx) => {
      this.db.prepare(
        `
        UPDATE contexts 
        SET last_accessed = unixepoch(), 
            access_count = access_count + 1
        WHERE id = ?
      `
      ).run(ctx.id);
    });
    const response = contexts.map(
      (ctx) => `[${ctx.type.toUpperCase()}] (importance: ${ctx.importance.toFixed(2)})
${ctx.content}`
    ).join("\n\n---\n\n");
    this.logAttention(query, response);
    return {
      content: [
        {
          type: "text",
          text: response || "No context available yet. Start adding decisions and information!"
        }
      ]
    };
  }
  async handleAddDecision(args) {
    const { content, type = "decision" } = args;
    const id = this.addContext(type, content, 0.8);
    return {
      content: [
        {
          type: "text",
          text: `\u2713 Added ${type}: ${content}
ID: ${id}`
        }
      ]
    };
  }
  async handleStartFrame(args) {
    const { name, type, constraints } = args;
    const inputs = {};
    if (constraints) {
      inputs.constraints = constraints;
    }
    const frameId = this.frameManager.createFrame({
      type,
      name,
      inputs
    });
    this.frameManager.addEvent("user_message", {
      action: "start_frame",
      name,
      type,
      constraints
    });
    this.addContext("active_frame", `Active frame: ${name} (${type})`, 0.9);
    const stackDepth = this.frameManager.getStackDepth();
    return {
      content: [
        {
          type: "text",
          text: `\u{1F680} Started ${type}: ${name}
Frame ID: ${frameId}
Stack depth: ${stackDepth}`
        }
      ]
    };
  }
  async handleCloseFrame(args) {
    const { result, outputs } = args;
    const currentFrameId = this.frameManager.getCurrentFrameId();
    if (!currentFrameId) {
      return {
        content: [
          {
            type: "text",
            text: "\u26A0\uFE0F No active frame to close"
          }
        ]
      };
    }
    this.frameManager.addEvent("assistant_message", {
      action: "close_frame",
      result,
      outputs
    });
    this.frameManager.closeFrame(currentFrameId, outputs);
    const newStackDepth = this.frameManager.getStackDepth();
    return {
      content: [
        {
          type: "text",
          text: `\u2705 Closed frame: ${result || "completed"}
Stack depth: ${newStackDepth}`
        }
      ]
    };
  }
  async handleAddAnchor(args) {
    const { type, text, priority = 5 } = args;
    const anchorId = this.frameManager.addAnchor(type, text, priority);
    this.frameManager.addEvent("decision", {
      anchor_type: type,
      text,
      priority,
      anchor_id: anchorId
    });
    return {
      content: [
        {
          type: "text",
          text: `\u{1F4CC} Added ${type}: ${text}
Anchor ID: ${anchorId}`
        }
      ]
    };
  }
  async handleGetHotStack(args) {
    const { maxEvents = 20 } = args;
    const hotStack = this.frameManager.getHotStackContext(maxEvents);
    const activePath = this.frameManager.getActiveFramePath();
    if (hotStack.length === 0) {
      return {
        content: [
          {
            type: "text",
            text: "\u{1F4DA} No active frames. Start a frame with start_frame tool."
          }
        ]
      };
    }
    let response = "\u{1F4DA} **Active Call Stack:**\n\n";
    activePath.forEach((frame, index) => {
      const indent = "  ".repeat(index);
      const context = hotStack[index];
      response += `${indent}${index + 1}. **${frame.name}** (${frame.type})
`;
      if (context && context.anchors && context.anchors.length > 0) {
        response += `${indent}   \u{1F4CC} ${context.anchors.length} anchors
`;
      }
      if (context && context.recentEvents && context.recentEvents.length > 0) {
        response += `${indent}   \u{1F4DD} ${context.recentEvents.length} recent events
`;
      }
      response += "\n";
    });
    response += `**Total stack depth:** ${hotStack.length}`;
    this.frameManager.addEvent("observation", {
      action: "get_hot_stack",
      stack_depth: hotStack.length,
      total_anchors: hotStack.reduce(
        (sum, frame) => sum + frame.anchors.length,
        0
      ),
      total_events: hotStack.reduce(
        (sum, frame) => sum + frame.recentEvents.length,
        0
      )
    });
    return {
      content: [
        {
          type: "text",
          text: response
        }
      ]
    };
  }
  logAttention(query, response) {
    this.db.prepare(
      `
      INSERT INTO attention_log (query, response)
      VALUES (?, ?)
    `
    ).run(query, response);
  }
  async handleCreateTask(args) {
    const { title, description, priority, estimatedEffort, dependsOn, tags } = args;
    const currentFrameId = this.frameManager.getCurrentFrameId();
    if (!currentFrameId) {
      return {
        content: [
          {
            type: "text",
            text: "\u26A0\uFE0F No active frame. Start a frame first with start_frame tool."
          }
        ]
      };
    }
    const taskId = this.taskStore.createTask({
      title,
      description,
      priority,
      frameId: currentFrameId,
      dependsOn,
      tags,
      estimatedEffort
    });
    this.frameManager.addEvent("decision", {
      action: "create_task",
      task_id: taskId,
      title,
      priority: priority || "medium"
    });
    return {
      content: [
        {
          type: "text",
          text: `\u2705 Created task: ${title}
ID: ${taskId}
Frame: ${currentFrameId}
Stored in: .stackmemory/tasks.jsonl`
        }
      ]
    };
  }
  async handleUpdateTaskStatus(args) {
    const { taskId, status, reason } = args;
    try {
      this.taskStore.updateTaskStatus(taskId, status, reason);
      this.frameManager.addEvent("observation", {
        action: "update_task_status",
        task_id: taskId,
        new_status: status,
        reason
      });
      return {
        content: [
          {
            type: "text",
            text: `\u2705 Updated task ${taskId} to ${status}${reason ? `
Reason: ${reason}` : ""}`
          }
        ]
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: `\u274C Failed to update task: ${error}`
          }
        ]
      };
    }
  }
  async handleGetActiveTasks(args) {
    const { frameId, status, priority, search, limit = 20 } = args;
    let tasks = this.taskStore.getActiveTasks(frameId);
    if (status) {
      tasks = tasks.filter((t) => t.status === status);
    }
    if (priority) {
      tasks = tasks.filter((t) => t.priority === priority);
    }
    if (search) {
      const searchLower = search.toLowerCase();
      tasks = tasks.filter(
        (t) => t.title.toLowerCase().includes(searchLower) || t.description && t.description.toLowerCase().includes(searchLower)
      );
    }
    const priorityOrder = { urgent: 0, high: 1, medium: 2, low: 3 };
    tasks.sort((a, b) => {
      const pa = priorityOrder[a.priority] ?? 2;
      const pb = priorityOrder[b.priority] ?? 2;
      if (pa !== pb) return pa - pb;
      return b.created_at - a.created_at;
    });
    tasks = tasks.slice(0, limit);
    if (tasks.length === 0) {
      return {
        content: [
          {
            type: "text",
            text: search ? `\u{1F4DD} No tasks matching "${search}"` : "\u{1F4DD} No active tasks found"
          }
        ]
      };
    }
    let response = `\u{1F4DD} **Tasks** (${tasks.length} found)

`;
    tasks.forEach((task) => {
      const priorityIcon = { urgent: "\u{1F534}", high: "\u{1F7E0}", medium: "\u{1F7E1}", low: "\u{1F7E2}" }[task.priority] || "\u26AA";
      const statusIcon = {
        pending: "\u23F3",
        in_progress: "\u{1F504}",
        completed: "\u2705",
        blocked: "\u{1F6AB}",
        cancelled: "\u274C"
      }[task.status] || "\u26AA";
      const effort = task.estimated_effort ? ` (~${task.estimated_effort}m)` : "";
      const linearMatch = task.title.match(/\[ENG-\d+\]/);
      const linearId = linearMatch ? linearMatch[0] : "";
      const title = linearId ? task.title.replace(linearId, "").trim() : task.title;
      response += `${statusIcon} ${priorityIcon} **${linearId || task.id}** ${title}${effort}
`;
      if (task.description) {
        const desc = task.description.split("\n")[0].slice(0, 100);
        response += `   ${desc}${task.description.length > 100 ? "..." : ""}
`;
      }
      if (task.tags && task.tags.length > 0) {
        response += `   \u{1F3F7}\uFE0F ${task.tags.join(", ")}
`;
      }
      response += "\n";
    });
    return {
      content: [
        {
          type: "text",
          text: response
        }
      ]
    };
  }
  async handleGetTaskMetrics(_args) {
    const metrics = this.taskStore.getMetrics();
    let response = "\u{1F4CA} **Task Metrics**\n\n";
    response += `**Total Tasks:** ${metrics.total_tasks}
`;
    response += `**Completion Rate:** ${(metrics.completion_rate * 100).toFixed(1)}%

`;
    response += "**By Status:**\n";
    Object.entries(metrics.by_status).forEach(([status, count]) => {
      response += `- ${status}: ${count}
`;
    });
    response += "\n**By Priority:**\n";
    Object.entries(metrics.by_priority).forEach(([priority, count]) => {
      response += `- ${priority}: ${count}
`;
    });
    if (metrics.blocked_tasks > 0) {
      response += `
\u26A0\uFE0F **${metrics.blocked_tasks} blocked tasks**`;
    }
    if (metrics.avg_effort_accuracy > 0) {
      response += `
\u{1F3AF} **Effort Accuracy:** ${(metrics.avg_effort_accuracy * 100).toFixed(1)}%`;
    }
    return {
      content: [
        {
          type: "text",
          text: response
        }
      ]
    };
  }
  async handleAddTaskDependency(args) {
    const { taskId, dependsOnId } = args;
    try {
      this.taskStore.addDependency(taskId, dependsOnId);
      this.frameManager.addEvent("decision", {
        action: "add_task_dependency",
        task_id: taskId,
        depends_on_id: dependsOnId
      });
      return {
        content: [
          {
            type: "text",
            text: `\u{1F517} Added dependency: ${taskId} depends on ${dependsOnId}`
          }
        ]
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: `\u274C Failed to add dependency: ${error}`
          }
        ]
      };
    }
  }
  // Linear Integration Handlers
  async handleLinearSync(args) {
    try {
      const tokens = this.linearAuthManager.loadTokens();
      if (!tokens) {
        return {
          content: [
            {
              type: "text",
              text: "\u274C Linear not authenticated. Run: stackmemory linear setup"
            }
          ]
        };
      }
      const syncConfig = { ...DEFAULT_SYNC_CONFIG, enabled: true };
      if (args.direction) {
        syncConfig.direction = args.direction;
      }
      this.linearSync.updateConfig(syncConfig);
      const result = await this.linearSync.sync();
      return {
        content: [
          {
            type: "text",
            text: `\u2705 Linear sync completed
- To Linear: ${result.synced.toLinear} tasks
- From Linear: ${result.synced.fromLinear} tasks
- Updated: ${result.synced.updated} tasks`
          }
        ]
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: `\u274C Linear sync failed: ${error.message}`
          }
        ]
      };
    }
  }
  async handleLinearUpdateTask(args) {
    try {
      const { LinearClient } = await import("../linear/client.js");
      const tokens = this.linearAuthManager.loadTokens();
      if (!tokens) {
        return {
          content: [
            {
              type: "text",
              text: "\u274C Linear not authenticated. Run: stackmemory linear setup"
            }
          ]
        };
      }
      const client = new LinearClient({
        apiKey: tokens.accessToken,
        useBearer: true,
        onUnauthorized: async () => {
          const refreshed = await this.linearAuthManager.refreshAccessToken();
          return refreshed.accessToken;
        }
      });
      let issue = await client.getIssue(args.issueId);
      if (!issue) {
        issue = await client.findIssueByIdentifier(args.issueId);
      }
      if (!issue) {
        return {
          content: [
            {
              type: "text",
              text: `\u274C Linear issue ${args.issueId} not found`
            }
          ]
        };
      }
      const updates = {};
      if (args.status) {
        const team = await client.getTeam();
        const states = await client.getWorkflowStates(team.id);
        const statusMap = {
          todo: "unstarted",
          "in-progress": "started",
          done: "completed",
          canceled: "cancelled"
        };
        const targetType = statusMap[args.status] || args.status;
        const targetState = states.find((s) => s.type === targetType);
        if (!targetState) {
          return {
            content: [
              {
                type: "text",
                text: `\u274C Invalid status: ${args.status}`
              }
            ]
          };
        }
        updates.stateId = targetState.id;
      }
      if (args.title) updates.title = args.title;
      if (args.description) updates.description = args.description;
      if (args.priority) updates.priority = args.priority;
      const updatedIssue = await client.updateIssue(issue.id, updates);
      this.linearSync.updateConfig({
        ...DEFAULT_SYNC_CONFIG,
        enabled: true,
        direction: "from_linear"
      });
      const syncResult = await this.linearSync.sync();
      let response = `\u2705 Updated ${updatedIssue.identifier}: ${updatedIssue.title}
`;
      if (args.status) {
        response += `Status: ${updatedIssue.state.name}
`;
      }
      response += `URL: ${updatedIssue.url}
`;
      response += `
\u{1F504} Local sync: ${syncResult.synced.fromLinear} new, ${syncResult.synced.updated} updated`;
      return {
        content: [
          {
            type: "text",
            text: response
          }
        ]
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: `\u274C Failed to update Linear task: ${error.message}`
          }
        ]
      };
    }
  }
  async handleLinearGetTasks(args) {
    try {
      const { LinearClient } = await import("../linear/client.js");
      const tokens = this.linearAuthManager.loadTokens();
      if (!tokens) {
        return {
          content: [
            {
              type: "text",
              text: "\u274C Linear not authenticated. Run: stackmemory linear setup"
            }
          ]
        };
      }
      const client = new LinearClient({
        apiKey: tokens.accessToken,
        useBearer: true,
        onUnauthorized: async () => {
          const refreshed = await this.linearAuthManager.refreshAccessToken();
          return refreshed.accessToken;
        }
      });
      let stateType = void 0;
      if (args.status && args.status !== "all") {
        const statusMap = {
          todo: "unstarted",
          "in-progress": "started",
          done: "completed"
        };
        stateType = statusMap[args.status] || args.status;
      }
      const issues = await client.getIssues({
        stateType,
        limit: args.limit || 20
      });
      if (!issues || issues.length === 0) {
        return {
          content: [
            {
              type: "text",
              text: "No Linear tasks found"
            }
          ]
        };
      }
      let response = `\u{1F4CB} **Linear Tasks** (${issues.length} items)

`;
      issues.forEach((issue) => {
        const priority = issue.priority ? `P${issue.priority}` : "-";
        response += `- **${issue.identifier}**: ${issue.title}
`;
        response += `  Status: ${issue.state.name} | Priority: ${priority}
`;
        if (issue.assignee) {
          response += `  Assignee: ${issue.assignee.name}
`;
        }
        response += `  ${issue.url}

`;
      });
      return {
        content: [
          {
            type: "text",
            text: response
          }
        ]
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: `\u274C Failed to get Linear tasks: ${error.message}`
          }
        ]
      };
    }
  }
  async handleLinearStatus(_args) {
    try {
      const { LinearClient } = await import("../linear/client.js");
      const tokens = this.linearAuthManager.loadTokens();
      if (!tokens) {
        return {
          content: [
            {
              type: "text",
              text: "\u274C Linear integration not configured\nRun: stackmemory linear setup"
            }
          ]
        };
      }
      try {
        const client = new LinearClient({
          apiKey: tokens.accessToken,
          useBearer: true,
          onUnauthorized: async () => {
            const refreshed = await this.linearAuthManager.refreshAccessToken();
            return refreshed.accessToken;
          }
        });
        const viewer = await client.getViewer();
        const team = await client.getTeam();
        return {
          content: [
            {
              type: "text",
              text: `\u2705 **Linear Integration Status**

Connected as: ${viewer.name} (${viewer.email})
Team: ${team.name} (${team.key})
Tokens: Valid`
            }
          ]
        };
      } catch (error) {
        return {
          content: [
            {
              type: "text",
              text: `\u26A0\uFE0F Linear configured but connection failed: ${error.message}`
            }
          ]
        };
      }
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: `\u274C Linear status check failed: ${error.message}`
          }
        ]
      };
    }
  }
  async handleGetTraces(args) {
    const { type, minScore, limit = 20 } = args;
    this.traceDetector.flush();
    let traces = this.traceDetector.getTraces();
    if (type) {
      traces = traces.filter((t) => t.type === type);
    }
    if (minScore !== void 0) {
      traces = traces.filter((t) => t.score >= minScore);
    }
    traces = traces.sort((a, b) => b.score - a.score).slice(0, limit);
    const formattedTraces = traces.map((trace) => ({
      id: trace.id,
      type: trace.type,
      score: trace.score.toFixed(2),
      summary: trace.summary,
      toolCount: trace.tools.length,
      duration: `${((trace.metadata.endTime - trace.metadata.startTime) / 1e3).toFixed(1)}s`,
      filesModified: trace.metadata.filesModified.length,
      hasErrors: trace.metadata.errorsEncountered.length > 0,
      compressed: !!trace.compressed
    }));
    return {
      content: [
        {
          type: "text",
          text: `Found ${formattedTraces.length} traces:

${formattedTraces.map(
            (t) => `[${t.type}] Score: ${t.score} | Tools: ${t.toolCount} | Duration: ${t.duration}
  ${t.summary}`
          ).join("\n\n")}`
        }
      ]
    };
  }
  async handleGetTraceStatistics(args) {
    this.traceDetector.flush();
    const stats = this.traceDetector.getStatistics();
    const typeBreakdown = Object.entries(stats.tracesByType).map(([type, count]) => `  ${type}: ${count}`).join("\n");
    return {
      content: [
        {
          type: "text",
          text: `**Trace Statistics**

Total Traces: ${stats.totalTraces}
Average Score: ${stats.averageScore.toFixed(2)}
Average Length: ${stats.averageLength.toFixed(1)} tools
High Importance (>0.7): ${stats.highImportanceCount}
Compressed: ${stats.compressedCount}

**Trace Types:**
${typeBreakdown}`
        }
      ]
    };
  }
  async handleFlushTraces(args) {
    this.traceDetector.flush();
    return {
      content: [
        {
          type: "text",
          text: "Pending traces have been flushed and finalized."
        }
      ]
    };
  }
  async handleCompressOldTraces(args) {
    const { ageHours = 24 } = args;
    const compressedCount = this.traceDetector.compressOldTraces(ageHours);
    return {
      content: [
        {
          type: "text",
          text: `Compressed ${compressedCount} traces older than ${ageHours} hours.`
        }
      ]
    };
  }
  async handleSmartContext(args) {
    const { query, tokenBudget = 4e3, forceRefresh = false } = args;
    try {
      const result = await this.contextRetrieval.retrieveContext(query, {
        tokenBudget,
        forceRefresh
      });
      const currentFrameId = this.frameManager.getCurrentFrameId();
      if (currentFrameId) {
        this.frameManager.addEvent("observation", {
          action: "smart_context",
          query,
          framesRetrieved: result.frames.length,
          tokenUsage: result.tokenUsage,
          confidence: result.analysis.confidenceScore
        });
      }
      let response = result.context;
      response += `

---
\u{1F4CA} **Retrieval Stats**
`;
      response += `- Frames included: ${result.frames.length}
`;
      response += `- Tokens used: ${result.tokenUsage.used}/${result.tokenUsage.budget}
`;
      response += `- Confidence: ${(result.analysis.confidenceScore * 100).toFixed(0)}%
`;
      response += `- Time: ${result.metadata.retrievalTimeMs}ms`;
      return {
        content: [
          {
            type: "text",
            text: response
          }
        ]
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: `\u274C Context retrieval failed: ${error.message}`
          }
        ]
      };
    }
  }
  async handleGetSummary(args) {
    const { forceRefresh = false } = args;
    try {
      const summary = this.contextRetrieval.getSummary(forceRefresh);
      let response = "\u{1F4CB} **Compressed Memory Summary**\n\n";
      response += "## Recent Session\n";
      response += `- Frames: ${summary.recentSession.frames.length}
`;
      response += `- Time range: ${new Date(summary.recentSession.timeRange.start).toLocaleString()} - ${new Date(summary.recentSession.timeRange.end).toLocaleString()}
`;
      if (summary.recentSession.dominantOperations.length > 0) {
        response += `- Dominant ops: ${summary.recentSession.dominantOperations.slice(0, 5).map((o) => `${o.operation}(${o.count})`).join(", ")}
`;
      }
      if (summary.recentSession.filesTouched.length > 0) {
        response += `- Files touched: ${summary.recentSession.filesTouched.slice(0, 5).map((f) => f.path).join(", ")}
`;
      }
      if (summary.recentSession.errorsEncountered.length > 0) {
        response += `- Errors: ${summary.recentSession.errorsEncountered.length}
`;
      }
      response += "\n## Historical Patterns\n";
      response += `- Topic counts: ${Object.keys(summary.historicalPatterns.topicFrameCounts).length} topics
`;
      if (summary.historicalPatterns.keyDecisions.length > 0) {
        response += `
### Key Decisions (${summary.historicalPatterns.keyDecisions.length})
`;
        summary.historicalPatterns.keyDecisions.slice(0, 5).forEach((d) => {
          response += `- ${d.text.substring(0, 80)}${d.text.length > 80 ? "..." : ""}
`;
        });
      }
      if (summary.historicalPatterns.recurringIssues.length > 0) {
        response += `
### Recurring Issues (${summary.historicalPatterns.recurringIssues.length})
`;
        summary.historicalPatterns.recurringIssues.slice(0, 3).forEach((i) => {
          response += `- ${i.issueType} (${i.occurrenceCount} times)
`;
        });
      }
      response += "\n## Available Indices\n";
      response += `- By time: ${Object.keys(summary.queryableIndices.byTimeframe).length} periods
`;
      response += `- By file: ${Object.keys(summary.queryableIndices.byFile).length} files
`;
      response += `- By topic: ${Object.keys(summary.queryableIndices.byTopic).length} topics
`;
      response += `- By error: ${Object.keys(summary.queryableIndices.byErrorType).length} error types
`;
      response += `
## Stats
`;
      response += `- Total frames: ${summary.stats.totalFrames}
`;
      response += `- Total anchors: ${summary.stats.totalAnchors}
`;
      response += `- Total events: ${summary.stats.totalEvents}
`;
      response += `- Generated: ${new Date(summary.generatedAt).toLocaleString()}`;
      return {
        content: [
          {
            type: "text",
            text: response
          }
        ]
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: `\u274C Failed to get summary: ${error.message}`
          }
        ]
      };
    }
  }
  // ============================================
  // Discovery Tools Handlers
  // ============================================
  async handleSmDiscover(args) {
    return this.discoveryHandlers.handleDiscover(args);
  }
  async handleSmRelatedFiles(args) {
    return this.discoveryHandlers.handleRelatedFiles(args);
  }
  async handleSmSessionSummary(args) {
    return this.discoveryHandlers.handleSessionSummary(args);
  }
  async handleSmSearch(args) {
    try {
      const { query, scope = "all", limit = 20 } = args;
      if (!query) {
        throw new Error("Query is required");
      }
      const results = [];
      if (scope === "all" || scope === "frames") {
        const frames = this.db.prepare(
          `
          SELECT frame_id, name, type, created_at, inputs, outputs
          FROM frames
          WHERE project_id = ? AND (name LIKE ? OR inputs LIKE ? OR outputs LIKE ?)
          ORDER BY created_at DESC
          LIMIT ?
        `
        ).all(
          this.projectId,
          `%${query}%`,
          `%${query}%`,
          `%${query}%`,
          limit
        );
        frames.forEach((f) => {
          results.push({
            type: "frame",
            id: f.frame_id,
            name: f.name,
            frameType: f.type,
            created: new Date(f.created_at * 1e3).toISOString()
          });
        });
      }
      if (scope === "all" || scope === "events") {
        const events = this.db.prepare(
          `
          SELECT e.event_id, e.type, e.data, e.timestamp, f.name as frame_name
          FROM events e
          JOIN frames f ON e.frame_id = f.frame_id
          WHERE f.project_id = ? AND e.data LIKE ?
          ORDER BY e.timestamp DESC
          LIMIT ?
        `
        ).all(this.projectId, `%${query}%`, limit);
        events.forEach((e) => {
          results.push({
            type: "event",
            id: e.event_id,
            eventType: e.type,
            frame: e.frame_name,
            timestamp: new Date(e.timestamp * 1e3).toISOString()
          });
        });
      }
      if (scope === "all" || scope === "decisions") {
        const anchors = this.db.prepare(
          `
          SELECT a.anchor_id, a.type, a.text, a.priority, a.created_at, f.name as frame_name
          FROM anchors a
          JOIN frames f ON a.frame_id = f.frame_id
          WHERE f.project_id = ? AND a.text LIKE ?
          ORDER BY a.created_at DESC
          LIMIT ?
        `
        ).all(this.projectId, `%${query}%`, limit);
        anchors.forEach((a) => {
          results.push({
            type: "decision",
            id: a.anchor_id,
            decisionType: a.type,
            text: a.text,
            priority: a.priority,
            frame: a.frame_name
          });
        });
      }
      if (scope === "all" || scope === "tasks") {
        try {
          const tasks = this.db.prepare(
            `
            SELECT id, title, description, status, priority
            FROM task_cache
            WHERE title LIKE ? OR description LIKE ?
            ORDER BY created_at DESC
            LIMIT ?
          `
          ).all(`%${query}%`, `%${query}%`, limit);
          tasks.forEach((t) => {
            results.push({
              type: "task",
              id: t.id,
              title: t.title,
              status: t.status,
              priority: t.priority
            });
          });
        } catch {
        }
      }
      let response = `# Search Results for "${query}"

`;
      response += `Found ${results.length} results

`;
      const grouped = results.reduce(
        (acc, r) => {
          if (!acc[r.type]) acc[r.type] = [];
          acc[r.type].push(r);
          return acc;
        },
        {}
      );
      for (const [type, items] of Object.entries(grouped)) {
        response += `## ${type.charAt(0).toUpperCase() + type.slice(1)}s (${items.length})
`;
        for (const item of items.slice(0, 10)) {
          if (type === "frame") {
            response += `- [${item.frameType}] ${item.name}
`;
          } else if (type === "decision") {
            response += `- [${item.decisionType}] ${item.text.slice(0, 60)}...
`;
          } else if (type === "task") {
            response += `- [${item.status}] ${item.title}
`;
          } else {
            response += `- ${JSON.stringify(item).slice(0, 80)}...
`;
          }
        }
        response += "\n";
      }
      return {
        content: [
          {
            type: "text",
            text: response
          }
        ],
        metadata: { results, query, scope }
      };
    } catch (error) {
      return {
        content: [
          {
            type: "text",
            text: `\u274C Search failed: ${error.message}`
          }
        ]
      };
    }
  }
  async start() {
    const transport = new StdioServerTransport();
    await this.server.connect(transport);
    console.error("StackMemory MCP Server started");
  }
}
var server_default = LocalStackMemoryMCP;
async function runMCPServer() {
  const server = new LocalStackMemoryMCP();
  await server.start();
}
if (import.meta.url === `file://${process.argv[1]}`) {
  const server = new LocalStackMemoryMCP();
  server.start().catch(console.error);
}
export {
  server_default as default,
  runMCPServer
};
//# sourceMappingURL=server.js.map
