Фазы запуска
Процесс запуска главного процесса Elftia разделён на 13 фаз, каждая из которых имеет чётко определённые обязанности и зависимости. Весь код фаз находится в функции createServices() в файле packages/desktop/app/main/index.ts.
Обзор фаз запуска
flowchart TB
P0[Фаза 0: Регистрация протоколов + Logger]
P1[Фаза 1: Ядровые сервисы]
P2[Фаза 2: Функциональные сервисы]
P25[Фаза 2.5: Загрузка пакетов]
P26[Фаза 2.6: Синхронизация пакетов]
P27[Фаза 2.7: Сервис управления пакетами]
PS1[Фаза S1: Magi Dispatch]
PS2[Фаза S2: MagiService]
PS25[Фаза S2.5: CronService]
PC1[Фаза C1: Channel-плагины]
PS3[Фаза S3: ChannelMagiBridge]
P3[Фаза 3: Регистрация IPC-маршрутов]
PT[Фаза T1-T3: Todo/Task/Notes]
PW1[Фаза W1: Создание окна]
PW2[Фаза W2: WebSocket/Протоколы]
P0 --> P1 --> P2 --> P25 --> P26 --> P27
P27 --> PS1 --> PS2 --> PS25
PS25 --> PC1 --> PS3
PS3 --> P3 --> PT --> PW1 --> PW2
Фаза 0: Регистрация протоколов + Logger
Выполняется до app.whenReady(). Регистрирует кастомные протоколы и основной сервис логирования.
flowchart LR
A[Зарегистрировать протокол elftia://] --> B[Зарегистрировать привилегированные схемы]
B --> C[wallpaper://]
B --> D[media://]
B --> E[resource://]
| Шаг | Действие | Описание |
|---|---|---|
| 1 | app.setAsDefaultProtocolClient('elftia') | Зарегистрировать протокол Deep Link |
| 2 | protocol.registerSchemesAsPrivileged() | Зарегистрировать привилегированные протоколы wallpaper/media/resource |
| 3 | new LoggerService() | Создать сервис логирования (Winston + daily-rotate) |
| 4 | setIpcLogger(logger) | Установить логгер для IPC-слоя |
| 5 | new ErrorHandler(logger) | Создать глобальный обработчик ошибок |
| 6 | setIpcErrorHandler(errorHandler) | Установить обработчик ошибок для IPC-слоя |
| 7 | new AutoUpdateService(logger) | Создать сервис автоматического обновления |
| 8 | new DownloadService(logger) | Создать сервис загрузки |
| 9 | new WebUpdateService(logger, downloadManager) | Создать сервис веб-обновлений |
Ключевые файлы: packages/desktop/app/main/services/infra/logger/LoggerService.ts, packages/desktop/app/main/services/infra/error/ErrorHandler.ts
Фаза 1: Ядровые сервисы
Создаёт базовые сервисы, необходимые для работы приложения; эти сервисы не имеют внешних зависимостей.
flowchart LR
RT[RuntimeService] --> AP[AppPaths]
AP --> DB[DbClient + ready]
DB --> SS[SettingsService]
SS --> CS[ConfigStore]
CS --> Migrate[Миграция конфигурации]
Migrate --> Auth[Цепочка Auth-сервисов]
Auth --> WC[WindowControlsService]
| Шаг | Сервис | Зависимости | Описание |
|---|---|---|---|
| 1 | RuntimeService | Нет | Информация о среде выполнения (версия, платформа, канал) |
| 2 | AppPaths | Нет | Разрешение путей |
| 3 | DbClient | AppPaths | Создание Worker базы данных |
| 4 | await db.ready() | DbClient | Блокирующее ожидание завершения инициализации Worker |
| 5 | initDatabase() | db.ready | Drizzle ORM + WAL + migrate |
| 6 | SettingsService | AppPaths | Настройки приложения |
| 7 | ConfigStore | AppPaths | Файл конфигурации electron-store |
| 8 | migrateSettingsToConfigStore() | Settings, ConfigStore | Миграция SQLite -> config.json |
| 9 | settings.setConfigStore(configStore) | - | Связывание через паттерн делегата |
| 10 | configStore.startWatching() | - | Горячая перезагрузка конфигурации через fs.watch |
| 11 | AccountService | AppPaths | Учётные данные пользователя |
| 12 | AuthTokenStore | AccountService | Хранение токенов |
| 13 | AuthSessionService | Runtime, AuthStore, AuthApi | Сессия аутентификации |
| 14 | AppPreferencesService | ConfigStore | Предпочтения приложения |
| 15 | WindowControlsService | Settings | Управление окном |
Ключевой момент: await db.ready() является точкой блокировки, которая гарантирует, что Worker SQLite завершил создание схемы до продолжения работы. Это предотвращает ошибку SQLITE_BUSY, возникающую при одновременной записи двух соединений при первом запуске.
Фаза 2: Функциональные сервисы
Создаёт лёгкие функциональные сервисы; тяжёлая инициализация откладывается до момента использования.
| Сервис | Зависимости | Описание |
|---|---|---|
ConfigManager | Logger, AppPaths | Управление файлами конфигурации |
SecurityService | Logger | Шифрование AES-256-GCM |
PerformanceMonitor | Logger | Мониторинг производительности |
CacheService | Logger | Кэш общего назначения |
DatabaseOptimizer | Logger, DbClient | Оптимизация SQLite |
NotificationService | Logger | Уведомления рабочего стола |
PluginManager | Logger | Жизненный цикл плагинов |
ProjectService | DbClient, AccountService | Управление проектами |
DiagnosticsService | AppPaths, ProjectService | Диагностический сервис |
ChatService | Logger | Сервис чата |
McpService | Logger | Управление MCP-сервером |
LLMConfigService | AppPaths, DbClient | Конфигурация LLM |
CompletionService | AppPaths, LLMConfigService | Завершение LLM |
ApiKeyPoolService | DB, CompletionService | Циклическое использование нескольких ключей |
ElfiService | ConfigStore, LLMConfig, Completion | Ассистент Elfi |
MediaConfigService | AppPaths, DbClient | Конфигурация медиа |
ImageGenerationService | MediaConfig | Генерация изображений |
ThemeService | Settings, AuthSession | Управление темой |
AgentService | DbClient, Settings, Logger | Сервис агентов |
TransformerService | - | Трансформация запросов |
WebSearchService | - | Веб-поиск |
EngineDispatcher + регистрация движков | Зависимости каждого движка | Диспетчер движков |
Порядок регистрации движков
{/* Регистрация движков */}
engineDispatcher.registerEngine(new ApiEngine(...));
engineDispatcher.registerEngine(new ChatEngine(...));
engineDispatcher.registerEngine(new ClaudeSdkEngine(...));
engineDispatcher.registerEngine(new CliRunnerEngine(...));
engineDispatcher.registerEngine(new TinyElfEngine(...));
engineDispatcher.registerEngine(new STChatEngine(...));
Фаза 2.5: Загрузка пакетов
Загружает пакеты Agent, пакеты Persona и Script-плагины с диска в память.
flowchart TB
subgraph "Phase 2.5a: Agent Packages"
AL[AgentPackageLoader] --> BP[Загрузить встроенные пакеты]
BP --> UP[Загрузить пакеты пользователя]
UP --> AR[AgentPackageRegistry]
end
subgraph "Phase 2.5b: Persona Packages"
PL[PersonaPackageLoader] --> BPP[Загрузить встроенные пакеты]
BPP --> UPP[Загрузить пакеты пользователя]
UPP --> PR[PersonaPackageRegistry]
end
subgraph "Phase 2.5c: Script Plugins"
SL[ScriptPluginLoader] --> BSP[Загрузить встроенные плагины]
BSP --> USP[Загрузить плагины пользователя]
USP --> SR[ScriptPluginRegistry]
end
Пути загрузки (паттерн двух директорий):
| Тип пакета | Встроенный путь (упакованный) | Встроенный путь (dev) | Пользовательский путь |
|---|---|---|---|
| Agent | resources/agent-packages/ | ../../agent-packages/ | {userData}/agent-packages/ |
| Persona | resources/persona-packages/ | ../../persona-packages/ | {userData}/persona-packages/ |
| Script | resources/script-plugins/ | ../../script-plugins/ | {userData}/script-plugins/ |
Фазы 2.6-2.7: Синхронизация и управление пакетами
| Фаза | Действие | Описание |
|---|---|---|
| 2.6 | PackageSyncService.syncAll() | Синхронизирует определения пакетов из памяти в базу данных (upsert FK anchors + данные persona) |
| 2.7 | new AgentPackageService(...) | Создаёт сервис управления пакетами, поддерживающий install/uninstall |
Фаза S1: Magi Dispatch
Создаёт сервисы, связанные с оркестрацией и диспетчеризацией агентов.
flowchart TB
AGM[AgentManagementService] --> EB[SessionEventBus]
EB --> AD[AgentDiscovery]
AD --> AO[AgentOrchestrator]
AO --> MR[MessageRouter]
MR --> SDI[SessionDispatcherImpl]
AO -.->|setEngineDispatcher| ED[EngineDispatcher]
AO -.->|setDbProvider| DB[DbClient]
SDI -.->|внедряется в| TE[TinyElfEngine]
| Шаг | Сервис | Описание |
|---|---|---|
| 1 | AgentManagementService | CRUD агентов + запросы к реестру пакетов |
| 2 | InternalSessionEventBus | Публикация/подписка на события сессии |
| 3 | AgentDiscovery | Реестр планируемых агентов (обнаруженных из БД + реестра пакетов) |
| 4 | AgentOrchestrator | Диспетчеризация и оркестрация агентов; обработчик API dispatch |
| 5 | MessageRouter | Двухрежимная маршрутизация сообщений (прямая / через Orchestrator) |
| 6 | SessionDispatcherImpl | Реализация межсессионной диспетчеризации |
| 7 | Внедряется в TinyElfEngine | tinyElfEngine.setSessionDispatcher(sessionDispatcher) |
| 8 | SubagentRegistry.setDb(db) | Сквозная запись реестра субагентов в хранилище |
Историческая справка: HTTP-сервер диспетчеризации
DispatchServerбыл удалён вcleanup-legacy-mcp(2026-05-19). Инструментdispatchтеперь собирается внутри процесса черезMagiDispatchProvider+MagiDispatchHandlersпосредством единого реестра; обработчики вызываютAgentOrchestrator/AgentDiscoveryнапрямую без использования HTTP. CLI-подпроцессы обращаются к нему через центральныйservices/capabilities/tools/mcp-builtin/BuiltinMcpHttpServer.ts.
Фаза S2: MagiService
Создаёт основной сервис обработки сообщений и внедряет все зависимости.
{/* Цепочка внедрения зависимостей MagiService */}
const magiService = new MagiService(
magiWorkspace, magiSession, magiOptionsBuilder,
magiOrchestrator, magiMessageRouter, magiEventBus,
llmConfig, logger, configStore,
);
// Отложенное внедрение (избегает циклических зависимостей)
magiService.setAgentService(agent);
magiService.setCompletionService(completion);
magiService.setAsrService(new AsrService(asrConfig));
magiService.setEngineDispatcher(engineDispatcher);
magiService.setDbProvider(db);
magiService.setMcpListProvider(() => mcp.list());
magiService.setDeveloperModeProvider(() => ...);
Горячая перезагрузка MCP: При изменении списка MCP-серверов происходит автоматическая синхронизация с рабочим пространством Magi и горячая перезагрузка активных сессий:
mcp.on('servers:changed', () => {
magiService.syncMcpServersToWorkspace();
magiService.notifyMcpChanged();
});
Фаза S2.5: CronService
Создаёт сервис планировщика задач Cron:
| Внедрение | Назначение |
|---|---|
setNotificationService(notification) | Уведомления рабочего стола |
setNotificationChecker(...) | Проверка предпочтений уведомлений |
setAgentExecutor(...) | Выполнение запланированных задач через MagiService |
setStatusBroadcaster(...) | Трансляция статуса задач во фронтенд |
Фаза C1: Channel-плагины
Обнаруживает, загружает и регистрирует Channel-плагины.
flowchart TB
CL[ChannelPluginLoader] --> Discover[обнаружить плагины]
Discover --> Load[загрузить каждый плагин]
Load --> CR[ChannelPluginRegistry.registerPlugin]
CR --> CM[ChannelMarketplaceService<br/>асинхронно получить удалённый манифест]
subgraph "Подключение сервисов безопасности"
UPS[UserPermissionService] --> CMR[ChannelMessageRouter]
CPG[ChannelPermissionGate] --> CMR
AL[AuditLogger] --> TE[TinyElfEngine]
RL[RateLimiter] --> CMR
IS[InputSanitizer] --> CMR
PG[PromptGuardian] --> CMR
end
CR --> CMR
Пути загрузки (паттерн двух директорий):
| Источник | Путь (упакованный) | Путь (dev) |
|---|---|---|
| Встроенный (только чтение) | resources/bundled-channel-plugins/ | elftia-channels/dist-plugins/ |
| Marketplace (с записью) | {userData}/channel-plugins/ | то же |
Порядок подключения сервисов безопасности:
UserPermissionService-> ChannelMessageRouter (проверка прав пользователя)ChannelPermissionGate-> ChannelMessageRouter + TinyElfEngine (подтверждение разрешений)AuditLogger-> TinyElfEngine (аудит-логирование)RateLimiter-> ChannelMessageRouter (ограничение частоты запросов)InputSanitizer-> ChannelMessageRouter (санитизация входных данных)PromptGuardian-> ChannelMessageRouter (обнаружение инъекций промптов)
Фаза S3: ChannelMagiBridge
Связывает события Channel с MagiService:
const channelMagiBridge = new ChannelMagiBridge(
channelRegistry,
channelMessageRouter,
magiService,
logger,
);
Историческая справка: HTTP-сервер
ChannelServerбыл удалён вcleanup-legacy-mcp(2026-05-19). Инструментыchannel_send/channel_listи другие теперь собираются внутри процесса черезMagiChannelProvider+MagiChannelHandlersпосредством единого реестра; обработчики вызываютChannelPluginRegistry/ChannelMessageRouterнапрямую.
Фаза 3: Регистрация IPC-маршрутов
Все IPC-обработчики регистрируются до создания окна.
const router = new Router(/* 60+ зависимостей сервисов */);
const { skillHubDownloadService } = router.register();
registerAllRouters() внутренне создаёт и регистрирует 68+ экземпляров Router:
| Класс Router | Префикс канала |
|---|---|
AuthRouter | auth:* |
ProjectRouter | projects:* |
SessionRouter | sessions:* |
CompletionRouter | completion:* |
LLMRouter | llmProviders:*, llmModels:* |
MediaRouter | media:* |
MagiRouter | magi:* |
ChannelPluginRouter | channels:* |
SecurityRouter | security:* |
TodoRouter | todo:* |
TaskRouter | tasks:* |
NoteRouter | notes:* |
SubagentRouter | subagents:* |
ElfiRouter | elfi:* |
EnvironmentRouter | env:* |
| ... и 50+ других маршрутизаторов | ... |
Фаза T1-T3: Todo/Task/Notes
flowchart LR
T1[Фаза T1: TodoService] --> T1a[initialize — загрузить TODO.md]
T2[Фаза T2: TaskService] --> T2a[initialize — сканировать задачи]
T3[Фаза T3: NoteFileService + NoteWatcher] --> T3a[ensureVaultDir]
T3a --> T3b[scanAllNotes + reindex]
T3b --> T3c[Проверка миграции заметок в БД]
| Фаза | Сервис | Действие |
|---|---|---|
| T1 | TodoService | Инициализировать систему задач на Markdown |
| T2 | TaskService | Инициализировать управление задачами через файловую систему + SQLite |
| T3 | NoteFileService | Убедиться, что директория хранилища существует |
| T3 | NoteWatcher | Наблюдатель за файловой системой |
| T3 | Миграция заметок | Однократная миграция из БД в .md-файлы |
| T3 | Переиндексация при запуске | Сканирование всех заметок и обновление индекса БД |
Фаза W1: Создание окна
Создаёт BrowserWindow после регистрации всех сервисов и IPC-маршрутов:
mainWindow = new BrowserWindow({
webPreferences: {
contextIsolation: true,
nodeIntegration: false,
sandbox: true,
preload: preloadPath,
},
});
Фаза W2: Обработка WebSocket/протоколов
Инициализация после создания окна:
| Шаг | Действие |
|---|---|
| 1 | Зарегистрировать обработчик протокола wallpaper:// |
| 2 | Зарегистрировать обработчик протокола media:// |
| 3 | Зарегистрировать обработчик протокола resource:// |
| 4 | Загрузить URL рендерера (dev-сервер или file://) |
| 5 | Обработать ожидающие Deep Link |
| 6 | Восстановить экземпляры Channel (autoConnect) |
| 7 | Настройка политики безопасности контента (Content Security Policy) |
| 8 | Перехват навигации (isAllowedNavigation) |
Время запуска
createServices() записывает время на ключевых фазах:
[INFO] Core services initialized { duration: ~50ms }
[INFO] Feature services created { duration: ~200ms }
[INFO] Agent packages loaded { builtin: N, user: M }
[INFO] Persona packages loaded { builtin: N, user: M }
[INFO] Script plugins loaded { builtin: N, user: M }
[INFO] Magi dispatch services created (Phase S1)
[INFO] MagiService created (Phase S2)
[INFO] ChannelMagiBridge created (Phase S3)
[INFO] IPC handlers registered { duration: ~500ms }
Связанные файлы
| Файл | Описание |
|---|---|
packages/desktop/app/main/index.ts | Точка входа главного процесса; функция createServices() |
packages/desktop/app/main/services/routers/index.ts | Регистрация маршрутов registerAllRouters() |
packages/desktop/app/main/db/index.ts | Инициализация базы данных initDatabase() |
packages/desktop/app/main/workers/DbClient.ts | Клиент Worker базы данных |
packages/desktop/app/main/services/infra/logger/LoggerService.ts | Сервис логирования |
packages/desktop/app/main/services/infra/paths/paths.ts | Управление путями AppPaths |
packages/desktop/app/main/services/platform/config/store/ConfigStore.ts | Хранилище конфигурации + fs.watch |
packages/desktop/app/main/services/agent-core/agent/AgentPackageLoader.ts | Загрузчик пакетов агентов |
packages/desktop/app/main/services/agent-core/agent/PersonaPackageLoader.ts | Загрузчик пакетов Persona |
packages/desktop/app/main/services/capabilities/tools/script-plugin/ScriptPluginLoader.ts | Загрузчик Script-плагинов |
packages/desktop/app/main/services/capabilities/integrations/channel/ChannelPluginLoader.ts | Загрузчик Channel-плагинов |
packages/desktop/app/main/services/agent-core/magi/MagiService.ts | Основной сервис Magi |
packages/desktop/app/main/services/agent-core/magi/AgentOrchestrator.ts | Оркестратор диспетчеризации агентов |
packages/desktop/app/main/services/platform/cron/CronService.ts | Сервис планировщика задач |
packages/desktop/app/main/services/content/workspace/todo/TodoService.ts | Сервис задач (Todo) |
packages/desktop/app/main/services/content/workspace/tasks/TaskService.ts | Сервис управления задачами |
packages/desktop/app/main/services/content/workspace/notes/NoteFileService.ts | Сервис файлов заметок |