56 lines
8.7 KiB
Markdown
56 lines
8.7 KiB
Markdown
# Rust Host v1 预览契约
|
||
|
||
状态:Rust 核心测试、clippy、Tauri 工程编译及 Windows GNU 开发可执行文件构建通过。**尚无可发布安装包,新标题栏仍待原生界面实测**。不将开发构建等同 D01–D08 全部通过。
|
||
|
||
## 命令
|
||
|
||
只允许本地 `main` WebView 使用 capability。不存在通用 shell、任意路径打开、任意 HTTP 转发或明文凭据读取命令。目录授权由原生目录选择器完成。
|
||
|
||
| 命令 | 参数 / 返回 |
|
||
| --- | --- |
|
||
| `host_capabilities` | protocol=1,workspace/credentials=true;core 随进程状态返回;sync/extensions=false |
|
||
| `core_request_prepare` | timeout_ms(1–600000),返回一次性 request_id;最多 64 个待执行/在途请求,默认前端超时 30000 ms |
|
||
| `core_request` | request 对象含 requestId、method、path、body/bodyBase64、contentType、idempotencyKey;必须使用未过期的预登记 ID 且仅执行一次。代理认证 Sidecar 的 `/health` 与 `/api/*`,不接受前端鉴权头 |
|
||
| `core_request_cancel` | request_id;取消未发送的预登记项或终止在途 HTTP Future,重复取消无副作用 |
|
||
| `workspace_choose` | 原生选择,取消返回 null;成功返回 vault_id/path/name |
|
||
| `workspace_open` | 只允许重开应用数据目录中已持久化授权的规范化路径 |
|
||
| `workspace_recent` | 最近 20 个用户主动选择的 Vault;只保存身份、名称和路径 |
|
||
| `workspace_revoke` | 释放当前 Vault;不删除用户内容 |
|
||
| `workspace_tree` | Markdown 与目录树;file_id/path/hash/revision/deleted/is_folder |
|
||
| `workspace_read` | path,返回条目与 UTF-8 content |
|
||
| `workspace_write` | path、expected(SHA-256)、content;返回新条目 |
|
||
| `workspace_operation` | vault_id、operation_id;返回 pending/committed/conflict 与提交时条目,未知 ID 返回 null |
|
||
| `workspace_rename` | path、destination、expected;文件 ID 保持不变 |
|
||
| `workspace_delete` | path、expected;正文保存在 `.ainote/trash` |
|
||
| `workspace_mkdir` | path,相对当前授权 Vault |
|
||
|
||
当前错误通过 Tauri rejection 返回稳定 code,前端 `DesktopError` 保留该 code。主要 code 为 REVISION_CONFLICT、RECOVERY_CONFLICT、UNSAFE_PATH、PATH_CONFLICT、VAULT_ALREADY_OPEN、SCHEMA_INCOMPATIBLE、ATOMIC_REPLACE_FAILED。常规 Core 请求新增 REQUEST_CANCELLED、REQUEST_TIMEOUT 及预登记错误;前端取消/超时错误带 request_id 和 outcome(not_sent/unknown)。已经发送的写入不能推断回滚,不自动重试;按业务 operation_id 确认提交结果的完整链路仍待实现。
|
||
|
||
凭据保险库解锁前取得独立 `.lock` 文件的 OS 排他锁,持有至手动锁定、错误后锁定或实例销毁。其他实例返回 CREDENTIALS_BUSY,不读取旧快照后继续覆盖写入;错误口令释放临时锁,进程退出由 OS 释放。Windows 禁止在持锁期间替换该锁文件。
|
||
|
||
Windows 使用独立隐藏窗口注册 WTS 会话通知,锁屏、注销及本地/远程会话断开立即增加凭据撤销代际。新解析和新修改检查该代际,不等待解锁 KDF 的 Mutex;解锁过程中发生撤销则解锁失败。后台清理加密会话,系统解锁不会自动解锁凭据库。通知注册失败时凭据解锁返回 SESSION_MONITOR_UNAVAILABLE,但本地笔记继续可用。设置页每 500 ms 刷新真实锁定状态。
|
||
|
||
`credentials_backup` 不接受路径参数,以原生保存窗口选择新的 `.onxcred` 文件,只导出加密快照且拒绝覆盖已有文件。`credentials_restore(password)` 通过原生文件选择和原生确认对话框恢复,要求当前保险库已锁定。先验证口令及每条凭据,再保留恢复前的加密文件并原子替换;失败不覆盖现有库,成功后仍保持锁定。口令对应备份创建时的口令,不能通过备份绕过口令遗失。两项命令均不返回秘密或文件内容。
|
||
|
||
## 写入及恢复
|
||
|
||
Workspace schema 2 新增持久操作回执。`workspace_write` 可选 operation_id(UUID),同 ID、同载荷重放返回原提交条目;不同载荷返回 OPERATION_PAYLOAD_CONFLICT。回执与文件元数据、outbox 在同一 SQLite 事务提交,即使之后再次编辑,查询仍返回对应操作的原始结果。schema 1 升级前用 SQLite VACUUM INTO 保存一致备份;旧 schema 1 Host 拒绝写入 schema 2。
|
||
|
||
Core 的 `workspace.list/read/write/mutate/operation` RPC 通过受控管道转发,严格拒绝未知字段并校验 Host HTTP 请求捕获的 vault_id。切换或撤销工作区后旧任务返回 VAULT_PERMISSION_CHANGED。普通 HTTP 与 SSE 均由 Rust 添加工作区头,WebView 不能指定。Core 笔记 CRUD 不再写入 unbound-vault,也不从旧 Core 笔记索引回退读取;Markdown 元数据随正文保存,笔记 ID 使用 Rust file_id。当前 Core 笔记 RPC 单篇上限 1 MiB,管道帧上限 8 MiB;大媒体传输与完整取消提交确认另行实现,不宣称已满足完整 A-03。
|
||
|
||
桌面检索与任务使用 Core 数据目录中的 `vault-state/<vault_id>/core.sqlite3`,不同 Vault 不共享笔记/向量/任务行。该库含持久任务,不能作为缓存整体删除。搜索前通过 Host 扫描摘要并事务更新全文投影,删除与修改使旧向量失效;向量重建通过 Host 读取正文并保持稳定 file_id。模型配置和凭据仍属设备配置,不随笔记库路由。没有授权 Vault 的知识请求明确失败,不回退全局索引。旧版无归属的 Core 任务不会自动指派给任意 Vault,其迁移入口仍待完成。
|
||
|
||
OS 文件锁配合 Rust Mutex 维持单实例 Vault 写入。Web `serialized_vault_mutation` 使用同一 OS 文件锁;发现 `.ainote/host.sqlite3` 后拒绝 Web 写入,不自动降级。已有个人 Vault 不会被测试读取或迁移。
|
||
|
||
保存前对比实际磁盘 SHA-256,先持久化包含内容的 journal,再同目录临时文件刷盘和替换,最后提交元数据及 outbox。文件已替换但数据库未提交时,启动恢复补齐同一 operation_id。摘要不匹配则保留 journal 冲突及外部正文。remote origin 不再次入 outbox。outbox 目前只持久化,**尚无上传/拉取循环**。
|
||
|
||
移动和删除另有 file_ops 日志;目标或回收正文刷盘后才删除来源,数据库失败可重放。Windows reparse point(包括 junction)、越界路径、保留目录和设备名被拒绝。最近 Vault 授权保存在应用数据目录的独立 SQLite 中,使用事务更新且不包含正文;任意路径不能绕过目录选择直接加入。大小写重命名暂报 PATH_CONFLICT,UNC 不支持;附件树、多窗口共享、目录移动/删除、稳定外部重命名识别、监听去重及完整恢复 UI 尚未实现。
|
||
|
||
本地恶意进程仍可能在路径校验与系统调用间改变文件系统;该预览不是 OS 沙箱。发布前须补句柄级路径固定及突破测试、磁盘满/掉电故障注入、真实 WebView 交互、性能门禁。
|
||
|
||
## 前端与发布
|
||
|
||
Web 模式沿用现有服务。Tauri Workspace Service 调用原生命令;Host 自动启动受认证的 Core,使用随机端口和管道交换会话;Core 不可用时返回稳定错误码。SSE 使用 `core_stream`/`core_stream_cancel`,凭据命令提供状态、解锁、手动锁定、改密及原生导入;细节与未完成项见[生产化实施记录](../development/OpenNexus生产化实施进度-2026-09-08.md)。桌面窗口关闭系统装饰,统一由应用标题栏提供拖动、最小化、最大化/还原及关闭;窗口命令只授予本地 `main` WebView。关闭请求先尝试保存,冲突或保存失败时保持窗口。标题栏下的完整应用菜单复用 `editorCommandService`,主题菜单直接调用统一主题 Store;功能页使用 `feature-page`、`feature-header`、`panel` 等主题扩展点,确保自定义主题同时作用于编辑器与应用页面。原生菜单事件和可见“段落”菜单复用 `editor.import-note-properties`;仅在源码模式、已打开笔记且无冲突时启用,转换作为单次编辑器历史事务执行。
|
||
|
||
默认 `bundle.active=false`,新增 `tauri.bundle.conf.json` 配置 Core 资源及 NSIS 目标,尚无自动更新或签名安装包。release Host 前必须执行 `uv run --directory backend --group packaging python ../scripts/build-core.py` 生成并嵌入 Core 摘要清单。开发命令为前端 `pnpm dev` 与 `cargo run --features desktop`;生产 EXE 必须在 `frontend` 目录执行 `pnpm desktop:build`,由 Tauri CLI 先构建并嵌入前端资源。不要用普通 `cargo build --release` 代替该命令,否则 Rust Host 会更新但 WebView 仍可能携带旧资源。需要对应平台 C++ 工具链和 WebView;本次 Windows 已使用系统 `x86_64-pc-windows-gnu` 工具链构建,仍不替代 MSVC 或其他平台验证。
|