新增Editor Agent Mock Agent P1落地计划
新增Editor Agent Mock Agent P1落地计划文档 明确P1使用确定性mock Agent生成结构化patch 补充runner命令白名单、工作区隔离、网络隔离和preview安全约束 更新docs总览中的editor agent文档索引
This commit is contained in:
@@ -21,7 +21,7 @@
|
|||||||
|
|
||||||
微信小程序虚拟支付接入、`wechat_mp_virtual` 渠道、`wx.requestVirtualPayment` 承接页和后端签名配置见 [【技术方案】微信虚拟支付接入-2026-05-26.md](./%E3%80%90%E6%8A%80%E6%9C%AF%E6%96%B9%E6%A1%88%E3%80%91%E5%BE%AE%E4%BF%A1%E8%99%9A%E6%8B%9F%E6%94%AF%E4%BB%98%E6%8E%A5%E5%85%A5-2026-05-26.md)。
|
微信小程序虚拟支付接入、`wechat_mp_virtual` 渠道、`wx.requestVirtualPayment` 承接页和后端签名配置见 [【技术方案】微信虚拟支付接入-2026-05-26.md](./%E3%80%90%E6%8A%80%E6%9C%AF%E6%96%B9%E6%A1%88%E3%80%91%E5%BE%AE%E4%BF%A1%E8%99%9A%E6%8B%9F%E6%94%AF%E4%BB%98%E6%8E%A5%E5%85%A5-2026-05-26.md)。
|
||||||
|
|
||||||
`/editor/agent` 浏览器内 AI Web 工程编辑器的静态 SPA 沙箱预览 MVP,采用“平台编辑器壳 + api-server 控制面 + 独立 runner worker + 独立预览域”四层结构;技术方案、威胁模型和验收清单见 [【技术方案】浏览器内AIWeb工程沙箱预览方案-2026-06-13.md](./technical/【技术方案】浏览器内AIWeb工程沙箱预览方案-2026-06-13.md)、[【安全模型】AIWeb工程Runner与预览隔离威胁模型-2026-06-13.md](./technical/【安全模型】AIWeb工程Runner与预览隔离威胁模型-2026-06-13.md) 和 [【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md](./technical/【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md)。
|
`/editor/agent` 浏览器内 AI Web 工程编辑器的静态 SPA 沙箱预览 MVP,采用“平台编辑器壳 + api-server 控制面 + 独立 runner worker + 独立预览域”四层结构;技术方案、威胁模型和验收清单见 [【技术方案】浏览器内AIWeb工程沙箱预览方案-2026-06-13.md](./technical/【技术方案】浏览器内AIWeb工程沙箱预览方案-2026-06-13.md)、[【安全模型】AIWeb工程Runner与预览隔离威胁模型-2026-06-13.md](./technical/【安全模型】AIWeb工程Runner与预览隔离威胁模型-2026-06-13.md) 和 [【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md](./technical/【测试用例】AIWeb工程静态预览MVP验收清单-2026-06-13.md)。P1 先用确定性 mock Agent 生成结构化 patch、真实打通项目 / 快照 / 构建 / artifact / 预览闭环,落地拆分见 [【技术方案】EditorAgentMockAgentP1落地计划-2026-06-15.md](./technical/【技术方案】EditorAgentMockAgentP1落地计划-2026-06-15.md)。
|
||||||
|
|
||||||
`/editor/canvas` 图片画布编辑器的画布素材 ZIP 导出能力,入口放在右上角标题栏下载图标内,第一版采用前端 JSZip 打包画布中有效图层引用的上传图、生成图和修改结果,方案见 [【前端架构】图片画布素材导出方案-2026-06-15.md](./technical/【前端架构】图片画布素材导出方案-2026-06-15.md)。
|
`/editor/canvas` 图片画布编辑器的画布素材 ZIP 导出能力,入口放在右上角标题栏下载图标内,第一版采用前端 JSZip 打包画布中有效图层引用的上传图、生成图和修改结果,方案见 [【前端架构】图片画布素材导出方案-2026-06-15.md](./technical/【前端架构】图片画布素材导出方案-2026-06-15.md)。
|
||||||
|
|
||||||
|
|||||||
488
docs/technical/【技术方案】EditorAgentMockAgentP1落地计划-2026-06-15.md
Normal file
488
docs/technical/【技术方案】EditorAgentMockAgentP1落地计划-2026-06-15.md
Normal file
@@ -0,0 +1,488 @@
|
|||||||
|
# Editor Agent Mock Agent P1 落地计划
|
||||||
|
|
||||||
|
更新时间:`2026-06-15`
|
||||||
|
|
||||||
|
## 背景
|
||||||
|
|
||||||
|
`/editor/agent` 的长期目标是浏览器内 AI Web 工程编辑器:用户通过自然语言和代码编辑生成一个完整 Web 工程,并在独立沙箱中预览。当前基础方案已确定为“平台编辑器壳 + api-server 控制面 + 独立 runner + 独立 preview origin”的四层结构。
|
||||||
|
|
||||||
|
P1 阶段先不接真实 AI Agent,不调用 LLM、不接 `platform-agent`、不做 Agent 记忆、工具调用或多轮规划。P1 使用确定性的 mock Agent 生成结构化 patch,把风险集中在真正需要先验证的工程链路:项目、快照、patch 校验、静态构建、artifact、preview gateway、iframe 预览和刷新恢复。
|
||||||
|
|
||||||
|
## P1 目标
|
||||||
|
|
||||||
|
P1 完成一个可端到端验收的最小纵切:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/editor/agent 输入 mock 指令
|
||||||
|
-> api-server mock Agent 生成结构化 patch
|
||||||
|
-> patch 校验并保存新 snapshot
|
||||||
|
-> 创建 preview build
|
||||||
|
-> runner 静态构建固定模板
|
||||||
|
-> 产出 immutable artifact
|
||||||
|
-> preview gateway 签发独立预览 URL
|
||||||
|
-> 前端 iframe 切换预览
|
||||||
|
```
|
||||||
|
|
||||||
|
P1 结束时,真实 Agent 仍可后置;后续只替换“需求文本 -> 结构化 patch”的来源,不推翻快照、构建和预览主链路。
|
||||||
|
|
||||||
|
## 非目标
|
||||||
|
|
||||||
|
P1 明确不做:
|
||||||
|
|
||||||
|
- 真实 LLM / Agent 调用。
|
||||||
|
- LangChain-Rust / `platform-agent` 接入。
|
||||||
|
- 任意 npm 依赖安装。
|
||||||
|
- AI 自定义 `package.json` scripts。
|
||||||
|
- HMR、长驻 dev server、WebSocket 代理。
|
||||||
|
- 终端 shell、后端服务、任意端口代理。
|
||||||
|
- Web project 作品化发布。
|
||||||
|
- 完整 lease / controller / worker 持久任务队列。
|
||||||
|
- 与主站同源预览。
|
||||||
|
- 把 AI 生成工程写入当前仓库源码目录。
|
||||||
|
|
||||||
|
## 阶段边界
|
||||||
|
|
||||||
|
P1 使用 mock Agent,但后续链路必须按生产架构实现:
|
||||||
|
|
||||||
|
| 能力 | P1 做法 | 后续替换点 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| 需求理解 | api-server 内确定性 mock 规则 | Phase 2/3 接真实 Agent |
|
||||||
|
| patch 生成 | mock Agent 返回结构化 patch | 保留同一 patch DTO |
|
||||||
|
| patch 校验 | api-server 真实校验 | 继续复用 |
|
||||||
|
| 快照保存 | SpacetimeDB 真实持久化 | 可拆对象存储优化 |
|
||||||
|
| 静态构建 | runner 真实构建固定模板 | 可换成持久队列领取 |
|
||||||
|
| artifact | 本地 / 受控 artifact store | 可换 OSS 或专用 artifact store |
|
||||||
|
| 预览 | 独立 origin / 独立端口 iframe | 生产接独立域名 |
|
||||||
|
|
||||||
|
## 与原始设计一致性检查
|
||||||
|
|
||||||
|
P1 与 2026-06-13 的技术方案、威胁模型和验收清单总体一致:mock Agent 只替换“需求文本 -> 结构化 patch”的来源,不改变“编辑器壳 -> api-server 控制面 -> runner 执行面 -> preview gateway”的信任边界。
|
||||||
|
|
||||||
|
为避免实现时放宽安全边界,P1 额外明确以下硬约束:
|
||||||
|
|
||||||
|
| 主题 | 原始设计要求 | P1 执行口径 |
|
||||||
|
| --- | --- | --- |
|
||||||
|
| Agent | AI 只能提交结构化 patch | mock Agent 也只能返回结构化 patch,并必须经过同一后端校验 |
|
||||||
|
| api-server | 控制面不执行 AI 工程代码 | api-server 可以创建 job 和触发 runner,但不得直接执行 `npm` / `vite` / 用户工程代码 |
|
||||||
|
| 允许命令 | 平台固定构建命令,禁止 AI 自定义脚本 | runner 只允许固定 argv 命令清单,不经 shell,不执行 `npm run`、`npx` 或用户传入命令 |
|
||||||
|
| 依赖 | 固定模板依赖,不开放任意 npm | P1 默认离线使用 runner 管理的模板依赖缓存;如需 registry,只能访问平台受控 mirror |
|
||||||
|
| 工作区 | 独立临时目录或容器,无宿主源码挂载 | 每个 job 使用 runner 创建的任务级临时目录;禁止挂载当前仓库源码、`.env`、Docker socket 和宿主 `node_modules` |
|
||||||
|
| 网络 | 构建期默认无外网 | 默认 deny all;只允许受控 npm mirror 和只读资产签名域,必须阻断内网、metadata、api-server、SpacetimeDB、Docker daemon |
|
||||||
|
| artifact | immutable artifact,不复用临时目录 | artifact root 由 runner 配置,不来自请求;preview 只服务 artifact,不服务工作区 |
|
||||||
|
| 预览 | 独立 preview origin | 开发态也必须使用独立端口 / origin;不得把预览挂在主站同源路径下 |
|
||||||
|
| 状态机 | 失败不覆盖上一版预览 | 只有当前 active snapshot 的 `succeeded` build 能推进 active preview |
|
||||||
|
|
||||||
|
## 契约设计
|
||||||
|
|
||||||
|
P1 新增 Web Project 契约,Rust `shared-contracts` 与前端 `packages/shared` 保持同名字段。
|
||||||
|
|
||||||
|
核心 DTO:
|
||||||
|
|
||||||
|
```text
|
||||||
|
WebProject
|
||||||
|
WebProjectSnapshot
|
||||||
|
WebProjectFile
|
||||||
|
WebProjectPatch
|
||||||
|
WebProjectPatchOperation
|
||||||
|
WebProjectPreviewBuild
|
||||||
|
WebProjectPreviewBuildEvent
|
||||||
|
MockAgentTurnRequest
|
||||||
|
MockAgentTurnResponse
|
||||||
|
```
|
||||||
|
|
||||||
|
P1 字段建议:
|
||||||
|
|
||||||
|
- `projectId`:不可枚举字符串 ID。
|
||||||
|
- `ownerUserId`:项目归属用户。
|
||||||
|
- `templateKey`:固定为 `react-vite-ts-static`。
|
||||||
|
- `activeSnapshotId`:当前编辑快照。
|
||||||
|
- `activePreviewBuildId`:当前成功预览构建。
|
||||||
|
- `files`:P1 可先存为 `Vec<WebProjectFile>` / JSON;只允许小型文本源码。
|
||||||
|
- `patchSummary`:mock Agent 或用户编辑摘要。
|
||||||
|
- `buildStatus`:`queued | running | succeeded | failed | cancelled | expired | stale`。
|
||||||
|
- `previewUrl`:由 api-server 返回给前端,不由前端拼接。
|
||||||
|
|
||||||
|
路径和内容限制必须写入契约注释和后端校验:
|
||||||
|
|
||||||
|
- 只允许相对路径。
|
||||||
|
- 拒绝绝对路径和 `..`。
|
||||||
|
- 拒绝 `.env`、`.npmrc`、`.git`、`.ssh`。
|
||||||
|
- 拒绝符号链接语义。
|
||||||
|
- 限制目录深度、单文件大小、snapshot 总大小。
|
||||||
|
- P1 只允许文本源码和少量静态资源。
|
||||||
|
- `package.json` 不是事实源;新增依赖和 scripts 在 P1 拒绝或忽略。
|
||||||
|
|
||||||
|
## 后端存储
|
||||||
|
|
||||||
|
P1 新增 SpacetimeDB 表:
|
||||||
|
|
||||||
|
```text
|
||||||
|
web_project
|
||||||
|
web_project_snapshot
|
||||||
|
web_project_preview_build
|
||||||
|
```
|
||||||
|
|
||||||
|
`web_project`:
|
||||||
|
|
||||||
|
- `project_id`
|
||||||
|
- `owner_user_id`
|
||||||
|
- `title`
|
||||||
|
- `template_key`
|
||||||
|
- `active_snapshot_id`
|
||||||
|
- `active_preview_build_id`
|
||||||
|
- `created_at`
|
||||||
|
- `updated_at`
|
||||||
|
|
||||||
|
`web_project_snapshot`:
|
||||||
|
|
||||||
|
- `snapshot_id`
|
||||||
|
- `project_id`
|
||||||
|
- `owner_user_id`
|
||||||
|
- `parent_snapshot_id`
|
||||||
|
- `template_key`
|
||||||
|
- `files_json`
|
||||||
|
- `patch_summary`
|
||||||
|
- `created_by`
|
||||||
|
- `created_at`
|
||||||
|
|
||||||
|
`web_project_preview_build`:
|
||||||
|
|
||||||
|
- `job_id`
|
||||||
|
- `project_id`
|
||||||
|
- `snapshot_id`
|
||||||
|
- `owner_user_id`
|
||||||
|
- `status`
|
||||||
|
- `logs_json`
|
||||||
|
- `artifact_id`
|
||||||
|
- `preview_token_id`
|
||||||
|
- `preview_url`
|
||||||
|
- `error_summary`
|
||||||
|
- `created_at`
|
||||||
|
- `started_at`
|
||||||
|
- `finished_at`
|
||||||
|
- `updated_at`
|
||||||
|
|
||||||
|
落点:
|
||||||
|
|
||||||
|
- `server-rs/crates/spacetime-module/src/web_project.rs`
|
||||||
|
- `server-rs/crates/spacetime-module/src/lib.rs`
|
||||||
|
- `server-rs/crates/spacetime-module/src/migration.rs`
|
||||||
|
- `server-rs/crates/spacetime-client/src/mapper/web_project.rs`
|
||||||
|
- `server-rs/crates/spacetime-client/src/web_project.rs`
|
||||||
|
|
||||||
|
如果已有表新增字段,字段必须放在结构体最后并设置明确默认值;修改字段名或字段类型前必须确认迁移计划。schema 修改后必须执行:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run spacetime:generate
|
||||||
|
npm run check:spacetime-schema
|
||||||
|
```
|
||||||
|
|
||||||
|
## api-server 控制面
|
||||||
|
|
||||||
|
新增模块:
|
||||||
|
|
||||||
|
```text
|
||||||
|
server-rs/crates/api-server/src/web_project.rs
|
||||||
|
server-rs/crates/api-server/src/web_project_mock_agent.rs
|
||||||
|
server-rs/crates/api-server/src/modules/web_project.rs
|
||||||
|
```
|
||||||
|
|
||||||
|
P1 API:
|
||||||
|
|
||||||
|
```text
|
||||||
|
POST /api/creation/web-project/projects
|
||||||
|
GET /api/creation/web-project/projects/{projectId}
|
||||||
|
GET /api/creation/web-project/projects/{projectId}/snapshot
|
||||||
|
PATCH /api/creation/web-project/projects/{projectId}/files
|
||||||
|
POST /api/creation/web-project/projects/{projectId}/mock-agent-turns
|
||||||
|
POST /api/runtime/web-project/projects/{projectId}/preview-builds
|
||||||
|
GET /api/runtime/web-project/preview-builds/{jobId}
|
||||||
|
GET /api/runtime/web-project/preview-builds/{jobId}/events
|
||||||
|
```
|
||||||
|
|
||||||
|
控制面职责:
|
||||||
|
|
||||||
|
- 鉴权并校验项目 owner。
|
||||||
|
- 创建固定模板项目。
|
||||||
|
- 读取 active snapshot。
|
||||||
|
- 校验用户编辑和 mock patch。
|
||||||
|
- 保存新 snapshot。
|
||||||
|
- 创建 preview build。
|
||||||
|
- 触发 P1 runner 构建。
|
||||||
|
- 记录构建日志和状态。
|
||||||
|
- 构建成功后签发 preview URL。
|
||||||
|
- 构建失败时保留上一版 active preview。
|
||||||
|
|
||||||
|
`/events` 复用 `src/services/sseStream.ts` 的事件口径。P1 可以先用 api-server 内存广播或短轮询兼容,但外部契约必须保持 SSE:
|
||||||
|
|
||||||
|
```text
|
||||||
|
queued
|
||||||
|
running
|
||||||
|
log
|
||||||
|
succeeded
|
||||||
|
failed
|
||||||
|
cancelled
|
||||||
|
expired
|
||||||
|
stale
|
||||||
|
```
|
||||||
|
|
||||||
|
## Mock Agent 规则
|
||||||
|
|
||||||
|
mock Agent 必须确定性、可测试、不可绕过 patch 校验。
|
||||||
|
|
||||||
|
输入:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"prompt": "做一个蓝色计数按钮页面",
|
||||||
|
"baseSnapshotId": "snapshot_xxx"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
输出:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"snapshot": "...",
|
||||||
|
"patch": {
|
||||||
|
"operations": [
|
||||||
|
{
|
||||||
|
"type": "updateFile",
|
||||||
|
"path": "src/App.tsx",
|
||||||
|
"content": "..."
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"summary": "更新首页计数按钮示例"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
P1 至少支持以下 mock 指令族:
|
||||||
|
|
||||||
|
- `计数` / `按钮`:生成带计数按钮的 React 页面。
|
||||||
|
- `卡片` / `列表`:生成卡片列表页面。
|
||||||
|
- `蓝色` / `绿色` / `粉色`:调整 CSS 主题色。
|
||||||
|
- `破坏构建`:生成一个 TypeScript 编译错误,用于验收失败保留上一版预览。
|
||||||
|
- 其它输入:只更新标题和说明文案,避免 mock 分支过多。
|
||||||
|
|
||||||
|
mock Agent 输出仍必须经过统一 `validate_web_project_patch(...)`,不得直接写表。
|
||||||
|
|
||||||
|
## Runner 与构建
|
||||||
|
|
||||||
|
P1 runner 可以先采用“api-server 创建 job 后触发一次性 runner 进程”的方式,不做持久 worker 队列;但执行面必须独立于 api-server、主站源码目录和预览域。api-server 只传递 job 身份和最小任务能力,不得在自身进程内执行构建命令。
|
||||||
|
|
||||||
|
建议新增:
|
||||||
|
|
||||||
|
```text
|
||||||
|
server-rs/crates/web-project-runner
|
||||||
|
```
|
||||||
|
|
||||||
|
P1 runner 输入:
|
||||||
|
|
||||||
|
- `jobId`
|
||||||
|
- `projectId`
|
||||||
|
- `snapshotId`
|
||||||
|
- snapshot files 包。
|
||||||
|
- artifact root 配置键或受控 artifact 写入能力。
|
||||||
|
|
||||||
|
请求体、snapshot 或 mock Agent 输出中不得携带 runner 命令、构建参数、工作区路径或 artifact 输出路径。
|
||||||
|
|
||||||
|
P1 runner 步骤:
|
||||||
|
|
||||||
|
1. 创建任务级临时目录。
|
||||||
|
2. 用 runner 内置模板或 runner 管理的只读模板缓存写入固定 React / Vite / TypeScript 模板。
|
||||||
|
3. 规范化 snapshot 文件路径,写入前确认最终路径仍在任务临时目录内。
|
||||||
|
4. 忽略或重写用户 `package.json` 的危险字段。
|
||||||
|
5. 使用环境变量白名单启动子进程,清空平台密钥、`.env`、token、代理和私有 registry 配置。
|
||||||
|
6. 执行平台固定命令清单。
|
||||||
|
7. 限制 CPU、内存、磁盘、进程数、打开文件数、构建时间、日志长度、单文件大小和 artifact 大小。
|
||||||
|
8. 成功后把 `dist/` 复制到 immutable artifact 目录;artifact 目录由 runner 配置计算,不接受请求指定。
|
||||||
|
9. 失败时返回错误摘要和日志片段,日志需脱敏并避免完整宿主路径。
|
||||||
|
10. 清理临时目录。
|
||||||
|
|
||||||
|
P1 允许的构建命令只能来自平台常量,使用 argv 方式执行,不经 shell、不拼接字符串、不执行用户传入命令:
|
||||||
|
|
||||||
|
```text
|
||||||
|
npm ci --ignore-scripts --offline --no-audit --fund=false
|
||||||
|
npm exec --offline -- vite build
|
||||||
|
```
|
||||||
|
|
||||||
|
如果离线缓存不足,P1 只能改为访问平台受控 npm registry mirror,并由 runner 写入受控 `.npmrc`;用户 snapshot 中的 `.npmrc`、registry、proxy、`package-lock.json` 篡改和新增依赖必须拒绝或重写。禁止为了开发速度复用当前仓库的 `node_modules`、源码目录或本机全局 npm cache 作为 runner 工作区输入。
|
||||||
|
|
||||||
|
P1 默认网络策略为 deny all。仅当使用平台受控 registry mirror 或资产只读签名域时开放精确白名单;必须阻断 RFC1918 内网、云 metadata 地址、api-server 管理端口、SpacetimeDB、生产数据库、Docker daemon,并覆盖 HTTP redirect 和 DNS rebinding 到内网的情况。
|
||||||
|
|
||||||
|
## Preview Gateway
|
||||||
|
|
||||||
|
P1 开发态 preview 可以使用独立端口:
|
||||||
|
|
||||||
|
```text
|
||||||
|
http://127.0.0.1:<previewPort>/p/<previewToken>/
|
||||||
|
```
|
||||||
|
|
||||||
|
生产形态继续对齐独立域名:
|
||||||
|
|
||||||
|
```text
|
||||||
|
https://sandbox.genarrative.world/p/<previewToken>/
|
||||||
|
```
|
||||||
|
|
||||||
|
gateway 必须:
|
||||||
|
|
||||||
|
- 校验 token。
|
||||||
|
- 绑定 owner / project / snapshot / artifact。
|
||||||
|
- 禁止 path traversal。
|
||||||
|
- MIME 类型按白名单输出。
|
||||||
|
- `index.html` fallback 只在 artifact 根内生效。
|
||||||
|
- token 过期或 artifact 删除后返回确定错误。
|
||||||
|
- 输出 CSP,默认 `connect-src 'none'`,并禁用 Service Worker 和持久缓存。
|
||||||
|
- 不向预览页注入平台 access token、用户 cookie、SpacetimeDB、OSS 写权限或 LLM provider 密钥。
|
||||||
|
|
||||||
|
preview gateway 可以与 api-server 共享代码仓库或部署单元,但服务静态 artifact 的入口必须是独立 listener / 端口 / vhost / origin;不得把 preview artifact 挂到主站同源路径下。
|
||||||
|
|
||||||
|
前端 iframe:
|
||||||
|
|
||||||
|
```text
|
||||||
|
sandbox="allow-scripts"
|
||||||
|
```
|
||||||
|
|
||||||
|
P1 不增加 `allow-same-origin`、`allow-downloads`、`allow-popups`、`allow-top-navigation`。
|
||||||
|
|
||||||
|
## 前端落点
|
||||||
|
|
||||||
|
新增:
|
||||||
|
|
||||||
|
```text
|
||||||
|
src/components/editor/agent/WebProjectAgentEditorPage.tsx
|
||||||
|
src/components/editor/agent/WebProjectAgentEditorPage.test.tsx
|
||||||
|
src/components/editor/agent/webProjectAgentViewModel.ts
|
||||||
|
src/services/web-project/webProjectClient.ts
|
||||||
|
src/services/web-project/webProjectSse.ts
|
||||||
|
src/services/web-project/webProjectClient.test.ts
|
||||||
|
```
|
||||||
|
|
||||||
|
入口路由:
|
||||||
|
|
||||||
|
```text
|
||||||
|
/editor/agent
|
||||||
|
```
|
||||||
|
|
||||||
|
P1 桌面布局:
|
||||||
|
|
||||||
|
- 左侧文件树。
|
||||||
|
- 中间代码编辑区,P1 可先用 `<textarea>`。
|
||||||
|
- 下方或右侧 mock Agent 输入区。
|
||||||
|
- 构建日志区。
|
||||||
|
- 右侧 iframe 预览。
|
||||||
|
|
||||||
|
P1 移动端布局:
|
||||||
|
|
||||||
|
- 使用 tabs:文件、代码、预览、日志。
|
||||||
|
- 不默认展示大段功能说明文案。
|
||||||
|
- 预览 iframe 保持可见尺寸和明确加载 / 失败状态。
|
||||||
|
|
||||||
|
前端状态原则:
|
||||||
|
|
||||||
|
- active preview 来自后端返回,不由前端自行推断。
|
||||||
|
- 构建失败不清空已有 iframe。
|
||||||
|
- 刷新后先读取项目和 active snapshot,再恢复未终态 job 订阅。
|
||||||
|
- 用户连续编辑触发新 snapshot 时,旧 build 只能显示为旧日志,不得覆盖新 preview。
|
||||||
|
|
||||||
|
## 任务拆分
|
||||||
|
|
||||||
|
| 编号 | 任务 | 主要文件 | 完成标准 |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| P1-01 | 契约与 DTO | `shared-contracts`、`packages/shared` | 前后端类型通过,字段和状态枚举一致 |
|
||||||
|
| P1-02 | SpacetimeDB 表与 procedure/facade | `spacetime-module`、`spacetime-client` | 能创建项目、保存 snapshot、记录 build |
|
||||||
|
| P1-03 | api-server Web Project 模块 | `api-server/src/web_project.rs` | API 鉴权、owner 校验、读写 snapshot |
|
||||||
|
| P1-04 | mock Agent | `api-server/src/web_project_mock_agent.rs` | 指令生成 patch 且走统一校验 |
|
||||||
|
| P1-05 | P1 runner | `server-rs/crates/web-project-runner` | 固定模板可构建,失败有日志摘要 |
|
||||||
|
| P1-06 | preview gateway | `api-server` 或独立 runner/gateway | 独立 URL 可服务 artifact,token 校验生效 |
|
||||||
|
| P1-07 | `/editor/agent` 页面 | `src/components/editor/agent` | 端到端可创建、编辑、构建、预览 |
|
||||||
|
| P1-08 | 自动化与 smoke | 测试文件、验收脚本 | happy path 和失败保留旧预览通过 |
|
||||||
|
|
||||||
|
## 验收场景
|
||||||
|
|
||||||
|
P1 必须通过:
|
||||||
|
|
||||||
|
1. 打开 `/editor/agent`,创建固定模板项目。
|
||||||
|
2. 输入“做一个蓝色计数按钮页面”。
|
||||||
|
3. mock Agent 返回结构化 patch。
|
||||||
|
4. api-server 保存新 snapshot。
|
||||||
|
5. 前端创建 preview build。
|
||||||
|
6. runner 构建成功并产出 immutable artifact。
|
||||||
|
7. SSE 返回 `queued -> running -> succeeded`。
|
||||||
|
8. iframe 切换到新 preview URL。
|
||||||
|
9. 输入“破坏构建”。
|
||||||
|
10. 新 build 进入 failed,页面展示错误摘要。
|
||||||
|
11. 上一版 active preview 仍保留。
|
||||||
|
12. 刷新 `/editor/agent` 后,项目、active snapshot、active preview 和未终态 job 状态可恢复。
|
||||||
|
|
||||||
|
安全验收必须覆盖:
|
||||||
|
|
||||||
|
- 绝对路径被拒绝。
|
||||||
|
- `..` 被拒绝。
|
||||||
|
- `.env` / `.npmrc` / `.git` / `.ssh` 被拒绝。
|
||||||
|
- 修改 `package.json` 新增依赖被拒绝或忽略。
|
||||||
|
- 用户传入构建命令、scripts、registry、proxy 被拒绝或忽略。
|
||||||
|
- runner 构建命令不经 shell,且只来自平台 allowlist。
|
||||||
|
- runner 无平台密钥环境变量、无宿主源码挂载、无 Docker socket、无宿主 `node_modules` 输入。
|
||||||
|
- runner 只能在任务级临时目录写入 snapshot,路径解析后不能逃逸工作区。
|
||||||
|
- 构建期默认无外网;允许网络时只能访问平台白名单域名。
|
||||||
|
- artifact root 不来自请求,preview 不服务 runner 临时工作区。
|
||||||
|
- preview iframe 与主站不同 origin。
|
||||||
|
- preview gateway 输出 CSP,禁止 Service Worker 和未白名单 `connect-src`。
|
||||||
|
- failed / cancelled / expired / stale 不覆盖 active preview。
|
||||||
|
|
||||||
|
## 验证命令
|
||||||
|
|
||||||
|
后端与 schema:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run spacetime:generate
|
||||||
|
npm run check:spacetime-schema
|
||||||
|
cargo test -p spacetime-module web_project --manifest-path server-rs/Cargo.toml
|
||||||
|
cargo test -p spacetime-client web_project --manifest-path server-rs/Cargo.toml
|
||||||
|
cargo test -p api-server web_project --manifest-path server-rs/Cargo.toml
|
||||||
|
```
|
||||||
|
|
||||||
|
前端:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
npm run test -- src/services/web-project
|
||||||
|
npm run test -- src/components/editor/agent
|
||||||
|
npm run typecheck
|
||||||
|
npm run check:encoding
|
||||||
|
git diff --check
|
||||||
|
```
|
||||||
|
|
||||||
|
浏览器 smoke:
|
||||||
|
|
||||||
|
```text
|
||||||
|
打开 /editor/agent
|
||||||
|
创建模板项目
|
||||||
|
提交一次 mock Agent 指令
|
||||||
|
等待静态构建成功
|
||||||
|
确认 iframe 展示新预览
|
||||||
|
提交一次破坏构建的 mock 指令
|
||||||
|
确认错误出现且上一版预览仍保留
|
||||||
|
刷新页面确认项目、日志和 active preview 可恢复
|
||||||
|
```
|
||||||
|
|
||||||
|
## 风险与处理
|
||||||
|
|
||||||
|
- Runner 与 api-server 边界被做薄:P1 可以由 api-server 触发 runner,但 runner 仍必须独立工作区执行,不能在主站源码目录构建。
|
||||||
|
- mock Agent 绕过校验:mock 输出必须走同一 patch DTO 和后端校验函数。
|
||||||
|
- P1 为赶进度直接同源预览:禁止;开发态也要独立端口或独立 origin。
|
||||||
|
- snapshot 存大 JSON 后续膨胀:P1 限制总大小;P2 再拆 digest/object store。
|
||||||
|
- 失败覆盖成功预览:状态机必须以 active snapshot 和 succeeded build 双条件推进 active preview。
|
||||||
|
|
||||||
|
## 后续衔接
|
||||||
|
|
||||||
|
P1 完成后进入 P2 时,优先补:
|
||||||
|
|
||||||
|
- `web_project_runtime_job` 持久任务表。
|
||||||
|
- lease / controller / worker 模式。
|
||||||
|
- 手动取消、stale、expired 和 runner crash 恢复。
|
||||||
|
- 构建日志分页与可重连 SSE。
|
||||||
|
- 真实 Agent 接入,但继续产出同一结构化 patch。
|
||||||
|
|
||||||
|
真实 Agent 接入前不得扩大 P1 的执行权限;任意依赖安装、HMR、dev server 和作品化发布必须进入后续独立评审。
|
||||||
Reference in New Issue
Block a user