diff --git a/UPSTREAM.md b/UPSTREAM.md index 2dceb2e0d1..81ea5b1797 100644 --- a/UPSTREAM.md +++ b/UPSTREAM.md @@ -1102,6 +1102,18 @@ presentation comes from a Scient hook (its import and its call), so a sign-in st as starting from the click, and a failed sign-in or setup takes the error status dot. See [provider lifecycle](docs/internals/provider-lifecycle.md#opening-sign-in-pages). +One marked seam in `packages/provider-acp/src/server/AcpSessionRuntime.ts` keeps an agent that owns +its process tree attached on Windows: `ownDetachedProcessGroup` spawns detached only off Windows, +where `taskkill /T` already stops the tree. A detached agent has no console, so every console +program it starts opens a visible window; Antigravity's own inner process is one. This is an +upstream bug (T3's Grok uses the same path) worth proposing. In Scient's retained +`AntigravityInstallation.ts`, a runtime check that runs out of time reports that instead of the +install's catch-all disk-space advice. +The install check, model refresh (`AntigravityDriver.ts`) and sign-out (`AntigravityAuth.ts`) +allow 5 minutes instead of T3's 90 seconds, each in a marked line: the +official Windows agent unpacks about 7,300 files (320 MiB) into a fresh folder on every start, which +took about 35 s on a development machine and can exceed 90 s on slower disks. + Antigravity reasoning presentation is a narrow client-side divergence. The shared `packages/client-runtime/src/antigravityModelPresentation.ts` groups recognized Google Gemini effort variants for the existing model and reasoning controls. diff --git a/apps/server/src/provider/AntigravityAuth.test.ts b/apps/server/src/provider/AntigravityAuth.test.ts index be6d61557e..0d62269aec 100644 --- a/apps/server/src/provider/AntigravityAuth.test.ts +++ b/apps/server/src/provider/AntigravityAuth.test.ts @@ -780,7 +780,7 @@ it.layer(NodeServices.layer)("AntigravityAuth", (it) => { .logout(Effect.void) .pipe(Effect.exit, Effect.forkScoped); yield* Deferred.await(entered); - yield* TestClock.adjust("90 seconds"); + yield* TestClock.adjust("5 minutes"); assert.isTrue(Exit.isFailure(yield* Fiber.join(logout))); yield* Deferred.await(harness.closed); assert.notInclude(harness.events, "logout"); diff --git a/apps/server/src/provider/AntigravityAuth.ts b/apps/server/src/provider/AntigravityAuth.ts index af50b1f0b0..0c2ee35a24 100644 --- a/apps/server/src/provider/AntigravityAuth.ts +++ b/apps/server/src/provider/AntigravityAuth.ts @@ -501,7 +501,9 @@ export const makeAntigravityAuth = Effect.fn("makeAntigravityAuth")(function* < }).pipe( Effect.scoped, Effect.timeoutOrElse({ - duration: "90 seconds", + // SCIENT-FORK:START — Antigravity unpacks itself (~320 MiB) on every start; slow disks need minutes. + duration: "5 minutes", + // SCIENT-FORK:END orElse: () => Effect.fail(setupError("logout", "Antigravity sign-out timed out.")), }), ), diff --git a/apps/server/src/provider/AntigravityInstallation.test.ts b/apps/server/src/provider/AntigravityInstallation.test.ts index fe957ec96f..5caecef955 100644 --- a/apps/server/src/provider/AntigravityInstallation.test.ts +++ b/apps/server/src/provider/AntigravityInstallation.test.ts @@ -546,6 +546,15 @@ it.layer(NodeServices.layer)("Antigravity installation", (it) => { cancel: true, valid: false, }, + { + name: "a Windows ARM verification that runs out of time with locked child processes", + platform: "win32" as const, + arch: "arm64" as const, + agentName: "antigravity-acp", + version: "fixture-new", + timeout: true, + valid: false, + }, ].flatMap((testCase) => { const cleanupErrorTags = testCase.platform === "win32" @@ -622,7 +631,9 @@ it.layer(NodeServices.layer)("Antigravity installation", (it) => { Effect.asVoid, ); if (!helper) { - expect(command.options.detached).toBe(true); + // The real host decides, not the simulated platform: Windows owns the + // tree with taskkill, and detaching there would show a console. + expect(command.options.detached).toBe(hostPlatform !== "win32"); stopNative = terminate; } yield* Effect.addFinalizer(() => @@ -652,7 +663,7 @@ it.layer(NodeServices.layer)("Antigravity installation", (it) => { Effect.orDie, ); methods.push(request.method); - if (testCase.cancel) { + if (testCase.cancel || testCase.timeout) { yield* Deferred.succeed(initializationStarted, undefined); return; } @@ -740,6 +751,10 @@ it.layer(NodeServices.layer)("Antigravity installation", (it) => { Effect.forkChild, ) : undefined; + if (testCase.timeout) { + yield* Deferred.await(initializationStarted); + yield* TestClock.adjust("5 minutes"); + } if (platform === "win32") { yield* Effect.raceFirst( Deferred.await(cleanupRetryStarted).pipe(Effect.andThen(TestClock.adjust("100 millis"))), @@ -750,6 +765,11 @@ it.layer(NodeServices.layer)("Antigravity installation", (it) => { expect((yield* terminalState(installation)).phase).toBe( testCase.cancel ? "cancelled" : testCase.valid ? "succeeded" : "failed", ); + if (testCase.timeout) { + expect((yield* terminalState(installation)).message).toBe( + "Antigravity didn't finish starting within 5 minutes while Scient was checking it. Starting it can take a while on some computers. Try again.", + ); + } yield* Deferred.await(stagingReleased); expect(methods).toEqual(["initialize"]); expect(closedRuntimes).toBe(1); diff --git a/apps/server/src/provider/AntigravityInstallation.ts b/apps/server/src/provider/AntigravityInstallation.ts index 15b3c9098a..a4e1ec0ea8 100644 --- a/apps/server/src/provider/AntigravityInstallation.ts +++ b/apps/server/src/provider/AntigravityInstallation.ts @@ -47,7 +47,9 @@ import { const DRIVER = ProviderDriverKind.make("antigravity"); const DOWNLOAD_TIMEOUT = "45 minutes"; -const VALIDATION_TIMEOUT = "90 seconds"; +// SCIENT-FORK:START — Antigravity unpacks itself (~320 MiB) on every start; slow disks need minutes. +const VALIDATION_TIMEOUT = "5 minutes"; +// SCIENT-FORK:END const FREE_SPACE_MARGIN = 256 * 1024 * 1024; const RECORD_MAX_BYTES = 8 * 1024; const RELEASE_RECORD = ".install-complete.json"; @@ -151,6 +153,20 @@ const installationError = (operation: string, detail: string, cause?: unknown) = const wrapFailure = (operation: string, detail: string) => (cause: unknown) => isInstallationError(cause) ? cause : installationError(operation, detail, cause); +// SCIENT-FORK:START — a check that runs out of time says so, instead of the +// install's catch-all advice to check disk space. +const validationTimeout = Effect.timeoutOrElse({ + duration: VALIDATION_TIMEOUT, + orElse: () => + Effect.fail( + installationError( + "verify", + `Antigravity didn't finish starting within ${VALIDATION_TIMEOUT} while Scient was checking it. Starting it can take a while on some computers. Try again.`, + ), + ), +}); +// SCIENT-FORK:END + function executableNames(platform: NodeJS.Platform) { return platform === "win32" ? { executable: "agy_acp_server.exe", harness: "localharness_external.exe" } @@ -712,7 +728,12 @@ export const makeAntigravityInstallation = Effect.fn("AntigravityInstallation.ma managedVersionDirectory: pairDirectory, }, asset.version, - ).pipe(Effect.scoped, Effect.timeout(VALIDATION_TIMEOUT)); + ).pipe( + Effect.scoped, + // SCIENT-FORK:START + validationTimeout, + // SCIENT-FORK:END + ); const record: InstalledRelease = { releaseId: asset.sha256, version: asset.version, diff --git a/apps/server/src/provider/Drivers/AntigravityDriver.test.ts b/apps/server/src/provider/Drivers/AntigravityDriver.test.ts index 73802d218a..7416570711 100644 --- a/apps/server/src/provider/Drivers/AntigravityDriver.test.ts +++ b/apps/server/src/provider/Drivers/AntigravityDriver.test.ts @@ -847,7 +847,7 @@ it.layer(testLayer)("AntigravityDriver", (it) => { yield* Deferred.await(spawned); expect(nativeLaunches(h)).toHaveLength(2); expect(yield* nativeLaunches(h)[1]!.handle.isRunning).toBe(true); - yield* TestClock.adjust("90 seconds"); + yield* TestClock.adjust("5 minutes"); expect(Exit.isFailure(yield* Fiber.join(logout))).toBe(true); yield* assertProcessesClosed(h, oldLaunches); yield* assertProcessesClosed(h); diff --git a/apps/server/src/provider/Drivers/AntigravityDriver.ts b/apps/server/src/provider/Drivers/AntigravityDriver.ts index eadff9e770..e461d806a8 100644 --- a/apps/server/src/provider/Drivers/AntigravityDriver.ts +++ b/apps/server/src/provider/Drivers/AntigravityDriver.ts @@ -533,7 +533,9 @@ export const AntigravityDriver: ScientProviderDriver< }, Effect.scoped, Effect.timeoutOrElse({ - duration: "90 seconds", + // SCIENT-FORK:START — Antigravity unpacks itself (~320 MiB) on every start; slow disks need minutes. + duration: "5 minutes", + // SCIENT-FORK:END orElse: () => Effect.fail( new ProviderDriverError({ diff --git a/docs/user/providers-antigravity.md b/docs/user/providers-antigravity.md index f35513a899..965e691255 100644 --- a/docs/user/providers-antigravity.md +++ b/docs/user/providers-antigravity.md @@ -191,7 +191,7 @@ longer want that credential method available. ## Troubleshooting -Health checks, model refresh, and sign-out allow up to 90 seconds for the official +Installation checks, model refresh, and sign-out allow up to 5 minutes for the official runtime to start, which can be slow on some computers. Explicit refresh uses saved credentials and does not launch a login page. Automatic checks verify installation only. Google controls account eligibility and limits; Scient does not silently diff --git a/packages/provider-acp/src/server/AcpSessionRuntime.ts b/packages/provider-acp/src/server/AcpSessionRuntime.ts index cbc012dd3c..701cc167ca 100644 --- a/packages/provider-acp/src/server/AcpSessionRuntime.ts +++ b/packages/provider-acp/src/server/AcpSessionRuntime.ts @@ -1554,9 +1554,17 @@ export const make = ( ...(options.spawn.cwd ? { cwd: options.spawn.cwd } : {}), ...(spawnEnvironment ? { env: spawnEnvironment } : {}), extendEnv: options.spawn.extendEnv ?? true, + // SCIENT-FORK:START — Windows owns the tree with taskkill /T, not a group. + // A detached agent has no console, so every console program it starts + // (Antigravity's own inner process included) opens a visible window. + // The host decides, not the teardown platform a test may simulate. ...(options.ownDetachedProcessGroup === undefined ? {} - : { detached: options.ownDetachedProcessGroup }), + : { + detached: + options.ownDetachedProcessGroup && (yield* HostProcess.Platform) !== "win32", + }), + // SCIENT-FORK:END shell: containedSpawnCommand.shell, }), )