diff --git a/apps/ai-game-creator-shell/src/App.tsx b/apps/ai-game-creator-shell/src/App.tsx index 89d002d1e..b78b58d3d 100644 --- a/apps/ai-game-creator-shell/src/App.tsx +++ b/apps/ai-game-creator-shell/src/App.tsx @@ -237,6 +237,17 @@ const commonAgentRunSupportReadDrafts = [ { label: '读上下文包', path: '.agent/context.bundle.json' }, ] as const; +const commonProjectInternalReadDrafts = [ + { label: '读 manifest', path: '.agent/manifest.json' }, + { label: '读 run 指针', path: '.agent/run.latest.json' }, + { label: '读规格', path: '.agent/spec.md' }, + { label: '读评审', path: '.agent/findings.md' }, + { label: '读权限策略', path: '.agent/policy.json' }, + { label: '读项目索引', path: '.agent/project.index.json' }, + { label: '读本地索引流', path: '.agent/agent.db' }, + { label: '读项目对话', path: '.agent/conversations/project.jsonl' }, +] as const; + interface ListLocalProjectFilesResult { projectPath: string; files: LocalProjectFileEntry[]; @@ -1890,6 +1901,7 @@ const chatCommandHelp = [ '/run-artifacts:列出最近 Run 产物读取命令', '/runs:列出已加载 Run 历史读取命令', '/run-files:列出 Agent 运行辅助文件读取命令', + '/internals:列出项目内部真相源读取命令', '/logs:列出常用日志读取命令', '/asset-register 路径 [kind] [mediaType]:登记项目内已有资产', '/read 路径:读取本地项目内文本文件', @@ -2401,6 +2413,7 @@ function summarizeNextProjectActions( addSuggestion('列出 Agent 运行辅助文件', '/run-files'); } addSuggestion('打开产物命令列表', '/artifacts'); + addSuggestion('列出内部真相源读取命令', '/internals'); addSuggestion('打开日志命令列表', '/logs'); const firstCommand = suggestions.find((item) => item.command); @@ -2776,6 +2789,12 @@ function summarizeAgentRunSupportFileReadDrafts() { .join('\n')}`; } +function summarizeProjectInternalReadDrafts() { + return `项目内部真相源读取命令:\n${commonProjectInternalReadDrafts + .map((file) => `- ${file.label} · ${file.path} · /read ${file.path}`) + .join('\n')}`; +} + function summarizeProjectAssets(nextManifest: GameCreationAppManifest) { if (nextManifest.assets.length === 0) { return '本地项目还没有登记资产。'; @@ -6187,6 +6206,22 @@ export function App() { return; } + if (prompt === '/internals') { + if (!requireChatProjectForUserAction()) { + return; + } + setMessages((current) => [ + ...current, + { + role: 'assistant', + text: summarizeProjectInternalReadDrafts(), + draftCommand: `/read ${commonProjectInternalReadDrafts[0].path}`, + draftCommandLabel: commonProjectInternalReadDrafts[0].label, + }, + ]); + return; + } + if (prompt === '/logs') { 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 69f687648..98f6f605f 100644 --- a/apps/ai-game-creator-shell/tests/appSurface.test.ts +++ b/apps/ai-game-creator-shell/tests/appSurface.test.ts @@ -2282,6 +2282,31 @@ describe('AI 游戏创作 App 界面边界', () => { ), ).toHaveLength(fileReadCountBeforeRunFiles); + const fileReadCountBeforeInternals = invoke.mock.calls.filter( + ([command]) => command === 'read_local_project_file', + ).length; + submitChat('/internals'); + expect(await screen.findByText(/项目内部真相源读取命令:/)).not.toBeNull(); + expect( + screen.getByText(/读 manifest · \.agent\/manifest\.json/), + ).not.toBeNull(); + expect( + screen.getByText(/读项目对话 · \.agent\/conversations\/project\.jsonl/), + ).not.toBeNull(); + const internalDraftButtons = screen.getAllByRole('button', { + name: '读 manifest', + }); + fireEvent.click(internalDraftButtons[internalDraftButtons.length - 1]); + expect(screen.getByLabelText('创作想法')).toHaveProperty( + 'value', + '/read .agent/manifest.json', + ); + expect( + invoke.mock.calls.filter( + ([command]) => command === 'read_local_project_file', + ), + ).toHaveLength(fileReadCountBeforeInternals); + const runLocalCountBeforeNext = invoke.mock.calls.filter( ([command]) => command === 'run_limited_local_command', ).length; @@ -2290,6 +2315,9 @@ describe('AI 游戏创作 App 界面边界', () => { expect(screen.getByText(/运行自检并启动本地预览:\/run/)).not.toBeNull(); expect(screen.getByText(/查看 .* 个 ready 任务:\/tasks/)).not.toBeNull(); expect(screen.getByText(/查看发布准备清单:\/publish/)).not.toBeNull(); + expect( + screen.getByText(/列出内部真相源读取命令:\/internals/), + ).not.toBeNull(); expect( screen.getByText(/列出 Agent 运行辅助文件:\/run-files/), ).not.toBeNull(); @@ -8063,6 +8091,9 @@ describe('AI 游戏创作 App 界面边界', () => { expect( screen.getByText(/\/run-files:列出 Agent 运行辅助文件读取命令/), ).not.toBeNull(); + expect( + screen.getByText(/\/internals:列出项目内部真相源读取命令/), + ).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 d869910e4..efdfe31a2 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -3875,8 +3875,9 @@ - 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 ` 草稿;聊天输入 `/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`、`/run`、`/open-preview`、`/assets`、`/audio`、`/publish`、`/artifacts`、`/run-artifacts`、`/run-files`、`/logs`、`/agent-resume ` 等安全命令草稿方向,并提供一个首选草稿;该命令不得直接执行 Tauri 读写、启动或打开预览、读取本地文件,也不得绕过原有命令确认和 `file.read` 权限流。 +- 2026-07-03 调整:普通用户通过聊天输入 `/next` 触发下一步建议入口,只基于主窗口当前已加载的 manifest、最近 run trace 和最近命令摘要生成聊天建议,列出 `/tasks`、`/trace`、`/run`、`/open-preview`、`/assets`、`/audio`、`/publish`、`/artifacts`、`/run-artifacts`、`/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-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 2140f2b71..f8dfe4a74 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` 可在普通聊天消息里查看当前项目风险并提供首个风险处理草稿,不新增普通用户面板;聊天输入 `/handoff` 可在普通聊天消息里生成当前项目交接摘要并提供 `/next` 草稿,不新增普通用户面板;聊天输入 `/runs` 可在普通聊天消息里列出已加载 Run 历史读取命令,不新增普通用户面板;聊天输入 `/run-files` 可在普通聊天消息里列出 Agent 运行辅助文件读取命令,不新增普通用户面板;聊天输入 `/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` 可在普通聊天消息里查看当前项目风险并提供首个风险处理草稿,不新增普通用户面板;聊天输入 `/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`。 - 生成代码和资产进入用户本地项目目录。 - 本地 HTTP 预览能启动,并在外部浏览器展示可玩原型。 - 美术/音乐资产能从画板链路回流到本地项目。 @@ -116,6 +116,7 @@ game-project/ - `/handoff` 聊天入口由 `appSurface.test.ts` 的主窗口 smoke 覆盖:只基于当前已加载的 manifest / trace / agent 状态 / run history 生成交接摘要,提供 `/next` 草稿,不触发 Tauri 读写、文件读取、预览启动或新增普通用户面板。 - `/runs` 聊天入口由 `appSurface.test.ts` 的主窗口 smoke 覆盖:只基于当前已加载的 latest trace 和已载入历史 run 批次生成 `/trace` 或 `/read .agent/runs/...` 草稿,不额外触发 Tauri 读取、不滚动加载更多历史、不新增普通用户面板。 - `/run-files` 聊天入口由 `appSurface.test.ts` 的主窗口 smoke 覆盖:只列出 `.agent/output.jsonl`、`.agent/activity.jsonl` 和 `.agent/context.bundle.json` 的 `/read` 草稿,不直接读取辅助文件、不触发 Tauri 读写或新增普通用户面板。 +- `/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`,跳过符号链接和非试玩包文件,不删除旧包、不做系统分享、不新增普通用户面板。 - `/audio` 聊天入口由 `appSurface.test.ts` 主窗口 smoke 和音频资产定向测试覆盖:只基于当前已加载 manifest 盘点音频素材数量、来源和路径,提供 `/asset-register assets/audio/sfx.wav audio audio/wav` 或 `/read assets/manifest.audio.json` 草稿,不触发 Tauri 文件读取、资产写入、画板导入或新增普通用户面板。 @@ -187,7 +188,8 @@ 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`、`/run`、`/export`、`/exports`、`/open-preview`、`/assets`、`/audio`、`/publish`、`/artifacts`、`/run-artifacts`、`/run-files`、`/logs`、`/agent-resume ` 等安全命令草稿方向,并提供一个首选草稿;该命令不调用 Tauri 读写、不启动或打开预览、不读取文件,用户必须再发送草稿并按原命令权限流继续。 +- 聊天输入 `/next` 只使用主窗口当前已加载的 manifest、最近 run trace 和最近命令摘要,在聊天里给出下一步建议,列出 `/tasks`、`/trace`、`/run`、`/export`、`/exports`、`/open-preview`、`/assets`、`/audio`、`/publish`、`/artifacts`、`/run-artifacts`、`/run-files`、`/internals`、`/logs`、`/agent-resume ` 等安全命令草稿方向,并提供一个首选草稿;该命令不调用 Tauri 读写、不启动或打开预览、不读取文件,用户必须再发送草稿并按原命令权限流继续。 +- 聊天输入 `/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`;该命令不调用 Tauri 读写、不读取文件、不新增普通用户内部文件面板,真正读取仍由用户发送 `/read` 并走 `file.read` 权限流。 - 聊天输入 `/publish` 只使用主窗口当前已加载的 manifest、最近 run trace、预览状态、资产来源和最近命令摘要,在聊天里生成发布准备清单,列出原型通过状态、预览、任务、资产、音频、包装说明和试玩包导出状态,并提供 `/run`、`/trace`、`/agent-resume ` 或 `/export` 草稿;该命令不调用 Tauri 读写、不启动或打开预览、不读取文件、不新增普通用户面板,真正导出仍由用户发送 `/export` 并走确认流。 - 主窗口可从 agent 状态列表进入单个 agent 对话;该入口只加载目标 agent 的 conversation JSONL,发送消息后追加到同一 agent conversation,不开启平行任务图、不 fork run,也不归档历史会话。 - v1 通过独立启动器窗口选择本地项目后再进入主窗口;主窗口只承载当前工作区的聊天、配置和 agent 状态,切换项目时关闭当前主窗口并回到启动器,主窗口按钮和 `/switch-project` 聊天命令都复用同一 Tauri 启动器入口,避免在主窗口内用遮罩面板混合多个工作区上下文。