aps-agent/docs/architecture/desktop.md

92 lines
5.1 KiB
Markdown
Raw Permalink Normal View History

# 桌面端与 Web 双形态
> 对标 Codex:桌面安装后用户主目录出现 `~/.aps`;同一套 UI 也可纯 Web 部署。
## 目录约定(对标 Codex `~/.codex`)
桌面端安装到电脑后,**固定**写到用户主目录(不是安装目录):
| 系统 | 路径 |
| --- | --- |
| Windows | `%USERPROFILE%\.aps` → 如 `C:\Users\<user>\.aps` |
| macOS / Linux | `~/.aps` |
```
~/.aps/ # 本机应用数据(会话 / DB / Skill…)
├─ sessions/
│ └─ workspace.json # 项目元数据 + 话题会话 + 消息
├─ skills/
├─ data/ # world.json / master.db / knowledge…
├─ cache/ tmp/ logs/ packs/
└─ config.json
<用户自选工程目录>/ # 新建项目时指定;排产业务文件放这里
├─ 订单 / 物料 / 工艺 Excel…
└─ …
```
- **话题会话**:存在 `~/.aps/sessions/`,可不绑定项目(独立话题)。
- **工程项目**:可选;创建时指定 `workDir`,业务数据文件由用户放在该目录。
| 变量 | 含义 |
| --- | --- |
| `APS_MODE` | `desktop` \| `web`(默认 `web`) |
| `APS_HOME` | 显式主目录(覆盖默认) |
| `APS_SKILLS_PATH` | 单文件 skills.json(测试兼容) |
| `APS_WORLD_PATH` / `APS_DB_PATH` / … | 单项覆盖 |
`GET /api/system/paths`、`GET /api/skills` 的 `skillsDir` / `mode` 可查看当前解析结果。
## 开发命令
在**仓库根**、`apps/web` 或 `apps/desktop` 均可执行(脚本会自动定位仓库根):
```bash
# 建议先在仓库根装依赖
cd ../.. # 若当前在 apps/desktop
npm run bootstrap
npm run dev:web # FastAPI + Vite(浏览器)
npm run dev:desktop # FastAPI + Vite + Electron(数据 → ~/.aps)
# 也可拆开(仅仓库根):
npm run dev:server
npm run dev:ui
```
## 打包
```bash
npm run build:web # 产出 apps/web/dist —— 静态资源,部署到 Nginx/CDN,API 另部服务端
npm run build:sidecar # 固定 CPython + 哈希锁依赖 + PyInstaller + 冻结产物冒烟
npm run build:desktop # Web + Sidecar + electron-builder Windows NSIS 安装包
```
- **Web 部署**:只部署 `apps/web/dist` + 后端进程(uvicorn / 容器);`APS_MODE=web`。
- **桌面分发**:安装包内含 `resources/sidecar/aps-sidecar.exe` 及其私有运行库,不调用 PATH 中的 Python;首次运行创建 `~/.aps`,Skill 写入 `~/.aps/skills/<id>/`。
Sidecar 构建固定使用 uv-managed Windows x64 CPython 3.13.12。`packaging/requirements-sidecar.lock` 精确锁定全部直接和传递依赖及 wheel hash;构建时强制 `--only-binary :all:`,并在产物生成后执行 NumPy、Pandas、OR-Tools CP-SAT 和真实 `/api/health` 冒烟。主要产物:
- `dist/sidecar/aps-sidecar/`:PyInstaller onedir Sidecar;
- `apps/desktop/release/win-unpacked/`:可直接冒烟的展开目录;
- `apps/desktop/release/aps-agent-desktop-<version>.exe`:NSIS 安装包。
安装态启动顺序为:Electron 预留 loopback 随机端口并生成请求侧 nonce,启动内嵌 Sidecar;只有当前 Electron session 会为当前 Sidecar origin 注入 `x-aps-sidecar-nonce`,缺失或错误 nonce 的请求在进入 FastAPI 前返回 403。Electron 等待带相同 nonce 的 `/api/health` 成功后才加载同源 Web UI。每次崩溃重启都会轮换端口和 nonce、清除旧 origin,并在新实例健康前把窗口冻结到 `about:blank`。renderer 启用 sandbox;CSP、默认拒绝权限请求、导航与重定向锁、HTTPS 外链限制和 IPC sender 校验共同约束当前 origin;应用使用单实例锁,Sidecar 固定单 worker 并只继承允许列表环境。标准输出和错误写入 `~/.aps/logs/sidecar.log`,单文件 10 MiB 轮转;意外退出最多重启 3 次,Electron 正常退出会回收进程树,Electron 异常消失时 Sidecar 的父进程看门狗会自行退出。
本机 Windows 构建和打包 Electron CDP 冒烟已证明产物不依赖系统 Python、renderer 可加载真实 Sidecar origin,且绕过 Electron 直接访问健康端点会被 403 拒绝。桌面依赖已升级到 Electron 43.2.0 和 electron-builder 26.15.3,使用官方 npm registry 的当前审计结果为 0。正式 stable 发布仍须在无 Python、无网络的干净 Win10/11 x64 虚拟机完成安装、20 次冷启动、Defender、代码签名、升级/回滚及中文/空格安装路径验收。
## 原生 / 顶栏菜单
Windows 桌面端使用**无边框窗口**(`frame: false`)+ 自绘顶栏:
1. 中文菜单 `文件 / 编辑 / 视图 / 窗口 / 帮助` 贴窗口最顶
2. 顶栏空白区可**拖动窗口**;双击空白可最大化/还原
3. 右侧自绘 **最小化 / 还原·退出全屏 / 关闭**(不依赖系统 overlay,避免点不动)
右侧面板拖拽上限随窗口宽度计算:只保证对话区 ≥280px。
## Skill 与旧「设置页卡片」的区别
旧实现是服务端 `server/data/skills.json` 的登记表。
现实现对标 Codex:Skill 是用户目录下的**文件夹资产**;管理台展示并维护 `manifest.json`,桌面/Web 共用同一套 API。