  // ============================================
  // Context Operations
  // ============================================

  ipcMain.handle(
    IPC_CHANNELS.CONTEXT_GET,
    async (_, projectId: string): Promise<IPCResult<ProjectContextData>> => {
      const project = projectStore.getProject(projectId);
      if (!project) {
        return { success: false, error: 'Project not found' };
      }

      try {
        // Load project index
        let projectIndex: ProjectIndex | null = null;
        const indexPath = path.join(project.path, AUTO_BUILD_PATHS.PROJECT_INDEX);
        if (existsSync(indexPath)) {
          const content = readFileSync(indexPath, 'utf-8');
          projectIndex = JSON.parse(content);
        }

        // Load graphiti state from most recent spec or project root
        let memoryState: GraphitiMemoryState | null = null;
        let memoryStatus: GraphitiMemoryStatus = {
          enabled: false,
          available: false,
          reason: 'Graphiti not configured'
        };

        // Check for graphiti state in specs
                const specsBaseDir = getSpecsDir(project.autoBuildPath);
        const specsDir = path.join(project.path, specsBaseDir);
        if (existsSync(specsDir)) {
          const specDirs = readdirSync(specsDir)
            .filter((f: string) => {
              const specPath = path.join(specsDir, f);
              return statSync(specPath).isDirectory();
            })
            .sort()
            .reverse();

          for (const specDir of specDirs) {
            const statePath = path.join(specsDir, specDir, AUTO_BUILD_PATHS.GRAPHITI_STATE);
            if (existsSync(statePath)) {
              const stateContent = readFileSync(statePath, 'utf-8');
              memoryState = JSON.parse(stateContent);

              // If we found a state, update memory status
              if (memoryState?.initialized) {
                memoryStatus = {
                  enabled: true,
                  available: true,
                  database: memoryState.database || 'auto_build_memory',
                  host: process.env.GRAPHITI_FALKORDB_HOST || 'localhost',
                  port: parseInt(process.env.GRAPHITI_FALKORDB_PORT || '6380', 10)
                };
              }
              break;
            }
          }
        }

        // Check environment for Graphiti config if not found in specs
        if (!memoryState) {
          // Load project .env file and global settings to check for Graphiti config
          let projectEnvVars: Record<string, string> = {};
          if (project.autoBuildPath) {
            const projectEnvPath = path.join(project.path, project.autoBuildPath, '.env');
            if (existsSync(projectEnvPath)) {
              try {
                const envContent = readFileSync(projectEnvPath, 'utf-8');
                // Parse .env file inline - handle both Unix and Windows line endings
                for (const line of envContent.split(/\r?\n/)) {
                  const trimmed = line.trim();
                  if (!trimmed || trimmed.startsWith('#')) continue;
                  const eqIndex = trimmed.indexOf('=');
                  if (eqIndex > 0) {
                    const key = trimmed.substring(0, eqIndex).trim();
                    let value = trimmed.substring(eqIndex + 1).trim();
                    if ((value.startsWith('"') && value.endsWith('"')) ||
                        (value.startsWith("'") && value.endsWith("'"))) {
                      value = value.slice(1, -1);
                    }
                    projectEnvVars[key] = value;
                  }
                }
              } catch {
                // Continue with empty vars
              }
            }
          }

          // Load global settings for OpenAI API key fallback
          let globalOpenAIKey: string | undefined;
          if (existsSync(settingsPath)) {
            try {
              const settingsContent = readFileSync(settingsPath, 'utf-8');
              const globalSettings = JSON.parse(settingsContent);
              globalOpenAIKey = globalSettings.globalOpenAIApiKey;
            } catch {
              // Continue without global settings
            }
          }

          // Check for Graphiti config: project .env > process.env
          const graphitiEnabled =
            projectEnvVars['GRAPHITI_ENABLED']?.toLowerCase() === 'true' ||
            process.env.GRAPHITI_ENABLED?.toLowerCase() === 'true';

          // Check for OpenAI key: project .env > global settings > process.env
          const hasOpenAI =
            !!projectEnvVars['OPENAI_API_KEY'] ||
            !!globalOpenAIKey ||
            !!process.env.OPENAI_API_KEY;

          // Get Graphiti connection details from project .env or process.env
          const graphitiHost = projectEnvVars['GRAPHITI_FALKORDB_HOST'] || process.env.GRAPHITI_FALKORDB_HOST || 'localhost';
          const graphitiPort = parseInt(projectEnvVars['GRAPHITI_FALKORDB_PORT'] || process.env.GRAPHITI_FALKORDB_PORT || '6380', 10);
          const graphitiDatabase = projectEnvVars['GRAPHITI_DATABASE'] || process.env.GRAPHITI_DATABASE || 'auto_build_memory';

          if (graphitiEnabled && hasOpenAI) {
            memoryStatus = {
              enabled: true,
              available: true,
              host: graphitiHost,
              port: graphitiPort,
              database: graphitiDatabase
            };
          } else if (graphitiEnabled && !hasOpenAI) {
            memoryStatus = {
              enabled: true,
              available: false,
              reason: 'OPENAI_API_KEY not set (required for Graphiti embeddings)'
            };
          }
        }

        // Load recent memories from file-based memory (session insights)
        const recentMemories: MemoryEpisode[] = [];
        if (existsSync(specsDir)) {
          const recentSpecDirs = readdirSync(specsDir)
            .filter((f: string) => {
              const specPath = path.join(specsDir, f);
              return statSync(specPath).isDirectory();
            })
            .sort()
            .reverse()
            .slice(0, 10); // Last 10 specs

          for (const specDir of recentSpecDirs) {
            const memoryDir = path.join(specsDir, specDir, 'memory');
            if (existsSync(memoryDir)) {
              // Load session insights from session_insights subdirectory
              const sessionInsightsDir = path.join(memoryDir, 'session_insights');
              if (existsSync(sessionInsightsDir)) {
                const sessionFiles = readdirSync(sessionInsightsDir)
                  .filter((f: string) => f.startsWith('session_') && f.endsWith('.json'))
                  .sort()
                  .reverse();

                for (const sessionFile of sessionFiles.slice(0, 3)) {
                  try {
                    const sessionPath = path.join(sessionInsightsDir, sessionFile);
                    const sessionContent = readFileSync(sessionPath, 'utf-8');
                    const sessionData = JSON.parse(sessionContent);

                    // Session files have: session_number, timestamp, subtasks_completed,
                    // discoveries, what_worked, what_failed, recommendations_for_next_session
                    if (sessionData.session_number !== undefined) {
                      recentMemories.push({
                        id: `${specDir}-${sessionFile}`,
                        type: 'session_insight',
                        timestamp: sessionData.timestamp || new Date().toISOString(),
                        content: JSON.stringify({
                          discoveries: sessionData.discoveries,
                          what_worked: sessionData.what_worked,
                          what_failed: sessionData.what_failed,
                          recommendations: sessionData.recommendations_for_next_session,
                          subtasks_completed: sessionData.subtasks_completed
                        }, null, 2),
                        session_number: sessionData.session_number
                      });
                    }
                  } catch {
                    // Skip invalid files
                  }
                }
              }

              // Also load codebase_map.json as a memory item
              const codebaseMapPath = path.join(memoryDir, 'codebase_map.json');
              if (existsSync(codebaseMapPath)) {
                try {
                  const mapContent = readFileSync(codebaseMapPath, 'utf-8');
                  const mapData = JSON.parse(mapContent);
                  if (mapData.discovered_files && Object.keys(mapData.discovered_files).length > 0) {
                    recentMemories.push({
                      id: `${specDir}-codebase_map`,
                      type: 'codebase_map',
                      timestamp: mapData.last_updated || new Date().toISOString(),
                      content: JSON.stringify(mapData.discovered_files, null, 2),
                      session_number: undefined
                    });
                  }
                } catch {
                  // Skip invalid files
                }
              }
            }
          }
        }

        return {
          success: true,
          data: {
            projectIndex,
            memoryStatus,
            memoryState,
            recentMemories: recentMemories.slice(0, 20),
            isLoading: false
          }
        };
      } catch (error) {
        return {
          success: false,
          error: error instanceof Error ? error.message : 'Failed to load project context'
        };
      }
    }
  );

  ipcMain.handle(
    IPC_CHANNELS.CONTEXT_REFRESH_INDEX,
    async (_, projectId: string): Promise<IPCResult<ProjectIndex>> => {
      const project = projectStore.getProject(projectId);
      if (!project) {
        return { success: false, error: 'Project not found' };
      }

      try {
        // Run the analyzer script to regenerate project_index.json
        const autoBuildSource = getAutoBuildSourcePath();

        if (!autoBuildSource) {
          return {
            success: false,
            error: 'Auto-build source path not configured'
          };
        }

        const analyzerPath = path.join(autoBuildSource, 'analyzer.py');
        const indexOutputPath = path.join(project.path, AUTO_BUILD_PATHS.PROJECT_INDEX);

        // Run analyzer
        await new Promise<void>((resolve, reject) => {
          const proc = spawn('python', [
            analyzerPath,
            '--project-dir', project.path,
            '--output', indexOutputPath
          ], {
            cwd: project.path,
            env: { ...process.env }
          });

          proc.on('close', (code: number) => {
            if (code === 0) {
              resolve();
            } else {
              reject(new Error(`Analyzer exited with code ${code}`));
            }
          });

          proc.on('error', reject);
        });

        // Read the new index
        if (existsSync(indexOutputPath)) {
          const content = readFileSync(indexOutputPath, 'utf-8');
          const projectIndex = JSON.parse(content);
          return { success: true, data: projectIndex };
        }

        return { success: false, error: 'Failed to generate project index' };
      } catch (error) {
        return {
          success: false,
          error: error instanceof Error ? error.message : 'Failed to refresh project index'
        };
      }
    }
  );

  ipcMain.handle(
    IPC_CHANNELS.CONTEXT_MEMORY_STATUS,
    async (_, projectId: string): Promise<IPCResult<GraphitiMemoryStatus>> => {
      const project = projectStore.getProject(projectId);
      if (!project) {
        return { success: false, error: 'Project not found' };
      }

      // Load project .env file to check for Graphiti config
      let projectEnvVars: Record<string, string> = {};
      if (project.autoBuildPath) {
        const projectEnvPath = path.join(project.path, project.autoBuildPath, '.env');
        if (existsSync(projectEnvPath)) {
          try {
            const envContent = readFileSync(projectEnvPath, 'utf-8');
            // Parse .env file inline - handle both Unix and Windows line endings
            for (const line of envContent.split(/\r?\n/)) {
              const trimmed = line.trim();
              if (!trimmed || trimmed.startsWith('#')) continue;
              const eqIndex = trimmed.indexOf('=');
              if (eqIndex > 0) {
                const key = trimmed.substring(0, eqIndex).trim();
                let value = trimmed.substring(eqIndex + 1).trim();
                if ((value.startsWith('"') && value.endsWith('"')) ||
                    (value.startsWith("'") && value.endsWith("'"))) {
                  value = value.slice(1, -1);
                }
                projectEnvVars[key] = value;
              }
            }
          } catch {
            // Continue with empty vars
          }
        }
      }

      // Load global settings for OpenAI API key fallback
      let globalOpenAIKey: string | undefined;
      if (existsSync(settingsPath)) {
        try {
          const settingsContent = readFileSync(settingsPath, 'utf-8');
          const globalSettings = JSON.parse(settingsContent);
          globalOpenAIKey = globalSettings.globalOpenAIApiKey;
        } catch {
          // Continue without global settings
        }
      }

      // Check for Graphiti config: project .env > process.env
      const graphitiEnabled =
        projectEnvVars['GRAPHITI_ENABLED']?.toLowerCase() === 'true' ||
        process.env.GRAPHITI_ENABLED?.toLowerCase() === 'true';

      // Check for OpenAI key: project .env > global settings > process.env
      const hasOpenAI =
        !!projectEnvVars['OPENAI_API_KEY'] ||
        !!globalOpenAIKey ||
        !!process.env.OPENAI_API_KEY;

      // Get Graphiti connection details from project .env or process.env
      const graphitiHost = projectEnvVars['GRAPHITI_FALKORDB_HOST'] || process.env.GRAPHITI_FALKORDB_HOST || 'localhost';
      const graphitiPort = parseInt(projectEnvVars['GRAPHITI_FALKORDB_PORT'] || process.env.GRAPHITI_FALKORDB_PORT || '6380', 10);
      const graphitiDatabase = projectEnvVars['GRAPHITI_DATABASE'] || process.env.GRAPHITI_DATABASE || 'auto_build_memory';

      if (!graphitiEnabled) {
        return {
          success: true,
          data: {
            enabled: false,
            available: false,
            reason: 'GRAPHITI_ENABLED not set to true'
          }
        };
      }

      if (!hasOpenAI) {
        return {
          success: true,
          data: {
            enabled: true,
            available: false,
            reason: 'OPENAI_API_KEY not set (required for embeddings)'
          }
        };
      }

      return {
        success: true,
        data: {
          enabled: true,
          available: true,
          host: graphitiHost,
          port: graphitiPort,
          database: graphitiDatabase
        }
      };
    }
  );

  ipcMain.handle(
    IPC_CHANNELS.CONTEXT_SEARCH_MEMORIES,
    async (_, projectId: string, query: string): Promise<IPCResult<ContextSearchResult[]>> => {
      const project = projectStore.getProject(projectId);
      if (!project) {
        return { success: false, error: 'Project not found' };
      }

      // For now, do simple text search in file-based memories
      // Graphiti search would require running Python subprocess
      const results: ContextSearchResult[] = [];
      const queryLower = query.toLowerCase();

      // Get specs directory path
      const specsBaseDir = getSpecsDir(project.autoBuildPath);
      const specsDir = path.join(project.path, specsBaseDir);
      if (existsSync(specsDir)) {
        const allSpecDirs = readdirSync(specsDir)
          .filter((f: string) => {
            const specPath = path.join(specsDir, f);
            return statSync(specPath).isDirectory();
          });

        for (const specDir of allSpecDirs) {
          const memoryDir = path.join(specsDir, specDir, 'memory');
          if (existsSync(memoryDir)) {
            const memoryFiles = readdirSync(memoryDir)
              .filter((f: string) => f.endsWith('.json'));

            for (const memFile of memoryFiles) {
              try {
                const memPath = path.join(memoryDir, memFile);
                const memContent = readFileSync(memPath, 'utf-8');

                if (memContent.toLowerCase().includes(queryLower)) {
                  const memData = JSON.parse(memContent);
                  results.push({
                    content: JSON.stringify(memData.insights || memData, null, 2),
                    score: 1.0,
                    type: 'session_insight'
                  });
                }
              } catch {
                // Skip invalid files
              }
            }
          }
        }
      }

      return { success: true, data: results.slice(0, 20) };
    }
  );

  ipcMain.handle(
    IPC_CHANNELS.CONTEXT_GET_MEMORIES,
    async (_, projectId: string, limit: number = 20): Promise<IPCResult<MemoryEpisode[]>> => {
      const project = projectStore.getProject(projectId);
      if (!project) {
        return { success: false, error: 'Project not found' };
      }

      const memories: MemoryEpisode[] = [];

      // Get specs directory path
      const specsBaseDir = getSpecsDir(project.autoBuildPath);
      const specsDir = path.join(project.path, specsBaseDir);

      if (existsSync(specsDir)) {
        const sortedSpecDirs = readdirSync(specsDir)
          .filter((f: string) => {
            const specPath = path.join(specsDir, f);
            return statSync(specPath).isDirectory();
          })
          .sort()
          .reverse();

        for (const specDir of sortedSpecDirs) {
          const memoryDir = path.join(specsDir, specDir, 'memory');
          if (existsSync(memoryDir)) {
            const memoryFiles = readdirSync(memoryDir)
              .filter((f: string) => f.endsWith('.json'))
              .sort()
              .reverse();

            for (const memFile of memoryFiles) {
              try {
                const memPath = path.join(memoryDir, memFile);
                const memContent = readFileSync(memPath, 'utf-8');
                const memData = JSON.parse(memContent);

                memories.push({
                  id: `${specDir}-${memFile}`,
                  type: memData.type || 'session_insight',
                  timestamp: memData.timestamp || new Date().toISOString(),
                  content: JSON.stringify(memData.insights || memData, null, 2),
                  session_number: memData.session_number
                });

                if (memories.length >= limit) {
                  break;
                }
              } catch {
                // Skip invalid files
              }
            }
          }

          if (memories.length >= limit) {
            break;
          }
        }
      }

      return { success: true, data: memories };
    }
  );
