13 KiB
13 KiB
7-64 [recycle] CodexMobile 嵌入 Page AI 方案 v1
创建时间:2026-06-23
当前状态:
RECYCLEOwner:07-ai / Page AI / CodexMobile embed
上位依据:
design/07-ai/done/7-62-page-ai-board-first-full-rewrite-v1.mddesign/07-ai/process/7-63-page-ai-board-first-productization-v1.mddesign/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。
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 之间的通信协议:
// 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 侧改动
// 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 前端侧改动
// 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 侧删除
删除文件:
- 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 注入时机
- Page AI 面板打开时:注入当前页路径、workspaceId、documentId
- 用户选中文本时:注入 selection
- 用户切换页面时:更新 primaryTarget
- 用户触发知识库查询时:注入 knowledgeContext
5.2 注入方式
MNote 通过 iframe.contentWindow.postMessage() 发送 mnote:context,CodexMobile 内新增 useMnoteBridge.ts composable 接收并注入到 Codex CLI 的 system prompt 中。
// 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.rsPage 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,长期可选)