diff --git a/apps/ai-game-creator-shell/scripts/agent-runtime-deterministic-playable-e2e.mjs b/apps/ai-game-creator-shell/scripts/agent-runtime-deterministic-playable-e2e.mjs index ba8b9b3eb..c6b20f6dd 100644 --- a/apps/ai-game-creator-shell/scripts/agent-runtime-deterministic-playable-e2e.mjs +++ b/apps/ai-game-creator-shell/scripts/agent-runtime-deterministic-playable-e2e.mjs @@ -1948,6 +1948,7 @@ async function runE2e(options) { ...process.env, NO_COLOR: '1', [platformSessionFixtureEnv]: fixturePath, + GENARRATIVE_AGC_DEBUG_PROVIDER_E2E: '1', }), ); childReport = parseChildReport(childResult); diff --git a/apps/ai-game-creator-shell/scripts/agent-runtime-real-e2e/harness/app-data.mjs b/apps/ai-game-creator-shell/scripts/agent-runtime-real-e2e/harness/app-data.mjs index f283ecf8e..3d8e052c6 100644 --- a/apps/ai-game-creator-shell/scripts/agent-runtime-real-e2e/harness/app-data.mjs +++ b/apps/ai-game-creator-shell/scripts/agent-runtime-real-e2e/harness/app-data.mjs @@ -773,7 +773,8 @@ export async function prepareIsolatedSuiteAppData({ isScopedAgentsSuite() || isProjectSkillSuite() || isParallelReadSuite() || - isSupervisorSwarmSuite() + isSupervisorSwarmSuite() || + isSupervisorAutonomousPlayableLaneDefenseSuite() ? 'private-copy' : 'hardlink'; try { @@ -796,7 +797,7 @@ export async function prepareIsolatedSuiteAppData({ storageMode === 'private-copy' && (linkedMetadata.dev !== source.metadata.dev || linkedMetadata.ino !== source.metadata.ino) && - (linkedMetadata.mode & 0o077) === 0; + (process.platform === 'win32' || (linkedMetadata.mode & 0o077) === 0); const hardlinkValid = storageMode === 'hardlink' && linkedMetadata.dev === source.metadata.dev && @@ -1976,7 +1977,7 @@ export async function verifyIsolatedSuiteConfigLinksUnchanged() { linkedMetadata.ino === link.linkedIno && (linkedMetadata.dev !== sourceMetadata.dev || linkedMetadata.ino !== sourceMetadata.ino) && - (linkedMetadata.mode & 0o077) === 0 + (process.platform === 'win32' || (linkedMetadata.mode & 0o077) === 0) : linkedMetadata.dev === link.dev && linkedMetadata.ino === link.ino; const sourceMetadataStable = sourceMetadata.mode === link.sourceMode && diff --git a/apps/ai-game-creator-shell/src-tauri/src/config.rs b/apps/ai-game-creator-shell/src-tauri/src/config.rs index 86f74f3e7..93aa0efe2 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/config.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/config.rs @@ -3446,18 +3446,33 @@ pub(crate) fn migrate_legacy_game_creator_agent_mode(path: &Path) -> Result<(), /// Returns whether a real AGC build must use the authenticated API Server /// proxy instead of any persisted provider credentials. /// -/// Debug and release binaries intentionally share this decision. The only -/// exception is the Rust unit-test build, where existing tests may install an -/// explicit loopback provider fixture; that fixture is never compiled into a -/// shipped binary and is not a runtime fallback. +/// Debug and release binaries intentionally share this decision. The two +/// exceptions are the Rust unit-test build and the explicitly env-gated debug +/// deterministic-provider E2E; their loopback fixtures are never compiled into +/// or enabled inside a shipped release binary. pub(crate) fn game_creator_official_llm_route_locked() -> bool { - game_creator_official_llm_route_locked_for_build(cfg!(test)) + !debug_provider_e2e_route_unlocked() + && game_creator_official_llm_route_locked_for_build(cfg!(test)) } pub(crate) fn game_creator_official_llm_route_locked_for_build(is_test_build: bool) -> bool { !is_test_build } +fn debug_provider_e2e_route_unlocked() -> bool { + debug_provider_e2e_route_unlocked_for_build( + cfg!(debug_assertions), + std::env::var_os("GENARRATIVE_AGC_DEBUG_PROVIDER_E2E").as_deref(), + ) +} + +pub(crate) fn debug_provider_e2e_route_unlocked_for_build( + debug_assertions: bool, + value: Option<&std::ffi::OsStr>, +) -> bool { + debug_assertions && value == Some(std::ffi::OsStr::new("1")) +} + pub(crate) fn lock_game_creator_app_config_to_official_route(config: &mut GameCreatorAppConfig) { if !game_creator_official_llm_route_locked() { return; diff --git a/apps/ai-game-creator-shell/src-tauri/src/main.rs b/apps/ai-game-creator-shell/src-tauri/src/main.rs index 53530b4a4..12a7e65a7 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/main.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/main.rs @@ -2316,7 +2316,7 @@ fn main() { app_log!("agent.runner.failed: {error}"); std::process::exit(1); } - if command.requires_external_agent_runner() { + if command.requires_external_agent_runner() || command.is_read_only_status() { let configured = if command.is_read_only_status() { configure_external_agent_runner_read_only(&config_dir) } else { diff --git a/apps/ai-game-creator-shell/src-tauri/src/tests/configuration.rs b/apps/ai-game-creator-shell/src-tauri/src/tests/configuration.rs index b797683fe..aebc0ea4d 100644 --- a/apps/ai-game-creator-shell/src-tauri/src/tests/configuration.rs +++ b/apps/ai-game-creator-shell/src-tauri/src/tests/configuration.rs @@ -330,6 +330,23 @@ fn official_llm_route_is_locked_for_debug_and_release_platform_builds() { assert!(!game_creator_official_llm_route_locked_for_build(true)); } +#[test] +fn debug_provider_e2e_flag_only_unlocks_debug_platform_build() { + assert!(debug_provider_e2e_route_unlocked_for_build( + true, + Some(std::ffi::OsStr::new("1")) + )); + assert!(!debug_provider_e2e_route_unlocked_for_build( + false, + Some(std::ffi::OsStr::new("1")) + )); + assert!(!debug_provider_e2e_route_unlocked_for_build( + true, + Some(std::ffi::OsStr::new("0")) + )); + assert!(!debug_provider_e2e_route_unlocked_for_build(true, None)); +} + #[test] fn codex_app_server_requires_responses_route_and_disables_native_web_search() { let mut llm = GameCreatorLlmConfig::default();