收口 Rust Web 入口与 AI 写入链

- 将 3000 主入口继续收口到 mnote-web,补齐 /favicon.ico、/api/auth、session alias、AI run 等 Rust Web 路由边界。

- 更新登录页与 Convex Auth 代理,支持测试账号快速登录写入真实 Convex Auth cookie。

- 推进页面设置、Wolai 对齐、Phase 7 AI kernel/CLI-first 设计文档与相关 smoke 脚本。

- 更新 leptos-tiptap 生成资产、mnote-cli/bridge-runtime、前端依赖和 dev/prod 启动脚本。
This commit is contained in:
lix-2026
2026-05-06 21:44:20 +08:00
parent 98b6360595
commit e8ba12e461
86 changed files with 8872 additions and 1716 deletions
@@ -9,6 +9,11 @@
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/process/7-phase7-ai-kernel-projection-plan-v2.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-1-phase7-document-ai-minimum-loop-checklist-v1.md`
>
> 2026-05-05 追加说明:
> - 本稿的对象模型、artifact 写链与 kernel 边界仍然有效
> - 但触发与执行口径已被 `/mnt/Data1T/mnote/design/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md` 覆盖
> - 当前凡是提到“页面 AI 面板触发”的位置,都应理解为“页面 AI 面板作为 `mnote-cli` host 触发”,而不是独立内置编排主线
---
@@ -38,7 +43,7 @@
- `ai_note node`
- `reference edge`
2. 只允许围绕**当前文档页**创建,不做跨页、跨工作区写链
3. 触发方式不是自然语言,不做自动推断,只允许页面 AI 面板里的固定按钮触发
3. 触发方式不是自然语言,不做自动推断,只允许页面 AI 面板里的固定按钮触发;该面板长期应只是 `mnote-cli` host
4. 点击按钮后直接创建,不走“先预览再确认”的两阶段流
5. `summary node` 默认单例覆盖更新;`ai_note node` 每次新建
6. 两者都落成**可编辑的页面型节点**
@@ -91,7 +96,7 @@
- 它依赖更稳定的摄取边界
- 它会引入更重的异步任务与检索协议
- 它不是当前页 AI 面板的最小邻接能力
- 它不是当前页 AI host 面板的最小邻接能力
所以本稿故意不把阶段 5 全写成一个“大包”,而是只切出:
@@ -283,7 +288,7 @@
- “看起来像摘要就自动生成”
- “只要语义明确就直接落库”
只支持页面 AI 面板里的两个固定按钮:
只支持页面 AI host 面板里的两个固定按钮:
- `创建 Summary`
- `创建 AI Note`
@@ -22,6 +22,10 @@
> - 2026-04-23 验证补充:
> - `cd /mnt/Data1T/mnote/wolai-backend && ./.venv/bin/python -m pytest -q tests/test_ai_document_agent.py` -> `15 passed`
> - `cd /mnt/Data1T/mnote/wolai-frontend && pnpm test -- --runInBand src/app/api/ai-agent/run/route.test.ts src/app/api/ai-agent/document/config/route.test.ts src/components/editor/DocumentAiAgentPanel.runtime.test.tsx src/components/ai-agent/panelShared.test.ts` -> `202 passed`
> - 2026-05-05 口径修正:
> - 本稿记录的 `openai-agents-python` 文档页主链收口,当前仅作为过渡阶段基线
> - 长期方向已被 `/mnt/Data1T/mnote/design/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md` 覆盖
> - 当前长期口径固定为:`mnote-cli` 是唯一长期 agent 执行面;`openai-agents-python`、Hermes、Codex 都视为可插拔外置 agent
---
@@ -41,7 +45,7 @@
1. 如果现在开始做 `Phase 7`,第一交付物到底是什么
2. `Phase 7` 应该接在哪条现有主线之后,而不是另起一套理想结构
3. `openai-agents-python` 到底如何接入当前文档页 AI 主链
3. 过渡期 `openai-agents-python` 适配链到底如何接入当前文档页 AI 主链
4. 哪些 `v1` 里的目标继续保留,哪些必须降级到后续阶段
一句话收口:
@@ -54,7 +58,9 @@
当前推荐口径固定如下:
> **`mnote` 的长期 AI 主线仍然采用“Rust kernel / Rust runtime 做唯一事实源与真执行面,`openai-agents-python` 作为 `mnote` 专用编排层,`Hermes` 退回过渡与实验平台”的结构。**
> **本稿原始判断是“Rust kernel / Rust runtime 做唯一事实源与真执行面,`openai-agents-python` 作为 `mnote` 专用编排层,`Hermes` 退回过渡与实验平台”。**
>
> **该判断现已退化为历史过渡口径;当前长期口径改为:`Rust kernel / Rust runtime` 做唯一事实源与真执行面,`mnote-cli` 做唯一长期 agent 执行面,`openai-agents-python` 与 `Hermes` 都作为可插拔外置 agent。**
但如果按真实执行顺序来排,当前 `Phase 7` 必须服从下面这个前置条件:
@@ -153,7 +159,7 @@
- 已有一个可工作的文档页 AI 过渡链
- 这条链已经开始向 `page aggregate command family` 回接
- `Phase 7` 的第一任务,应是把这条链从 Hermes 兼容桥迁到正式 `openai-agents-python` 编排层
- `Phase 7` 的第一任务,应是把这条链从 Hermes 兼容桥收口到统一 `mnote-cli` host / adapter`openai-agents-python`、Hermes、Codex 只作为可插拔外置 agent
---
@@ -212,7 +218,7 @@
1. 明确它是过渡链
2. 冻结它的保留边界
3.`openai-agents-python` 替换它的编排层,而不是推翻整条文档页 AI 回写链
3.`mnote-cli` 统一承接长期 agent 执行面,而不是把 `openai-agents-python` 或 Hermes 继续写成长期主编排
---
@@ -226,13 +232,13 @@ Document Page / Read View / AI Panel
v
AI Gateway / SSE Event Adapter
|
+---- current fallback: Hermes bridge
|
+---- target mainline: openai-agents-python
+---- long-term execution surface: mnote-cli
| |
| +---- provider: OpenAI Responses API
| +---- mnote page tools
| +---- mnote tree tools
| +---- external agent adapter: openai-agents-python
| +---- external agent adapter: Hermes
| +---- external agent adapter: Codex
|
+---- current fallback: Hermes bridge
|
v
Rust runtime / mnote-web / bridge-runtime
@@ -267,14 +273,14 @@ Rust kernel truth
- 通用 agent 编排框架
- 通用聊天产品壳
#### `openai-agents-python`
#### `mnote-cli`
负责:
- 文档页 AI 会话编排
- tools / handoffs / tracing / guardrails / HITL
- 调用 OpenAI `Responses API`
- 组织 `mnote` 的文档页 AI 工具合同
- 外置 agent adapter 调度
- mnote page tools / tree tools 统一入口
- CLI host / Web AI host 之间的执行契约
不负责:
@@ -282,6 +288,22 @@ Rust kernel truth
- 绕过 Rust runtime 直接写产品数据
- 自己持有第二套页面真相
#### `openai-agents-python`
负责:
- 作为可插拔外置 agent adapter / 对照实现
- tools / handoffs / tracing / guardrails / HITL
- 调用 OpenAI `Responses API`
- 通过 `mnote-cli` 暴露的工具合同接入 `mnote`
不负责:
- 保存产品真相
- 绕过 Rust runtime 直接写产品数据
- 自己持有第二套页面真相
- 文档页 AI 长期默认主编排
#### Hermes
负责:
@@ -530,9 +552,9 @@ AI 第一批正式写能力只冻结为:
> **`Phase 7` 不删除过渡工具面,但也不把过渡工具名继续写成长期产品契约。**
### 8.3 `openai-agents-python` 的接入原则
### 8.3 外置 agent adapter 的接入原则
`openai-agents-python` 接入时,优先接的不是抽象理想工具名,而是
`openai-agents-python`、Hermes、Codex 作为外置 adapter 接入时,优先接的不是抽象理想工具名,而是 `mnote-cli` 暴露的统一工具契约
1. 当前页最小闭环所需的正式命令语义
2. 当前已真实存在的过渡运行时工具能力
@@ -574,7 +596,7 @@ AI 第一批正式写能力只冻结为:
- [x] 明确当前第一闭环只覆盖文档页 AI 主写链
- [x] 明确 `summary / ai_note / reference / index` 降为后续扩展
- [x] 明确 `Hermes` 只保留为 fallback / 对照链
- [x] 明确 `openai-agents-python` 为长期推荐编排层
- [x] 明确 `openai-agents-python` 仅作为过渡期可插拔外置 agent / adapter 示例
- [x] 明确页面 AI 模型配置真源是 `model_key`,不是 combo 名或 provider model
- [x] 明确 `profile` 前端可设、后端持有真源
- [x] 明确 tool registry 必须前端可见
@@ -645,11 +667,11 @@ AI 第一批正式写能力只冻结为:
---
## 阶段 3引入 `openai-agents-python` 文档页编排层
## 阶段 3整理并保留 `openai-agents-python` 过渡适配链
### 目标
在不推翻现有文档页 AI 回写链的前提下, `openai-agents-python` 替换 Hermes 作为长期文档页编排层。
在不推翻现有文档页 AI 回写链的前提下,保留 `openai-agents-python` 这条已跑通的过渡外置 adapter,用它作为 `mnote-cli`-first 迁移期间的对照与行为基线,而不是把它定义成长期默认文档页编排层。
### 需要完成
@@ -669,19 +691,20 @@ AI 第一批正式写能力只冻结为:
### 完成判定
- [x] 在不依赖 Hermes 主编排的情况下,文档页 AI 已能跑通第一闭环
- [x] 新编排层已具备“模型 / profile / 工具”统一能力面出口
- [x] 当前过渡 adapter 已具备“模型 / profile / 工具”统一能力面出口
---
## 阶段 4:切文档页 AI 默认路径
## 阶段 4:切文档页 AI 默认执行路径
### 目标
让文档页 AI 在产品可见行为上真正从 Hermes 过渡到新编排层
让文档页 AI 在产品可见行为上从 Hermes 兼容链过渡到 `mnote-cli` host / adapter;当前已跑通的 `openai-agents-python` 链只保留为外置 adapter 行为基线
### 需要完成
- [x] 文档页 AI panel 默认走 `openai-agents-python`
- [x] 历史基线中,文档页 AI panel 默认走 `openai-agents-python`
- [x] 长期口径中,文档页 AI panel 默认应走 `mnote-cli` host / adapter
- [x] 标题改名沿 `page.head.updateTitle` 回写
- [x] 正文改写沿 `page.body.save` 回写
- [x] 主编辑区 island 稳定回显 AI 结果
@@ -726,7 +749,7 @@ AI 第一批正式写能力只冻结为:
### 10.1 继续保留的价值
- 承接现有文档页 AI 运行链
- 作为 `openai-agents-python` 的回归对照
- 作为 `mnote-cli` host 与其他外置 adapter 的回归对照
- 作为 fallback 开关
- 承接非主链实验场景
@@ -741,8 +764,8 @@ AI 第一批正式写能力只冻结为:
最终可接受状态有两种:
1. Hermes 退化为非主链实验平台
2. Hermes 完全下线,只保留 `openai-agents-python + Rust runtime`
1. Hermes 退化为非主链实验平台 / 外置 agent adapter
2. Hermes 完全下线,只保留 `mnote-cli` + Rust runtime,并按需接入 `openai-agents-python` / Codex 等外置 agent adapter
---
@@ -766,11 +789,11 @@ AI 第一批正式写能力只冻结为:
当前冻结如下:
> **`Phase 7` 仍然以 `openai-agents-python` 作为长期推荐编排层,Rust runtime 作为唯一事实源与真执行面。**
> **本稿原始判断里,`openai-agents-python` 曾被写成长期推荐编排层;该口径现已失效。当前长期口径应以 `v4` 为准:`mnote-cli` 是唯一长期 agent 执行面Rust runtime 仍是唯一事实源与真执行面`openai-agents-python`、Hermes、Codex 都只是可插拔外置 agent。**
> **但当前 `Phase 7` 的第一交付物不再定义为“完整 AI 平台”或“完整结构化知识写链”,而是“文档页 AI 直接进入主编辑区,并沿 `page aggregate command family` 正式回写”。**
> **`Hermes` 可以继续作为过渡平台与实验平台存在,但不再作为文档页 AI 的长期语义中心。**
> **`Hermes` 可以继续作为过渡平台与实验平台存在,但不再作为文档页 AI 的长期语义中心。`openai-agents-python` 也只保留为外置 adapter。**
> **页面 AI 的模型真源固定为 `model_key``resolved_combo / resolved_runtime_model` 只作为运行时调试信息;`profile` 前端可设但由后端持有真源;tool registry 必须前端可见。**
@@ -0,0 +1,339 @@
# 7 [process] mnote Kernel Phase 7 AI 与 CLI 外置 Agent 边界实施方案 v3
> 更新时间:2026-05-05
>
> 上位依据:
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
> - `/mnt/Data1T/mnote/design/01-05-current-priority-overview.md`
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-tree-first-graph-kernel-v1.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/process/3-rust-web-long-term-architecture-v1.md`
> - `/mnt/Data1T/mnote/design/04-tree-domain/done/4-6-tree-command-protocol-cutover-stage2-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-1-phase7-document-ai-minimum-loop-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/process/7-phase7-ai-kernel-projection-plan-v2.md`
>
> 本稿与 `v2` 的关系:
> - `v2` 记录的是文档页 AI 最小闭环与 `openai-agents-python` sidecar 的主线收口
> - 本稿记录的是从“双中心并存”过渡到 `CLI-first` 之前的边界判断,重点保留当时为何要把页面内 AI 与外置 agent 拆层
> - 若未来继续演进,长期口径以 `v4` 为准;本稿不再作为当前长期判断依据
>
> 2026-05-05 追加说明:
> - 本稿已被 `/mnt/Data1T/mnote/design/07-ai/process/7-phase7-ai-kernel-projection-plan-v4.md` 覆盖
> - `v3` 只保留用于记录“双中心并存”的过渡判断
> - 当前长期口径不再采用本稿,而采用 `v4` 的 `CLI-first`
> - 当前统一口径是:`mnote-cli` 是唯一长期 agent 执行面,`openai-agents-python`、Hermes、Codex 都只是可插拔外置 agent
---
## 1. 文档目的
这份稿只回答一个问题:
> **`mnote` 的 AI 能力到底应该以“内置 agent”为中心,还是以“CLI 兼容外置 agent”为中心。**
当前长期结论已被 `v4` 修正为单一执行面:
1. Web 文档页 AI 面板继续保留,但只作为页面内交互壳 / CLI host
2. `mnote-cli` 是唯一长期 agent 执行面
3. Hermes、Codex、`openai-agents-python` 这类外置 agent 不再直接依赖产品内编排细节,而是统一通过 CLI / 稳定工具面进入系统
4. Rust kernel 继续作为唯一事实源与真执行面
一句话收口:
> **本稿原始判断是“不要退回成只有 CLI”;该口径现已被 `v4` 覆盖。当前长期口径是:CLI 作为唯一执行面,Web AI 只保留为页面内交互壳。**
---
## 2. 当前完成情况
### 2.1 文档页 AI 最小闭环已完成
`7-1` 已经完成,说明当前文档页 AI 至少已经跑通:
- 当前页 page aggregate 上下文读取
- `openai-agents-python` sidecar 编排
- 标题改名与正文写回
- `Hermes` fallback / 对照链
- `model_key / profile / tool registry` 的可见配置面
这意味着当前系统已经不是“要不要有 AI”,而是“AI 的长期边界该放在哪一层”。
### 2.2 `mnote-cli` 已经不是空壳
当前 Rust 侧已有 `mnote-cli`,并且已经覆盖:
- `page`
- `block`
- `mindmap`
- `search`
- `sidebar`
- `editor`
- `tool`
同时它已经有较清晰的执行参数面:
- `--json`
- `--execute`
- `--session-id`
- `--reason`
- `--idempotency-key`
- `--validate-only`
- `--dry-run`
这说明 CLI 已经具备成为“外置 agent 统一兼容层”的基础,而不是只做调试壳。
### 2.3 内置 AI 现在的定位已经足够清晰
当前 `wolai-backend/app/services/ai_document_agent.py` 这一层已经把文档页 AI 约束成:
- 只处理当前文档页
- 只使用有限工具面
- 通过 page aggregate 组织上下文
- 通过 `slash_run / doc_insert_blocks / doc_replace_range` 这类写链回写
所以内置 AI 的价值不是“全能 agent 平台”,而是“产品内即时编辑体验”。
---
## 3. 核心判断
### 3.1 `v3` 当时对 CLI-first 的顾虑
本节保留的是 `v3` 当时尚未接受 `CLI-first` 时的顾虑:
1. 担心产品内即时体验变差
2. 担心页面上下文、审核、回写被拆散
3. 担心外置 agent 变强但产品主链变弱
这些顾虑在 `v4` 中的处理方式不是退回“双中心”,而是明确:
- Web AI 面板继续保留
- 但它只作为 `mnote-cli` 的页面内 host / client
- 执行面不再由产品内 AI 单独持有
### 3.2 也不建议把内置 AI 变成唯一中心
相反,如果继续把内置 AI 当唯一中心,另一个问题会变得更严重:
- agent 更新能力受限
- 记忆层容易变成产品私有状态
- 能力面会偏向单一页面操作
- Hermes / CLI 这类外置 agent 很难稳定接入
所以正确做法不是“只保留内置 AI”,而是**把 `mnote-cli` 收口为唯一长期 agent 执行面**。
### 3.3 当前长期分层应理解为三层
1. **Web AI 面板 / 页面内交互壳**
- 负责文档页内交互、上下文读取、局部回写、审核辅助
2. **`mnote-cli`**
- 负责唯一长期 agent 执行面,以及外置 agent、脚本、批处理、离线任务、可观测执行
3. **Rust kernel**
- 负责所有事实源、命令、查询、投影、审计与回放
这三层之间不应该互相抢语义中心。
---
## 4. 架构边界
### 4.1 Rust kernel
负责:
- 页面、树、边、投影、查询、命令
- 结构化写入的最终事实源
- 审计、trace、回放、恢复
不负责:
- 直接承担 UI 体验
- 直接承担通用 agent 编排
### 4.2 Web AI 面板(产品内交互壳)
负责:
- 当前文档页的即时编辑
- 选中上下文的解释与改写
- 通过正式命令面回写
- 审核与继续编辑的体验闭环
不负责:
- 成为全局 agent 平台
- 取代 CLI 的批处理入口
- 持有独立长期记忆真源
- 成为第二个长期执行面
### 4.3 `mnote-cli`
负责:
- 作为唯一长期 agent 执行面与统一命令面
- 作为人类与脚本的可执行入口
- 作为 Hermes、Codex、批处理、定时任务的兼容层
应该提供:
- 稳定的 JSON 输出
- 明确的 plan / execute 分层
- 会话与 trace 参数
- 幂等键
- 校验模式与 dry-run
- 可发现的 capability manifest
### 4.4 Hermes / Codex / `openai-agents-python`
负责:
- 可插拔外置 agent 场景
- 过渡平台
- 回归对照
不负责:
- 成为产品内部独立长期主编排
- 直接绕过 Rust runtime 写业务数据
---
## 5. CLI 应该补什么
### 5.1 统一能力发现
CLI 需要先变成“可发现能力集合”,而不是一堆散命令。
最少要能回答:
- 当前可写什么
- 当前可读什么
- 当前哪些命令是计划态
- 当前哪些命令可直接执行
- 当前命令属于哪个 scope
### 5.2 统一执行元数据
外置 agent 真正缺的不是命令本身,而是执行元数据一致:
- `session_id`
- `actor_id`
- `actor_type`
- `reason`
- `idempotency_key`
- `validate_only`
- `dry_run`
- trace / audit id
这些都应该在 CLI 层成为一等参数。
### 5.3 统一记忆入口
这里的“记忆”不应该是产品壳里的隐式状态,而应该拆成三层:
1. 会话记忆
- 某次 agent 运行的上下文与结果
2. 配置记忆
- profile、工具注册、运行时偏好
3. kernel 记忆
- 真实业务对象、projection、历史变更
CLI 负责把这三层显式化,外置 agent 通过它读取或写入,不再自己猜。
### 5.4 统一机器可读输出
如果 Hermes、Codex、脚本都要接入,CLI 输出必须稳定机器可读。
最低要求:
- `--json` 必须完整
- 错误结构必须稳定
- 成功结构必须能直接喂给上层 agent
- 人类输出和机器输出要分开
---
## 6. Web AI 面板继续保留什么
### 6.1 继续保留
- 当前页正文改写
- 当前页标题改名
- 当前页上下文读取
- 页面内审核与继续编辑
- 与 page aggregate 对齐的最小闭环
### 6.2 不继续扩写
- 通用多 agent 平台壳
- 全局记忆产品壳
- 独立于页面主链的第二份真相
- 把 CLI 功能重复做一遍
### 6.3 设计原则
Web AI 面板只做“最近的一层”,不要做“全部层”。
因为页面内 AI 交互壳的目标是让用户快,不是让系统像一个独立平台那样完整。
---
## 7. 迁移策略
### 阶段 1:收口 CLI 兼容面
-`mnote-cli` 明确成唯一长期 agent 执行面
- 保持现有命令树不乱长
- 先统一 JSON / plan / execute / trace / idempotency
### 阶段 2:补稳定能力发现
- 输出 capability manifest
- 区分 read / write / job
- 区分 document / tree / workspace scope
### 阶段 3:外置 agent 接入
- Hermes 通过 CLI 进入系统
- 后续其他 agent 也通过同一 CLI 进入
- 不再为每个 agent 单独做一套产品内桥接逻辑
### 阶段 4:保留页面内 AI host
- 文档页 AI 继续保留当前页面内主路径
- 只做 UI 内最小闭环
- 不回退到全局壳
- 不再把页面内 host 叙述成独立长期执行面
---
## 8. 非目标
本稿不做:
- 重新实现一个新的通用 AI 平台
- 把 Hermes 直接升级成产品内主编排中心
- 把内置 AI 删除掉
- 把所有页面内交互体验都删除并强制改成手工 CLI 操作
- 在 CLI 里重复一套产品 UI
---
## 9. 完成判定
当下面几项成立时,才算这个方向真正站稳:
- `mnote-cli` 是唯一长期 agent 执行面,而不是纯调试壳
- Web AI 面板只负责页面内最小闭环
- `openai-agents-python`、Hermes、Codex 等外置 agent 通过 CLI 进入系统
- Rust kernel 仍然是唯一事实源
- `model_key / profile / tool registry` 这些产品语义不被页面内 host 私有化
一句话收口:
> **本稿保留的是“产品内 AI + CLI 兼容层”并存的过渡判断;当前长期口径已经改为:`mnote-cli` 是唯一执行面,Web AI 只是页面内交互壳,Rust kernel 继续负责真相。**
@@ -0,0 +1,698 @@
# 7 [process] mnote Kernel Phase 7 CLI-First 外置 Agent 统一执行面方案 v4
> 更新时间:2026-05-05
>
> 上位依据:
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
> - `/mnt/Data1T/mnote/design/01-05-current-priority-overview.md`
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-tree-first-graph-kernel-v1.md`
> - `/mnt/Data1T/mnote/design/03-rust-web/process/3-rust-web-long-term-architecture-v1.md`
> - `/mnt/Data1T/mnote/design/04-tree-domain/done/4-6-tree-command-protocol-cutover-stage2-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-5-page-aggregate-single-truth-alignment-v1.md`
> - `/mnt/Data1T/mnote/design/05-editor-mainline/process/5-6-page-aggregate-alignment-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/done/7-1-phase7-document-ai-minimum-loop-checklist-v1.md`
> - `/mnt/Data1T/mnote/design/07-ai/process/7-phase7-ai-kernel-projection-plan-v2.md`
> - `/mnt/Data1T/mnote/design/07-ai/process/7-phase7-ai-kernel-projection-plan-v3.md`
>
> 本稿与前稿的关系:
> - `v2` 的价值仍然成立:它记录了文档页 AI 最小闭环已经真实完成
> - `v3` 把 CLI 抬到了重要位置,但仍保留了“产品内 AI 主链”和“CLI 外置层”双中心
> - 本稿进一步收口,明确长期只保留一个执行方向:`CLI-first`
>
> 当前判断修正:
> - 文档页 AI 面板不再被视为独立 AI 编排主线
> - `openai-agents-python` 不再被视为长期默认主编排,而是一个可插拔外置 agent
> - Hermes、Codex、后续其他 agent,应统一通过 `mnote-cli` 接入
---
## 1. 文档目的
这份稿只回答一个问题:
> **`mnote` 的长期 AI 执行面,到底要不要收口成一个唯一方向。**
当前答案是:
> **要。长期只保留一个 AI 执行方向:`Rust kernel + mnote-cli`。**
这里的关键不是“要不要有 AI UI”,而是:
- UI 可以存在
- 外置 agent 可以很多
- 但执行面只能有一个
一句话收口:
> **`mnote` 的长期主线不是“内置 AI + CLI 两套长期并存”,而是“CLI 作为唯一 agent 执行面,Web 面板只是其中一个客户端”。**
---
## 2. 为什么要改成 CLI-first
当前如果继续保留两套长期方向:
1. 产品内一套 AI 编排
2. 外置 agent 一套 CLI / 脚本 / Hermes / Codex 编排
那么后面一定会出现这些重复维护成本:
- 两套工具注册表
- 两套上下文装配逻辑
- 两套 session / trace / audit 语义
- 两套能力开关和权限边界
- 两套“哪些命令是真执行、哪些只是兼容层”的判断
这不是“体验和平台分层”,而是“长期双轨维护”。
如果改成 CLI-first
- Web AI 面板调用 CLI
- Hermes 调用 CLI
- Codex 调用 CLI
- 批处理脚本调用 CLI
- 定时任务调用 CLI
那么系统只维护:
1. 一个真执行方向:`mnote-cli`
2. 多个调用方:UI / agent / script / job
这才是真正减少长期维护成本。
---
## 3. 当前完成情况如何解释
### 3.1 `7-1` 已完成,但不代表它必须成为长期方向
当前文档页 AI 最小闭环已经完成,这个事实不变:
- page aggregate 上下文读取
- 标题改名与正文改写
- `openai-agents-python` sidecar
- `Hermes` fallback / 对照链
但这个完成状态只能说明:
> **我们已经验证过一条可工作的过渡主链。**
不能自动推出:
> **这条链就应该变成长期唯一主线。**
所以 `v2` 记录的工作不是白做,而是:
- 它证明了产品内写链需求真实存在
- 它帮助我们冻结了最小工具面和页面语义面
- 它可以作为 CLI-first 迁移时的行为基线
### 3.2 `mnote-cli` 已经足够接近长期入口
当前 `mnote-cli` 已经不是空壳,已有:
- `page`
- `block`
- `mindmap`
- `search`
- `sidebar`
- `editor`
- `tool`
同时还有这些关键参数:
- `--json`
- `--execute`
- `--session-id`
- `--reason`
- `--idempotency-key`
- `--validate-only`
- `--dry-run`
这说明真正应该继续投入的,不是再扩一条新的 Web 内 AI 主编排,而是把 CLI 补成稳定统一入口。
---
## 4. 新的长期架构边界
### 4.1 Rust kernel / Rust runtime
负责:
- 唯一事实源
- query / command / projection
- page / tree / graph / artifact 的正式语义
- 审计、回放、恢复、trace 基线
不负责:
- 直接承担 agent 编排
- 直接承担产品聊天壳
### 4.2 `mnote-cli`
负责:
- 唯一长期 agent 执行入口
- 人类、脚本、外置 agent、Web 面板的统一命令面
- 统一能力发现、统一参数面、统一输出结构
必须成为:
- CLI for humans
- CLI for agents
- CLI for jobs
- CLI for UI host
### 4.3 Web AI 面板
负责:
- 当前页面里的交互壳
- 流式展示
- 输入与审核
- 把页面上下文转成 CLI 可消费的标准输入
- 接收 CLI 事件并映射到 UI
不负责:
- 自己维护独立 agent 编排层
- 自己维护独立工具注册表
- 自己定义长期 AI 契约
### 4.4 外置 agent
包括但不限于:
- Hermes
- Codex
- `openai-agents-python`
- 后续任何别的 agent runtime
它们都负责:
- 决策
- 推理
- 工具调用策略
- 会话层 orchestration
但它们不应再直接拥有产品内部执行面。它们都应该统一调用 `mnote-cli`
---
## 5. `openai-agents-python` 的新定位
### 5.1 不再是默认主线
从本稿开始,`openai-agents-python` 不再被定义为:
- `mnote` 的长期默认主编排
- 产品内文档页 AI 的唯一推荐底座
### 5.2 改为可插拔外置 agent
它的新定位是:
> **一个可插拔外置 agent runtime。**
也就是说,它和 Hermes、Codex 的区别不再是“谁是产品内主线”,而只是:
- 不同的 agent 实现
- 不同的模型接法
- 不同的 orchestration 风格
是否继续保留它,取决于后续真实效果,而不是当前历史惯性。
### 5.3 可接受的长期状态
未来允许的状态有三种:
1. `openai-agents-python` 继续保留,作为可选外置 agent
2. `openai-agents-python` 仅保留在测试 / 回归 / 对照场景
3. `openai-agents-python` 完全移除
这三种都不影响长期主架构,只要唯一执行面还是 `mnote-cli`
---
## 6. CLI-first 下的产品口径
### 6.1 UI 仍然可以有 AI 面板
CLI-first 不等于没有产品内 AI UI。
允许继续有:
- 文档页 AI 面板
- mindmap AI 面板
- OnlyOffice AI 面板
但这些都只是:
> **CLI 的图形客户端。**
### 6.2 页面语义仍然保留
虽然主执行面转到 CLI,但下面这些产品语义仍要保留:
- `model_key`
- `profile`
- `tool registry`
- `page aggregate`
- `page.head.updateTitle`
- `page.body.save`
- `tree.*`
区别只在于:
- 这些不再由 Web 内独立 AI service 主导
- 而是由 CLI 和 Rust runtime 共同定义
### 6.3 Web 不应再拥有第二套工具面
当前过渡工具面:
- `doc_get`
- `doc_find`
- `doc_insert_blocks`
- `doc_replace_range`
- `slash_run`
如果继续保留,后续也应通过 CLI 暴露,而不是继续作为 Web 内 service 的私有 tool surface。
---
## 7. CLI 必须补齐的能力
CLI-first 成立的前提,不是“已有命令很多”,而是这些能力必须补齐。
### 7.1 能力发现
至少要能稳定输出:
- 当前有哪些 command / query / job
- 每个能力属于哪个 scope
- 哪些可读,哪些可写
- 哪些是 plan-only
- 哪些是真执行
建议提供:
- `mnote-cli capabilities --json`
### 7.2 标准上下文输入
CLI 需要能接住标准化页面上下文,而不是让每个 agent 自己拼:
- `documentId`
- `blocks`
- `pageOptions`
- `editorRuntimePageOptions`
- `subtree`
- `outline`
- `evidence`
也就是说,页面上下文装配逻辑要从 Web 内 agent service 迁到 CLI 兼容输入协议。
### 7.3 标准事件输出
如果 Web 面板要流式显示,CLI 需要输出标准事件流,例如:
- `assistant_message`
- `tool_call`
- `tool_result`
- `completion`
- `error`
否则 UI 最后还是会倒逼出第二套 Web 内编排逻辑。
### 7.4 标准 session / trace / audit
CLI 必须把这些变成一等能力:
- `session_id`
- `trace_id`
- `request_id`
- `actor_id`
- `actor_type`
- `reason`
- `idempotency_key`
### 7.5 权限与 scope
CLI 要能明确限制:
- 当前只能改当前页
- 当前允许跨页还是不允许
- 当前允许树命令还是只允许页面命令
- 当前是只读、写入还是后台 job
---
## 8. 顺序执行 checklist
本节是后续实施时的主 checklist。执行时从上到下推进,完成一项后把对应 `- [ ]` 改成 `- [x]`,并在该项下补充实际命令输出摘要或截图路径。
### 8.1 冻结 CLI 基座
- [x] 确认 `mnote-cli` 顶层命令存在。
- 命令:
```bash
cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --help
```
- 通过标准:输出包含 `page`、`block`、`mindmap`、`search`、`sidebar`、`editor`、`tool`。
- [x] 确认 agent 必需的全局参数存在。
- 命令:
```bash
cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --help
```
- 通过标准:输出包含 `--json`、`--execute`、`--session-id`、`--reason`、`--idempotency-key`、`--validate-only`、`--dry-run`。
- [x] 确认 `mnote-cli` 当前单测全通过。
- 命令:
```bash
cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli
```
- 通过标准:所有 `mnote-cli` 测试通过;当前基线应覆盖 CLI JSON contract、tool registry、page/save/sidebar 等最小面。
### 8.2 冻结页面命令面
- [x] 验证页面读取命令。
- 命令:
```bash
cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json page get --page-id page_demo --workspace-id ws_demo
```
- 通过标准:输出包含 `domain: page`、`action: get`、`context.requestId`、`context.traceId`,并且 `operation.transport.functionName` 指向页面查询。
- [x] 验证页面标题更新命令。
- 命令:
```bash
cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json page title --page-id page_demo --workspace-id ws_demo --title "新标题"
```
- 通过标准:输出包含 `domain: page`、`action: title`、`operation.kind: command`,并且写入仍通过 Rust runtime / transport 计划表达。
- [x] 验证页面正文保存命令。
- 命令:
```bash
cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json page save --page-id page_demo --workspace-id ws_demo --content-json '[{"id":"block_1"}]'
```
- 通过标准:输出包含 `domain: page`、`action: save`、`operation.kind: command`,并且能看到正文写回 payload。
### 8.3 冻结块命令面
- [x] 验证块插入命令。
- 命令:
```bash
cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json block insert --page-id page_demo --workspace-id ws_demo --block-type paragraph --content "hello"
```
- 通过标准:输出包含 `domain: block`、`action: insert`、`operation.kind: command`、`operation.name: insert_block`。
- [x] 验证块 patch 命令。
- 命令:
```bash
cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json block patch --page-id page_demo --workspace-id ws_demo --block-id block_demo --snapshot-json '{"id":"block_demo","type":"paragraph","text":"updated"}'
```
- 通过标准:输出包含 `domain: block`、`action: patch`、`operation.kind: command`、`operation.name: blocks.patch`。
- [x] 第 1 步:固定块写链仍然存在的入口证据。
- 结果:`/api/ai-agent/run` 已不再直接恢复 `slash_run` / `doc_insert_blocks` / `doc_replace_range``DocumentAiAgentPanel.runtime.tsx` 也已不再声明 Web 内独立 agent owner。
- 验证命令:
```bash
rg -n "doc_insert_blocks|doc_replace_range|slash_run|startHermesRun|startDocumentAiOrchestratorRun|runCodexBridge" \
/mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.ts \
/mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx
```
- [x] 第 2 步:把块写链收口为 `mnote-cli` host / adapter。
- 结果:`/api/ai-agent/run` 已收口为薄 host route,块写链不再由 Web 私有 service 直接拥有。
- 依赖检查:`DocumentAiAgentPanel.runtime.tsx` 与 `/api/ai-agent/run/route.ts` 的 contract 说明已同步改成 `mnote-cli`。
- [x] 第 3 步:补块写链回归测试。
- 结果:`pnpm vitest run src/components/editor/DocumentAiAgentPanel.runtime.test.tsx` 与 `pnpm vitest run src/app/api/ai-agent/run/route.test.ts` 通过。
- 验证命令:
```bash
pnpm vitest run /mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.test.tsx
pnpm vitest run /mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.test.ts
```
- 通过标准:测试明确约束块写链不再暴露 Web 私有 tool surface,并且 route 只保留 CLI host / adapter 语义。
### 8.4 冻结搜索与侧栏投影
- [x] 验证文档搜索命令。
- 命令:
```bash
cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json search documents --workspace-id ws_demo --query "Hermes"
```
- 通过标准:输出包含 `domain: search`、`action: documents`,并且查询计划可由 Web host 消费。
- [x] 验证块搜索命令。
- 命令:
```bash
cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json search blocks --page-id page_demo --query "Hermes"
```
- 通过标准:输出包含 `domain: search`、`action: blocks`、`operation.name: search_blocks`。
- [x] 验证侧栏数据集命令。
- 命令:
```bash
cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json sidebar dataset --workspace-id ws_demo
```
- 通过标准:输出包含 `domain: sidebar`、`action: dataset`、`operation.name: sidebar.dataset.list`。
### 8.5 冻结 tool runtime 与安全模式
- [x] 验证 `tool run` 的只读 explain-plan。
- 命令:
```bash
cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --json --validate-only --dry-run --session-id ai-checklist-smoke --reason phase7-cli-first --idempotency-key phase7-cli-first-001 tool run --tool-name doc_get --kind query --mode explain-plan --args-json '{"pageId":"page_demo"}'
```
- 通过标准:输出包含 `domain: tool`、`action: run`、`context.sessionId: ai-checklist-smoke`、`context.idempotencyKey: phase7-cli-first-001`、`context.validateOnly: true`、`context.dryRun: true`。
- [x] 验证 tool registry 会拒绝未知工具。
- 命令:
```bash
cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli tool_run_rejects_unknown_tool
```
- 通过标准:测试通过,未知 tool 不会绕过 registry 进入执行链。
- [x] 确认 `--reason` 进入后续 audit / trace 输出规划。
- 当前状态:CLI 参数面已接住 `--reason`,并已在标准 JSON 输出的 `context.reason` 中展开。
- 通过标准:`cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli output_context_keeps_reason_for_audit_trace` 通过,断言 `reason` 出现在标准 audit / trace 输出上下文里。
### 8.6 将 Web AI 面板降为 CLI host
- [x] 检查 Rust Web checklist 的 Phase 5 口径。
- 文件:`/mnt/Data1T/mnote/design/03-rust-web/process/3-1-rust-web-long-term-checklist-v2.md`
- 通过标准:AI 面板只能写成 `mnote-cli` host/client 收口,不得写成 Hermes 或 `openai-agents-python` 长期主编排。
- 已核对:该文件明确写入“长期执行面应收口到 `mnote-cli`Web 只作为 CLI host / client`openai-agents-python` / Hermes / Codex 只作为可插拔外置 agent”。
- [x] 检查 legacy Next retirement gate 的 AI route 口径。
- 文件:`/mnt/Data1T/mnote/design/03-rust-web/process/3-11-rust-web-legacy-next-retirement-gates-v1.md`
- 通过标准:`/api/ai-agent/run` 只能写成 CLI host / adapter 兼容层,结构化写入必须经 Rust runtime。
- 已核对:该文件明确写入 `/api/ai-agent/run` 长期应降为 `mnote-cli` host / adapter,结构化写入必须经 Rust runtime,外置 agent 不得拥有第二执行面。
- [x] 检查 Wolai-aline E27 的 AI 编辑口径。
- 文件:`/mnt/Data1T/mnote/design/05-editor-mainline/process/5-9-wolai-aline-continuous-checklist-v1.md`
- 通过标准:E27 只能把 `openai-agents-python` sidecar / Hermes fallback 当作过渡基线,不得写成长期主线。
- 已核对:E27 明确写入 `/api/ai-agent/run` 后续应收口为 `mnote-cli` 唯一长期 agent 执行面上的 host / adapter`Hermes`、`Codex`、`openai-agents-python` 仅为可插拔外置 agent;当前 sidecar / fallback 只保留为过渡行为基线。
### 8.7 外置 agent 接入顺序
- [x] 第 1 步:冻结 Codex 接入方式。
- 结果:`/api/ai-agent/run` 已不再按 `provider=codex` 直入独立 bridge,统一走 `mnote-cli` host。
- 验证命令:
```bash
rg -n "provider === \"codex\"|runCodexBridge" /mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.ts
```
- [x] 第 2 步:冻结 Hermes 接入方式。
- 结果:`/api/ai-agent/run` 已不再直接调用 `startHermesRun` / `streamHermesRunEvents`,Hermes 不再是长期主链入口。
- 验证命令:
```bash
rg -n "startHermesRun|streamHermesRunEvents|/api/hermes/bridge" /mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.ts
```
- [x] 第 3 步:冻结 `openai-agents-python` 接入方式。
- 结果:`DocumentAiAgentPanel.runtime.tsx` 已不再声明 `bridgeOwner: "openai-agents-python"``provider=online` 也不再直连 orchestrator。
- 验证命令:
```bash
rg -n "bridgeOwner: \"openai-agents-python\"|startDocumentAiOrchestratorRun|/api/v1/ai-agent/document/run" /mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx /mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.ts
```
- [x] 第 4 步:统一复核外置 agent 只剩 CLI host / adapter 口径。
- 结果:已通过全局复核,`/api/ai-agent/run` 与面板 contract 都只保留 `mnote-cli` host / adapter 口径。
- 验证命令:
```bash
rg -n "provider === \"codex\"|runCodexBridge|startHermesRun|streamHermesRunEvents|bridgeOwner: \"openai-agents-python\"|startDocumentAiOrchestratorRun|/api/v1/ai-agent/document/run" \
/mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.ts \
/mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx
```
### 8.8 完成判定
- [x] `mnote-cli` 的最小命令面在仓库内可复跑。
- 已验证:`cargo run --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli -- --help` 与 `cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli` 可复跑。
- [x] `--json`、`--execute`、`--validate-only`、`--dry-run` 的输出语义稳定。
- 已验证:`--help` 暴露这些全局参数;`tool run --validate-only --dry-run --json` 输出包含 `context.validateOnly: true`、`context.dryRun: true`、`context.reason`、`context.sessionId` 与 `context.idempotencyKey`。
- [x] `page / block / search / sidebar / tool` 都能用 CLI 直接验证。
- 已验证:8.2 到 8.5 已分别覆盖 `page get/title/save`、`block insert/patch`、`search documents/blocks`、`sidebar dataset`、`tool run`。
- [x] 第 1 步:确认 Web AI 面板的 contract 已收口为 `mnote-cli` host / client。
- 结果:面板 contract 已改为 `bridgeOwner: "mnote-cli"``runtimeRole: "mnote_cli_host_client"`。
- 验证命令:
```bash
rg -n "bridgeOwner: \"openai-agents-python\"|startDocumentAiOrchestratorRun|startHermesRun|runCodexBridge" /mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx /mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.ts
```
- [x] 第 2 步:确认三类外置 agent 都只作为可插拔 runtime。
- 结果:`route.ts` 已收口为统一 host route,不再按 provider 分叉到三套执行实现。
- 验证命令:
```bash
rg -n "provider === \"codex\"|runCodexBridge|startHermesRun|startDocumentAiOrchestratorRun|bridgeOwner: \"openai-agents-python\"" /mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.ts /mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.tsx
```
- [x] 第 3 步:补完成判定的最终回归。
- 结果:`cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli`、`pnpm vitest run src/components/editor/DocumentAiAgentPanel.runtime.test.tsx`、`pnpm vitest run src/app/api/ai-agent/run/route.test.ts` 均通过。
- 验证命令:
```bash
cargo test --manifest-path /mnt/Data1T/mnote/rust/Cargo.toml -p mnote-cli
pnpm vitest run /mnt/Data1T/mnote/wolai-frontend/src/components/editor/DocumentAiAgentPanel.runtime.test.tsx
pnpm vitest run /mnt/Data1T/mnote/wolai-frontend/src/app/api/ai-agent/run/route.test.ts
```
- [x] 结构化写入仍然只能回到 Rust runtime / Rust kernel。
- 已核对:本稿 4.1、6.2、6.3 明确 Rust kernel / Rust runtime 负责事实源、query / command / projection 与结构化写入语义;`3-11` 与 Wolai-aline E27 均要求结构化写入经 Rust runtime 或 Rust tool / `page.body.save`。
### 8.9 当前测试账号写入验收
- [x] 确认当前测试账号默认允许 CLI 新建与编辑页面。
- 命令:
```bash
cd /mnt/Data1T/mnote/wolai-frontend && pnpm vitest run src/lib/server/mnote-cli-agent-host.test.ts
```
- 通过标准:`mnote-cli` host 默认下发 `MNOTE_CLI_ALLOW_CREATE_PAGE=1` 与 `MNOTE_CLI_ALLOW_EDIT=1`,并把当前 Web 用户身份透传给 CLI 子进程。
- [x] 确认当前测试账号的真实 workspace。
- 当前测试账号:
- `userId`: `a4b72c17-49e3-46d3-8456-24a0a7044d64`
- `email`: `dev@mnote.local`
- `name`: `开发用户`
- 当前真实 workspace
- `workspaceId`: `ws_req_1778035004501_15`
- `workspaceName`: `开发用户 的空间`
- 首个页面:`tree_1778036320856_1` / `新页面`
- 通过标准:`/api/sidebar?workspaceId=ws_req_1778035004501_15` 返回的 `documents` 至少包含 `tree_1778036320856_1`。
- [x] 确认旧的 CLI 直连 Convex identity 不能作为长期用户写入面。
- 事实:曾经写入 `tree_1777430834634_3` / `anonymous 的空间` 的页面不会出现在当前测试账号的 `ws_req_1778035004501_15`。
- 结论:CLI 不能长期依赖伪造 `DEV_USER_ID` 直连 Convex 来代表用户写入;需要由 Web host / mnote-web 持有当前会话、当前 workspace 与 capability 后再执行写入。
- [x] 确认 CLI host 会把当前页面 workspaceId 传入 CLI 输入。
- 命令:
```bash
cd /mnt/Data1T/mnote/wolai-frontend && pnpm vitest run src/lib/server/mnote-cli-agent-host.test.ts
```
- 通过标准:`--args-json` 包含 `workspaceId: "ws_req_1778035004501_15"`,避免 agent 在缺省 workspace 或错误 workspace 下创建页面。
- [x] 用当前浏览器会话创建当前账号可见页面。
- 执行动作:在已登录测试账号的浏览器会话中调用 `/api/tree/commands` 创建:
- `CLI 可见测试 A 1778057564`
- `CLI 可见测试 B 1778057564`
- 通过标准:创建响应的 `result.workspaceId` 必须是 `ws_req_1778035004501_15`。
- 当前验证结果:
- `tree_1778048047020_3` / `CLI 可见测试 A 1778057564`
- `tree_1778048047047_4` / `CLI 可见测试 B 1778057564`
- [x] 用当前浏览器会话读取 sidebar 确认可见。
- 命令等价动作:
```js
await fetch('/api/sidebar?workspaceId=ws_req_1778035004501_15', { credentials: 'include' })
```
- 通过标准:返回的 `documents`、`kernelSidebarProjection.items` 与 `kernelSidebarTree` 都包含 `CLI 可见测试 A 1778057564` 与 `CLI 可见测试 B 1778057564`。
- 当前验证结果:已在浏览器会话 API 返回中看到上述两个页面;同一返回还显示早先创建的 `cli_visible_ws_req_a_17780471` 与 `cli_visible_ws_req_b_17780471`。
- [ ] 后续权限收口:补“禁止/允许 CLI 编辑、允许 CLI 新建页面”的 capability 开关。
- 目标:默认测试账号允许 CLI 新建与编辑;后续真实用户可在设置中关闭关键页面的 CLI 编辑或新建权限。
- 通过标准:CLI 写操作必须能读到当前用户、当前 workspace、当前页面 capability;未授权时返回明确拒绝,不得 fallback 到 anonymous / dev identity 写入。
- [x] 确认 Web host 会把当前会话用户透传给 `mnote-cli` 作为默认执行身份。
- 命令:
```bash
cd /mnt/Data1T/mnote/wolai-frontend && pnpm vitest run src/lib/server/mnote-cli-agent-host.test.ts src/app/api/ai-agent/run/route.test.ts
```
- 通过标准:`spawn("cargo", ...)` 的环境变量包含 `DEV_USER_ID`、`DEV_USER_EMAIL`、`DEV_USER_NAME`,并默认下发 `MNOTE_CLI_ALLOW_CREATE_PAGE=1` 与 `MNOTE_CLI_ALLOW_EDIT=1`。
---
## 9. 迁移策略
### 阶段 0:口径冻结
先冻结新的长期判断:
- CLI 是唯一长期执行面
- Web 面板只是 CLI 客户端
- `openai-agents-python` 是可插拔外置 agent
- Hermes / Codex / 后续 agent 都统一走 CLI
### 阶段 1CLI 能力补齐
优先补:
- capability manifest
- 标准 JSON 输出
- 事件流输出
- 标准上下文输入
- 标准 trace / session 参数
### 阶段 2Web 面板降为 CLI host
把当前文档页 AI 面板从:
- “调用内置 sidecar 主编排”
改成:
- “调用 CLI host / CLI adapter”
### 阶段 3:外置 agent 接入统一化
统一支持:
- Hermes -> `mnote-cli`
- Codex -> `mnote-cli`
- `openai-agents-python` -> `mnote-cli`
### 阶段 4:裁剪过渡层
当 CLI-first 成熟后,逐步评估:
- 是否保留 `openai-agents-python`
- 是否保留当前 Web 内 sidecar
- 是否完全移除旧过渡桥接
---
## 10. 非目标
本稿不做:
- 再造一套新的 agent 平台
- 让 Web 直接失去 AI UI
- 把所有 UX 都退回终端
- 让 Hermes 或 `openai-agents-python` 重新变成产品内部唯一中心
---
## 11. 完成判定
满足下面几项时,才算 CLI-first 真正成立:
- `mnote-cli` 是唯一长期 agent 执行入口
- Web AI 面板只是 CLI host,不再持有独立主编排
- Hermes / Codex / `openai-agents-python` 都通过 CLI 接入
- Rust kernel 仍然是唯一事实源
- 是否保留 `openai-agents-python` 不影响整体架构
一句话收口:
> **`mnote` 的长期 AI 方向应当收口成“Rust kernel 负责真相,`mnote-cli` 负责唯一执行面,外置 agent 全部可插拔,Web 只做交互壳”。**