138 lines
10 KiB
Markdown
138 lines
10 KiB
Markdown
# LineUp Tauri Reference Host
|
||
|
||
这是 LineUp Mini Runtime 的第一版 Tauri 2 Reference Host。它独立于当前 `upstream/tangsengdaodao-android/` 快速实验工程,不替换或修改现有 Android 验证路径。
|
||
|
||
## 已实现的最小闭环
|
||
|
||
- 可信 Host 前端:AppServer 地址、手机号/验证码登录、退出;
|
||
- AppServer 交互:`/login`、`/messages/send`、`/messages/sync`;
|
||
- 用户消息本地即时回显与送达状态;
|
||
- HTTP 同步游标:首次 `0`、后续最后序号 `+ 1`;
|
||
- `lineup.v1.text`、`agent.status`、`agent.progress`、`error` 的基础 Renderer;
|
||
- `marked + DOMPurify` 的 GFM Markdown 安全渲染;
|
||
- Tauri 2 Rust Host、capability 文件与桌面窗口配置。
|
||
|
||
AppServer 已配置只允许 `tauri://localhost`、`https://tauri.localhost`、`http://tauri.localhost` 三个 Tauri Host origin 跨源调用。若产品使用新的 Tauri origin 或独立 Web 客户端,应先在 `lineup-app-server/configs/lineup.yaml` 的 `client.allowedOrigins` 显式加入,不能放开任意 Origin。
|
||
|
||
macOS 的 `src-tauri/Info.plist` 为当前 Tailscale / 私网 HTTP AppServer 配置了 `NSAllowsArbitraryLoadsInWebContent`。该例外仅作用于 Host 的 WKWebView 内容请求,使其能访问类似 `http://100.x.y.z:8090` 的地址,不放宽 Rust 原生网络层;待所有 AppServer 都迁移到 HTTPS 后应移除。
|
||
|
||
`ui.open / patch / close` 和 `app.call` 已被协议层识别,但目前安全降级为可见提示;它们是下一阶段 Mini Runtime Surface Host 与 Capability Registry 的实现范围,不能在当前 Host 页面中直接执行 Agent JavaScript 或直接授予设备能力。
|
||
|
||
## Milestone 0 当前行为基线
|
||
|
||
本节记录 Runtime 重构前已经由 Mac 开发态验证的行为。它是 M0 的回归基线,不代表最终模块结构;正式阶段任务和准入门槛见 [App Layer 架构方案 §9.1](../../设计/02.正式方案/lineup-app-layer-architecture.md#91-阶段任务清单与硬性准入门槛)。
|
||
|
||
| 范围 | 当前行为 | 当前实现位置 | 重构后必须保持 |
|
||
|---|---|---|---|
|
||
| 登录 | 用户输入 AppServer 地址、手机号、验证码;登录请求 10 秒超时;地址仅保存到 localStorage | `src/main.ts` | 成功登录进入会话;失败原因对用户可见 |
|
||
| 会话 | 当前只有一个 Agent channel;退出清空页面内消息并停止同步 | `src/main.ts` | 会话状态必须可由 Store 管理,不能依赖 DOM |
|
||
| 发送 | 用户消息先本地显示,再调用 `/messages/send`;显示已发送或失败 | `src/main.ts` | 即时反馈、送达状态与失败可见性不退化 |
|
||
| 历史同步 | 首次从 cursor `0` 连续拉取到空页;之后以 `lastSeq + 1` 每 1.5 秒增量轮询 | `src/main.ts` | 保持包含式 cursor 语义,不能漏消息或无限热循环 |
|
||
| Agent 文本 | 将 `lineup.v1.text` 解码为 Markdown,使用 `marked + DOMPurify` 渲染 | `src/protocol.ts`、`src/main.ts` | GFM、安全净化和外链防护不退化 |
|
||
| Agent 状态 | `thinking` 显示临时指示器;其他状态更新顶栏 presence | `src/protocol.ts`、`src/main.ts` | 状态应更新已有状态项,而非无限追加气泡 |
|
||
| 进度和错误 | progress/error 目前以系统提示显示 | `src/protocol.ts`、`src/main.ts` | 迁移后至少保持可见,M1 再升级为正式卡片 |
|
||
| 未实现扩展 | `ui.open / patch / close` 与 `app.call` 仅安全降级为提示,绝不执行不可信脚本或原生能力 | `src/protocol.ts`、`src/main.ts` | 在 M2/M3 完成前始终保持拒绝执行 |
|
||
|
||
### M0 回归场景
|
||
|
||
每次迁移或拆分模块后,至少执行以下场景;其中 `R01` 为构建级检查,其余为 Mac 浏览器访问 Linux 开发 Host 的人工验收,直至 M0 建立自动化测试。
|
||
|
||
- **M0-R01:构建。** `npm run build` 通过 TypeScript 检查与 Vite 打包。
|
||
- **M0-R02:登录。** 使用 Tailscale AppServer 登录;成功切换到聊天页,错误地址/超时给出可理解提示。
|
||
- **M0-R03:历史追平。** 登录后 presence 从“正在同步消息”变为“已同步,等待消息”,已有 Agent 历史可见。
|
||
- **M0-R04:本地回显。** 发送普通文本后,用户气泡立即出现,随后显示已发送或发送失败。
|
||
- **M0-R05:Agent 回复。** Hermes 回复能够在未刷新页面时出现,并按 Markdown 安全渲染。
|
||
- **M0-R06:刷新恢复。** 刷新并重新登录后,历史仍可追平,不能重复无限渲染同一条 Agent 消息。
|
||
- **M0-R07:安全降级。** 收到未知 `lineup.v1.*` 类型、`ui.*` 或 `app.*` 请求时,页面不崩溃、不执行脚本/能力,并给出可见提示。
|
||
|
||
### 当前结构债务(M0 的改造对象)
|
||
|
||
`src/main.ts` 目前同时包含 App Shell、页面 DOM、登录、直接 HTTP `fetch`、会话 cursor、同步循环、协议到展示的映射和 renderer。M0 的目的不是改变上述用户行为,而是将它们迁入 `app-shell`、`transport`、`conversation-store`、`interaction-kernel` 和 `renderer-registry` 等独立边界;在 M0 准入前不新增 Surface 或 Capability 功能。
|
||
|
||
### M0-02 协议模型(已完成)
|
||
|
||
`src/protocol.ts` 是目前唯一允许把 Transport 原始 payload 转换成可信表现模型的入口。它定义了 `JsonValue`、`Actor`、严格 `Envelope`、`ConversationItem`、`UserAction`、`DeliveryState` 与 `ProtocolFallback`,并提供:
|
||
|
||
- `parseEnvelope(value)`:校验版本、消息类型、`id`、`conversation_id`、sender/target、timestamp 和 JSON payload;
|
||
- `parseEnvelopeJSON(raw)`:供不接受历史纯文本的 Transport / Kernel 路径把非法 JSON 明确归为 `invalid_json`;
|
||
- `decodeConversationItem(raw)`:保留历史纯文本作为 Markdown 的兼容行为;对于非法 LineUp envelope、未知类型和各类非法 payload,返回受控 fallback,绝不触发执行。
|
||
|
||
该文件不依赖 DOM、`fetch`、Tauri 或本地存储。Surface 与 Capability 在本阶段只校验其基础合约并降级显示;不加载 bundle,也不调用能力。下一项 M0-03 才会将此模型接入 Interaction Kernel 和 Renderer Registry。
|
||
|
||
### M0-03 Interaction Kernel 与 Renderer Registry(已完成)
|
||
|
||
`src/runtime/interaction-kernel.ts` 是 Transport 与表现层之间的唯一入口:它将原始同步/实时 payload 解码为 `ConversationItem`,对有有效 LineUp `id` 的消息实施有界去重,并将 Agent status 投影为可读取的 presence 快照。它不执行 `ui.*`、`app.*` 或用户动作。
|
||
|
||
`src/runtime/renderer-registry.ts` 只根据已验证的 `ConversationItem.kind` 分派已注册的可信 renderer;renderer 的输入只有表现项与 View context,不会获得 Transport 或 Capability 对象。当前聊天页已通过该 Registry 渲染同步进入的标准项。为了避免在 M0-03 跨阶段重写 UI,具体 DOM renderer 仍在 `main.ts`;M0-06 会把它们迁移为独立可信 renderer 模块。
|
||
|
||
## 本地命令
|
||
|
||
```bash
|
||
cd lineup-app/tauri
|
||
npm install
|
||
|
||
# 日常开发:启动 Vite 热更新 + 未打包的 Tauri 桌面壳
|
||
npm run desktop:dev
|
||
|
||
# 纯 Web 开发:Linux 开发机监听全部网卡,供 Mac 浏览器访问
|
||
npm run web:dev
|
||
|
||
# Mac 浏览器访问(经 Tailscale)
|
||
# http://100.121.118.116:1420
|
||
|
||
# 仅检查并构建前端静态文件
|
||
npm run build
|
||
|
||
# Linux:仅构建 Debian 包,避免为不需要的 AppImage 下载额外运行器
|
||
npm run tauri -- build --debug --bundles deb
|
||
|
||
# macOS(Apple Silicon / Intel):生成 .app 与 .dmg
|
||
npm run tauri build -- --debug
|
||
```
|
||
|
||
`npm run desktop:dev` 不生成 `.app`、`.dmg` 或安装包。前端 TypeScript / CSS / HTML 保存后会由 Vite 自动热更新;改动 `src-tauri/` 中的 Rust Host 代码时,Tauri 会重新编译并重启开发窗口。只有需要交付可安装文件时才执行 `tauri build`。
|
||
|
||
`npm run web:dev` 只运行同一份可信 Host Web UI,适合在浏览器中快速调试登录、消息和 Renderer。它监听 `0.0.0.0:1420`,Mac 通过 Tailscale 打开 `http://100.121.118.116:1420`,直接验证 Linux 工作区的 Vite 热更新;不需要为每次验证将源码同步到 Mac。它不具备 Tauri 原生能力,也不应作为第三方 Mini Runtime Surface 的安全验收环境。AppServer 仅对固定开发 Origin `http://127.0.0.1:1420` 和 `http://100.121.118.116:1420` 配置 CORS;若改动 Vite 端口或 Host 地址,必须同步收紧更新 AppServer 的 `client.allowedOrigins`,不得改为 wildcard。
|
||
|
||
本项目的 `tauri` 与 `check:rust` npm 脚本会自动识别 Linux x86_64、macOS Apple Silicon、macOS Intel 的 Rust stable toolchain,并加入 `PATH`。因此不要直接执行裸 `tauri build`;统一使用 `npm run tauri build -- --debug`。如 Rust toolchain 安装在其他位置,可临时覆盖:
|
||
|
||
```bash
|
||
RUST_TOOLCHAIN_BIN=/path/to/rust/bin npm run tauri build -- --debug
|
||
```
|
||
|
||
## 本机构建状态(2026-08-03)
|
||
|
||
- `npm run build`:已通过;
|
||
- Cargo/Tauri Rust crates:已下载并开始编译;
|
||
- Tauri Linux desktop build:已通过;debug 可执行文件和 Debian 包已生成;
|
||
- Android Spike:尚未开始。仍需要 Android NDK、Rust Android targets 与 Tauri Android 初始化。
|
||
|
||
Linux 桌面构建依赖以下系统开发库;本机已具备。新环境缺少时可安装:
|
||
|
||
```bash
|
||
sudo apt-get update
|
||
sudo apt-get install -y pkg-config libdbus-1-dev libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev
|
||
```
|
||
|
||
本机已生成的产物:
|
||
|
||
```text
|
||
src-tauri/target/debug/lineup-tauri
|
||
src-tauri/target/debug/bundle/deb/LineUp_0.1.0_amd64.deb
|
||
```
|
||
|
||
Tauri 构建产物位于 `src-tauri/target/`,已被 Git 忽略。图标源文件是 `src-tauri/icons/icon.svg`,其余 PNG/ICO/ICNS 与 Android/iOS 图标由 `npm run tauri icon src-tauri/icons/icon.svg` 生成。
|
||
|
||
## 目录边界
|
||
|
||
```text
|
||
tauri/
|
||
├── src/ # 可信 LineUp Host 前端
|
||
│ ├── main.ts # 会话 UI、AppServer transport、Renderer 调度
|
||
│ └── protocol.ts # 平台无关的 LineUp v1 → ConversationItem 解码
|
||
├── src-tauri/ # Tauri Rust Host 与 capability 配置
|
||
└── package.json # Vite、Tauri CLI 与前端依赖
|
||
```
|
||
|
||
第三方 Agent Surface 未来必须运行于独立隔离执行域,只能经 LineUp Mini Runtime 事件桥与 Capability Gateway 通信;不得访问 Tauri `invoke`、Host DOM、登录态或本机特权。
|