initialize method

Future<bool> initialize()

Implementation

Future<bool> initialize() async {
  SintSentinel.logger.i('ChatController.initialize() starting...');
  final config = await _authService.loadApiConfig();
  if (config == null) return false;

  _provider = _createProvider(config);
  _toolRegistry = _createToolRegistry();

  final settings = await AppSettings.load();

  // Generate session ID
  sessionId.value = _uuid.v4();

  // Initialize session history manager (saves/loads full sessions)
  if (!kIsWeb) {
    _sessionHistoryManager = SessionHistoryManager(
      baseDir: SystemConstants.sessionDir,
    );
  }

  // Initialize compaction service (auto-compact + microcompact)
  _compactionService = CompactionService(provider: _provider!);

  // Initialize session memory (periodic extraction)
  if (!kIsWeb) {
    final projectDir = Directory.current.path;
    _sessionMemoryService = SessionMemoryService(
      sessionId: sessionId.value,
      projectDir: '${SystemConstants.configDir}/projects/${_sanitizePath(projectDir)}',
    );
  }

  // Initialize memdir (persistent memory across sessions)
  if (!kIsWeb) {
    _memdirService = MemdirService(projectRoot: Directory.current.path);
  }

  // Load personality modules (IDENTITY, COGNITION, CAPABILITIES, TOOLS, etc.)
  await NeomageSystemPrompt.load();

  // Build memdir context
  String? memoryContext;
  if (_memdirService != null) {
    try {
      final memoryResult = await _memdirService!.loadMemoryPrompt();
      memoryContext = memoryResult.prompt;
      SintSentinel.logger.i(
        'Loaded ${memoryResult.memoryFileCount} memory files into context',
      );
    } catch (e) {
      SintSentinel.logger.w('Failed to load memory prompt: $e');
    }
  }

  // Load NEOMAGE.md / project instructions
  final neomageInstructions = await _loadNeomageInstructions();

  // Load existing session memory if resuming
  String? sessionMemoryContext;
  if (_sessionMemoryService != null) {
    try {
      sessionMemoryContext = await _sessionMemoryService!.load();
    } catch (_) {}
  }

  // Detect working directory, git branch, and platform info
  String workingDir = '.';
  String? gitBranch;
  bool isGitRepo = false;
  String? platformInfo;
  if (!kIsWeb) {
    workingDir = Directory.current.path;
    try {
      final branchResult = await Process.run('git', ['branch', '--show-current'],
          workingDirectory: workingDir);
      if (branchResult.exitCode == 0) {
        gitBranch = (branchResult.stdout as String).trim();
        isGitRepo = true;
      }
    } catch (_) {}
    try {
      final unameResult = await Process.run('uname', ['-sr']);
      if (unameResult.exitCode == 0) {
        platformInfo = (unameResult.stdout as String).trim();
      }
    } catch (_) {
      platformInfo = Platform.operatingSystem;
    }
  } else {
    platformInfo = 'Web';
  }

  // Build the full system prompt from personality modules + dynamic context.
  // If user has a custom system prompt override, use that instead of modules.
  String systemPrompt;
  if (settings.customSystemPrompt != null) {
    systemPrompt = settings.customSystemPrompt!;
  } else {
    // Combine memdir + session memory into single memory block
    final combinedMemory = [
      if (memoryContext != null && memoryContext.isNotEmpty) memoryContext,
      if (sessionMemoryContext != null && sessionMemoryContext.isNotEmpty)
        '<session_memory>\n$sessionMemoryContext\n</session_memory>',
    ].join('\n\n');

    systemPrompt = NeomageSystemPrompt.build(
      model: config.model,
      workingDirectory: workingDir,
      gitBranch: gitBranch,
      isGitRepo: isGitRepo,
      platform: platformInfo,
      projectFramework: 'Flutter/Dart',
      userInstructions: neomageInstructions,
      memoryContext: combinedMemory.isEmpty ? null : combinedMemory,
    );
  }

  // Create query engine with ALL services connected
  _engine = QueryEngine(
    provider: _provider!,
    toolRegistry: _toolRegistry!,
    systemPrompt: systemPrompt,
    compactionService: _compactionService,
    sessionMemory: _sessionMemoryService,
  );

  // Initialize rate limit service
  _rateLimitService = RateLimitService(
    apiKey: config.apiKey,
    baseUrl: config.baseUrl,
    cacheDir: SystemConstants.configDir,
  );
  // Load policies in background — fail-open if unavailable
  _rateLimitService!.loadPolicies().ignore();

  // Start telemetry session
  _telemetry.startSession(metadata: {
    'sessionId': sessionId.value,
    'provider': config.type.name,
    'model': config.model,
  });

  // Register slash commands
  _registerBuiltinCommands();

  // Initialize transcript file for JSONL persistence
  if (!kIsWeb) {
    _transcriptPath = '${SystemConstants.sessionDir}/${sessionId.value}.jsonl';
    await _ensureTranscriptDir();
  }

  // Try to restore last session if no messages
  if (messages.isEmpty && !kIsWeb) {
    await _tryRestoreLastSession();
  }

  // Fire session_start lifecycle hook
  await _hookExecutor.executeAsync(
    HookType.onSessionStart,
    HookContext.now(
      hookType: HookType.onSessionStart,
      sessionId: sessionId.value,
      metadata: {
        'provider': config.type.name,
        'model': config.model,
      },
    ),
  );

  update();
  SintSentinel.logger.i(
    'ChatController.initialize() completed — '
    'session=${sessionId.value}, '
    'compaction=${_compactionService != null}, '
    'sessionMemory=${_sessionMemoryService != null}, '
    'memdir=${_memdirService != null}, '
    'transcript=${_transcriptPath != null}',
  );
  return true;
}