Skip to content

refactor(ipc): migrate presenter transport to typed route/event system#1765

Merged
zerob13 merged 9 commits into
devfrom
codex/presenter-ipc-migration-plan
Jun 13, 2026
Merged

refactor(ipc): migrate presenter transport to typed route/event system#1765
zerob13 merged 9 commits into
devfrom
codex/presenter-ipc-migration-plan

Conversation

@zerob13

@zerob13 zerob13 commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator

refactor(ipc): migrate presenter transport to typed route/event system

Summary

  • Remove legacy presenter reflection transport (presenter:call, remoteControlPresenter:call)
  • Delete src/main/routes/legacyTypedEventBridge.ts and src/renderer/api/legacy/** quarantine
  • Introduce typed route contracts (src/shared/contracts/routes.ts) and event contracts (src/shared/contracts/events.ts)
  • Migrate all renderer settings surfaces from useLegacyPresenter() to typed API clients (src/renderer/api/*Client.ts)
  • Add src/main/routes/index.ts dispatcher with deepchat:route:invoke channel and runtime dependency injection
  • Harden preload boundaries: createBridge.ts validates route input/output and typed event envelopes
  • Add build-time guard scripts/check-background-exec-utility-host.mjs to prevent @electron-toolkit/utils leaking into utility-process bundles
  • Move shell environment helper logging onto a utility-host-safe logger
  • Tighten RTK rewrite detection for exit code 3 output and cover with unit tests
  • Inject reset runtime dependencies into DevicePresenter for explicit testable reset flows
  • Update architecture-guard.mjs to enforce zero legacy presenter imports in renderer business code

Architecture Impact

  • 271 typed routes across 24 domains (browser, chat, config, device, dialog, file, knowledge, MCP, models, onboarding, project, providers, sessions, settings, skills, sync, system, tab, tools, upgrade, window, workspace, etc.)
  • 54 typed events with schema validation
  • src/main/presenter/index.ts no longer exposes generic dispatch; all IPC goes through typed route runtime

Testing

  • Unit tests for route dispatcher (test/main/routes/dispatcher.test.ts), contract schemas (test/main/routes/contracts.test.ts), and renderer API clients (test/renderer/api/clients.test.ts)
  • E2E smoke tests for IPC boundary enforcement (29 scenarios covering settings, floating, browser, main, remote-control, knowledge, MCP, dashboard, skills, ACP, provider, skill-sync, data-security, project, window, config, workspace)
  • Architecture guard tests verifying legacy import rejection (test/main/scripts/architectureGuard.test.ts)
  • Unit tests for RTK rewrite classification, shell helper import safety, and injected reset runtime behavior

@coderabbitai

coderabbitai Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

Important

Review skipped

Too many files!

This PR contains 300 files, which is 150 over the limit of 150.

To get a review, narrow the scope:
• coderabbit review --type committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bd9d1364-c57b-4341-bb86-4d25354611e8

📥 Commits

Reviewing files that changed from the base of the PR and between ba8ec75 and 02ff2d9.

📒 Files selected for processing (300)
  • docs/ARCHITECTURE.md
  • docs/README.md
  • docs/architecture/agent-fff-node-api-search/plan.md
  • docs/architecture/agent-fff-node-api-search/tasks.md
  • docs/architecture/agent-runtime-presenter-split/spec.md
  • docs/architecture/baselines/archive-reference-report.md
  • docs/architecture/baselines/dependency-report.md
  • docs/architecture/baselines/main-kernel-boundary-baseline.md
  • docs/architecture/baselines/main-kernel-bridge-register.md
  • docs/architecture/baselines/main-kernel-migration-scoreboard.json
  • docs/architecture/baselines/main-kernel-migration-scoreboard.md
  • docs/architecture/baselines/test-failure-groups.md
  • docs/architecture/baselines/zero-inbound-candidates.md
  • docs/architecture/chat-scroll-windowing/plan.md
  • docs/architecture/chat-scroll-windowing/spec.md
  • docs/architecture/chat-scroll-windowing/tasks.md
  • docs/architecture/chat-status-bar-split/plan.md
  • docs/architecture/chat-status-bar-split/spec.md
  • docs/architecture/chat-status-bar-split/tasks.md
  • docs/architecture/console-log-cleanup/plan.md
  • docs/architecture/console-log-cleanup/spec.md
  • docs/architecture/console-log-cleanup/tasks.md
  • docs/architecture/event-system.md
  • docs/architecture/tool-system.md
  • docs/architecture/unify-provider-settings-ui/plan.md
  • docs/architecture/unify-provider-settings-ui/spec.md
  • docs/architecture/unify-provider-settings-ui/tasks.md
  • docs/archives/sidebar-collapsed-agent-expand/plan.md
  • docs/archives/sidebar-collapsed-agent-expand/spec.md
  • docs/archives/sidebar-collapsed-agent-expand/tasks.md
  • docs/features/agent-session-transfer/plan.md
  • docs/features/agent-session-transfer/tasks.md
  • docs/features/automatic-turn-activity-collapse/plan.md
  • docs/features/automatic-turn-activity-collapse/tasks.md
  • docs/features/cloud-sync-s3/plan.md
  • docs/features/cloud-sync-s3/tasks.md
  • docs/features/remote-agent-switch/plan.md
  • docs/features/remote-agent-switch/tasks.md
  • docs/features/sidebar-chat-number-shortcuts/plan.md
  • docs/features/sidebar-chat-number-shortcuts/tasks.md
  • docs/features/skill-draft-confirmation-card/plan.md
  • docs/features/skill-draft-confirmation-card/tasks.md
  • docs/features/skill-install-drag-drop/plan.md
  • docs/features/skill-install-drag-drop/tasks.md
  • docs/features/windows-arm64-support/plan.md
  • docs/features/windows-arm64-support/spec.md
  • docs/features/windows-arm64-support/tasks.md
  • docs/guides/code-navigation.md
  • docs/guides/debugging.md
  • docs/guides/getting-started.md
  • docs/guides/plugin-packaging.md
  • docs/issues/agent-exec-utility-process-crash/plan.md
  • docs/issues/agent-exec-utility-process-crash/spec.md
  • docs/issues/agent-exec-utility-process-crash/tasks.md
  • docs/issues/agent-loop-input-exec-responsiveness/plan.md
  • docs/issues/agent-loop-input-exec-responsiveness/spec.md
  • docs/issues/agent-loop-input-exec-responsiveness/tasks.md
  • docs/issues/ai-sdk-system-message-warning/plan.md
  • docs/issues/ai-sdk-system-message-warning/spec.md
  • docs/issues/ai-sdk-system-message-warning/tasks.md
  • docs/issues/ask-user-empty-prompt-compaction-order/plan.md
  • docs/issues/ask-user-empty-prompt-compaction-order/spec.md
  • docs/issues/ask-user-empty-prompt-compaction-order/tasks.md
  • docs/issues/assistant-action-type-null-renderer-crash/plan.md
  • docs/issues/assistant-action-type-null-renderer-crash/spec.md
  • docs/issues/assistant-action-type-null-renderer-crash/tasks.md
  • docs/issues/browser-rich-url-paste/plan.md
  • docs/issues/browser-rich-url-paste/spec.md
  • docs/issues/browser-rich-url-paste/tasks.md
  • docs/issues/cc-switch-config-path-discovery/plan.md
  • docs/issues/cc-switch-config-path-discovery/spec.md
  • docs/issues/cc-switch-config-path-discovery/tasks.md
  • docs/issues/chat-top-p-tooltip/plan.md
  • docs/issues/chat-top-p-tooltip/spec.md
  • docs/issues/chat-top-p-tooltip/tasks.md
  • docs/issues/cherry-studio-config-path-discovery/plan.md
  • docs/issues/cherry-studio-config-path-discovery/spec.md
  • docs/issues/cherry-studio-config-path-discovery/tasks.md
  • docs/issues/cua-driver-v0-2-0-sync/plan.md
  • docs/issues/cua-driver-v0-2-0-sync/spec.md
  • docs/issues/cua-driver-v0-2-0-sync/tasks.md
  • docs/issues/feishu-pairing-save-race/plan.md
  • docs/issues/feishu-pairing-save-race/spec.md
  • docs/issues/feishu-pairing-save-race/tasks.md
  • docs/issues/fff-packaged-native-loading/plan.md
  • docs/issues/fff-packaged-native-loading/spec.md
  • docs/issues/fff-packaged-native-loading/tasks.md
  • docs/issues/floating-button-position-persistence/plan.md
  • docs/issues/floating-button-position-persistence/tasks.md
  • docs/issues/guided-onboarding-first-chat-confirm/plan.md
  • docs/issues/guided-onboarding-first-chat-confirm/spec.md
  • docs/issues/guided-onboarding-first-chat-confirm/tasks.md
  • docs/issues/image-generation-context-budget-bypass/plan.md
  • docs/issues/image-generation-context-budget-bypass/tasks.md
  • docs/issues/mac-app-name-identity/plan.md
  • docs/issues/mac-app-name-identity/spec.md
  • docs/issues/mac-app-name-identity/tasks.md
  • docs/issues/mac-native-feel-audit/plan.md
  • docs/issues/mac-native-feel-audit/spec.md
  • docs/issues/mac-native-feel-audit/tasks.md
  • docs/issues/markdown-codeblock-session-scroll-regressions/plan.md
  • docs/issues/markdown-codeblock-session-scroll-regressions/tasks.md
  • docs/issues/merged-activity-groups/plan.md
  • docs/issues/merged-activity-groups/spec.md
  • docs/issues/merged-activity-groups/tasks.md
  • docs/issues/onboarding-provider-mcp-handoff/plan.md
  • docs/issues/onboarding-provider-mcp-handoff/spec.md
  • docs/issues/onboarding-provider-mcp-handoff/tasks.md
  • docs/issues/openai-compatible-video-prompt-duration-fallback/plan.md
  • docs/issues/openai-compatible-video-prompt-duration-fallback/spec.md
  • docs/issues/openai-compatible-video-prompt-duration-fallback/tasks.md
  • docs/issues/opendal-native-binding-release/plan.md
  • docs/issues/opendal-native-binding-release/spec.md
  • docs/issues/opendal-native-binding-release/tasks.md
  • docs/issues/pr-1621-ai-review-fixes/plan.md
  • docs/issues/pr-1621-ai-review-fixes/spec.md
  • docs/issues/pr-1621-ai-review-fixes/tasks.md
  • docs/issues/pr-base-dev-default/plan.md
  • docs/issues/pr-base-dev-default/spec.md
  • docs/issues/pr-base-dev-default/tasks.md
  • docs/issues/pr1765-final-cleanup/plan.md
  • docs/issues/pr1765-final-cleanup/spec.md
  • docs/issues/pr1765-final-cleanup/tasks.md
  • docs/issues/prcheck-format-onboarding/plan.md
  • docs/issues/prcheck-format-onboarding/spec.md
  • docs/issues/prcheck-format-onboarding/tasks.md
  • docs/issues/project-group-session-update-sort/plan.md
  • docs/issues/project-group-session-update-sort/tasks.md
  • docs/issues/qqbot-remote-settings-clone-error/plan.md
  • docs/issues/qqbot-remote-settings-clone-error/spec.md
  • docs/issues/qqbot-remote-settings-clone-error/tasks.md
  • docs/issues/reasoning-heading-font-size/plan.md
  • docs/issues/reasoning-heading-font-size/spec.md
  • docs/issues/reasoning-heading-font-size/tasks.md
  • docs/issues/release-lockfile-sync/plan.md
  • docs/issues/release-lockfile-sync/spec.md
  • docs/issues/release-lockfile-sync/tasks.md
  • docs/issues/release-tooltip-alias/plan.md
  • docs/issues/release-tooltip-alias/spec.md
  • docs/issues/release-tooltip-alias/tasks.md
  • docs/issues/remote-acp-default-agent-flicker/plan.md
  • docs/issues/remote-acp-default-agent-flicker/tasks.md
  • docs/issues/remote-tool-result-images/plan.md
  • docs/issues/remote-tool-result-images/tasks.md
  • docs/issues/remove-gpt5-temperature-hardcode/plan.md
  • docs/issues/remove-gpt5-temperature-hardcode/spec.md
  • docs/issues/remove-gpt5-temperature-hardcode/tasks.md
  • docs/issues/scheduled-task-prompt-picker-ux/plan.md
  • docs/issues/scheduled-task-prompt-picker-ux/spec.md
  • docs/issues/scheduled-task-prompt-picker-ux/tasks.md
  • docs/issues/scheduled-tasks-clone-error/plan.md
  • docs/issues/scheduled-tasks-clone-error/spec.md
  • docs/issues/scheduled-tasks-clone-error/tasks.md
  • docs/issues/scheduled-tasks-real-dispatch/plan.md
  • docs/issues/scheduled-tasks-real-dispatch/spec.md
  • docs/issues/scheduled-tasks-real-dispatch/tasks.md
  • docs/issues/session-list-stable-alphabetical-sort/plan.md
  • docs/issues/session-list-stable-alphabetical-sort/spec.md
  • docs/issues/session-list-stable-alphabetical-sort/tasks.md
  • docs/issues/skill-presenter-sync-io/plan.md
  • docs/issues/skill-presenter-sync-io/tasks.md
  • docs/issues/skills-path-cross-platform-repair/plan.md
  • docs/issues/skills-path-cross-platform-repair/spec.md
  • docs/issues/skills-path-cross-platform-repair/tasks.md
  • docs/issues/startup-warning-cleanup/plan.md
  • docs/issues/startup-warning-cleanup/spec.md
  • docs/issues/startup-warning-cleanup/tasks.md
  • docs/issues/stop-pauses-pending-queue/plan.md
  • docs/issues/stop-pauses-pending-queue/tasks.md
  • docs/issues/telegram-message-markdown-render/plan.md
  • docs/issues/telegram-message-markdown-render/tasks.md
  • docs/issues/vite-mixed-import-warnings/plan.md
  • docs/issues/vite-mixed-import-warnings/spec.md
  • docs/issues/vite-mixed-import-warnings/tasks.md
  • docs/issues/windows-arm64-duckdb-upgrade/plan.md
  • docs/issues/windows-arm64-duckdb-upgrade/spec.md
  • docs/issues/windows-arm64-duckdb-upgrade/tasks.md
  • docs/issues/windows-release-build-arch/plan.md
  • docs/issues/windows-release-build-arch/spec.md
  • docs/issues/windows-release-build-arch/tasks.md
  • docs/issues/workspace-insert-input/plan.md
  • docs/issues/workspace-insert-input/spec.md
  • docs/issues/workspace-insert-input/tasks.md
  • docs/issues/yobrowser-cdp-graceful-degradation/plan.md
  • docs/issues/yobrowser-cdp-graceful-degradation/tasks.md
  • docs/issues/yobrowser-runtime-point-parsing/plan.md
  • docs/issues/yobrowser-runtime-point-parsing/spec.md
  • docs/issues/yobrowser-runtime-point-parsing/tasks.md
  • docs/release-flow.md
  • docs/spec-driven-dev.md
  • resources/acp-registry/registry.json
  • resources/model-db/providers.json
  • scripts/architecture-guard.mjs
  • scripts/generate-architecture-baseline.mjs
  • src/main/appMain.ts
  • src/main/contextMenuHelper.ts
  • src/main/eventbus.ts
  • src/main/events.ts
  • src/main/lib/agentRuntime/rtkRuntimeService.ts
  • src/main/lib/agentRuntime/shellEnvHelper.ts
  • src/main/presenter/agentRuntimePresenter/dispatch.ts
  • src/main/presenter/agentRuntimePresenter/echo.ts
  • src/main/presenter/agentRuntimePresenter/index.ts
  • src/main/presenter/agentRuntimePresenter/pendingInputCoordinator.ts
  • src/main/presenter/agentSessionPresenter/index.ts
  • src/main/presenter/browser/YoBrowserPresenter.ts
  • src/main/presenter/configPresenter/acpInitHelper.ts
  • src/main/presenter/configPresenter/eventPublishers.ts
  • src/main/presenter/configPresenter/index.ts
  • src/main/presenter/configPresenter/mcpConfHelper.ts
  • src/main/presenter/configPresenter/modelStatusHelper.ts
  • src/main/presenter/configPresenter/providerDbLoader.ts
  • src/main/presenter/configPresenter/providerHelper.ts
  • src/main/presenter/configPresenter/providerModelHelper.ts
  • src/main/presenter/configPresenter/systemPromptHelper.ts
  • src/main/presenter/configPresenter/uiSettingsHelper.ts
  • src/main/presenter/deeplinkPresenter/index.ts
  • src/main/presenter/devicePresenter/index.ts
  • src/main/presenter/dialogPresenter/index.ts
  • src/main/presenter/floatingButtonPresenter/FloatingButtonWindow.ts
  • src/main/presenter/floatingButtonPresenter/index.ts
  • src/main/presenter/index.ts
  • src/main/presenter/knowledgePresenter/knowledgeStorePresenter.ts
  • src/main/presenter/lifecyclePresenter/SplashWindowManager.ts
  • src/main/presenter/lifecyclePresenter/hooks/ready/eventListenerSetupHook.ts
  • src/main/presenter/lifecyclePresenter/index.ts
  • src/main/presenter/llmProviderPresenter/acp/acpProcessManager.ts
  • src/main/presenter/llmProviderPresenter/baseProvider.ts
  • src/main/presenter/llmProviderPresenter/managers/ollamaManager.ts
  • src/main/presenter/llmProviderPresenter/managers/rateLimitManager.ts
  • src/main/presenter/llmProviderPresenter/oauthHelper.ts
  • src/main/presenter/llmProviderPresenter/providers/acpProvider.ts
  • src/main/presenter/mcpPresenter/index.ts
  • src/main/presenter/mcpPresenter/mcpClient.ts
  • src/main/presenter/mcpPresenter/serverManager.ts
  • src/main/presenter/mcpPresenter/toolManager.ts
  • src/main/presenter/notificationPresenter.ts
  • src/main/presenter/presenterCallErrorHandler.ts
  • src/main/presenter/sessionPresenter/events.ts
  • src/main/presenter/sessionPresenter/index.ts
  • src/main/presenter/sessionPresenter/managers/conversationManager.ts
  • src/main/presenter/sessionPresenter/managers/messageManager.ts
  • src/main/presenter/sessionPresenter/tab/tabManager.ts
  • src/main/presenter/shortcutPresenter.ts
  • src/main/presenter/skillPresenter/index.ts
  • src/main/presenter/skillSyncPresenter/index.ts
  • src/main/presenter/syncPresenter/index.ts
  • src/main/presenter/tabPresenter.ts
  • src/main/presenter/toolPresenter/agentTools/agentToolManager.ts
  • src/main/presenter/toolPresenter/agentTools/chatSettingsTools.ts
  • src/main/presenter/toolPresenter/runtimePorts.ts
  • src/main/presenter/upgradePresenter/index.ts
  • src/main/presenter/windowPresenter/FloatingChatWindow.ts
  • src/main/presenter/windowPresenter/index.ts
  • src/main/presenter/workspacePresenter/index.ts
  • src/main/routes/config/configRouteHandler.ts
  • src/main/routes/config/configRouteSupport.ts
  • src/main/routes/index.ts
  • src/main/routes/legacyTypedEventBridge.ts
  • src/main/routes/providers/providerRouteHandler.ts
  • src/main/routes/publishDeepchatEvent.ts
  • src/preload/browser-overlay-preload.ts
  • src/preload/floating-preload.ts
  • src/preload/index.d.ts
  • src/preload/index.ts
  • src/preload/splash-preload.ts
  • src/renderer/api/AcpTerminalClient.ts
  • src/renderer/api/AppRuntimeClient.ts
  • src/renderer/api/BrowserClient.ts
  • src/renderer/api/ConfigClient.ts
  • src/renderer/api/ContextMenuClient.ts
  • src/renderer/api/DatabaseSecurityClient.ts
  • src/renderer/api/DeviceClient.ts
  • src/renderer/api/KnowledgeClient.ts
  • src/renderer/api/McpClient.ts
  • src/renderer/api/NowledgeMemClient.ts
  • src/renderer/api/OAuthClient.ts
  • src/renderer/api/ProjectClient.ts
  • src/renderer/api/ProviderClient.ts
  • src/renderer/api/RemoteControlClient.ts
  • src/renderer/api/RemoteControlRuntime.ts
  • src/renderer/api/SessionClient.ts
  • src/renderer/api/ShortcutClient.ts
  • src/renderer/api/ShortcutRuntime.ts
  • src/renderer/api/SkillClient.ts
  • src/renderer/api/SkillSyncClient.ts
  • src/renderer/api/WindowClient.ts
  • src/renderer/api/index.ts
  • src/renderer/api/legacy/README.md
  • src/renderer/api/legacy/presenterTransport.ts
  • src/renderer/api/legacy/presenters.ts
  • src/renderer/api/legacy/runtime.ts
  • src/renderer/api/runtime.ts
  • src/renderer/floating/FloatingButton.vue
  • src/renderer/floating/env.d.ts
  • src/renderer/floating/main.ts
  • src/renderer/settings/App.vue
  • src/renderer/settings/components/AboutUsSettings.vue
  • src/renderer/settings/components/AcpDebugDialog.vue
  • src/renderer/settings/components/AcpDependencyDialog.vue

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/presenter-ipc-migration-plan

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@zerob13

zerob13 commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator Author

PR #1765 重构代码审查报告

1. Guard 清理分析

1.1 重构前已存在的 Guard(需要保留)

  • scripts/agent-cleanup-guard.mjs - 检查 agent 相关代码是否引入旧版导入,仍需保留
  • scripts/architecture-guard.mjs - 核心架构守卫,检查 renderer 不使用 legacy presenter、window.electron 等,仍需保留但部分规则可收紧

1.2 重构中新加的 Guard(需要保留)

  • scripts/check-background-exec-utility-host.mjs - 检查 background exec utility host 不引入 @electron-toolkit/utils 和 main-only Electron 导入,必须保留,这是 PR 的核心目标

1.3 建议清理的 Guard

  • scripts/architecture-guard.mjs 中的 MIGRATED_RAW_CHANNEL_GUARD_PATHSMIGRATED_RAW_CHANNEL_BASELINE

    • 这些路径已经完整迁移到 typed route/event 系统,基线检查(expected <= baseline)可以收紧为 expected == 0
    • 特别是 src/main/presenter/windowPresenter/index.ts 的基线 4 和 src/renderer/src/App.vue 的基线 1,应该归零
  • RETIRED_RENDERER_LEGACY_ENTRY_PATHS 中的 src/renderer/src/composables/usePresenter.ts

    • 检查该文件是否已删除,如果已删除则保留;如果仍存在需要清理
  • RENDERER_QUARANTINE_ROOT (src/renderer/api/legacy):

    • 检查该目录是否已为空或已删除,可以移除相关检查逻辑

2. 类型一致性检查

2.1 Legacy 类型引用问题

  • src/shared/types/presenters/llmprovider.presenter.d.ts:7 - 从 legacy.presenters 导入 AcpDebugRequest, AcpDebugRunResult, AcpWorkdirInfo
  • src/shared/types/presenters/window.presenter.d.ts:1 - 从 legacy.presenters 导入 IWindowPresenter, TabData
  • src/shared/types/presenters/index.d.ts:136 - export * from './legacy.presenters'
  • src/shared/types/index.d.ts:3 - export type * from './presenters/legacy.presenters'

建议:这些类型应该被提取到独立的类型文件中,逐步减少对 legacy.presenters 的依赖。

2.2 新增类型

  • src/shared/contracts/routes.tssrc/shared/contracts/events.ts 中的新路由/事件定义结构清晰,使用 zod schema 定义输入输出,类型安全。
  • src/shared/contracts/common.ts 中的 RouteContractEventContract 接口定义完整。

3. 遗留代码检查

3.1 已清理的遗留代码

  • src/main/routes/legacyTypedEventBridge.ts - 已删除(459 行删除)
  • src/renderer/api/legacy/presenterTransport.ts - 已删除
  • src/renderer/api/legacy/presenters.ts - 已删除
  • src/renderer/api/legacy/runtime.ts - 已删除
  • src/renderer/src/composables/useLegacyPresenter.ts - 测试引用已移除

3.2 仍存在的遗留代码

  • src/main/presenter/lifecyclePresenter/hooks/after-start/legacyImportHook.ts - 用于启动旧版数据导入,需要保留直到所有用户数据迁移完成
  • src/main/presenter/agentSessionPresenter/index.ts:1525 - startLegacyImport() 方法仍需保留
  • src/shared/types/presenters/legacy.presenters.d.ts - 仍被多处引用,需要逐步拆分

4. 潜在 Bug 检查

4.1 路由注册完整性

  • src/main/routes/index.ts:3257-3276 - registerMainKernelRoutes 函数正确注册 IPC handler,使用 getRuntime() 延迟获取 runtime
  • dispatchDeepchatRoute 函数在 src/main/routes/index.ts:1084 处有完整的 hasDeepchatRouteContract 检查,未知路由会抛出明确错误
  • 路由分发逻辑覆盖:config → provider → model → 其他路由,结构清晰

4.2 Presenter 初始化顺序

  • src/main/presenter/index.ts:140-200 - Presenter 初始化顺序合理,但需要注意 mcpPresenterllmproviderPresenter 之后初始化,而 llmproviderPresenter 构造函数中引用了 this.mcpPresenter(第 173 行),这是一个循环依赖风险
    this.llmproviderPresenter = new LLMProviderPresenter(
      this.configPresenter,
      this.sqlitePresenter,
      {
        getNpmRegistry: () => this.mcpPresenter.getNpmRegistry?.() ?? null,
        getUvRegistry: () => this.mcpPresenter.getUvRegistry?.() ?? null
      }
    )
    此时 this.mcpPresenter 尚未初始化,但因为是函数延迟调用,实际运行时已经初始化,当前实现安全但脆弱

4.3 事件发布/订阅

  • src/main/presenter/agentRuntimePresenter/internalSessionEvents.ts - 使用 Node.js EventEmitter 进行内部事件通信,有明确的 subscribeemit 函数
  • src/main/routes/publishDeepchatEvent.ts - 使用 eventBus 发送事件到 renderer,有类型安全的 envelope 包装
  • src/main/events.ts - 定义了完整的事件常量,但注意这些事件名和 src/shared/contracts/events.ts 中的事件名是两套系统,需要确认是否重复或互补

4.4 错误处理完整性

  • src/main/routes/index.ts:1084-1086 - 未知路由抛出 Error
  • src/main/routes/index.ts:3266-3268 - runtime 未初始化时抛出明确错误
  • src/main/presenter/index.ts:915-916 - getMainKernelRouteRuntime 在 presenter 未初始化时抛出错误
  • src/main/presenter/lifecyclePresenter/hooks/after-start/scheduledTasksStartHook.ts:28-33 - 有 try-catch 保护 runtime 初始化

5. 测试完整性

5.1 新测试覆盖

  • test/main/routes/dispatcher.test.ts - 路由分发器测试(2122 行,非常全面)
  • test/main/routes/contracts.test.ts - 合约测试(938 行)
  • test/e2e/specs/ - 29 个 e2e smoke 测试,覆盖 IPC 边界、路由只读等场景
  • test/renderer/api/clients.test.ts - 客户端 API 测试(1486 行)
  • test/renderer/api/preloadBoundaries.test.ts - preload 边界测试(326 行)
  • test/main/scripts/architectureGuard.test.ts - 架构守卫测试

5.2 测试缺失

  • test/main/presenter/index.ts - 缺少对 Presenter 类初始化的直接单元测试
  • getMainKernelRouteRuntime 函数没有直接测试
  • src/main/presenter/lifecyclePresenter/hooks/after-start/legacyImportHook.ts 没有直接测试

6. 其他问题

6.1 缓存问题

  • src/main/presenter/index.ts:881 - cachedMainKernelRouteRuntime 是模块级变量,一旦创建不会重置。如果 presenter 被重新初始化(虽然 getInstance 有单例保护),缓存会过时。建议添加缓存失效机制或在 getInstance 中重置缓存。

6.2 类型导出冗余

  • src/shared/types/presenters/index.d.tssrc/shared/types/index.d.ts 都导出了 legacy.presenters,存在冗余。

6.3 文档和代码一致性

  • docs/architecture/presenter-ipc-migration-plan/ 下的文档非常详细,但需要注意文档中的计划是否和实际代码一致。

总结建议

  1. 高优先级:清理 architecture-guard.mjs 中已迁移完成路径的基线,收紧为 0
  2. 中优先级:将 legacy.presenters.d.ts 中仍被引用的类型(AcpDebugRequest, AcpDebugRunResult, AcpWorkdirInfo, IWindowPresenter, TabData)提取到独立文件
  3. 中优先级:为 getMainKernelRouteRuntimePresenter 初始化添加单元测试
  4. 低优先级:考虑为 cachedMainKernelRouteRuntime 添加缓存失效机制

@zerob13

zerob13 commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator Author

补充检查结果

基于进一步深入代码审查,以下是针对 5 个关键问题的具体验证结论:

1. llmproviderPresenter 初始化引用 mcpPresenter 问题 ✅ 安全

文件: src/main/presenter/index.ts:169-176

this.llmproviderPresenter = new LLMProviderPresenter(
  this.configPresenter,
  this.sqlitePresenter,
  {
    getNpmRegistry: () => this.mcpPresenter.getNpmRegistry?.() ?? null,
    getUvRegistry: () => this.mcpPresenter.getUvRegistry?.() ?? null
  }
)

结论: 当前实现安全。getNpmRegistrygetUvRegistry 是函数延迟调用,在构造函数执行时只保存了函数引用,不会立即调用 this.mcpPresenter。实际调用发生在 LLMProviderPresenter 后续运行时的某个时刻,此时 this.mcpPresenter 已在第 189 行完成初始化。但这是一个脆弱的设计——如果未来有人改为立即调用的模式,会引入时序 bug。

建议: 考虑在 LLMProviderPresenter 构造函数中添加运行时断言,确保调用时 mcpPresenter 已可用。


2. legacy.presenters.d.ts 类型引用分析

文件: src/shared/types/presenters/legacy.presenters.d.ts

仍被引用的类型:

类型 引用文件 行号
AcpDebugRequest, AcpDebugRunResult, AcpWorkdirInfo src/shared/types/presenters/llmprovider.presenter.d.ts 7
IWindowPresenter, TabData src/shared/types/presenters/window.presenter.d.ts 1
legacy.presenters 全部导出 src/shared/types/presenters/index.d.ts 136
legacy.presenters 全部导出 src/shared/types/index.d.ts 3

结论: legacy.presenters.d.ts 仍被 4 个文件引用,无法直接删除。需要先将 AcpDebugRequest, AcpDebugRunResult, AcpWorkdirInfo, IWindowPresenter, TabData 提取到独立类型文件后,才能移除对 legacy.presenters 的依赖。


3. 事件系统两套定义分析 ✅ 互补,非重复

文件对比:

  • src/main/events.ts (163 行): 包含 CONFIG_EVENTS, MCP_EVENTS, WINDOW_EVENTS, SETTINGS_EVENTS, SYNC_EVENTS, DEEPLINK_EVENTS, SHORTCUT_EVENTS, TAB_EVENTS, TRAY_EVENTS, LIFECYCLE_EVENTS, PROVIDER_DB_EVENTS, SYSTEM_EVENTS, UPDATE_EVENTS
  • src/shared/contracts/events.ts (258 行): 包含 zod schema 定义的 DEEPCHAT_EVENT_CATALOG,用于 typed event envelope 验证
  • src/renderer/src/events.ts (95 行): 包含 renderer 侧使用的事件常量

结论: 两套系统是互补的:

  • src/main/events.tssrc/renderer/src/events.ts运行时事件常量(字符串值),用于 eventBus.sendToMain() / eventBus.sendToRenderer() 的 main->renderer 通信
  • src/shared/contracts/events.ts类型契约系统,用于 publishDeepchatEvent() 的 typed event envelope 验证

注意: window.state.changed 等事件通过 publishDeepchatEvent() 发送(typed),而 WINDOW_EVENTS.WINDOW_FOCUSED 等通过 eventBus.sendToMain() 发送(untyped)。这是设计上的不一致——窗口相关事件有两套发送路径。


4. MIGRATED_RAW_CHANNEL_BASELINE 基线分析 ⚠️ 应收紧

文件: scripts/architecture-guard.mjs:83-86

const MIGRATED_RAW_CHANNEL_BASELINE = new Map([
  ['src/main/presenter/windowPresenter/index.ts', 4],
  ['src/renderer/src/App.vue', 1]
])

验证结果:

  • windowPresenter/index.ts 中的 4 个 raw channel 是 eventBus.sendToMain(WINDOW_EVENTS.*) 调用,这些不是 IPC 直接调用,而是 EventBus 封装调用
  • App.vue 中的 1 个 raw channel 需要确认

结论: 基线值应该收紧为 0。当前 windowPresenter 中的 EventBus 调用不应被计入 raw channel,因为 EventBus 是内部抽象层。如果 guard 的 regex 将 eventBus.sendToMain() 匹配为 INLINE_EVENTBUS_CHANNEL_PATTERN,这是误报,需要调整 regex 或收紧基线。


5. cachedMainKernelRouteRuntime 缓存机制 ✅ 当前安全

文件: src/main/presenter/index.ts:881-922

let cachedMainKernelRouteRuntime: ReturnType<typeof createMainKernelRouteRuntime> | undefined

export function getMainKernelRouteRuntime(): ReturnType<typeof createMainKernelRouteRuntime> {
  if (!presenter) {
    throw new Error('Presenter must be initialized before accessing the kernel route runtime')
  }
  if (!cachedMainKernelRouteRuntime) {
    cachedMainKernelRouteRuntime = buildMainKernelRouteRuntime()
  }
  return cachedMainKernelRouteRuntime
}

结论: 当前实现安全,因为:

  • Presenter 是单例模式(getInstance 只初始化一次)
  • presenter 模块变量一旦赋值不会重置
  • cachedMainKernelRouteRuntime 在首次调用时构建,后续直接返回

潜在风险: 如果未来支持 presenter 热重启或重新初始化,缓存会过时。建议添加注释说明此缓存与单例模式绑定,或添加缓存版本检查机制。


总结

问题 结论 优先级
llmproviderPresenter 初始化 安全但脆弱
legacy.presenters 类型引用 需逐步拆分
事件系统两套定义 互补但窗口事件有不一致
MIGRATED_RAW_CHANNEL_BASELINE 应收紧为 0
cachedMainKernelRouteRuntime 当前安全

@zerob13

zerob13 commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator Author

IPC Migration Code Review

整体来看这个重构的迁移很完整,主线逻辑正确。以下是发现的问题和建议:


1. 潜在 Bug / 不合理之处

无关键 bug 发现。 核心迁移链路验证通过:

  • Stream 事件:dispatch.ts 中移除了 eventBus.sendToRenderer(STREAM_EVENTS.RESPONSE/END) 后,renderer 端 messageIpc.ts 已完全通过 chatClient.onStreamUpdated/onStreamCompleted/onStreamFailed 订阅 typed events,链路无断裂。
  • configPresenter/eventPublishers.ts 新文件正确实现了 dual-publish(eventBus.sendToMain + publishDeepchatEvent),renderer 端 ConfigClient.ts / ModelClient.ts 均有对应订阅。
  • Floating preload 返回的 unsubscribe 函数在 FloatingButton.vuefloating/main.ts 中均被正确存储和清理。
  • Splash preload 重写后 loading.vue 正确使用 window.deepchatSplash API 并在 onBeforeUnmount 清理 listeners。
  • exposeElectronAPI 移除后 renderer 中已无 window.electron 使用,getPlatform() 正确替代了原先通过 electron-toolkit 暴露的 process.platform

2. Guard 是否还需要保留

09eb09e (Guard background exec host from shared logger imports) — 需要保留。

这不是临时兼容代码,而是结构性 guard:

  • backgroundExecLogger.ts 防止 utility process 引入完整的 Electron main 模块链。
  • devicePresenter 中注入 DeviceResetRuntime port 消除了循环 import。
  • scripts/check-background-exec-utility-host.mjs 是 build-time 静态分析防回归。

这些 guard 解决的是模块依赖隔离问题,与 IPC 迁移是正交的,迁移完成后仍需保留。


3. 未完成 / 不干净的地方

3.1 过时注释 — src/main/presenter/index.ts:90-91

// 注意: 现在大部分事件已在各自的 presenter 中直接发送到渲染进程
// 剩余的自动转发事件已在 EventBus 的 DEFAULT_RENDERER_EVENTS 中定义

DEFAULT_RENDERER_EVENTS 已不存在于代码库中,这段注释应删除或更新。

3.2 死常量 — src/main/events.ts

以下事件常量无任何消费者,应清理:

常量 说明
SETTINGS_EVENTS.CHECK_FOR_UPDATES L93 无引用
SETTINGS_EVENTS.PROVIDER_INSTALL L94 无引用
DEEPLINK_EVENTS.PROTOCOL_RECEIVED L118 无引用

注意:TRAY_EVENTS.CHECK_FOR_UPDATES(L150)仍有使用,不要误删。

3.3 Floating preload 死代码 — onConfigUpdate

floatingButtonAPI.onConfigUpdate 在 preload 中暴露、env.d.ts 中声明,但 floating renderer 中没有任何组件实际订阅它。建议移除或确认是否有计划中的消费者。

3.4 src/renderer/api/index.ts barrel export 不一致

OnboardingClient.tsStartupClient.tsScheduledTasksClient.ts 存在但未从 barrel 文件 re-export,与其他 ~30 个 client 的 export 模式不一致。功能上不影响(调用方用直接路径),但作为清理项可以统一。


4. 总结

迁移本身是完整且正确的

  • 所有 legacy presenter reflection 调用已移除
  • 所有 eventBus.sendToRenderer 已替换为 publishDeepchatEvent
  • Renderer 全面使用 typed client/event 订阅
  • 二级渲染进程(floating/splash/browser-overlay)preload 已强化 payload 验证
  • Architecture guard 已扩展覆盖 settings renderer
  • Legacy 文件 (api/legacy/**, ShortcutRuntime, RemoteControlRuntime 等) 已完全删除

剩余清理量很小(~10 行),建议在 merge 前一并处理。

@zerob13

zerob13 commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator Author

PR #1765 重构代码审查报告

整体评价

本次 PR 是 presenter IPC 迁移计划的一部分,主要完成了以下工作:

  1. 清理了大量旧版 IPC 事件系统 - 删除了 legacyTypedEventBridge.ts(459 行),移除了 DISPATCHABLE_PRESENTERSREMOTE_CONTROL_METHODS 等旧常量
  2. 将 presenter 事件发布统一迁移到 publishDeepchatEvent - 所有 presenter 现在都通过类型化的 DeepchatEvent 通道与渲染进程通信
  3. 新增 check-background-exec-utility-host.mjs 构建时 guard - 防止 background exec utility host bundle 引入 @electron-toolkit/utils
  4. DevicePresenter 注入 reset runtime 依赖 - 解耦了全局 presenter 引用,提升了可测试性
  5. 新增大量 route 定义 - 补全了之前缺失的 route 覆盖(knowledge、remoteControl、shortcut、skillSync、oauth 等)

整体架构方向正确,代码质量较高。但存在以下需要关注和修复的问题。


严重问题(需要修复)

1. floatingButtonPresenter 仍使用旧版 ipcMain.handle/on 直接注册 IPC(17 处)

位置: src/main/presenter/floatingButtonPresenter/index.ts:247-360

ipcMain.handle(FLOATING_BUTTON_EVENTS.SNAPSHOT_REQUEST, async () => { ... })
ipcMain.on(FLOATING_BUTTON_EVENTS.CLICKED, () => { ... })

问题: 这是唯一一个仍直接注册 IPC 的 presenter。所有其他 presenter 都已通过 route 系统暴露功能。这破坏了架构一致性,且 floating button 的事件通道未纳入 guard 监控。

建议: 将这些 IPC 注册迁移到 route 系统,或在 architecture-guard.mjs 中为 floatingButtonPresenter 添加白名单/基线豁免。

2. windowPresenter 中仍有 6 处直接 ipcMain.on 注册

位置: src/main/presenter/windowPresenter/index.ts:93-146

ipcMain.on('get-window-id', (event) => { ... })
ipcMain.on('get-web-contents-id', (event) => { ... })
ipcMain.on('browser:chrome-height', (event, payload) => { ... })
ipcMain.on('close-floating-window', (event) => { ... })
ipcMain.on(SHORTCUT_EVENTS.GO_SETTINGS, async () => { ... })
ipcMain.on(SETTINGS_EVENTS.READY, (event) => { ... })

问题: 这些通道是窗口生命周期和浏览器视图协调所必需的,但部分可以迁移到 route 系统(如 get-window-idget-web-contents-id)。browser:chrome-heightclose-floating-window 是内部协调通道,建议保留但需更新 guard 基线。

建议:

  • get-window-id / get-web-contents-id -> 迁移为 route
  • SHORTCUT_EVENTS.GO_SETTINGS -> 已存在 shortcutRegisterRoute 等,确认是否重复
  • 更新 MIGRATED_RAW_CHANNEL_BASELINE 以反映这些剩余通道

3. SplashWindowManager 仍有 2 处 ipcMain.on

位置: src/main/presenter/lifecyclePresenter/SplashWindowManager.ts:328,346

ipcMain.on(DATABASE_UNLOCK_SUBMIT_CHANNEL, (event, payload) => { ... })
ipcMain.on(DATABASE_UNLOCK_CANCEL_CHANNEL, (event, payload) => { ... })

问题: 数据库解锁是安全敏感流程,直接 IPC 绕过了 route 的输入验证层。

建议: 迁移到带 zod schema 验证的 route 系统。


中等问题(建议修复)

4. eventBus.sendToRenderer 仍被 publishDeepchatEvent.ts 使用

位置: src/main/routes/publishDeepchatEvent.ts:25

eventBus.sendToRenderer(DEEPCHAT_EVENT_CHANNEL, SendTarget.ALL_WINDOWS, envelope)

问题: 这是唯一一处仍使用 sendToRenderer + SendTarget 的代码。虽然功能正确,但 SendTarget 枚举和 sendToRenderer 方法的存在意味着旧 API 未被完全清理。

建议:

  • publishDeepchatEvent.ts 中直接使用 windowPresenter.sendToAllWindows() 或保留此封装但标记为 // Legacy bridge, remove after full migration
  • 考虑在 eventBus.ts 中将 sendToRenderer 标记为 @deprecated

5. eventBus.setTabPresenter 是空实现但保留注释

位置: src/main/eventbus.ts:111-113

setTabPresenter(_tabPresenter: ITabPresenter) {
  // Intentionally kept as a compatibility hook for legacy initialization paths.
}

问题: 如果 TabPresenter 已不再通过 EventBus 路由,此方法可以安全删除。但需确认是否有初始化代码仍调用它。

建议: 搜索所有 setTabPresenter 调用,如无调用则删除。

6. windowPresentersendToWebContentsTargetcreateTypedEnvelopeForLegacyRendererChannel 是兼容层

位置: src/main/presenter/windowPresenter/index.ts:586-633

private createTypedEnvelopeForLegacyRendererChannel(channel: string, args: unknown[]) {
  switch (channel) {
    case DEEPLINK_EVENTS.START: ...
    case 'window-focused': ...
    case SHORTCUT_EVENTS.ZOOM_IN: ...
  }
}

问题: 这个兼容层将旧字符串通道映射为新类型化事件,但通道列表可能不完整。如果渲染进程仍有代码监听 'window-focused' 等旧通道,而主进程发送的是 DEEPCHAT_EVENT_CHANNEL 信封,则事件可能无法被正确解析。

建议: 确认渲染进程侧是否已完全迁移到 DEEPCHAT_EVENT_CHANNEL 监听。如果已完成,此兼容层可以逐步移除。


低风险问题(可选优化)

7. architecture-guard.mjsMIGRATED_RAW_CHANNEL_BASELINE 需要更新

位置: scripts/architecture-guard.mjs:83-86

const MIGRATED_RAW_CHANNEL_BASELINE = new Map([
  ['src/main/presenter/windowPresenter/index.ts', 4],
  ['src/renderer/src/App.vue', 1]
])

问题: windowPresenter/index.ts 的基线是 4,但实际剩余的直接通道数(ipcMain.on + webContents.send)已超过此值。这会导致 guard 在严格模式下失败。

建议: 重新统计并更新基线,或将未迁移的通道加入白名单。

8. DevicePresentersetResetRuntime 调用时机

位置: src/main/presenter/index.ts:208-211

devicePresenter.setResetRuntime({
  closeSqlite: () => this.sqlitePresenter.close(),
  destroyKnowledge: () => this.knowledgePresenter.destroy()
})

问题: 依赖注入正确,但 closeSqlite 是同步调用而 destroyKnowledge 返回 Promise。DevicePresenter 中未处理 destroyKnowledge 的异步错误。

建议: 在 DevicePresenter.resetDataByType 中为 destroyKnowledge 添加 try/catch 和日志。

9. configPresenter/eventPublishers.ts 中部分函数缺少错误处理

位置: src/main/presenter/configPresenter/eventPublishers.ts

export function emitThemeChanged(...) {
  void readThemeState(configPresenter)
    .then((state) => { ... })
    .catch((error) => { console.error(...) })
}

问题: void 前缀抑制了 Promise 未处理的警告,但如果 readThemeState 抛出异常,错误仅被打印到控制台,调用方无法感知。

建议: 确认这些 emit 函数是否需要返回 Promise 或统一错误处理策略。


已正确完成的部分

  1. 旧版事件系统清理彻底 - legacyTypedEventBridge.ts 已删除,events.ts 中大量旧事件常量已移除
  2. Presenter 事件发布统一 - configPresenteragentRuntimePresenteragentSessionPresentermcpPresenterupgradePresentersyncPresenterskillPresenterskillSyncPresenterknowledgePresenternotificationPresenterdeeplinkPresentershortcutPresenterrateLimitManagerollamaManager 等都已迁移到 publishDeepchatEvent
  3. Route 系统补全 - 新增了大量 route 定义,覆盖 knowledge、remoteControl、shortcut、skillSync、oauth、exporter 等之前缺失的 presenter
  4. Guard 脚本新增 - check-background-exec-utility-host.mjs 有效防止 utility process 引入主进程依赖
  5. 测试覆盖 - 新增了大量单元测试,包括 architectureGuard.test.tsdevicePresenter.test.ts、renderer 侧 API 测试等

Guard 清理建议

以下 guard 可以考虑清理或更新:

Guard 状态 建议
architecture-guard.mjs 需要更新 MIGRATED_RAW_CHANNEL_BASELINE 基线需重新统计;MAIN_GUARD_PATHS 中 presenter 导入限制需确认是否仍适用
check-background-exec-utility-host.mjs 保留 新增且有效,防止 utility process 依赖泄漏
eventBus.sendToRenderer / SendTarget 可标记 deprecated publishDeepchatEvent.ts 使用,完成迁移后可移除
ipcMain.handle/on in floatingButtonPresenter 需要迁移 唯一未迁移的 presenter,需补全 route 或更新 guard
ipcMain.on in windowPresenter 部分迁移 生命周期通道建议保留,功能通道建议迁移
ipcMain.on in SplashWindowManager 建议迁移 安全敏感流程应通过 route 验证

总结

本次重构整体方向正确,架构清晰,测试覆盖良好。主要风险点在于:

  1. floatingButtonPresenter 是唯一未迁移到 route 系统的 presenter
  2. windowPresenterSplashWindowManager 中仍有少量直接 IPC 注册
  3. architecture-guard.mjs 的基线数据需要同步更新以反映当前状态

建议优先修复严重问题 1-3,然后更新 guard 基线,最后考虑清理 eventBus 中的 deprecated API。

@zerob13 zerob13 changed the title Guard the background exec utility host from shared logger imports refactor(ipc): migrate presenter transport to typed route/event system Jun 13, 2026
@zerob13

zerob13 commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator Author

Review follow-up 处理结果

已参考几条模型 review 评论并做了两轮小范围修复,避免把启动期/窗口生命周期/floating 专用 IPC 迁移扩大成第二个大重构。

已修复

  • 删除 src/main/presenter/index.ts 中引用已不存在 DEFAULT_RENDERER_EVENTS 的过时注释。
  • 删除 main 侧无运行时消费者的事件常量:
    • SETTINGS_EVENTS.CHECK_FOR_UPDATES
    • SETTINGS_EVENTS.PROVIDER_INSTALL
    • DEEPLINK_EVENTS.PROTOCOL_RECEIVED
  • 移除 floating preload 中未使用的 onConfigUpdate / CONFIG_UPDATE 暴露和类型声明。
  • 补齐 renderer API barrel exports:OnboardingClientScheduledTasksClientStartupClient
  • 收紧 architecture-guard.mjs 的 obsolete App.vue raw-channel allowance;保留 windowPresenter 的 4 个实际窄 IPC allowance,并补充注释说明它们是窗口 identity/chrome coordination 通道。
  • cachedMainKernelRouteRuntime 增加注释,明确它绑定当前 Presenter 单例假设。
  • 新增 docs/issues/pr1765-review-followups/ 记录本轮处理范围和 deferred 项。

提交:

  • 9ece79fc refactor(ipc): address pr review followups
  • b9296cd1 chore(ipc): remove stale event constants

未在本轮修复的项及原因

  • floatingButtonPresenteripcMain.handle/on:暂不迁移。它是独立 floating renderer 的专用控制通道,迁到 main kernel route 会牵涉 preload 协议、事件源校验和现有 smoke 覆盖,不适合作为 review cleanup 混入本 PR。
  • windowPresenter 的 4 个直接 IPC:暂不迁移。get-window-id / get-web-contents-id 当前是 preload 的同步身份查询;browser:chrome-height / close-floating-window 是窗口 chrome/浮窗协调通道。已在 architecture guard 中保留显式 allowance,而不是误收紧为 0。
  • SplashWindowManager 数据库解锁 IPC:暂不迁移。该流程发生在启动解锁阶段,早于完整 route runtime 可用;迁移需要单独设计 splash/preload/database-security route 生命周期。
  • publishDeepchatEvent.ts 内部仍调用 eventBus.sendToRenderer:保留。这里是 typed event envelope 的单一出口,不是业务层继续使用 legacy presenter IPC;直接改成 windowPresenter 反而会让 route/event 发布层重新耦合 presenter 单例。
  • eventBus.setTabPresenter:保留。当前仍有初始化调用和 EventBus 测试覆盖;移除需要同步清理 docs/tests,不属于本轮风险收益比最高的点。
  • legacy.presenters.d.ts 类型拆分:暂不处理。这个需要拆 AcpDebug*AcpWorkdirInfoIWindowPresenterTabData 的类型归属,适合后续独立类型清理 PR。
  • DevicePresenter.destroyKnowledge 异步错误处理:未改。当前 resetDataByType() 的 close/destroy 调用已经在对应 try/catch 内,会记录并继续进入 reset 流程。
  • configPresenter/eventPublishers.ts 返回 Promise:未改。当前这些 emit 是 fire-and-forget 事件发布 helper,内部已有 .catch() 记录错误;改成返回 Promise 会改变调用方语义。

验证

  • pnpm exec vitest run test/renderer/api/preloadBoundaries.test.ts test/renderer/api/clients.test.ts test/main/scripts/architectureGuard.test.ts --silent --reporter=dot
  • pnpm exec vitest run test/main/presenter/windowPresenter.test.ts test/renderer/components/AboutUsSettings.test.ts test/renderer/components/SettingsApp.providerDeeplink.test.ts --silent --reporter=dot
  • pnpm run format
  • pnpm run i18n
  • pnpm run lint
  • pnpm run typecheck

@zerob13

zerob13 commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator Author

Follow-up Review (post-fixup)

上一轮提出的 4 项全部已修复(过时注释、死常量、floating onConfigUpdate、barrel exports)。新 commits 质量干净。


新发现:windowPresenter 中 4 个无发送方的 ipcMain.on 死处理器

src/main/presenter/windowPresenter/index.ts 中有 4 个 ipcMain.on 注册但实际无 renderer/preload 发送方:

Channel 为什么是死代码
103-109 'browser:chrome-height' 全项目无任何 ipcRenderer.send('browser:chrome-height', ...) 调用。tabPresenter.updateChromeHeight 唯一调用方就是这个死处理器,chrome height 始终走 DEFAULT_CHROME_HEIGHT 兜底。
111-120 'close-floating-window' 全项目无任何发送方。Floating renderer 不发此事件。
138-144 SHORTCUT_EVENTS.GO_SETTINGS 无 renderer 发送方。shortcutPresenter 通过 eventBus.sendToMain 发送,由 line 129 的 eventBus.on 处理。此 ipcMain 注册完全多余。
146-148 SETTINGS_EVENTS.READY 已迁移到 typed route windowNotifySettingsReadyRoute。Settings renderer 现使用 windowClient.notifySettingsReady() 而非 raw IPC。

影响:

  • 非功能性 bug,不会阻断任何现有功能
  • architecture guard 的 baseline 4 实际只需要 2get-window-id + get-web-contents-id
  • 清理后 baseline 可收紧到 2

建议处理: 可在本 PR 清理或作为 follow-up。优先级低,属于收尾清扫。


确认:其他 deferred 项合理

Follow-up comment 中列出的 deferred 项(floating IPC、splash unlock IPC、publishDeepchatEvent 内部用 eventBus.sendToRenderereventBus.setTabPresenter)均已确认合理:

  • get-window-id / get-web-contents-id:preload 同步身份查询,无法迁移到 async route。
  • Floating renderer 专用 IPC:独立 preload channel 是合理设计。
  • Splash database unlock:早于 route runtime 可用,保持 raw IPC 正确。
  • publishDeepchatEvent 内部 sendToRenderer:是 typed event 的单一出口实现,不是 legacy 残留。

总结

重构完整度很高。唯一残留是上述 4 个死处理器,风险为零但不干净。除此之外 LGTM。

@zerob13

zerob13 commented Jun 13, 2026

Copy link
Copy Markdown
Collaborator Author

二次 review 死代码清理结果

已核查最新 review 指出的 windowPresenter 4 个 raw IPC handler,结论属实,已清理。

已删除

  • ipcMain.on('browser:chrome-height', ...)
    • 全项目无发送方;TabPresenter.updateChromeHeight() 唯一调用方就是该死 handler。
  • ipcMain.on('close-floating-window', ...)
    • 全项目无发送方,floating renderer/preload 不发送此 channel。
  • ipcMain.on(SHORTCUT_EVENTS.GO_SETTINGS, ...)
    • 无 renderer 发送方;实际路径是 ShortcutPresenter -> eventBus.sendToMain(SHORTCUT_EVENTS.GO_SETTINGS),由 eventBus.on 处理。
  • ipcMain.on(SETTINGS_EVENTS.READY, ...)
    • 已被 window.notifySettingsReady typed route 替代,settings renderer 使用 WindowClient.notifySettingsReady()
  • TabPresenter.updateChromeHeight()
    • 删除上述 handler 后无剩余调用方,一并清理。
  • main 侧 SETTINGS_EVENTS.READY
    • raw IPC handler 删除后无 main 侧消费者,一并移除。

Guard 更新

architecture-guard.mjssrc/main/presenter/windowPresenter/index.ts 的 raw-channel baseline 已从 4 收紧到 2,只保留:

  • get-window-id
  • get-web-contents-id

这两个仍是 preload 同步 identity lookup,不能等价迁到 async route。

提交

  • 0a7ba48c chore(ipc): remove dead window ipc handlers

验证

  • pnpm exec vitest run test/main/presenter/windowPresenter.test.ts test/main/scripts/architectureGuard.test.ts test/main/routes/dispatcher.test.ts test/renderer/components/SettingsApp.test.ts test/renderer/components/SettingsApp.providerDeeplink.test.ts --silent --reporter=dot
  • pnpm run typecheck
  • pnpm run format
  • pnpm run i18n
  • pnpm run lint

@zerob13 zerob13 merged commit 32bacc5 into dev Jun 13, 2026
8 checks passed
@zhangmo8 zhangmo8 deleted the codex/presenter-ipc-migration-plan branch June 14, 2026 01:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant