diff --git a/apps/ai-game-creator-shell/src/App.tsx b/apps/ai-game-creator-shell/src/App.tsx index f066a7879..485b148e9 100644 --- a/apps/ai-game-creator-shell/src/App.tsx +++ b/apps/ai-game-creator-shell/src/App.tsx @@ -1898,6 +1898,7 @@ const chatCommandHelp = [ '/history:重新读取当前项目对话历史', '/files:列出本地项目文件', '/assets:列出本地项目资产', + '/art:查看美术素材与下一步草稿', '/audio:查看音频素材与下一步草稿', '/artifacts:列出常用生成产物读取命令', '/run-artifacts:列出最近 Run 产物读取命令', @@ -2569,6 +2570,12 @@ function summarizeNextProjectActions( if (nextManifest.assets.length > 0) { addSuggestion(`查看 ${nextManifest.assets.length} 个本地资产`, '/assets'); + addSuggestion( + nextManifest.assets.some(isProjectVisualAsset) + ? '查看美术素材' + : '生成或同步美术素材', + '/art', + ); addSuggestion( nextManifest.assets.some(isProjectAudioAsset) ? '查看音频素材' @@ -2581,6 +2588,7 @@ function summarizeNextProjectActions( '/asset-register assets/hero.png image image/png', ); addSuggestion('同步已有画板项目资源', '/sync-canvas-project '); + addSuggestion('生成或同步美术素材', '/art'); addSuggestion('登记或导入音频素材', '/audio'); } @@ -3009,6 +3017,89 @@ function isProjectAudioAsset(asset: GameCreationAppManifest['assets'][number]) { ); } +function isProjectVisualAsset( + asset: GameCreationAppManifest['assets'][number], +) { + const mediaType = asset.mediaType.toLowerCase(); + const kind = asset.kind.toLowerCase(); + return ( + mediaType.startsWith('image/') || + mediaType.startsWith('video/') || + mediaType === 'application/vnd.genarrative.image-sequence' || + kind === 'image' || + kind === 'sprite' || + kind === 'icon' || + kind === 'ui' || + kind === 'background' || + kind === 'character-animation' + ); +} + +function summarizeProjectVisualAssets(nextManifest: GameCreationAppManifest) { + const visualAssets = nextManifest.assets.filter(isProjectVisualAsset); + if (visualAssets.length === 0) { + return { + text: [ + '美术素材:暂无登记图片、视频或序列帧。', + '可先生成首版美术,或同步已有画板项目资源。', + ].join('\n'), + draftCommand: '/generate-art 首版核心美术素材', + draftCommandLabel: '生成美术', + }; + } + + const sourceCounts = visualAssets.reduce( + (counts, asset) => { + counts[asset.source.kind] += 1; + return counts; + }, + { uploaded: 0, generated: 0, canvas: 0 } satisfies Record< + GameCreationAppAssetSourceKind, + number + >, + ); + const visibleAssets = visualAssets.slice(0, 8); + const lines = visibleAssets.map( + (asset) => + `- ${asset.localPath} · ${asset.mediaType} · ${ + assetSourceKindLabels[asset.source.kind] + }${ + asset.source.canvasProjectId + ? ` · 画板 ${asset.source.canvasProjectId}` + : '' + }`, + ); + if (visualAssets.length > visibleAssets.length) { + lines.push( + `- 还有 ${visualAssets.length - visibleAssets.length} 个美术素材`, + ); + } + const hasCanvasVisualAsset = visualAssets.some( + (asset) => asset.source.kind === 'canvas', + ); + + return { + text: [ + `美术素材:${visualAssets.length} 个`, + `来源:${(Object.keys(sourceCounts) as GameCreationAppAssetSourceKind[]) + .filter((source) => sourceCounts[source] > 0) + .map( + (source) => + `${assetSourceKindLabels[source]} ${sourceCounts[source]}`, + ) + .join('、')}`, + hasCanvasVisualAsset + ? '画板来源:已接入' + : '画板来源:暂无 · 建议 /generate-art 首版核心美术素材', + lines.join('\n'), + ].join('\n'), + draftCommand: hasCanvasVisualAsset + ? '/read assets/manifest.art.json' + : '/generate-art 首版核心美术素材', + draftCommandLabel: hasCanvasVisualAsset ? '读美术清单' : '生成美术', + }; +} + function summarizeProjectAudioAssets(nextManifest: GameCreationAppManifest) { const audioAssets = nextManifest.assets.filter(isProjectAudioAsset); if (audioAssets.length === 0) { @@ -6350,6 +6441,23 @@ export function App() { return; } + if (prompt === '/art') { + if (!requireChatProjectForUserAction()) { + return; + } + const summary = summarizeProjectVisualAssets(manifest); + setMessages((current) => [ + ...current, + { + role: 'assistant', + text: summary.text, + draftCommand: summary.draftCommand, + draftCommandLabel: summary.draftCommandLabel, + }, + ]); + return; + } + if (prompt === '/audio') { if (!requireChatProjectForUserAction()) { return; diff --git a/apps/ai-game-creator-shell/tests/appSurface.test.ts b/apps/ai-game-creator-shell/tests/appSurface.test.ts index cebed6078..a7db92425 100644 --- a/apps/ai-game-creator-shell/tests/appSurface.test.ts +++ b/apps/ai-game-creator-shell/tests/appSurface.test.ts @@ -2420,6 +2420,7 @@ describe('AI 游戏创作 App 界面边界', () => { expect(await screen.findByText(/下一步建议:/)).not.toBeNull(); expect(screen.getByText(/运行自检并启动本地预览:\/run/)).not.toBeNull(); expect(screen.getByText(/查看 .* 个 ready 任务:\/tasks/)).not.toBeNull(); + expect(screen.getByText(/查看美术素材:\/art/)).not.toBeNull(); expect(screen.getByText(/查看发布准备清单:\/publish/)).not.toBeNull(); expect(screen.getByText(/查看试玩状态:\/playtest/)).not.toBeNull(); expect(screen.getByText(/查看评审和返工焦点:\/review/)).not.toBeNull(); @@ -2621,6 +2622,36 @@ describe('AI 游戏创作 App 界面边界', () => { 'uploaded · text/plain · uploaded', ), ).not.toBeNull(); + const artManifestReadCountBefore = invoke.mock.calls.filter( + ([command, args]) => + command === 'read_local_project_file' && + args && + 'relativePath' in args && + args.relativePath === 'assets/manifest.art.json', + ).length; + submitChat('/art'); + expect(await screen.findByText(/美术素材:1 个/)).not.toBeNull(); + expect(screen.getByText(/来源:画板 1/)).not.toBeNull(); + expect( + screen.getByText(/assets\/canvas-sync\/tiles\.png · image\/png · 画板/), + ).not.toBeNull(); + const visualDraftButtons = screen.getAllByRole('button', { + name: '读美术清单', + }); + fireEvent.click(visualDraftButtons[visualDraftButtons.length - 1]); + expect(composerInput).toHaveProperty( + 'value', + '/read assets/manifest.art.json', + ); + expect( + invoke.mock.calls.filter( + ([command, args]) => + command === 'read_local_project_file' && + args && + 'relativePath' in args && + args.relativePath === 'assets/manifest.art.json', + ), + ).toHaveLength(artManifestReadCountBefore); const audioManifestReadCountBefore = invoke.mock.calls.filter( ([command, args]) => command === 'read_local_project_file' && @@ -2658,7 +2689,11 @@ describe('AI 游戏创作 App 界面边界', () => { ['读音频清单', '/read assets/manifest.audio.json'], ['读发布说明', '/read exports/README.md'], ] as const) { - fireEvent.click(screen.getByRole('button', { name: buttonName })); + fireEvent.click( + within(screen.getByLabelText('预览快捷操作')).getByRole('button', { + name: buttonName, + }), + ); expect(composerInput).toHaveProperty('value', draftValue); await waitFor(() => expect(document.activeElement).toBe(composerInput)); } @@ -8304,6 +8339,7 @@ describe('AI 游戏创作 App 界面边界', () => { expect( screen.getByText(/\/artifacts:列出常用生成产物读取命令/), ).not.toBeNull(); + expect(screen.getByText(/\/art:查看美术素材与下一步草稿/)).not.toBeNull(); expect( screen.getByText(/\/audio:查看音频素材与下一步草稿/), ).not.toBeNull(); @@ -14152,6 +14188,130 @@ describe('AI 游戏创作 App 界面边界', () => { ); }); + it('summarizes art assets from chat without reading project files', async () => { + const manifest = createGameCreationAppManifest( + 'local-project-draft', + '未命名游戏原型', + ); + manifest.assets.push( + { + id: 'art-generated', + kind: 'image', + mediaType: 'image/png', + localPath: 'assets/generated/hero.png', + source: { kind: 'generated' }, + }, + { + id: 'art-canvas', + kind: 'character-animation', + mediaType: 'application/vnd.genarrative.image-sequence', + localPath: 'assets/canvas-sync/hero-run', + source: { kind: 'canvas', canvasProjectId: 'canvas-art' }, + }, + { + id: 'audio-asset', + kind: 'audio', + mediaType: 'audio/wav', + localPath: 'assets/audio/sfx.wav', + source: { kind: 'uploaded' }, + }, + ); + const invoke = vi.fn( + async (command: string, args?: Record) => { + if (command === 'append_local_permission_log') { + return {}; + } + if (command === 'init_local_game_project') { + const projectPath = String(args?.projectPath ?? ''); + return { + projectPath, + manifestPath: `${projectPath}/.agent/manifest.json`, + manifest, + }; + } + if (command === 'read_local_conversation') { + return { + path: '/tmp/authorized-game/.agent/conversations/project.jsonl', + agentId: null, + messages: [], + }; + } + if (command === 'append_local_conversation_message') { + return { + path: '/tmp/authorized-game/.agent/conversations/project.jsonl', + agentId: null, + messages: [], + }; + } + if (command === 'read_local_project_file') { + throw new Error('art summary should not read project files'); + } + throw new Error(`unexpected invoke ${command}`); + }, + ); + window.__TAURI__ = { core: { invoke } }; + renderAppAt('/'); + + submitChat('/project /tmp/authorized-game'); + fireEvent.click(screen.getByRole('button', { name: '确认' })); + expect( + await screen.findByText('已设置本地项目:/tmp/authorized-game'), + ).not.toBeNull(); + invoke.mockClear(); + + submitChat('/art'); + + expect(await screen.findByText(/美术素材:2 个/)).not.toBeNull(); + expect(screen.getByText(/来源:生成 1、画板 1/)).not.toBeNull(); + expect(screen.getByText(/画板来源:已接入/)).not.toBeNull(); + expect( + screen.getByText(/assets\/generated\/hero\.png · image\/png · 生成/), + ).not.toBeNull(); + expect( + screen.getByText( + /assets\/canvas-sync\/hero-run · application\/vnd\.genarrative\.image-sequence · 画板 · 画板 canvas-art/, + ), + ).not.toBeNull(); + const artManifestDraftButtons = screen.getAllByRole('button', { + name: '读美术清单', + }); + fireEvent.click( + artManifestDraftButtons[artManifestDraftButtons.length - 1], + ); + expect(screen.getByLabelText('创作想法')).toHaveProperty( + 'value', + '/read assets/manifest.art.json', + ); + expect(invoke).not.toHaveBeenCalledWith( + 'read_local_project_file', + expect.anything(), + ); + expect(invoke).not.toHaveBeenCalledWith( + 'get_local_game_manifest', + expect.anything(), + ); + expect(invoke).not.toHaveBeenCalledWith( + 'generate_platform_art_asset', + expect.anything(), + ); + expect(invoke).not.toHaveBeenCalledWith( + 'sync_canvas_project_assets', + expect.anything(), + ); + expect(invoke).not.toHaveBeenCalledWith( + 'import_canvas_asset', + expect.anything(), + ); + expect(invoke).not.toHaveBeenCalledWith( + 'register_local_asset', + expect.anything(), + ); + expect(invoke).not.toHaveBeenCalledWith( + 'run_limited_local_command', + expect.anything(), + ); + }); + it('registers an existing project asset from chat after confirmation', async () => { const manifest = createGameCreationAppManifest( 'local-project-draft', diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index 1cd0dd41e..6dbbd47b5 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -3875,9 +3875,10 @@ - 2026-07-03 调整:`/llm-status` 读取到的 agent 级 LLM 配置状态可回填到主窗口 Agent 状态列表、聊天侧 `/agents` 汇总和单 Agent 对话头部,显示 provider 类型、模型、流式开关和 API Key 是否已读取;密钥本体仍不能进入聊天、状态列表、manifest、trace 或本地项目文件。 - 2026-07-03 调整:开发窗口日志面板提供 `.agent/logs/command.log`、`.agent/logs/preview.log` 和 `.agent/logs/agent.log` 的只读查看入口,复用 `file.read` 授权策略;普通用户聊天输入 `/logs` 只列出这三个日志文件对应的 `/read ...` 草稿 / 命令并提供首个草稿,不直接读取日志,不新增普通用户日志面板,实际读取仍走聊天侧 `file.read`。 - 2026-07-03 调整:单 Agent 对话面板允许用户把当前输入手动追加到该 agent 的 `memory/agents//.md` 私有记忆;写入复用 `memory.write` 项目策略、项目锁和 Tauri 本地目录能力,不把普通对话流水自动混入私有记忆;聊天侧 `/agent-conversations` 和 `/agent-memories` 只列出同一批 Agent 对话与私有记忆读取命令并提供首个 `/read` 草稿,不直接读取文件。 +- 2026-07-03 调整:普通用户通过聊天输入 `/art` 查看美术素材,只基于当前 manifest 盘点图片、视频和序列帧素材的数量、来源、画板接入状态和路径,并提供 `/generate-art 首版核心美术素材` 或 `/read assets/manifest.art.json` 草稿;该入口不得触发 Tauri 读写、平台生成、画板同步或新增普通用户美术面板。 - 2026-07-03 调整:主窗口新增音效登记和画板音频导入快捷入口,只填入 `/asset-register assets/audio/sfx.wav audio audio/wav` 或 `/import-canvas-asset assets/audio/sfx.wav ` 草稿;聊天输入 `/audio` 只基于当前 manifest 盘点音频素材、来源和路径,并给出登记音效或读取 `assets/manifest.audio.json` 的草稿。音乐组仍复用现有资产登记 / 画板回流链路,不新增独立音频生成系统。 - 2026-07-03 调整:主窗口新增常用生成产物读取入口,只把入口 HTML、设计、数值、美术清单、音频清单和发布说明对应的 `/read` 草稿填入聊天输入框;聊天命令 `/artifacts` 只列出同一组固定读取命令并提供首个读取草稿,`/run-artifacts` 只列出最近 trace 里的产物读取命令并提供首个 `/read` 草稿,`/logs` 只列出固定日志读取命令;实际读取仍走聊天侧 `file.read` 权限流,不直接读本地文件。 -- 2026-07-03 调整:普通用户通过聊天输入 `/next` 触发下一步建议入口,只基于主窗口当前已加载的 manifest、最近 run trace 和最近命令摘要生成聊天建议,列出 `/tasks`、`/trace`、`/review`、`/playtest`、`/run`、`/open-preview`、`/assets`、`/audio`、`/publish`、`/artifacts`、`/run-artifacts`、`/passes`、`/run-files`、`/internals`、`/logs`、`/agent-resume ` 等安全命令草稿方向,并提供一个首选草稿;该命令不得直接执行 Tauri 读写、启动或打开预览、读取本地文件,也不得绕过原有命令确认和 `file.read` 权限流。 +- 2026-07-03 调整:普通用户通过聊天输入 `/next` 触发下一步建议入口,只基于主窗口当前已加载的 manifest、最近 run trace 和最近命令摘要生成聊天建议,列出 `/tasks`、`/trace`、`/review`、`/playtest`、`/run`、`/open-preview`、`/assets`、`/art`、`/audio`、`/publish`、`/artifacts`、`/run-artifacts`、`/passes`、`/run-files`、`/internals`、`/logs`、`/agent-resume ` 等安全命令草稿方向,并提供一个首选草稿;该命令不得直接执行 Tauri 读写、启动或打开预览、读取本地文件,也不得绕过原有命令确认和 `file.read` 权限流。 - 2026-07-03 调整:普通用户通过聊天输入 `/publish` 生成发布准备清单,只基于主窗口当前已加载的 manifest、最近 run trace、预览状态、资产来源和最近命令摘要列出原型通过、预览、任务、资产、音频、包装说明和试玩包状态,并提供 `/run`、`/trace`、`/agent-resume ` 或 `/export` 草稿;该入口不得触发 Tauri 读写、不得启动或打开预览、不得读取文件,也不得新增普通用户发布面板。 - 2026-07-03 调整:普通用户通过聊天输入 `/internals` 只列出 `.agent/manifest.json`、`.agent/run.latest.json`、`.agent/spec.md`、`.agent/findings.md`、`.agent/policy.json`、`.agent/project.index.json`、`.agent/agent.db` 和 `.agent/conversations/project.jsonl` 的 `/read` 草稿,并提供首个读取草稿;该入口不得直接读取内部文件、不得触发 Tauri 读写,也不得新增普通用户内部文件面板。 - 2026-07-03 调整:普通用户通过聊天输入 `/passes` 只从当前已加载的最近 run trace artifacts 中筛选 `.agent/passes/` 轮次产物,列出 `/read` 草稿并提供首个读取草稿;该入口不得直接读取轮次文件、不得触发 Tauri 读写,也不得新增普通用户轮次面板。 diff --git a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md index e0823d74a..587151222 100644 --- a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md +++ b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md @@ -100,7 +100,7 @@ game-project/ ## v1 验收 - 用户能创建本地 Web 游戏项目。 -- 用户侧看到当前工作区项目名 / 路径、最近 run、预览状态、任务完成数 / ready 数、资产数量 / 来源分布、最近命令摘要、聊天框、上传入口、Agent 状态列表和单 Agent 对话;聊天输入 `/brief` 可在普通聊天消息里生成当前项目简报并提供 `/next` 草稿,不新增普通用户面板;聊天输入 `/risks` 可在普通聊天消息里查看当前项目风险并提供首个风险处理草稿,不新增普通用户面板;聊天输入 `/review` 可在普通聊天消息里查看 Evaluator 评审、返工焦点和返工路线并提供读取评审记录或继续修复草稿,不新增普通用户面板;聊天输入 `/playtest` 可在普通聊天消息里查看最近 run 是否可试玩、当前预览状态和 Playtest 任务状态并提供启动或打开预览草稿,不新增普通用户试玩面板;聊天输入 `/handoff` 可在普通聊天消息里生成当前项目交接摘要并提供 `/next` 草稿,不新增普通用户面板;聊天输入 `/runs` 可在普通聊天消息里列出已加载 Run 历史读取命令,不新增普通用户面板;聊天输入 `/run-files` 可在普通聊天消息里列出 Agent 运行辅助文件读取命令,不新增普通用户面板;聊天输入 `/internals` 可在普通聊天消息里列出项目内部真相源读取命令,不新增内部文件面板;聊天输入 `/audio` 可基于当前 manifest 盘点音频素材并提供登记或读取草稿,不新增音频生成系统;聊天输入 `/publish` 可基于当前 manifest 和最近 run 生成发布准备清单并提供运行、trace、继续或导出草稿,不新增发布面板;聊天输入 `/export` 确认后把当前可试玩原型导出为本地试玩 ZIP,聊天输入 `/exports` 可只读列出已导出的本地试玩包;Agent 状态列表和单 Agent 对话在 `/llm-status` 后显示该 agent 当前 LLM provider / 模型 / 流式 / API Key 读取状态,但不显示密钥本体;最近项目资产入口显示本地路径、kind、mediaType 和来源类型,并可一键填入 `/read` 草稿,开发环境通过独立窗口查看任务拆分、专业组细节、产物、文件面板、嵌入预览以及 `.agent/logs/command.log` / `preview.log` / `agent.log`。 +- 用户侧看到当前工作区项目名 / 路径、最近 run、预览状态、任务完成数 / ready 数、资产数量 / 来源分布、最近命令摘要、聊天框、上传入口、Agent 状态列表和单 Agent 对话;聊天输入 `/brief` 可在普通聊天消息里生成当前项目简报并提供 `/next` 草稿,不新增普通用户面板;聊天输入 `/risks` 可在普通聊天消息里查看当前项目风险并提供首个风险处理草稿,不新增普通用户面板;聊天输入 `/review` 可在普通聊天消息里查看 Evaluator 评审、返工焦点和返工路线并提供读取评审记录或继续修复草稿,不新增普通用户面板;聊天输入 `/playtest` 可在普通聊天消息里查看最近 run 是否可试玩、当前预览状态和 Playtest 任务状态并提供启动或打开预览草稿,不新增普通用户试玩面板;聊天输入 `/handoff` 可在普通聊天消息里生成当前项目交接摘要并提供 `/next` 草稿,不新增普通用户面板;聊天输入 `/runs` 可在普通聊天消息里列出已加载 Run 历史读取命令,不新增普通用户面板;聊天输入 `/run-files` 可在普通聊天消息里列出 Agent 运行辅助文件读取命令,不新增普通用户面板;聊天输入 `/internals` 可在普通聊天消息里列出项目内部真相源读取命令,不新增内部文件面板;聊天输入 `/art` 可基于当前 manifest 盘点美术素材并提供生成或读取草稿,不新增美术面板;聊天输入 `/audio` 可基于当前 manifest 盘点音频素材并提供登记或读取草稿,不新增音频生成系统;聊天输入 `/publish` 可基于当前 manifest 和最近 run 生成发布准备清单并提供运行、trace、继续或导出草稿,不新增发布面板;聊天输入 `/export` 确认后把当前可试玩原型导出为本地试玩 ZIP,聊天输入 `/exports` 可只读列出已导出的本地试玩包;Agent 状态列表和单 Agent 对话在 `/llm-status` 后显示该 agent 当前 LLM provider / 模型 / 流式 / API Key 读取状态,但不显示密钥本体;最近项目资产入口显示本地路径、kind、mediaType 和来源类型,并可一键填入 `/read` 草稿,开发环境通过独立窗口查看任务拆分、专业组细节、产物、文件面板、嵌入预览以及 `.agent/logs/command.log` / `preview.log` / `agent.log`。 - 聊天输入 `/passes` 可在普通聊天消息里列出最近 run trace 中 `.agent/passes/` 轮次产物读取命令,不直接读取轮次文件,也不新增普通用户轮次面板。 - 生成代码和资产进入用户本地项目目录。 - 本地 HTTP 预览能启动,并在外部浏览器展示可玩原型。 @@ -112,7 +112,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 产物读取命令,聊天侧 `/run-files` 可列出 Agent 运行辅助文件读取命令,聊天侧 `/logs` 可列出固定日志读取命令且不直接读取日志,聊天侧 `/brief` 只基于当前已加载的 manifest / 最近 run trace / 预览状态 / 资产数量 / 最近命令生成项目简报,提供 `/next` 后续草稿且不直接触发 Tauri 读写、文件读取、预览启动或新增面板,聊天侧 `/next` 基于当前已加载的 manifest / 最近 run trace 输出下一步建议和 `/tasks` / `/trace` / `/run` / `/open-preview` / `/assets` / `/artifacts` / `/run-artifacts` / `/run-files` / `/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 轮失败时不会写入最终游戏产物。 +- `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` 策略、主窗口提供音效登记、画板音频导入和常用生成产物读取草稿入口,聊天侧 `/art` 可盘点美术素材且不直接触发平台生成或画板同步,聊天侧 `/artifacts` 可列出常用生成产物读取命令,聊天侧 `/run-artifacts` 可列出最近 run 产物读取命令,聊天侧 `/run-files` 可列出 Agent 运行辅助文件读取命令,聊天侧 `/logs` 可列出固定日志读取命令且不直接读取日志,聊天侧 `/brief` 只基于当前已加载的 manifest / 最近 run trace / 预览状态 / 资产数量 / 最近命令生成项目简报,提供 `/next` 后续草稿且不直接触发 Tauri 读写、文件读取、预览启动或新增面板,聊天侧 `/next` 基于当前已加载的 manifest / 最近 run trace 输出下一步建议和 `/tasks` / `/trace` / `/run` / `/open-preview` / `/assets` / `/art` / `/artifacts` / `/run-artifacts` / `/run-files` / `/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 轮失败时不会写入最终游戏产物。 - `/risks` 聊天入口由 `appSurface.test.ts` 的主窗口 smoke 覆盖:只基于当前已加载的 manifest / trace / 预览 / 任务 / 资产 / 最近命令生成风险摘要,提供首个风险处理草稿,不触发 Tauri 读写、文件读取、预览启动或新增普通用户面板。 - `/review` 聊天入口由 `appSurface.test.ts` 主窗口 smoke 覆盖:只基于当前已加载 run trace 汇总 Evaluator 状态、返工焦点、返工路线和最近评审步骤,提供 `/read .agent/findings.md` 或 `/agent-resume ` 草稿,不直接读取评审文件、不触发 Tauri 读写或新增普通用户面板。 - `/playtest` 聊天入口由 `appSurface.test.ts` 主窗口 smoke 覆盖:只基于当前已加载 manifest、最近 run trace 和 preview 状态汇总是否可试玩、Playtest 任务状态和预览日志读取命令,提供 `/run`、`/open-preview`、`/trace` 或 `/review` 草稿,不触发 Tauri 读写、预览启动 / 打开或新增普通用户试玩面板。 @@ -123,6 +123,7 @@ game-project/ - `/internals` 聊天入口由 `appSurface.test.ts` 主窗口 smoke 覆盖:只列出 `.agent/manifest.json`、`.agent/run.latest.json`、`.agent/spec.md`、`.agent/findings.md`、`.agent/policy.json`、`.agent/project.index.json`、`.agent/agent.db` 和 `.agent/conversations/project.jsonl` 的 `/read` 草稿,不直接读取内部文件、不触发 Tauri 读写或新增普通用户面板。 - `/export` 聊天入口由 `appSurface.test.ts` 的主窗口 smoke 和 Tauri Rust 测试覆盖:确认后执行 `project.export_package`,导出 `exports/playtest-package-*.zip`,只打包 `game/**`、`assets/**` 和 `exports/README.md`,不包含 `.agent/`、`memory/`、运行时配置、日志、trace 或密钥文件;导出前必须通过 `game/index.html` 可试玩静态验收,并写入 manifest `commandRuns`、`.agent/logs/command.log` 和 `.agent/agent.db`。 - `/exports` 聊天入口由 `appSurface.test.ts` 主窗口 smoke、项目权限确认测试和 Tauri Rust 测试覆盖:只读执行 `project.export_list`,列出 `exports/playtest-package-*.zip`,跳过符号链接和非试玩包文件,不删除旧包、不做系统分享、不新增普通用户面板。 +- `/art` 聊天入口由 `appSurface.test.ts` 主窗口 smoke 和美术资产定向测试覆盖:只基于当前已加载 manifest 盘点图片、视频和序列帧美术素材数量、来源、画板接入状态和路径,提供 `/generate-art 首版核心美术素材` 或 `/read assets/manifest.art.json` 草稿,不触发 Tauri 文件读取、平台生成、画板同步、资产写入或新增普通用户面板。 - `/audio` 聊天入口由 `appSurface.test.ts` 主窗口 smoke 和音频资产定向测试覆盖:只基于当前已加载 manifest 盘点音频素材数量、来源和路径,提供 `/asset-register assets/audio/sfx.wav audio audio/wav` 或 `/read assets/manifest.audio.json` 草稿,不触发 Tauri 文件读取、资产写入、画板导入或新增普通用户面板。 - `/publish` 聊天入口由 `appSurface.test.ts` 主窗口 smoke 覆盖:只基于当前已加载 manifest、最近 run trace、预览状态、资产来源和最近命令生成发布准备清单,提供 `/run`、`/trace`、`/agent-resume ` 或 `/export` 草稿,不触发 Tauri 读写、预览启动、文件读取或新增普通用户面板。 - 主窗口策略快捷入口只填入 `/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 生命周期写入。 @@ -182,7 +183,7 @@ game-project/ - 聊天区待确认命令必须先记录 `permission.pending`,用户点击后再记录 `permission.confirm` 或 `permission.cancel`;已授权本地项目内的权限事件同步追加到 `.agent/logs/command.log`,待确认卡片显示本地写入目标路径。 - 聊天输入 `/status` 会读取 `.agent/manifest.json` 并在聊天里汇总项目目录、任务状态、资产数量、预览状态和最近命令,不向普通用户暴露任务或文件面板。 - 聊天输入 `/files` 会通过 `file.list` 只读列出本地项目内的文件摘要;主窗口最近项目文件可一键读取,也可一键填入 `/read` 或 `/asset-register` 草稿,但资产登记仍必须走聊天确认;`/checkpoints` 复用 `file.list` / `file.read` 只读列出最近 checkpoint id、文件数、大小和可复制的 `/diff` / `/restore` 命令,主窗口最近 checkpoint 列表也可填入对应草稿;普通用户仍不暴露文件读写面板。 -- 聊天输入 `/assets` 会读取 `.agent/manifest.json` 并在聊天里列出本地项目资产路径、类型和来源,资产列表消息和主窗口最近项目资产入口都可一键填入对应资产的 `/read` 草稿;聊天输入 `/audio` 只使用当前已加载 manifest 盘点音频素材,并提供登记音效或读取音频清单草稿,不直接读取文件、不触发资产写入;`/asset-register 路径 [kind] [mediaType]` 可确认后登记项目内已有资产;主窗口音效快捷入口只填入 `/asset-register assets/audio/sfx.wav audio audio/wav` 草稿,不直接写 manifest;普通用户仍不暴露资产面板。 +- 聊天输入 `/assets` 会读取 `.agent/manifest.json` 并在聊天里列出本地项目资产路径、类型和来源,资产列表消息和主窗口最近项目资产入口都可一键填入对应资产的 `/read` 草稿;聊天输入 `/art` 只使用当前已加载 manifest 盘点美术素材,并提供首版美术生成或读取美术清单草稿,不直接读取文件、不触发平台生成或画板同步;聊天输入 `/audio` 只使用当前已加载 manifest 盘点音频素材,并提供登记音效或读取音频清单草稿,不直接读取文件、不触发资产写入;`/asset-register 路径 [kind] [mediaType]` 可确认后登记项目内已有资产;主窗口音效快捷入口只填入 `/asset-register assets/audio/sfx.wav audio audio/wav` 草稿,不直接写 manifest;普通用户仍不暴露资产面板。 - 聊天输入 `/read 本地相对路径` 会通过 `file.read` 只读返回项目内文本文件内容并在聊天中截断长文本;普通用户仍不暴露文件写入或删除能力。 - 主窗口常用生成产物入口只把 `game/index.html`、`game/game_design.md`、`game/balance.json`、`assets/manifest.art.json`、`assets/manifest.audio.json` 和 `exports/README.md` 的 `/read` 草稿填入聊天输入框;聊天输入 `/artifacts` 只列出这组固定读取命令并提供首个 `/read` 草稿,聊天输入 `/run-artifacts` 只列出最近 run trace 里的产物读取命令并提供首个 `/read` 草稿,聊天输入 `/run-files` 只列出 `.agent/output.jsonl`、`.agent/activity.jsonl` 和 `.agent/context.bundle.json` 的读取命令并提供首个 `/read` 草稿;读取仍由聊天侧 `file.read` 权限流执行。 - 聊天输入 `/logs` 只列出 `.agent/logs/command.log`、`.agent/logs/preview.log` 和 `.agent/logs/agent.log` 对应的 `/read ...` 草稿 / 命令,并提供首个 `/read` 草稿;该命令不直接读取日志,不新增普通用户日志面板,实际读取仍由聊天侧 `file.read` 权限流执行。 @@ -192,7 +193,7 @@ game-project/ - 聊天输入 `/risks` 只使用主窗口当前已加载的 manifest、最近 run trace、预览状态、任务状态、资产来源和最近命令摘要,在聊天里列出当前项目风险,并提供首个风险处理草稿;该命令不调用 Tauri 读写、不读取文件、不启动或打开预览、不新增普通用户面板,用户必须再发送草稿并按原命令权限流继续。 - 聊天输入 `/handoff` 只使用主窗口当前已加载的 manifest、最近 run trace、Agent 状态和已载入历史 run 批次,在聊天里生成项目交接摘要,并提供 `/next` 作为后续草稿;该命令不调用 Tauri 读写、不读取文件、不启动或打开预览、不新增普通用户面板,用户必须再发送草稿并按原命令权限流继续。 - 聊天输入 `/runs` 只使用主窗口当前已加载的 latest trace 和已载入历史 run 批次,在聊天里列出 `/trace` 和 `/read .agent/runs/...` 读取草稿;该命令不调用 Tauri 读写、不滚动加载更多历史、不启动或打开预览、不新增普通用户面板,用户必须再发送草稿并按原命令权限流继续。 -- 聊天输入 `/next` 只使用主窗口当前已加载的 manifest、最近 run trace 和最近命令摘要,在聊天里给出下一步建议,列出 `/tasks`、`/trace`、`/review`、`/playtest`、`/run`、`/export`、`/exports`、`/open-preview`、`/assets`、`/audio`、`/publish`、`/artifacts`、`/run-artifacts`、`/passes`、`/run-files`、`/internals`、`/logs`、`/agent-resume ` 等安全命令草稿方向,并提供一个首选草稿;该命令不调用 Tauri 读写、不启动或打开预览、不读取文件,用户必须再发送草稿并按原命令权限流继续。 +- 聊天输入 `/next` 只使用主窗口当前已加载的 manifest、最近 run trace 和最近命令摘要,在聊天里给出下一步建议,列出 `/tasks`、`/trace`、`/review`、`/playtest`、`/run`、`/export`、`/exports`、`/open-preview`、`/assets`、`/art`、`/audio`、`/publish`、`/artifacts`、`/run-artifacts`、`/passes`、`/run-files`、`/internals`、`/logs`、`/agent-resume ` 等安全命令草稿方向,并提供一个首选草稿;该命令不调用 Tauri 读写、不启动或打开预览、不读取文件,用户必须再发送草稿并按原命令权限流继续。 - 聊天输入 `/review` 只使用主窗口当前已加载的最近 run trace,在聊天里列出 Evaluator 通过 / 需返工状态、返工焦点、返工路线、下一步和最近评审步骤;该命令不调用 Tauri 读写、不读取 `.agent/findings.md`、不新增普通用户评审面板,真正读取评审记录仍由用户发送 `/read .agent/findings.md` 并走 `file.read` 权限流,需要返工时只填入 `/agent-resume ` 草稿。 - 聊天输入 `/playtest` 只使用主窗口当前已加载的 manifest、最近 run trace 和 preview 状态,在聊天里列出原型是否已通过、预览是否运行、Playtest 任务状态、最近试玩步骤和 `.agent/logs/preview.log` 读取命令;该命令不调用 Tauri 读写、不启动或打开预览、不读取日志、不新增普通用户试玩面板,真正运行或打开仍由用户发送 `/run` 或 `/open-preview` 并走原确认流。 - 聊天输入 `/passes` 只使用主窗口当前已加载的最近 run trace,从 `artifacts` 中筛选 `.agent/passes/` 相对路径,在聊天里列出轮次产物读取命令并提供首个 `/read` 草稿;该命令不调用 Tauri 读写、不读取文件、不新增普通用户轮次面板,真正读取仍由用户发送 `/read` 并走 `file.read` 权限流。