All files / src main.js

0% Statements 0/56
0% Branches 0/18
0% Functions 0/3
0% Lines 0/56

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201                                                                                                                                                                                                                                                                                                                                                                                                                 
/**
 * Main entry point for the DevContext server
 *
 * This module initializes the server, performs validation checks,
 * connects to the database, and sets up the MCP server.
 */
 
import { McpServer } from "@modelcontextprotocol/sdk";
import { z } from "zod";
import config from "./config.js";
import logger from "./utils/logger.js";
import { initializeDbClient } from "./db/client.js";
import { initializeDatabaseSchema } from "./db/queries.js";
import { pingServerHandler } from "./mcp-handlers/index.js";
import GitMonitorService from "./services/git.service.js";
import initialScanService from "./services/initialScan.service.js";
 
/**
 * Start the server
 */
async function startServer() {
  try {
    // Log server startup
    logger.info("DevContext server starting...");
 
    // Validate that PROJECT_PATH is a Git repository
    const gitValidation = await config.validateGitRepository();
 
    if (!gitValidation.isValid) {
      // This is a critical error - log and exit with non-zero status code
      logger.error(
        "Critical error: PROJECT_PATH is not a valid Git repository",
        {
          projectPath: config.PROJECT_PATH,
          error: gitValidation.error?.message || "Unknown error",
        }
      );
 
      // Exit the process with a non-zero status code
      process.exit(1);
    }
 
    // If we get here, the Git repository is valid
    logger.info("Git repository validation completed successfully");
 
    // Initialize database client
    const dbClient = initializeDbClient();
 
    // Verify database connection with a simple query
    try {
      logger.info("Verifying TursoDB connection...");
      await dbClient.execute("SELECT 1");
      logger.info("TursoDB connection verified successfully");
    } catch (dbError) {
      // This is a critical error - log and exit with non-zero status code
      logger.error("Critical error: Failed to connect to TursoDB", {
        error: dbError.message,
        stack: dbError.stack,
        databaseUrl: config.TURSO_DATABASE_URL ? "(set)" : "(not set)",
        authToken: config.TURSO_AUTH_TOKEN
          ? "(auth token provided)"
          : "(no auth token)",
      });
 
      // Exit the process with a non-zero status code
      process.exit(1);
    }
 
    // Initialize database schema
    try {
      logger.info("Initializing database schema...");
      await initializeDatabaseSchema(dbClient);
      logger.info("Database schema initialization completed successfully");
    } catch (schemaError) {
      // This is a critical error - log and exit with non-zero status code
      logger.error("Critical error: Failed to initialize database schema", {
        error: schemaError.message,
        stack: schemaError.stack,
      });
 
      // Exit the process with a non-zero status code
      process.exit(1);
    }
 
    // Perform initial codebase scan
    try {
      logger.info("Initiating initial codebase scan...");
      const scanResult = await initialScanService.performInitialScan();
      if (scanResult.status === "success") {
        logger.info("Initial codebase scan completed successfully", {
          filesScanned: scanResult.filesScanned,
          filesProcessed: scanResult.filesProcessed,
        });
      } else if (scanResult.status === "skipped") {
        logger.info("Initial codebase scan skipped", {
          reason: scanResult.reason,
        });
      } else {
        logger.warn("Initial codebase scan completed with status", {
          status: scanResult.status,
          error: scanResult.error,
        });
      }
    } catch (scanError) {
      // Log error but don't exit - allow the system to continue
      logger.error("Error during initial codebase scan", {
        error: scanError.message,
        stack: scanError.stack,
      });
      logger.warn("Continuing server startup despite initial scan failure");
    }
 
    // Initialize and start Git monitoring service
    try {
      logger.info("Initializing Git monitoring service...");
      const gitMonitorService = new GitMonitorService(dbClient);
 
      // Initialize the service
      await gitMonitorService.initialize();
 
      // Start the monitoring process
      await gitMonitorService.startMonitoring();
 
      logger.info("Git monitoring service started successfully");
    } catch (gitMonitorError) {
      // Log error but don't exit - this is not a critical service
      logger.error("Error initializing Git monitoring service", {
        error: gitMonitorError.message,
        stack: gitMonitorError.stack,
      });
      logger.warn(
        "Continuing server startup despite Git monitoring service failure"
      );
    }
 
    // Initialize MCP server
    try {
      logger.info("Initializing MCP server...");
 
      // Create the MCP server instance
      const mcpServer = new McpServer({
        name: "DevContext MCP Server",
        version: config.VERSION || "1.0.0",
        logger: logger,
      });
 
      // Register the ping_server tool using the correct method
      mcpServer.tool(
        "ping_server",
        {}, // Empty object as we don't need input parameters
        pingServerHandler
      );
 
      // Start the MCP server
      await mcpServer.listen();
 
      logger.info("MCP server initialized and listening for requests");
      logger.info("DevContext server started successfully");
    } catch (mcpError) {
      // This is a critical error - log and exit with non-zero status code
      logger.error("Critical error: Failed to initialize MCP server", {
        error: mcpError.message,
        stack: mcpError.stack,
      });
 
      // Exit the process with a non-zero status code
      process.exit(1);
    }
  } catch (error) {
    // Handle any unexpected errors during server startup
    logger.error("Unexpected error during server startup", {
      error: error.message,
      stack: error.stack,
    });
 
    // Exit with a non-zero status code on critical errors
    process.exit(1);
  }
}
 
// Handle uncaught exceptions
process.on("uncaughtException", (error) => {
  logger.error("Uncaught exception", {
    error: error.message,
    stack: error.stack,
  });
  process.exit(1);
});
 
// Handle unhandled promise rejections
process.on("unhandledRejection", (reason, promise) => {
  logger.error("Unhandled promise rejection", {
    reason: reason instanceof Error ? reason.message : String(reason),
    stack: reason instanceof Error ? reason.stack : undefined,
  });
  process.exit(1);
});
 
// Start the server
startServer();