# 7-64 [recycle] CodexMobile 嵌入 Page AI 方案 v1 > 创建时间:2026-06-23 > > 当前状态:`RECYCLE` > > Owner:07-ai / Page AI / CodexMobile embed > > 上位依据: > - `design/07-ai/done/7-62-page-ai-board-first-full-rewrite-v1.md` > - `design/07-ai/process/7-63-page-ai-board-first-productization-v1.md` > - `design/07-ai/done/7-38-page-ai-sidebar-runtime-owner-split-v1.md` > 过时原因:已由 `design/07-ai/process/7-65-opencode-webui-embed-page-ai-v1.md` 替代;Page AI 新主路径只接入 opencode 官方 runtime + 官方 WebUI。 ## 1. 核心结论 放弃 Board-first 和自研聊天 UI 两条路,改为 **fork CodexMobile 开源代码 → 精简 → iframe 嵌入 MNote**。 ```text MNote Page AI = MNote 原生上下文 pills + CodexMobile 精简版 iframe CodexMobile = Vue 3 SPA + Express server → Codex CLI app-server (RPC) ``` 理由: - CodexMobile(`friuns2/codex-mobile`,MIT,675⭐)已提供成熟的聊天 UI、流式渲染、session 管理、plan/tool 卡片 - 当前 MNote Page AI runtime(4457 行 JS)+ Rust bridge(~20000 行)维护成本高,且聊天体验不如 CodexMobile - CodexMobile 直接对接 Codex CLI,CodexRelay 已解决 DeepSeek 兼容,不需要 Board 中介 - 嵌入方案比自研省 90% 代码量,比 Board-first 少一层依赖 ## 2. CodexMobile 现状 ### 2.1 仓库信息 | 项目 | 值 | |---|---| | 仓库 | `friuns2/codex-mobile` | | 协议 | MIT | | 星数 | 675 | | 语言 | TypeScript (Vue 3 + Express) | | 本地版本 | v0.1.90 (`/home/lix/.local/lib/node_modules/codexapp/`) | | 当前运行 | `codexapp --no-login --no-tunnel --no-open --port 5900` | ### 2.2 架构 ``` 浏览器 Vue SPA (hash router) ↓ fetch /codex-api/rpc Express httpServer.ts ↓ codexAppServerBridge.ts Codex CLI app-server (RPC over HTTP) ↓ Codex CLI (实际 agent 执行) ``` ### 2.3 核心模块 | 模块 | 文件 | 作用 | |---|---|---| | RPC 桥接 | `codexAppServerBridge.ts` (~2500行) | 代理所有 Codex RPC 调用 | | API 网关 | `codexGateway.ts` | 线程/消息/模型/账户等高层 API | | RPC 客户端 | `codexRpcClient.ts` | 底层 RPC 调用与错误处理 | | HTTP 服务 | `httpServer.ts` | Express + WebSocket + 静态文件 | | 聊天 UI | `ThreadConversation.vue` | 消息气泡、plan 卡片、工具卡片 | | 输入框 | `ThreadComposer.vue` | 消息输入、发送、模型选择 | | 侧边栏 | `SidebarThreadTree.vue` | 线程列表、搜索、切换 | | 布局 | `DesktopLayout.vue` | 整体布局框架 | ## 3. 精简方案 ### 3.1 删除清单 | 删除模块 | 原因 | |---|---| | xterm 终端 (`terminalManager.ts`, `ThreadTerminalPanel.vue`) | MNote 不是终端 | | 文件浏览 (`localBrowseUi.ts`) | MNote 有 FileTree | | Firebase auth | MNote 用 SQLite control-plane | | Telegram bridge (`telegramThreadBridge.ts`) | 无关 | | Composio 集成 | 无关 | | OpenRouter proxy (`openRouterProxy.ts`) | 无关 | | Zen proxy (`zenProxy.ts`) | 无关 | | Custom endpoint proxy (`customEndpointProxy.ts`) | 无关 | | Free mode (`freeMode.ts`) | 无关 | | Skills routes/hub (`skillsRoutes.ts`, `SkillsHub.vue`, `SkillCard.vue`) | 无关 | | Review git (`reviewGit.ts`, `ReviewPane.vue`) | 无关 | | Automations (`AutomationsPanel.vue`) | 无关 | | Directory hub (`DirectoryHub.vue`) | 无关 | | Account menu (`AccountMenu.vue`) | 简化 | | Rate limit status (`RateLimitStatus.vue`) | 无关 | | Dictation (`useDictation.ts`) | 无关 | | GitHub skills sync (`useGithubSkillsSync.ts`) | 无关 | | API methods panel (`ApiMethodsPanel.vue`) | 调试工具 | | Pending request panel (`ThreadPendingRequestPanel.vue`) | 简化 | | Queued messages (`QueuedMessages.vue`) | 简化 | | Composer dropdowns (runtime/search/skill picker) | 简化 | | Header git branch dropdown | 无关 | ### 3.2 保留清单 | 保留模块 | 作用 | |---|---| | `codexAppServerBridge.ts` | 核心 RPC 桥接 | | `codexGateway.ts` | 高层 API | | `codexRpcClient.ts` | RPC 客户端 | | `httpServer.ts` | Express + WebSocket | | `authMiddleware.ts` | 简化为 MNote token 验证 | | `ThreadConversation.vue` | 聊天气泡 | | `ThreadComposer.vue` | 输入框 | | `SidebarThreadTree.vue` | 线程列表 | | `DesktopLayout.vue` | 布局 | | `ContentHeader.vue` | 顶部信息 | | `appServerDtos.ts` | 类型定义 | | `codexErrors.ts` | 错误处理 | | WebSocket 流式事件 | 实时消息 | ### 3.3 新增:postMessage Bridge MNote 原生层与 CodexMobile iframe 之间的通信协议: ```typescript // MNote → CodexMobile interface MnoteContextMessage { type: 'mnote:context'; payload: { workspaceId: string; documentId: string; pageTitle: string; rootUri: string; // file:///... primaryTarget: { absolutePath: string; relativePath: string; }; selection?: { text: string; }; allowedRoots: Array<{ rootUri: string; permission: 'read' | 'write'; }>; knowledgeContext?: string; // LightRAG 查询结果 }; } // CodexMobile → MNote interface CodexMobileEvent { type: 'codex:file-changed' | 'codex:session-update' | 'codex:ready'; payload: { changedFiles?: string[]; sessionId?: string; threadId?: string; }; } ``` ## 4. 集成架构 ### 4.1 整体拓扑 ``` ┌──────────────────────────────────────────────────┐ │ MNote Rust SSR (localhost:3000) │ │ │ │ ┌─ Page AI Panel ──────────────────────────────┐ │ │ │ ┌─ MNote 原生上下文 pills ──────────────────┐ │ │ │ │ │ [当前页] [选区] [知识库] [allowed roots] │ │ │ │ │ └────────────────────────────────────────────┘ │ │ │ │ ┌─ iframe ───────────────────────────────────┐ │ │ │ │ │ CodexMobile 精简版 SPA │ │ │ │ │ │ (Vue 3, hash router, 独立端口 5900) │ │ │ │ │ │ │ │ │ │ │ │ ThreadConversation + ThreadComposer │ │ │ │ │ └────────────────────────────────────────────┘ │ │ │ │ postMessage ↑↓ │ │ │ └────────────────────────────────────────────────┘ │ │ │ │ /codex-mobile/* → reverse proxy → 127.0.0.1:5900 │ └──────────────────────────────────────────────────┘ ↓ CodexMobile Express (5900) ↓ Codex CLI app-server (RPC) ↓ Codex CLI + CodexRelay → DeepSeek ``` ### 4.2 Rust 侧改动 ```rust // mnote-web routes/mod.rs 新增 .route("/codex-mobile/{*path}", any(codex_mobile_proxy)) // codex_mobile_proxy: 反向代理到 127.0.0.1:5900 // 仅对已认证 session 放行 // 注入 X-Mnote-Workspace-Id / X-Mnote-Document-Id header ``` ### 4.3 前端侧改动 ```javascript // sidebar-page-ai-runtime.js 精简为: // 1. 渲染上下文 pills(当前页、选区、知识库) // 2. 创建 iframe 指向 /codex-mobile/ // 3. postMessage 监听与转发 // 4. 文件变更事件 → watcher 刷新编辑器 // 删除: // - 所有 provider 选择逻辑 (Hermes/Reasonix/Chat-only) // - 所有 session/message/run 持久化逻辑 // - 所有 Board bridge 调用 // - 所有 workflow/worker 选择器 // 预计从 4457 行精简到 ~300 行 ``` ### 4.4 Rust 侧删除 ```text 删除文件: - routes/page_ai_board.rs (317 行) - routes/page_ai_workflow.rs (967 行) - routes/hermes_client.rs 中 Page AI 相关部分 保留: - hermes_tools/doc.rs 中的 mnote.doc.* tools(非 Page AI 路径仍需要) ``` ## 5. 上下文注入机制 ### 5.1 注入时机 1. Page AI 面板打开时:注入当前页路径、workspaceId、documentId 2. 用户选中文本时:注入 selection 3. 用户切换页面时:更新 primaryTarget 4. 用户触发知识库查询时:注入 knowledgeContext ### 5.2 注入方式 MNote 通过 `iframe.contentWindow.postMessage()` 发送 `mnote:context`,CodexMobile 内新增 `useMnoteBridge.ts` composable 接收并注入到 Codex CLI 的 system prompt 中。 ```typescript // CodexMobile 侧新增 useMnoteBridge.ts // 监听 postMessage,将上下文追加到 thread/start 的 system prompt // ponytail: 最小实现,只做 system prompt 注入,不做 UI 展示 ``` ### 5.3 文件编辑闭环 ``` 用户输入 "把当前页的 A 替换为 B" → Codex CLI 通过 CodexRelay 执行 → Codex CLI 直接编辑 primaryTarget.absolutePath → 磁盘文件变化 → CodexMobile 检测文件变更 → postMessage 'codex:file-changed' → MNote watcher 检测到文件变化 → 刷新 tiptap 编辑器 ``` ## 6. 实施计划 ### Phase A:Fork 与精简(1天) - [ ] `git clone https://github.com/friuns2/codex-mobile` 到 `/mnt/Data1T/mnote/codex-mobile/` - [ ] 删除 3.1 清单中的所有模块 - [ ] 简化 `authMiddleware.ts`:接受 MNote session token - [ ] 新增 `useMnoteBridge.ts`:postMessage 监听 - [ ] 验证 `npm run build` 通过 - [ ] 验证精简版可独立运行(`codexapp --port 5900`) ### Phase B:MNote 集成(1天) - [ ] Rust 新增 `/codex-mobile/{*path}` 反向代理路由 - [ ] `sidebar-page-ai-runtime.js` 精简为上下文 pills + iframe + postMessage - [ ] 删除 `page_ai_board.rs`、`page_ai_workflow.rs` - [ ] 上下文 pills 实现(当前页、选区、知识库引用) - [ ] postMessage bridge 双向通信验证 ### Phase C:闭环验证(0.5天) - [ ] smoke:打开 Page AI → 看到 CodexMobile 聊天界面 - [ ] smoke:发送消息 → 流式回复可见 - [ ] smoke:编辑当前页 → 文件变化 → 编辑器刷新 - [ ] smoke:刷新页面 → 会话恢复 - [ ] smoke:上下文 pills 正确显示当前页信息 ### Phase D:旧代码清理(后续) - [ ] 归档 `sidebar-page-ai-runtime.js` 旧代码 - [ ] 归档 `hermes_client.rs` Page AI 相关代码 - [ ] 更新 `ARCHITECTURE.md` 和 `CURRENT_ARCHITECTURE.md` ## 7. 验收标准 ### 7.1 聊天体验 - 用户可在 Page AI 面板中与 Codex 对话 - 流式回复实时可见 - 支持 stop / retry / copy - 刷新页面后会话历史可恢复 - plan 卡片和工具调用卡片可见(含 plan 持久化补丁) ### 7.2 上下文注入 - 上下文 pills 显示当前页标题和路径 - 选区内容自动注入 - Codex 能读取和编辑当前页文件 - 文件编辑后 MNote 编辑器自动刷新 ### 7.3 代码精简 - `sidebar-page-ai-runtime.js` 从 4457 行精简到 <500 行 - 删除 `page_ai_board.rs` 和 `page_ai_workflow.rs`(~1300 行) - 不再依赖 Agent Board 服务 ## 8. 风险与处理 | 风险 | 处理 | |---|---| | CodexMobile 上游更新导致 fork 过时 | 定期 rebase,只保留精简 diff | | Codex CLI 不可用 | 降级提示 "Codex CLI 未运行",不伪装可用 | | iframe 跨域问题 | 同源反向代理(`/codex-mobile/*`),无跨域 | | postMessage 安全 | 验证 origin,只接受已知消息类型 | | plan 卡片刷新消失 | 已有 `codexmobile-plan-persist.js` 补丁,合入 fork | | npm 升级清空 codexapp 目录 | fork 到 MNote 仓库内,不依赖 npm 全局安装 | ## 9. 与旧方案的对比 | | Board-first (7-62/7-63) | CodexMobile 嵌入 (本方案) | |---|---|---| | MNote 代码量 | ~4457 JS + ~20000 Rust | ~500 JS + ~50 Rust | | 聊天 UI 成熟度 | 自研,持续打磨 | 675⭐ 开源验证 | | 依赖服务 | Agent Board (必须) | Codex CLI (必须) | | Agent 选择 | 通过 Board 间接 | 直接使用 Codex CLI | | Provider 适配 | Board 负责 | CodexRelay 负责 | | 上下文注入 | 自研 pills | 自研 pills + system prompt | | 维护负担 | Board bridge + 聊天 UI | 追上游 + postMessage bridge | | 差异化 | 上下文 pills | 上下文 pills + 成熟聊天体验 | ## 10. 非目标 - 不把 CodexMobile 的终端、文件浏览、Skills、Review 等功能带入 MNote - 不替换 MNote 的 FileTree、编辑器、知识库等核心功能 - 不要求 CodexMobile 支持 MNote 特有的资源类型(mindmap、OnlyOffice) - 不实现 CodexMobile 与 MNote auth 的 SSO 统一(短期独立 auth,长期可选)