diff --git a/apps/ai-game-creator-shell/src/App.tsx b/apps/ai-game-creator-shell/src/App.tsx index 091a4bb7c..f93eeb970 100644 --- a/apps/ai-game-creator-shell/src/App.tsx +++ b/apps/ai-game-creator-shell/src/App.tsx @@ -1825,6 +1825,7 @@ const chatCommandHelp = [ '/capabilities:查看 Agent 能力清单', '/audit:审计当前项目的 Agent 能力证据', '/status:查看项目状态', + '/next:查看下一步建议', '/open-project:在系统文件管理器中显示项目目录', '/switch-project:回到项目启动器切换工作区', '/index:刷新本地项目索引', @@ -1972,6 +1973,78 @@ function summarizeProjectStatus( .join('\n'); } +function summarizeNextProjectActions( + nextManifest: GameCreationAppManifest, + trace: GameCreationAgentRunTrace | null, +) { + const suggestions: Array<{ label: string; command?: string }> = []; + const addSuggestion = (label: string, command?: string) => { + if (command && suggestions.some((item) => item.command === command)) { + return; + } + suggestions.push({ label, command }); + }; + + const preview = nextManifest.preview; + if (!trace) { + addSuggestion('直接输入一句游戏需求,确认后生成首版原型'); + } else if ( + trace.lifecycleStatus === 'killed' || + trace.status === 'failed' || + trace.stopReason === 'max-passes-exhausted' + ) { + addSuggestion('补充说明并继续最近 run', '/agent-resume '); + } else if ( + trace.status === 'passed' || + trace.status === 'artifacts-written' || + trace.stopReason === 'evaluator-passed' + ) { + addSuggestion( + preview?.status === 'running' && preview.url + ? '打开当前本地预览' + : '运行自检并启动本地预览', + preview?.status === 'running' && preview.url ? '/open-preview' : '/run', + ); + } else { + addSuggestion('查看最近 loop 进展', '/trace'); + } + + const readyTasks = selectGameCreationAppReadyTasks({ + tasks: taskRowsFromManifest(nextManifest), + }); + if (readyTasks.length > 0) { + addSuggestion(`查看 ${readyTasks.length} 个 ready 任务`, '/tasks'); + } else { + addSuggestion('查看任务拆分和等待项', '/tasks'); + } + + if (nextManifest.assets.length > 0) { + addSuggestion(`查看 ${nextManifest.assets.length} 个本地资产`, '/assets'); + } else { + addSuggestion( + '登记本地素材或同步画板资源', + '/asset-register assets/hero.png image image/png', + ); + addSuggestion('同步已有画板项目资源', '/sync-canvas-project '); + } + + if (trace) { + addSuggestion('查看最近 trace 摘要', '/trace'); + addSuggestion('列出最近 Run 产物', '/run-artifacts'); + } + addSuggestion('打开产物命令列表', '/artifacts'); + addSuggestion('打开日志命令列表', '/logs'); + + const firstCommand = suggestions.find((item) => item.command); + return { + text: `下一步建议:\n${suggestions + .map((item) => `- ${item.label}${item.command ? `:${item.command}` : ''}`) + .join('\n')}`, + draftCommand: firstCommand?.command, + draftCommandLabel: firstCommand?.label, + }; +} + function summarizeMainProjectHeader( nextManifest: GameCreationAppManifest, agents: AgentStatusCard[], @@ -5215,6 +5288,23 @@ export function App() { return; } + if (prompt === '/next') { + if (!requireChatProjectForUserAction()) { + return; + } + const summary = summarizeNextProjectActions(manifest, agentRunTrace); + setMessages((current) => [ + ...current, + { + role: 'assistant', + text: summary.text, + draftCommand: summary.draftCommand, + draftCommandLabel: summary.draftCommandLabel, + }, + ]); + return; + } + if (prompt === '/index') { void queueOrExecuteProjectIndex(); return; diff --git a/apps/ai-game-creator-shell/tests/appSurface.test.ts b/apps/ai-game-creator-shell/tests/appSurface.test.ts index 2f134a634..4a90e8995 100644 --- a/apps/ai-game-creator-shell/tests/appSurface.test.ts +++ b/apps/ai-game-creator-shell/tests/appSurface.test.ts @@ -2119,6 +2119,27 @@ describe('AI 游戏创作 App 界面边界', () => { expect(await screen.findByText(/项目:未命名游戏原型/)).not.toBeNull(); expect(screen.getByText(/目录:\/tmp\/authorized-game/)).not.toBeNull(); + const runLocalCountBeforeNext = invoke.mock.calls.filter( + ([command]) => command === 'run_limited_local_command', + ).length; + submitChat('/next'); + expect(await screen.findByText(/下一步建议:/)).not.toBeNull(); + expect(screen.getByText(/运行自检并启动本地预览:\/run/)).not.toBeNull(); + expect(screen.getByText(/查看 .* 个 ready 任务:\/tasks/)).not.toBeNull(); + const nextMessageList = document.querySelector('.message-list'); + expect(nextMessageList).not.toBeNull(); + fireEvent.click( + within(nextMessageList as HTMLElement).getByRole('button', { + name: '运行自检并启动本地预览', + }), + ); + expect(screen.getByLabelText('创作想法')).toHaveProperty('value', '/run'); + expect( + invoke.mock.calls.filter( + ([command]) => command === 'run_limited_local_command', + ), + ).toHaveLength(runLocalCountBeforeNext); + fireEvent.click(screen.getByRole('button', { name: '权限' })); expect( await screen.findByText(/策略:\.agent\/policy\.json/), @@ -7675,6 +7696,7 @@ describe('AI 游戏创作 App 界面边界', () => { expect( screen.getByText(/\/switch-project:回到项目启动器切换工作区/), ).not.toBeNull(); + expect(screen.getByText(/\/next:查看下一步建议/)).not.toBeNull(); expect( screen.getByText( /\/asset-register 路径 \[kind\] \[mediaType\]:登记项目内已有资产/, diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 9cf1a9de2..161b7b4ae 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -3861,6 +3861,7 @@ - 2026-07-03 调整:单 Agent 对话面板允许用户把当前输入手动追加到该 agent 的 `memory/agents//.md` 私有记忆;写入复用 `memory.write` 项目策略、项目锁和 Tauri 本地目录能力,不把普通对话流水自动混入私有记忆;聊天侧 `/agent-conversations` 和 `/agent-memories` 只列出同一批 Agent 对话与私有记忆读取命令并提供首个 `/read` 草稿,不直接读取文件。 - 2026-07-03 调整:主窗口新增音效登记和画板音频导入快捷入口,只填入 `/asset-register assets/audio/sfx.wav audio audio/wav` 或 `/import-canvas-asset assets/audio/sfx.wav ` 草稿;音乐组仍复用现有资产登记 / 画板回流链路,不新增独立音频生成系统。 - 2026-07-03 调整:主窗口新增常用生成产物读取入口,只把入口 HTML、设计、数值、美术清单、音频清单和发布说明对应的 `/read` 草稿填入聊天输入框;聊天命令 `/artifacts` 只列出同一组固定读取命令并提供首个读取草稿,`/run-artifacts` 只列出最近 trace 里的产物读取命令并提供首个 `/read` 草稿,`/logs` 只列出固定日志读取命令;实际读取仍走聊天侧 `file.read` 权限流,不直接读本地文件。 +- 2026-07-03 调整:普通用户通过聊天输入 `/next` 触发下一步建议入口,只基于主窗口当前已加载的 manifest、最近 run trace 和最近命令摘要生成聊天建议,列出 `/tasks`、`/trace`、`/run`、`/open-preview`、`/assets`、`/artifacts`、`/run-artifacts`、`/logs`、`/agent-resume ` 等安全命令草稿方向,并提供一个首选草稿;该命令不得直接执行 Tauri 读写、启动或打开预览、读取本地文件,也不得绕过原有命令确认和 `file.read` 权限流。 - 2026-06-25 调整:本地 HTTP 预览静态 `HEAD` 必须返回与 `GET` 相同的真实 `Content-Length`,但不返回 body;浏览器、图片、音频和视频探测不能拿到 `Content-Length: 0` 的假响应。 - 2026-06-25 调整:普通用户通过聊天输入 `/run` 触发待确认 `game.run_local`,确认后只能复用白名单 `game.static_smoke` 自检当前 `game/index.html`,通过后启动 `127.0.0.1` 本地 HTTP 预览。独立执行 `game.static_smoke` 时如果已有 `.agent/run.latest.json`,必须追加 `Playtest / game.static_smoke` trace step,避免“运行了代码但编排 trace 不可见”。 - 2026-06-25 调整:普通用户通过聊天输入 `/trace` 触发只读 `agent.trace_read`,读取 `.agent/run.latest.json` 并在聊天里摘要 loop 轮次、stopReason、nextStep、active / carry-over 任务、repairRoutes、agent 建议命令和最近 step。trace 面板仍只在开发窗口展示,普通用户窗口不新增面板。 diff --git a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md index 8fc7565cb..4be5a700c 100644 --- a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md +++ b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md @@ -111,7 +111,7 @@ game-project/ ## v1 验收证据矩阵 -- `npm run ai-game-creator-shell:check`:覆盖壳 typecheck、聊天命令单测、用户 / 开发窗口 UI 边界 smoke、主窗口命令按钮复用 `/help` 命令列表、主窗口项目摘要从 manifest / trace 派生任务完成数、ready 数、资产来源分布和最近命令且未选项目时不显示、灵感草稿只填充输入框不提交、能力按钮复用 `/capabilities`、LLM状态按钮复用 `/llm-status` 且结果回填 Agent 状态列表、聊天侧 `/agents` 汇总和单 Agent 对话的 provider / 模型 / 流式 / API Key 读取状态、开发日志面板只读读取 `.agent/logs/command.log` / `preview.log` / `agent.log`、项目状态按钮复用 `/status`、权限按钮复用 `/policy` 且策略草稿按钮只填入 `/policy-confirm project.index` / `/policy-confirm asset.register` / `/policy-confirm memory.write` / `/policy-confirm preview.start` / `/policy-confirm preview.open` / `/policy-confirm preview.stop` / `/policy-confirm agent.run_status` / `/policy-confirm conversation.read` / `/policy-confirm conversation.write`、审计按钮复用 `/audit`、资产按钮复用 `/assets` 且资产结果可一键复用 `/read`、任务按钮复用 `/tasks`、聊天侧 `/agents` 汇总每个 Agent 的当前状态、聊天侧 `/agent-conversations` 列出 Agent 对话读取命令、聊天侧 `/agent-memories` 列出 Agent 私有记忆读取命令、Trace 按钮复用 `/trace`、文件按钮复用 `/files` 且文件结果可一键复用 `/read`、索引按钮复用 `/index`、记忆 / 短期记忆 / 黑板按钮复用 `/memory long|short|blackboard`、快照按钮复用 `/checkpoint`、快照列表按钮复用 `/checkpoints` 且 checkpoint 结果可一键复用 `/diff` / `/restore`、历史按钮复用 `/history`、受限命令白名单按钮复用 `/commands` 且无需项目初始化、静态自检快捷按钮复用 `/smoke`、预览状态快捷按钮复用 `/preview-status`、主窗口运行时配置面板读写 Tauri 配置目录中的 `game-creator.config.json`、支持全局与每个 agent 单独选择 LLM Provider 且不把 API Key 写入聊天、单 Agent 对话面板可手动追加私有记忆且走 `memory.write` 策略、主窗口提供音效登记、画板音频导入和常用生成产物读取草稿入口,聊天侧 `/artifacts` 可列出常用生成产物读取命令,聊天侧 `/run-artifacts` 可列出最近 run 产物读取命令,聊天侧 `/logs` 可列出固定日志读取命令且不直接读取日志、聊天侧 `/capabilities` 展示标准 Agent 能力清单且不打开开发面板、聊天侧 `/audit` 从 manifest / 本地文件 / `.agent/run.latest.json` 分别汇总用户面、6 组任务配置、6 组协作证据、任务编排、loop、记忆、本地产物、HTTP 预览、画板回流和权限日志证据且不打开开发面板;未生成 `.agent/run.latest.json` 前,`/audit` 只能标记任务配置通过,不能把 6 组协作证据误判为通过;trace 已存在但状态为 `failed`、`needs-revision`、`running`、`max-passes-exhausted` 或缺少 `Evaluator passed` 步骤时,`/audit` 不能把 loop 误判为通过。聊天侧 `/llm-status` 只显示 base_url / model / API Key 已读取状态且不泄露密钥本体、聊天侧长期记忆查看 / 追加 / 覆盖 / 删除的授权本地项目路径、上传资产写入后的 manifest 刷新和 `/assets` 聊天可见性、`/smoke` 聊天侧确认后只通过授权本地项目路径执行白名单 `game.static_smoke`、`/run` 聊天侧确认后通过授权本地项目路径执行 `game.static_smoke`、启动 `127.0.0.1` 本地预览并交给外部浏览器、`/preview` 聊天侧确认后通过授权本地项目路径启动 `127.0.0.1` 本地预览并交给外部浏览器、`/status` 聊天侧项目 / 任务 / 资产 / 预览 / 最近命令汇总、`/files` 聊天侧本地项目文件列表、`/read` 聊天侧文件读取的授权本地项目路径、`/tasks` 聊天侧任务拆分与下一步专业组展示的授权本地项目路径、聊天确认生成后实时展示 Planner / Orchestrator / 角色 brief / Generator / Evaluator / 写盘 / 自检进度,并自动读取 `.agent/run.latest.json` 在普通聊天消息里展示 Run、LLM 对话、loop 轮次、工具调用、active / carry-over 任务、返工焦点、编排轮次、最近步骤、画板同步建议命令和本地产物快照、`/trace` 聊天侧读取 `.agent/run.latest.json` 并展示 loop 轮次 / active 任务 / 返工路线 / dependency waves 的授权本地项目路径、`platform-agent` 编排测试、共享契约测试、Tauri 本地能力测试和无密钥本地 provider 端到端 smoke;用于证明独立 App、真实 LLM-compatible loop、本地落盘、自检和 HTTP 预览闭环,并覆盖 loop 跑满 3 轮失败时不会写入最终游戏产物。 +- `npm run ai-game-creator-shell:check`:覆盖壳 typecheck、聊天命令单测、用户 / 开发窗口 UI 边界 smoke、主窗口命令按钮复用 `/help` 命令列表、主窗口项目摘要从 manifest / trace 派生任务完成数、ready 数、资产来源分布和最近命令且未选项目时不显示、灵感草稿只填充输入框不提交、能力按钮复用 `/capabilities`、LLM状态按钮复用 `/llm-status` 且结果回填 Agent 状态列表、聊天侧 `/agents` 汇总和单 Agent 对话的 provider / 模型 / 流式 / API Key 读取状态、开发日志面板只读读取 `.agent/logs/command.log` / `preview.log` / `agent.log`、项目状态按钮复用 `/status`、权限按钮复用 `/policy` 且策略草稿按钮只填入 `/policy-confirm project.index` / `/policy-confirm asset.register` / `/policy-confirm memory.write` / `/policy-confirm preview.start` / `/policy-confirm preview.open` / `/policy-confirm preview.stop` / `/policy-confirm agent.run_status` / `/policy-confirm conversation.read` / `/policy-confirm conversation.write`、审计按钮复用 `/audit`、资产按钮复用 `/assets` 且资产结果可一键复用 `/read`、任务按钮复用 `/tasks`、聊天侧 `/agents` 汇总每个 Agent 的当前状态、聊天侧 `/agent-conversations` 列出 Agent 对话读取命令、聊天侧 `/agent-memories` 列出 Agent 私有记忆读取命令、Trace 按钮复用 `/trace`、文件按钮复用 `/files` 且文件结果可一键复用 `/read`、索引按钮复用 `/index`、记忆 / 短期记忆 / 黑板按钮复用 `/memory long|short|blackboard`、快照按钮复用 `/checkpoint`、快照列表按钮复用 `/checkpoints` 且 checkpoint 结果可一键复用 `/diff` / `/restore`、历史按钮复用 `/history`、受限命令白名单按钮复用 `/commands` 且无需项目初始化、静态自检快捷按钮复用 `/smoke`、预览状态快捷按钮复用 `/preview-status`、主窗口运行时配置面板读写 Tauri 配置目录中的 `game-creator.config.json`、支持全局与每个 agent 单独选择 LLM Provider 且不把 API Key 写入聊天、单 Agent 对话面板可手动追加私有记忆且走 `memory.write` 策略、主窗口提供音效登记、画板音频导入和常用生成产物读取草稿入口,聊天侧 `/artifacts` 可列出常用生成产物读取命令,聊天侧 `/run-artifacts` 可列出最近 run 产物读取命令,聊天侧 `/logs` 可列出固定日志读取命令且不直接读取日志,聊天侧 `/next` 基于当前已加载的 manifest / 最近 run trace 输出下一步建议和 `/tasks` / `/trace` / `/run` / `/open-preview` / `/assets` / `/artifacts` / `/run-artifacts` / `/logs` / `/agent-resume ` 等安全命令草稿方向,提供一个首选草稿且不直接触发 Tauri 读写、预览启动或文件读取,聊天侧 `/capabilities` 展示标准 Agent 能力清单且不打开开发面板、聊天侧 `/audit` 从 manifest / 本地文件 / `.agent/run.latest.json` 分别汇总用户面、6 组任务配置、6 组协作证据、任务编排、loop、记忆、本地产物、HTTP 预览、画板回流和权限日志证据且不打开开发面板;未生成 `.agent/run.latest.json` 前,`/audit` 只能标记任务配置通过,不能把 6 组协作证据误判为通过;trace 已存在但状态为 `failed`、`needs-revision`、`running`、`max-passes-exhausted` 或缺少 `Evaluator passed` 步骤时,`/audit` 不能把 loop 误判为通过。聊天侧 `/llm-status` 只显示 base_url / model / API Key 已读取状态且不泄露密钥本体、聊天侧长期记忆查看 / 追加 / 覆盖 / 删除的授权本地项目路径、上传资产写入后的 manifest 刷新和 `/assets` 聊天可见性、`/smoke` 聊天侧确认后只通过授权本地项目路径执行白名单 `game.static_smoke`、`/run` 聊天侧确认后通过授权本地项目路径执行 `game.static_smoke`、启动 `127.0.0.1` 本地预览并交给外部浏览器、`/preview` 聊天侧确认后通过授权本地项目路径启动 `127.0.0.1` 本地预览并交给外部浏览器、`/status` 聊天侧项目 / 任务 / 资产 / 预览 / 最近命令汇总、`/files` 聊天侧本地项目文件列表、`/read` 聊天侧文件读取的授权本地项目路径、`/tasks` 聊天侧任务拆分与下一步专业组展示的授权本地项目路径、聊天确认生成后实时展示 Planner / Orchestrator / 角色 brief / Generator / Evaluator / 写盘 / 自检进度,并自动读取 `.agent/run.latest.json` 在普通聊天消息里展示 Run、LLM 对话、loop 轮次、工具调用、active / carry-over 任务、返工焦点、编排轮次、最近步骤、画板同步建议命令和本地产物快照、`/trace` 聊天侧读取 `.agent/run.latest.json` 并展示 loop 轮次 / active 任务 / 返工路线 / dependency waves 的授权本地项目路径、`platform-agent` 编排测试、共享契约测试、Tauri 本地能力测试和无密钥本地 provider 端到端 smoke;用于证明独立 App、真实 LLM-compatible loop、本地落盘、自检和 HTTP 预览闭环,并覆盖 loop 跑满 3 轮失败时不会写入最终游戏产物。 - 主窗口策略快捷入口只填入 `/policy-confirm project.index`、`/policy-confirm asset.register`、`/policy-confirm memory.write`、`/policy-confirm preview.start`、`/policy-confirm preview.open`、`/policy-confirm preview.stop`、`/policy-confirm agent.run_status`、`/policy-confirm conversation.read` 或 `/policy-confirm conversation.write` 草稿;Agent 状态栏的“继续说明”只填入 `/agent-resume ` 草稿,不直接触发 run 生命周期写入。 - 主窗口最近 checkpoint 列表展示 checkpoint id、文件数、大小和创建时间,同时提供直接对比、填入 `/diff`、确认回滚和填入 `/restore`;回滚继续走 `project.restore` 确认卡,不直接写项目文件。 - `npm run check:native-shells`:覆盖 AI 游戏创作壳的 release/dev 窗口边界、正式用户 App 不嵌入游戏预览 iframe、用户侧预览命令交给外部浏览器和 Tauri release `--no-bundle` 构建 smoke;用于证明正式发布只登记 `launcher` 启动器窗口,选择工作区后才关闭启动器并打开 `main` 主窗口,开发面板只在 debug/dev 路径打开,独立壳能完成 release 编译。 @@ -175,6 +175,7 @@ game-project/ - 聊天输入 `/logs` 只列出 `.agent/logs/command.log`、`.agent/logs/preview.log` 和 `.agent/logs/agent.log` 对应的 `/read ...` 草稿 / 命令,并提供首个 `/read` 草稿;该命令不直接读取日志,不新增普通用户日志面板,实际读取仍由聊天侧 `file.read` 权限流执行。 - 聊天输入 `/tasks` 会读取 `.agent/manifest.json` 并在聊天里列出专业组、角色、任务状态、产物交接和下一步可执行任务;普通用户仍不暴露任务面板。 - 聊天输入 `/trace` 会通过 `agent.trace_read` 只读读取 `.agent/run.latest.json`,在聊天里汇总最近一次 loop 的轮次、stopReason、nextStep、active/carry-over 任务、repairRoutes、agent 建议命令、产物快照和最近 step;没有待同步建议命令时,首个安全产物可一键填入 `/read ` 草稿;active、carry-over、repairRoutes 和 dependencyWaves 必须把 taskId 映射成专业组 / 角色 / 任务名,避免普通用户只能看到内部 id;普通用户仍不暴露开发 trace 面板。 +- 聊天输入 `/next` 只使用主窗口当前已加载的 manifest、最近 run trace 和最近命令摘要,在聊天里给出下一步建议,列出 `/tasks`、`/trace`、`/run`、`/open-preview`、`/assets`、`/artifacts`、`/run-artifacts`、`/logs`、`/agent-resume ` 等安全命令草稿方向,并提供一个首选草稿;该命令不调用 Tauri 读写、不启动或打开预览、不读取文件,用户必须再发送草稿并按原命令权限流继续。 - 主窗口可从 agent 状态列表进入单个 agent 对话;该入口只加载目标 agent 的 conversation JSONL,发送消息后追加到同一 agent conversation,不开启平行任务图、不 fork run,也不归档历史会话。 - v1 通过独立启动器窗口选择本地项目后再进入主窗口;主窗口只承载当前工作区的聊天、配置和 agent 状态,切换项目时关闭当前主窗口并回到启动器,主窗口按钮和 `/switch-project` 聊天命令都复用同一 Tauri 启动器入口,避免在主窗口内用遮罩面板混合多个工作区上下文。 - 主窗口可通过系统文件管理器显示当前项目目录,也可在聊天输入 `/open-project` 走同一只读打开动作;该操作只打开本地目录,不初始化项目、不写项目文件、不切换工作区。主窗口头部显示最近 `.agent/run.latest.json` 的 run 状态摘要和当前项目预览状态,并通过“刷新状态”重新读取同一 trace,不新增状态数据库。