From 7842d5bab38cdb9634b058226a4fa9042a13f9c2 Mon Sep 17 00:00:00 2001 From: AIGameCreator App Date: Fri, 10 Jul 2026 19:33:14 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E5=A4=8DTauri=E4=BA=8B=E4=BB=B6?= =?UTF-8?q?=E8=AE=A2=E9=98=85=E4=B8=8E=E5=BC=80=E5=8F=91=E7=99=BD=E5=B1=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 为客户端与开发窗口补齐只读事件监听 capability 允许 Vite 开发服务器加载仓库共享契约 增加 capability 与共享源码配置门禁 同步更新实施计划和项目决策记录 --- .../scripts/check-config.mjs | 47 +++++++++++++++++++ .../src-tauri/capabilities/events.json | 10 ++++ apps/ai-game-creator-shell/vite.config.ts | 3 ++ .../shared-memory/decision-log.md | 1 + ...案】AI游戏创作智能体App实施计划-2026-06-24.md | 1 + 5 files changed, 62 insertions(+) create mode 100644 apps/ai-game-creator-shell/src-tauri/capabilities/events.json diff --git a/apps/ai-game-creator-shell/scripts/check-config.mjs b/apps/ai-game-creator-shell/scripts/check-config.mjs index d42276459..60fd9a2ef 100644 --- a/apps/ai-game-creator-shell/scripts/check-config.mjs +++ b/apps/ai-game-creator-shell/scripts/check-config.mjs @@ -9,6 +9,10 @@ const tauriConfig = JSON.parse( 'utf8', ), ); +const eventCapabilityPath = new URL( + '../src-tauri/capabilities/events.json', + import.meta.url, +); const defaultAppConfig = JSON.parse( fs.readFileSync( new URL('../game-creator.config.json', import.meta.url), @@ -384,6 +388,43 @@ if (tauriConfig.app?.withGlobalTauri !== true) { ); } +if (!fs.existsSync(eventCapabilityPath)) { + throw new Error( + 'AI game creator shell must declare a Tauri event-listener capability', + ); +} +const eventCapability = JSON.parse( + fs.readFileSync(eventCapabilityPath, 'utf8'), +); +const eventCapabilityWindows = new Set(eventCapability.windows ?? []); +const eventCapabilityPermissions = new Set(eventCapability.permissions ?? []); +for (const windowLabel of ['client', 'developer', 'main', 'launcher']) { + if (!eventCapabilityWindows.has(windowLabel)) { + throw new Error( + `AI game creator shell event capability missing window: ${windowLabel}`, + ); + } +} +for (const permission of [ + 'core:event:allow-listen', + 'core:event:allow-unlisten', +]) { + if (!eventCapabilityPermissions.has(permission)) { + throw new Error( + `AI game creator shell event capability missing permission: ${permission}`, + ); + } +} +if ( + eventCapabilityPermissions.has('core:event:allow-emit') || + eventCapabilityPermissions.has('core:event:allow-emit-to') || + eventCapabilityPermissions.has('core:event:default') +) { + throw new Error( + 'AI game creator shell frontend event capability must stay listen-only', + ); +} + if ( !Array.isArray(tauriConfig.app?.windows) || tauriConfig.app.windows.length !== 1 || @@ -458,6 +499,12 @@ if (!viteConfigSource.includes('strictPort: true')) { ); } +if (!viteConfigSource.includes('allow: [repoRoot]')) { + throw new Error( + 'AI game creator shell Vite dev server must allow shared repository sources', + ); +} + if ( !( tauriConfig.build?.beforeDevCommand?.includes( diff --git a/apps/ai-game-creator-shell/src-tauri/capabilities/events.json b/apps/ai-game-creator-shell/src-tauri/capabilities/events.json new file mode 100644 index 000000000..ee720194b --- /dev/null +++ b/apps/ai-game-creator-shell/src-tauri/capabilities/events.json @@ -0,0 +1,10 @@ +{ + "$schema": "../gen/schemas/desktop-schema.json", + "identifier": "events", + "description": "允许客户端窗口订阅并取消订阅 Rust Runtime 事件。", + "windows": ["client", "developer", "main", "launcher"], + "permissions": [ + "core:event:allow-listen", + "core:event:allow-unlisten" + ] +} diff --git a/apps/ai-game-creator-shell/vite.config.ts b/apps/ai-game-creator-shell/vite.config.ts index 94caaba66..d1cbd26fe 100644 --- a/apps/ai-game-creator-shell/vite.config.ts +++ b/apps/ai-game-creator-shell/vite.config.ts @@ -62,6 +62,9 @@ export default defineConfig({ host: '127.0.0.1', port: 3080, strictPort: true, + fs: { + allow: [repoRoot], + }, proxy: { '/api': { target: apiTarget, diff --git a/docs/project-memory/shared-memory/decision-log.md b/docs/project-memory/shared-memory/decision-log.md index a2e4b0230..c8ac93873 100644 --- a/docs/project-memory/shared-memory/decision-log.md +++ b/docs/project-memory/shared-memory/decision-log.md @@ -4105,6 +4105,7 @@ - 2026-07-04 调整,2026-07-08 更新:`apps/ai-game-creator-shell/src-tauri/src/main.rs` 拆成薄入口,继续只保留共享类型 / 常量、模块声明、CLI preflight、`tauri::Builder`、运行时配置初始化和 `invoke_handler` 清单;CLI 参数解析与终端运行输出放入 `cli.rs`,Tauri command 包装放入 `commands.rs`,运行时配置 / LLM 配置检查放入 `config.rs`,Agent loop 与生成编排放入 `agent.rs`,上传 / 画板 / 平台美术生成接入放入 `assets.rs`,本地项目文件、记忆、对话、权限、checkpoint、manifest 和通用路径工具放入 `project.rs`,本地 HTTP 预览 server、preview registry 和 preview Tauri command 放入 `preview.rs`,旧窗口 URL 与兼容 command 放入 `windows.rs`,Rust 单测放入 `tests.rs`。拆分不得改变 Tauri command 名、JSON 字段、`.agent/*` 路径、项目权限策略或错误语义。 - 2026-06-24 调整,2026-07-08 更新:AI 游戏创作 App 的 release 配置只登记一个普通用户窗口,登录后在同一 WebView 中进入首页、项目组和项目开发占位;开发专用单 Agent 对话、任务、文件、记忆、预览、日志和能力面板只能通过 Vite dev 的 `?dev/#dev` 分支或 debug 构建自动打开的 `developer` 开发窗口查看,不进入普通用户窗口。旧工作区窗口切换 command 只保留兼容,用户主流程不得调用它。 - 2026-06-24 调整,2026-07-08 更新:`check:native-shells` 必须静态守住 AI 游戏创作 App 的用户 / 开发边界:release 只保留一个普通用户窗口,用户侧预览只交给系统外部浏览器,开发面板只能在 `devMode` 分支或 debug-only `developer` 窗口渲染,`developer` 窗口当前使用 `index.html?agent-chat` 并复用 `.agent/conversations/agents/.jsonl` 持久化单 Agent 对话;发布入口和普通用户窗口不得暴露 `Agent 聊天` 导航,也不得调用旧工作区窗口切换 command。 +- 2026-07-10 调整:AI 游戏创作 App 的 Runtime 实时状态依赖 Tauri event listen。`src-tauri/capabilities/events.json` 必须覆盖 `client`、`developer`、`main`、`launcher`,只授予 `core:event:allow-listen` 与 `core:event:allow-unlisten`,不得向前端授予 emit;`check-config.mjs` 静态守住窗口和权限边界。Vite 开发服务器必须把仓库根目录加入 `server.fs.allow`,因为 App 直接加载 `packages/shared/src`;否则真实 WebView 会因共享源码 403 白屏,即使 TypeScript 检查仍通过。 - 2026-06-25 调整:`check:native-shells` 在 `ai-game-creator-shell:check` 之后必须追加 `ai-game-creator-shell:build -- --no-bundle`,让原生壳总门禁同时证明 AI 游戏创作独立 Tauri 壳能完成 release 编译,而不是只证明前端 / Rust 逻辑测试通过。 - 2026-06-24 调整:普通用户通过聊天输入 `/preview` 触发待确认 `preview.start`,完成 `/project` 初始化后可通过 `/open-preview` 触发待确认 `preview.open` 并只打开当前已授权项目对应的 `127.0.0.1` 本地预览,通过 `/preview-status` 查询当前项目预览,通过 `/preview-stop` 停止当前项目预览;预览 iframe 和状态面板仍只在开发窗口可见,不能把 `preview.open` 扩展成任意 URL 打开能力,也不能打开、展示或停止其它本地项目遗留的全局预览。 - 2026-06-25 调整:`/preview-status` 虽然是只读命令,也必须写入 `preview.status` 命令日志并向聊天返回错误,不得因查询失败产生未捕获异常或无审计记录。 diff --git a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md index 54e44a6f0..9e841476c 100644 --- a/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md +++ b/docs/technical/【技术方案】AI游戏创作智能体App实施计划-2026-06-24.md @@ -308,6 +308,7 @@ game-project/ - 终端可用 `npm run ai-game-creator-shell:agent-run -- /绝对项目路径 "游戏创作需求"` 跑一次真实 LLM 生成、落盘、`game.static_smoke` 和本地 HTTP 预览;发布 App 读取 Tauri 应用配置目录中的 `game-creator.config.json`,开发 CLI 无 AppHandle 时才读取仓库旁边的配置模板和 gitignored 本机覆盖文件,不把 API Key 写入仓库或项目文件。自动验证可加 `--no-wait`,例如 `npm run ai-game-creator-shell:agent-run -- --no-wait /tmp/genarrative-ai-game-test "像素风反弹弹幕厨房"`,生成预览 trace 后立即停止本地预览,避免终端卡在回车等待。默认 API kind 为 `openai_responses`;旧 Chat Completions 兼容网关设置 `llm.apiKind` 为 `openai_chat`,Anthropic Messages 网关设置 `llm.apiKind` 为 `anthropic`。真实 OpenAI-compatible 网关建议设置 `llm.stream` 为 `true` 跑 Planner 和 Generator,避免长请求非流式空闲断连。 - 终端可用 `npm run ai-game-creator-shell:agent-run:smoke` 跑一次无密钥本地端到端 smoke:脚本启动本机 OpenAI-compatible SSE 流式测试 provider,预置一个本地上传图片和一个本地上传音频,复用真实 `--agent-run`、Planner / Orchestrator / 角色 agent / Generator / Evaluator loop、本地落盘、`game.static_smoke` 和本地 HTTP 预览,并断言每次 provider 请求都使用 `stream: true`、Planner 与 Generator 分别命中自己的 `agentLlm` provider 配置、provider prompt 收到图片与音频资产上下文以及最近对话上下文、生成 HTML 引用这些资产、预览服务能用 `GET` 读取 `/assets/...`、用 `HEAD` 返回真实资源长度和对应 MIME、headless Chrome 打开预览后至少执行一帧游戏 JS,且通过确定性亮色探针采样证明 canvas 不是空白画布、`.agent/run.latest.json` 的 step group 覆盖 design / balance / art / audio / code / publishing 六组、第二轮会重跑 Evaluator 命中任务及其下游影响任务,未受影响角色 carry-over;随后脚本自动给 CLI 发送回车停止预览。该脚本只用于开发验证,不进入产品生成路径。 - `npm run ai-game-creator-shell:dev` 的 Tauri `devUrl` 固定为 `http://127.0.0.1:3080/`,Vite 必须 `strictPort` 对齐;`beforeDevCommand` 先复用已经跑在 3080 且页面标题为 `AI 游戏创作` 的本 app Vite server,否则才启动新的 Vite,若端口被其它服务占用则直接失败并提示释放端口。 +- AI 游戏创作 App 的 Vite root 保持在 `apps/ai-game-creator-shell`,但开发服务器必须通过 `server.fs.allow: [repoRoot]` 允许加载 `packages/shared/src` 共享契约;配置自检同时守住该规则,避免 typecheck 通过后真实 Tauri WebView 因共享源码 403 变成白屏。Tauri 事件 capability 只向 `client`、`developer`、`main`、`launcher` 窗口开放 `core:event:allow-listen` 和 `core:event:allow-unlisten`;Runtime 事件仍由 Rust 发出,前端不获得 `emit` 权限。 - `.agent/manifest.json` 会保存 6 个专业组下 16 个组内角色任务状态,当前覆盖 `Director`、`Gameplay`、`Difficulty`、`Asset`、`Polish`、`SFX`、`Code`、`Review`、`Preview`、`Playtest`、`Publish`;程序组内显式包含 `quality-review` 质量评审 gate,由 Evaluator trace 标记完成;开发窗口的专业组面板读取 manifest,而不是前端硬编码。 - 主窗口的 agent 状态列表以 manifest 角色任务为底表,再合并最近 run trace 中 `taskGraph.tasks` 的任务状态、同 taskId / group / role 的最新 step 状态、输入输出路径、错误摘要、lifecycleStatus 和 `activeTaskIds` / `carriedTaskIds` / `readyTaskIds` 编排标记;如果 trace 缺失或过期,只展示 manifest 的静态任务状态和“暂无最近运行证据”。 - 共享契约和 `platform-agent` 会按任务依赖与 `completed` 状态计算当前可执行任务,作为 v1 的最小编排选择器;每轮 `Orchestrator` 的 activeTaskIds、carriedTaskIds、repairRoutes 和 dependencyWaves 由 `platform-agent` 纯编排内核产出,`apps/ai-game-creator-shell` 只负责写入 `.agent/passes/pass-N/` 和执行本地工具;`Evaluator` 会在 `.agent/findings.md` 写出 `## Repair Routes` JSON,下一轮编排优先采用该结构化 taskIds,解析不到时才退回关键词路由;返工路由会按任务图自动扩展下游影响任务,例如美术资产变化会继续触发程序预览和运营包装重算。