import * as vscode from 'vscode'; import * as fs from 'fs'; import * as path from 'path'; // axios removed in favor of native fetch import { _getBrainDir, _isBrainDirExplicitlySet, findBrainFiles, SYSTEM_PROMPT, buildApiUrl, logError, logInfo } from './utils'; import { getConfig, validateConfig } from './config'; import { AgentExecutor } from './agent'; import { BridgeServer } from './bridge'; import { SidebarChatProvider } from './sidebarProvider'; import { HealthCheckMonitor } from './core/health'; import { initAstraPathResolver } from './core/astraPath'; /** * Astra Extension Entry Point */ export async function activate(context: vscode.ExtensionContext) { logInfo('Astra activating...'); // Initialize Astra Path Resolver (.astra → ConnectAI/.astra/) initAstraPathResolver(context); // Start Environment Health Monitoring HealthCheckMonitor.runAllChecks(); HealthCheckMonitor.startInterval(600000); // Check every 10 mins // 0. Validate Configuration const validation = validateConfig(); if (!validation.valid) { vscode.window.showErrorMessage(`Astra Configuration Error: ${validation.errors.join(' ')}`); logError('Configuration validation failed.', { errors: validation.errors }); } // 1. Ensure Brain Directory await _ensureBrainDir(context); // 2. Initialize Agent Executor const agent = new AgentExecutor(context); // 3. Initialize Sidebar Provider const provider = new SidebarChatProvider(context.extensionUri, context, agent); context.subscriptions.push( vscode.window.registerWebviewViewProvider(SidebarChatProvider.viewType, provider) ); // 4. Initialize Bridge Server (Port 4825) const bridge = new BridgeServer(provider); try { bridge.start(); logInfo('Bridge server started on port 4825.'); } catch (err) { logError('Failed to start bridge server.', err); } // 5. Register Core Commands context.subscriptions.push( vscode.commands.registerCommand('g1nation.focusInput', () => { provider.focusInput(); }) ); context.subscriptions.push( vscode.commands.registerCommand('g1nation.clearChat', () => { provider.clearChat(); }) ); context.subscriptions.push( vscode.commands.registerCommand('g1nation.syncBrain', async () => { await provider.syncBrain(); }) ); // 6. Run Initial Setup (Automatic Model/Engine Detection) const setupComplete = context.globalState.get('setupComplete', false); if (!setupComplete) { await runInitialSetup(context); } } export function deactivate() {} async function runInitialSetup(context: vscode.ExtensionContext) { try { let engineName = ''; let modelName = ''; try { const res = await fetch(buildApiUrl('http://127.0.0.1:1234', 'lmstudio', 'models'), { signal: AbortSignal.timeout(2000) }); const data = await res.json() as any; if (data?.data?.length > 0) { engineName = 'LM Studio'; modelName = data.data[0].id; await vscode.workspace.getConfiguration('g1nation').update('ollamaUrl', 'http://127.0.0.1:1234', vscode.ConfigurationTarget.Global); await vscode.workspace.getConfiguration('g1nation').update('defaultModel', modelName, vscode.ConfigurationTarget.Global); logInfo('Initial setup detected LM Studio.', { modelName }); } } catch (err) { logInfo('Initial setup could not reach LM Studio.', err); } if (!engineName) { try { const res = await fetch('http://127.0.0.1:11434/api/tags', { signal: AbortSignal.timeout(2000) }); const data = await res.json() as any; if (data?.models?.length > 0) { engineName = 'Ollama'; modelName = data.models[0].name; await vscode.workspace.getConfiguration('g1nation').update('ollamaUrl', 'http://127.0.0.1:11434', vscode.ConfigurationTarget.Global); await vscode.workspace.getConfiguration('g1nation').update('defaultModel', modelName, vscode.ConfigurationTarget.Global); logInfo('Initial setup detected Ollama.', { modelName }); } } catch (err) { logInfo('Initial setup could not reach Ollama.', err); } } context.globalState.update('setupComplete', true); if (engineName) { vscode.window.showInformationMessage(`Setup Complete: ${engineName} detected with model ${modelName}`); } } catch (e) { logError('Initial setup failed.', e); context.globalState.update('setupComplete', true); } } async function _ensureBrainDir(context: vscode.ExtensionContext): Promise { if (_isBrainDirExplicitlySet()) { const dir = _getBrainDir(); if (!fs.existsSync(dir)) { try { fs.mkdirSync(dir, { recursive: true }); } catch (e) {} } return dir; } const defaultDir = _getBrainDir(); if (!fs.existsSync(defaultDir)) { try { fs.mkdirSync(defaultDir, { recursive: true }); // Create a welcome file fs.writeFileSync(path.join(defaultDir, 'Welcome.md'), "# Welcome to your Second Brain\n\nAstra will store and retrieve knowledge from here."); } catch (e) {} } return defaultDir; } /** * Astra Extension Entry Point */