refactor(process): main process decoupling phase 2 — full DI for all bridge/service modules#1447
Conversation
… (Phase 2 PR-A) - Add `listAllConversations()` to IConversationRepository and IConversationService interfaces - Implement `listAllConversations()` in SqliteConversationRepository and ConversationServiceImpl - Add FallbackConversationRepository decorator delegating all methods to inner repo - Refactor WorkerTaskManager constructor to accept IConversationRepository; remove direct getDatabase() and ProcessChat calls from getOrBuildTask - Wire SqliteConversationRepository into workerTaskManagerSingleton - Fix conversationBridge.getAssociateConversation to call conversationService.listAllConversations() instead of getDatabase() — closes last direct DB coupling in conversationBridge - Rewrite WorkerTaskManager.test.ts to use mock IConversationRepository - Add conversationBridge.test.ts covering listAllConversations path and failure cases
…s (Phase 2 PR-B) - taskBridge, geminiConversationBridge, acpConversationBridge, applicationBridge now accept workerTaskManager: IWorkerTaskManager as a parameter instead of importing the singleton directly - bridge/index.ts passes deps.workerTaskManager to each init function - Add unit tests: taskBridge, geminiConversationBridge, acpConversationBridge, applicationBridge — covering both success and failure paths
…injection (PR-C) - Add ICronRepository, ICronEventEmitter, ICronJobExecutor interfaces - Add SqliteCronRepository, IpcCronEventEmitter, WorkerTaskManagerJobExecutor implementations - Refactor CronService to accept constructor injection; remove singleton export - Add cronServiceSingleton.ts for production wiring - Export CronBusyGuard class (previously unexported) - Update all cronService import sites to use cronServiceSingleton - Rewrite CronService.test.ts to use mock interfaces (no SQLite, no Electron required)
…oupling (PR-D) - Add IChannelRepository interface with getChannelPlugins, getPendingPairingRequests, getChannelUsers, deleteChannelUser, getChannelSessions - Add SqliteChannelRepository delegating to getDatabase() channel methods - Refactor initChannelBridge() to accept IChannelRepository instead of calling getDatabase() directly; remove unused row-converter imports - Wire SqliteChannelRepository into initAllBridges via BridgeDependencies - Add channelBridge.test.ts with 11 unit tests covering all DB-touching handlers and failure paths (repo throws → error response)
…and extensionsBridge (PR-E) - Add searchMessages() and order param to getMessages() in IConversationRepository - Implement searchMessages() in SqliteConversationRepository and FallbackConversationRepository - Refactor databaseBridge.ts: replace getDatabase() with injected IConversationRepository - Extract ActivitySnapshotBuilder class (src/process/bridge/services/) with injected repo + taskManager - Refactor extensionsBridge.ts: remove singleton imports, accept repo + taskManager params - Add conversationRepo to BridgeDependencies and pass through initAllBridges - Add 16 unit tests for databaseBridge (all 3 handlers + failure paths) - Add 6 unit tests for ActivitySnapshotBuilder (totalConversations, runningConversations, grouping, error state)
…nService singleton
- Create conversationServiceSingleton.ts wired with SqliteConversationRepository
- Migrate SystemActions.ts: replace ConversationService static methods with
conversationServiceSingleton.createConversation; adapt result shape from
{success, conversation?, error?} to try/catch around Promise<TChatConversation>
- Migrate ActionExecutor.ts: same replacement; inline conversation creation now
uses try/catch instead of success-flag branching
- Delete src/process/services/conversationService.ts (old singleton with direct
getDatabase() and workerTaskManager calls)
- Update vitest.config.ts coverage.include to add all Phase 2 new files:
FallbackConversationRepository, SqliteChannelRepository, SqliteCronRepository,
IpcCronEventEmitter, WorkerTaskManagerJobExecutor, ActivitySnapshotBuilder,
databaseBridge
…ontracts Shows the 10 new interface contracts, implementation classes, singleton wiring points, and constructor-injected bridges introduced in Phase 2.
Code Review:refactor(process): main process decoupling phase 2 — full DI for all bridge/service modules (#1447)变更概述本 PR 完成主进程解耦第二阶段,将所有 bridge 和 service 模块从直接导入单例改为构造函数注入。新增了 方案评估结论: 整体 DI 方向正确,接口划分清晰,单元测试可独立运行的目标基本达到。但 问题清单🟠 HIGH — CronService.runJob():
|
| # | 严重级别 | 文件 | 问题 |
|---|---|---|---|
| 1 | 🟠 HIGH | src/process/services/cron/CronService.ts:385 |
setProcessing(true) 在 executeJob 前调用,异常时 busy 状态泄漏 |
| 2 | 🟡 MEDIUM | src/process/database/FallbackConversationRepository.ts |
无行为、无实例化、无测试的死代码类 |
| 3 | 🔵 LOW | tests/unit/WorkerTaskManager.test.ts |
makeRepo() 缺少 searchMessages mock |
结论
❌ 需要修改 — #1(HIGH)是行为回归,会在会话被删除后导致定时任务 busy 状态永久泄漏;#2 引入了误导性的空壳类。两个问题都应在合并前修复。
本报告由本地 pr-review skill 生成,包含完整项目上下文,无截断限制。
…ocess-decouple-phase2
- Fix setProcessing(true) busy-state leak: move into executeJob after task acquisition via onAcquired callback, preserving onceIdle ordering guarantee - Remove FallbackConversationRepository dead-code class (no instantiation point, no fallback logic, no tests); remove from vitest coverage include - Add missing searchMessages mock to WorkerTaskManager.test.ts makeRepo() Review follow-up for #1447
PR Fix 验证报告
总结: ✅ 已修复 3 个 | ❌ 未能修复 0 个 | ⏭️ 跳过 0 个 质量门控: |
…rview Class was dead code with no instantiation point or fallback logic; architecture diagram updated to match actual implementation.
- Fix setProcessing(true) busy-state leak: move into executeJob after task acquisition via onAcquired callback, preserving onceIdle ordering guarantee - Remove FallbackConversationRepository dead-code class (no instantiation point, no fallback logic, no tests); remove from vitest coverage include - Add missing searchMessages mock to WorkerTaskManager.test.ts makeRepo() Review follow-up for #1447
Summary
Completes Phase 2 of the main process decoupling plan. All remaining bridge and service modules now receive their dependencies via constructor injection instead of importing singletons directly. Every new business-logic class can be unit-tested without Electron, SQLite, or any singleton.
PRs in this branch (6 commits)
WorkerTaskManagerIConversationRepository; remove directgetDatabase()+ProcessChatcallsIWorkerTaskManagerintotaskBridge,geminiConversationBridge,acpConversationBridge,applicationBridgeCronServiceICronRepository,ICronEventEmitter,ICronJobExecutor; remove all 6 singleton importsIChannelRepository+SqliteChannelRepository; inject intochannelBridgedatabaseBridge+extensionsBridgeIConversationRepository; extractActivitySnapshotBuilderas testable classconversationService.ts; migrateActionExecutor+SystemActionstoIConversationService; add Phase 2 files to coverageNew interfaces
IChannelRepositoryICronRepositoryICronEventEmitterICronJobExecutorNew implementations
SqliteChannelRepository,SqliteCronRepository,IpcCronEventEmitter,WorkerTaskManagerJobExecutorFallbackConversationRepository(decorator overIConversationRepository)ActivitySnapshotBuilder(extracted fromextensionsBridge)conversationServiceSingleton(replaces old staticConversationService)New tests (15 new test files)
WorkerTaskManager,conversationBridge,taskBridge,geminiConversationBridge,acpConversationBridge,applicationBridge,channelBridge,databaseBridge,extensionsBridge(ActivitySnapshotBuilder),CronService(expanded)Test plan
bun run test— 844 tests passbunx tsc --noEmit— no new TypeScript errorsbun run lint:fix— no errors (warnings only)bun run test:coverage— verify new files ≥ 80%bun run test:integration— integration regression gate