完善游戏创作工作台与智能体恢复闭环

实现横屏项目开发工作台、资源画布、Supervisor 对话与专业 Agent 状态展示

修复总控和专业 Agent 重试、Runner 接管、历史成果跨 Run 持久展示及确认流程

补齐画板图片产物合同、客户端内预览、共享契约与安全边界

新增完整回归测试、工作台 PRD、技术方案与待解决事项
This commit is contained in:
AIGameCreator App
2026-07-20 19:48:05 +08:00
parent 29228afb9e
commit 3a8dff1404
35 changed files with 10982 additions and 614 deletions
+42 -15
View File
@@ -26,6 +26,14 @@ const aiGameCreatorShellAppSource = fs.readFileSync(
'apps/ai-game-creator-shell/src/App.tsx',
'utf8',
);
const aiGameCreatorProjectDevelopmentSource = fs.readFileSync(
'apps/ai-game-creator-shell/src/view/project-development/index.tsx',
'utf8',
);
const aiGameCreatorPreviewRustSource = fs.readFileSync(
'apps/ai-game-creator-shell/src-tauri/src/preview.rs',
'utf8',
);
const aiGameCreatorShellTauriConfig = JSON.parse(
fs.readFileSync('apps/ai-game-creator-shell/src-tauri/tauri.conf.json', 'utf8'),
);
@@ -1972,8 +1980,8 @@ function assertAiGameCreatorShellUserDevBoundary() {
.split(';')
.map((directive) => directive.trim())
.find((directive) => directive.startsWith('frame-src ')) ?? '';
if (releaseFrameSrc.includes('http://127.0.0.1:*')) {
throw new Error('AI game creator release shell must not allow embedded local preview frames');
if (!releaseFrameSrc.includes('http://127.0.0.1:*')) {
throw new Error('AI game creator release shell must allow the client-local preview frame');
}
if (!devFrameSrc.includes('http://127.0.0.1:*')) {
throw new Error('AI game creator dev shell must keep local preview iframe access for the developer window');
@@ -1998,7 +2006,7 @@ function assertAiGameCreatorShellUserDevBoundary() {
const devModeBranchIndex = aiGameCreatorShellAppSource.indexOf('{devMode ? (');
const developerPaneIndex = aiGameCreatorShellAppSource.indexOf('className="developer-pane"');
if (previewFrameIndexes.length !== 1) {
throw new Error('AI game creator user shell must not embed game preview frames');
throw new Error('AI game creator developer pane preview frame count drifted');
}
if (
devModeBranchIndex < 0 ||
@@ -2010,26 +2018,45 @@ function assertAiGameCreatorShellUserDevBoundary() {
throw new Error('AI game creator preview iframe must stay inside the dev-only pane');
}
const clientPreviewFrameCount = [
...aiGameCreatorProjectDevelopmentSource.matchAll(/<iframe\b/g),
].length;
if (clientPreviewFrameCount !== 1) {
throw new Error('AI game creator client workbench must own exactly one local preview frame');
}
for (const snippet of [
'async function openPreviewInExternalBrowser(',
"await invoke<LocalPreviewStatus>('open_local_game_preview'",
"return '已交给外部浏览器打开。';",
'const openMessage = await openPreviewInExternalBrowser(',
"appendLocalPermissionLog(\n openedProject.projectPath,\n 'permission.confirm',\n 'project.create',",
'function resolveEmbeddedPreviewUrl(',
"url.protocol !== 'http:' || url.hostname !== '127.0.0.1'",
'sandbox="allow-scripts allow-same-origin allow-forms allow-pointer-lock"',
'src={embeddedPreviewUrl}',
]) {
if (!aiGameCreatorShellAppSource.includes(snippet)) {
throw new Error(`AI game creator external preview boundary drifted: missing ${snippet}`);
if (!aiGameCreatorProjectDevelopmentSource.includes(snippet)) {
throw new Error(`AI game creator embedded preview boundary drifted: missing ${snippet}`);
}
}
for (const snippet of [
'fn open_local_game_preview(',
'.open_url(&url, None::<&str>)',
"await invoke<LocalPreviewStatus>(\n 'activate_local_game_preview'",
'已切换到客户端运行视图',
]) {
if (!aiGameCreatorShellTauriSource.includes(snippet)) {
throw new Error(`AI game creator external preview boundary drifted: missing ${snippet}`);
if (!aiGameCreatorShellAppSource.includes(snippet)) {
throw new Error(`AI game creator client preview activation drifted: missing ${snippet}`);
}
}
for (const snippet of [
'fn activate_local_game_preview(',
'preview_open_url(&status)?;',
]) {
if (!aiGameCreatorPreviewRustSource.includes(snippet)) {
throw new Error(`AI game creator client preview command drifted: missing ${snippet}`);
}
}
if (
aiGameCreatorShellAppSource.includes('openPreviewInExternalBrowser') ||
aiGameCreatorShellAppSource.includes('open_local_game_preview') ||
aiGameCreatorPreviewRustSource.includes('.open_url(&url')
) {
throw new Error('AI game creator preview must not invoke the external browser');
}
for (const snippet of [
'#[cfg(all(debug_assertions, not(test)))]\npub(crate) fn open_developer_window(',
'#[cfg(all(debug_assertions, not(test)))]\n open_developer_window(app.handle())?;',