diff --git a/apps/ai-game-creator-shell/scripts/check-package-layout.mjs b/apps/ai-game-creator-shell/scripts/check-package-layout.mjs index 90dd0ce92..b90209878 100755 --- a/apps/ai-game-creator-shell/scripts/check-package-layout.mjs +++ b/apps/ai-game-creator-shell/scripts/check-package-layout.mjs @@ -453,7 +453,7 @@ function renderGenerated(declaration) { return `// @generated by apps/ai-game-creator-shell/scripts/check-package-layout.mjs // 来源:build_support/package-layout.json。不要手工编辑本文件。 // 修改随包资源布局请编辑声明文件,然后运行 -// npm run agc:package-layout:sync(在仓库根目录) +// npm run agc:bundled-resources:sync(在仓库根目录) // 门禁会校验两者一致(npm run agc:typecheck 链内含 check-package-layout.mjs)。 pub const DECLARATION_SCHEMA: &str = ${rustString(EXPECTED_SCHEMA)}; @@ -615,7 +615,7 @@ function main() { `随包资源声明与 Rust 常量不一致:`, ` 声明:${path.relative(process.cwd(), DECLARATION_PATH)}`, ` 生成:${path.relative(process.cwd(), GENERATED_PATH)}`, - '请运行:npm run agc:package-layout:sync', + '请运行:npm run agc:bundled-resources:sync', ].join('\n'), ); process.exit(1); diff --git a/apps/ai-game-creator-shell/scripts/prepare-bundled-resources.mjs b/apps/ai-game-creator-shell/scripts/prepare-bundled-resources.mjs index 9ec3828ac..674e668e4 100755 --- a/apps/ai-game-creator-shell/scripts/prepare-bundled-resources.mjs +++ b/apps/ai-game-creator-shell/scripts/prepare-bundled-resources.mjs @@ -660,8 +660,8 @@ function pluginSourceFingerprint(declaration, plugins, target, features) { for (const plugin of plugins) { for (const subdirectory of declaration.plugins.subdirectories) { if ( - subdirectoryAppliesToPlugin(subdirectory, plugin.name) || - subdirectoryEnabled(subdirectory, target, features) + !subdirectoryAppliesToPlugin(subdirectory, plugin.name) || + !subdirectoryEnabled(subdirectory, target, features) ) { continue; } @@ -747,10 +747,7 @@ function pluginTreeMatches( return false; } for (const subdirectory of declaration.plugins.subdirectories) { - if ( - !subdirectoryAppliesToPlugin(subdirectory, plugin.name) || - !subdirectoryEnabled(subdirectory, target, features) - ) { + if (!subdirectoryAppliesToPlugin(subdirectory, plugin.name)) { continue; } const stagedDirectory = path.join(pluginDestination, subdirectory.path); @@ -763,10 +760,7 @@ function pluginTreeMatches( } const sourceRoot = path.join(plugin.root, subdirectory.path); if (subdirectory.origin !== 'source') { - if ( - existsSync(sourceRoot) && - !existsSync(path.join(pluginDestination, subdirectory.path)) - ) { + if (existsSync(sourceRoot) && !existsSync(stagedDirectory)) { return false; } continue; @@ -1053,6 +1047,21 @@ function copyPreparedPayloads({ } } +/// 内容一致时不重写(保住时间戳与「命中缓存零写入」口径)。 +function copyFilePreservingModeIfChanged(source, destination) { + if (existsSync(destination)) { + const sourceInfo = statSync(source); + const destinationInfo = statSync(destination); + if ( + sourceInfo.size === destinationInfo.size && + Buffer.compare(readFileSync(source), readFileSync(destination)) === 0 + ) { + return; + } + } + copyFilePreservingMode(source, destination); +} + /// Cocos bridge 的 dll 既要进插件工作区(唯一真源),也要进随包目录。 function copyNativePayloads({ declaration, @@ -1100,7 +1109,7 @@ function copyNativePayloads({ } const destinationName = payload.destinationFileName ?? payload.sourceFileName; - copyFilePreservingMode( + copyFilePreservingModeIfChanged( source, path.join( repoRoot, @@ -1110,7 +1119,7 @@ function copyNativePayloads({ destinationName, ), ); - copyFilePreservingMode( + copyFilePreservingModeIfChanged( source, path.join( staging, diff --git a/apps/ai-game-creator-shell/src-tauri/build_support/package_layout.rs b/apps/ai-game-creator-shell/src-tauri/build_support/package_layout.rs index 8c8732039..f7de69dcd 100644 --- a/apps/ai-game-creator-shell/src-tauri/build_support/package_layout.rs +++ b/apps/ai-game-creator-shell/src-tauri/build_support/package_layout.rs @@ -280,7 +280,15 @@ pub fn validate_staged_plugins( if !staged_manifest.is_file() { return Err(format!("随包插件缺少清单:{}", staged_manifest.display())); } - if sha256_file(&source_manifest).ok() != sha256_file(&staged_manifest).ok() { + let source_manifest_digest = sha256_file(&source_manifest) + .map_err(|error| format!("读取插件清单失败 {}:{error}", source_manifest.display()))?; + let staged_manifest_digest = sha256_file(&staged_manifest).map_err(|error| { + format!( + "读取随包插件清单失败 {}:{error}", + staged_manifest.display() + ) + })?; + if source_manifest_digest != staged_manifest_digest { return Err(format!( "随包插件清单与源码不一致:{}", staged_manifest.display() @@ -319,7 +327,13 @@ pub fn validate_staged_plugins( if !staged_file.is_file() { return Err(format!("随包插件缺少文件:{}", staged_file.display())); } - if sha256_file(&source_file).ok() != sha256_file(&staged_file).ok() { + let source_digest = sha256_file(&source_file).map_err(|error| { + format!("读取插件文件失败 {}:{error}", source_file.display()) + })?; + let staged_digest = sha256_file(&staged_file).map_err(|error| { + format!("读取随包插件文件失败 {}:{error}", staged_file.display()) + })?; + if source_digest != staged_digest { return Err(format!( "随包插件文件与源码不一致:{}", staged_file.display() diff --git a/apps/ai-game-creator-shell/src-tauri/resources/cocos-editor-bridge/.gitignore b/apps/ai-game-creator-shell/src-tauri/resources/cocos-editor-bridge/.gitignore deleted file mode 100644 index 6a7461313..000000000 --- a/apps/ai-game-creator-shell/src-tauri/resources/cocos-editor-bridge/.gitignore +++ /dev/null @@ -1 +0,0 @@ -*.dll diff --git a/apps/ai-game-creator-shell/src-tauri/resources/cocos-editor-bridge/.gitkeep b/apps/ai-game-creator-shell/src-tauri/resources/cocos-editor-bridge/.gitkeep deleted file mode 100644 index e69de29bb..000000000 diff --git a/package.json b/package.json index 2c852e22f..250192b8f 100644 --- a/package.json +++ b/package.json @@ -170,8 +170,8 @@ "agc:skill-pack:sync": "npm --prefix apps/ai-game-creator-shell run skill-pack:sync", "agc:bundled-resources:check": "npm --prefix apps/ai-game-creator-shell run bundled-resources:check", "agc:bundled-resources:sync": "npm --prefix apps/ai-game-creator-shell run bundled-resources:sync", - "agc:bundled-resources:prepare": "npm --prefix apps/ai-game-creator-shell run bundled-resources:prepare", - "agc:bundled-resources:test": "npm --prefix apps/ai-game-creator-shell run bundled-resources:test", + "agc:bundled-resources:prepare": "npm --prefix apps/ai-game-creator-shell run bundled-resources:prepare --", + "agc:bundled-resources:test": "npm --prefix apps/ai-game-creator-shell run bundled-resources:test --", "agc:plugins:test": "node --test plugins/agc-cocos-editor/src/entry.test.mjs plugins/agc-unity-editor/src/entry.test.mjs plugins/agc-godot-editor/src/entry.test.mjs", "agc:plugins:native-test": "cargo test --manifest-path plugins/agc-cocos-editor/native/cocos-editor-bridge/Cargo.toml && cargo test --locked --manifest-path plugins/agc-unity-editor/native/unity-editor-bridge/Cargo.toml && cargo test --locked --manifest-path plugins/agc-godot-editor/native/godot-editor-bridge/Cargo.toml", "agc:plugins:check": "npm run agc:plugins:test && npm run agc:plugins:native-test",