Persist PageTree expand state via control-plane view-state and align chevron/DOM with restored expansion; keep Sidex-style shallow page-tree scan and drop the unused recursive scanner that only added cargo noise. Add password vault workbench routes/runtime/skill/CLI, split page_ai_pi into a module package, and retire Hermes/ACP/OpenHub recycle + root harness evidence from the index while gitignoring recycle and local diag dumps. Archive superseded design/bugs docs under old/, point architecture at ARCHITECTURE.md, and refresh smokes for Pi S1–S7, vault, and editor regressions so the working tree can stay clean.
431 lines
19 KiB
Markdown
431 lines
19 KiB
Markdown
# [recycle] 3-25 Local Folder MinerU OCR Sidecar Checklist v1
|
||
|
||
> 创建时间:2026-05-29
|
||
> 状态:`process`
|
||
> Owner:03-rust-web / local-folder resource runtime
|
||
>
|
||
> 2026-06-01 复核:后端 mock 闭环已落地 `local_ocr.rs` 与 OCR route;真实 MinerU HTTP client 已补本地 HTTP mock 成功路径测试;resource tab 图片/PDF OCR 工具条、附件/File Tree 资源菜单入口和 `task526` UI smoke 已补。active job store、`local_ocr.job.updated` realtime event、全局任务抽屉和 AI 资源上下文读取 OCR sidecar 尚未落地。本文继续保持 `process`,不得被本轮 Page AI / OnlyOffice / ChatOnly 收口误归档。
|
||
|
||
## 背景
|
||
|
||
当前 mnote local-first 主线中,本地 Markdown 和同目录资源是默认数据真相。本地图片 / 附件上传已通过 `/api/local-folder/assets/upload` 写入 Markdown 文件附近,并返回 `sourcePath` / `attachmentRef`。现在需要给图片和图片型 PDF 增加 OCR 能力,识别引擎使用 MinerU API。
|
||
|
||
OCR 结果不应默认写进用户正文,也不应只存在 `.mnote` 私有缓存里。用户希望 OCR 附件位于当前 Markdown 文件相同目录下,并用单独文件夹承载,因为一个 Markdown 页面可能对应多个 OCR 文件。
|
||
|
||
## 目标
|
||
|
||
- 对 local-folder 图片和图片型 PDF 提供手动触发 OCR。
|
||
- 使用 MinerU API 识别本地文件,生成 Markdown OCR 结果。
|
||
- OCR 结果作为页面旁路资源落盘到当前 Markdown 同目录的 `{pageStem}.ocr/` 文件夹。
|
||
- OCR 文本默认作为资源 sidecar 被搜索、资源面板和后续 AI 上下文消费,不自动污染正文。
|
||
- 支持用户显式把某个 OCR 结果插入当前正文。
|
||
- 提供全局 OCR 任务进展入口,让用户离开当前资源后仍能看到 OCR 是否完成、失败或需要重试。
|
||
- 保持 local-first 可迁移性:OCR Markdown 文件本身可读、可备份、可编辑;`.mnote` 索引只作为缓存和状态加速。
|
||
|
||
## 非目标
|
||
|
||
- 不做全 workspace 自动 OCR。
|
||
- 不默认把 OCR 文本追加到页面正文。
|
||
- 不把 MinerU token 打印到日志、前端 payload 或用户可见错误里。
|
||
- 不在前端直接调用 MinerU API。
|
||
- 不把 OCR 文件当成普通页面加入 Page Tree。
|
||
- 不为 cloud / Convex / remote source 设计默认 OCR 主路径;第一阶段只覆盖 local-folder。
|
||
- 不承诺精确百分比进度;MinerU API 第一阶段按阶段型状态展示。
|
||
- 不把任务进展做成前端定时轮询主链;优先走现有 realtime / WS / SSE 事件。
|
||
|
||
## 文件布局
|
||
|
||
假设当前页面为:
|
||
|
||
```text
|
||
docs/Page.md
|
||
```
|
||
|
||
附件可能为:
|
||
|
||
```text
|
||
docs/Page.assets/photo.png
|
||
docs/Page.assets/spec.pdf
|
||
```
|
||
|
||
OCR 结果目录固定为:
|
||
|
||
```text
|
||
docs/Page.ocr/
|
||
```
|
||
|
||
OCR 结果文件示例:
|
||
|
||
```text
|
||
docs/Page.ocr/photo.png.ocr.md
|
||
docs/Page.ocr/spec.pdf.ocr.md
|
||
```
|
||
|
||
同一页面下存在同名来源文件时,用来源 root-relative path、文件大小和 mtime 派生短 hash:
|
||
|
||
```text
|
||
docs/Page.ocr/photo.png-8f3a21.ocr.md
|
||
```
|
||
|
||
## OCR Markdown frontmatter
|
||
|
||
OCR Markdown 是 OCR 正文真相,必须能脱离 `.mnote` 索引独立说明来源。
|
||
|
||
```markdown
|
||
---
|
||
mnote_ocr_version: 1
|
||
provider: mineru
|
||
model_version: vlm
|
||
owner_document: ./Page.md
|
||
source_path: ./Page.assets/photo.png
|
||
source_root_relative_path: docs/Page.assets/photo.png
|
||
source_size: 123456
|
||
source_mtime_ms: 1760000000000
|
||
status: done
|
||
created_at: 2026-05-29T12:00:00+08:00
|
||
updated_at: 2026-05-29T12:00:00+08:00
|
||
---
|
||
|
||
识别文本...
|
||
```
|
||
|
||
字段口径:
|
||
|
||
- `owner_document`:相对 OCR 文件所在目录到 owner Markdown 的相对路径。
|
||
- `source_path`:相对 owner Markdown 所在目录的来源附件路径,和正文中的附件引用口径保持一致。
|
||
- `source_root_relative_path`:相对 workspace root 的来源路径,用于稳定查找和索引。
|
||
- `source_size` / `source_mtime_ms`:用于判断 OCR 是否 stale。
|
||
- `status`:`done`、`failed` 或 `stale`。`queued/running` 只写入 `.mnote/ocr-index.json`,避免半成品 OCR 文件被误读。
|
||
|
||
## `.mnote` 索引
|
||
|
||
`.mnote/ocr-index.json` 是状态缓存,不是 OCR 正文真相。
|
||
|
||
```json
|
||
{
|
||
"version": 1,
|
||
"entries": {
|
||
"docs/Page.assets/photo.png": {
|
||
"ownerDocumentId": "local-md:docs~2FPage.md",
|
||
"ownerDocumentPath": "docs/Page.md",
|
||
"sourceRootRelativePath": "docs/Page.assets/photo.png",
|
||
"ocrRootRelativePath": "docs/Page.ocr/photo.png.ocr.md",
|
||
"provider": "mineru",
|
||
"modelVersion": "vlm",
|
||
"status": "done",
|
||
"sourceSize": 123456,
|
||
"sourceMtimeMs": 1760000000000,
|
||
"createdAtMs": 1760000000000,
|
||
"updatedAtMs": 1760000000000,
|
||
"plainTextPreview": "识别文本前 240 字"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
索引用途:
|
||
|
||
- 资源面板快速展示 OCR 状态。
|
||
- 搜索索引快速定位 OCR sidecar。
|
||
- 避免重复提交同一个未变化资源。
|
||
- 记录失败原因,但错误文本需要脱敏,不包含 token、预签名 URL 或完整外部响应体。
|
||
|
||
## 资源归属与树投影
|
||
|
||
- OCR 文件夹 `{pageStem}.ocr/` 应在 File Tree 中作为页面旁路资源文件夹出现。
|
||
- `{pageStem}.ocr/*.ocr.md` 不应作为普通 Markdown 页面进入 Page Tree。
|
||
- local search 不应把 OCR sidecar 当普通 Markdown 页面索引,否则会出现重复页面和错误导航。
|
||
- 搜索 OCR 命中时,应返回 owner page 作为结果,`hasOcr=true`,evidence 指向来源附件和 OCR sidecar。
|
||
- File Tree 可展示 OCR 文件,点击默认作为 Markdown resource tab 打开,不切换成页面文档。
|
||
|
||
## MinerU 调用边界
|
||
|
||
后端读取 MinerU token,前端不接触 token。
|
||
|
||
配置优先级:
|
||
|
||
1. `MNOTE_MINERU_API_TOKEN`
|
||
2. `MINERU_API_TOKEN`
|
||
3. 开发环境可选读取 `~/.hermes/.env` 中的 `MINERU_API_TOKEN`
|
||
|
||
第一阶段使用 MinerU `model_version=vlm`。
|
||
|
||
本地文件流程:
|
||
|
||
1. `POST https://mineru.net/api/v4/file-urls/batch` 申请上传地址。
|
||
2. 使用 `PUT` 把本地文件上传到预签名 URL。
|
||
3. 轮询 `GET /extract-results/batch/{batch_id}`。
|
||
4. 下载 `full_zip_url`。
|
||
5. 解压并提取结果 Markdown。
|
||
6. 写入 `{pageStem}.ocr/*.ocr.md`。
|
||
7. 更新 `.mnote/ocr-index.json`。
|
||
|
||
## 后端 API
|
||
|
||
### 创建或复用 OCR job
|
||
|
||
`POST /api/local-folder/ocr/jobs`
|
||
|
||
请求:
|
||
|
||
```json
|
||
{
|
||
"rootUri": "file:///mnt/Data1T/mnote-notes",
|
||
"documentId": "local-md:docs~2FPage.md",
|
||
"sourcePath": "Page.assets/photo.png",
|
||
"sourceRootRelativePath": "docs/Page.assets/photo.png",
|
||
"provider": "mineru",
|
||
"force": false
|
||
}
|
||
```
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"ok": true,
|
||
"job": {
|
||
"status": "done",
|
||
"ownerDocumentId": "local-md:docs~2FPage.md",
|
||
"sourceRootRelativePath": "docs/Page.assets/photo.png",
|
||
"ocrRootRelativePath": "docs/Page.ocr/photo.png.ocr.md",
|
||
"stale": false
|
||
}
|
||
}
|
||
```
|
||
|
||
第一阶段可以同步执行并在请求内返回最终状态;如果真实耗时过长,再升级为后台 job。同步版本必须设置合理超时,并让 UI 显示运行中状态。
|
||
|
||
### 查询 OCR 状态
|
||
|
||
`GET /api/local-folder/ocr/status?rootUri=...&sourceRootRelativePath=...`
|
||
|
||
返回 `.mnote/ocr-index.json` 中的状态,并重新对比来源文件 `size/mtime` 判断 `stale`。
|
||
|
||
### 查询 OCR 任务列表
|
||
|
||
`GET /api/local-folder/ocr/jobs?rootUri=...`
|
||
|
||
返回当前 root 下 active jobs 和最近完成 / 失败任务,用于全局任务栏首次渲染和刷新后恢复。
|
||
|
||
响应:
|
||
|
||
```json
|
||
{
|
||
"ok": true,
|
||
"jobs": [
|
||
{
|
||
"jobId": "ocr_1760000000000_abcd",
|
||
"fileName": "spec.pdf",
|
||
"ownerDocumentId": "local-md:docs~2FPage.md",
|
||
"ownerDocumentPath": "docs/Page.md",
|
||
"sourceRootRelativePath": "docs/Page.assets/spec.pdf",
|
||
"ocrRootRelativePath": "docs/Page.ocr/spec.pdf.ocr.md",
|
||
"status": "mineru_processing",
|
||
"stageLabel": "识别中",
|
||
"startedAtMs": 1760000000000,
|
||
"updatedAtMs": 1760000000000,
|
||
"finishedAtMs": null,
|
||
"stale": false
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
### 读取 OCR 文本
|
||
|
||
`GET /api/local-folder/ocr/read?rootUri=...&ocrRootRelativePath=...`
|
||
|
||
返回 OCR Markdown 文本、frontmatter 摘要、来源路径和 stale 状态。
|
||
|
||
### 插入 OCR 到正文
|
||
|
||
`POST /api/local-folder/ocr/insert`
|
||
|
||
只在用户显式触发时执行。默认插入为链接块:
|
||
|
||
```markdown
|
||
[OCR:photo.png](./Page.ocr/photo.png.ocr.md)
|
||
```
|
||
|
||
可选模式 `inlineSection` 插入正文段落:
|
||
|
||
```markdown
|
||
### OCR:photo.png
|
||
|
||
<!-- mnote:ocr-source ./Page.assets/photo.png -->
|
||
|
||
识别文本...
|
||
```
|
||
|
||
## UI 行为
|
||
|
||
- 编辑器图片 toolbar / 附件右键菜单增加 `OCR 识别`。
|
||
- File Tree 图片/PDF 资源右键菜单增加 `OCR 识别`。
|
||
- PDF preview / image resource tab 显示 OCR 状态和结果入口。
|
||
- 全局任务栏 / 任务抽屉显示运行中、完成、失败和 interrupted 的 OCR 任务。
|
||
- 状态文案只表达:未识别、排队中、上传中、识别中、写入中、已识别、来源已变化、识别失败、已中断。
|
||
- 对 `stale` 结果展示“重新识别”操作,不自动覆盖旧 OCR 文件,除非用户确认或传 `force=true`。
|
||
- OCR 结果打开在 resource tab,不切到普通文档页面。
|
||
|
||
## 搜索与 AI 消费
|
||
|
||
- `includeOcr=false` 时不搜索 OCR sidecar。
|
||
- `includeOcr=true` 时,搜索 OCR 文本并返回 owner page。
|
||
- 搜索 evidence 包含:
|
||
- `kind: "ocr"`
|
||
- `sourceRootRelativePath`
|
||
- `ocrRootRelativePath`
|
||
- `snippet`
|
||
- 后续 `image_read` / Page AI attachment context 可以读取 OCR sidecar,优先返回已存在 OCR 文本,不让 agent 重复调用 OCR。
|
||
|
||
## 任务进展与全局入口
|
||
|
||
OCR 是慢任务,提交后必须有全局可见状态,不应只依赖 toast 或当前 resource tab。
|
||
|
||
第一阶段进度采用阶段型状态:
|
||
|
||
```text
|
||
queued -> uploading -> mineru_processing -> downloading -> writing_sidecar -> done
|
||
```
|
||
|
||
失败和中断状态:
|
||
|
||
```text
|
||
failed
|
||
interrupted
|
||
stale
|
||
```
|
||
|
||
状态含义:
|
||
|
||
- `queued`:任务已创建,等待执行。
|
||
- `uploading`:正在上传原始图片/PDF 到 MinerU 预签名地址。
|
||
- `mineru_processing`:MinerU 正在识别。
|
||
- `downloading`:正在下载 MinerU 结果包。
|
||
- `writing_sidecar`:正在写入 `{pageStem}.ocr/*.ocr.md` 和 `.mnote/ocr-index.json`。
|
||
- `done`:OCR sidecar 已写入。
|
||
- `failed`:任务失败,可重试。
|
||
- `interrupted`:mnote-web 进程或任务 worker 中断,不能确认完成,可重试。
|
||
- `stale`:来源文件在 OCR 后发生变化。
|
||
|
||
后端维护一个运行时 active job store,并把每次状态变更写入 `.mnote/ocr-index.json`。页面刷新后,已完成、失败、stale 和 interrupted 状态可以从磁盘恢复;正在运行中的内存任务如果因进程重启丢失,应在下次读取时标记为 `interrupted`,由用户重试。
|
||
|
||
状态变化通过现有 realtime / WS / SSE 事件链路广播,不在前端叠加 `setInterval` 轮询主链。事件示例:
|
||
|
||
```json
|
||
{
|
||
"type": "local_ocr.job.updated",
|
||
"jobId": "ocr_1760000000000_abcd",
|
||
"rootUri": "file:///mnt/Data1T/mnote-notes",
|
||
"ownerDocumentId": "local-md:docs~2FPage.md",
|
||
"sourceRootRelativePath": "docs/Page.assets/spec.pdf",
|
||
"ocrRootRelativePath": "docs/Page.ocr/spec.pdf.ocr.md",
|
||
"status": "mineru_processing",
|
||
"stageLabel": "识别中",
|
||
"updatedAtMs": 1760000000000
|
||
}
|
||
```
|
||
|
||
前端需要两类展示:
|
||
|
||
- 资源局部状态:图片/PDF resource tab、附件菜单、File Tree 行显示当前 OCR 状态。
|
||
- 全局任务栏 / 任务抽屉:底栏或右上角显示 `OCR 2` / `1 个任务进行中`。点开后列出文件名、所属页面、阶段、开始时间、完成/失败状态,以及“打开 OCR”“重试”等操作。
|
||
|
||
第一阶段不强制支持取消。若 MinerU 任务 API 后续提供可靠取消,再补 `cancel` 动作。
|
||
|
||
## 隐私与安全
|
||
|
||
- OCR 必须由用户手动触发。
|
||
- UI 首次触发时应明确提示:文件会发送到 MinerU API。
|
||
- 后端只允许读取 `rootUri` 授权根内文件,禁止绝对路径和 `..` 越界。
|
||
- 日志不记录 token、预签名 URL、完整外部错误响应和 OCR 正文全文。
|
||
- 失败状态写入简短错误码和脱敏消息。
|
||
|
||
## 实施 Checklist
|
||
|
||
- [x] 后端:新增 MinerU client,支持本地文件上传、轮询、结果 zip 下载和 Markdown 提取。
|
||
- [x] 后端:新增 OCR 路由模块,提供 job/status/read/insert API。(当前 insert 只支持 link 模式)
|
||
- [x] 后端:新增 OCR active job store,记录 queued/uploading/mineru_processing/downloading/writing_sidecar/done/failed/interrupted/stale。
|
||
- [x] 后端:OCR 状态变化写入 `.mnote/ocr-index.json` 并广播 `local_ocr.job.updated` 事件。
|
||
- [x] 后端:提供 OCR jobs list API,用于全局任务栏刷新后恢复。
|
||
- [x] 后端:实现 `{pageStem}.ocr/` 路径规划、文件名冲突处理和 UTF-8 OCR Markdown 写入。
|
||
- [x] 后端:实现 `.mnote/ocr-index.json` 读写、stale 检测和脱敏错误记录。
|
||
- [x] 后端:扩展 local-folder 文件分类,让 `{pageStem}.ocr/*.ocr.md` 不进入 Page Tree 普通页面。
|
||
- [x] 搜索:扩展 local search index,`includeOcr=true` 时索引 OCR sidecar 并返回 owner page。
|
||
- [x] UI:在附件右键菜单、File Tree 资源菜单和资源 tab 增加 OCR 识别入口。
|
||
- [x] UI:展示 OCR 状态、stale、失败和重新识别动作。
|
||
- [x] UI:新增全局 OCR 任务栏 / 任务抽屉,显示任务阶段、所属页面、打开 OCR、重试。
|
||
- [x] UI/API:增加“插入 OCR 链接到正文”动作。(可选“插入 OCR 正文段落”不作为本阶段验收项,后续需要时另拆增强稿)
|
||
- [x] AI:让 image/PDF 资源上下文优先读取已有 OCR sidecar。
|
||
- [x] 测试:Rust 单测覆盖路径规划、frontmatter、索引读写、stale、越界拒绝。
|
||
- [x] 测试:Rust route 测试覆盖无 token、真实 MinerU HTTP mock 成功、模拟失败和脱敏错误。
|
||
- [x] 测试:local search 测试覆盖 OCR 命中返回 owner page,OCR sidecar 不作为普通页面。
|
||
- [x] Smoke:浏览器覆盖图片/PDF 手动 OCR、全局任务栏状态、打开 OCR resource tab、搜索 OCR 命中、插入 OCR 链接。
|
||
- [x] 文档:补充 `scripts/TESTING_REFERENCE.md` 中 OCR smoke 基线。
|
||
|
||
## 验收标准
|
||
|
||
- 本地图片或图片型 PDF 可被用户手动提交 MinerU OCR。
|
||
- OCR 结果落在 owner Markdown 同目录的 `{pageStem}.ocr/` 下,文件为 UTF-8 Markdown。
|
||
- `.mnote/ocr-index.json` 删除后,仍能从 OCR Markdown frontmatter 重建核心绑定关系。
|
||
- OCR 文件不会污染 Page Tree,也不会作为普通页面搜索结果出现。
|
||
- 搜索 OCR 文本时返回 owner page,结果标记 `hasOcr=true`。
|
||
- 用户未显式选择插入时,页面正文不发生变化。
|
||
- 用户提交 OCR 后,即使离开当前资源,也能在全局 OCR 任务栏看到阶段状态;完成后可打开 OCR,失败或中断后可重试。
|
||
- 所有外部 API token 和预签名 URL 均不出现在日志、前端 payload 或错误响应中。
|
||
|
||
## 2026-06-01 后端 mock 闭环
|
||
|
||
已落地 `rust/crates/mnote-web/src/routes/local_ocr.rs` 与 route 注册,第一刀只承诺后端 mock 闭环:`provider=mock` 可同步生成 `{pageStem}.ocr/*.ocr.md`,写入 `.mnote/ocr-index.json`,提供 jobs/status/read;当时 `provider=mineru` 尚未执行真实外部调用,缺 token 时返回 `mineru_token_missing`,有 token 时返回 `mineru_runtime_not_enabled`。
|
||
|
||
同时已把 OCR sidecar 从 Page Tree 普通 Markdown 扫描中排除,并扩展 local search:`includeOcr=false` 不命中 OCR 文本,`includeOcr=true` 返回 owner page,结果带 `hasOcr=true` 与 `ocrEvidence`。
|
||
|
||
验证:
|
||
|
||
- `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 local_search_ocr -- --test-threads=1`
|
||
|
||
2026-06-01 续补:
|
||
|
||
- `local_ocr` route 测试新增来源路径越界、非图片/PDF 来源和 mock 失败脱敏 response 形态覆盖。
|
||
- `local_ocr` route 测试新增缺 MinerU token response 覆盖:`mineru_token_missing`。
|
||
- `local_ocr` route 测试新增 token 存在但真实 runtime 未接入 response 覆盖:`mineru_runtime_not_enabled`,避免把 mock OCR 闭环误报为真实 MinerU 能力。该旧口径已在后续真实后端 runtime 补齐后由 HTTP mock 成功路径测试替代。
|
||
- 新增 `POST /api/local-folder/ocr/insert`,当前只支持 `mode=link`,显式把 OCR sidecar 链接追加到 owner Markdown;`local_ocr_insert_route_appends_explicit_ocr_link` 已覆盖。
|
||
|
||
2026-06-01 浏览器 API smoke 续补:
|
||
|
||
- 新增 `scripts/task526-local-folder-ocr-api-smoke.js`,在真实浏览器登录态页面内通过 `fetch` 串起 `POST /api/local-folder/ocr/jobs`、`status`、`read`、`jobs`、`/api/search/documents includeOcr=true` 和 `POST /api/local-folder/ocr/insert`。
|
||
- 该 smoke 固定使用 `provider=mock`,不触碰真实 MinerU token、上传、轮询、zip 下载和 Markdown 提取链路。
|
||
- 已验证 mock OCR sidecar 落盘、`.mnote/ocr-index.json` jobs/status/read 可读、`includeOcr=false` 不命中 OCR 文本、`includeOcr=true` 返回 owner page 且带 `hasOcr/ocrEvidence`、显式 insert 才向 owner Markdown 追加 OCR 链接。
|
||
- 已通过:
|
||
- `node --check scripts/task526-local-folder-ocr-api-smoke.js`
|
||
- `MNOTE_UI_BASE_URL=http://127.0.0.1:3301 MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3301 node scripts/task526-local-folder-ocr-api-smoke.js`
|
||
- `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 local_search_ocr -- --test-threads=1`
|
||
|
||
2026-06-01 后端真实 MinerU runtime 续补:
|
||
|
||
- `local_ocr.rs` 已补 `mineru_api_base_url`、`mineru_poll_interval`、`mineru_max_polls` 配置函数。
|
||
- `provider=mineru` 后端路径已接入申请上传 URL、PUT 上传、轮询 batch 结果、下载 zip、提取 Markdown。
|
||
- 新增 `local_ocr_jobs_route_runs_mineru_runtime_against_http_mock`,用本地 HTTP mock 覆盖真实 client 合同,不访问外网。
|
||
- 已通过:
|
||
- `cargo test --manifest-path rust/Cargo.toml -p mnote-web local_ocr -- --test-threads=1`
|
||
|
||
2026-06-01 任务链与 AI context 收口:
|
||
|
||
- 后端在 `AppState` 增加 OCR active job store 和 `local_ocr_job_tx` broadcast;`POST /api/local-folder/ocr/jobs` 会在 queued / uploading / mineru_processing / downloading / writing_sidecar / done / failed 阶段更新 `.mnote/ocr-index.json`,并通过 `/api/local-folder/events` 发出 `local_ocr.job.updated`。
|
||
- 资源 tab 增加全局 OCR 任务 dock / drawer;任务抽屉从 jobs API 恢复历史状态,并通过 `local_ocr.job.updated` 事件更新,支持打开 OCR 和失败/stale 重试。
|
||
- Page AI active image/PDF resource target 会在发 run 前读取已有 OCR sidecar,把 `mnote.local_ocr_context.v1` 放入 active_editor contextRef、targetPackage、currentFile 和 primary target。
|
||
- 已通过:
|
||
- `node --check rust/crates/mnote-web/browser/document-resource-tab-runtime.js`
|
||
- `node --check rust/crates/mnote-web/browser/sidebar-page-ai-runtime.js`
|
||
- `node --check rust/crates/mnote-web/browser/sidebar-page-ai-target-runtime.js`
|
||
- `node --check scripts/task526-local-folder-ocr-api-smoke.js`
|
||
- `node --check scripts/task520-page-ai-raw-resource-target-smoke.js`
|
||
- `cargo fmt --check --all`
|
||
- `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 local_search_ocr -- --test-threads=1`
|
||
- `MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3000 node scripts/task526-local-folder-ocr-api-smoke.js`
|
||
- `TASK520_OCR_CONTEXT=1 MNOTE_UI_BASE_URL=http://127.0.0.1:3000 MNOTE_WEB_SMOKE_BASE_URL=http://127.0.0.1:3000 node scripts/task520-page-ai-raw-resource-target-smoke.js`
|