合并 GameAgent V1 UI 分支
引入游戏创作工作台与资源预览界面 同步 UI 原型生成和视觉验收约束 # Conflicts: # apps/ai-game-creator-shell/src/App.tsx # docs/README.md # docs/project-memory/shared-memory/decision-log.md # server-rs/crates/api-server/src/editor_project.rs
This commit is contained in:
@@ -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'),
|
||||
);
|
||||
@@ -1918,8 +1926,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');
|
||||
@@ -1944,7 +1952,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 ||
|
||||
@@ -1956,26 +1964,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())?;',
|
||||
|
||||
Reference in New Issue
Block a user