合并 origin/master:待发消息队列归宿主叠加 master 的 active-turns 广播与保活下沉
- direct_runtime/mod.rs:保留本分支「Thread Manager 是活动回合唯一事实源」(direct_active_turn_id_at), 丢掉 master 的 DirectTaonierActiveInvocationGuard 第二份进程内表;master 的美术背景路由改动全部保留 - direct_thread_manager.rs:双方都保留——本分支的待发队列 / 容量上限 / 残留回合兜底释放, 与 master 的 emit_direct_active_turns_changed 广播、unsubscribe、update_active_turn 返回「是否真的变了」 - useDirectProjectChatController.ts:保留本分支入队化逻辑,采纳 master 的 rawMessage 小重构与保活下沉 - direct_turn_dispatch.rs:会话保活改挂放行占用(DirectTurnReservation._session_keepalive), 随占用释放即停,等价承接 master 放在调用身份守卫里的保活意图 - 保留本分支对 direct-execution-production-fixture.mjs 的删除(--direct-codex-chat CLI 已退役,夹具无入口) - 连带退役 scripts/run-agc-direct-execution-fixture.mjs 与 npm run check:agc-direct-execution-fixture(只服务该夹具) - 文档同步:ADR / 09-24 实施计划 / decision-log 记录上述退役,09-16 与 09-18 里程碑、pitfalls 的夹具命令标注为已退役
This commit is contained in:
@@ -33,7 +33,7 @@
|
||||
## 验收
|
||||
|
||||
- `src/services/sseStream.test.ts` 覆盖 CRLF / LF 边界、UTF-8 尾部 flush、异常 JSON 跳过和提前停止取消 reader。
|
||||
- `src/services/llmClient.test.ts` 覆盖 OpenAI 兼容文本流、异常 JSON 跳过和 `[DONE]` 后提前停止。
|
||||
- `src/services/llmClient.test.ts` 覆盖 OpenAI 兼容文本流、异常 JSON 跳过和 `[DONE]` 后提前停止。**2026-09-24 修订**:`src/services/llmClient.ts` 与其测试已随旧创作链路退役删除,该条不再是现行验收项;现行 SSE 传输层验收由 `src/services/sseStream.test.ts`(已放回根 `vitest.config.ts` 的 include,2026-09-24)与各业务 client 的既有用例承担。
|
||||
- `src/services/image-editor/editorAgentClient.test.ts` 覆盖会话 CRUD 和 `/messages` 普通 JSON 路由;画布 Agent 不纳入 SSE parser 验收。
|
||||
- 已有 OpenAI 兼容文本流、NPC 聊天流、创作 Agent、创意互动 Agent、视觉小说运行态和充值订单状态测试继续通过。
|
||||
- `npm run typecheck` 不产生新的类型错误。
|
||||
|
||||
@@ -44,6 +44,37 @@
|
||||
|
||||
Web 宿主需要显式启用 Tailwind 4,并引入 `@genarrative/shared/styles.css` 和 `@genarrative/shared/theme.css`;Tauri WebView 与网站共用这套源码,移动端 React Native 不消费 DOM/CSS 组件。筛选工具栏所需的 `platform-category-*` chrome 样式也已放入共享样式文件,独立宿主无需依赖网站 `src/index.css`。组件库不提供页面壳或业务流程。`components.json` 只用于 shadcn CLI 定位源码,不允许覆盖现有业务组件。
|
||||
|
||||
## 后台管理端组件层(2026-09-29)
|
||||
|
||||
陶泥儿后台(`apps/admin-web`)原先每个页签各自手写页面壳、面板、按钮、提示条、空态、状态胶囊、标签、键值列表、数据表外壳、表单字段和分页条,同一套 `admin-*` 类名在 25 个页面里重复出现。现在这些跨页签重复的 chrome 统一收口到 `packages/shared/src/components/admin/`,由 `@genarrative/shared/components` 导出,页面只保留业务取数、筛选状态和领域文案:
|
||||
|
||||
- 页面壳与标题:`AdminPage`、`AdminPageHeading`(标题 / 说明 / 右侧操作)。
|
||||
- 面板:`AdminPanel`(`as="div" | "section" | "form"`、`tone="warning"`)、`AdminPanelHeading`(`title` / `description` / `count` / `extra` / `titleProps`)、`AdminActionRow`。
|
||||
- 动作:`AdminButton`(`primary` / `secondary` / `danger` / `ghost` / `text` / `icon` 六种既有类名变体,CVA 组织变体)。
|
||||
- 反馈:`AdminAlert`(默认错误底色,`warning` / `success`,`role` 可选)、`AdminToast`、`AdminEmptyState`、`AdminStatusPill`(`ok` / `pending` / `error`)、`AdminTag`、`AdminTagList`。
|
||||
- 数据与表单:`AdminTable`(滚动容器 + `compact` / `wide` 尺寸)、`AdminJsonPreview`、`AdminField` / `AdminFieldGroup` / `AdminFormRow`、`AdminInfoList` / `AdminInfoItem`、`AdminPagination`(统计 + 每页条数 + 上一页 / 下一页)。
|
||||
- 列表:`AdminListPanel` + `AdminListColumn`——把「面板 + 加载态 + 空态 + 表格 + 分页」收成一个组件。表格形态由 `columns` 驱动(`render` 自定义单元格、`renderRow` 自定义整行、`header`/`headerProps` 支持排序表头、`dataLabel` 写移动端标签),卡片/网格或自定义表格走 `children`(`alwaysRenderChildren` 可让空列表也保留骨架);空态三态 `state`/`text`/`row`,加载两口径 `empty`/`line`,另有 `toolbar`、`pagination` 槽位和 `showEmpty` 判据覆盖。后台 20 个页签的 23 个列表已全部改用它。
|
||||
- 列头排序:同一组件上用 `sortable` / `sortValue` / `sortDescription` 声明可排序列,交互与表查询列头一致(正序 → 倒序 → 不排序,同步 `aria-sort`,稳定排序)。它是**前端排序**,只适用于「一次取全」的列表(邀请码、灰度、任务配置等);分页明细列表要排序必须让后端接口接受 `sortColumn`/`sortDirection`(当前只有表查询行数据与 API Key 两个接口支持),不要在分页数据上做前端排序。
|
||||
- 收敛范围:后台 21 个文件里的 26 处列表全部走 `AdminListPanel`,其中 24 处是 `columns` 形态(含 2 处弹窗内 `surface="plain"`);仅账号管理的卡片列表与账号配置的键值列表保留 `children` 形态(它们不是表格)。新增列表时请直接用 `columns` + `renderRow`,不要再在页面里手写 `<thead>` 或把 `<AdminTable>` 当 children 传进去。唯一例外是「上传模板」弹窗里的待上传队列表(逐行校验/进度的编辑态表格),有意不纳入列表组件。
|
||||
- 弹窗:`AdminDialog`——遮罩 + 面板 + 标题行 + 关闭动作,统一 `role="dialog"`、`aria-modal`、Esc、点遮罩关闭、初始聚焦与 `aria-labelledby`;`as="form"` 支持表单弹窗(提交时可用 `closeDisabled` / `closeOnBackdrop` / `closeOnEscape` 冻结关闭),`panelClassName` / `backdropClassName` / `showClose` / `extra` 承接页面既有视觉类。后台 12 处弹窗外壳已全部改用它。
|
||||
- 时间展示:`formatAdminDateTime` / `formatAdminDate`(`packages/shared/src/components/admin/AdminFormat.ts`)统一后台的 ISO/epoch/Date 渲染(`zh-CN`、24 小时、解析失败回落 `fallback`)。页面里原先 7 份重复的本地 `formatDateTime` / `formatTime` 已删除,列表和详情不再出现裸 ISO 串。
|
||||
|
||||
样式归属:组件的 `.admin-*` 规则随组件放在 `packages/shared/src/components/admin/admin.css`(与 `PlatformProfileRechargeModal/index.css` 同一种按组件自带样式的做法),由组件入口 `import './admin.css'` 引入;`apps/admin-web/src/styles/admin.css` 只保留后台壳层布局和页面专属规则。媒体查询里针对公共组件的覆盖(980px 表单单列、560px 面板内边距与标题字号等)同样放在共享表,保证共享组件样式表单独看也是完整的。`apps/admin-web/src/styles/admin.test.ts` 锁定这条边界:共享表必须定义公共 chrome,页面表不得再重复定义。
|
||||
|
||||
迁移里做的刻意归一:页面标题的 `<h1>` 和面板标题的 `<h2>` 统一为 `AdminPageHeading` / `AdminPanelHeading` 的 `<h2>` / `<h3>`;分页条统一走 `AdminPagination`(游标分页与偏移分页的取数逻辑仍由页面持有);弹窗遮罩从页面自有的 `.admin-detail-modal` 换成共享 `.admin-confirm-backdrop`(遮罩底色与层级随之统一),`AdminAgcTemplatesPage` 的列表从「页面直出表格」改为列表面板(多了白底卡片)。取数、筛选、分页状态、写操作确认流程仍留在页面。
|
||||
|
||||
本地核对渲染效果(不依赖 Rust 后端与 SpacetimeDB):
|
||||
|
||||
```powershell
|
||||
node scripts/admin-web-fake-api.mjs 8099
|
||||
$env:ADMIN_API_TARGET="http://127.0.0.1:8099"; node scripts/dev.mjs admin-web
|
||||
# 打开 http://127.0.0.1:3111/admin/ ,localStorage 写入 genarrative_admin_token=local-fake-token 即可进入
|
||||
```
|
||||
|
||||
`scripts/admin-web-fake-api.mjs` 提供 overview / dashboard / tracking / error-reports / feature-gates / invite-codes / project-snapshots / accounts / user-detail 等夹具,够逐页核对列表、空态、分页与弹窗;接口形状不符时页面会整页空白(后台目前没有 error boundary),加夹具时对照 `apps/admin-web/src/api/adminApiTypes.ts`。
|
||||
|
||||
后台组件的边界与平台组件一致:只接 props、图标节点和回调,不读 token、不发请求、不持有正式业务状态;路由、鉴权、`/admin/api/*` 调用和筛选/分页状态留在 `apps/admin-web`。
|
||||
|
||||
## 展示页
|
||||
|
||||
网站 `/components`(兼容别名 `/design-system`)是共享组件展示页,不经过账号 Gate。页面按“基础组件”“平台通用组件”“Token”“状态”分区,覆盖公共组件的主要变体、交互态、筛选/标签/媒体/上传/异步状态/指标列表等平台 chrome 和移动端布局;展示数据均为本地静态示例,不调用 API。平台组件分区中的筛选按示例素材状态过滤结果,排序按最近使用或名称重排结果,并在筛选按钮、排序按钮和独立筛选面板之间保持同一份本地状态。展示页可用于网站与客户端接入前的视觉回归和人工验收。平台通用组件示例优先从 `@genarrative/shared/components` 直接导入,业务代码仍可通过 `src/components/common` 的兼容出口渐进迁移;展示页只接入不读取请求、store 或业务实体的 chrome,不把账号、发布和编辑器业务流程嵌入展示页。
|
||||
|
||||
@@ -148,6 +148,8 @@ kick 幂等(并发两次只认领一次);队首在放行后被移除、rem
|
||||
- `agent/direct_runtime/mod.rs`:删 `run_direct_game_creator_turn_at` 与 `run_direct_game_creator_turn_at_with_creation_type`
|
||||
(各自只有彼此与 CLI 一个调用方)。
|
||||
- 删 `apps/ai-game-creator-shell/scripts/direct-execution-production-fixture.mjs`(CLI 的唯一消费者)。
|
||||
- 删 `scripts/run-agc-direct-execution-fixture.mjs` 与 `package.json` 的 `check:agc-direct-execution-fixture`
|
||||
(只服务该夹具,夹具没了没有第二个消费者)。
|
||||
- `DirectTurnError::TurnAlreadyRunning` 与前端"同一轮消息仍在处理中"文案、专属分支、`project-conversation.suite.ts`
|
||||
的对应断言**挪到第 5 步**(它最后一个生产点在调用身份守卫里)。
|
||||
- 文档同步:09-22 里程碑把 `--direct-codex-chat` 从"范围外(保留)"改成退役项;两份 Direct 技术方案的 CLI 承诺删掉;
|
||||
|
||||
@@ -64,7 +64,7 @@ npm run check:pingora-release-readiness
|
||||
|
||||
`check:nginx-spa-routes` 从 `appPageRoutes.ts` 的 `STAGE_ROUTE_ENTRIES` / `APP_RUNTIME_ROUTES`、`appRoutes.tsx` 的精确路由判断和兼容恢复路径 `/creation/rpg/agent` 提取当前主站 SPA allowlist,确认生产、开发和容器三套 Nginx 模板集合一致,并验证大小写、尾部斜杠和 `/creation/not-exist`、`/runtime/not-exist`、`/puzzle/not-exist` 等未知反例。
|
||||
|
||||
`check:pingora-route-parity` 会先执行同一 Nginx SPA 路由门禁,再读取 `deploy/pingora/nginx-route-parity.matrix.json`,静态确认生产 / 开发 Nginx 模板、Pingora Rust 路由 allowlist / 单测和本文档都覆盖同一组核心路由。`cargo test -p pingora-gateway --manifest-path server-rs/Cargo.toml matches_nginx_route_parity_matrix` 会读取同一份矩阵,逐条断言 `classify_path` 的路由结果、body limit 和接流保护分组。
|
||||
`check:pingora-route-parity` 会先执行同一 Nginx SPA 路由门禁,再读取 `deploy/pingora/nginx-route-parity.matrix.json`,静态确认生产 / 开发 Nginx 模板、Pingora Rust 路由 allowlist / 单测和本文档都覆盖同一组核心路由,并做**反向覆盖**(模板里的每条 `location` 都必须被矩阵声明)。`cargo test -p pingora-gateway --manifest-path server-rs/Cargo.toml matches_nginx_route_parity_matrix` 会读取同一份矩阵,逐条断言 `classify_path` 的路由结果、body limit 和接流保护分组。`check:nginx-spa-routes` 与 `check:pingora-route-parity` 已串进 `npm run lint`(因此 `check:repository-ci`、CI 与 pre-push 都会执行),接线本身由 `check:production-ops` 的 guardrail 锁定。
|
||||
|
||||
`check:nginx-pingora-canary` 会静态校验 `deploy/nginx/snippets/genarrative-pingora-canary.conf` 的本机来源限制、handoff 响应头、probe token 占位、前缀 rewrite、低缓冲和 WebSocket Upgrade 设置,也会校验 `deploy/nginx/snippets/genarrative-pingora-realpath-canary.conf` 只能作为独立 loopback `server` 片段使用、默认监听 `127.0.0.1:18083`、写独立 access log、没有 rewrite、覆盖真实 `/api` / `/v1` / `/assets` 代表路径。本机安装了 Nginx 时脚本会额外把两个 snippet 包进临时 `http {}` 执行 `nginx -t`;需要在 CI / 目标 agent 上强制要求真实 Nginx 语法检查时执行 `node scripts/check-nginx-pingora-canary.mjs --require-nginx`。
|
||||
|
||||
@@ -534,9 +534,15 @@ dev 根盘空间在安装后曾接近满盘;2026-06-17 进入 canary 前已清
|
||||
| `/v1/database/{db}/subscribe`、`/v1/identity*` | 转发到 SpacetimeDB,保留 WebSocket Upgrade 头。 |
|
||||
| `/__genarrative_pingora/healthz` | 仅在携带 `X-Genarrative-Pingora-Probe` 且匹配配置 token 时返回 shadow JSON,否则 404。 |
|
||||
| `/v1/*`、`/generated-*`、`/healthz*`、`/readyz*` | 返回 404,保持生产公网不暴露口径。 |
|
||||
| 主站 SPA allowlist | 只对 `/`、`/creation`、`/project`、`/profile` 与 `/editor/canvas` 失败回退 `/index.html`;匹配大小写不敏感并允许一个尾部斜杠,HTML 默认 `no-cache`。 |
|
||||
| 主站 SPA allowlist | 只对 `/`、`/components`、`/creation`、`/design-system`、`/editor/canvas`、`/games`、`/games/detail`、`/games/mine`、`/games/play`、`/games/publish`、`/profile`、`/project` 失败回退 `/index.html`(集合与前端路由源、Nginx 三份模板逐条一致,由 `npm run check:pingora-route-parity` 与 `cargo test -p pingora-gateway matches_nginx_route_parity_matrix` 比对);匹配大小写不敏感并允许一个尾部斜杠,HTML 默认 `no-cache`。`/games/game_<32 位十六进制 id>/…` 是发行网关路由,不在 SPA allowlist 内。 |
|
||||
| 其它 Web 路径 | 只读取真实静态文件或目录 index,缺失时返回真实 404;`/creation/not-exist`、`/runtime/not-exist`、`/puzzle/not-exist` 不进入 SPA fallback。 |
|
||||
|
||||
SPA allowlist 里属于游戏分发入口的深链(游戏目录 / 详情 / 游玩 / 我的 / 发布深链:`/games`、`/games/detail`、`/games/play`、`/games/mine`、`/games/publish`)与 Nginx 三份模板同口径;Pingora 侧由路由对照矩阵的 `games_spa_fallback` 用例与 `cargo test -p pingora-gateway matches_nginx_route_parity_matrix` 逐条断言。根路径 `/` 精确回退 `/index.html`(Nginx 在 `location = /` 里用 `try_files /index.html =404;`,不带 `$uri`),由矩阵的 `web_root_spa` 用例固定。发行网关路径 `/games/game_<32 位十六进制 id>/…` 不走 SPA,见下一节的对照说明。
|
||||
|
||||
`npm run check:pingora-route-parity` 同时对两份 Nginx 模板做**反向覆盖**检查:模板里出现的每条 `location` 都必须被矩阵某条用例的 `nginx` 片段声明,否则失败。这条是 2026-09-29 补的——此前只做正向检查(矩阵片段必须存在于模板),于是「模板加/改了路由、矩阵与 Pingora 没跟上」这类漂移(发行网关路由就是这么漏的)不会被门禁发现。
|
||||
|
||||
**平台同源发行入口**(`/games/game_<32 位十六进制 id>/…`)与 SPA allowlist 是两条不同的路由:Nginx 用 `location ~ "^/games/(?<game_id>game_[0-9a-f]{32})(?<game_path>/.*)?$"` 把它代理到 api-server 的发行网关(`proxy_set_header Cookie ""` + `proxy_pass .../api/game-distribution/releases/$game_id$game_path`),Pingora 侧对应 `RouteDecision::ReleaseGateway`:走 api 上游,但把上游路径重写成 `/api/game-distribution/releases/<gameId><asset 路径>`(与 Nginx 的 `proxy_pass` 同口径,原来的 query 不再拼接)、清空 `Cookie`,并按 Nginx 该 location 的语义既不进 SPA fallback、也不套用 `limit_conn` / `limit_req` 分组、不受维护闸拦截。只认小写、固定 32 位十六进制 id;`/games/detail` 这类 SPA 深链与 `/games/game/...` 这类形状不符的路径都不会被吞进发行网关。该口径由矩阵的 `games_release_gateway` 用例(含 `upstreamPath` 期望值)与 `cargo test -p pingora-gateway matches_nginx_route_parity_matrix` 固定。
|
||||
|
||||
维护模式下,公网 API-like 路由返回 JSON `503`;公网 Web 静态路由先读取 `GENARRATIVE_PINGORA_GATEWAY_MAINTENANCE_PAGE_FILE` 指向的 release 外运行态公告,缺失时回退 `GENARRATIVE_PINGORA_GATEWAY_WEB_ROOT/maintenance.html`,两者都不存在时返回纯文本 `503`。版本化默认页不得包含日期或具体时段,临时公告由 `maintenance-on.sh --page-file` 安装并在 `maintenance-off.sh` 时清理。IPv4 loopback / RFC1918 / link-local 和 IPv6 loopback / ULA / link-local 来源绕过整站维护闸,主站页面与静态资源、普通 API、后台页面与后台 API、SpacetimeDB 路由均按非维护状态继续处理;应用层登录、管理员鉴权和其它业务鉴权保持不变。Pingora 直连按 TCP peer 判定来源;仅当 peer 是 loopback 的同机 Nginx 时才接受 Nginx 强制覆盖的 `X-Real-IP`,绝不使用客户端可伪造的 `X-Forwarded-For` 做维护放行。该放行只绕过网关维护响应;若 `pause-after-stdb` 已停止 api-server,内网普通 API 和后台 API 仍不可用。
|
||||
代理失败时,API / SpacetimeDB 等代理路由返回统一 JSON 网关错误;本地静态路由仍保持对应 HTTP 错误状态。
|
||||
静态 `Range` 只支持单段 bytes range;多段 range 暂按完整文件返回,避免在正式替换前引入 multipart 响应面。`If-None-Match` / `If-Modified-Since` 优先于 `Range` 判定,命中时仍返回 `304`;`If-Range` 日期匹配时继续返回 `206`,日期旧于文件或弱 ETag 校验器时回完整 `200`;`206` / `304` / `416` 不做 gzip 压缩,避免 `Content-Range` 语义被响应体改写破坏。Gateway smoke 会用固定 `X-Request-Id` 对账静态 `304`、`405`、`206`、`416` 的 Pingora access log 行,确认本地响应状态也进入正式切换证据链。
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 【技术方案】AGC 后端框架整理与演进路线
|
||||
|
||||
更新时间:`2026-09-18`
|
||||
更新时间:`2026-09-23`
|
||||
|
||||
## 结论
|
||||
|
||||
@@ -49,7 +49,7 @@ flowchart TB
|
||||
PROJECT[Local Project Plane\nfiles / manifest / JSONL / locks / checkpoints]
|
||||
|
||||
UI --> HOST
|
||||
UI --> API
|
||||
HOST --> API
|
||||
HOST --> CORE
|
||||
HOST --> ORCH
|
||||
HOST --> CONTRACT
|
||||
@@ -190,7 +190,7 @@ UI
|
||||
### 云端资源/生成操作
|
||||
|
||||
```text
|
||||
AGC tool or UI
|
||||
AGC tool or UI -> Local Rust Host
|
||||
-> api-server route
|
||||
-> auth + project ownership + idempotency
|
||||
-> module-* validation
|
||||
@@ -223,14 +223,28 @@ Local project snapshot
|
||||
3. **文件系统单一入口**:任何 Agent 文件读写都经过项目 scope、写锁和受控工具;不能在 API 或前端加旁路写入。
|
||||
4. **外部服务单一入口**:LLM、生成、OSS、认证等外部调用只经 `platform-*`,不能在业务 handler 里散落裸 HTTP。
|
||||
5. **数据访问单一入口**:`api-server` 和本地需要的云端调用使用 `spacetime-client` facade,不直接拼 SpacetimeDB 请求。
|
||||
6. **前端只消费投影**:前端不推导正式业务状态,不直接访问本地项目数据库或 SpacetimeDB。
|
||||
6. **前端只消费投影**:AGC React 按离线前端设计,只负责展示、交互、输入草稿及短暂 UI 状态。正式数据、持久化、网络请求编排、重试和恢复由 Rust 本地宿主与云端控制面持有。React 通过领域命令表达用户意图,通过事件或 channel 接收结果,不在渲染/effect 中主动回写收到的正式状态,不直接访问本地项目数据库或 SpacetimeDB。
|
||||
7. **身份与凭据分离**:同一身份的 access token 轮换不使在途 Run 失效;换号、退出或 origin 变化必须使旧 Run 停止后续副作用。
|
||||
8. **可恢复优先**:持久动作、异步生成、Runner 续跑、外部结果回填和最终状态写入必须有稳定 ID、版本/CAS 或幂等键。
|
||||
|
||||
## 当前缺口
|
||||
|
||||
### 渲染层数据与 I/O 边界尚未完成
|
||||
|
||||
2026-09-23 已完成第一条可复核的网络下沉闭环:官方模型目录 GET /api/llm/models 由 Tauri `load_game_creator_llm_models` 持有会话凭据、HTTP 请求、响应 envelope 解析、响应大小上限和身份代次复核,React `llmModelCatalog` 在 Tauri 中只通过 typed invoke 取得目录快照;无 native host 时明确报告本地模型服务不可用,不回退到 React HTTP。该闭环不覆盖账户、素材直传、错误上报或发行网络,不能据此宣称全部 React 网络 I/O 已归 Rust。
|
||||
|
||||
本轮又完成发行网络闭环:`game_distribution_publish.rs` 从 Rust `platform_session` 读取当前 user/token/origin,在 Rust 内完成发布灰度、资料建议、封面定价/生成及异步任务收口、创建游戏/版本、分片续传和送审;`gameDistributionPublish.ts` 只保留 typed `invoke` façade,不再 import `requestClientApi` / `fetchClientHttp`、读取 token 或拼接远端 URL。封面队列由 Rust 统一做有界轮询,React 静止时不再按 1.6 秒访问远端任务;账户刷新、素材上传、错误上报和其它 clientApi 链路仍未迁移。
|
||||
本文件的离线前端规则是目标合同,不能据此宣称当前代码已全部满足。2026-09-23 已将项目创建目录与最近工作区偏好迁到 Tauri Rust AppData JSON、typed command 和变更事件;发送前提醒偏好已在 2026-09-24 迁到同一份 Rust 客户端偏好(`set_chat_prompt_polish_reminder_disabled` + 偏好事件);素材上传、错误报告与账户/钱包也已改为 Rust typed command(`upload_platform_media_asset`、`submit_error_report`、`account_api` 五条命令),渲染层不再持有 token、拼远端 URL 或发平台请求。2026-09-24 已完成最后一段:登录、验证码、refresh、登出与开发服务器选择迁到 Rust `auth_session`(AppData 私有 `client-session.json` 持有 refresh 凭据,登录/续期/登出后 Rust 自己安装本机运行时会话并发出状态事件);渲染层 `services/clientApi.ts` 删除、`clientHttp.ts` 收敛为 origin 校验与渠道默认值,`src` 内不再有 `fetch(` 调用、也不再读写 access token 或 refresh cookie。账户钱包、素材上传、错误报告、模型目录、发行与工作区偏好同样已改为 Rust typed command。Direct 回合保活也已归 Rust:回合登记时启动保活任务(按 access token 签发时间自助续期),回合结束即停止,渲染层不再持有任何业务定时器。仍未完成的是运行时验收:真实账号登录/续期/登出、微信支付与多窗口并发刷新。迁移必须保留账号/origin 隔离、幂等请求身份、失败关闭与既有数据恢复,不能通过增加一个任意 URL 的 HTTP IPC 代理伪装完成。
|
||||
|
||||
优先消除能在本地重复验证的请求放大:事件订阅必须在页面卸载和迟到 bootstrap 时同时释放前端监听与 Rust subscriber;持久化失败不得由 `setState → effect` 自触发无限重写;活动回合、本地生成任务和插件状态使用事件变化通知与启动快照,静止时不按周期读列表。正式状态仍以 Rust 注册表/账本为准,重复通知合并为一次在途读取和最多一次补读,旧作用域结果不能覆盖新项目。订阅不可用或首次读取失败必须明确报告可观察性失败,不能伪造业务终态。
|
||||
|
||||
低频离散状态使用事件即可,高吞吐流采用有界 channel 或已有 subscribe/consume 队列;二者都必须有订阅释放、初始快照、顺序/代次隔离和有界积压。显示耗时、验证码倒计时、动画和长按交互属于短暂 UI 状态,不与业务轮询混淆。只有上游没有推送能力时,才允许由 Rust 统一管理有界、可取消的轮询。
|
||||
|
||||
验证包含:静止窗口的业务读取计数、重复挂载/卸载后的 Rust subscriber 数、失败写入调用次数上界、通知并发单飞、旧项目/迟到响应隔离。真实交互时延须区分用户动作到本地反馈、IPC 等待、Rust 执行和远端网络耗时,未实测不得给出“几百毫秒已消除”的结论。
|
||||
|
||||
### 缺少 AGC application facade
|
||||
|
||||
账户素材库快照和图片预览由 Rust typed command 提供:read_editor_asset_library 只返回稳定 assetId、文件夹与展示元数据,read_editor_asset_preview 在 Rust 内完成当前账号解析、换签、有界下载、图片 magic/重定向/session 校验并返回 data URL。AssetImporter/ImageImporterPreview 不请求素材库或 read-url,也不把签名地址交给 WebView。远程导入只提交 assetId 列表和现有 policy/requirements,由 Rust 重新解析权威素材、下载并登记;预览字节不作为导入事实。React 切换素材、项目或卸载后忽略旧预览结果。
|
||||
能力散落在 `agent`、`editor_project.rs`、`external_editor_api.rs`、`ai_tasks.rs`、快照路由和生成队列中。它们各自可用,但调用方难以判断一项用户意图应该走本地 Run、云端 task 还是外部 generation operation。
|
||||
|
||||
**整理方向**:先建立逻辑 facade 和 capability catalog,保留现有路由作为 adapter;只有当两个以上入口共享同一业务流程时,才下沉 application service。
|
||||
|
||||
@@ -101,7 +101,7 @@ templates/
|
||||
| --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `fetch_game_template_library` | 读 `templates/index.json`(≤4 MiB),校验后缓存到 `<app_data>/templates/index.json`;网络失败时回退本机缓存并在 `source` 标 `cache`。远端已经答话但正文不是合法 UTF-8 或不符合 schema、以及缓存自己损坏时,一律失败关闭,不用缓存掩盖远端错误 |
|
||||
| `download_game_template` | 取清单里对应条目,流式下载 zip(≤512 MiB),校验字节数与 SHA-256,解压到 `<app_data>/templates/installed/<id>/<version>/`,最后写 `installed.json` 作为安装完成的唯一标记 |
|
||||
| `create_automatic_local_game_project_from_template` | 需要时先安装模板,然后在自动工作区根目录下按既有自动工作区规则建目录:先复制模板文件;Cocos 项目更新自身身份后走既有 Cocos 导入,Godot 项目改写工程显示名后走既有 Godot 导入,其余沿现有 `init_local_game_project_at` 初始化。根目录默认是 `<app_data>/projects/`,用户可选 `projectsRoot` 覆盖(必须来自本机目录选择器并通过私有路径门禁),见 [`【实施计划】AGC项目创建目录可选-2026-09-17.md`](../project-memory/plans/【实施计划】AGC项目创建目录可选-2026-09-17.md) |
|
||||
| `create_automatic_local_game_project_from_template` | 需要时先安装模板,然后在自动工作区根目录下按既有自动工作区规则建目录:先复制模板文件;Cocos 项目更新自身身份后走既有 Cocos 导入,Godot 项目改写工程显示名后走既有 Godot 导入,其余沿现有 `init_local_game_project_at` 初始化。根目录默认是 `<app_data>/projects/`;用户在设置「工作区」里改选的创建目录由 Rust 客户端偏好(`workspace-preferences.json`)持有,建项时由 Rust 读取并执行同一套私有路径门禁(非空绝对路径、普通目录、拒绝链接与 reparse point、user-selected 一次性修复) |
|
||||
|
||||
安全与健壮性:
|
||||
|
||||
|
||||
@@ -582,6 +582,8 @@ V1.11 把命令安全边界从“固定 program + argv 规则 + 隔离环境变
|
||||
|
||||
### V1.11.1 可信 launch 握手
|
||||
|
||||
Linux 一次性命令的退出确认按进程组最终状态判断:正常退出、取消与超时在同一有界清理预算内等待组内非 `Z / X` 成员消失,空组立即返回。bwrap leader 已回收而 namespace 后代尚在退出时,不凭一次瞬时扫描报错,也不向无法确认 leader 启动身份的进程组发送信号;持续存活、不可读或归属不明仍失败关闭。启动身份在放行目标前记录,terminal 协议错误也必须完成清理并停止输出 reader。回归用独立 subreaper 夹具控制后代退出时序,保留 CI 的现有并行与分片,不增加测试失败重试。
|
||||
|
||||
V1.11.1 必须把 `prepared -> child-created -> sandbox-ready -> commit-persisted -> exec-established -> running/exited` 做成 launcher 状态机,不能再把 bwrap 进程 spawn 或 `--json-status-fd` 的 `child-pid` 当作 sandbox-ready。实测 `child-pid` 会在 `--block-fd` 放行前出现,此时目标程序尚未执行;它只能证明 namespace child 已创建。关闭 block writer 也不能作为 abort,因为 bwrap 会把 EOF 当作可读并继续执行,失败关闭必须显式 kill + wait/reap。
|
||||
|
||||
- Linux 最终 `COMMAND` 必须先进入受信任 trampoline,而不是直接进入用户目标。trampoline 通过与 PTY/transcript 分离的私有控制通道发送带随机 nonce 的 `SANDBOX_READY`,等待 Runtime 完成 revision / verification gate / process record 的 durable commit 后接收 `COMMIT_EXEC`,再用 exec-error pipe 启动目标并回报 `EXEC_ESTABLISHED` 或 `TARGET_EXEC_FAILED`。commit 前的 EOF、错 nonce、协议错误和持久化失败都必须杀死并回收整个 bwrap 树,目标零执行。
|
||||
|
||||
@@ -1,5 +1,28 @@
|
||||
# AI 游戏创作智能体 App 实施计划
|
||||
|
||||
## 2026-09-29 Codex 私有运行目录路径解析
|
||||
|
||||
新建的私有运行目录先确认是普通目录并收紧权限,再解析真实路径,后续 `codex-home`、`workspace` 和隔离用户目录均在真实路径下创建,避免 macOS 系统临时目录的符号链接阻断启动。Windows 扩展 UNC 路径 `\\?\UNC\server\share\...` 必须转换为 `\\server\share\...`,盘符路径才直接去掉 `\\?\` 前缀;转换后保留绝对路径语义。私有子目录仍执行原有祖先符号链接与 reparse point 检查。
|
||||
|
||||
定向验证使用 Rust 单测过滤器 `codex_private_runtime_`,覆盖 UNC、盘符和普通路径转换,以及 Unix 祖先链接解析与内部链接拒绝;Windows 绝对路径断言在 Windows 测试环境执行。
|
||||
|
||||
## 2026-09-28 Web 环境版本探测的用户目录隔离
|
||||
|
||||
Node/npm 版本探测清空继承环境后,必须设置客户端创建的临时 `HOME`、`USERPROFILE`、`APPDATA` 和 `LOCALAPPDATA`,并指定空的用户及全局 npm 配置、临时缓存和临时工作目录。临时目录保留到探测子进程退出,不依赖 Windows 用户资料查询,也不读取用户或项目的 `.npmrc`。探测继续使用校验后的客户端运行时;初始化临时环境失败返回 `runtime-probe-home-unavailable`,不回退到系统 Node 或真实用户目录。
|
||||
|
||||
验证使用真实 Node/npm 的 `environment_check::tests::real_node_npm_environment_versions`,同时用 `src-tauri/tests/fixtures/environment-probe.cjs` 检查隔离目录及空配置,避免正常机器的 Windows 后备查询掩盖回归。测试通过 `include_str!` 引用独立夹具,不把 Node 环境断言内嵌到生产源码扫描范围。此测试需要本地 Node/npm,默认忽略,定向验收时显式运行;另运行 `npm run ai-game-creator-shell:typecheck` 覆盖配置静态检查。
|
||||
|
||||
## 2026-09-28 AGC 客户端现行分工:离线前端、事件驱动与维护态出口
|
||||
|
||||
本节是 AGC 客户端「React 只做展示与交互」的现行口径,取代更早文档里渲染层直连平台网络、按固定频率轮询、自行解析维护响应的做法。
|
||||
|
||||
- **网络与凭据只在 Rust**。平台 origin、Bearer/refresh 凭据、OSS 直传票据、Provider 与更新清单请求都由 `src-tauri` 承担;渲染层通过 typed command 提交结构化意图,不再持有 access token,也不再声明 `http:default` 权限(`capabilities/main.json`)。`src/services/clientApi.ts` 与 `fetchClientHttp` 已删除。
|
||||
- **状态变更由 Rust 事件驱动**。正式状态归 Rust:Direct 活动回合的唯一事实源是 Direct 线程管理器的活动回合快照(`list_direct_active_turns` 只读它),登记、进度内容变化、收口各广播一次 `game-creator-direct-active-turns-changed`;素材生成与插件状态同理。渲染层进入入口时**先订阅、再读一次受控快照**,事件重复或内容未变时保持数组身份,卸载后迟到事件不写回;不恢复任何固定频率轮询(纯 UI 计时器、拖拽重复器与动画 tick 除外)。
|
||||
- **维护态判定归 Rust,渲染层只订阅**。平台请求的错误分支统一经 `platform_maintenance::watch_platform_response` 分类(只有 `503` 且命中 `MAINTENANCE` 或「维护」才算,对象存储自身的 503 不误伤),命中后广播 `genarrative-client-maintenance-detected`;渲染层由 `clientMaintenance.subscribeClientMaintenanceEvent` 订阅并打开唯一的「系统维护中」弹窗,业务面板各自的错误文案保持不变,同一批并发失败只弹一次。
|
||||
- **失败文案只展示宿主给的脱敏摘要**。`turn.completed.failure` 是失败说明的唯一来源,渲染层不做 HTTP 判定、不预读诊断正文;失败线索留在 `.agent/runtime/errors`、应用日志与错误上报池(`5398a53e6` 起用户可见文案不再带诊断引用)。
|
||||
- **活动回合之外的两条配套约束**:命令返回 `Ok` 只代表接单成立,整轮收场只由 `turn.completed` 回答;渲染层的队列、忙态与提示都以事件流的这些终态为准。
|
||||
|
||||
证据入口:`cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml --offline -- direct_thread_manager --test-threads=1`、`-- platform_maintenance --test-threads=1`、`npx vitest run tests/directActiveTurns.test.tsx tests/maintenanceNotice.test.tsx --root apps/ai-game-creator-shell`。
|
||||
## 2026-09-23 UI 编辑器退役界面图参考语义建议
|
||||
|
||||
本节覆盖下文“2026-08-18 UI Editor 从属页面、手势与保存失败边界”中的 `UIDesignImage.metadata.slave_to` 口径,以及“界面语义建议”相关描述。
|
||||
@@ -182,6 +205,7 @@ UI 编辑器的“分析参考图”步骤、Rust 命令 `suggest_ui_design_sema
|
||||
- OAuth 在目录捕获与模型进程内产生的轮换结果仅在宿主私有 runtime 中延续,按原始认证来源指纹、路由、项目及稳定账户/用户身份绑定后复制到下一回合的新私有 HOME;不回写用户原始认证文件,不缓存 API Key。来源、路由或身份改变时不继承,迟到的旧实例不得覆盖新回合结果;轮换结果未确认时禁止重用旧 token。
|
||||
- 实例退役与验收完成使用不同判据:Windows 仍要求完整 Job 退出;Unix 已确认主进程退出且所控进程组为空时可退役并允许下一显式用户回合,但 group-only 证明不能使原会话从 Interrupted 升为 Completed,不能自动重放旧操作。主进程、所属组或退出状态仍未知时继续阻断新实例。
|
||||
- 补丁完整复用固定版本官方语法解析与执行语义。宿主枚举每个源和目标(包括所有 Move 和重复操作),检查项目边界、受保护路径和链接,在本地短写事务中复核后执行;取消、预算、退出证明和未知结果仍走统一宿主控制。失败可能已有部分修改,不能声称全批回滚或自动原样重放。
|
||||
- 2026-09-29:`agc_read_project_context` 与 `agc_list_project_files` 可以读取绝对路径,以及用 `..` 离开当前项目的路径。项目内相对路径仍拒绝 `.agent`、凭据文件名、符号链接和硬链接;项目外读取同样拒绝这些受保护名字和链接。项目外文件打开与目录列表须逐段检查访问路径(包括列表起始目录及其父目录),拒绝符号链接与 Windows 重解析点,不能只检查末段文件;目录扫描在进入子目录前再次检查。含系统目录别名的外部路径也遵守该规则,调用方应提供不含链接的真实路径。`agc_write_file`、`agc_apply_patch`、素材导入和原生补丁仍限定在当前项目。Codex 进程沙箱仍是 `read-only`。提示词未改。
|
||||
- 模型计划进度保存到同一回合的宿主状态,仅作展示,不等于验收通过;计划更新和长资源调用可以同时推进。真正共享资源的修改仍保持必要顺序。
|
||||
|
||||
### 验收
|
||||
@@ -1116,6 +1140,7 @@ game-project/
|
||||
- 结构化对话记录按授权本地项目路径追加 JSONL;正式聊天读取 Supervisor active Session 与只读 legacy 项目历史,开发单 Agent 对话读取对应 Agent Session。开发入口已支持本地 Session 新建、切换、归档和分叉,但不提供云端同步。
|
||||
- Agent 状态列表从 `.agent/manifest.json` 的任务 / 角色清单、`.agent/run.latest.json` / `.agent/runs/<runId>.json` 的 step、taskGraph、passPlans、lifecycleStatus,以及 `read_game_creator_agent_runtimes` 批量读取的 `.agent/runtime/agents/<taskId>.json` 和最近任务派生;v1 不新增独立状态数据库,也不承诺完整后台 runner。
|
||||
- 首页发送、项目组目录选择和本地文件选择必须使用 Tauri 非阻塞原生 picker,并把选择器绑定到当前 `client` 窗口;禁止在同步 command 中调用 `blocking_pick_folder` / `blocking_pick_file` 阻塞 WebView 事件循环。选择器打开期间保留首页草稿可编辑,取消后恢复“开启创作”按钮并回显“已取消”。
|
||||
- 外壳状态栏(首页输入框下方、项目组页面头部那一行)不占页面:`status` 一律由外壳的浮层承载(见 `LauncherNoticeToast`)。进行中进度与失败结论走粘性浮层,生存期与原来那行一致(被下一条状态替换或清空时才消失,切页回来仍可见);成功、取消这类回显走一次性浮层,成功与取消 2.6 秒、失败 6 秒收起。
|
||||
- GameAgent 首页“灵感推荐”当前使用客户端随包发布的内置图片素材,不请求主站 `/creation` 的陶泥儿精选 `/api/editor/showcase/resources`,也不引入远端灵感数据源。图片按原始宽高比组成响应式瀑布流,首页内容区域允许纵向滚动;点击图片只打开全屏原图预览,点击图片外遮罩或按 Escape 关闭,不展示标题或其它业务动作。后续改接远端数据前仍须先明确独立数据契约和交互验收。
|
||||
- 首页正式桌面版以约 `814px` 的居中内容栏组织品牌区、创作类型、输入框、最近项目与灵感推荐;品牌区和类型按钮在内容栏左缘对齐,输入框和下方模块仍保持整体居中。标题使用深色暖橙层级,固定副标题为“你的游戏创作管家”;选中的创作类型使用实心暖橙按钮,未选中项使用浅色描边,输入框使用更舒展的单行创作起始比例。
|
||||
- 最近项目固定展示至多三个横向信息卡:左侧为本地渐变封面占位,右侧只投影项目名称、项目类型、目录真实修改时间和已有最近运行状态。目录检查通过 `modifiedAt` 提供修改时间;没有封面资产时不得假装读取了项目封面,也不新增封面持久化字段。
|
||||
@@ -1442,7 +1467,8 @@ game-project/
|
||||
## 2026-08-20 Direct Codex 审核 Skill Pack 与受控工具内核
|
||||
|
||||
- 普通项目对话由一个 project-bound Codex app-server thread 执行。客户端系统提示词包含最小工程合同、项目 prompts 和审核 Skill 索引;源码与 Skill 正文按任务需要读取。提示词、工具描述与 Skill 直接描述当前任务、输入和成功条件,细节按调用需要提供。
|
||||
- 首页提供“做游戏 / 做素材 / 做方案”三个创作类型,默认“做游戏”。每次首页提交自动创建一个新项目并进入项目工作台。用户正文原样进入项目对话,`game|art|doc` 作为受限结构化首轮上下文传给同一 Codex thread。
|
||||
- 首页提供“做游戏 / 做方案”两个创作类型(`game` / `doc`),默认“做游戏”;“做素材”入口已退役,素材生成在项目内按实际工作流触发。每次首页提交自动创建一个新项目并进入项目工作台。用户正文原样进入项目对话,`game|doc` 作为受限结构化首轮上下文传给同一 Codex thread;持久草稿里遗留的 `art` 按 `game` 处理(`effectiveCreationType` 映射),不再产生第三种首轮上下文。
|
||||
- 「策划补全」是“做游戏”专属的提交前勾选(2026-09-15 起):勾选时该档提交 `planning`,未勾选时提交 `direct-build`;“做方案”始终走立项策划链路,与本勾选无关。复选框只在“做游戏”档渲染;切换创作类型时首页表面整体重挂,勾选状态随之清除,切回来必须是未勾选——这条可观察契约由 `appSurface` 的「scopes the 策划补全 option to the game entry」与「submits the game entry with planning when 策划补全 is checked」两条用例钉住,实现侧不额外维护重置逻辑。
|
||||
- 2026-09-23 清理了未注册的 DirectHome 用户对话命令及旧附件 sidecar 渲染链;首页仍先创建项目再进入 DirectProject,不恢复无项目对话。自动项目命名和提示润色仍调用内部 `direct_game_creator_home_codex_chat`,其 DirectHome 只读隔离通道与测试继续保留。附件作为 canonical `userItem.content` 中的 `agc_attachment_reference` 携带名称、媒体类型、大小、项目相对路径及状态,经现役 validation/wire 校验与投影;路径映射不等于灌入全文,也不按 GDD 特判。附件清洗与数量上限继续复用 `direct_codex_attachments.rs`,旧 sidecar DTO、header、专属 prompt key 和测试不再是保留合同。
|
||||
- `agc-skill-pack.v1` 包含完整游戏交付流程、项目结构、陶泥儿美术、Web 游戏实现、真实浏览器试玩、客户端资源投影,以及 Unity/Godot 编辑器常用操作八项审核 Skill。清单记录用途、触发条件、所需工具、版本和内容 SHA-256;审核文本按 UTF-8 读取并将 CRLF 规范为 LF 后计算指纹和安装,避免混合换行造成 Windows / Linux 构建结果漂移,语义内容变化时必须同步重算对应清单指纹并提升版本。同步统一运行 `npm run agc:skill-pack:sync`,只读校验由 AGC `typecheck` 和 release build 自动执行,发现漂移时直接列出 Skill 与实际摘要,不让失配内容进入构建产物。客户端把审核文件安装到隔离目录后通过 app-server `skills/extraRoots/set + skills/list` 注册并复核,完整正文由 Codex 原生 Skill 机制按意图加载,一层引用只能经 `agc_read_skill_resource` 读取清单内 Markdown。引用路径按平台无关规则拒绝反斜杠、盘符、UNC、绝对路径和 `..`,不能依赖当前宿主的 `std::path` 语义判断其它平台路径。
|
||||
- DirectProject 连接客户端内置的 `agc_tools` STDIO MCP,并在启动时接入客户端扩展仓库中用户已启用的独立第三方 STDIO/HTTP MCP 配置。内置工具包括审核引用读取、图片生成、标准陶泥儿美术准备、已登记资源有界查询、视频 / 角色动画 / 音效 / BGM 的 create-or-derive 语义生成、已登记图片去背景、desktop/mobile 浏览器试玩和受控 `agc_web_search`。内置 MCP 进程负责协议;真实浏览器、付费平台调用与受控搜索通过随机 loopback 地址回到客户端主进程,GUI 登录态、开发者 Key、项目路径、revision、operation 与幂等键由客户端持有并隔离于模型上下文。内置与用户启用的第三方 MCP 工具沿用 DirectProject 自动批准方式;付费资源工具由客户端绑定稳定回合身份、串行执行并优先恢复匹配账本。`llm.webSearchEnabled` 控制 DirectProject 的 AGC 受控搜索工具暴露与执行。原生工具与审批权限以下方“DirectProject Codex 完整访问覆盖”为准。
|
||||
@@ -1493,6 +1519,9 @@ game-project/
|
||||
|
||||
## 2026-08-23 Direct Codex 美术包显式重生成与切片投影
|
||||
|
||||
- 标准美术包在客户端将规范图、背景图和主图集统一保存为 PNG:下载仍校验来源、声明类型与文件签名,随后按真实内容接受 PNG/JPEG/WebP,在已有 20 MiB、4096 像素单边和 64 MiB 解码内存限制内完整解码。有效 PNG 原样保留,JPEG/WebP 编码成 PNG,最终内容也不得超过 20 MiB;本地媒体类型固定为 `image/png`。转码不补造透明度,主图集与独立切片继续执行真实 alpha、可见像素、尺寸和唯一性合同;平台独立切片仍须为 PNG。此行为仅属于美术包,普通图片工具的指定扩展名合同不变。
|
||||
- 美术包的转码在项目提交锁和本地写入之前完成,文件摘要、已安装结果识别、替换恢复和 manifest 登记均使用最终 PNG。转码失败保留原生成账本与平台身份,同冻结意图重试重新读取已有结果,不提交新的付费生成;不改变请求快照、幂等身份、固定资源路径或旧 PNG 包的复用方式,无数据迁移。验收覆盖 JPEG/WebP 转码、PNG 字节不变、损坏/超限拒绝、真实透明度以及已有结果重复恢复零生成 POST;客户端真实 Provider 的整包验证单独记录。
|
||||
- 转码自动化验收由 `canvas_generation_tests` 的格式/边界用例和 `retained_runtime_generation_retries_a_completed_stage_without_posting_again` 本地 HTTP 夹具覆盖:PNG/JPEG/WebP 均先下载损坏内容,再从同一已完成账本恢复两次,核对最终 PNG、稳定本地 asset ID、Canvas 来源身份、账本保留/清理及零生成 POST;替换与补偿继续由现有图集事务和 Direct 重生成用例覆盖。真实 Provider 的客户端整包效果不由这些夹具替代。
|
||||
- `agc_tools.taonier_prepare_game_art` 的请求模式固定为 `reuse-or-create | regenerate`。缺省使用 `reuse-or-create`,完整且可信的本地包继续零付费复用;只有用户显式要求重做、替换或切换视觉风格时使用 `regenerate`,并绕过完整包短路,按规范图、背景图、透明图集顺序生成和原位替换。`regenerate` 的旧包前置门只要求规范图和背景图已经可下载、可解码、来源一致且存在可信 manifest 登记,使两项旧字节与登记可以完整 rollback;历史主图集、私有回执、公开清单或 canonical 切片可以缺失。客户端必须把八个严格路径的实际存在性和摘要,以及其中受管顶层 asset identity,逐项冻结为 `Present/Some` 或 `Missing/None`,不能把缺失状态伪造成空文件或虚假登记。规范图或背景图任一缺失或身份无效时才失败关闭并提示先用 `reuse-or-create` 修复基础素材。
|
||||
- 显式重生成不放宽 External Editor 幂等与未知态边界。固定阶段已有 `prepared / accepted` 账本时,本次生成 prompt 必须与账本冻结 prompt 一致才可恢复;不一致返回 `platform-generation-result-unknown` 并保留原 `Idempotency-Key / operationId` 对账,禁止把旧结果解释为新意图,也禁止另起付费 POST。
|
||||
- 整包重生成在首个付费阶段前建立客户端私有 v4 workflow,状态固定为 `resetting / in-progress / compensating / completed`,并同时绑定意图摘要和客户端稳定 `clientTurnId`。专用 `direct-codex-art` 跨进程执行锁覆盖整个付费重生成生命周期,但不持有通用项目写锁等待网络。规范图和背景图替换后立即持久化旧字节、旧 manifest entry 与本轮双 CAS 锚点;任一后续阶段失败时进入 `compensating`,可在进程重启后继续恢复旧文件及旧登记。已成功阶段的生成账本继续保留;`completed` 持久化经脱敏和数量 / 长度限制的完整工具结果,同一 `clientTurnId` 回包丢失时必须等值重放且零新 POST。新的显式用户回合先持久化目标回合所有的 `resetting` workflow,再清理上一轮三阶段账本并转回 `in-progress`,任一崩溃点都不得出现无 workflow 窗口。只有尚无任何阶段账本且无替换锚点的孤立 `in-progress` 空壳允许被新回合原子接管;其余身份冲突、未知版本以及缺少新恢复字段的旧 v2/v3 workflow 均失败关闭,不能用 serde 缺省值把旧状态升级成可执行状态。
|
||||
@@ -1622,6 +1651,8 @@ DirectProject、Agent Runtime、Provider、app-server、内置 MCP、命令执
|
||||
|
||||
项目内统一落库目录为 `.agent/runtime/errors/`,事件记录采用幂等 JSONL 或 JSON sidecar;写入失败不能覆盖原始业务错误,但必须在事件中标记 `persistenceFailed`。DirectProject 对话历史必须持久化本轮用户消息、终态错误的安全 assistant 投影和诊断引用,使下一轮能够读取上一轮失败证据。前端只展示 `publicText`,点击详情后按 `detailRef` 读取有界、脱敏的诊断,不直接展示私有 `detail`。
|
||||
|
||||
前端取回 `detailRef` 的口径是失败文案末尾的固定后缀「;详情:<detailRef>」:Rust 侧 `direct_codex_failure_text_keeps_the_detail_ref_marker_for_the_renderer` 与前端 `tests/agentRuntimeErrorDetail.test.ts` 各自钉住同一份文案形状与它的解析,任一侧改文案或改解析都会变红。失败提示只展示映射后的安全 `publicText`(v1 历史形状与 v2 现行形状都映射成「阶段 + 摘要 + 建议 + 是否可直接重试」),诊断正文不在提示里预读、也不写入历史投影,而是由聊天状态栏下方的「查看详情」入口按需调用只读命令读取并二次脱敏;这条交互由 `tests/appSurface/chat-composer.suite.ts` 的「失败提示保留可执行原因,诊断正文只在「查看详情」时读取」与 `tests/agentRuntimeModel.test.ts` 的 v2 映射用例钉住,渲染层仍不参与错误分类。
|
||||
|
||||
`turn/completed` 等待超时必须区分 `idle-timeout`、`hard-timeout`、`transport-closed`、`failed-turn`、`invalid-terminal` 和 `tool-error`;收到内置工具参数错误后必须结束当前工具调用并进入可行动终态,不能继续使用越界的试玩 `attempt` 或无限等待。试玩次数由客户端按当前 `clientTurnId` 持久化分配,模型不能自由递增;超过上限必须返回一次终态并停止回合。
|
||||
|
||||
游戏素材完成门必须扫描实际参与构建的 `game/` 源码模块,读取 manifest 的登记身份与相对路径,并把构建后的 URL 映射回登记身份。固定素材路径只能作为兼容候选,不能作为唯一准入。已登记且被真实源码引用、被构建纳入并在浏览器证据中观察到的资源通过;未登记、来源不匹配或只存在于设计规范中的资源继续失败关闭。
|
||||
@@ -1728,6 +1759,22 @@ Direct 回合的所有权属于进程内项目身份锁,不属于当前页面
|
||||
- 运行时 smoke:AGC 开发态打开项目、观察索引写入与同步日志、关闭工作区窗口后确认关闭触发的那次同步执行;报告为"客户端 diff 已验证 / 服务端已配置环境联调"两层,不合并成一句"已通"。
|
||||
- 边界:新增日志与错误文案不含 Access Token、AccessKey、绝对路径与项目内容。
|
||||
|
||||
| 验收面 | 对应证据 |
|
||||
| --- | --- |
|
||||
| 首次全量、单文件改动、删除与摘要复用 | `project_snapshot_diff_reuses_metadata_and_reports_a_single_modification`、`project_snapshot_diff_treats_touched_but_identical_content_as_metadata_only`、`project_snapshot_manifest_metadata_changes_sync_without_content_changes` |
|
||||
| 排除口径与 `.agent` 整目录上传 | `project_snapshot_scan_skips_excluded_paths_and_oversized_files`、`project_snapshot_scan_uploads_whole_agent_directory`、`project_snapshot_sync_policy_keeps_agent_state_and_still_blocks_credentials` |
|
||||
| 单次预算、延后与失败文件不推进索引 | `project_snapshot_diff_defers_files_over_the_sync_budget`、`project_snapshot_synced_files_exclude_failed_and_deferred_paths`、`project_snapshot_pending_files_include_every_unsynced_path_once` |
|
||||
| 幂等跳过与确定性鉴权失败停止 | `project_snapshot_upload_marks_remote_duplicates_and_sends_marker_headers`、`project_snapshot_upload_stops_after_a_deterministic_authentication_failure` |
|
||||
| 同步期间被改写的文件不上传也不推进索引 | `project_snapshot_diff_defers_files_that_changed_while_being_read`、`project_snapshot_upload_skips_files_that_changed_after_the_diff` |
|
||||
| 同项目串行化、周期触发让位与退出等待 | `project_snapshot_sync_is_serialized_per_project`、`project_snapshot_periodic_trigger_yields_while_a_sync_is_in_flight`、`project_snapshot_exit_wait_includes_scheduled_tasks_waiting_for_the_project_lock` |
|
||||
| 单窗口生命周期登记与项目身份校验 | `project_snapshot_workspace_lifecycle_tracks_the_single_client_window`、`project_snapshot_independent_window_url_supplies_a_fallback_project`、`project_snapshot_project_id_validation_rejects_paths_and_unsafe_values` |
|
||||
| 索引往返、损坏恢复与旧清单完整性未知 | `project_snapshot_index_round_trips_and_recovers_from_corruption`、`project_snapshot_legacy_index_keeps_completeness_unknown` |
|
||||
| 远端回收只删上一版登记过的对象、读不到上一版一张不删、单轮有上限 | `project_snapshot_reclamation_retires_only_objects_the_previous_manifest_registered`、`project_snapshot_reclamation_deletes_nothing_without_a_readable_previous_manifest`、`project_snapshot_reclamation_is_bounded_per_manifest_write` |
|
||||
| 服务端校验、413 与 429、渠道失败关闭 | `project_snapshot_manifest_rejects_duplicates_and_out_of_range_values`、`project_snapshot_manifest_rejects_too_many_entries`、`project_snapshot_manifest_rejects_a_project_over_the_total_cap`、`project_snapshots_upload_accepts_empty_files_and_rejects_false_checksums`、`project_snapshot_user_quota_stops_after_the_hourly_file_limit`、`project_snapshot_channel_fails_closed_on_invalid_configuration` |
|
||||
| 真实 OSS 往返 | `project_snapshot_live_sync_uploads_once_then_reports_no_op`(默认忽略,需要 `GENARRATIVE_AGC_PROJECT_SNAPSHOT_LIVE_PROJECT` 与真实 api-server / OSS 凭据) |
|
||||
|
||||
本轮定向证据:客户端 `cargo test --manifest-path apps/ai-game-creator-shell/src-tauri/Cargo.toml project_snapshot -- --test-threads=1` 为 24 passed / 1 ignored;服务端 `cargo test -p api-server project_snapshot -- --test-threads=1` 为 21 passed / 1 ignored。真实 OSS 往返、开发态打开项目的索引写入与关窗触发仍属运行时 smoke,未在本轮取得证据。
|
||||
|
||||
### 后台工程列表与下载
|
||||
|
||||
- 正式客户端在单窗口内切换启动器和项目,不以窗口 URL 判断活动项目。前端把当前窗口的已打开项目登记给原生同步器;打开后发起首轮同步,离开/切换项目和物理关窗为旧项目补同步,周期扫描只读这份窗口登记。重复登记同一路径不重复发起;注册失败写诊断,不能假装已登记。
|
||||
|
||||
@@ -193,3 +193,20 @@ subscriber 不依赖 `unsubscribe` 或传输层断开清理。每次 `subscribe`
|
||||
`subscribe` 必须在同一个 Thread Manager 边界注册 subscriber、捕获 queue 尾部、确定历史锚点和当前运行态事件;bootstrap 期间产生的新事件由该 subscriber 的内部 cursor 继续通过 `consume` 获取,不能丢失。
|
||||
|
||||
断线恢复优先调用 `consume(subscriptionId)`。subscription 仍有效时只返回该 subscriber 尚未消费的 queue 事件;subscription 已过期或 Thread Manager 重启后统一走新的 `subscribe`,再由前端按 `lastCompletedItemId` 从历史懒加载。Rust 不提供 `getItemSnapshot(itemId)`,已完成 item 始终通过历史读取。
|
||||
|
||||
### 钉住本节的用例(2026-09-24 复核)
|
||||
|
||||
本节的行为由以下用例守住;改动 Thread Manager 时按同一清单复核:
|
||||
|
||||
| 契约 | 用例 |
|
||||
| --- | --- |
|
||||
| 多 subscriber 各自游标、互不推进 | `direct_thread_manager::tests::subscribers_have_independent_cursors_on_one_global_queue` |
|
||||
| 逻辑队头回收与落后订阅过期 | `queue_cleanup_only_removes_a_cleanable_prefix`、`slow_subscriber_is_expired_when_queue_limit_is_reached` |
|
||||
| 完成事件只在 item 持久化后入队 | `completion_releases_item_events_only_after_the_completion_event_is_appended` |
|
||||
| 生命周期锚点独立于 replay 队列 | `turn_completed_anchor_survives_empty_queue_for_new_subscriber`、`bootstrap_contains_lifecycle_anchor_and_unfinished_events_only` |
|
||||
| 未完成 item 从 opener 起可重放、未决审批保留 | `bootstrap_replays_opener_user_item_id`、`unresolved_approval_is_kept_in_bootstrap_until_resolved` |
|
||||
| 订阅释放幂等且能回收队头 | `unsubscribe_releases_the_subscriber_and_is_idempotent`、`unsubscribe_allows_a_cleanable_prefix_to_be_trimmed` |
|
||||
| legacy 历史行失败关闭(不 fallback、不迁移) | `direct_project_history_item_from_parsed_line` 对非 canonical `type` 直接报错;见 `direct_project_history` 定向用例 |
|
||||
| 前端按 `subscriptionId` 唤醒并处理回执竞态 | `apps/ai-game-creator-shell/tests/directThreadChatSubscription.test.tsx` |
|
||||
|
||||
运行时验收(关闭/切页后重进、并发 item、短暂断线 consume、过期重订阅)仍需真实客户端执行;自动化只覆盖到此表为止。
|
||||
|
||||
@@ -126,7 +126,7 @@ Project 头与行(禁止出现 GDD / 规格 / 权威 / 必须读取):
|
||||
### 3.3 谁渲染、谁看见
|
||||
|
||||
- sidecar **只在进 Codex 前由 Rust 拼装**。
|
||||
- `.agent/conversations/project.jsonl` 继续写用户原文(现有 `append_local_conversation_message`)。
|
||||
- `.agent/conversations/project.jsonl` 继续由 Rust Direct/Design coordinator 写入用户原文;React 渲染层只保留当前页面投影,不再通过通用 `append_local_conversation_message` 追加聊天行。
|
||||
- 工作台气泡继续显示 latch / 输入框原文,不把 sidecar 画进 UI。
|
||||
- 未完成首轮的 hydration 重放目前只带 prompt:本期不把附件写进 jsonl,进程重启后的未完成首轮可能丢映射。完整成功首轮不受影响。不为此新增会话 schema。
|
||||
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
# 【技术方案】External v1 游戏场景生成路由
|
||||
|
||||
更新时间:`2026-09-24`
|
||||
|
||||
## 目标
|
||||
|
||||
为 `/api/external/v1` 补齐游戏场景生成的结构化专用路由,使 AGC 客户端(陶泥儿美术包背景阶段)在平台收紧 `kind = scene` / `assetKind = scene` 边界校验后仍有合规的场景生成入口:
|
||||
|
||||
```text
|
||||
AGC 美术包背景阶段(结构化场景意图)
|
||||
-> POST /api/external/v1/editor/scenes/generations
|
||||
-> 后端确定性组装场景 Prompt(与站内场景路由同一实现)
|
||||
-> 现有 editor_image_generation 队列与 Worker
|
||||
-> 现有计费、幂等、失败、资源持久化与 canvasCompletion
|
||||
```
|
||||
|
||||
同时修复 AGC 客户端背景阶段保留账本匹配口径与实际请求不一致的既有隐患。
|
||||
|
||||
## 非目标
|
||||
|
||||
- 保持站内 `/api/editor/scenes/generations` 的场景字段、Prompt 和计费规则;补齐 AGC 账号模式所需的可选幂等键与队列结果协议。
|
||||
- 不放松通用 `/api/editor/images/generations` 与 `/api/external/v1/editor/images/generations` 对 `kind = scene` / `assetKind = scene` 的拒绝。
|
||||
- 不新增场景 Worker、任务表、计费档位或 SpacetimeDB schema。
|
||||
- 不改变美术包背景图的出图风格与尺寸(16:9 / 1K)。
|
||||
- 不处理 issue #495 的抠图重放 409 与动画 compact 字段问题(独立排期)。
|
||||
|
||||
## 入口与边界
|
||||
|
||||
- 系统入口:AGC 客户端 Direct 美术包流程的背景阶段(`reuse-or-create` 与 `regenerate` 均经过)。
|
||||
- 涉及模块:`api-server`(external v1 路由与场景 Prompt 组装)、`shared-contracts`(DTO 复用)、AGC `src-tauri`(请求构造、保留账本、身份对账与恢复扫描常量)。
|
||||
- 正式状态来源:`external_generation_job` 队列记录与项目 manifest 登记,与现役外部生成入口一致。
|
||||
|
||||
## 必须成立的行为
|
||||
|
||||
### 正常路径
|
||||
|
||||
1. 新路由 `POST /api/external/v1/editor/scenes/generations` 接受与站内场景路由相同的 `EditorSceneGenerateRequest` 字段(`sceneContent`、`stylePreset`、`customStyle?`、`model?`、`aspectRatio?`、`imageSize?`、`referenceImageSrcs?`、`projectId?`、`generationInputs?`、`assetFolderId?`、`assetLabel?`、`canvasCompletion?`),不接受调用方组装后的完整 `prompt`。
|
||||
2. 场景 Prompt 由后端经与站内路由完全相同的组装实现生成;两路由只共享这一份组装逻辑。
|
||||
3. 鉴权复用现有 `editor:image-generate` scope;与现役外部生成入口一样强制 `Idempotency-Key` 请求头。
|
||||
4. 受理响应与现役外部生成入口同形(operationId 异步受理信封),轮询继续走 `/api/external/v1/generations/{operation_id}`。
|
||||
5. 入队后 `kind = scene`、`assetKind = scene`,队列类型、Worker、计费与持久化与站内场景路由一致;队列标题与任务摘要口径不变。
|
||||
6. AGC 美术包背景阶段以 `stylePreset = custom` + `customStyle` 承载现有风格描述,`sceneContent` 承载 brief 衍生的画面内容,出图风格与比例不因迁移改变。
|
||||
7. 普通账号自动映射到 `/api/editor/scenes/generations`,该入口读取可选 `Idempotency-Key` 并传给现有队列;未提供时保留站内按请求 ID 入队的行为。场景组装仅保留 `generationInputs.source = ai-game-creator-client` 这一精确标记,其余配方字段仍由服务端重建。该标记让账号任务沿用 AGC 幂等命名空间和包含可下载 `result` 的队列结果,轮询走 `/api/runtime/external-generation/jobs/{operation_id}`。
|
||||
|
||||
### 失败、重试与幂等
|
||||
|
||||
1. 缺少 `sceneContent`、非法 `stylePreset`、自定义风格缺少 `customStyle` 等参数错误返回 400,与站内路由同语义。
|
||||
2. 缺少或非法幂等键、越权 scope 的拒绝语义与现役外部生成入口一致。
|
||||
3. 同一幂等键 + 同一请求重放返回原任务,不新建任务、不重复扣费;同键不同请求返回 409。
|
||||
4. Provider 失败、取消与 lease 耗尽沿用现有扣退费语义。
|
||||
5. 账号场景入口拒绝非法幂等键(400);同键重放复用现有队列幂等实现。来源标记不参与权限授予,任务归属仍来自已认证用户。
|
||||
|
||||
### 权限、归属与数据边界
|
||||
|
||||
1. 资源归属、项目绑定与素材文件夹解析沿用现役外部生成入口的 owner 口径。
|
||||
2. 任务摘要只展示 `generationInputs.fields` 的「画面内容」,不把后端完整 Prompt 暴露到任务侧栏。
|
||||
3. 场景产物以 `assetKind = scene` 持久化并保存 `scene.generate` V2 配方,与站内产物口径一致。
|
||||
|
||||
## 契约与迁移
|
||||
|
||||
- API / DTO / OpenAPI:新增 external v1 场景路由,DTO 复用 `shared-contracts` 的 `EditorSceneGenerateRequest`;同一次变更同步 `docs/openapi/genarrative-external-v1.openapi.json` 与契约测试(路由矩阵、鉴权、参数 400、幂等重放)。
|
||||
- SpacetimeDB schema / migration / bindings:不变。
|
||||
- 兼容与迁移策略:AGC 客户端背景阶段的路由、manifest 身份登记、保留账本匹配与恢复扫描常量整圈迁移到新路由;历史已登记的背景身份(旧通用路由 + `kind = spec`)保持可读,不做数据迁移。
|
||||
|
||||
## 验收标准与证据
|
||||
|
||||
| 条款 | 验收方式 | 证据 |
|
||||
| ---- | -------- | ---- |
|
||||
| 账号入口幂等键校验与 AGC 下载结果 | 非法键路由测试、场景来源到结果序列化测试、共享队列幂等命名空间测试 | `cargo test --locked -p api-server scene`(18 项)、`editor_generation_queue::tests`(19 项)、`external`(158 项)通过;本地启动因 SpacetimeDB 连接拒绝未通过健康检查,真实 Provider 出图与账号同键重放尚未联调 |
|
||||
| 新路由受理/参数校验/鉴权/幂等重放 | api-server 契约测试与单测 | 待补 |
|
||||
| 与站内路由同一 Prompt 组装结果 | 共享实现的单测对照 | 待补 |
|
||||
| OpenAPI 与实现一致 | 契约测试 + `check:openapi` 类门禁 | 待补 |
|
||||
| 美术包背景端到端(reuse-or-create / regenerate) | 客户端定向测试 + 本地真实栈 smoke | 待补 |
|
||||
| 中断恢复:保留账本匹配与身份对账 | 客户端定向测试 | 待补 |
|
||||
|
||||
## 未决问题与决策
|
||||
|
||||
- `stylePreset` 取舍:已决策——AGC 美术包背景固定 `custom` + `customStyle` 承载现有风格文案,不绑定预设风格(2026-09-24,与用户确认)。
|
||||
@@ -1,6 +1,6 @@
|
||||
# 策划 Agent 生产迁移与工作区浏览方案
|
||||
|
||||
更新时间:2026-09-23
|
||||
更新时间:2026-09-29
|
||||
状态:已完成(2026-09-18)
|
||||
|
||||
> 现状说明(2026-09-18):本文记录的迁移已完成,当前策划入口统一使用 Design Agent。旧 Planning V1/V2 会话、专用命令、审批卡和展示适配已删除;文中提到的 V2 文件仅代表迁移时的参考来源,不得作为现行实现、回退路径或测试迁移目标。
|
||||
@@ -14,7 +14,7 @@
|
||||
迁移后,策划 Agent 应能:
|
||||
|
||||
- 持续接收用户自然语言指示;
|
||||
- 自由读取、创建、写入、局部修改、删除和搜索工作区文件;
|
||||
- 自由读取、创建、写入、局部修改、删除和搜索工作区文件,并对绝对路径和工作区外路径做同样的读写;
|
||||
- 按五个策划阶段推进,并在最后进入顾问态;
|
||||
- 按阶段注入提示词和明确要求的必读资源;
|
||||
- 通过澄清卡或普通文本向用户询问;
|
||||
@@ -45,7 +45,7 @@
|
||||
| Provider 重试 | 复用瞬态错误识别、退避、最大重试次数和失败持久化 |
|
||||
| 会话持久化 | 复用项目级会话目录、原子写入和恢复入口,但使用新的设计会话数据结构 |
|
||||
| 并发保护 | 保留项目级短时写锁和会话活跃保护,防止文件或状态写入损坏 |
|
||||
| 文件底层能力 | 按原型工具契约筛选已有底层函数;绑定工作区,剥离旧业务门禁;缺少的目录删除、搜索等能力局部补齐 |
|
||||
| 文件底层能力 | 按原型工具契约筛选已有底层函数;工作区内沿用原写入,并接受绝对路径与离开工作区的路径;缺少的目录删除、搜索等能力局部补齐 |
|
||||
| 审计与 debug | 复用正式动作记录和诊断采集;恢复或审计必需资料保存在 `.agent`,额外 debug 改为只写、可删除、不阻塞的旁路 |
|
||||
| Tauri 通信 | 复用命令注册、事件流、会话恢复通知和前端状态同步机制 |
|
||||
| 用户文件浏览 | 复用 Game Agent 的文件列表、文件读取和工作区刷新模式 |
|
||||
@@ -68,7 +68,7 @@
|
||||
- 旧的“批准 / 修改 / 退回重做”审批语义;
|
||||
- 多 Agent、Wiki、知识库、外部搜索和自动任务编排。
|
||||
|
||||
路径穿越、绝对路径、控制目录访问和凭据泄露防护属于安全边界,可以保留;它们不能扩展成限制正常策划创作的业务门禁。
|
||||
2026-09-29:策划文件工具可以读取和写入绝对路径,以及 `design_artifacts` 之外的路径。相对路径仍以策划工作区为基准,`..` 可以离开工作区。用户工作区浏览和附件导入仍只使用 `design_artifacts`。删除允许路径经过祖先链接;删除目标本身是链接时只移除链接(包括悬空链接),递归删除目录不跟随其中的目录链接。删除普通目录前以真实路径检查目标,拒绝工作区根目录及其上级目录,绝对路径中的 `..`、大小写或祖先链接别名均不得绕过;检查必须在删除任何内容前完成。相对删除路径保留 `..`,按文件系统实际链接目标解析,不提前做字符串折叠。凭据不写入提示词或日志。
|
||||
|
||||
当前实现入口如下:
|
||||
|
||||
@@ -76,8 +76,8 @@
|
||||
| --- | --- |
|
||||
| `apps/ai-game-creator-shell/src-tauri/src/agent/design_runtime.rs` | Provider 请求、工具循环、重试、阶段审批与会话恢复 |
|
||||
| `apps/ai-game-creator-shell/src-tauri/src/agent/runtime_protocol/design_session.rs` | 设计会话、阶段状态与待交互请求的持久化 |
|
||||
| `apps/ai-game-creator-shell/src-tauri/src/agent/design_tools.rs` | 固定资源包、工作区文件读写、补丁、删除、搜索与路径安全边界 |
|
||||
| `apps/ai-game-creator-shell/src-tauri/src/project/filesystem.rs` | 路径解析、文件列出和读取、基础写入;内部绝对路径字段不得传给模型 |
|
||||
| `apps/ai-game-creator-shell/src-tauri/src/agent/design_tools.rs` | 固定资源包与文件工具。文件工具接受工作区相对路径、离开工作区的相对路径和绝对路径;用户浏览与附件导入仍限定在策划工作区 |
|
||||
| `apps/ai-game-creator-shell/src-tauri/src/project/filesystem.rs` | 项目内路径解析、文件列出和读取、基础写入。该模块返回给界面的内部绝对路径字段仍不是模型输入 |
|
||||
| `apps/ai-game-creator-shell/src/App.tsx` | Design Agent IPC、事件订阅、文件刷新、会话恢复与输入提交 |
|
||||
| `apps/ai-game-creator-shell/src/features/project-workspace/DesignWorkspacePanel.tsx` | 策划工作区文件浏览与正文展示,直接打开文件视图 |
|
||||
| `apps/ai-game-creator-shell/src/features/project-workspace/DesignAgentSurface.tsx` | 消息、reasoning、澄清与阶段审批交互 |
|
||||
@@ -124,7 +124,7 @@ Runtime 不维护文档版本号,不解析文档版本,不提供版本回退
|
||||
|
||||
**交付结果**:策划 Agent 对话复用 GameAgent 的模型、推理档选择控件及配置通道,用户的新选择对后续策划回合实际生效,并保持 GameAgent 原有行为兼容。
|
||||
|
||||
本节是本次变更的唯一主规范。控件接入已完成并提交,运行时模型生效逻辑已实现、待验收。拆分与验收见 [控件接入里程碑](../project-memory/plans/【里程碑】策划Agent模型与推理档控件接入-2026-09-20.md) 和 [模型生效里程碑](../project-memory/plans/【里程碑】策划Agent回合模型选择生效-2026-09-20.md)。
|
||||
本节是本次变更的唯一主规范。控件接入已完成并验收(对应开发期里程碑与实施计划已归档删除,结论以本节为准);运行时模型生效逻辑已实现、待验收,见 [模型生效里程碑](../project-memory/plans/【里程碑】策划Agent回合模型选择生效-2026-09-20.md)。
|
||||
|
||||
#### 范围与非目标
|
||||
|
||||
@@ -223,16 +223,28 @@ submit_phase_for_approval
|
||||
get_workflow_status
|
||||
```
|
||||
|
||||
工具使用相对工作区路径。工具执行结果继续通过 Runtime 统一记录和展示,但不向 Agent 暴露宿主绝对路径。
|
||||
文件工具的 `path` 可以是工作区相对路径、含 `..` 的路径或绝对路径。相对路径以 `design_artifacts` 为基准。工具结果按实际目标返回:工作区内用工作区相对路径,工作区外用解析后的绝对路径,并写入 Runtime 会话记录。
|
||||
|
||||
`patch_file` 保留原型按唯一原文匹配、范围不重叠、全部通过才原子写入的语义、换行归一化和缺文件错误。批量 edits 会一次性完成全部校验,并把未找到、多处匹配、重叠等失败项汇总返回;未找到时同时给出候选行号和可见化缩进提示,帮助 Provider 基于当前文件修正锚点。正常工作区写入与删除不逐次请求用户审批;阶段审批不能被复用为文件操作许可。
|
||||
|
||||
`list_resources` 一次返回完整逻辑分类、资源 ID、标题和简介;`read_resource` 按一个资源 ID 读取一个文件。资源描述不增加 `required=true/false` 分类,也不增加引导同轮多次调用的说明。
|
||||
|
||||
`read_resource` 成功后的用户可见工具提示只显示“读取资源”,不附加资源 ID 或名称。文件工具继续显示原有路径,失败提示保持原样;资源目录、工具参数、实际读写及 Provider 收到的工具结果不变。此规则作用于新生成的工具提示,不回写已有会话消息。
|
||||
|
||||
`get_workflow_status` 只返回阶段列表、当前阶段、已批准阶段和待审批阶段,不修改状态。保留原型的常驻提示约束:用户口头表示批准或要求进入下一阶段时,Agent 先查询实际阶段,不能凭普通文本自行切换。现有 `agent.run_status` 的任务/委派状态不能替代这个工具。
|
||||
|
||||
## 6. 阶段与提示词注入
|
||||
|
||||
常驻提示词统一要求按具体项目的需求、规模和复杂度安排文档结构与内容密度。模板和样例仅供参考,章节与字段可按需增加、合并或删减;简单内容简述,复杂或易歧义处充分展开,不为填模板增加设计、重复论证或无关内容。精简须保留当前阶段判断与后续实现所需信息,TDD 仍须独立指导当前范围的实现。
|
||||
|
||||
2026-09-27:常驻提示词删除每次修改文件后汇报修改内容和相对路径、将不确定内容统一分为用户确认/Agent 建议/待原型验证事项的要求。汇报形式按当前协作需要决定;仍按后文规则标注暂定方案并就关键问题询问用户。提示词简化可以调整核心行为,以调整后的行为是否合理作为评估依据。
|
||||
|
||||
概念层规则、模板和样例围绕核心体验、主要吸引力与重要边界组织。先利用已有对话和资料,仅按影响当前设计的缺口补问;模板与样例按需读取,参照只说明具体借鉴点,不自动继承参照作品的全部设计。章节按项目需要选取,不要求固定句式、字数、唯一卖点、六项锚点、调性滑杆、T 编号或重复定稿,也不要求先回答固定定调问题或标注“零参照”。
|
||||
|
||||
概念层的设计原则帮助后续判断方向,不替代具体问题的分析。说明核心体验所需的数值、操作方式和界面形式可以保留,详细规则、数值平衡和界面规格留待后续展开;规模依据实际团队和项目条件确定。交付检查聚焦概念是否清楚、是否符合已有意图和约束、是否存在影响交付的矛盾或缺口,避免为填模板编造内容。
|
||||
|
||||
下游按相关内容或章节承接概念,不强制张力逐条对应或附编号;TDD 美术规则与样例不再依赖概念层固定第 2 节或 T 原则。美术圣经保留设计依据及来源版本,并在 TDD 内写全视觉规格;总册引用对应 TDD 分册,继续满足只看 TDD 即可完成当前范围实现的标准。资源路径、产物路径及阶段审批合同保持不变。
|
||||
|
||||
阶段顺序固定为:
|
||||
|
||||
```text
|
||||
@@ -276,16 +288,67 @@ concept → top_design → architecture → systems → tdd → consultant
|
||||
| 技术文档 | `project/04_tdd/01_技术实现.md`、`project/04_tdd/02_美术圣经.md`、`project/04_tdd/03_数据与配表.md`、`project/04_tdd/总册.md` |
|
||||
| 顾问态 | 不提交下一阶段审批 |
|
||||
|
||||
`systems: []` 是已确定的行为,不是迁移时需要补齐的缺口。`project/analysis.md`、`project/决策台账.md`、`project/dialog.md` 保持原型中的共享过程文件口径,不升级为新的审批必需项。速览卡保留原型结构提示,但 Runtime 与 UI 不解析其章节或内容字段。
|
||||
`systems: []` 是已确定的行为,不是迁移时需要补齐的缺口。`project/analysis.md`、`project/决策台账.md`、`project/dialog.md` 保持原型中的共享过程文件口径,不升级为新的审批必需项。速览卡采用下述简短概览结构,Runtime 与 UI 不解析其章节或内容字段。
|
||||
|
||||
提示词中的路径是策划 Agent 使用的相对路径约定:
|
||||
|
||||
- `project/...` 以策划工作区为根,Agent 将其传给 `read_file`、`write_file`、`patch_file` 等文件工具来读取和维护正式产物及过程文件。宿主将它映射到项目的 `design_artifacts/project/...`;阶段审批按登记的相对路径检查必需产物。提示词写明 `project/速览卡.md`、`project/analysis.md` 等目标位置,是在告诉 Agent 文件应写在哪里,并非泄露宿主绝对路径。
|
||||
- `resources/skills/...`、`resources/templates/...`、`resources/exemplars/...` 和 `resources/modules/system-types/...` 指向随应用发布的固定策划资源包,用于定位分册、模板、例子及系统类型资料,不是策划工作区的写入目标。资源目录在 `resources/catalog.json` 中登记相对路径与资源 ID;Agent 可用 `list_resources` 查 ID,再用 `read_resource` 按 ID 读取。分册中省略 `resources/` 前缀的 `templates/...` 等写法仍指同一资源包内的位置。
|
||||
|
||||
这些路径直接服务于 Agent 的文件操作和资源查阅,属于提示词应保留的契约;即使阶段上下文也注入了某条产物路径,分册和模板中的路径仍提供目标文件与交叉引用的具体定位。去除客户端与宿主实现细节时,不应把这类相对路径当作意外暴露的内部实现;宿主安装目录、项目绝对路径及会话控制文件位置才不属于 Agent 的操作输入。
|
||||
这些路径直接服务于 Agent 的文件操作和资源查阅,属于提示词应保留的契约;即使阶段上下文也注入了某条产物路径,分册和模板中的路径仍提供目标文件与交叉引用的具体定位。去除客户端与宿主实现细节时,仍保留这类相对路径。Runtime 文件工具同时接受绝对路径和离开 `design_artifacts` 的路径,包括项目内其他目录和宿主上的其他位置。常驻提示词写明工作区是相对路径根目录 `.`,并仍要求策划文件放在工作区内并使用相对路径。六个文件工具的说明不再把路径限定为相对路径或工作目录内。正式产物的相对路径约定保持不变。
|
||||
|
||||
过程文档记录关键依据、决定和待办,不要求实时完整,也不应重复正式设计文档;阶段提交前补齐影响验收的关键记录。顶层设计的分册、模板和示例保留核心定位及按需说明的易混淆方向与排除理由,不强制使用固定的“不是 X,而是 Y”句式。
|
||||
共享文档按以下职责维护,文件路径和审批必需产物清单保持不变:
|
||||
|
||||
| 文档 | 用途与更新时机 |
|
||||
| --- | --- |
|
||||
| `project/analysis.md` | 按需保留重要取舍的依据与当前结论;存在实际备选时再比较,未决问题说明原因或下一步。结论稳定或依据变化时更新,可合并修订条目,不记录每次讨论。 |
|
||||
| `project/决策台账.md` | 按需集中列出待处理事项和下一步,必要时引用分析或正式设计。事项变化时更新,完成后移出待办,不再重复保存全部已采用决定。 |
|
||||
| `project/dialog.md` | 仅在用户需要对话摘要或交接记录时维护,不逐轮转录聊天。 |
|
||||
| `project/速览卡.md` | 概念阶段形成简短游戏概览、当前范围与已有设计入口;仅在概览内容或入口变化时更新,不复制系统表、参数、素材数量、完整排除清单或验证计划。 |
|
||||
|
||||
正式设计承载当前采用的规则,共享文档按各自用途记录,不要求同一决定在多处重复登记。不强制连续编号、状态枚举、候选数、问题数量、推翻条件或完整历史流水;尚未确定的事项用自然语言说明,不冒充用户确认。阶段提交前检查影响交付的信息是否一致,不以补齐过程记录作为新门禁。已有项目文件不批量重写或删除。
|
||||
|
||||
速览卡让读者快速了解游戏、当前准备做什么及详细设计的位置。分类、支柱、循环和目标玩家可合入概述,不再分别展开;不设固定字数,也不要求填满参考结构。只提示会改变方向或当前范围的重要未决问题,并引用详细位置;设计入口仅链接已存在且有用的文档,不为填卡新增范围或未来计划。注入说明与星露谷样例同步,样例清除旧 NPC、图标和换装数量,按当前日常原型概括;`project/速览卡.md` 仍为概念阶段必需产物。
|
||||
|
||||
TDD 的决策记录采用相同原则:设计要求、当前采用值和实际工程约束直接写入对应分册,重要取舍按需保留分析,未决事项说明影响与下一步,不要求逐项登记到外部台账或附推翻条件。总册保留施工索引、跨分册约定与重要缺口,详细问题指向对应分册。问题解决后更新受影响的 GDD 与 TDD 正文并关闭待办,不能只登记处理去向。
|
||||
|
||||
“施工方只看 TDD,应能完成当前范围的实现”仍是完成标准:设计要求、内容与数值、实际工程约束和验收条件写全,施工方无需回查 GDD 或猜测关键设计。保留来源版本与变更同步,外部分析与台账不能代替正文。代码组织、算法、内部接口、字段与数据结构、配置载体、资源命名与打包由施工方自主决定;未预定这些实现选择不构成策划缺口。已有工程契约、实际数据/资源格式和用户明确交付约束必须记录;有依据的实现建议可供参考,不成为唯一方案,也不增加逐项登记或用户确认。
|
||||
|
||||
TDD 阶段验收对象是策划文档:当前范围的行为、内容、数值、界面、表现要求与实际接入约束须完整、自洽,完成文档一致性、内容关系和必要数值验算。奖励、失败后果、关键视觉状态等设计缺口须补齐;函数签名、源码目录、内部字段或打包格式未预定不阻塞验收。保留实际构建与交付约束,验收条件明确,必要时给代表性场景;测试脚本、执行顺序、截图数量和测量工具由施工方安排,性能指标与专门验证须有实际目标或风险依据。不要求产品或资产已经完成,只有实际执行过才能记录通过。当前采用的设计值明确,后续调优不能代替当前设计。
|
||||
|
||||
同一验证的场景、判据和结果在对应 TDD 分册完整写一次,其他位置引用并只补充独有要求;总册汇总重要结论、缺口与位置,不复制清单。不强制每册单列完整验证章节或新增统一验证表。数据册保留必要数值计算,不重复技术册的行为状态推演;文档验算与实际运行检查不能互相代替。当前采用值不自动成为调优待办,只有具体体验疑虑才记录验证问题,不默认安排替代版本对照。架构与 TDD 对范围外内容简述边界,只有已确定的后续计划或确实约束当前设计的要求才补充,不自动承诺里程碑或扩展实现。规则、模板与样例同步,已有用户项目不批量改写。
|
||||
|
||||
TDD 总纲与技术分册把选型限定在 Game Agent 已支持的 Web、Unity、Godot、Cocos Creator 范围,不逐框架分级说明支持程度。新 Web 使用 npm + Vite,二维使用 Phaser 4.2.1,三维按需求选择适用技术栈;依赖由 npm 管理,预览和导出使用包目录下的 `dist/index.html`,运行素材随构建进入 dist。已有工程沿用实际结构,不因模板自动迁移。该约束与 GameAgent 的 `prompts/runtime/texts/direct.json` 工程提示、`src/project/manifest.rs` 脚手架一致;本轮不修改 GameAgent 提示词或运行时。
|
||||
|
||||
TDD 按实际内容组织,可重组 GDD 规则而不要求逐段全文复制;来源版本集中在总册记录,设计变化同步受影响正文。取消固定编写顺序、必读样例、统一图表和逐项登记要求。技术分册写行为、工程约束、存档要求及验证,已有接口按契约描述,不为新项目预定代码目录或内部调用。数据分册写全当前内容、数值、关系与文案及可复核验算,不以示例行代替,也不强制写成可加载配置。美术分册写共性表现、对象与状态、用途及验收,已有素材记录真实接入约束,不通用强制帧键、图集、命名或目录。
|
||||
|
||||
总册保留当前范围、分册索引、来源版本、实际跨分册约定与重要缺口,不重复生产验收表或以 frozen 标签判定通过。`project/04_tdd/01_技术实现.md`、`02_美术圣经.md`、`03_数据与配表.md`、`总册.md` 四个产物继续保留,不涉及的方向在分册简述原因。十二份 TDD 规则、模板和样例同步这一口径;星露谷样例聚焦首个日常原型,数值与素材规格标明示例假设,未附证据的原作实证、构建通过和资产验收声明清理,规格与验算缺口如实保留。资源 ID、路径、阶段注入及 Runtime 的文件存在性检查不变。
|
||||
|
||||
数据模板将含义、关系与完整内容合写:少量参数直接列当前值与单位,同结构多条内容可共用属性说明;文案集中列一次,其他位置引用唯一权威定义。固定行为写在相关规则中,是否配置化由施工方选择,不为未来可能变更承诺尚未定义的模式或开关。派生值保留计算关系,不重复登记;已有数据格式或明确要求交付可加载数据时,才按实际契约补充字段、类型、默认或必填规则。当前范围完整内容、文案和验算要求保留。
|
||||
|
||||
写作规则由 `system-prompt.md`、`phase-context/`、资源目录登记的 `skills/` 与各分册承接;重复且过期的 `resources/SKILL.md` 合并总稿已删除,历史由 Git 保留。
|
||||
|
||||
顶层设计将概念展开为游玩过程、关键规则与反馈、资源与进展、选择后果、版本范围及验证计划。规则、模板和样例按实际玩法组织,不强制三层循环、三种互相供给的回报、资源“来源—储存—消耗”链、日历节奏、反馈层数、唯一原型片段或失败三选一;最优解是否成立取决于玩法,必要的规则与参数可以在顶层明确。保留核心定位及按需说明的易混淆方向与排除理由,不强制固定句式或结尾重复定稿。
|
||||
|
||||
原型范围由要验证的问题决定,与完整版本范围分别说明;验证可以结合试玩观察、完成情况、玩家反馈和指标,明确如何形成判断,不把未验证的预期写成结论。星露谷样例按选择双方的收益与代价比较,按场景说明损失与恢复,并区分单日、多日和后续内容的验证范围。
|
||||
|
||||
架构层承接顶层已有的玩法描述、能力范围、版本边界和验证计划,按实际职责、状态与数据边界拆分或合并系统,不要求顶层清单逐项对应系统。规则、模板与样例围绕系统职责、协作和数据归属、系统文档映射、实现范围及验证组织;取消固定系统数量、每个系统必须属于 P0、“不负责”必填列、图表格式、状态分类、数值基准分类和逐轮变更记录。重要取舍按需保留依据。
|
||||
|
||||
拆分应带来有用的独立规则边界,不因变量、操作不同或未来可能替换就单独设系统;简单职责可在同一系统内部表达。架构概述关键协作,保留影响结果的顺序与共享约束,职责、数据归属和文档位置可合写,不重复建表。完整行为流程在主要负责的系统文档展开,其他参与方说明自身接收、处理与返回,按需引用完整流程并就近保留理解本系统所需的前提和结果。
|
||||
|
||||
系统交互区分调用、通知、读取与玩法反馈;双向关系不自动判为架构错误,按实际问题检查职责纠缠和更新顺序。主数据归属明确,实际需要的副本或快照说明来源与预期结果,不要求额外设计更新机制。系统文档展开行为,TDD 收编并补齐设计要求、内容与数值及实际约束,内部实现由施工方决定。
|
||||
|
||||
保留 Sxx 编号与 `project/03_systems/...` 文档位置,可以按内容合并或拆分文档;该映射不决定代码目录,代码模块与文件组织由施工方选择。实现范围区分完整版本、首个原型及后续内容,不固定 P0/P1/P2,也不要求验证失败就退回顶层或禁止调整系统划分。星露谷样例明确 NPC 日程、资源点、物品与经济等归属,首个原型包含基础采集,按单日选择和多日成长分别验证。
|
||||
|
||||
系统总纲、相关系统类型资料与 TDD 的直接引用同步承接职责、协作、数据归属和当前实现范围,不再依赖架构 P0 清单、固定依赖图或仅限定性的数值基准。数据侧按实际玩法选择验算场景与跨度;技术侧按当前施工范围收编全部必需行为,不能因某系统标为后续优先级而遗漏当前所需规格。速览卡与 TDD 样例同步首个原型范围,基础采集、跨日结算规格和完整数值验算的缺口如实标明,局部推算不作为验算通过的证据。施工完备要求、产物路径与阶段审批合同保持不变。
|
||||
|
||||
系统层按实际行为展开职责、触发条件、状态变化、结果、协作与反馈,类型规则、模板和样例按需使用,不要求先归入十二类之一。取消固定十二节、顶层条目编号、取舍表列、循环层级、“三不”、全部枚举及禁止段落等填写纪律;未决事项按影响处理,不只保留结构问题,也不把全部数值问题自动推给原型。代表性验证场景说明预期结果和判断依据,不冒充已完成验证。
|
||||
|
||||
这些维度是信息覆盖要求,不是独立章节要求。参与方、数据来源、处理顺序和反馈可随行为一次说明,已讲清的内容不再另列协作表或反馈章节;简单同步处理不额外设计消息、确认或中间状态。相关类型模板将协作与反馈并入具体行为,架构样例合并职责与文档映射、战斗样例将协作归属就近写入行为。去重不降低关键行为边界、结果一致性和 TDD 独立施工要求,不改写已有项目产物。
|
||||
|
||||
十二类系统资料保留类型特有的设计问题,模板不预填未经选择的动作、状态、循环和数据表。日历、生产队列、成长分支、复杂叙事、节日专属玩法和战斗定位均由实际项目决定;系统职责与权威数据归属遵循架构,UI 可以维护交互、导航和临时状态,正式玩法校验与结算仍由对应系统负责。跨系统行动明确整体成功或失败的预期结果,TDD 收编设计约束,具体实现机制由施工方选择。
|
||||
|
||||
系统文档保留已定规则、单位和参数,TDD 从相关内容收编并补齐设计与实际接入缺口,不依赖固定交接章节。系统编号、文档位置、资源登记及审批语义不变。战斗样例明确为后续矿井原型的暂定方案:实时基础动作、安全撤退保留成果、倒下可能损失部分钱物,未定设计和待执行验证如实标明;TDD 日常原型样例不提前收编后续战斗。样例中的代码、数据和资源组织不再作为预先设计或验收要求,仍缺少的玩法、内容、数值及表现如实保留。
|
||||
|
||||
进入下一阶段必须由用户批准触发。Runtime 推进后向 Agent 追加明确的用户行为语义,例如“用户已批准上一阶段,现在进入顶层设计阶段”,避免 Agent 误认为 Runtime 自行推进。
|
||||
|
||||
@@ -327,7 +390,7 @@ UI 使用“批准”和“继续修改”两个文字按钮,分别配 Lucide
|
||||
|
||||
## 8. 用户工作区浏览
|
||||
|
||||
`design_artifacts` 同时是 Agent 工作区和用户查看策划资料的文件区。用户不需要通过聊天请求 Agent 才能看到文件。
|
||||
`design_artifacts` 是用户查看策划资料的文件区,也是 Agent 的默认工作区。用户不需要通过聊天请求 Agent 才能看到这里的文件。用户文件树只列出该目录。Agent 文件工具还可以读写绝对路径和该目录之外的路径,那些路径不因此出现在用户文件树中。
|
||||
|
||||
第一版提供只读浏览:
|
||||
|
||||
@@ -383,7 +446,7 @@ UI 使用“批准”和“继续修改”两个文字按钮,分别配 Lucide
|
||||
1. 核对原型行为基线,选择生产 Provider、恢复、审计、文件和事件通信的可复用函数;仅拆分实际阻碍复用的局部业务耦合。
|
||||
2. 新增独立的设计会话状态结构和持久化路径。
|
||||
3. 新增自由策划 Agent Provider 回合循环。
|
||||
4. 将文件工具绑定到 `design_artifacts`,移除旧 Planning V2 的业务产物门禁。
|
||||
4. 将文件工具绑定到 `design_artifacts`,移除旧 Planning V2 的业务产物门禁。2026-09-29 起,这一绑定只保留给用户文件浏览和附件导入;策划文件工具同时接受绝对路径和 `design_artifacts` 之外的路径。
|
||||
5. 接入阶段提示、必读资源注入和 `get_workflow_status`。
|
||||
6. 接入 `submit_phase_for_approval` 和 ✅/❌ 审批事件。
|
||||
7. 复用 Game Agent 文件浏览实现,让用户查看 `design_artifacts` 文件。
|
||||
|
||||
@@ -209,7 +209,7 @@ cargo test -p spacetime-module web_project --manifest-path server-rs/Cargo.toml
|
||||
|
||||
```bash
|
||||
npm run test -- src/services/sseStream.test.ts
|
||||
npm run test -- src/components/editor/agent
|
||||
npm run test -- src/services/image-editor/editorAgentClient.test.ts # 2026-09-24 修订:`src/components/editor/agent` 已随旧创作链路退役,现行画布 Agent 用例在 image-editor 目录
|
||||
npm run typecheck
|
||||
npm run check:encoding
|
||||
git diff --check
|
||||
|
||||
Reference in New Issue
Block a user