收口 MNote P0 P1 P2 审查尾项
- 归档 OnlyOffice live bridge、Page AI、mindmap、design governance 与相关 bug 条目 - 补齐 MinerU OCR 后端 runtime 合同与 smoke/test 基线 - 收口 ChatOnly/Doubao、ObjectIdentity、Page Aggregate compat 与 runtime owner 文档口径 验证: - cargo test --manifest-path rust/Cargo.toml -p mnote-web local_ocr -- --test-threads=1 - cargo test --manifest-path rust/Cargo.toml -p mnote-web onlyoffice_bridge -- --test-threads=1 - git diff --check - git diff --cached --check - codegraph index . --force && codegraph status . - codegraph sync . && codegraph status .
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
>
|
||||
> 上位依据:
|
||||
> - `/mnt/Data1T/mnote/ARCHITECTURE.md`
|
||||
> - `/mnt/Data1T/mnote/design/01-05-current-priority-overview.md`
|
||||
> - `/mnt/Data1T/mnote/CURRENT_ARCHITECTURE.md`
|
||||
> - `/mnt/Data1T/mnote/design/01-tree-first-graph-kernel/process/1-8-mvp-post-process-execution-order-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/05-editor-mainline/done/5-6-page-aggregate-alignment-checklist-v1.md`
|
||||
> - `/mnt/Data1T/mnote/design/07-ai/done/7-15-page-ai-acp-agent-runtime-unified-layer-v1.md`
|
||||
@@ -276,10 +276,10 @@ Rust SQLite control-plane 是默认控制面,负责:
|
||||
|
||||
### Phase A0:target selection 与 UI
|
||||
|
||||
- [ ] Page AI composer 可见 target chip,显示 workspace、target title、resourceKind、scope、readonly / dirty 状态。
|
||||
- [ ] 点击 target chip 打开 target picker,可在当前焦点、打开 tabs、树选中项之间选择。
|
||||
- [ ] 默认 target 来自 last focused editor / resource tab,不来自第一个 tab、URL documentId 或树选中项。
|
||||
- [ ] mindmap / office / raw file target 显示真实 resourceKind,不伪装成 markdown page。
|
||||
- [x] Page AI composer 可见 target chip,显示 workspace、target title、resourceKind、scope、readonly / dirty 状态。
|
||||
- [x] 点击 target chip 打开 target picker,可在当前焦点、打开 tabs、树选中项之间选择。
|
||||
- [x] 默认 target 来自 last focused editor / resource tab,不来自第一个 tab、URL documentId 或树选中项。
|
||||
- [x] mindmap / office / raw file target 显示真实 resourceKind,不伪装成 markdown page。
|
||||
- [ ] 多 tab / 跨 workspace / dirty write 时发送前需要显式确认。
|
||||
- [ ] 发送后消息记录冻结 target 摘要,切换 tab 不影响已启动 run。
|
||||
|
||||
@@ -291,6 +291,8 @@ Rust SQLite control-plane 是默认控制面,负责:
|
||||
- [ ] allowed roots 外文件写入被 agent runtime 或 MNote 审计层拒绝。
|
||||
- [ ] readonly 页面不会启动可写 run,或只启动只读问答 run。
|
||||
|
||||
2026-06-01 进展:已补第一版 `mnote.agent_target_package.v1` 运行时输入。前端 Page AI run body 会从当前 `editorTarget` / `WorkspacePath` 生成 `targetPackage`;后端会 sanitize 该包,并把 local-first `aiAccessScope.allowedFiles` / `allowedFilePaths` 与 `agentRunEnvelope.allowedFiles` 从该包派生。`task502-page-ai-agent-selector-context-smoke.js` 已覆盖 page / mindmap / OnlyOffice target picker 与 payload 冻结;`task520-page-ai-raw-resource-target-smoke.js` 已覆盖真实 raw local resource tab,并断言 `objectIdentity` 不退化为 `[object Object]`。当前仍未完成跨 workspace 多选确认和真实 agent 写入回收 smoke,因此本文继续保持 `process`。
|
||||
|
||||
### Phase B:写入回收与前台同步
|
||||
|
||||
- [ ] agent 修改当前 `.md` 后,MNote 能回收 changed files / diff。
|
||||
|
||||
@@ -1,146 +0,0 @@
|
||||
# Reasonix Browser Test Contract v1
|
||||
|
||||
## 状态
|
||||
|
||||
- 状态:process
|
||||
- Owner:AI runtime / browser verification
|
||||
- 背景:Reasonix 已能作为独立辅助 agent 执行只读审计,但浏览器验收若只输出自然语言结论,主控仍需重测,无法稳定节省 token。
|
||||
|
||||
## 目标
|
||||
|
||||
把 Reasonix 浏览器测试从“描述性结论”收口为“可审计证据包”。Codex/Hermes 主控只接受带截图、日志、网络、断言和环境前置条件的 Reasonix 浏览器结论。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不让 Reasonix 直接裁决业务 bug 是否完成。
|
||||
- 不让 Reasonix 修改源码、提交 git、回滚文件。
|
||||
- 不把浏览器测试结论写成长期产品事实源;长期事实仍以 bug/design/checklist 和真实验证日志为准。
|
||||
|
||||
## 合同
|
||||
|
||||
每个 Reasonix 浏览器测试任务必须产出以下文件:
|
||||
|
||||
```text
|
||||
result.json
|
||||
final.md
|
||||
process-handoff.md
|
||||
process-handoff.json
|
||||
artifacts/
|
||||
screenshots/
|
||||
console.json
|
||||
network.json
|
||||
trace-or-steps.md
|
||||
```
|
||||
|
||||
`result.json` 至少包含:
|
||||
|
||||
```json
|
||||
{
|
||||
"status": "passed | failed | blocked",
|
||||
"run_id": "reasonix-...",
|
||||
"target_url": "http://127.0.0.1:3000",
|
||||
"environment": {
|
||||
"dev_server_restarted": true,
|
||||
"cache_cleared": true,
|
||||
"browser_context": "isolated",
|
||||
"auth_mode": "test-account",
|
||||
"workspace_root": "/tmp/..."
|
||||
},
|
||||
"steps": [
|
||||
{
|
||||
"name": "upload first attachment",
|
||||
"action": "drag file into editor",
|
||||
"screenshot": "artifacts/screenshots/01-upload-first.png"
|
||||
}
|
||||
],
|
||||
"assertions": [
|
||||
{
|
||||
"name": "attachment opens in tab after second upload",
|
||||
"expected": "tab count increases and active tab kind is resource",
|
||||
"actual": "click produced no tab change",
|
||||
"passed": false,
|
||||
"evidence": "artifacts/screenshots/04-click-after-second-upload.png"
|
||||
}
|
||||
],
|
||||
"console_errors": [],
|
||||
"network_failures": [],
|
||||
"screenshots": [],
|
||||
"modified_files": []
|
||||
}
|
||||
```
|
||||
|
||||
## 浏览器前置条件
|
||||
|
||||
- 测试前重启 `npm run dev:hot` 或复用主控明确提供的已重启服务。
|
||||
- 使用全新 isolated browser context;清空 cookies、localStorage、sessionStorage、IndexedDB、Cache Storage。
|
||||
- 默认使用 `http://127.0.0.1:3000/auth` 的测试账号快速登录。
|
||||
- local-first 测试必须创建临时页面或临时 workspace,并记录路径。
|
||||
- 所有上传文件路径必须记录,不能只写“上传文件”。
|
||||
|
||||
## 截图要求
|
||||
|
||||
用户可见 bug 至少保留:
|
||||
|
||||
- 初始状态截图。
|
||||
- 关键动作后截图。
|
||||
- 失败状态截图。
|
||||
- 修复验证时的通过状态截图。
|
||||
|
||||
如果 bug 涉及 “点击无反应”,必须同时记录:
|
||||
|
||||
- 点击前 tab 列表。
|
||||
- 点击后 tab 列表。
|
||||
- 点击目标节点截图。
|
||||
- console/network。
|
||||
|
||||
## 0524 试验集映射
|
||||
|
||||
`bugs/0524.md` 可作为第一批协同测试样本:
|
||||
|
||||
1. 我的空间拖入附件路径错误:
|
||||
- 验收:上传后文件实际路径应在当前页面 bundle/下级,而不是与主文件夹同级。
|
||||
- Reasonix 输出:文件树截图、实际磁盘路径、上传请求、编辑区附件截图。
|
||||
2. 上传后文件冲突:
|
||||
- 验收:本页面不误报自写冲突;新建页面不继承旧冲突状态。
|
||||
- Reasonix 输出:冲突弹窗截图、页面切换后截图、console/network。
|
||||
3. 隐藏本地 Markdown 标题设置:
|
||||
- 验收:不同 workspace/source 的默认值区分,用户选择刷新后保持。
|
||||
- Reasonix 输出:设置变更前后截图、刷新后截图、local/session storage 或后端请求证据。
|
||||
4. Ctrl+Z/Ctrl+Y 删除链接:
|
||||
- 验收:删除附件链接后 undo/redo 可恢复/再次删除。
|
||||
- Reasonix 输出:键盘动作步骤、编辑区 DOM/截图、断言结果。
|
||||
5. md 文件上传后黑色方块刷新变灰:
|
||||
- 验收:上传前后和刷新后附件 icon 状态一致,或有明确缺失状态样式。
|
||||
- Reasonix 输出:刷新前后截图、附件节点属性。
|
||||
|
||||
## 主控接受条件
|
||||
|
||||
Codex/Hermes 只有在以下条件满足时,才能把 Reasonix 浏览器结果作为验收证据:
|
||||
|
||||
- `result.json` 存在且能解析。
|
||||
- 至少一张截图能直接显示用户可见状态。
|
||||
- console/network 不为空时已被解释;为空时明确记录为空。
|
||||
- `modified_files` 为 `[]` 或 `none`,确认 Reasonix 没有改源码。
|
||||
- `process-handoff` 已 retain 到 Hindsight,主控可 recall。
|
||||
|
||||
## 失败处理
|
||||
|
||||
- 缺截图:结果降级为线索,不作为验收。
|
||||
- 缺 console/network:UI 失败只可作为复现证据,不可作为根因证据。
|
||||
- 没清缓存或没隔离 browser context:结果标记 `blocked` 或 `needs_rerun`。
|
||||
- Reasonix 修改源码:本次测试作废,主控检查 diff 后决定是否保留建议。
|
||||
|
||||
## 评价指标
|
||||
|
||||
- accepted_browser_findings:Reasonix 浏览器发现最终被主控采纳的数量。
|
||||
- false_browser_leads:Reasonix 浏览器结论导致主控走错方向的数量。
|
||||
- retest_required_ratio:主控必须完全重测的比例。
|
||||
- artifact_read_time:主控读取证据包并形成判断所需时间。
|
||||
- missing_artifact_count:缺失截图、console、network、断言的数量。
|
||||
|
||||
## Done Gate
|
||||
|
||||
- [ ] `reasonix-browser-tester` skill 已补入本合同的最小 artifact 要求。
|
||||
- [ ] 使用 `bugs/0524.md` 中至少 1 个 bug 进行 Reasonix 浏览器试跑。
|
||||
- [ ] 试跑后记录 accepted findings / false leads / retest required。
|
||||
- [ ] 根据试跑结果更新本合同或 Reasonix skill。
|
||||
@@ -1,146 +0,0 @@
|
||||
# Reasonix Skill Maintainer v1
|
||||
|
||||
## 状态
|
||||
|
||||
- 状态:process
|
||||
- Owner:AI runtime / multi-agent collaboration
|
||||
- 背景:Hindsight 解决了 Reasonix 过程可追溯问题,但不能自动让 Reasonix 下一次更好。需要一个主控驱动的最小自进化机制,由 Codex/Hermes 根据真实 run 修改 Reasonix skill、任务模板和 handoff 合同。
|
||||
|
||||
## 目标
|
||||
|
||||
建立“真实任务 -> 复盘 -> 修改 Reasonix skill/模板 -> 小 smoke -> 再试跑”的闭环,让 Reasonix 从通用辅助逐步变成可审计、低噪声、能节省主控 token 的 worker。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 不让 Reasonix 自主修改自己的 skill。
|
||||
- 不照搬 Hermes 的完整自进化机制。
|
||||
- 不把一次失败就提升为长期规则。
|
||||
- 不修改项目 `AGENTS.md`,除非用户明确要求。
|
||||
|
||||
## 角色边界
|
||||
|
||||
- Codex/Hermes:主控,负责判断哪些协作缺陷值得固化为 skill 规则。
|
||||
- Reasonix:被维护的 worker,负责执行明确任务。
|
||||
- Hindsight:热记忆,保存过程 handoff 和协作复盘。
|
||||
- MemPalace:冷归档,保存长期可检索的会话摘要。
|
||||
|
||||
## 输入
|
||||
|
||||
每次维护 Reasonix skill 前,主控必须先读取:
|
||||
|
||||
- Reasonix run 输出目录:
|
||||
- `result.json`
|
||||
- `process-handoff.json`
|
||||
- `process-handoff.md`
|
||||
- `final.md`
|
||||
- 必要时 `reasonix-transcript.jsonl`
|
||||
- Hindsight recall:
|
||||
- `hindsight-embed -p agents memory recall reasonix "<run-id 或任务关键词>"`
|
||||
- 当前相关 skill:
|
||||
- `reasonix-coding-worker`
|
||||
- `reasonix-browser-tester`
|
||||
- `reasonix-parallel-coding-flow`
|
||||
- 新增 `reasonix-skill-maintainer`
|
||||
|
||||
## 复盘维度
|
||||
|
||||
每个 Reasonix run 至少评估:
|
||||
|
||||
- accepted_findings:被主控采纳的关键发现数。
|
||||
- false_leads:误导主控的判断数。
|
||||
- missing_evidence:缺失证据项。
|
||||
- verification_strength:是否有真实命令、截图、日志、网络、diff。
|
||||
- handoff_cleanliness:handoff 是否能快速读懂。
|
||||
- modified_files_accuracy:是否准确记录修改文件。
|
||||
- retest_required:主控是否必须完全重测。
|
||||
- token_saving_estimate:是否减少主控探索或验证成本。
|
||||
|
||||
## 维护决策
|
||||
|
||||
只有满足以下至少一项,才修改 Reasonix skill:
|
||||
|
||||
- 同类缺陷出现两次以上。
|
||||
- 单次缺陷导致主控明显走错方向。
|
||||
- 缺失 artifact 使浏览器结果无法验收。
|
||||
- `process-handoff` 的结构缺陷导致主控必须重读 transcript。
|
||||
- 用户明确指出 Reasonix 协同方式需要调整。
|
||||
|
||||
不应修改 skill 的情况:
|
||||
|
||||
- 只是单次措辞不佳。
|
||||
- 是当前任务本身不清楚,而不是 Reasonix 规则缺失。
|
||||
- 可通过更好的任务书解决,不需要变成长期规则。
|
||||
|
||||
## 修改范围
|
||||
|
||||
优先顺序:
|
||||
|
||||
1. 修改任务书模板:成本最低,适合单类任务。
|
||||
2. 修改 Reasonix skill:适合跨任务重复规则。
|
||||
3. 修改 runner/extractor schema:适合结构化输出缺陷。
|
||||
4. 修改 Codex/Hermes 主控 skill:适合复核顺序和验收口径。
|
||||
|
||||
每次只做最小修改,并记录:
|
||||
|
||||
- 修改前问题。
|
||||
- 修改文件。
|
||||
- 预期改善。
|
||||
- smoke 验证方式。
|
||||
|
||||
## Smoke 验证
|
||||
|
||||
修改 Reasonix skill 后,必须至少做一个轻量 smoke:
|
||||
|
||||
- 只读任务优先,不改业务代码。
|
||||
- 要求 Reasonix 产出新格式字段。
|
||||
- 主控检查字段是否存在、是否可解析、是否减少噪声。
|
||||
|
||||
浏览器类 smoke 应检查:
|
||||
|
||||
- 是否有截图路径。
|
||||
- 是否有 console/network 摘要。
|
||||
- 是否有 `cache_cleared`、`browser_context`。
|
||||
- 是否有 `assertions[]`。
|
||||
|
||||
## 0524 试跑计划
|
||||
|
||||
使用 `bugs/0524.md` 作为真实任务池,不一次性全交给 Reasonix:
|
||||
|
||||
1. 第一轮:只让 Reasonix 浏览器复现第 2 个 bug“上传后文件冲突”,不修代码。
|
||||
- 目标:验证 browser artifact contract 是否足够。
|
||||
2. 第二轮:让 Reasonix 只读审计第 1 个 bug“我的空间附件路径错误”。
|
||||
- 目标:验证 coding-worker handoff 是否能给出可采纳根因。
|
||||
3. 第三轮:Codex 修复其中一个 bug 后,让 Reasonix 做回归。
|
||||
- 目标:评估 Reasonix 是否能减少主控浏览器验证 token。
|
||||
|
||||
每轮都记录:
|
||||
|
||||
- Reasonix 耗时。
|
||||
- 主控读取 handoff 所需时间。
|
||||
- 主控是否重测。
|
||||
- 被采纳发现。
|
||||
- 误导点。
|
||||
- 需要修改的 skill 规则。
|
||||
|
||||
## 输出记录
|
||||
|
||||
建议每次维护后在对应 bug/design 中补一段:
|
||||
|
||||
```text
|
||||
Reasonix 协同复盘:
|
||||
- run id:
|
||||
- 任务类型:
|
||||
- accepted findings:
|
||||
- false leads:
|
||||
- missing artifacts:
|
||||
- skill changes:
|
||||
- next iteration:
|
||||
```
|
||||
|
||||
## Done Gate
|
||||
|
||||
- [ ] 创建 `reasonix-skill-maintainer` skill。
|
||||
- [ ] `reasonix-browser-tester` 已引用 browser artifact contract。
|
||||
- [ ] 用 `bugs/0524.md` 至少跑一轮真实 Reasonix 协同测试。
|
||||
- [ ] 根据真实结果更新 skill 或明确“不需要修改”。
|
||||
- [ ] 在 Hindsight / MemPalace 中保留协作复盘摘要。
|
||||
@@ -1,141 +0,0 @@
|
||||
# 7-37 Claude Code / Reasonix Worker 评估协议:0524 Bug2 v1
|
||||
|
||||
## 目标
|
||||
|
||||
用 `bugs/0524.md` 第 2 条“本地 Markdown 上传/文件树拖入后误报文件冲突”作为真实任务,评估 Claude Code 与 Reasonix 作为 worker 的可用性:
|
||||
|
||||
1. 编码能力:是否能在相同基线下定位根因、做小范围修复、补测试并通过验证。
|
||||
2. 网页测试能力:是否能在真实浏览器中复现/验收,产出可审计截图、console、network 和结构化结论。
|
||||
|
||||
Codex 仍是主控,负责设计、派发、复核、合并和最终验收。
|
||||
|
||||
## 公平性约束
|
||||
|
||||
- 两个 coding worker 使用从同一 `HEAD` 创建的独立 worktree,不共享当前主工作区未提交改动。
|
||||
- 两个 coding worker 使用同一份任务书,允许修改范围一致,验收命令一致。
|
||||
- 两个 browser worker 对同一个主工作区修复结果做只读验证,不允许改源码。
|
||||
- 评分只基于可复核产物:diff、测试输出、process handoff、截图、console/network,不凭 final 文本。
|
||||
- 若 worker 卡住、超时、无 handoff、无截图或修改范围失控,按实际情况扣分,不手工补完其证据。
|
||||
|
||||
## Coding Worker 任务切片
|
||||
|
||||
输入:
|
||||
|
||||
- bug:`bugs/0524.md` 第 2 条。
|
||||
- 参考设计:`design/05-editor-mainline/process/5-27-local-markdown-working-copy-conflict-contract-v1.md`。
|
||||
- 允许修改:
|
||||
- `rust/crates/mnote-web/src/routes/web_shell.rs`
|
||||
- `rust/crates/mnote-web/src/routes/local_folder_events.rs`
|
||||
- `scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`
|
||||
- 必要时新增/更新同目录小测试
|
||||
- 禁止修改:无关设计、AGENTS、其它 bugs、git 提交、回滚用户改动。
|
||||
|
||||
验收:
|
||||
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web document_event_filter_rejects_resource_only_changes -- --nocapture`
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web document_shell_renders_local_markdown_with_same_sidebar_surfaces -- --nocapture`
|
||||
- `cargo fmt --manifest-path rust/Cargo.toml --all --check`
|
||||
- 若能启动浏览器 smoke,运行 `node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js` 并记录结果。
|
||||
|
||||
## Browser Worker 任务切片
|
||||
|
||||
输入:
|
||||
|
||||
- 被测主工作区当前修复结果。
|
||||
- 入口:`http://127.0.0.1:3000`。
|
||||
- 登录:`/auth` 的“测试账号快速登录”。
|
||||
|
||||
必须验证:
|
||||
|
||||
- 打开本地 Markdown 页面,上传附件后,不出现 `mnote-editor-conflict-panel`。
|
||||
- 新建/切换页面后,旧冲突面板不残留到新页面。
|
||||
- 向文件树文件夹拖入文件后,不出现 `external-change-conflict`。
|
||||
- 真实冲突路径仍可用:dirty 当前 Markdown 后外部修改同一 `.md` 文件,应显示冲突。
|
||||
|
||||
必须产出:
|
||||
|
||||
- `result.json`
|
||||
- `process-handoff.md/json`
|
||||
- 至少一张显示通过或失败状态的截图
|
||||
- console/network 摘要
|
||||
- `modified_files` 必须为空
|
||||
|
||||
## 评分维度
|
||||
|
||||
- `root_cause`:是否找到两个核心根因:document event 越界、冲突 DOM 残留。
|
||||
- `patch_scope`:是否只改必要文件,未引入架构外补丁。
|
||||
- `test_quality`:是否补了能失败/能防回归的测试。
|
||||
- `verification`:是否实际运行命令并记录输出。
|
||||
- `handoff_quality`:是否有过程证据,而不是只给最终摘要。
|
||||
- `latency_cost`:完成时间、工具调用量、是否卡住。
|
||||
- `mislead_risk`:错误假设、过度修改、把无关失败归因到本 bug 的风险。
|
||||
|
||||
## 初步观察
|
||||
|
||||
- Reasonix 只读分析较快完成,正确指出空 `documentId` 会污染 session,但对新建页时序有部分猜测,需要主控复核。
|
||||
- Claude Code 修复后本轮可产出 handoff,明确指出冲突面板 DOM 生命周期缺口;耗时更长,但对第二个根因帮助明显。
|
||||
- 后续需要用隔离 coding 任务和真实 browser 任务继续比较,而不是只比较只读分析。
|
||||
|
||||
## 0524 Bug2 本轮实测记录
|
||||
|
||||
### 主控基线
|
||||
|
||||
- 主控修复覆盖三个切片:
|
||||
- document event channel 从 `rootUri` 收窄到 `rootUri#documentId`。
|
||||
- 空 `documentId` 的资源事件不再进入正文冲突链路。
|
||||
- editor view unmount 清理旧 session 冲突面板 DOM。
|
||||
- 主控验证:
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web document_event_filter_rejects_resource_only_changes -- --nocapture`:通过。
|
||||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web document_shell_renders_local_markdown_with_same_sidebar_surfaces -- --nocapture`:通过。
|
||||
- `cargo fmt --manifest-path rust/Cargo.toml --all --check`:通过。
|
||||
- `node scripts/task451-local-markdown-conflict-resolution-ui-smoke.js`:通过,真实冲突仍可用。
|
||||
- `node scripts/task479-local-folder-markdown-resource-lifecycle-smoke.js`:上传附件和文件树拖入 no-conflict 断言通过;后续 broken-link 检查失败,属于其它已知路径,不计入本 bug 修复失败。
|
||||
|
||||
### Coding Worker 对比
|
||||
|
||||
- Reasonix coding:
|
||||
- run id:`reasonix-2026-05-24T07-44-15-864Z-6898e686`。
|
||||
- worktree:`/mnt/Data1T/mnote-wt-0524b-reasonix-coding`。
|
||||
- 正确抓到空 `documentId` 事件污染正文 session。
|
||||
- 补了前端 `if (!documentId) return;` 和后端映射测试。
|
||||
- 漏掉冲突面板 DOM 残留,也没有做 `rootUri#documentId` channel 隔离。
|
||||
- 自报未跑 Playwright,适合作为“定位主因 + 小补丁”证据,不足以直接合并。
|
||||
- Claude Code coding:
|
||||
- run id:`claudecode-2026-05-24T07-44-15-975Z-e03aaf1f`。
|
||||
- worktree:`/mnt/Data1T/mnote-wt-0524b-claudecode-coding`。
|
||||
- 正确抓到空 `documentId` 事件污染。
|
||||
- 额外抓到冲突面板 DOM 生命周期问题。
|
||||
- 修复位置是 `releaseDocumentSession`,比主控采用的 `unmountEditorViewBinding` 更晚,仍可能存在切换瞬间残留风险。
|
||||
- 未做 `rootUri#documentId` channel 隔离,也未补 task479 no-conflict smoke。
|
||||
- 编码帮助大于 Reasonix,但仍需主控补边界。
|
||||
|
||||
### Browser Worker 对比
|
||||
|
||||
- Claude Code browser:
|
||||
- run id:`claudecode-2026-05-24T07-47-11-262Z-46f574f0`。
|
||||
- artifact:`/tmp/mnote-0524-bug2-browser-worker-1779608936242/`。
|
||||
- 产出 `result.json`、截图、console/network。
|
||||
- 上传附件 no-conflict、文件树拖入 no-conflict、dirty + 外部修改真实冲突均通过。
|
||||
- `modified_files=[]`。
|
||||
- 该轮可作为较高质量浏览器验收证据。
|
||||
- Reasonix browser:
|
||||
- run id:`reasonix-2026-05-24T07-47-11-249Z-43f061bb`。
|
||||
- artifact:`/tmp/mnote-0524-bug2-browser-worker-0524T0800/`。
|
||||
- 产出 `result.json`、截图、console/network。
|
||||
- 上传附件 no-conflict、文件树拖入 no-conflict 通过。
|
||||
- runner status 为 `error` / handoff status 为 `failed`,但 `result.json.status=passed`,状态合同不一致。
|
||||
- 将 `/api/local-folder/events` 500 判断为真实冲突阻塞;主控 `task451` 和 Claude Code browser 已证明真实冲突仍可验证,因此该判断有误导风险。
|
||||
- 可作为部分 UI 证据,但不能单独作为最终验收。
|
||||
|
||||
### 可审计性结论
|
||||
|
||||
- Hindsight recall 可召回本轮 Claude Code 与 Reasonix 过程 handoff,但 Reasonix recall 混入了无关项目结果,主控不能只看 recall 摘要。
|
||||
- Claude Code 的 browser artifact 更适合验收:`result.json`、截图路径、console/network、`modified_files=[]` 之间一致。
|
||||
- Reasonix 的 browser artifact 可作为辅助证据,但 runner `status=error` 与 artifact `status=passed` 冲突时,必须降级为线索。
|
||||
- 本轮公平测试说明:worker 能节省主控定位和浏览器操作 token,但不能替代主控做架构边界、diff 取舍和最终验收。
|
||||
|
||||
## 当前评分倾向
|
||||
|
||||
- 编码能力:Claude Code 略优,能补出 DOM 生命周期根因;Reasonix 更快但更像最小局部补丁。
|
||||
- 浏览器测试能力:Claude Code 本轮明显优于 Reasonix,证据更完整且能覆盖真实冲突;Reasonix 产物可审计但状态和结论自相矛盾。
|
||||
- 主控策略:以后可让 Reasonix 做低风险定位/快速 smoke,让 Claude Code 做更完整的 browser artifact;两者结论都必须由 Codex 复核 diff、截图和命令输出。
|
||||
@@ -1,35 +0,0 @@
|
||||
# 7-38 Page AI sidebar runtime owner split v1
|
||||
|
||||
> 创建时间:2026-05-25
|
||||
> 状态:`process`
|
||||
> 来源:`design/03-rust-web/done/3-22-sidebar-tree-runtime-second-stage-split-v1.md` Batch A。
|
||||
> 2026-05-26 更新:`design/10-review/done/16-mnote-web-runtime-module-maintainability-checklist-v1.md` 已把 Page AI 主体迁入 `browser/sidebar-page-ai-runtime.js`;本文件继续作为后续 AI owner 收口 checklist。
|
||||
|
||||
## 1. 背景
|
||||
|
||||
`rust/crates/mnote-web/browser/sidebar-tree-runtime.js` 曾包含大量 Page AI panel 代码:会话、消息、profile、skills、gateway health、ACP runtime、permission dialog、plan/status event、session search/resume 等。2026-05-26 的 runtime 可维护性批次已将主体迁入 `browser/sidebar-page-ai-runtime.js`,tree runtime 目前只保留 sidebar click/change/input 委托、少量 `pageUiState.pageAi*` 状态壳和触发器代理。
|
||||
|
||||
这些代码不是 tree/filetree runtime 的长期 owner。继续把 Page AI 面板放在 `03-rust-web` 的 sidebar runtime 拆分里,会让 tree shell、local folder、AI session 三条边界继续混在一起。
|
||||
|
||||
## 2. Owner 判断
|
||||
|
||||
- owner:`07-ai`
|
||||
- 运行位置:当前仍可挂在 sidebar UI,但 runtime 模块应独立于 tree/filetree runtime。
|
||||
- 当前目标模块:`rust/crates/mnote-web/browser/sidebar-page-ai-runtime.js`
|
||||
- 主壳职责:只加载 asset、提供当前 document/workspace/root/bootstrap。
|
||||
|
||||
## 3. 后续执行建议
|
||||
|
||||
- [x] 只读审计 Page AI panel 的状态入口:`pageUiState.pageAi*`、storage、session 列表、profile/skills、permission dialog。
|
||||
- [x] 建立独立 Page AI sidebar owner runtime:`sidebar-page-ai-runtime.js`。
|
||||
- [ ] 从 `sidebar-tree-runtime.js` 继续迁出 Page AI click/change/input/keydown 委托,tree runtime 只保留 `data-mnote-action="open-page-ai"` 入口。
|
||||
- [ ] 将 `pageUiState.pageAi*` 从通用 sidebar state 中下沉到 Page AI owner runtime,并保留兼容 getter/setter 或明确 bootstrap contract。
|
||||
- [ ] 若 `sidebar-page-ai-runtime.js` 继续超过 2,500 行,再按 `session/profile-skill/permission/conversation` 拆成子模块。
|
||||
- [ ] 浏览器验证使用页面 AI / ACP smoke,而不是 tree/filetree smoke 替代。
|
||||
|
||||
## 4. 非目标
|
||||
|
||||
- 不在 03-rust-web 的 sidebar runtime 二阶段里继续扩大 Page AI 实现。
|
||||
- 不在 10-review runtime 可维护性收口里继续重构 ACP/Hermes session 语义;这里只记录 owner 边界。
|
||||
- 不改变 Hermes / Reasonix ACP runtime 协议。
|
||||
- 不把 local-first agent 文件编辑链路改回粗粒度 `mnote.page.save`。
|
||||
@@ -1,425 +0,0 @@
|
||||
# 7-41 Page AI Hermes / Reasonix user profile isolation v2
|
||||
|
||||
> 创建时间:2026-05-29
|
||||
>
|
||||
> 状态:`process`
|
||||
>
|
||||
> Owner:Page AI agent identity / Hermes profile policy / Reasonix memory policy
|
||||
>
|
||||
> 上位依据:
|
||||
> - `design/07-ai/done/7-39-page-ai-agent-selector-context-authorization-settings-v1.md`
|
||||
> - `design/07-ai/done/7-40-page-ai-context-envelope-and-run-receipt-v1.md`
|
||||
> - `design/07-ai/process/7-18-local-first-agent-file-editing-control-plane-v1.md`
|
||||
> - `design/07-ai/process/7-38-page-ai-sidebar-runtime-owner-split-v1.md`
|
||||
>
|
||||
> 参考依据:
|
||||
> - Hermes 官方 profile 文档:profile 是独立 Hermes home,包含 `config.yaml`、`.env`、`SOUL.md`、memories、sessions、skills、cron、state database、gateway state。
|
||||
> - Hermes WebUI:技能 toggle 直接写 profile `config.skills.disabled`。
|
||||
> - Hermes VSCode:只管理会话和一次性上下文建议,不提供真正的 per-user skill disable。
|
||||
> - PilotDeck:以 WorkSpace 为边界隔离文件、记忆和技能,并强调白盒记忆可追溯。
|
||||
> - Reasonix 文档/本地实现:默认使用 `~/.reasonix/memory/global` 与 `~/.reasonix/memory/<project-hash>`,`REASONIX_MEMORY=off|false|0` 可关闭 memory 注入。
|
||||
|
||||
## 1. 背景
|
||||
|
||||
`7-39` 已把 Page AI UI 收口为 agent selector + contextRefs + SQLite per-user preference。`7-40` 进一步把 MNote skill library 定位为 agent 可按需读取的能力摘要,而不是每轮强行注入 prompt。
|
||||
|
||||
但当前 Hermes skill/profile 的真实边界仍不正确:
|
||||
|
||||
- Hermes 的 `skills.disabled` 是 profile 级配置,不是 MNote 用户级偏好。
|
||||
- Hermes profile 自带 `SOUL.md`、memory、session、skills 和 state;多个 MNote 用户共用同一个可写 profile,会把个人偏好、记忆和技能配置混在一起。
|
||||
- 当前 Page AI UI 已经能展示 Hermes skill toggle,但普通用户如果直接写共享 Hermes profile,就会影响其它用户。
|
||||
- Reasonix 虽然不像 Hermes 那样有 SOUL 人格,但它也有 global/project memory。默认共享 `~/.reasonix` 时,不能假设完全无状态。
|
||||
|
||||
因此本稿把 Page AI agent identity 从“选择 Hermes / Reasonix”提升为“选择 agent + profile scope + memory policy”。
|
||||
|
||||
## 2. 产品决策
|
||||
|
||||
### 2.1 Hermes profile 分层
|
||||
|
||||
Hermes profile 分为两类:
|
||||
|
||||
| profile kind | owner | 普通用户能否使用 | 普通用户能否改 skill | memory/session |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `personal` | 单个 MNote 用户 | 能 | 能,仅限自己的 profile | 用户独立 |
|
||||
| `shared` | 系统 / 管理员 | 能,若管理员公开 | 不能 | 默认不写入用户私有长期记忆 |
|
||||
|
||||
初始共享 Hermes profile 只包含 `lite`。
|
||||
|
||||
要求:
|
||||
|
||||
- 每个 MNote 用户可以访问自己的 personal Hermes profile。
|
||||
- 每个 MNote 用户可以访问被管理员公开的 shared Hermes profile。
|
||||
- shared Hermes profile 的 skill/config 只有管理员能改。
|
||||
- personal Hermes profile 的 skill/config 只有该 profile owner 或管理员能改。
|
||||
- Page AI 发送请求时必须携带解析后的 `agentProfileRef`,不能只携带裸 `profile=lite`。
|
||||
|
||||
### 2.2 MNote 内置技能开关
|
||||
|
||||
MNote 内置 skill / tool 属于 MNote 自己的能力面,普通用户应该可以按用户启停。该开关不写 Hermes profile,而是写 SQLite control-plane。
|
||||
|
||||
含义:
|
||||
|
||||
- `mnote_builtin_skill_enabled` 是 per-user 偏好和服务端执行策略,必须按当前 SQLite 用户隔离。
|
||||
- `hide_builtin_skills=true` 只是 UI 展示偏好,用于折叠或隐藏 MNote 内置能力说明;它不等于禁用。
|
||||
- MNote tool 是否可调用由服务端根据 `user_id + agentId + contextRefs + allowedRoots + mnote_builtin_skill_enabled` 决定。
|
||||
- 普通用户可启停自己的 MNote 内置 skills;管理员可设置默认值或全局禁用策略。
|
||||
- MNote 内置 skill 开关不修改 Hermes profile `config.yaml`,也不影响 shared Hermes profile。
|
||||
|
||||
### 2.3 Hermes profile skills
|
||||
|
||||
可以配置的只有 Hermes profile 自己的 skills。
|
||||
|
||||
规则:
|
||||
|
||||
- personal profile:用户可启停该 profile 下的 Hermes skills,写入该 personal profile 的 `config.yaml`。
|
||||
- shared profile:普通用户只读;管理员可启停 shared profile skills。
|
||||
- skill toggle API 必须做服务端权限检查,不能只靠 UI 禁用按钮。
|
||||
- MNote 不再把 `ai.agent.hermes.profile.<name>.skills.enabled` 当成普通用户对共享 profile 的安全开关;MNote 内置 skill 的 per-user 开关应使用独立 SQLite key。
|
||||
|
||||
### 2.4 Reasonix memory policy
|
||||
|
||||
Reasonix 默认关闭 memory 注入。
|
||||
|
||||
规则:
|
||||
|
||||
- 默认启动 Reasonix ACP 时设置 `REASONIX_MEMORY=off`。
|
||||
- 每个 MNote 用户可在设置中开启 Reasonix memory。
|
||||
- 该设置保存到 SQLite `user_ui_preferences`,按用户隔离。
|
||||
- 开启后,UI 需明确标注 Reasonix 将使用 global/project memory。
|
||||
- 第一阶段不强制给 Reasonix 每用户独立 HOME;若后续需要更强隔离,再增加 `reasonix_home_mode=per_user`。
|
||||
|
||||
## 3. 数据合同
|
||||
|
||||
### 3.1 Agent profile ref
|
||||
|
||||
Page AI payload 中新增或固定以下结构:
|
||||
|
||||
```json
|
||||
{
|
||||
"agentId": "hermes",
|
||||
"agentProfileRef": {
|
||||
"kind": "personal",
|
||||
"profileId": "usr_123_default",
|
||||
"ownerUserId": "usr_123",
|
||||
"baseProfile": "default",
|
||||
"displayName": "我的 Hermes"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
shared profile:
|
||||
|
||||
```json
|
||||
{
|
||||
"agentId": "hermes",
|
||||
"agentProfileRef": {
|
||||
"kind": "shared",
|
||||
"profileId": "shared_lite",
|
||||
"ownerUserId": null,
|
||||
"baseProfile": "lite",
|
||||
"displayName": "Lite"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
服务端要求:
|
||||
|
||||
- 不接受浏览器直接提交任意 Hermes filesystem path。
|
||||
- `profileId` 必须由 SQLite control-plane 解析到当前用户可访问的 profile。
|
||||
- 对 personal profile,当前用户必须是 owner 或 admin。
|
||||
- 对 shared profile,必须是公开 profile 或 admin。
|
||||
- 所有 run / skill list / skill toggle / settings read 都通过 `agentProfileRef` 解析,不走裸 profile name。
|
||||
|
||||
### 3.2 SQLite control-plane
|
||||
|
||||
建议新增控制面表,避免只用偏好 key 表达权限关系:
|
||||
|
||||
```text
|
||||
ai_agent_profiles
|
||||
- id
|
||||
- agent_id # hermes
|
||||
- profile_kind # personal | shared
|
||||
- owner_user_id # personal 必填,shared 为空
|
||||
- base_profile_name # Hermes 原始 profile 名或模板名
|
||||
- isolated_profile_name # MNote 管理后的真实 Hermes profile 名
|
||||
- display_name
|
||||
- status # active | disabled
|
||||
- created_at
|
||||
- updated_at
|
||||
|
||||
ai_agent_profile_grants
|
||||
- profile_id
|
||||
- user_id
|
||||
- role # owner | user | admin
|
||||
- can_run
|
||||
- can_manage_skills
|
||||
- can_manage_config
|
||||
- created_at
|
||||
- updated_at
|
||||
```
|
||||
|
||||
第一阶段也可以在现有 `user_ui_preferences` 中保存默认选择:
|
||||
|
||||
- `ai.agent.hermes.default_profile_id`
|
||||
- `ai.agent.hermes.hide_builtin_skills`
|
||||
- `ai.agent.mnote_builtin.skills.enabled`
|
||||
- `ai.agent.reasonix.memory_enabled`
|
||||
|
||||
但 profile 权限、owner、shared/personal 类型不应只存在于 UI preference。
|
||||
|
||||
MNote 内置 skill 的用户级开关可以第一阶段存在 `user_ui_preferences`,但服务端 tool policy 读取时必须视为执行策略,而不是纯 UI 状态。若后续需要审计、管理员默认值或组织策略,应升级为独立表:
|
||||
|
||||
```text
|
||||
ai_user_skill_preferences
|
||||
- user_id
|
||||
- skill_id
|
||||
- enabled
|
||||
- updated_at
|
||||
```
|
||||
|
||||
### 3.3 Hermes profile provisioning
|
||||
|
||||
创建 personal Hermes profile 时:
|
||||
|
||||
- 可从共享模板复制 `config.yaml`、`.env`、`SOUL.md` 和 skills。
|
||||
- 不复制 memories、sessions、state database、gateway state。
|
||||
- 生成的真实 profile name 必须包含 MNote 用户隔离标识,例如 `mnote-u-<userId>-default`。
|
||||
- provisioning 过程由服务端执行,并记录到 SQLite control-plane。
|
||||
|
||||
shared `lite`:
|
||||
|
||||
- 初始由管理员登记为 `shared_lite`。
|
||||
- 普通用户只可 run / list readonly。
|
||||
- 管理员可改 skill/config。
|
||||
|
||||
## 4. API 合同
|
||||
|
||||
### 4.1 Profile list
|
||||
|
||||
`GET /api/ai/agent-profiles?agentId=hermes`
|
||||
|
||||
返回当前用户可访问 profiles:
|
||||
|
||||
```json
|
||||
{
|
||||
"profiles": [
|
||||
{
|
||||
"profileId": "usr_123_default",
|
||||
"kind": "personal",
|
||||
"displayName": "我的 Hermes",
|
||||
"canRun": true,
|
||||
"canManageSkills": true
|
||||
},
|
||||
{
|
||||
"profileId": "shared_lite",
|
||||
"kind": "shared",
|
||||
"displayName": "Lite",
|
||||
"canRun": true,
|
||||
"canManageSkills": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 4.2 Skill list
|
||||
|
||||
`GET /api/hermes/client/skills?profileId=...`
|
||||
|
||||
要求:
|
||||
|
||||
- personal profile 返回可 toggle 状态。
|
||||
- shared profile 对普通用户返回 readonly 状态。
|
||||
- MNote 内置 skills 返回值必须标记 `builtin=true`、`configurable=true`、`configScope=user_sqlite`。
|
||||
- Hermes profile skills 标记 `builtin=false`、`configurable=canManageSkills`。
|
||||
|
||||
### 4.3 Skill toggle
|
||||
|
||||
`PUT /api/hermes/client/skills/toggle`
|
||||
|
||||
请求:
|
||||
|
||||
```json
|
||||
{
|
||||
"profileId": "usr_123_default",
|
||||
"skillName": "writer",
|
||||
"enabled": false
|
||||
}
|
||||
```
|
||||
|
||||
服务端必须:
|
||||
|
||||
- 解析 `profileId`。
|
||||
- 若 `skillKind=mnote_builtin`,写当前用户 SQLite skill preference,不写 Hermes profile。
|
||||
- 若 `skillKind=hermes_profile`,校验 `canManageSkills=true`。
|
||||
- 拒绝普通用户修改 shared profile 的 Hermes profile skills。
|
||||
- personal profile skill toggle 只写目标 Hermes profile 的 `config.yaml`。
|
||||
|
||||
错误码建议:
|
||||
|
||||
- `ai_profile_not_found`
|
||||
- `ai_profile_forbidden`
|
||||
- `ai_profile_readonly`
|
||||
- `ai_builtin_skill_preference_failed`
|
||||
- `hermes_skill_toggle_failed`
|
||||
|
||||
### 4.4 Reasonix run
|
||||
|
||||
Reasonix ACP spawn / session create 需读取当前用户设置:
|
||||
|
||||
```json
|
||||
{
|
||||
"agentId": "reasonix",
|
||||
"memoryPolicy": {
|
||||
"enabled": false,
|
||||
"source": "user_ui_preferences"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
默认:
|
||||
|
||||
- `enabled=false`
|
||||
- 子进程环境包含 `REASONIX_MEMORY=off`
|
||||
|
||||
开启:
|
||||
|
||||
- 不设置 `REASONIX_MEMORY=off`,或设置为 `on`
|
||||
- UI 明确展示 memory 已开启
|
||||
|
||||
## 5. UI 设计
|
||||
|
||||
### 5.1 Agent selector
|
||||
|
||||
Hermes agent 下增加 profile 子选择:
|
||||
|
||||
```text
|
||||
Hermes
|
||||
我的 Hermes personal · 可配置
|
||||
Lite shared · 只读
|
||||
```
|
||||
|
||||
显示规则:
|
||||
|
||||
- personal profile 显示“可配置”。
|
||||
- shared profile 显示“共享 / 只读”。
|
||||
- 若普通用户选择 shared profile,技能开关显示为只读。
|
||||
- 管理员选择 shared profile,技能开关可用,并显示“管理员正在修改共享 profile”。
|
||||
|
||||
### 5.2 Skills panel
|
||||
|
||||
三组仍保留:
|
||||
|
||||
- MNote 内置技能:可折叠,可隐藏/显示,也可由普通用户按自己账号启停。
|
||||
- Hermes 技能:随当前 Hermes profile 变化;personal 可配置,shared 普通用户只读。
|
||||
- Reasonix 技能:展示可用能力;memory 是单独设置,不混入 skill toggle。
|
||||
|
||||
Hermes profile 切换时:
|
||||
|
||||
- 必须重新加载 profile skills。
|
||||
- 必须清空旧 profile skill cache。
|
||||
- `hide_builtin_skills` 不随 Hermes profile 改变;它是用户 UI 偏好。
|
||||
- MNote 内置 skill enable/disable 不随 Hermes profile 改变;它是当前 MNote 用户的 SQLite policy。
|
||||
|
||||
### 5.3 Settings
|
||||
|
||||
设置页拆分:
|
||||
|
||||
- Common:授权区域、contextRefs 默认值、内置技能显示/隐藏、内置技能启停。
|
||||
- Hermes:默认 Hermes profile、personal profile 管理、shared profile 只读/管理员管理。
|
||||
- Reasonix:默认关闭 memory;用户可开启。
|
||||
- Chat-only:只聊天配置。
|
||||
|
||||
## 6. 非目标
|
||||
|
||||
- 不让普通用户直接修改 shared Hermes profile。
|
||||
- 不把 shared Hermes profile 用作沉淀个人偏好的长期人格。
|
||||
- 不在本阶段实现 Reasonix per-user HOME;只实现默认 memory off 与可选开启。
|
||||
- 不新增第二套目录授权真相;文件访问仍由 SQLite directory grants / allowedRoots 控制。
|
||||
- 不实现 PilotDeck 的完整 router、always-on 或 memory engine。
|
||||
|
||||
## 7. Checklist
|
||||
|
||||
### Batch A - 现状冻结与风险取证
|
||||
|
||||
- [ ] 复核当前 Page AI Hermes skill toggle 的真实写入路径,确认是否直接写 Hermes profile `config.yaml`。
|
||||
- [ ] 复核当前 UI preference 中 `hide_builtin`、MNote 内置 skill enabled、profile skill enabled、default profile 的存储键。
|
||||
- [ ] 复核 Reasonix ACP spawn 环境,确认当前是否默认注入 memory。
|
||||
- [ ] 形成 RED 证据:普通用户修改 shared profile skill 会影响其它用户,或当前缺少服务端权限边界。
|
||||
- [ ] 验证:Rust/JS 只读审计记录在本文档或后续 checklist evidence 中。
|
||||
|
||||
### Batch B - SQLite profile policy 合同
|
||||
|
||||
- [ ] 新增或扩展 SQLite control-plane profile policy:`ai_agent_profiles` / `ai_agent_profile_grants` 或等价结构。
|
||||
- [ ] 初始化 shared Hermes profile:仅 `lite`,普通用户 `canRun=true`、`canManageSkills=false`。
|
||||
- [ ] 为每个用户 provision personal Hermes profile。
|
||||
- [ ] 补 Rust 定点测试:personal owner、shared readonly、admin manage、跨用户不可管理。
|
||||
- [ ] 验证:不同用户查询 profile list 只返回自己 personal + shared lite。
|
||||
|
||||
### Batch C - Hermes profile resolver
|
||||
|
||||
- [ ] 新增服务端 `agentProfileRef` resolver,禁止前端提交任意 Hermes path。
|
||||
- [ ] `/api/hermes/client/runs` 从 `profileId` 解析真实 Hermes profile。
|
||||
- [ ] `/api/hermes/client/skills` 从 `profileId` 解析真实 Hermes profile。
|
||||
- [ ] 保留旧 `profile=` 参数只作为兼容入口,并映射到当前用户可访问 profile。
|
||||
- [ ] 验证:旧路径兼容不允许越权访问 shared/admin profile。
|
||||
|
||||
### Batch D - Skill toggle 权限收口
|
||||
|
||||
- [ ] 修改 skill toggle API:只接受 `profileId + skillName + enabled`。
|
||||
- [ ] 区分 `mnote_builtin` 与 `hermes_profile` skill kind。
|
||||
- [ ] MNote 内置 skill toggle 写当前用户 SQLite preference。
|
||||
- [ ] 拒绝普通用户修改 shared profile 的 Hermes profile skills。
|
||||
- [ ] personal profile skill toggle 只写该用户 isolated profile `config.yaml`。
|
||||
- [ ] shared profile skill toggle 仅 admin 可写。
|
||||
- [ ] 验证:Rust API 测试覆盖 `ai_profile_readonly`、MNote 内置 skill per-user toggle、personal profile skill success。
|
||||
|
||||
### Batch E - MNote 内置 skill per-user policy
|
||||
|
||||
- [ ] 将 MNote 内置 skill enable/disable 保存为 SQLite per-user policy。
|
||||
- [ ] UI 中 `hide_builtin_skills` 只影响展示,不影响 enable/disable。
|
||||
- [ ] Skills panel 标记 `builtin=true`、`configurable=true`、`configScope=user_sqlite`。
|
||||
- [ ] 服务端 MNote tool policy 按 `user_id + agentId + contextRefs + allowedRoots + mnote_builtin_skill_enabled` 判断。
|
||||
- [ ] 验证:用户 A 禁用某内置 skill 不影响用户 B;禁用后对应 MNote tool 被服务端拒绝;隐藏展示不影响 enable 状态。
|
||||
|
||||
### Batch F - Reasonix memory policy
|
||||
|
||||
- [ ] 新增 per-user 设置 `ai.agent.reasonix.memory_enabled`,默认 `false`。
|
||||
- [ ] Reasonix ACP spawn 默认设置 `REASONIX_MEMORY=off`。
|
||||
- [ ] 开启 memory 后不注入 `REASONIX_MEMORY=off`,并在 UI 显示 memory enabled。
|
||||
- [ ] 补 JS/Rust 测试或 smoke,覆盖默认 off、用户开启、不同用户隔离 preference。
|
||||
- [ ] 验证:普通消息由 Reasonix 自己决定是否使用工具;MNote 不再强行注入 memory/context 正文。
|
||||
|
||||
### Batch G - UI 收口
|
||||
|
||||
- [ ] Agent selector 中 Hermes profile 显示 personal/shared/readonly 状态。
|
||||
- [ ] Skills panel 三组均可折叠。
|
||||
- [ ] Hermes profile 切换必须刷新 skill catalog,避免旧 profile skill 残留。
|
||||
- [ ] shared profile 的 Hermes profile skills 对普通用户展示只读开关或锁定状态。
|
||||
- [ ] MNote 内置 skills 对普通用户展示可启停状态,并标明按当前 MNote 用户保存。
|
||||
- [ ] 管理员对 shared profile 显示可管理状态,并提示影响所有用户。
|
||||
- [ ] 验证:真实浏览器截图覆盖 MNote 内置 skill per-user 可配置、personal Hermes skill 可配置、shared Hermes skill 只读、admin shared 可配置。
|
||||
|
||||
### Batch H - 回归矩阵与文档收尾
|
||||
|
||||
- [ ] 更新 Page AI 设计说明,明确 MNote 内置 skill per-user policy、personal/shared Hermes profile 与 Reasonix memory policy。
|
||||
- [ ] 更新 smoke:agent 切换、MNote 内置 skill per-user toggle、Hermes profile 切换、shared readonly、personal skill toggle、Reasonix memory off/on。
|
||||
- [ ] 运行 `node --check` 覆盖相关 browser runtime / smoke。
|
||||
- [ ] 运行 Rust 定点测试覆盖 SQLite profile policy 与 Hermes skill toggle 权限。
|
||||
- [ ] 运行真实浏览器验证并截图。
|
||||
- [ ] 运行 `git diff --check`。
|
||||
- [ ] 涉及代码图后运行 `codegraph sync .`。
|
||||
- [ ] 完成后将本 checklist 移动到 `done/` 或标记为 `done`。
|
||||
|
||||
## 8. 验收口径
|
||||
|
||||
完成后必须满足:
|
||||
|
||||
- 普通用户可以启停自己的 MNote 内置 skills,开关保存到 SQLite 并由服务端 tool policy 执行。
|
||||
- 用户 A 的 MNote 内置 skill 开关不影响用户 B。
|
||||
- 普通用户无法修改 shared `lite` 的 Hermes profile skills。
|
||||
- 普通用户可以修改自己的 personal Hermes profile skills。
|
||||
- MNote 内置 skill 的显示/隐藏与启停是两个不同状态:隐藏只影响 UI,启停影响服务端可调用性。
|
||||
- Hermes profile 切换后 skill catalog 正确刷新。
|
||||
- Reasonix 默认 memory off,开启 memory 是 per-user preference。
|
||||
- Page AI run payload 不再用裸 Hermes profile name 表达身份,而是经服务端解析的 `agentProfileRef` / `profileId`。
|
||||
- 所有文件访问仍受 SQLite directory grants / allowedRoots 约束。
|
||||
@@ -0,0 +1,273 @@
|
||||
# 7-43 ONLYOFFICE Plugin Bridge Design v1
|
||||
|
||||
> 状态:process
|
||||
>
|
||||
> Owner:07-ai / ONLYOFFICE live bridge / Page AI target runtime
|
||||
>
|
||||
> 创建时间:2026-06-01
|
||||
>
|
||||
> 当前口径:工具层 session/scope 安全阻断、真实 iframe 非 dry-run 写入落点验证、Page AI target picker 到真实 Office iframe session 的端到端绑定均已落地;本文继续留在 `process`,用于承接后续 recipe 扩展、Office 主文档加载噪音治理和 P2 plugin bridge 产品化收口,不再作为 P0 安全阻断项。
|
||||
|
||||
## 背景
|
||||
|
||||
当前本机 ONLYOFFICE DocumentServer 由 Docker 暴露在宿主机 `8082`:
|
||||
|
||||
- `mnote-onlyoffice-documentserver`: `onlyoffice/documentserver:9.4.0`
|
||||
- 端口映射:`0.0.0.0:8082 -> container:80`
|
||||
- MNote 公开入口:`http://127.0.0.1:3000`
|
||||
- MNote 通过 `/onlyoffice-server` 反代 DocumentServer 静态资源和 editor iframe
|
||||
|
||||
实测当前社区镜像不暴露 `docEditor.createConnector()`,因此不能依赖 ONLYOFFICE Automation API。MNote 的 live Office agent 能力应建立在社区版可用的 Plugin API 上:插件 iframe 使用 `window.Asc.plugin.executeMethod()` 和 `window.Asc.plugin.callCommand()` 调用 Office JavaScript API。
|
||||
|
||||
## 目标
|
||||
|
||||
建立一个完整、可扩展、可验证的 MNote ONLYOFFICE bridge 插件,让 Hermes、Reasonix 和页面 AI 能通过白名单 recipe 操作当前打开的 ONLYOFFICE 文档。
|
||||
|
||||
目标能力:
|
||||
|
||||
- 支持当前浏览器内打开的 Word、Excel、PPT live editor session。
|
||||
- 通过 MNote bridge API 派发命令,插件执行后回传 JSON-safe result。
|
||||
- 不暴露任意 JavaScript 执行能力。
|
||||
- 写操作继续遵守 MNote tool 权限、`dryRun` 和 `idempotencyKey` 模型。
|
||||
- 所有新增 recipe 必须同时支持 browser direct smoke 和 tool API smoke。
|
||||
|
||||
非目标:
|
||||
|
||||
- 不绕过 ONLYOFFICE Developer / Automation API 授权。
|
||||
- 不后台批量编辑任意 Office 文件;离线批处理仍优先使用 `officecli`。
|
||||
- 不把 ONLYOFFICE iframe DOM 当作编辑接口。
|
||||
|
||||
## 端口与 URL 边界
|
||||
|
||||
有两条 base URL,必须严格区分:
|
||||
|
||||
1. 浏览器可达的 MNote origin
|
||||
- 示例:`http://127.0.0.1:3000`
|
||||
- 用途:插件 iframe 调用 MNote bridge API。
|
||||
- 来源:`location.origin`
|
||||
- 禁止替换成 `host.docker.internal`,因为浏览器侧可能无法解析。
|
||||
|
||||
2. DocumentServer 容器可达的 MNote origin
|
||||
- 示例:`http://host.docker.internal:3000`
|
||||
- 用途:`document.url`、`callbackUrl`、local file proxy。
|
||||
- 来源:`ONLYOFFICE_DOCUMENT_URL_BASE`
|
||||
- 依赖 compose 中 `extra_hosts: ["host.docker.internal:host-gateway"]`。
|
||||
|
||||
DocumentServer 静态资源访问:
|
||||
|
||||
- Browser -> MNote -> DocumentServer
|
||||
- URL 形态:`/onlyoffice-server/web-apps/apps/api/documents/api.js`
|
||||
- 插件 SDK:`/onlyoffice-server/sdkjs-plugins/v1/plugins.js`
|
||||
|
||||
## 加载流程
|
||||
|
||||
1. 用户打开 `/onlyoffice?...`。
|
||||
2. MNote 页面加载 `/onlyoffice-server/web-apps/apps/api/documents/api.js`。
|
||||
3. MNote 构造 `DocsAPI.DocEditor` config。
|
||||
4. `document.url` 和 `callbackUrl` 使用 `ONLYOFFICE_DOCUMENT_URL_BASE`,供 DocumentServer 容器访问。
|
||||
5. `editorConfig.plugins.pluginsData` 指向:
|
||||
`/api/onlyoffice/bridge/plugin/config?sessionId=...&apiBase=http://127.0.0.1:3000`
|
||||
6. ONLYOFFICE 加载 MNote bridge 插件 iframe。
|
||||
7. 插件 iframe 调用 `POST /api/onlyoffice/bridge/session` 注册 session。
|
||||
8. 插件通过 `GET /api/onlyoffice/bridge/commands/next` 长轮询取命令。
|
||||
9. 插件执行白名单 recipe。
|
||||
10. 插件调用 `POST /api/onlyoffice/bridge/results` 回传结果。
|
||||
|
||||
## Bridge API
|
||||
|
||||
当前 API:
|
||||
|
||||
- `GET /api/onlyoffice/bridge/plugin/config`
|
||||
- `GET /api/onlyoffice/bridge/plugin/index`
|
||||
- `GET /api/onlyoffice/bridge/plugin/index/config.json`
|
||||
- `GET /api/onlyoffice/bridge/plugin/index/{state}`
|
||||
- `POST /api/onlyoffice/bridge/session`
|
||||
- `GET /api/onlyoffice/bridge/session/current`
|
||||
- `POST /api/onlyoffice/bridge/session/close`
|
||||
- `GET /api/onlyoffice/bridge/sessions`
|
||||
- `GET /api/onlyoffice/bridge/capabilities`
|
||||
- `POST /api/onlyoffice/bridge/commands`
|
||||
- `GET /api/onlyoffice/bridge/commands/next`
|
||||
- `POST /api/onlyoffice/bridge/results`
|
||||
- `GET /api/onlyoffice/bridge/results`
|
||||
|
||||
## Session 模型
|
||||
|
||||
每个打开的 ONLYOFFICE 页面生成一个 `sessionId`:
|
||||
|
||||
```text
|
||||
mnote-oo-{docKey}-{tabRandomSuffix}
|
||||
```
|
||||
|
||||
服务端保存:
|
||||
|
||||
- `sessionId`
|
||||
- `editorType`: `word` / `cell` / `slide`
|
||||
- `documentId`
|
||||
- `assetId`
|
||||
- `fileType`
|
||||
- `docKey`
|
||||
- `pageOrigin`
|
||||
- `lastSeenMillis`
|
||||
- `pendingCommands`
|
||||
- `pendingResults`
|
||||
|
||||
多 session 规则:
|
||||
|
||||
- 插件每次 `/commands/next` 都刷新 `lastSeenMillis`。
|
||||
- `session.current` 返回最近活跃 session。
|
||||
- 严肃写操作应显式传 `onlyofficeSessionId`,避免多标签页误写。
|
||||
- 不同 editorType 的 recipe 必须在插件或 wrapper 层做类型保护。
|
||||
|
||||
2026-06-01 复核:`sessionId` 已加入浏览器 tab 级随机后缀,tool 侧读写均要求显式 `onlyofficeSessionId` / `bridgeSessionId`,并按 `aiAccessScope.allowedResourceIds` 校验 session resource。当前 HTTP / mock plugin 层已有 `task515`、`task516`、`task517` 证据;真实 ONLYOFFICE iframe / DocumentServer 层新增 `task518` 证据,覆盖插件 autostart 注册、同一文档双 tab 不共用 session、A/B 资源 scope mismatch 403、授权 dry-run 200,以及非 dry-run 写入 B 后导出验证 A 不含 marker、B 含 marker。随后 `task523` 补齐 Page AI target picker 到 Office session 的端到端 UI 绑定:真实文档页打开 Office resource tab 后,Page AI run payload 会把 iframe live `onlyofficeSessionId` 冻结进 `editorTarget`、`targetPackage` 和 `targetPackage.targets[0]`,且不再把 Office target 当作 Markdown buffer 查询 `/api/documents/buffer-state`。
|
||||
|
||||
2026-06-01 续补:已新增 `GET /api/onlyoffice/bridge/session/current`、`POST /api/onlyoffice/bridge/session/close`,session state 已写入 `docKey` / `pageOrigin`,`/onlyoffice` 页面会把当前文档 `docKey` 与页面 origin 透传给 bridge plugin config。已通过 `cargo test --manifest-path rust/Cargo.toml -p mnote-web onlyoffice_bridge -- --test-threads=1`、`node scripts/task517-onlyoffice-bridge-plugin-direct-smoke.js`、`MNOTE_UI_BASE_URL=http://127.0.0.1:3302 node scripts/task516-onlyoffice-bridge-multisession-browser-smoke.js`。本文继续保留在 `process`,只跟踪 Office 主文档加载噪音治理和第三批 recipe 逐项实测。
|
||||
|
||||
## Recipe 分层
|
||||
|
||||
### 已实现 recipe
|
||||
|
||||
Word / 通用:
|
||||
|
||||
- `selection.get`
|
||||
- `document.insert_text`
|
||||
- `document.replace_selection`
|
||||
- `document.insert_html`
|
||||
- `document.export`
|
||||
- `document.search_replace`
|
||||
- `document.insert_table`
|
||||
- `document.get_comments`
|
||||
- `document.add_comment`
|
||||
|
||||
Excel:
|
||||
|
||||
- `sheet.get_sheets`
|
||||
- `sheet.add_sheet`
|
||||
- `sheet.rename_sheet`
|
||||
- `sheet.get_range`
|
||||
- `sheet.get_range_values`
|
||||
- `sheet.get_values`
|
||||
- `sheet.set_value`
|
||||
- `sheet.set_formula`
|
||||
- `sheet.batch_set_values`
|
||||
- `sheet.set_range_values`
|
||||
- `sheet.format_range`
|
||||
- `sheet.set_dimensions`
|
||||
- `sheet.sort_range`
|
||||
- `sheet.add_chart`
|
||||
|
||||
PPT:
|
||||
|
||||
- `presentation.get_slides`
|
||||
- `presentation.get_slide_texts`
|
||||
- `presentation.get_shapes`
|
||||
- `presentation.add_text_slide`
|
||||
- `presentation.replace_text`
|
||||
- `presentation.set_shape_text`
|
||||
- `presentation.delete_slide`
|
||||
- `presentation.add_table`
|
||||
- `presentation.clear_slide`
|
||||
- `presentation.add_shape`
|
||||
|
||||
### 第二批 recipe 说明
|
||||
|
||||
Word:
|
||||
|
||||
- `document.search_replace` 走 `Api.GetDocument().SearchAndReplace(...)`,适合精确文本替换。纯搜索暂不单独暴露,全文读取先用 `document.export`。
|
||||
- `document.insert_table` 走 `Api.CreateTable(cols, rows)` 并 `doc.Push(table)`,可用二维 `data` 填充单元格;默认插入到文档末尾。
|
||||
- `document.get_comments` 走 `doc.GetAllComments()`,返回评论 id、作者、正文和引用文本。
|
||||
- `document.add_comment` 支持给当前选区或 `document_start` 添加评论;选区模式依赖 `doc.GetRangeBySelect()`,没有选区时应显式用 `target=document_start`。
|
||||
|
||||
Excel:
|
||||
|
||||
- `sheet.get_sheets` 走 `Api.GetSheets()` / `worksheet.GetName()`,用于让 agent 明确当前 workbook sheet 结构。
|
||||
- `sheet.add_sheet` 走 `Api.AddSheet(name)`,用于创建新 sheet。
|
||||
- `sheet.rename_sheet` 走 `worksheet.SetName(name)`,用于重命名指定 `sheetIndex` 的 sheet。
|
||||
- `sheet.get_range_values` / `sheet.set_range_values` 接受 A1 地址(例如 `B2:C3`),适合按用户可见坐标读写二维区域。
|
||||
- `sheet.set_range_values` 只写入 A1 range 与 `values` 的交集;调用方需要保证二维数据尺寸符合预期。
|
||||
- `sheet.format_range` 走 `ApiRange` 格式 API,只暴露小范围字体粗斜体、下划线、填充色、字体色、字号、字体名、对齐、数字格式。
|
||||
- `sheet.set_dimensions` 走 `worksheet.SetColumnWidth` / `worksheet.SetRowHeight`,行列索引沿插件内部零基坐标。
|
||||
- `sheet.sort_range` 走 `range.SetSort(...)`,只暴露 A1 range、range 内 1 基 `keyColumn`、升降序和是否有表头。
|
||||
- `sheet.add_chart` 走 `worksheet.AddChart(...)`,只暴露 A1 数据区、图表类型、基础尺寸和插入位置。
|
||||
|
||||
PPT:
|
||||
|
||||
- `presentation.get_slide_texts` 读取 slide 文本框纯文本。
|
||||
- `presentation.replace_text` 替换文本框纯文本;命中的文本框会按纯文本段落重建,不承诺保留复杂 run 格式。
|
||||
- `presentation.get_shapes` 返回每页 shape 的 `slideIndex` / `shapeIndex` / `shapeId` / text 预览,用于精确定位文本框。
|
||||
- `presentation.set_shape_text` 按 `slideIndex + shapeIndex` 重写指定 shape 文本;只面向文本 shape,复杂样式不承诺保留。
|
||||
- `presentation.delete_slide` 删除指定 `slideIndex` 的幻灯片;调用前应先读 slide 列表确认目标页。
|
||||
- `presentation.add_table` 走 `Api.CreateTable(...)` + `slide.AddObject(table)`,支持二维 `data` 和基础位置/尺寸。
|
||||
- `presentation.clear_slide` 走 `slide.RemoveAllObjects()`,用于清空指定页对象;这是高影响写操作,调用前必须确认目标页。
|
||||
- `presentation.add_shape` 走 `Api.CreateShape(...)` + `slide.AddObject(shape)`,只暴露基础形状、文字、填充色、位置和尺寸。
|
||||
|
||||
### 第三批 recipe
|
||||
|
||||
- 已实装:Excel 排序、Excel 图表、PPT 表格。
|
||||
- 已实装:PPT 清空页对象、PPT 添加基础形状。
|
||||
- 待验证后再扩:Word 图片、修订、content controls、表格增删行列和样式。
|
||||
- 待验证后再扩:Excel 筛选、工作表删除/移动。
|
||||
- 待验证后再扩:PPT 图片、重排 slide、主题/布局、shape 样式与位置。
|
||||
- PDF/forms 字段读取与填写。
|
||||
|
||||
第三批必须逐项实测,不允许凭 API 名称直接暴露给 agent。
|
||||
|
||||
## 权限与安全
|
||||
|
||||
插件只负责执行当前 editor session 允许的动作;MNote 负责业务权限:
|
||||
|
||||
- 当前用户是否能打开文档。
|
||||
- agent 是否拥有 `office.read` / `office.write`。
|
||||
- 写操作是否显式 `dryRun`。
|
||||
- 写操作是否带 `idempotencyKey`。
|
||||
|
||||
安全规则:
|
||||
|
||||
- 不暴露 raw JavaScript。
|
||||
- action 必须是白名单。
|
||||
- payload 必须 schema 校验。
|
||||
- 批量单元格读写默认限制为 5000 cells。
|
||||
- result 必须 JSON-safe。
|
||||
- command timeout 默认 25 秒。
|
||||
|
||||
## 验证基线
|
||||
|
||||
每个 recipe 必须三层验证:
|
||||
|
||||
1. Rust unit test
|
||||
- manifest 暴露
|
||||
- route dispatch
|
||||
- dryRun / 权限 / queue result
|
||||
|
||||
2. Browser direct smoke
|
||||
- 直接调用 `window.__MNOTE_ONLYOFFICE_BRIDGE__.run(...)`
|
||||
- 不经过 Hermes/Reasonix
|
||||
- 必须保存截图并检查 `pageErrors=[]`
|
||||
|
||||
3. Tool API smoke
|
||||
- 通过 `/api/hermes/tools/mnote/call`
|
||||
- 验证 agent 实际可调用
|
||||
|
||||
完成标准:
|
||||
|
||||
- `cargo test -p mnote-web onlyoffice_ -- --test-threads=1`
|
||||
- `cargo test -p mnote-web hermes_tools_manifest_returns_first_batch_tools -- --test-threads=1`
|
||||
- `cargo test -p mnote-web skill_registry_exposes_onlyoffice_live_skill_to_agents -- --test-threads=1`
|
||||
- `node scripts/task517-onlyoffice-bridge-plugin-direct-smoke.js` 覆盖 bridge plugin index 在 mock `Asc.plugin` 环境中的 session 注册、`docKey/pageOrigin` 元数据、command 消费、result 回传和 token 拒绝。
|
||||
- `node scripts/task518-onlyoffice-real-iframe-session-scope-smoke.js` 覆盖真实 ONLYOFFICE iframe / DocumentServer 下插件 autostart、同文档双 tab session salt、bridge command 回收、resource scope 拒写、授权 dry-run,以及授权 B session 非 dry-run 写入后 A/B 导出内容不串台。
|
||||
- `node scripts/task523-page-ai-onlyoffice-real-target-session-smoke.js` 覆盖真实文档页内 Office resource tab -> Page AI target picker -> run payload 的 live session 绑定,并断言 Office target 不触发 Markdown buffer-state 404。
|
||||
- 关键 browser direct smoke 通过
|
||||
- `git diff --check` 通过
|
||||
- `codegraph sync .` 已运行
|
||||
|
||||
2026-06-01 进展:已新增并通过 `task517-onlyoffice-bridge-plugin-direct-smoke.js`,证明 MNote bridge plugin index 与 bridge HTTP loop 可在真实 Chromium 中直接运行。随后新增并通过 `task518-onlyoffice-real-iframe-session-scope-smoke.js`,在真实 ONLYOFFICE iframe / DocumentServer 下打开同一 docx 两个 tab 和另一个 docx,验证三者 sessionId 均不同、同文档双 tab 共享 docKey 但使用不同随机 salt、`selection.get` 可各自回收、scope=A 显式调用 B session 返回 403、scope=B 授权 dry-run 返回 200。`task518` 已继续扩展为非 dry-run 写入 B 并导出 A/B 内容验证不串台,截图保存在 `tmp/task518-onlyoffice-real-iframe-session-scope-smoke/screenshots/office-a-after-write.png` 与 `office-b-after-write.png`。`task523-page-ai-onlyoffice-real-target-session-smoke.js` 已补齐 Page AI target picker 到 `onlyofficeSessionId` 的真实 UI 绑定,截图保存在 `tmp/task523-page-ai-onlyoffice-real-target-session-smoke/screenshots/`。
|
||||
|
||||
`task518` 已把 Office 主文档加载噪音分类为三类:bridge plugin translation 404、ONLYOFFICE 内置插件噪音、主文档加载失败。smoke 会断言 bridge session 注册和 command loop 正常,并把 `errorCode=-18` 或 editor 未 ready 归为主文档失败,避免把打不开文档误判为插件噪音。
|
||||
|
||||
补充验证矩阵:
|
||||
|
||||
- `task515-onlyoffice-live-scope-http-smoke.js`:覆盖缺 explicit session、scope mismatch、缺 scope 和授权 dry-run。
|
||||
- `task516-onlyoffice-bridge-multisession-browser-smoke.js`:覆盖 A/B bridge session token、`docKey/pageOrigin` 元数据、command queue、result 回收互不串台,以及 `session/current` / `session/close`。
|
||||
- `task517-onlyoffice-bridge-plugin-direct-smoke.js`:覆盖 mock `Asc.plugin` 下 plugin index 注册、`docKey/pageOrigin` 透传和 command loop。
|
||||
- `task518-onlyoffice-real-iframe-session-scope-smoke.js`:覆盖真实 ONLYOFFICE iframe / DocumentServer 下插件 autostart、同文档双 tab session 隔离、A/B session command 回收、`resource:onlyoffice` scope mismatch 403、授权 scope dry-run、授权非 dry-run 写入 B 后导出验证 A 不含 marker / B 含 marker。
|
||||
- `task523-page-ai-onlyoffice-real-target-session-smoke.js`:覆盖真实文档页打开 Office resource tab、等待 iframe bridge ready、通过 Page AI target picker 选择 Office target,并验证 live `onlyofficeSessionId` 写入 run payload。
|
||||
Reference in New Issue
Block a user