From 19197a10431785db621a8ec44cd857a53b83b64a Mon Sep 17 00:00:00 2001 From: Trevor Walker Date: Wed, 30 Sep 2026 10:19:04 -0600 Subject: [PATCH] chore: clear Effect language service suggestions across Pylon's tree Applies the mechanical rewrites behind upstream 568c9bc4d0ef0dddf74d813619c9877bd35624d7 (#13536) to Pylon's own sources. --- .../src/app/DesktopAppIdentity.test.ts | 2 +- .../app/DesktopConnectionCatalogStore.test.ts | 2 +- .../src/app/DesktopConnectionCatalogStore.ts | 2 +- .../src/app/DesktopLinuxUrlHandler.test.ts | 2 +- .../backend/DesktopBackendConfiguration.ts | 4 +- .../src/backend/DesktopBackendManager.test.ts | 6 +- .../src/backend/DesktopBackendPool.test.ts | 9 +- .../DesktopLocalEnvironmentAuth.test.ts | 3 +- apps/desktop/src/electron/ElectronMenu.ts | 2 +- .../src/electron/ElectronShell.test.ts | 5 +- apps/desktop/src/ipc/methods/snapShot.test.ts | 28 +-- .../desktop/src/ipc/methods/sshEnvironment.ts | 12 +- apps/desktop/src/ipc/methods/window.test.ts | 26 +- apps/desktop/src/ipc/methods/wsl.test.ts | 3 +- .../src/preview/BrowserImport/ChromiumKeys.ts | 4 +- apps/desktop/src/preview/BrowserSession.ts | 12 +- apps/desktop/src/preview/Manager.ts | 53 ++--- .../settings/DesktopClientSettings.test.ts | 4 +- .../src/settings/DesktopClientSettings.ts | 2 +- .../settings/DesktopSavedEnvironments.test.ts | 2 +- apps/desktop/src/snapShot/DesktopSnapShot.ts | 13 +- .../src/ssh/DesktopSshPasswordPrompts.test.ts | 7 +- .../telemetry/DesktopTelemetryPublisher.ts | 13 +- .../desktop/src/updates/updatesTestHarness.ts | 10 +- .../src/window/DesktopApplicationMenu.test.ts | 7 +- apps/desktop/src/window/DesktopWindow.test.ts | 6 +- apps/desktop/src/wsl/DesktopWslBackend.ts | 4 +- apps/desktop/src/wsl/DesktopWslEnvironment.ts | 6 +- ...ProviderSessionStartup.integration.test.ts | 2 +- apps/server/scripts/migrate-dev-db.ts | 4 +- apps/server/scripts/t3-sqlite-state.ts | 4 +- apps/server/src/assets/AssetAccess.ts | 6 +- .../src/assets/NativeAppIconResolver.ts | 4 +- .../server/src/auth/PairingGrantStore.test.ts | 5 +- apps/server/src/auth/ServerSecretStore.ts | 2 +- apps/server/src/auth/dpop.ts | 2 +- .../checkpointing/CheckpointDiffQuery.test.ts | 70 +++--- apps/server/src/cli/theme.ts | 37 ++- .../src/cloud/ManagedEndpointRuntime.test.ts | 3 +- apps/server/src/cloud/http.test.ts | 4 +- apps/server/src/cloud/http.ts | 6 +- apps/server/src/cloud/selfUpdate.test.ts | 2 +- .../src/desktopUpdate/DesktopAppUpdate.ts | 2 +- apps/server/src/device/DeviceHubProxy.ts | 2 +- apps/server/src/device/DeviceService.ts | 12 +- apps/server/src/device/LocalDeviceHost.ts | 4 +- .../src/environment/ServerEnvironment.test.ts | 3 +- .../src/environment/ServerEnvironment.ts | 13 +- .../src/environment/ServerEnvironmentLabel.ts | 2 +- .../environment/ServerEnvironmentMachine.ts | 4 +- apps/server/src/git/GitManager.ts | 2 +- .../src/git/linkCreatedPullRequest.test.ts | 2 +- apps/server/src/keybindings.test.ts | 6 +- apps/server/src/mcp/McpHttpServer.test.ts | 3 +- apps/server/src/mcp/McpInvocationContext.ts | 14 +- apps/server/src/mcp/McpSessionRegistry.ts | 2 +- .../src/mcp/toolkits/preview/handlers.ts | 11 +- .../Layers/CheckpointReactor.test.ts | 2 +- .../orchestration/Layers/CheckpointReactor.ts | 75 +++--- .../Layers/OrchestrationEngine.test.ts | 16 +- .../Layers/OrchestrationEngine.ts | 2 +- .../Layers/ProjectionPipeline.ts | 1 + .../Layers/ProviderCommandReactor.ts | 67 +++--- .../Layers/ProviderRuntimeIngestion.ts | 21 +- .../Layers/RollbackAdmissionAtomic.test.ts | 72 +++--- .../Layers/ThreadDeletionReactor.ts | 36 ++- .../orchestration/ProjectSettingsReactor.ts | 12 +- .../orchestration/PullRequestSyncReactor.ts | 12 +- .../orchestration/ThreadPullRequestReactor.ts | 60 ++--- .../orchestration/ThreadSettlementReactor.ts | 40 ++-- .../src/orchestration/commandInvariants.ts | 32 ++- apps/server/src/orchestration/decider.ts | 70 +++--- .../src/orchestration/workflowScriptQuery.ts | 21 +- .../src/persistence/AuthPairingLinks.ts | 8 +- apps/server/src/persistence/AuthSessions.ts | 2 +- .../Layers/ProjectionCheckpoints.ts | 4 +- .../src/persistence/Layers/ProjectionTurns.ts | 5 +- .../src/persistence/ProviderSessionRuntime.ts | 6 +- .../src/project/AgentSessionImporter.test.ts | 6 +- .../server/src/project/AgentSessionScanner.ts | 2 +- .../src/project/ProjectFaviconResolver.ts | 4 +- .../src/project/RepositoryIdentityResolver.ts | 2 +- .../server/src/project/T3ProjectFileLoader.ts | 4 +- .../src/provider/AntigravityInstallation.ts | 2 +- .../src/provider/Drivers/AntigravityDriver.ts | 2 +- .../src/provider/Drivers/AntigravitySkills.ts | 2 +- .../src/provider/Drivers/CodexDriver.ts | 36 ++- .../src/provider/Layers/AntigravityAdapter.ts | 6 +- .../provider/Layers/AntigravityProvider.ts | 4 +- .../src/provider/Layers/ClaudeAdapter.test.ts | 1 + .../src/provider/Layers/ClaudeAdapter.ts | 2 +- .../src/provider/Layers/ClaudeProvider.ts | 2 +- .../src/provider/Layers/CodexAdapter.test.ts | 10 +- .../provider/Layers/CodexSessionRuntime.ts | 2 +- .../server/src/provider/Layers/GrokAdapter.ts | 75 +++--- .../provider/Layers/OpenCodeAdapter.test.ts | 2 +- .../src/provider/Layers/OpenCodeAdapter.ts | 13 +- .../provider/Layers/ProviderService.test.ts | 12 +- .../src/provider/Layers/ProviderService.ts | 18 +- .../Layers/ProviderSessionDirectory.ts | 4 +- .../src/provider/Layers/cursorUsageLimits.ts | 14 +- .../src/provider/Layers/grokUsageLimits.ts | 2 +- apps/server/src/provider/ModelManifest.ts | 2 +- .../src/provider/ProviderLoginSessions.ts | 4 +- .../src/provider/acp/AcpSessionRuntime.ts | 42 ++-- .../src/provider/antigravityAuthSupport.ts | 5 +- apps/server/src/provider/claudeOAuthUsage.ts | 6 +- .../src/provider/codexAccountIdentity.ts | 2 +- .../src/provider/makeManagedServerProvider.ts | 1 + .../prime/PrimeAgentDaemonAdapter.test.ts | 16 +- .../provider/prime/PrimeAgentDaemonAdapter.ts | 4 +- .../provider/prime/PrimeAgentDaemonManager.ts | 9 +- .../PrimeAgentDaemonSessionRuntime.test.ts | 1 + .../prime/PrimeAgentDaemonSessionRuntime.ts | 22 +- ...AgentMultipleInstances.integration.test.ts | 21 +- .../PrimeAgentRealDaemon.integration.test.ts | 1 + .../prime/PrimeAgentRecoveryLedger.ts | 12 +- .../server/src/provider/primeAgentBackends.ts | 2 +- .../src/provider/providerInstallation.ts | 2 +- .../src/provider/providerLoginCoordinator.ts | 6 +- .../src/provider/providerMaintenanceRunner.ts | 2 +- .../src/provider/sharedUsageReadCache.ts | 4 +- .../src/pullRequest/GitLabPullRequestCli.ts | 2 +- .../src/pullRequest/PullRequestReadCache.ts | 2 +- .../pullRequest/PullRequestService.test.ts | 6 +- .../src/pullRequest/PullRequestService.ts | 18 +- .../src/relay/AgentAwarenessRelay.test.ts | 6 +- .../relay/AgentAwarenessRelayStartup.test.ts | 2 +- .../src/resourceTelemetry/HostResources.ts | 4 +- .../src/rollback/RollbackAdmission.test.ts | 34 ++- apps/server/src/server.test.ts | 222 ++++++++---------- .../serverRuntimeStartup.reconcile.test.ts | 88 +++---- apps/server/src/serverRuntimeStartup.test.ts | 54 ++--- apps/server/src/serverRuntimeStartup.ts | 86 ++++--- apps/server/src/serverRuntimeState.ts | 4 +- .../serverSettings.providerInstances.test.ts | 5 +- .../ForgejoSourceControlProvider.ts | 19 +- .../src/sourceControl/GitHubCli.test.ts | 6 +- .../SourceControlProviderRegistry.ts | 6 +- apps/server/src/telemetry/Identify.ts | 4 +- apps/server/src/terminal/Manager.ts | 22 +- .../AntigravityTextGeneration.ts | 2 +- .../CodexTextGeneration.test.ts | 4 +- .../src/textGeneration/CodexTextGeneration.ts | 7 +- apps/server/src/usage/UsageService.ts | 4 +- apps/server/src/vcs/GitVcsDriver.ts | 2 +- apps/server/src/vcs/GitVcsDriverCore.ts | 29 +-- apps/server/src/vcs/VcsStatusBroadcaster.ts | 6 +- apps/server/src/ws.ts | 58 ++--- apps/web/src/components/ui/alert-dialog.tsx | 2 +- apps/web/src/components/ui/dialog.tsx | 2 +- apps/web/src/components/ui/empty.tsx | 6 +- apps/web/src/components/ui/scroll-area.tsx | 2 +- apps/web/src/components/ui/sheet.tsx | 2 +- apps/web/src/composerDraftStore.test.ts | 2 +- apps/web/src/connection/platform.ts | 2 +- apps/web/src/connection/storage.ts | 8 +- apps/web/src/index.css | 2 + .../src/authorization/layer.test.ts | 2 +- .../src/connection/registry.test.ts | 6 +- .../client-runtime/src/connection/resolver.ts | 14 +- .../src/connection/supervisor.test.ts | 4 +- .../src/connection/supervisor.ts | 1 + .../src/platform/storageDocument.test.ts | 2 +- .../src/relay/discovery.test.ts | 18 +- .../client-runtime/src/relay/discovery.ts | 2 +- .../client-runtime/src/relay/managedRelay.ts | 11 +- .../src/relay/managedRelayState.ts | 14 +- .../client-runtime/src/rpc/session.test.ts | 10 +- .../src/state/pullRequests.test.ts | 2 +- .../client-runtime/src/state/server.test.ts | 76 +++--- .../src/state/serverUsage.test.ts | 8 +- packages/client-runtime/src/state/session.ts | 2 +- .../src/state/shell-sync.test.ts | 36 +-- .../src/state/sourceControl.test.ts | 8 +- .../src/state/threads-atoms.test.ts | 6 +- .../src/state/threads-failures.test.ts | 8 +- .../src/state/threads-pagination.test.ts | 6 +- .../src/state/threads-sync.test.ts | 6 +- packages/client-runtime/src/state/vcs.test.ts | 6 +- .../src/state/vcsAction.test.ts | 8 +- .../effectParseOptionsCompatibility.test.ts | 6 +- packages/contracts/src/project.test.ts | 2 +- packages/contracts/src/pullRequest.test.ts | 2 +- packages/contracts/src/rpc.test.ts | 2 +- packages/effect-acp/src/client.ts | 8 +- packages/effect-acp/src/protocol.ts | 2 +- .../src/_internal/shared.ts | 2 +- .../src/schema.test.ts | 2 +- packages/shared/src/httpReadiness.ts | 18 +- packages/shared/src/relayClient.ts | 24 +- packages/shared/src/relayTracing.ts | 2 +- packages/shared/src/schemaJson.ts | 3 +- tsconfig.base.json | 3 +- 194 files changed, 1172 insertions(+), 1327 deletions(-) diff --git a/apps/desktop/src/app/DesktopAppIdentity.test.ts b/apps/desktop/src/app/DesktopAppIdentity.test.ts index 092f154cd4..36abd767e5 100644 --- a/apps/desktop/src/app/DesktopAppIdentity.test.ts +++ b/apps/desktop/src/app/DesktopAppIdentity.test.ts @@ -77,7 +77,7 @@ const makeAssetsLayer = (png: Option.Option) => icns: Option.none(), png, }), - resolveResourcePath: () => Effect.succeed(Option.none()), + resolveResourcePath: () => Effect.succeedNone, } satisfies DesktopAssets.DesktopAssets["Service"]); const makeEnvironmentLayer = (overrides: TestEnvironmentInput = {}) => { diff --git a/apps/desktop/src/app/DesktopConnectionCatalogStore.test.ts b/apps/desktop/src/app/DesktopConnectionCatalogStore.test.ts index aa28ff8d86..805f6e8600 100644 --- a/apps/desktop/src/app/DesktopConnectionCatalogStore.test.ts +++ b/apps/desktop/src/app/DesktopConnectionCatalogStore.test.ts @@ -40,7 +40,7 @@ function makeSafeStorageLayer(available: boolean, failDecrypt: Ref.Ref return decoded.slice("encrypted:".length); }); }, - selectedStorageBackend: Effect.succeed(Option.none()), + selectedStorageBackend: Effect.succeedNone, } satisfies ElectronSafeStorage.ElectronSafeStorage["Service"]); } diff --git a/apps/desktop/src/app/DesktopConnectionCatalogStore.ts b/apps/desktop/src/app/DesktopConnectionCatalogStore.ts index e2e0cd413b..46b2546e68 100644 --- a/apps/desktop/src/app/DesktopConnectionCatalogStore.ts +++ b/apps/desktop/src/app/DesktopConnectionCatalogStore.ts @@ -205,7 +205,7 @@ const readDocument = ( raw === null ? Effect.succeed(Option.none()) : decodeEncryptedConnectionCatalogDocumentJson(raw).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.mapError( (cause) => new DesktopConnectionCatalogStoreDocumentDecodeError({ diff --git a/apps/desktop/src/app/DesktopLinuxUrlHandler.test.ts b/apps/desktop/src/app/DesktopLinuxUrlHandler.test.ts index 6980bf1ca2..5f8801434e 100644 --- a/apps/desktop/src/app/DesktopLinuxUrlHandler.test.ts +++ b/apps/desktop/src/app/DesktopLinuxUrlHandler.test.ts @@ -85,7 +85,7 @@ const makeHandlerLayer = ( icns: Option.none(), png: input.bundledIcon ? Option.some(BUNDLED_ICON_PATH) : Option.none(), }), - resolveResourcePath: () => Effect.succeed(Option.none()), + resolveResourcePath: () => Effect.succeedNone, }), ), FileSystem.layerNoop({ diff --git a/apps/desktop/src/backend/DesktopBackendConfiguration.ts b/apps/desktop/src/backend/DesktopBackendConfiguration.ts index 89f07e9481..972cf1ed2c 100644 --- a/apps/desktop/src/backend/DesktopBackendConfiguration.ts +++ b/apps/desktop/src/backend/DesktopBackendConfiguration.ts @@ -214,11 +214,11 @@ const readPersistedBackendObservabilitySettings = Effect.gen(function* () { const fileSystem = yield* FileSystem.FileSystem; const environment = yield* DesktopEnvironment.DesktopEnvironment; const raw = yield* fileSystem.readFileString(environment.serverSettingsPath).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catchTags({ PlatformError: (cause) => cause.reason._tag === "NotFound" - ? Effect.succeed(Option.none()) + ? Effect.succeedNone : logBackendObservabilitySettingsReadFailure(environment.serverSettingsPath, cause).pipe( Effect.as(Option.none()), ), diff --git a/apps/desktop/src/backend/DesktopBackendManager.test.ts b/apps/desktop/src/backend/DesktopBackendManager.test.ts index 4bbecd7d74..18d352313f 100644 --- a/apps/desktop/src/backend/DesktopBackendManager.test.ts +++ b/apps/desktop/src/backend/DesktopBackendManager.test.ts @@ -162,7 +162,7 @@ function makeTestInstance(input: MakeInstanceInput) { forInstance: () => Effect.succeed(stubLog), } satisfies DesktopObservability.DesktopBackendOutputLogFactory["Service"]), Layer.succeed(DesktopTelemetryPublisher.DesktopTelemetryPublisher, { - latest: Effect.succeed(Option.none()), + latest: Effect.succeedNone, changes: Stream.empty, encoded: input.desktopTelemetryStream ?? Stream.empty, handleControl: () => Effect.void, @@ -1547,7 +1547,7 @@ describe("DesktopBackendManager", () => { const mockPool = Layer.succeed(DesktopBackendPool.DesktopBackendPool, { list: Effect.succeed([instance1, instance2]), - get: () => Effect.succeed(Option.none()), + get: () => Effect.succeedNone, primary: Effect.die(new Error("primary not implemented")), register: () => Effect.die(new Error("register not implemented")), unregister: () => Effect.die(new Error("unregister not implemented")), @@ -1623,7 +1623,7 @@ describe("DesktopBackendManager", () => { const mockPool = Layer.succeed(DesktopBackendPool.DesktopBackendPool, { list: Effect.succeed([instance1, instance2]), - get: () => Effect.succeed(Option.none()), + get: () => Effect.succeedNone, primary: Effect.die(new Error("primary not implemented")), register: () => Effect.die(new Error("register not implemented")), unregister: () => Effect.die(new Error("unregister not implemented")), diff --git a/apps/desktop/src/backend/DesktopBackendPool.test.ts b/apps/desktop/src/backend/DesktopBackendPool.test.ts index 2ad87e1a76..e7643eeb5b 100644 --- a/apps/desktop/src/backend/DesktopBackendPool.test.ts +++ b/apps/desktop/src/backend/DesktopBackendPool.test.ts @@ -68,7 +68,7 @@ function makePoolLayer( } satisfies DesktopObservability.DesktopBackendOutputLogShape), } satisfies DesktopObservability.DesktopBackendOutputLogFactory["Service"]), Layer.succeed(DesktopTelemetryPublisher.DesktopTelemetryPublisher, { - latest: Effect.succeed(Option.none()), + latest: Effect.succeedNone, changes: Stream.empty, encoded: Stream.empty, handleControl: () => Effect.void, @@ -137,9 +137,10 @@ describe("DesktopBackendPool", () => { it.effect("layerTest dies when no instances are supplied", () => Effect.exit( - Effect.gen(function* () { - yield* DesktopBackendPool.DesktopBackendPool; - }).pipe(Effect.provide(DesktopBackendPool.layerTest([]))), + DesktopBackendPool.DesktopBackendPool.pipe( + Effect.asVoid, + Effect.provide(DesktopBackendPool.layerTest([])), + ), ).pipe(Effect.map((exit) => assert.equal(exit._tag, "Failure"))), ); diff --git a/apps/desktop/src/backend/DesktopLocalEnvironmentAuth.test.ts b/apps/desktop/src/backend/DesktopLocalEnvironmentAuth.test.ts index e7a58baef1..ed71bd332d 100644 --- a/apps/desktop/src/backend/DesktopLocalEnvironmentAuth.test.ts +++ b/apps/desktop/src/backend/DesktopLocalEnvironmentAuth.test.ts @@ -1,7 +1,6 @@ import { assert, describe, it } from "@effect/vitest"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; -import * as Option from "effect/Option"; import * as Ref from "effect/Ref"; import * as HttpClient from "effect/unstable/http/HttpClient"; import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse"; @@ -60,7 +59,7 @@ describe("DesktopLocalEnvironmentAuth", () => { { id: PRIMARY_LOCAL_ENVIRONMENT_ID, label: Effect.succeed("Windows"), - currentConfig: Effect.succeed(Option.some(config)), + currentConfig: Effect.succeedSome(config), }, ]), } as unknown as DesktopBackendPool.DesktopBackendPool["Service"]); diff --git a/apps/desktop/src/electron/ElectronMenu.ts b/apps/desktop/src/electron/ElectronMenu.ts index 1360fb545b..401e0c27cc 100644 --- a/apps/desktop/src/electron/ElectronMenu.ts +++ b/apps/desktop/src/electron/ElectronMenu.ts @@ -226,7 +226,7 @@ export const make = Effect.gen(function* () { Effect.callback>((resume) => { const normalizedItems = normalizeContextMenuItems(input.items); if (normalizedItems.length === 0) { - resume(Effect.succeed(Option.none())); + resume(Effect.succeedNone); return; } diff --git a/apps/desktop/src/electron/ElectronShell.test.ts b/apps/desktop/src/electron/ElectronShell.test.ts index 904ee3b369..0bc3f9ac1d 100644 --- a/apps/desktop/src/electron/ElectronShell.test.ts +++ b/apps/desktop/src/electron/ElectronShell.test.ts @@ -124,7 +124,7 @@ describe("ElectronShell", () => { it.effect("rejects encoded or malformed Zed SSH authorities", () => Effect.gen(function* () { const electronShell = yield* ElectronShell.ElectronShell; - const results = yield* Effect.all( + const results = yield* Effect.forEach( [ "user%40example.com", "user%3Asecret%40example.com", @@ -133,7 +133,8 @@ describe("ElectronShell", () => { "example.com%0A", "example.com%20", "example.com%", - ].map((host) => electronShell.openExternal(`zed://ssh/${host}/path`)), + ], + (host) => electronShell.openExternal(`zed://ssh/${host}/path`), ); assert.deepEqual(results, Array(7).fill(false)); assert.equal(openExternalMock.mock.calls.length, 0); diff --git a/apps/desktop/src/ipc/methods/snapShot.test.ts b/apps/desktop/src/ipc/methods/snapShot.test.ts index 7e20890ef5..138bcbc36d 100644 --- a/apps/desktop/src/ipc/methods/snapShot.test.ts +++ b/apps/desktop/src/ipc/methods/snapShot.test.ts @@ -51,7 +51,7 @@ describe("window capture IPC", () => { Effect.provide( Layer.mergeAll( Layer.succeed(ElectronWindow.ElectronWindow, { - main: Effect.succeed(Option.some({ webContents: { id: 7 } })), + main: Effect.succeedSome({ webContents: { id: 7 } }), } as ElectronWindow.ElectronWindow["Service"]), Layer.succeed(DesktopSnapShot.DesktopSnapShot, { previewConfig: () => @@ -87,7 +87,7 @@ describe("window capture IPC", () => { Effect.provide( Layer.mergeAll( Layer.succeed(ElectronWindow.ElectronWindow, { - main: Effect.succeed(Option.some({ webContents: { id: 7 } })), + main: Effect.succeedSome({ webContents: { id: 7 } }), } as ElectronWindow.ElectronWindow["Service"]), Layer.succeed(DesktopSnapShot.DesktopSnapShot, { state: Effect.succeed({ @@ -120,7 +120,7 @@ describe("window capture IPC", () => { Effect.provide( Layer.mergeAll( Layer.succeed(ElectronWindow.ElectronWindow, { - main: Effect.succeed(Option.some({ webContents: { id: 7 } })), + main: Effect.succeedSome({ webContents: { id: 7 } }), } as ElectronWindow.ElectronWindow["Service"]), Layer.succeed(DesktopSnapShot.DesktopSnapShot, { state: Effect.succeed({ linuxBackend: "niri" }), @@ -156,13 +156,11 @@ describe("window capture IPC", () => { Layer.succeed( ElectronWindow.ElectronWindow, ElectronWindow.ElectronWindow.of({ - main: Effect.succeed( - Option.some({ - getBounds: () => ({ x: 100, y: 80, width: 1_000, height: 700 }), - getContentBounds: () => ({ x: 100, y: 118, width: 1_000, height: 662 }), - webContents, - }), - ), + main: Effect.succeedSome({ + getBounds: () => ({ x: 100, y: 80, width: 1_000, height: 700 }), + getContentBounds: () => ({ x: 100, y: 118, width: 1_000, height: 662 }), + webContents, + }), } as ElectronWindow.ElectronWindow["Service"]), ), Layer.succeed( @@ -220,7 +218,7 @@ describe("window capture IPC", () => { Layer.succeed( ElectronWindow.ElectronWindow, ElectronWindow.ElectronWindow.of({ - main: Effect.succeed(Option.some({ webContents })), + main: Effect.succeedSome({ webContents }), } as ElectronWindow.ElectronWindow["Service"]), ), Layer.succeed( @@ -256,7 +254,7 @@ describe("window capture IPC", () => { Effect.provideService( ElectronWindow.ElectronWindow, ElectronWindow.ElectronWindow.of({ - main: Effect.succeed(Option.some({ webContents: { id: 7 } })), + main: Effect.succeedSome({ webContents: { id: 7 } }), } as ElectronWindow.ElectronWindow["Service"]), ), Effect.provideService(DesktopSnapShot.DesktopSnapShot, null as never), @@ -277,7 +275,7 @@ describe("window capture IPC", () => { Effect.provide( Layer.mergeAll( Layer.succeed(ElectronWindow.ElectronWindow, { - main: Effect.succeed(Option.some({ webContents: { id: 7 } })), + main: Effect.succeedSome({ webContents: { id: 7 } }), } as ElectronWindow.ElectronWindow["Service"]), Layer.succeed(DesktopSnapShot.DesktopSnapShot, { setup: (action: string) => @@ -295,7 +293,7 @@ describe("window capture IPC", () => { Layer.succeed( ElectronWindow.ElectronWindow, ElectronWindow.ElectronWindow.of({ - main: Effect.succeed(Option.some({ webContents: { id: 7 } })), + main: Effect.succeedSome({ webContents: { id: 7 } }), } as ElectronWindow.ElectronWindow["Service"]), ), Layer.succeed( @@ -320,7 +318,7 @@ describe("window capture IPC", () => { Layer.succeed( ElectronWindow.ElectronWindow, ElectronWindow.ElectronWindow.of({ - main: Effect.succeed(Option.some({ webContents: { id: 7 } })), + main: Effect.succeedSome({ webContents: { id: 7 } }), } as ElectronWindow.ElectronWindow["Service"]), ), Layer.succeed( diff --git a/apps/desktop/src/ipc/methods/sshEnvironment.ts b/apps/desktop/src/ipc/methods/sshEnvironment.ts index cfb993d35c..e953530010 100644 --- a/apps/desktop/src/ipc/methods/sshEnvironment.ts +++ b/apps/desktop/src/ipc/methods/sshEnvironment.ts @@ -137,13 +137,11 @@ export const ensureSshEnvironment = DesktopIpc.makeIpcMethod({ }) { const sshEnvironment = yield* DesktopSshEnvironment.DesktopSshEnvironment; return yield* sshEnvironment.ensureEnvironment(target, options).pipe( - Effect.catch((error) => - DesktopSshEnvironment.isDesktopSshPasswordPromptCancellation(error) - ? Effect.succeed({ - type: DesktopSshPasswordPromptCancelledType, - message: error.message, - }) - : Effect.fail(error), + Effect.catchIf(DesktopSshEnvironment.isDesktopSshPasswordPromptCancellation, (error) => + Effect.succeed({ + type: DesktopSshPasswordPromptCancelledType, + message: error.message, + }), ), ); }), diff --git a/apps/desktop/src/ipc/methods/window.test.ts b/apps/desktop/src/ipc/methods/window.test.ts index 4d4ca7b63e..f2fd2c8493 100644 --- a/apps/desktop/src/ipc/methods/window.test.ts +++ b/apps/desktop/src/ipc/methods/window.test.ts @@ -59,7 +59,7 @@ const defaultWslInstance: DesktopBackendManager.DesktopBackendInstance = { label: Effect.succeed("WSL (default distro)"), start: Effect.void, stop: () => Effect.void, - currentConfig: Effect.succeed(Option.some(readyWslConfig)), + currentConfig: Effect.succeedSome(readyWslConfig), snapshot: Effect.succeed({ desiredRunning: true, ready: true, @@ -99,7 +99,7 @@ describe("getLocalEnvironmentBootstraps", () => { }; const retryingInstance: DesktopBackendManager.DesktopBackendInstance = { ...defaultWslInstance, - currentConfig: Effect.succeed(Option.some(retryingConfig)), + currentConfig: Effect.succeedSome(retryingConfig), snapshot: Effect.succeed({ desiredRunning: true, ready: false, @@ -126,16 +126,14 @@ describe("getLocalEnvironmentBootstraps", () => { it.effect("omits a bounded transient bootstrap after retries stop", () => { const stoppedInstance: DesktopBackendManager.DesktopBackendInstance = { ...defaultWslInstance, - currentConfig: Effect.succeed( - Option.some({ - ...readyWslConfig, - preflightFailure: Option.some({ - reason: "WSL probe timed out", - fatal: false, - retryLimit: 12, - }), + currentConfig: Effect.succeedSome({ + ...readyWslConfig, + preflightFailure: Option.some({ + reason: "WSL probe timed out", + fatal: false, + retryLimit: 12, }), - ), + }), snapshot: Effect.succeed({ desiredRunning: false, ready: false, @@ -161,7 +159,7 @@ describe("getWindowFullscreenState", () => { }).pipe( Effect.provide( Layer.mock(ElectronWindow.ElectronWindow)({ - currentMainOrFirst: Effect.succeed(Option.some(window)), + currentMainOrFirst: Effect.succeedSome(window), }), ), ); @@ -204,7 +202,7 @@ describe("pasteAsText", () => { }).pipe( Effect.provide( Layer.mock(ElectronWindow.ElectronWindow)({ - main: Effect.succeed(Option.some(window)), + main: Effect.succeedSome(window), }), ), ); @@ -221,7 +219,7 @@ describe("pickProjectFavicon", () => { Layer.mergeAll( Layer.mock(ElectronDialog.ElectronDialog)({ pickFiles }), Layer.mock(ElectronWindow.ElectronWindow)({ - focusedMainOrFirst: Effect.succeed(Option.none()), + focusedMainOrFirst: Effect.succeedNone, }), ), ), diff --git a/apps/desktop/src/ipc/methods/wsl.test.ts b/apps/desktop/src/ipc/methods/wsl.test.ts index 38435e286f..d128dc179d 100644 --- a/apps/desktop/src/ipc/methods/wsl.test.ts +++ b/apps/desktop/src/ipc/methods/wsl.test.ts @@ -2,7 +2,6 @@ import { DesktopWslStateSchema } from "@t3tools/contracts"; import { assert, describe, it } from "@effect/vitest"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; -import * as Option from "effect/Option"; import * as Schema from "effect/Schema"; import * as DesktopEnvironment from "../../app/DesktopEnvironment.ts"; @@ -34,7 +33,7 @@ function makeWslBackendLayer(input: { readonly onReconcile?: Effect.Effect DesktopWslBackend.DesktopWslBackend, DesktopWslBackend.DesktopWslBackend.of({ reconcile: input.onReconcile ?? Effect.void, - lastPreflightError: Effect.succeed(Option.none()), + lastPreflightError: Effect.succeedNone, }), ); } diff --git a/apps/desktop/src/preview/BrowserImport/ChromiumKeys.ts b/apps/desktop/src/preview/BrowserImport/ChromiumKeys.ts index 9310fd1c92..866cd0b7a9 100644 --- a/apps/desktop/src/preview/BrowserImport/ChromiumKeys.ts +++ b/apps/desktop/src/preview/BrowserImport/ChromiumKeys.ts @@ -315,9 +315,7 @@ export const resolveChromiumKeys = Effect.fn("ChromiumKeys.resolveChromiumKeys") // v10 remains importable when Secret Service is absent or does not // contain a key. An explicit denial/lock/cancel remains a consent // failure rather than being silently downgraded. - Effect.catch((error) => - error.reason === "needsKeychainApproval" ? Effect.fail(error) : Effect.succeed(error), - ), + Effect.catchIf((error) => error.reason !== "needsKeychainApproval", Effect.succeed), ) : undefined; return { diff --git a/apps/desktop/src/preview/BrowserSession.ts b/apps/desktop/src/preview/BrowserSession.ts index 769b6f6008..acebe407fd 100644 --- a/apps/desktop/src/preview/BrowserSession.ts +++ b/apps/desktop/src/preview/BrowserSession.ts @@ -212,8 +212,9 @@ export const make = Effect.gen(function* BrowserSessionMake() { getSession, clearCookies: Effect.fn("BrowserSession.clearCookies")(function* (partitions?) { const sessions = yield* SynchronizedRef.get(sessionsRef); - yield* Effect.all( - selectSessions(sessions, partitions).map(([partition, browserSession]) => + yield* Effect.forEach( + selectSessions(sessions, partitions), + ([partition, browserSession]) => Effect.tryPromise({ try: () => browserSession.clearStorageData({ @@ -225,14 +226,14 @@ export const make = Effect.gen(function* BrowserSessionMake() { cause, }), }), - ), { concurrency: "unbounded", discard: true }, ); }), clearCache: Effect.fn("BrowserSession.clearCache")(function* (partitions?) { const sessions = yield* SynchronizedRef.get(sessionsRef); - yield* Effect.all( - selectSessions(sessions, partitions).map(([partition, browserSession]) => + yield* Effect.forEach( + selectSessions(sessions, partitions), + ([partition, browserSession]) => Effect.tryPromise({ try: () => browserSession.clearCache(), catch: (cause) => @@ -241,7 +242,6 @@ export const make = Effect.gen(function* BrowserSessionMake() { cause, }), }), - ), { concurrency: "unbounded", discard: true }, ); }), diff --git a/apps/desktop/src/preview/Manager.ts b/apps/desktop/src/preview/Manager.ts index 5670f200f2..50dcfce7ad 100644 --- a/apps/desktop/src/preview/Manager.ts +++ b/apps/desktop/src/preview/Manager.ts @@ -954,14 +954,14 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function delivery: () => Effect.Effect, ) => Effect.suspend(delivery).pipe( - Effect.catchCause((cause) => - Cause.hasInterrupts(cause) - ? Effect.failCause(cause) - : Effect.logWarning("Desktop preview event listener failed.", { - eventKind, - tabId, - cause, - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterrupts(cause), + (cause) => + Effect.logWarning("Desktop preview event listener failed.", { + eventKind, + tabId, + cause, + }), ), ); @@ -1127,15 +1127,13 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function } return resolvedPath; }).pipe( - Effect.flatMap((resolvedPath) => - resolvedPath === null - ? Effect.fail( - new PreviewArtifactPathOutsideDirectoryError({ - artifactPath, - artifactDirectory: resolvedArtifactDirectory, - }), - ) - : Effect.succeed(resolvedPath), + Effect.filterOrFail( + (resolvedPath) => resolvedPath !== null, + () => + new PreviewArtifactPathOutsideDirectoryError({ + artifactPath, + artifactDirectory: resolvedArtifactDirectory, + }), ), ); @@ -1416,14 +1414,13 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function wcDebugger.on("message", onMessage); wcDebugger.attach("1.3"); }); - yield* Effect.all( - ["Runtime.enable", "Accessibility.enable", "Network.enable", "Log.enable"].map( - (method) => - attemptPromise( - { operation: `initializeDebugger.${method}`, webContentsId: wc.id }, - () => wcDebugger.sendCommand(method), - ), - ), + yield* Effect.forEach( + ["Runtime.enable", "Accessibility.enable", "Network.enable", "Log.enable"], + (method) => + attemptPromise( + { operation: `initializeDebugger.${method}`, webContentsId: wc.id }, + () => wcDebugger.sendCommand(method), + ), { concurrency: "unbounded", discard: true }, ); return [ @@ -4081,13 +4078,13 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function receiptKey: JSON.stringify(`__t3NativeKey_${NodeCrypto.randomUUID()}`), })), ({ frames, receiptKey }) => - Effect.all( - frames.map((frame) => + Effect.forEach( + frames, + (frame) => evaluate(frame, `globalThis[${receiptKey}]?.dispose()`).pipe( Effect.timeoutOption(1_000), Effect.ignore, ), - ), { concurrency: "unbounded", discard: true }, ), ); diff --git a/apps/desktop/src/settings/DesktopClientSettings.test.ts b/apps/desktop/src/settings/DesktopClientSettings.test.ts index 1ad8e5d6bb..62c4e0d985 100644 --- a/apps/desktop/src/settings/DesktopClientSettings.test.ts +++ b/apps/desktop/src/settings/DesktopClientSettings.test.ts @@ -390,11 +390,11 @@ describe("DesktopClientSettings", () => { set: () => Effect.void, }); const direct = DesktopClientSettings.DesktopClientSettings.of({ - get: Effect.succeed(Option.some({ ...clientSettings, confirmQuit: "direct" })), + get: Effect.succeedSome({ ...clientSettings, confirmQuit: "direct" }), set: () => Effect.void, }); const missing = DesktopClientSettings.DesktopClientSettings.of({ - get: Effect.succeed(Option.none()), + get: Effect.succeedNone, set: () => Effect.void, }); diff --git a/apps/desktop/src/settings/DesktopClientSettings.ts b/apps/desktop/src/settings/DesktopClientSettings.ts index f914d752d8..3827444045 100644 --- a/apps/desktop/src/settings/DesktopClientSettings.ts +++ b/apps/desktop/src/settings/DesktopClientSettings.ts @@ -80,7 +80,7 @@ const readClientSettings = ( settingsPath: string, ): Effect.Effect, DesktopClientSettingsReadError> => fileSystem.readFileString(settingsPath).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catchTags({ PlatformError: (cause) => cause.reason._tag === "NotFound" diff --git a/apps/desktop/src/settings/DesktopSavedEnvironments.test.ts b/apps/desktop/src/settings/DesktopSavedEnvironments.test.ts index 348f6cb384..d2d476a849 100644 --- a/apps/desktop/src/settings/DesktopSavedEnvironments.test.ts +++ b/apps/desktop/src/settings/DesktopSavedEnvironments.test.ts @@ -87,7 +87,7 @@ function makeSafeStorageLayer(input: { } return Effect.succeed(decoded.slice("enc:".length)); }, - selectedStorageBackend: Effect.succeed(Option.none()), + selectedStorageBackend: Effect.succeedNone, } satisfies ElectronSafeStorage.ElectronSafeStorage["Service"]); } diff --git a/apps/desktop/src/snapShot/DesktopSnapShot.ts b/apps/desktop/src/snapShot/DesktopSnapShot.ts index 4fcef01c1b..41f57e351d 100644 --- a/apps/desktop/src/snapShot/DesktopSnapShot.ts +++ b/apps/desktop/src/snapShot/DesktopSnapShot.ts @@ -825,7 +825,7 @@ export const make = Effect.gen(function* () { }; const emit = (event: DesktopSnapShotEvent) => - desktopWindow.dispatchSnapShotEvent(event).pipe(Effect.catchCause(() => Effect.void)); + desktopWindow.dispatchSnapShotEvent(event).pipe(Effect.ignoreCause); const setFailure = (message: string, captureId?: string) => Ref.update(stateRef, (state) => ({ ...state, message })).pipe( Effect.andThen( @@ -851,10 +851,9 @@ export const make = Effect.gen(function* () { const discardCapture = Effect.fn("desktop.snapShot.discardCapture")(function* (id: string) { closeLinuxFeedback(id); transition.dismiss(id); - yield* Effect.all( - [`${id}.png`, `${id}.tmp.png`, `${id}.json`, `${id}.json.tmp`].map((name) => - fileSystem.remove(path.join(captureDirectory, name), { force: true }), - ), + yield* Effect.forEach( + [`${id}.png`, `${id}.tmp.png`, `${id}.json`, `${id}.json.tmp`], + (name) => fileSystem.remove(path.join(captureDirectory, name), { force: true }), { concurrency: "unbounded", discard: true }, ).pipe(Effect.ignore); }); @@ -909,7 +908,7 @@ export const make = Effect.gen(function* () { if (snapshot.animationStarted) { yield* emit({ type: "started", id: id as DesktopSnapShotId }); } else { - yield* desktopWindow.activate.pipe(Effect.catchCause(() => Effect.void)); + yield* desktopWindow.activate.pipe(Effect.ignoreCause); } return { id, capturedAt, ...snapshot }; }).pipe(Effect.mapError((cause) => captureFailure(cause, id))); @@ -1516,7 +1515,7 @@ export const make = Effect.gen(function* () { null, ), ), - Effect.catch(() => Effect.void), + Effect.ignore, ), ), configure, diff --git a/apps/desktop/src/ssh/DesktopSshPasswordPrompts.test.ts b/apps/desktop/src/ssh/DesktopSshPasswordPrompts.test.ts index aa3b7c0b4d..27ab73d2e5 100644 --- a/apps/desktop/src/ssh/DesktopSshPasswordPrompts.test.ts +++ b/apps/desktop/src/ssh/DesktopSshPasswordPrompts.test.ts @@ -4,7 +4,6 @@ import * as Duration from "effect/Duration"; import * as Effect from "effect/Effect"; import * as Fiber from "effect/Fiber"; import * as Layer from "effect/Layer"; -import * as Option from "effect/Option"; import * as TestClock from "effect/testing/TestClock"; import type * as Electron from "electron"; @@ -92,9 +91,9 @@ function makeElectronWindowLayer(window: ReturnType["wind ElectronWindow.ElectronWindow, ElectronWindow.ElectronWindow.of({ create: () => Effect.die("unexpected BrowserWindow creation"), - main: Effect.succeed(Option.some(window as Electron.BrowserWindow)), - currentMainOrFirst: Effect.succeed(Option.some(window as Electron.BrowserWindow)), - focusedMainOrFirst: Effect.succeed(Option.some(window as Electron.BrowserWindow)), + main: Effect.succeedSome(window as Electron.BrowserWindow), + currentMainOrFirst: Effect.succeedSome(window as Electron.BrowserWindow), + focusedMainOrFirst: Effect.succeedSome(window as Electron.BrowserWindow), setMain: () => Effect.void, clearMain: () => Effect.void, prepareReveal: () => Effect.succeed(false), diff --git a/apps/desktop/src/telemetry/DesktopTelemetryPublisher.ts b/apps/desktop/src/telemetry/DesktopTelemetryPublisher.ts index 8fd478c821..ff581290d2 100644 --- a/apps/desktop/src/telemetry/DesktopTelemetryPublisher.ts +++ b/apps/desktop/src/telemetry/DesktopTelemetryPublisher.ts @@ -290,12 +290,12 @@ export const make = Effect.fn("desktop.telemetryPublisher.make")(function* () { yield* Ref.set(latest, Option.some(snapshot)); yield* PubSub.publish(changes, snapshot); }).pipe( - Effect.catchCause((cause) => - Cause.hasInterrupts(cause) - ? Effect.failCause(cause) - : Effect.logWarning("Failed to sample Electron telemetry", { - cause: String(cause), - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterrupts(cause), + (cause) => + Effect.logWarning("Failed to sample Electron telemetry", { + cause: String(cause), + }), ), ); @@ -307,6 +307,7 @@ export const make = Effect.fn("desktop.telemetryPublisher.make")(function* () { Ref.get(diagnosticsDemandSources).pipe(Effect.map((sources) => sources.size > 0)), Ref.get(hostPowerIntervals), ]); + // @effect-diagnostics-next-line raceFirstWithSleepToTimeout:off - races a trigger queue against the interval; both arms are real outcomes, not a timeout const allowSuspendRecovery = yield* Effect.raceFirst( Queue.take(sampleTriggers).pipe(Effect.as(false)), Effect.sleep(sampleInterval(currentPower, demand, intervals)).pipe(Effect.as(true)), diff --git a/apps/desktop/src/updates/updatesTestHarness.ts b/apps/desktop/src/updates/updatesTestHarness.ts index 59de3f1451..27e75a897c 100644 --- a/apps/desktop/src/updates/updatesTestHarness.ts +++ b/apps/desktop/src/updates/updatesTestHarness.ts @@ -147,9 +147,9 @@ export function makeHarness(options: UpdatesHarnessOptions = {}): UpdatesHarness const windowLayer = Layer.succeed(ElectronWindow.ElectronWindow, { create: () => Effect.die("unexpected BrowserWindow creation"), - main: Effect.succeed(Option.none()), - currentMainOrFirst: Effect.succeed(Option.none()), - focusedMainOrFirst: Effect.succeed(Option.none()), + main: Effect.succeedNone, + currentMainOrFirst: Effect.succeedNone, + focusedMainOrFirst: Effect.succeedNone, setMain: () => Effect.void, clearMain: () => Effect.void, prepareReveal: () => Effect.succeed(false), @@ -171,7 +171,7 @@ export function makeHarness(options: UpdatesHarnessOptions = {}): UpdatesHarness installSteps.push("startBackend"); }).pipe(Effect.andThen(options.startBackend ?? Effect.void)), stop: () => options.stopBackend ?? Effect.void, - currentConfig: Effect.succeed(Option.none()), + currentConfig: Effect.succeedNone, snapshot: Effect.succeed({ desiredRunning: false, ready: false, @@ -206,7 +206,7 @@ export function makeHarness(options: UpdatesHarnessOptions = {}): UpdatesHarness const wslInstance: DesktopBackendPool.DesktopBackendInstance = { ...stubBackendInstance, id: DesktopBackendPool.BackendInstanceId("wsl:Ubuntu"), - currentConfig: Effect.succeed(Option.some(wslConfig)), + currentConfig: Effect.succeedSome(wslConfig), stop: () => Effect.sync(() => { wslMarkerSteps.push("stopWslBackend"); diff --git a/apps/desktop/src/window/DesktopApplicationMenu.test.ts b/apps/desktop/src/window/DesktopApplicationMenu.test.ts index 2e5279f721..3a80b689e0 100644 --- a/apps/desktop/src/window/DesktopApplicationMenu.test.ts +++ b/apps/desktop/src/window/DesktopApplicationMenu.test.ts @@ -3,7 +3,6 @@ import { assert, describe, it } from "@effect/vitest"; import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; -import * as Option from "effect/Option"; import type * as Electron from "electron"; @@ -52,7 +51,7 @@ const electronAppLayer = Layer.succeed(ElectronApp.ElectronApp, { } satisfies ElectronApp.ElectronApp["Service"]); const electronDialogLayer = Layer.succeed(ElectronDialog.ElectronDialog, { - pickFolder: () => Effect.succeed(Option.none()), + pickFolder: () => Effect.succeedNone, pickFiles: () => Effect.succeed([]), showMessageBox: () => Effect.succeed({ response: 0, checkboxChecked: false }), showErrorBox: () => Effect.void, @@ -64,7 +63,7 @@ const desktopUpdatesLayer = Layer.succeed(DesktopUpdates.DesktopUpdates, { isInstallActive: Effect.succeed(false), subscribe: Effect.die("unexpected subscribe"), emitState: Effect.void, - disabledReason: Effect.succeed(Option.none()), + disabledReason: Effect.succeedNone, configure: Effect.void, check: () => Effect.die("unexpected check"), download: Effect.die("unexpected download"), @@ -98,7 +97,7 @@ const makeElectronMenuLayer = ( setApplicationMenu: (template) => Deferred.succeed(applicationMenuTemplate, template).pipe(Effect.asVoid), popupTemplate: () => Effect.void, - showContextMenu: () => Effect.succeed(Option.none()), + showContextMenu: () => Effect.succeedNone, } satisfies ElectronMenu.ElectronMenu["Service"]); const configureMenu = ( diff --git a/apps/desktop/src/window/DesktopWindow.test.ts b/apps/desktop/src/window/DesktopWindow.test.ts index c8179d494a..6d1b245a97 100644 --- a/apps/desktop/src/window/DesktopWindow.test.ts +++ b/apps/desktop/src/window/DesktopWindow.test.ts @@ -147,7 +147,7 @@ function makeFakeBrowserWindow() { } const desktopClientSettingsLayer = Layer.mock(DesktopClientSettings.DesktopClientSettings)({ - get: Effect.succeed(Option.none()), + get: Effect.succeedNone, }); const electronAppLayer = Layer.mock(ElectronApp.ElectronApp)({ @@ -181,7 +181,7 @@ const desktopServerExposureLayer = Layer.succeed(DesktopServerExposure.DesktopSe const electronMenuLayer = Layer.succeed(ElectronMenu.ElectronMenu, { setApplicationMenu: () => Effect.void, popupTemplate: () => Effect.void, - showContextMenu: () => Effect.succeed(Option.none()), + showContextMenu: () => Effect.succeedNone, } satisfies ElectronMenu.ElectronMenu["Service"]); const electronThemeLayer = Layer.succeed(ElectronTheme.ElectronTheme, { @@ -288,7 +288,7 @@ function makeTestLayer(input: { electronAppLayer, Layer.succeed(ElectronMenu.ElectronMenu, { setApplicationMenu: () => Effect.void, - showContextMenu: () => Effect.succeed(Option.none()), + showContextMenu: () => Effect.succeedNone, popupTemplate: input.onPopupTemplate ?? (() => Effect.void), }), Layer.succeed(ElectronShell.ElectronShell, { diff --git a/apps/desktop/src/wsl/DesktopWslBackend.ts b/apps/desktop/src/wsl/DesktopWslBackend.ts index 605f4e7a47..d7512eed1f 100644 --- a/apps/desktop/src/wsl/DesktopWslBackend.ts +++ b/apps/desktop/src/wsl/DesktopWslBackend.ts @@ -138,7 +138,7 @@ export const layer = Layer.effect( const primaryConfig = yield* serverExposure.backendConfig; const port = yield* scanForWslPort(primaryConfig.port + 1).pipe( Effect.provideService(NetService.NetService, net), - Effect.map((value) => Option.some(value)), + Effect.asSome, Effect.catch((error) => logWslBackendWarning("could not allocate port for WSL backend", { error: error.message, @@ -171,7 +171,7 @@ export const layer = Layer.effect( onReady: () => Ref.set(preflightErrorRef, Option.none()), }) .pipe( - Effect.map((registered) => Option.some(registered)), + Effect.asSome, Effect.catch((error) => logWslBackendWarning("WSL backend already registered, skipping start", { id: targetId, diff --git a/apps/desktop/src/wsl/DesktopWslEnvironment.ts b/apps/desktop/src/wsl/DesktopWslEnvironment.ts index 278700324d..cd162e9ae7 100644 --- a/apps/desktop/src/wsl/DesktopWslEnvironment.ts +++ b/apps/desktop/src/wsl/DesktopWslEnvironment.ts @@ -1089,11 +1089,7 @@ const preWarmImpl = ( const handle = yield* spawner.spawn(command); yield* handle.exitCode; }), - ).pipe( - Effect.timeoutOption(PRE_WARM_TIMEOUT), - Effect.asVoid, - Effect.catch(() => Effect.void), - ); + ).pipe(Effect.timeoutOption(PRE_WARM_TIMEOUT), Effect.asVoid, Effect.ignore); const windowsToWslPathImpl = ( distro: string | null, diff --git a/apps/server/integration/orphanedProviderSessionStartup.integration.test.ts b/apps/server/integration/orphanedProviderSessionStartup.integration.test.ts index 4c4d0bf4f9..e3b6a4a33f 100644 --- a/apps/server/integration/orphanedProviderSessionStartup.integration.test.ts +++ b/apps/server/integration/orphanedProviderSessionStartup.integration.test.ts @@ -101,7 +101,7 @@ const startupDependencies = Layer.mergeAll( Layer.succeed(ServiceLauncherClient.ServiceLauncherClient, { managed: false, requestUpdate: () => Effect.die("unused"), - prepareTrial: Effect.sync(() => undefined), + prepareTrial: Effect.undefined, }), Layer.succeed( HttpServer.HttpServer, diff --git a/apps/server/scripts/migrate-dev-db.ts b/apps/server/scripts/migrate-dev-db.ts index 6965c6200f..1afa8ddd70 100644 --- a/apps/server/scripts/migrate-dev-db.ts +++ b/apps/server/scripts/migrate-dev-db.ts @@ -405,8 +405,8 @@ export const runMigrateDevDb = Effect.fn("runMigrateDevDb")(function* ( // Compared canonically so a symlink pointing at a protected home cannot slip // past the guard. const canonicalBaseDir = yield* fs.realPath(baseDir).pipe(Effect.orElseSucceed(() => baseDir)); - const canonicalProtectedHomes = yield* Effect.all( - protectedHomes.map((home) => fs.realPath(home).pipe(Effect.orElseSucceed(() => home))), + const canonicalProtectedHomes = yield* Effect.forEach(protectedHomes, (home) => + fs.realPath(home).pipe(Effect.orElseSucceed(() => home)), ); if (canonicalProtectedHomes.includes(canonicalBaseDir)) { return yield* new MigrateDevDbSharedHomeError(); diff --git a/apps/server/scripts/t3-sqlite-state.ts b/apps/server/scripts/t3-sqlite-state.ts index ba663d428e..d030a2a9b6 100644 --- a/apps/server/scripts/t3-sqlite-state.ts +++ b/apps/server/scripts/t3-sqlite-state.ts @@ -204,8 +204,8 @@ export const runSqliteState = Effect.fn("runSqliteState")(function* ( // Compared canonically so a symlink pointing at a protected home cannot // slip past the guard. const canonicalBaseDir = yield* fs.realPath(baseDir); - const canonicalProtectedHomes = yield* Effect.all( - protectedHomes.map((home) => fs.realPath(home).pipe(Effect.orElseSucceed(() => home))), + const canonicalProtectedHomes = yield* Effect.forEach(protectedHomes, (home) => + fs.realPath(home).pipe(Effect.orElseSucceed(() => home)), ); if (canonicalProtectedHomes.includes(canonicalBaseDir)) { return yield* new SqliteStateSharedHomeMutationError(); diff --git a/apps/server/src/assets/AssetAccess.ts b/apps/server/src/assets/AssetAccess.ts index 6612e1cf59..b612991945 100644 --- a/apps/server/src/assets/AssetAccess.ts +++ b/apps/server/src/assets/AssetAccess.ts @@ -190,7 +190,7 @@ const optionOnNotFound = ( effect: Effect.Effect, ): Effect.Effect, PlatformError.PlatformError, R> => effect.pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catchTags({ PlatformError: (error) => error.reason._tag === "NotFound" ? Effect.succeed(Option.none()) : Effect.fail(error), @@ -213,9 +213,9 @@ const resolveCanonicalWorkspaceFile = Effect.fn("AssetAccess.resolveCanonicalWor const fileSystem = yield* FileSystem.FileSystem; const workspacePaths = yield* WorkspacePaths.WorkspacePaths; const resolved = yield* workspacePaths.resolveRelativePathWithinRoot(input).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catchTags({ - WorkspacePathOutsideRootError: () => Effect.succeed(Option.none()), + WorkspacePathOutsideRootError: () => Effect.succeedNone, }), ); if (Option.isNone(resolved)) return null; diff --git a/apps/server/src/assets/NativeAppIconResolver.ts b/apps/server/src/assets/NativeAppIconResolver.ts index 89a6d06360..34299f9514 100644 --- a/apps/server/src/assets/NativeAppIconResolver.ts +++ b/apps/server/src/assets/NativeAppIconResolver.ts @@ -43,10 +43,10 @@ function appFromCacheKey(key: string): ToolActivityNativeAppReference { const existingFile = Effect.fn("NativeAppIconResolver.existingFile")(function* (filePath: string) { const fileSystem = yield* FileSystem.FileSystem; const info = yield* fileSystem.stat(filePath).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catchTags({ PlatformError: (error) => - error.reason._tag === "NotFound" ? Effect.succeed(Option.none()) : Effect.fail(error), + error.reason._tag === "NotFound" ? Effect.succeedNone : Effect.fail(error), }), ); return Option.isSome(info) && info.value.type === "File" ? filePath : null; diff --git a/apps/server/src/auth/PairingGrantStore.test.ts b/apps/server/src/auth/PairingGrantStore.test.ts index 9a093be41c..beb07627c6 100644 --- a/apps/server/src/auth/PairingGrantStore.test.ts +++ b/apps/server/src/auth/PairingGrantStore.test.ts @@ -3,7 +3,6 @@ import { expect, it } from "@effect/vitest"; import * as Duration from "effect/Duration"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; -import * as Option from "effect/Option"; import * as Stream from "effect/Stream"; import * as Queue from "effect/Queue"; import * as TestClock from "effect/testing/TestClock"; @@ -47,10 +46,10 @@ const makePairingGrantStoreTestLayer = ( AuthPairingLinks.AuthPairingLinkRepository, AuthPairingLinks.AuthPairingLinkRepository.of({ create: () => Effect.void, - consumeAvailable: () => Effect.succeed(Option.none()), + consumeAvailable: () => Effect.succeedNone, listActive: () => Effect.succeed([]), revoke: () => Effect.succeed(false), - getByCredential: () => Effect.succeed(Option.none()), + getByCredential: () => Effect.succeedNone, ...overrides, }), ), diff --git a/apps/server/src/auth/ServerSecretStore.ts b/apps/server/src/auth/ServerSecretStore.ts index e936a1f85c..c386f7e51d 100644 --- a/apps/server/src/auth/ServerSecretStore.ts +++ b/apps/server/src/auth/ServerSecretStore.ts @@ -174,7 +174,7 @@ export const make = Effect.gen(function* () { Effect.map((bytes) => Option.some(Uint8Array.from(bytes))), Effect.catch((cause) => cause.reason._tag === "NotFound" - ? Effect.succeed(Option.none()) + ? Effect.succeedNone : Effect.fail( new SecretStoreReadError({ resource: `secret ${name}`, diff --git a/apps/server/src/auth/dpop.ts b/apps/server/src/auth/dpop.ts index a0f439a972..5e026f5842 100644 --- a/apps/server/src/auth/dpop.ts +++ b/apps/server/src/auth/dpop.ts @@ -118,7 +118,7 @@ export const verifyRequestDpopProof = (input: { "environment.dpop.failure_code": mapped.dpopFailureReason, }); } - return yield* Effect.fail(mapped); + return yield* mapped; }), ), ); diff --git a/apps/server/src/checkpointing/CheckpointDiffQuery.test.ts b/apps/server/src/checkpointing/CheckpointDiffQuery.test.ts index 2a57a21acd..7b3327c483 100644 --- a/apps/server/src/checkpointing/CheckpointDiffQuery.test.ts +++ b/apps/server/src/checkpointing/CheckpointDiffQuery.test.ts @@ -90,10 +90,10 @@ describe("CheckpointDiffQuery.layer", () => { getSnapshotSequence: () => Effect.succeed({ snapshotSequence: 0 }), getCounts: () => Effect.succeed({ projectCount: 0, threadCount: 0 }), getEventReplayStats: () => Effect.die("unused"), - getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()), + getActiveProjectByWorkspaceRoot: () => Effect.succeedNone, getProjectShells: () => Effect.die("unused"), - getProjectShellById: () => Effect.succeed(Option.none()), - getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()), + getProjectShellById: () => Effect.succeedNone, + getFirstActiveThreadIdByProjectId: () => Effect.succeedNone, getImportedAgentSessionSources: () => Effect.die("unused"), getThreadCheckpointContext: () => Effect.sync(() => { @@ -114,9 +114,9 @@ describe("CheckpointDiffQuery.layer", () => { }), getThreadRuntimeContext: () => Effect.die("unused"), getTurnStartMessage: () => Effect.die("unused"), - getThreadShellById: () => Effect.succeed(Option.none()), - getThreadDetailById: () => Effect.succeed(Option.none()), - getThreadDetailSnapshot: () => Effect.succeed(Option.none()), + getThreadShellById: () => Effect.succeedNone, + getThreadDetailById: () => Effect.succeedNone, + getThreadDetailSnapshot: () => Effect.succeedNone, searchThreads: () => Effect.succeed({ matches: [] }), }), ), @@ -208,18 +208,18 @@ describe("CheckpointDiffQuery.layer", () => { getSnapshotSequence: () => Effect.succeed({ snapshotSequence: 0 }), getCounts: () => Effect.succeed({ projectCount: 0, threadCount: 0 }), getEventReplayStats: () => Effect.die("unused"), - getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()), + getActiveProjectByWorkspaceRoot: () => Effect.succeedNone, getProjectShells: () => Effect.die("unused"), - getProjectShellById: () => Effect.succeed(Option.none()), - getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()), + getProjectShellById: () => Effect.succeedNone, + getFirstActiveThreadIdByProjectId: () => Effect.succeedNone, getImportedAgentSessionSources: () => Effect.die("unused"), - getThreadCheckpointContext: () => Effect.succeed(Option.some(threadCheckpointContext)), + getThreadCheckpointContext: () => Effect.succeedSome(threadCheckpointContext), getFullThreadDiffContext: () => Effect.die("unused"), getThreadRuntimeContext: () => Effect.die("unused"), getTurnStartMessage: () => Effect.die("unused"), - getThreadShellById: () => Effect.succeed(Option.none()), - getThreadDetailById: () => Effect.succeed(Option.none()), - getThreadDetailSnapshot: () => Effect.succeed(Option.none()), + getThreadShellById: () => Effect.succeedNone, + getThreadDetailById: () => Effect.succeedNone, + getThreadDetailSnapshot: () => Effect.succeedNone, searchThreads: () => Effect.succeed({ matches: [] }), }), ), @@ -301,18 +301,18 @@ describe("CheckpointDiffQuery.layer", () => { getSnapshotSequence: () => Effect.succeed({ snapshotSequence: 0 }), getCounts: () => Effect.succeed({ projectCount: 0, threadCount: 0 }), getEventReplayStats: () => Effect.die("unused"), - getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()), + getActiveProjectByWorkspaceRoot: () => Effect.succeedNone, getProjectShells: () => Effect.die("unused"), - getProjectShellById: () => Effect.succeed(Option.none()), - getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()), + getProjectShellById: () => Effect.succeedNone, + getFirstActiveThreadIdByProjectId: () => Effect.succeedNone, getImportedAgentSessionSources: () => Effect.die("unused"), - getThreadCheckpointContext: () => Effect.succeed(Option.some(threadCheckpointContext)), + getThreadCheckpointContext: () => Effect.succeedSome(threadCheckpointContext), getFullThreadDiffContext: () => Effect.die("unused"), getThreadRuntimeContext: () => Effect.die("unused"), getTurnStartMessage: () => Effect.die("unused"), - getThreadShellById: () => Effect.succeed(Option.none()), - getThreadDetailById: () => Effect.succeed(Option.none()), - getThreadDetailSnapshot: () => Effect.succeed(Option.none()), + getThreadShellById: () => Effect.succeedNone, + getThreadDetailById: () => Effect.succeedNone, + getThreadDetailSnapshot: () => Effect.succeedNone, searchThreads: () => Effect.succeed({ matches: [] }), }), ), @@ -379,18 +379,18 @@ describe("CheckpointDiffQuery.layer", () => { getSnapshotSequence: () => Effect.succeed({ snapshotSequence: 0 }), getCounts: () => Effect.succeed({ projectCount: 0, threadCount: 0 }), getEventReplayStats: () => Effect.die("unused"), - getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()), + getActiveProjectByWorkspaceRoot: () => Effect.succeedNone, getProjectShells: () => Effect.die("unused"), - getProjectShellById: () => Effect.succeed(Option.none()), - getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()), + getProjectShellById: () => Effect.succeedNone, + getFirstActiveThreadIdByProjectId: () => Effect.succeedNone, getImportedAgentSessionSources: () => Effect.die("unused"), - getThreadCheckpointContext: () => Effect.succeed(Option.some(threadCheckpointContext)), + getThreadCheckpointContext: () => Effect.succeedSome(threadCheckpointContext), getFullThreadDiffContext: () => Effect.die("unused"), getThreadRuntimeContext: () => Effect.die("unused"), getTurnStartMessage: () => Effect.die("unused"), - getThreadShellById: () => Effect.succeed(Option.none()), - getThreadDetailById: () => Effect.succeed(Option.none()), - getThreadDetailSnapshot: () => Effect.succeed(Option.none()), + getThreadShellById: () => Effect.succeedNone, + getThreadDetailById: () => Effect.succeedNone, + getThreadDetailSnapshot: () => Effect.succeedNone, searchThreads: () => Effect.succeed({ matches: [] }), }), ), @@ -442,18 +442,18 @@ describe("CheckpointDiffQuery.layer", () => { getSnapshotSequence: () => Effect.succeed({ snapshotSequence: 0 }), getCounts: () => Effect.succeed({ projectCount: 0, threadCount: 0 }), getEventReplayStats: () => Effect.die("unused"), - getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()), + getActiveProjectByWorkspaceRoot: () => Effect.succeedNone, getProjectShells: () => Effect.die("unused"), - getProjectShellById: () => Effect.succeed(Option.none()), - getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()), + getProjectShellById: () => Effect.succeedNone, + getFirstActiveThreadIdByProjectId: () => Effect.succeedNone, getImportedAgentSessionSources: () => Effect.die("unused"), - getThreadCheckpointContext: () => Effect.succeed(Option.none()), - getFullThreadDiffContext: () => Effect.succeed(Option.none()), + getThreadCheckpointContext: () => Effect.succeedNone, + getFullThreadDiffContext: () => Effect.succeedNone, getThreadRuntimeContext: () => Effect.die("unused"), getTurnStartMessage: () => Effect.die("unused"), - getThreadShellById: () => Effect.succeed(Option.none()), - getThreadDetailById: () => Effect.succeed(Option.none()), - getThreadDetailSnapshot: () => Effect.succeed(Option.none()), + getThreadShellById: () => Effect.succeedNone, + getThreadDetailById: () => Effect.succeedNone, + getThreadDetailSnapshot: () => Effect.succeedNone, searchThreads: () => Effect.succeed({ matches: [] }), }), ), diff --git a/apps/server/src/cli/theme.ts b/apps/server/src/cli/theme.ts index 4e9e54e7fc..342d715e10 100644 --- a/apps/server/src/cli/theme.ts +++ b/apps/server/src/cli/theme.ts @@ -260,12 +260,10 @@ const writeDefaultTheme = Effect.fn(function* (input: { // Falling through here would overwrite whatever landed in between, which // is exactly the loss this loop exists to prevent. if (attempt >= CONCURRENT_WRITE_ATTEMPTS) { - return yield* Effect.fail( - new ThemeSettingsBusyError({ - settingsPath: input.settingsPath, - attempts: CONCURRENT_WRITE_ATTEMPTS, - }), - ); + return yield* new ThemeSettingsBusyError({ + settingsPath: input.settingsPath, + attempts: CONCURRENT_WRITE_ATTEMPTS, + }); } continue; } @@ -299,12 +297,13 @@ const publishThemeFile = Effect.fn(function* (input: { Effect.mapError((cause) => new ThemeFileUnreadableError({ filePath: input.filePath, cause })), ); if (info.type !== "File") { - return yield* Effect.fail(new ThemeFileUnreadableError({ filePath: input.filePath })); + return yield* new ThemeFileUnreadableError({ filePath: input.filePath }); } if (Number(info.size) > MAX_THEME_FILE_BYTES) { - return yield* Effect.fail( - new ThemeFileTooLargeError({ filePath: input.filePath, limit: MAX_THEME_FILE_BYTES }), - ); + return yield* new ThemeFileTooLargeError({ + filePath: input.filePath, + limit: MAX_THEME_FILE_BYTES, + }); } // An explicit source path is the user's own input, and a symlink there is a @@ -320,17 +319,15 @@ const publishThemeFile = Effect.fn(function* (input: { ); const raw = readThemeFileGuarded(resolvedSource, MAX_THEME_FILE_BYTES); if (raw === null) { - return yield* Effect.fail(new ThemeFileUnreadableError({ filePath: input.filePath })); + return yield* new ThemeFileUnreadableError({ filePath: input.filePath }); } const decoded = decodeThemeFileJsonExit(raw); if (decoded._tag === "Failure") { - return yield* Effect.fail( - new ThemeFileInvalidError({ filePath: input.filePath, cause: decoded.cause }), - ); + return yield* new ThemeFileInvalidError({ filePath: input.filePath, cause: decoded.cause }); } if (!environmentThemeFileHasColors(decoded.value)) { - return yield* Effect.fail(new ThemeFileColorlessError({ filePath: input.filePath })); + return yield* new ThemeFileColorlessError({ filePath: input.filePath }); } const fileBasename = path.basename(input.filePath, ".json"); @@ -338,7 +335,7 @@ const publishThemeFile = Effect.fn(function* (input: { // The same rules the watcher applies when it reads the directory back, so a // publish cannot report success for a file that will then be skipped. if (!isEnvironmentThemeId(themeId) || UNPUBLISHABLE_THEME_IDS.has(themeId)) { - return yield* Effect.fail(new ThemeFileIdInvalidError({ themeId, filePath: input.filePath })); + return yield* new ThemeFileIdInvalidError({ themeId, filePath: input.filePath }); } const destinationPath = path.join(input.themesDir, `${themeId}.json`); @@ -479,7 +476,7 @@ const themeSetCommand = Command.make("set", { const fs = yield* FileSystem.FileSystem; const target = yield* expandHomePath(flags.theme.trim()); if (target.length === 0) { - return yield* Effect.fail(new ThemeTargetMissingError()); + return yield* new ThemeTargetMissingError(); } const paths = yield* resolveThemePaths(flags.baseDir); @@ -514,15 +511,15 @@ const themeSetCommand = Command.make("set", { revertPublish = published.revert; cleanupPublish = published.cleanup; } else if (looksLikePath) { - return yield* Effect.fail(new ThemeFileUnreadableError({ filePath: target })); + return yield* new ThemeFileUnreadableError({ filePath: target }); } else if (isEnvironmentThemeId(target)) { const known = yield* resolvableThemeIds(paths.themesDir); if (!known.includes(target)) { - return yield* Effect.fail(new ThemeIdUnknownError({ themeId: target, known })); + return yield* new ThemeIdUnknownError({ themeId: target, known }); } themeId = target; } else { - return yield* Effect.fail(new ThemeIdInvalidError({ themeId: target })); + return yield* new ThemeIdInvalidError({ themeId: target }); } // set means set: if the default cannot be written, the publish that diff --git a/apps/server/src/cloud/ManagedEndpointRuntime.test.ts b/apps/server/src/cloud/ManagedEndpointRuntime.test.ts index ba2cf5c5ac..d43db4c5c4 100644 --- a/apps/server/src/cloud/ManagedEndpointRuntime.test.ts +++ b/apps/server/src/cloud/ManagedEndpointRuntime.test.ts @@ -5,7 +5,6 @@ import * as Duration from "effect/Duration"; import * as Effect from "effect/Effect"; import * as Fiber from "effect/Fiber"; import * as Layer from "effect/Layer"; -import * as Option from "effect/Option"; import * as PlatformError from "effect/PlatformError"; import * as Sink from "effect/Sink"; import * as Stream from "effect/Stream"; @@ -38,7 +37,7 @@ const runtimeDependencies = ( Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner), relayClientLayer, Layer.mock(ServerSecretStore.ServerSecretStore)({ - get: () => Effect.succeed(Option.none()), + get: () => Effect.succeedNone, }), ); diff --git a/apps/server/src/cloud/http.test.ts b/apps/server/src/cloud/http.test.ts index d4c23c1f3a..481213e3a1 100644 --- a/apps/server/src/cloud/http.test.ts +++ b/apps/server/src/cloud/http.test.ts @@ -231,7 +231,7 @@ describe("reconcileDesiredCloudLink", () => { CliTokenManager.CloudCliTokenManager, CliTokenManager.CloudCliTokenManager.of({ get: unusedSecretStoreOperation(), - getExisting: Effect.succeed(Option.none()), + getExisting: Effect.succeedNone, hasCredential: unusedSecretStoreOperation(), store: () => unusedSecretStoreOperation(), clear: unusedSecretStoreOperation(), @@ -345,7 +345,7 @@ describe("releaseManagedTunnelOnShutdown", () => { CliTokenManager.CloudCliTokenManager, CliTokenManager.CloudCliTokenManager.of({ get: unusedSecretStoreOperation(), - getExisting: Effect.succeed(Option.some(cliToken)), + getExisting: Effect.succeedSome(cliToken), hasCredential: unusedSecretStoreOperation(), store: () => unusedSecretStoreOperation(), clear: unusedSecretStoreOperation(), diff --git a/apps/server/src/cloud/http.ts b/apps/server/src/cloud/http.ts index 7f27a92408..68324db22f 100644 --- a/apps/server/src/cloud/http.ts +++ b/apps/server/src/cloud/http.ts @@ -152,8 +152,9 @@ export function consumeCloudReplayGuards(input: { readonly names: ReadonlyArray; readonly value: Uint8Array; }) { - return Effect.all( - input.names.map((name) => + return Effect.forEach( + input.names, + (name) => input.secrets.create(name, input.value).pipe( Effect.as(true), Effect.catchIf(ServerSecretStore.isSecretStoreError, (error) => @@ -162,7 +163,6 @@ export function consumeCloudReplayGuards(input: { : Effect.fail(error), ), ), - ), { concurrency: input.names.length }, ).pipe(Effect.map((created) => created.every(Boolean))); } diff --git a/apps/server/src/cloud/selfUpdate.test.ts b/apps/server/src/cloud/selfUpdate.test.ts index e6d8010f19..a32ec6a419 100644 --- a/apps/server/src/cloud/selfUpdate.test.ts +++ b/apps/server/src/cloud/selfUpdate.test.ts @@ -84,7 +84,7 @@ const makeHarness = Effect.fn("test.make_self_update_harness")(function* ( order.push("accept"); return "launcher-id"; })), - prepareTrial: Effect.sync((): undefined => undefined), + prepareTrial: Effect.undefined, }); const config = yield* ServerConfig.ServerConfig.pipe( Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)), diff --git a/apps/server/src/desktopUpdate/DesktopAppUpdate.ts b/apps/server/src/desktopUpdate/DesktopAppUpdate.ts index e9da15a299..a574eb26fb 100644 --- a/apps/server/src/desktopUpdate/DesktopAppUpdate.ts +++ b/apps/server/src/desktopUpdate/DesktopAppUpdate.ts @@ -106,7 +106,7 @@ export const make = Effect.fn("desktopUpdate.desktopAppUpdate.make")(function* ( ? emitStage(desktopUpdateProgressStage(report.state)).pipe( Effect.as(Option.none()), ) - : Effect.succeed(Option.some(report)), + : Effect.succeedSome(report), ), Stream.filterMap( Option.match({ diff --git a/apps/server/src/device/DeviceHubProxy.ts b/apps/server/src/device/DeviceHubProxy.ts index 8ddcf6132d..ac65538980 100644 --- a/apps/server/src/device/DeviceHubProxy.ts +++ b/apps/server/src/device/DeviceHubProxy.ts @@ -130,7 +130,7 @@ const proxyWebSocket = Effect.fn("DeviceHubProxy.proxyWebSocket")(function* ( const upstream = yield* Socket.makeWebSocket(upstreamUrl, { openTimeout: "10 seconds", }).pipe(Effect.provide(NodeSocket.layerWebSocketConstructor)); - yield* relayWebSocketFrames(client, upstream).pipe(Effect.catchCause(() => Effect.void)); + yield* relayWebSocketFrames(client, upstream).pipe(Effect.ignoreCause); return HttpServerResponse.empty(); }); diff --git a/apps/server/src/device/DeviceService.ts b/apps/server/src/device/DeviceService.ts index 07ffeded90..2de69fd3a0 100644 --- a/apps/server/src/device/DeviceService.ts +++ b/apps/server/src/device/DeviceService.ts @@ -917,13 +917,11 @@ export const makeWithHosts = Effect.fn("DeviceService.makeWithHosts")(function* lifecycleLock.withPermit( Effect.gen(function* () { if (!installTool) - return yield* Effect.fail( - new DeviceOperationError({ - operation: "update device tool", - reason: "request_failed", - cause: new Error("Tool installation is unavailable in this device service."), - }), - ); + return yield* new DeviceOperationError({ + operation: "update device tool", + reason: "request_failed", + cause: new Error("Tool installation is unavailable in this device service."), + }); yield* installTool(tool); return yield* inspect; }), diff --git a/apps/server/src/device/LocalDeviceHost.ts b/apps/server/src/device/LocalDeviceHost.ts index 139034a178..839a761938 100644 --- a/apps/server/src/device/LocalDeviceHost.ts +++ b/apps/server/src/device/LocalDeviceHost.ts @@ -321,7 +321,7 @@ export const make = Effect.fn("LocalDeviceHost.make")(function* () { } } yield* fs.remove(hubStatePath(), { force: true }).pipe(Effect.ignore); - }).pipe(Effect.catchCause(() => Effect.void)); + }).pipe(Effect.ignoreCause); const recordHub = (hub: HubProcess, hubTool: DeviceToolPaths) => encodeHubStateFile({ @@ -422,7 +422,7 @@ export const make = Effect.fn("LocalDeviceHost.make")(function* () { Stream.runForEach((line) => Effect.logDebug("Device hub output", { pid: Number(hub.child.pid), output: line }), ), - Effect.catchCause(() => Effect.void), + Effect.ignoreCause, ); /** diff --git a/apps/server/src/environment/ServerEnvironment.test.ts b/apps/server/src/environment/ServerEnvironment.test.ts index 71f228b3dc..99f7f888d0 100644 --- a/apps/server/src/environment/ServerEnvironment.test.ts +++ b/apps/server/src/environment/ServerEnvironment.test.ts @@ -6,7 +6,6 @@ import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Layer from "effect/Layer"; -import * as Option from "effect/Option"; import * as PlatformError from "effect/PlatformError"; import * as Schema from "effect/Schema"; @@ -35,7 +34,7 @@ const makeServerEnvironmentLayer = (baseDir: string) => const emptySecretStoreLayer = Layer.succeed( ServerSecretStore.ServerSecretStore, ServerSecretStore.ServerSecretStore.of({ - get: () => Effect.succeed(Option.none()), + get: () => Effect.succeedNone, set: () => Effect.void, create: () => Effect.void, getOrCreateRandom: () => Effect.succeed(new Uint8Array()), diff --git a/apps/server/src/environment/ServerEnvironment.ts b/apps/server/src/environment/ServerEnvironment.ts index 33ce952e8c..9c1a765fe5 100644 --- a/apps/server/src/environment/ServerEnvironment.ts +++ b/apps/server/src/environment/ServerEnvironment.ts @@ -127,13 +127,12 @@ const makeIdentity = Effect.gen(function* () { }); yield* fileSystem.writeFileString(tempPath, `${value}\n`); // Publish the completed file without replacing an ID created by another process. - yield* fileSystem - .link(tempPath, destinationPath) - .pipe( - Effect.catch((cause) => - cause.reason._tag === "AlreadyExists" ? Effect.void : Effect.fail(cause), - ), - ); + yield* fileSystem.link(tempPath, destinationPath).pipe( + Effect.catchIf( + (cause) => cause.reason._tag === "AlreadyExists", + () => Effect.void, + ), + ); if (mode === "recover") { // Keep the recovery ID so delayed initializers also publish the same winner. yield* fileSystem.remove(tempPath); diff --git a/apps/server/src/environment/ServerEnvironmentLabel.ts b/apps/server/src/environment/ServerEnvironmentLabel.ts index 1d94449233..4a5d0a009b 100644 --- a/apps/server/src/environment/ServerEnvironmentLabel.ts +++ b/apps/server/src/environment/ServerEnvironmentLabel.ts @@ -128,7 +128,7 @@ const runFriendlyLabelCommand = Effect.fn("runFriendlyLabelCommand")(function* ( cause, }), ), - Effect.map(Option.some), + Effect.asSome, Effect.catchTags({ ServerEnvironmentLabelCommandError: (error) => Effect.logDebug(error.message).pipe( diff --git a/apps/server/src/environment/ServerEnvironmentMachine.ts b/apps/server/src/environment/ServerEnvironmentMachine.ts index 9d11a1ef59..e9f5e51af6 100644 --- a/apps/server/src/environment/ServerEnvironmentMachine.ts +++ b/apps/server/src/environment/ServerEnvironmentMachine.ts @@ -107,7 +107,7 @@ const readOptionalFile = Effect.fn("readOptionalFile")(function* (path: string) const fileSystem = yield* FileSystem.FileSystem; return yield* fileSystem.readFileString(path).pipe( Effect.map(normalize), - Effect.catch(() => Effect.succeed(null)), + Effect.orElseSucceed(() => null), ); }); @@ -125,7 +125,7 @@ const runProbe = Effect.fn("runMachineProbe")(function* (input: { }) .pipe( Effect.map((result) => (result.code === 0 ? normalize(result.stdout) : null)), - Effect.catch(() => Effect.succeed(null)), + Effect.orElseSucceed(() => null), ); }); diff --git a/apps/server/src/git/GitManager.ts b/apps/server/src/git/GitManager.ts index 06a21f1400..8d10c42bc6 100644 --- a/apps/server/src/git/GitManager.ts +++ b/apps/server/src/git/GitManager.ts @@ -2166,7 +2166,7 @@ export const make = Effect.gen(function* () { title: generated.title, bodyFile, }) - .pipe(Effect.ensuring(fileSystem.remove(bodyFile).pipe(Effect.catch(() => Effect.void)))); + .pipe(Effect.ensuring(fileSystem.remove(bodyFile).pipe(Effect.ignore))); const created = yield* findOpenPr(cwd, headContext); if (!created) { diff --git a/apps/server/src/git/linkCreatedPullRequest.test.ts b/apps/server/src/git/linkCreatedPullRequest.test.ts index 2c33d82792..2e8be05feb 100644 --- a/apps/server/src/git/linkCreatedPullRequest.test.ts +++ b/apps/server/src/git/linkCreatedPullRequest.test.ts @@ -83,7 +83,7 @@ const makeDependencies = ( Layer.mergeAll( Layer.mock(ProjectionSnapshotQuery)({ getThreadShellById: () => Effect.succeed(Option.fromNullishOr(threadShell)), - getProjectShellById: () => Effect.succeed(Option.some(project)), + getProjectShellById: () => Effect.succeedSome(project), }), Layer.mock(OrchestrationEngineService)({ readEvents: () => Stream.empty, diff --git a/apps/server/src/keybindings.test.ts b/apps/server/src/keybindings.test.ts index fcd567b267..82cfc9f7d2 100644 --- a/apps/server/src/keybindings.test.ts +++ b/apps/server/src/keybindings.test.ts @@ -683,13 +683,13 @@ it.layer(NodeServices.layer)("keybindings", (it) => { ); yield* Effect.gen(function* () { const keybindings = yield* Keybindings.Keybindings; - yield* Effect.all( - commands.map((command, index) => + yield* Effect.forEach( + commands, + (command, index) => keybindings.upsertKeybindingRule({ key: `mod+${String.fromCharCode(97 + index)}`, command, }), - ), { concurrency: "unbounded", discard: true }, ); }); diff --git a/apps/server/src/mcp/McpHttpServer.test.ts b/apps/server/src/mcp/McpHttpServer.test.ts index 8f7da50383..3de7741e0b 100644 --- a/apps/server/src/mcp/McpHttpServer.test.ts +++ b/apps/server/src/mcp/McpHttpServer.test.ts @@ -6,7 +6,6 @@ import * as Deferred from "effect/Deferred"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Layer from "effect/Layer"; -import * as Option from "effect/Option"; import * as Path from "effect/Path"; import * as Schema from "effect/Schema"; import * as Stream from "effect/Stream"; @@ -60,7 +59,7 @@ const PullRequestsTestLayer = McpHttpServer.PullRequestsToolkitRegistrationLive. Layer.provide( Layer.mergeAll( Layer.mock(ProjectionSnapshotQuery)({ - getThreadShellById: () => Effect.succeed(Option.none()), + getThreadShellById: () => Effect.succeedNone, }), Layer.mock(OrchestrationEngineService)({}), NodeServices.layer, diff --git a/apps/server/src/mcp/McpInvocationContext.ts b/apps/server/src/mcp/McpInvocationContext.ts index c3a8e5d3c0..e6d11909e4 100644 --- a/apps/server/src/mcp/McpInvocationContext.ts +++ b/apps/server/src/mcp/McpInvocationContext.ts @@ -47,9 +47,11 @@ const missingCapability = ( export const requireMcpCapability = ( capability: C, ): Effect.Effect, McpInvocationContext> => - Effect.flatMap(McpInvocationContext, (invocation) => - invocation.capabilities.has(capability) - ? Effect.succeed(invocation) - : // The conditional type narrows what the literal argument decided at runtime. - Effect.fail(missingCapability(invocation, capability) as McpCapabilityError), - ).pipe(Effect.withSpan("mcp.requireCapability")); + McpInvocationContext.pipe( + Effect.filterOrFail( + (invocation) => invocation.capabilities.has(capability), + // The conditional type narrows what the literal argument decided at runtime. + (invocation) => missingCapability(invocation, capability) as McpCapabilityError, + ), + Effect.withSpan("mcp.requireCapability"), + ); diff --git a/apps/server/src/mcp/McpSessionRegistry.ts b/apps/server/src/mcp/McpSessionRegistry.ts index bfc057a831..6144aae826 100644 --- a/apps/server/src/mcp/McpSessionRegistry.ts +++ b/apps/server/src/mcp/McpSessionRegistry.ts @@ -304,7 +304,7 @@ export const issueActiveMcpCredential = ( ): Effect.Effect => activeMcpSessionRegistry ? activeMcpSessionRegistry.issueIfCurrent(request, isCurrent) - : Effect.sync((): McpIssuedCredential | undefined => undefined); + : Effect.undefined; export const revokeActiveMcpProviderSession = (providerSessionId: string): Effect.Effect => activeMcpSessionRegistry diff --git a/apps/server/src/mcp/toolkits/preview/handlers.ts b/apps/server/src/mcp/toolkits/preview/handlers.ts index 9a7ab49f81..76935affdd 100644 --- a/apps/server/src/mcp/toolkits/preview/handlers.ts +++ b/apps/server/src/mcp/toolkits/preview/handlers.ts @@ -88,7 +88,7 @@ const invoke = Effect.fn("PreviewToolkit.invoke")(function* ( updateCurrentTab: false, ...(statusTabId === undefined ? {} : { tabId: statusTabId }), }) - .pipe(Effect.catch(() => Effect.succeed(null))); + .pipe(Effect.orElseSucceed(() => null)); return { result, ...(page?.url && /^https?:\/\//i.test(page.url) && page.url.length <= 4096 @@ -197,10 +197,11 @@ export const claimPreviewRecording = Effect.fn("PreviewToolkit.claimRecording")( yield* fileSystem.rename(currentPath, finalPath); }).pipe( // Another stop may already have claimed this exact upload for this thread. - Effect.catch((cause) => - cause._tag !== "PreviewAutomationRecordingTransferError" && cause.reason._tag === "NotFound" - ? validateFile(finalPath) - : Effect.fail(cause), + Effect.catchIf( + (cause) => + cause._tag !== "PreviewAutomationRecordingTransferError" && + cause.reason._tag === "NotFound", + () => validateFile(finalPath), ), Effect.mapError((cause) => new PreviewAutomationRecordingTransferError({ threadId, cause })), ); diff --git a/apps/server/src/orchestration/Layers/CheckpointReactor.test.ts b/apps/server/src/orchestration/Layers/CheckpointReactor.test.ts index 52767d799f..fa5bc853e6 100644 --- a/apps/server/src/orchestration/Layers/CheckpointReactor.test.ts +++ b/apps/server/src/orchestration/Layers/CheckpointReactor.test.ts @@ -354,7 +354,7 @@ describe("CheckpointReactor", () => { options?.conversationRollback ?? "relative", ); const historicalRollbackEvents = Effect.runSync(PubSub.unbounded()); - const historicalRollbackReady = Effect.runSync(Deferred.make()); + const historicalRollbackReady = Deferred.makeUnsafe(); const orchestrationLayer = OrchestrationEngineLive.pipe( Layer.provide(OrchestrationProjectionSnapshotQueryLive), Layer.provide(ThreadBackgroundLiveness.layer), diff --git a/apps/server/src/orchestration/Layers/CheckpointReactor.ts b/apps/server/src/orchestration/Layers/CheckpointReactor.ts index ef3d211311..c5614459a4 100644 --- a/apps/server/src/orchestration/Layers/CheckpointReactor.ts +++ b/apps/server/src/orchestration/Layers/CheckpointReactor.ts @@ -146,12 +146,12 @@ export const make = Effect.gen(function* () { const entryRefreshWorker = yield* makeDrainableWorker((cwd: string) => Effect.sync(() => queuedEntryRefreshes.delete(cwd)).pipe( Effect.andThen(workspaceEntries.refresh(cwd)), - Effect.catchCause((cause) => - Cause.hasInterruptsOnly(cause) - ? Effect.failCause(cause) - : Effect.logWarning("failed to refresh checkpoint workspace entries", { - failureKind: "workspace-entry-refresh", - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + () => + Effect.logWarning("failed to refresh checkpoint workspace entries", { + failureKind: "workspace-entry-refresh", + }), ), ), ); @@ -768,15 +768,14 @@ export const make = Effect.gen(function* () { branch: checkedOutBranch, }); }).pipe( - Effect.catchCause((cause) => { - if (Cause.hasInterruptsOnly(cause)) { - return Effect.failCause(cause); - } - return Effect.logWarning("failed to follow worktree branch drift", { - threadId: input.threadId, - failureKind: "unexpected", - }); - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + () => + Effect.logWarning("failed to follow worktree branch drift", { + threadId: input.threadId, + failureKind: "unexpected", + }), + ), ); }); @@ -786,13 +785,13 @@ export const make = Effect.gen(function* () { const statusRefreshWorker = yield* makeDrainableWorker( (event: Extract) => refreshLocalGitStatusFromTurnCompletion(event).pipe( - Effect.catchCause((cause) => - Cause.hasInterruptsOnly(cause) - ? Effect.failCause(cause) - : Effect.logWarning("failed to refresh git status after turn completion", { - threadId: event.threadId, - failureKind: "unexpected", - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + () => + Effect.logWarning("failed to refresh git status after turn completion", { + threadId: event.threadId, + failureKind: "unexpected", + }), ), ), ); @@ -900,13 +899,12 @@ export const make = Effect.gen(function* () { paths.add(session.cwd); } for (const candidate of paths) { - const otherCwd = yield* fileSystem - .realPath(candidate) - .pipe( - Effect.catch((error) => - error.reason._tag === "NotFound" ? Effect.succeed(null) : Effect.fail(error), - ), - ); + const otherCwd = yield* fileSystem.realPath(candidate).pipe( + Effect.catchIf( + (error) => error.reason._tag === "NotFound", + () => Effect.succeed(null), + ), + ); if (otherCwd === null) continue; const isWithin = (parent: string, child: string) => { const relative = path.relative(parent, child); @@ -1121,16 +1119,15 @@ export const make = Effect.gen(function* () { const processInputSafely = (input: ReactorInput) => processInput(input).pipe( - Effect.catchCause((cause) => { - if (Cause.hasInterruptsOnly(cause)) { - return Effect.failCause(cause); - } - return Effect.logWarning("checkpoint reactor failed to process input", { - source: input.source, - eventType: input.source === "saga" ? "rollback.saga.reconcile" : input.event.type, - failureKind: input.source === "saga" ? "rollback-saga" : "unexpected", - }); - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + () => + Effect.logWarning("checkpoint reactor failed to process input", { + source: input.source, + eventType: input.source === "saga" ? "rollback.saga.reconcile" : input.event.type, + failureKind: input.source === "saga" ? "rollback-saga" : "unexpected", + }), + ), ); const worker = yield* makeDrainableWorker(processInputSafely); diff --git a/apps/server/src/orchestration/Layers/OrchestrationEngine.test.ts b/apps/server/src/orchestration/Layers/OrchestrationEngine.test.ts index 96d0c01230..2520cec5cb 100644 --- a/apps/server/src/orchestration/Layers/OrchestrationEngine.test.ts +++ b/apps/server/src/orchestration/Layers/OrchestrationEngine.test.ts @@ -632,18 +632,18 @@ describe("OrchestrationEngine", () => { Effect.succeed({ snapshotSequence: projectionSnapshot.snapshotSequence }), getCounts: () => Effect.succeed({ projectCount: 1, threadCount: 1 }), getEventReplayStats: () => Effect.die("unused"), - getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()), - getProjectShellById: () => Effect.succeed(Option.none()), + getActiveProjectByWorkspaceRoot: () => Effect.succeedNone, + getProjectShellById: () => Effect.succeedNone, getProjectShells: () => Effect.succeed([]), - getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()), + getFirstActiveThreadIdByProjectId: () => Effect.succeedNone, getImportedAgentSessionSources: () => Effect.die("unused"), - getThreadCheckpointContext: () => Effect.succeed(Option.none()), - getFullThreadDiffContext: () => Effect.succeed(Option.none()), + getThreadCheckpointContext: () => Effect.succeedNone, + getFullThreadDiffContext: () => Effect.succeedNone, getThreadRuntimeContext: () => Effect.die("unused"), getTurnStartMessage: () => Effect.die("unused"), - getThreadShellById: () => Effect.succeed(Option.none()), - getThreadDetailById: () => Effect.succeed(Option.none()), - getThreadDetailSnapshot: () => Effect.succeed(Option.none()), + getThreadShellById: () => Effect.succeedNone, + getThreadDetailById: () => Effect.succeedNone, + getThreadDetailSnapshot: () => Effect.succeedNone, searchThreads: () => Effect.succeed({ matches: [] }), }), ), diff --git a/apps/server/src/orchestration/Layers/OrchestrationEngine.ts b/apps/server/src/orchestration/Layers/OrchestrationEngine.ts index 2dc989779e..12e981958c 100644 --- a/apps/server/src/orchestration/Layers/OrchestrationEngine.ts +++ b/apps/server/src/orchestration/Layers/OrchestrationEngine.ts @@ -649,7 +649,7 @@ const makeOrchestrationEngine = Effect.gen(function* () { status: "rejected", error: error.message, }) - .pipe(Effect.catch(() => Effect.void)); + .pipe(Effect.ignore); } } diff --git a/apps/server/src/orchestration/Layers/ProjectionPipeline.ts b/apps/server/src/orchestration/Layers/ProjectionPipeline.ts index e82e67d529..7f88b43c98 100644 --- a/apps/server/src/orchestration/Layers/ProjectionPipeline.ts +++ b/apps/server/src/orchestration/Layers/ProjectionPipeline.ts @@ -2483,6 +2483,7 @@ const makeOrchestrationProjectionPipeline = Effect.fn("makeOrchestrationProjecti updatedAt: event.occurredAt, }; } + // @effect-diagnostics-next-line returnEffectInGen:off - the caller runs the returned cleanup effect after the transaction; nothing to clean up here return Effect.void; } // Return the cleanup effect so the caller runs it after the outer transaction commits. diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts index a6477fb216..2abc3a33a5 100644 --- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts +++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts @@ -648,14 +648,14 @@ const make = Effect.gen(function* () { Effect.andThen( gitWorkflow.createWorktree({ cwd, refName: branch, path: worktreePath }, { submodules }), ), - Effect.catchCause((cause) => - Cause.hasInterruptsOnly(cause) - ? Effect.failCause(cause) - : Effect.logWarning("provider command reactor failed to recreate worktree", { - threadId: thread.id, - worktreePath, - cause: Cause.pretty(cause), - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + (cause) => + Effect.logWarning("provider command reactor failed to recreate worktree", { + threadId: thread.id, + worktreePath, + cause: Cause.pretty(cause), + }), ), ); }); @@ -1633,16 +1633,15 @@ const make = Effect.gen(function* () { return; } const result = yield* regenerateThreadTitle(event, requestId).pipe( - Effect.catchCause((cause) => { - if (Cause.hasInterruptsOnly(cause)) { - return Effect.failCause(cause); - } - return Effect.logWarning("provider command reactor failed to regenerate thread title", { - threadId: event.payload.threadId, - failureKind: Cause.hasDies(cause) ? "defect" : "failure", - reasonCount: cause.reasons.length, - }).pipe(Effect.as({ _tag: "Completed", title: undefined } as const)); - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + (cause) => + Effect.logWarning("provider command reactor failed to regenerate thread title", { + threadId: event.payload.threadId, + failureKind: Cause.hasDies(cause) ? "defect" : "failure", + reasonCount: cause.reasons.length, + }).pipe(Effect.as({ _tag: "Completed", title: undefined } as const)), + ), ); if (result._tag === "Superseded") { return; @@ -1654,36 +1653,28 @@ const make = Effect.gen(function* () { ...(result.title !== undefined ? { title: result.title } : {}), }; yield* dispatchThreadTitleRegenerationCompletion(completion).pipe( - Effect.catchCause((cause) => { - if (Cause.hasInterruptsOnly(cause)) { - return Effect.failCause(cause); - } - return Effect.logWarning( - "provider command reactor retrying title regeneration completion", - { + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + (cause) => + Effect.logWarning("provider command reactor retrying title regeneration completion", { threadId: event.payload.threadId, failureKind: Cause.hasDies(cause) ? "defect" : "failure", reasonCount: cause.reasons.length, - }, - ).pipe(Effect.andThen(dispatchThreadTitleRegenerationCompletion(completion))); - }), + }).pipe(Effect.andThen(dispatchThreadTitleRegenerationCompletion(completion))), + ), ); }, (effect, event) => effect.pipe( - Effect.catchCause((cause) => { - if (Cause.hasInterruptsOnly(cause)) { - return Effect.failCause(cause); - } - return Effect.logWarning( - "provider command reactor failed to complete title regeneration", - { + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + (cause) => + Effect.logWarning("provider command reactor failed to complete title regeneration", { threadId: event.payload.threadId, failureKind: Cause.hasDies(cause) ? "defect" : "failure", reasonCount: cause.reasons.length, - }, - ); - }), + }), + ), ), ); const threadTitleRegenerationWorker = yield* makeDrainableWorker( diff --git a/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts b/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts index b3904ce182..691554c5fc 100644 --- a/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts +++ b/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts @@ -3475,17 +3475,16 @@ const make = Effect.gen(function* () { (source: string, event: { readonly eventId: string; readonly type: string }) => (effect: Effect.Effect) => effect.pipe( - Effect.catchCause((cause) => { - if (Cause.hasInterruptsOnly(cause)) { - return Effect.failCause(cause); - } - return Effect.logWarning("provider runtime ingestion failed to process event", { - source, - eventId: event.eventId, - eventType: event.type, - cause: Cause.pretty(cause), - }); - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + (cause) => + Effect.logWarning("provider runtime ingestion failed to process event", { + source, + eventId: event.eventId, + eventType: event.type, + cause: Cause.pretty(cause), + }), + ), ); const worker = yield* makeDrainableWorker((input: RuntimeIngestionInput) => diff --git a/apps/server/src/orchestration/Layers/RollbackAdmissionAtomic.test.ts b/apps/server/src/orchestration/Layers/RollbackAdmissionAtomic.test.ts index 1f53338972..09d535ce5e 100644 --- a/apps/server/src/orchestration/Layers/RollbackAdmissionAtomic.test.ts +++ b/apps/server/src/orchestration/Layers/RollbackAdmissionAtomic.test.ts @@ -46,43 +46,41 @@ const privateCanary = "PRIVATE_ATOMIC_TARGET_CANARY"; const admission = Layer.succeed(RollbackAdmission, { prepare: ({ requestEventId, command }) => - Effect.succeed( - Option.some({ - operationId, - requestEventId, - threadId, - projectId, - workspaceKey: "workspace-atomic", - workspaceCwd: "/workspace/atomic", - sourceRevision: 2, - targetRevision: 1, - ...(command.type === "thread.conversation.revert" ? { restoreFiles: false } : {}), - sourceTurnId: null, - targetTurnId: null, - sourceCheckpointRef: checkpointRefForThreadTurn(threadId, 2), - sourceCheckpointOid: "2".repeat(40), - targetCheckpointRef: checkpointRefForThreadTurn(threadId, 1), - targetCheckpointOid: "1".repeat(40), - targetCheckpointDigest: "target-tree", - providerInstanceId, - sessionIncarnationId, - phase: "source-anchor-capture-started" as const, - attempt: 0, - lastErrorCode: null, - compensation: "none" as const, - cleanup: "pending" as const, - sourceAnchor: null, - sourceAnchorDigest: null, - desiredAnchor: { leafId: privateCanary }, - desiredAnchorDigest: "target-anchor", - preimage: null, - workspaceReceiptDigest: null, - providerReceiptDigest: null, - projectionCommitSequence: null, - createdAt: now, - updatedAt: now, - }), - ), + Effect.succeedSome({ + operationId, + requestEventId, + threadId, + projectId, + workspaceKey: "workspace-atomic", + workspaceCwd: "/workspace/atomic", + sourceRevision: 2, + targetRevision: 1, + ...(command.type === "thread.conversation.revert" ? { restoreFiles: false } : {}), + sourceTurnId: null, + targetTurnId: null, + sourceCheckpointRef: checkpointRefForThreadTurn(threadId, 2), + sourceCheckpointOid: "2".repeat(40), + targetCheckpointRef: checkpointRefForThreadTurn(threadId, 1), + targetCheckpointOid: "1".repeat(40), + targetCheckpointDigest: "target-tree", + providerInstanceId, + sessionIncarnationId, + phase: "source-anchor-capture-started" as const, + attempt: 0, + lastErrorCode: null, + compensation: "none" as const, + cleanup: "pending" as const, + sourceAnchor: null, + sourceAnchorDigest: null, + desiredAnchor: { leafId: privateCanary }, + desiredAnchorDigest: "target-anchor", + preimage: null, + workspaceReceiptDigest: null, + providerReceiptDigest: null, + projectionCommitSequence: null, + createdAt: now, + updatedAt: now, + }), }); const engine = OrchestrationEngineLive.pipe( diff --git a/apps/server/src/orchestration/Layers/ThreadDeletionReactor.ts b/apps/server/src/orchestration/Layers/ThreadDeletionReactor.ts index 14a92a5eae..092ca1b1d4 100644 --- a/apps/server/src/orchestration/Layers/ThreadDeletionReactor.ts +++ b/apps/server/src/orchestration/Layers/ThreadDeletionReactor.ts @@ -27,15 +27,14 @@ export const logCleanupCauseUnlessInterrupted = ({ readonly threadId: ThreadDeletedEvent["payload"]["threadId"]; }): Effect.Effect => effect.pipe( - Effect.catchCause((cause) => { - if (Cause.hasInterruptsOnly(cause)) { - return Effect.failCause(cause); - } - return Effect.logDebug(message, { - threadId, - cause: Cause.pretty(cause), - }); - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + (cause) => + Effect.logDebug(message, { + threadId, + cause: Cause.pretty(cause), + }), + ), ); const make = Effect.gen(function* () { @@ -67,16 +66,15 @@ const make = Effect.gen(function* () { const processThreadDeletedSafely = (event: ThreadDeletedEvent) => processThreadDeleted(event).pipe( - Effect.catchCause((cause) => { - if (Cause.hasInterruptsOnly(cause)) { - return Effect.failCause(cause); - } - return Effect.logWarning("thread deletion reactor failed to process event", { - eventType: event.type, - threadId: event.payload.threadId, - cause: Cause.pretty(cause), - }); - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + (cause) => + Effect.logWarning("thread deletion reactor failed to process event", { + eventType: event.type, + threadId: event.payload.threadId, + cause: Cause.pretty(cause), + }), + ), ); const worker = yield* makeDrainableWorker(processThreadDeletedSafely); diff --git a/apps/server/src/orchestration/ProjectSettingsReactor.ts b/apps/server/src/orchestration/ProjectSettingsReactor.ts index 82b298d22d..9108619ee8 100644 --- a/apps/server/src/orchestration/ProjectSettingsReactor.ts +++ b/apps/server/src/orchestration/ProjectSettingsReactor.ts @@ -25,12 +25,12 @@ const make = Effect.gen(function* () { const worker = yield* makeDrainableWorker((_event: OrchestrationEvent) => settings.updateSettings({}).pipe( Effect.asVoid, - Effect.catchCause((cause) => - Cause.hasInterruptsOnly(cause) - ? Effect.failCause(cause) - : Effect.logWarning("legacy project settings synchronization failed", { - cause: Cause.pretty(cause), - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + (cause) => + Effect.logWarning("legacy project settings synchronization failed", { + cause: Cause.pretty(cause), + }), ), ), ); diff --git a/apps/server/src/orchestration/PullRequestSyncReactor.ts b/apps/server/src/orchestration/PullRequestSyncReactor.ts index 3ca2abe026..22e0143819 100644 --- a/apps/server/src/orchestration/PullRequestSyncReactor.ts +++ b/apps/server/src/orchestration/PullRequestSyncReactor.ts @@ -257,12 +257,12 @@ export const make = Effect.gen(function* () { Effect.map((stack) => ({ stack: stack === null ? null : ({ kind: "native", ...stack } as const), })), - Effect.catchCause((cause) => - Cause.hasInterruptsOnly(cause) - ? Effect.failCause(cause) - : Effect.logWarning("pull request stack lookup failed", { - key, - }).pipe(Effect.as(null)), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + () => + Effect.logWarning("pull request stack lookup failed", { + key, + }).pipe(Effect.as(null)), ), ) : null; diff --git a/apps/server/src/orchestration/ThreadPullRequestReactor.ts b/apps/server/src/orchestration/ThreadPullRequestReactor.ts index 6ebaf55418..b53ded28cb 100644 --- a/apps/server/src/orchestration/ThreadPullRequestReactor.ts +++ b/apps/server/src/orchestration/ThreadPullRequestReactor.ts @@ -260,16 +260,16 @@ export const make = Effect.gen(function* () { } return { thread, branchPullRequest, replacement }; }).pipe( - Effect.catchCause((cause) => - Cause.hasInterruptsOnly(cause) - ? Effect.failCause(cause) - : Effect.logWarning("thread pull request discovery failed", { - threadId: thread.id, - cause: Cause.pretty(cause), - }).pipe( - Effect.tap(() => Effect.sync(() => failBackfill([thread]))), - Effect.as(null), - ), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + (cause) => + Effect.logWarning("thread pull request discovery failed", { + threadId: thread.id, + cause: Cause.pretty(cause), + }).pipe( + Effect.tap(() => Effect.sync(() => failBackfill([thread]))), + Effect.as(null), + ), ), ), ); @@ -326,25 +326,25 @@ export const make = Effect.gen(function* () { OrchestrationCommandInvariantError: () => Effect.sync(() => finishBackfill([thread])), }), - Effect.catchCause((cause) => - Cause.hasInterruptsOnly(cause) - ? Effect.failCause(cause) - : Effect.logWarning("thread pull request update failed", { - threadId: thread.id, - cause: Cause.pretty(cause), - }).pipe(Effect.tap(() => Effect.sync(() => failBackfill([thread])))), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + (cause) => + Effect.logWarning("thread pull request update failed", { + threadId: thread.id, + cause: Cause.pretty(cause), + }).pipe(Effect.tap(() => Effect.sync(() => failBackfill([thread])))), ), ), { discard: true }, ); }).pipe( - Effect.catchCause((cause) => - Cause.hasInterruptsOnly(cause) - ? Effect.failCause(cause) - : Effect.logWarning("thread branch pull request lookup failed", { - threadIds: group.map((thread) => thread.id), - cause: Cause.pretty(cause), - }).pipe(Effect.tap(() => Effect.sync(() => failBackfill(group)))), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + (cause) => + Effect.logWarning("thread branch pull request lookup failed", { + threadIds: group.map((thread) => thread.id), + cause: Cause.pretty(cause), + }).pipe(Effect.tap(() => Effect.sync(() => failBackfill(group)))), ), ), { concurrency: 8, discard: true }, @@ -353,12 +353,12 @@ export const make = Effect.gen(function* () { const worker = yield* makeDrainableWorker((request: RefreshRequest) => synchronize(request).pipe( - Effect.catchCause((cause) => - Cause.hasInterruptsOnly(cause) - ? Effect.failCause(cause) - : Effect.logWarning("thread pull request refresh failed", { - cause: Cause.pretty(cause), - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + (cause) => + Effect.logWarning("thread pull request refresh failed", { + cause: Cause.pretty(cause), + }), ), ), ); diff --git a/apps/server/src/orchestration/ThreadSettlementReactor.ts b/apps/server/src/orchestration/ThreadSettlementReactor.ts index 3dddff2b58..f813f8d99b 100644 --- a/apps/server/src/orchestration/ThreadSettlementReactor.ts +++ b/apps/server/src/orchestration/ThreadSettlementReactor.ts @@ -133,13 +133,13 @@ export const make = Effect.gen(function* () { }, (effect, thread) => effect.pipe( - Effect.catchCause((cause) => - Cause.hasInterruptsOnly(cause) - ? Effect.failCause(cause) - : Effect.logWarning("automatic thread settlement skipped", { - threadId: thread.id, - cause: Cause.pretty(cause), - }).pipe(Effect.as(null)), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + (cause) => + Effect.logWarning("automatic thread settlement skipped", { + threadId: thread.id, + cause: Cause.pretty(cause), + }).pipe(Effect.as(null)), ), ), ); @@ -301,13 +301,13 @@ export const make = Effect.gen(function* () { discard: true, }); }).pipe( - Effect.catchCause((cause) => - Cause.hasInterruptsOnly(cause) - ? Effect.failCause(cause) - : Effect.logWarning("automatic thread settlement skipped", { - threadIds: group.map((thread) => thread.id), - cause: Cause.pretty(cause), - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + (cause) => + Effect.logWarning("automatic thread settlement skipped", { + threadIds: group.map((thread) => thread.id), + cause: Cause.pretty(cause), + }), ), ), { concurrency: 8, discard: true }, @@ -319,12 +319,12 @@ export const make = Effect.gen(function* () { threadId?: ThreadId, ) => sweep(mergedPullRequest, threadId).pipe( - Effect.catchCause((cause) => - Cause.hasInterruptsOnly(cause) - ? Effect.failCause(cause) - : Effect.logWarning("automatic thread settlement sweep failed", { - cause: Cause.pretty(cause), - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterruptsOnly(cause), + (cause) => + Effect.logWarning("automatic thread settlement sweep failed", { + cause: Cause.pretty(cause), + }), ), ); const worker = yield* makeDrainableWorker((threadId: ThreadId | undefined) => diff --git a/apps/server/src/orchestration/commandInvariants.ts b/apps/server/src/orchestration/commandInvariants.ts index 873eab007b..244a6a9e9c 100644 --- a/apps/server/src/orchestration/commandInvariants.ts +++ b/apps/server/src/orchestration/commandInvariants.ts @@ -119,15 +119,13 @@ export function requireThreadArchived(input: { readonly threadId: ThreadId; }): Effect.Effect { return requireThread(input).pipe( - Effect.flatMap((thread) => - thread.archivedAt !== null - ? Effect.succeed(thread) - : Effect.fail( - invariantError( - input.command.type, - `Thread '${input.threadId}' is not archived for command '${input.command.type}'.`, - ), - ), + Effect.filterOrFail( + (thread) => thread.archivedAt !== null, + () => + invariantError( + input.command.type, + `Thread '${input.threadId}' is not archived for command '${input.command.type}'.`, + ), ), ); } @@ -138,15 +136,13 @@ export function requireThreadNotArchived(input: { readonly threadId: ThreadId; }): Effect.Effect { return requireThread(input).pipe( - Effect.flatMap((thread) => - thread.archivedAt === null - ? Effect.succeed(thread) - : Effect.fail( - invariantError( - input.command.type, - `Thread '${input.threadId}' is already archived and cannot handle command '${input.command.type}'.`, - ), - ), + Effect.filterOrFail( + (thread) => thread.archivedAt === null, + () => + invariantError( + input.command.type, + `Thread '${input.threadId}' is already archived and cannot handle command '${input.command.type}'.`, + ), ), ); } diff --git a/apps/server/src/orchestration/decider.ts b/apps/server/src/orchestration/decider.ts index 8707760fa0..37ee5a9af1 100644 --- a/apps/server/src/orchestration/decider.ts +++ b/apps/server/src/orchestration/decider.ts @@ -606,12 +606,10 @@ export const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand" command.type === "thread.auto-settle" && (thread.settledOverride !== null || thread.autoSettleDisabledAt != null) ) { - return yield* Effect.fail( - new OrchestrationCommandInvariantError({ - commandType: command.type, - detail: `thread ${command.threadId} changed before automatic settlement`, - }), - ); + return yield* new OrchestrationCommandInvariantError({ + commandType: command.type, + detail: `thread ${command.threadId} changed before automatic settlement`, + }); } // The server owns settle eligibility. A stale command must not settle // a thread whose session is coming alive or working. @@ -766,12 +764,10 @@ export const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand" // structurally just a string): NaN fails every comparison, and an // unparseable snoozedUntil must never persist. if (!(Date.parse(command.snoozedUntil) > Date.parse(occurredAt))) { - return yield* Effect.fail( - new OrchestrationCommandInvariantError({ - commandType: command.type, - detail: `thread ${command.threadId} snooze wake time ${command.snoozedUntil} is not in the future`, - }), - ); + return yield* new OrchestrationCommandInvariantError({ + commandType: command.type, + detail: `thread ${command.threadId} snooze wake time ${command.snoozedUntil} is not in the future`, + }); } // Blocked-on-you work must not be snoozed away: a pending approval or // user-input request is the agent waiting on the user, and hiding it @@ -781,24 +777,20 @@ export const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand" openRequests({ ...thread, activities: pendingRequestActivities ?? thread.activities }) .size > 0 ) { - return yield* Effect.fail( - new OrchestrationCommandInvariantError({ - commandType: command.type, - detail: `thread ${command.threadId} has a pending approval or user-input request and cannot be snoozed`, - }), - ); + return yield* new OrchestrationCommandInvariantError({ + commandType: command.type, + detail: `thread ${command.threadId} has a pending approval or user-input request and cannot be snoozed`, + }); } // A queued turn start — a user message no turn has adopted yet — is // invisible pending work: no session, no pending flags. Snoozing in // that window would hide a just-requested turn exactly the way settle // would. if (hasQueuedTurnStartForThread(thread, occurredAt)) { - return yield* Effect.fail( - new OrchestrationCommandInvariantError({ - commandType: command.type, - detail: `thread ${command.threadId} has a queued turn start and cannot be snoozed`, - }), - ); + return yield* new OrchestrationCommandInvariantError({ + commandType: command.type, + detail: `thread ${command.threadId} has a queued turn start and cannot be snoozed`, + }); } // Re-snoozing an already-snoozed thread to the SAME wake time is a // duplicate (double-click, raced clients): re-emit with the original @@ -960,12 +952,10 @@ export const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand" // (rather than silently pinning) keeps a raced reorder-after-unpin // from resurrecting a pin the user just cleared. if (thread.pinnedAt == null) { - return yield* Effect.fail( - new OrchestrationCommandInvariantError({ - commandType: command.type, - detail: `thread ${command.threadId} is not pinned and cannot be reordered`, - }), - ); + return yield* new OrchestrationCommandInvariantError({ + commandType: command.type, + detail: `thread ${command.threadId} is not pinned and cannot be reordered`, + }); } // Idempotent by re-emission (see thread.settle): a duplicate drop on // the same slot keeps the existing updatedAt so it projects as a no-op. @@ -1101,12 +1091,10 @@ export const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand" if (command.linkedPullRequest != null) { const { linkedPullRequest: linked, ...metadata } = command; const project = readModel.projects.find((project) => project.id === thread.projectId); - let host = project?.repositoryIdentity?.canonicalKey.split("/")[0] ?? "unknown"; - try { - host = new URL(linked.url).hostname; - } catch { - // Historical clients can send links without a parseable URL. - } + // Historical clients can send links without a parseable URL. + const host = URL.canParse(linked.url) + ? new URL(linked.url).hostname + : (project?.repositoryIdentity?.canonicalKey.split("/")[0] ?? "unknown"); const hasMetadata = Object.entries(metadata).some( ([key, value]) => !["type", "commandId", "threadId"].includes(key) && value !== undefined, ); @@ -2571,12 +2559,10 @@ export const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand" sessionComingAlive || hasQueuedTurnStartForThread(thread, command.createdAt) ) { - return yield* Effect.fail( - new OrchestrationCommandInvariantError({ - commandType: command.type, - detail: `thread ${command.threadId} was re-engaged after settle; skipping session stop`, - }), - ); + return yield* new OrchestrationCommandInvariantError({ + commandType: command.type, + detail: `thread ${command.threadId} was re-engaged after settle; skipping session stop`, + }); } } const targetSession = thread.session; diff --git a/apps/server/src/orchestration/workflowScriptQuery.ts b/apps/server/src/orchestration/workflowScriptQuery.ts index 06bbd35ccf..184abc6147 100644 --- a/apps/server/src/orchestration/workflowScriptQuery.ts +++ b/apps/server/src/orchestration/workflowScriptQuery.ts @@ -32,9 +32,10 @@ export const readWorkflowScript = Effect.fn("orchestration.readWorkflowScript")( const requested = input.scriptPath; if (!NodePath.isAbsolute(requested) || NodePath.extname(requested) !== ".js") { - return yield* Effect.fail( - new OrchestrationGetWorkflowScriptError({ reason: "invalid-path", scriptPath: requested }), - ); + return yield* new OrchestrationGetWorkflowScriptError({ + reason: "invalid-path", + scriptPath: requested, + }); } const root = yield* Effect.tryPromise({ @@ -60,14 +61,16 @@ export const readWorkflowScript = Effect.fn("orchestration.readWorkflowScript")( }); if (resolved !== root && !resolved.startsWith(`${root}${NodePath.sep}`)) { - return yield* Effect.fail( - new OrchestrationGetWorkflowScriptError({ reason: "outside-root", scriptPath: resolved }), - ); + return yield* new OrchestrationGetWorkflowScriptError({ + reason: "outside-root", + scriptPath: resolved, + }); } if (NodePath.extname(resolved) !== ".js") { - return yield* Effect.fail( - new OrchestrationGetWorkflowScriptError({ reason: "not-js", scriptPath: resolved }), - ); + return yield* new OrchestrationGetWorkflowScriptError({ + reason: "not-js", + scriptPath: resolved, + }); } // TOCTOU-safe read (review finding): open FIRST, then verify what was diff --git a/apps/server/src/persistence/AuthPairingLinks.ts b/apps/server/src/persistence/AuthPairingLinks.ts index aae55dd2fe..7ad1d95ed7 100644 --- a/apps/server/src/persistence/AuthPairingLinks.ts +++ b/apps/server/src/persistence/AuthPairingLinks.ts @@ -268,7 +268,7 @@ export const make = Effect.gen(function* () { ), Effect.flatMap((rowOption) => Option.match(rowOption, { - onNone: () => Effect.succeed(Option.none()), + onNone: () => Effect.succeedNone, onSome: (row) => decodeAuthPairingLinkDbRow(row).pipe( Effect.mapError((cause) => @@ -278,7 +278,7 @@ export const make = Effect.gen(function* () { { pairingLinkId: row.id }, ), ), - Effect.map(Option.some), + Effect.asSome, ), }), ), @@ -329,7 +329,7 @@ export const make = Effect.gen(function* () { ), Effect.flatMap((rowOption) => Option.match(rowOption, { - onNone: () => Effect.succeed(Option.none()), + onNone: () => Effect.succeedNone, onSome: (row) => decodeAuthPairingLinkDbRow(row).pipe( Effect.mapError((cause) => @@ -339,7 +339,7 @@ export const make = Effect.gen(function* () { { pairingLinkId: row.id }, ), ), - Effect.map(Option.some), + Effect.asSome, ), }), ), diff --git a/apps/server/src/persistence/AuthSessions.ts b/apps/server/src/persistence/AuthSessions.ts index 37db33556e..0e9b5ac88f 100644 --- a/apps/server/src/persistence/AuthSessions.ts +++ b/apps/server/src/persistence/AuthSessions.ts @@ -404,7 +404,7 @@ export const make = Effect.gen(function* () { ), Effect.flatMap((rowOption) => Option.match(rowOption, { - onNone: () => Effect.succeed(Option.none()), + onNone: () => Effect.succeedNone, onSome: (row) => decodeAuthSessionDbRow(row).pipe( Effect.mapError((cause) => diff --git a/apps/server/src/persistence/Layers/ProjectionCheckpoints.ts b/apps/server/src/persistence/Layers/ProjectionCheckpoints.ts index cfa5658d0e..9483f8ff97 100644 --- a/apps/server/src/persistence/Layers/ProjectionCheckpoints.ts +++ b/apps/server/src/persistence/Layers/ProjectionCheckpoints.ts @@ -189,9 +189,9 @@ const makeProjectionCheckpointRepository = Effect.gen(function* () { ), Effect.flatMap((rowOption) => Option.match(rowOption, { - onNone: () => Effect.succeed(Option.none()), + onNone: () => Effect.succeedNone, onSome: (row) => - Effect.succeed(Option.some(row as Schema.Schema.Type)), + Effect.succeedSome(row as Schema.Schema.Type), }), ), ); diff --git a/apps/server/src/persistence/Layers/ProjectionTurns.ts b/apps/server/src/persistence/Layers/ProjectionTurns.ts index bd57a4eaa3..94443c867f 100644 --- a/apps/server/src/persistence/Layers/ProjectionTurns.ts +++ b/apps/server/src/persistence/Layers/ProjectionTurns.ts @@ -317,9 +317,8 @@ const makeProjectionTurnRepository = Effect.gen(function* () { ), Effect.flatMap((rowOption) => Option.match(rowOption, { - onNone: () => Effect.succeed(Option.none()), - onSome: (row) => - Effect.succeed(Option.some(row as Schema.Schema.Type)), + onNone: () => Effect.succeedNone, + onSome: (row) => Effect.succeedSome(row as Schema.Schema.Type), }), ), ); diff --git a/apps/server/src/persistence/ProviderSessionRuntime.ts b/apps/server/src/persistence/ProviderSessionRuntime.ts index 7b6e8d8eb0..1ec7adcd62 100644 --- a/apps/server/src/persistence/ProviderSessionRuntime.ts +++ b/apps/server/src/persistence/ProviderSessionRuntime.ts @@ -402,7 +402,7 @@ export const make = Effect.gen(function* () { ), Effect.flatMap((runtimeRowOption) => Option.match(runtimeRowOption, { - onNone: () => Effect.succeed(Option.none()), + onNone: () => Effect.succeedNone, onSome: (row) => decodeRuntimeRow(row).pipe( Effect.mapError((cause) => @@ -412,7 +412,7 @@ export const make = Effect.gen(function* () { { threadId: input.threadId }, ), ), - Effect.map((runtime) => Option.some(runtime)), + Effect.asSome, ), }), ), @@ -432,7 +432,7 @@ export const make = Effect.gen(function* () { // every consumer that enumerates sessions, such as the reaper. Effect.forEach(rows, (row) => decodeRuntimeRow(row).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catch((cause) => Effect.logWarning("provider.session.runtime.row-skipped", { threadId: row.threadId, diff --git a/apps/server/src/project/AgentSessionImporter.test.ts b/apps/server/src/project/AgentSessionImporter.test.ts index 3d19cd2f2b..8618910240 100644 --- a/apps/server/src/project/AgentSessionImporter.test.ts +++ b/apps/server/src/project/AgentSessionImporter.test.ts @@ -234,7 +234,7 @@ it.layer(NodeServices.layer)("AgentSessionImporter", (it) => { upsert: (binding) => Effect.sync(() => void bindings.push(binding)), getProvider: () => Effect.die("unused"), recordImportedTranscript: () => Effect.void, - getBinding: () => Effect.succeed(Option.none()), + getBinding: () => Effect.succeedNone, removeExact: () => Effect.die("unused"), listThreadIds: () => Effect.die("unused"), listBindings: () => Effect.die("unused"), @@ -461,7 +461,7 @@ it.layer(NodeServices.layer)("AgentSessionImporter", (it) => { upsert: () => Effect.die("must not replace an active binding"), getProvider: () => Effect.die("unused"), recordImportedTranscript: () => Effect.void, - getBinding: () => Effect.succeed(Option.some(runningBinding)), + getBinding: () => Effect.succeedSome(runningBinding), removeExact: () => Effect.die("unused"), listThreadIds: () => Effect.die("unused"), listBindings: () => Effect.die("unused"), @@ -517,7 +517,7 @@ it.layer(NodeServices.layer)("AgentSessionImporter", (it) => { upsert: () => Effect.die("must not bind malformed or wrong-project sessions"), getProvider: () => Effect.die("unused"), recordImportedTranscript: () => Effect.die("unused"), - getBinding: () => Effect.succeed(Option.none()), + getBinding: () => Effect.succeedNone, removeExact: () => Effect.die("unused"), listThreadIds: () => Effect.die("unused"), listBindings: () => Effect.die("unused"), diff --git a/apps/server/src/project/AgentSessionScanner.ts b/apps/server/src/project/AgentSessionScanner.ts index b1e330ff2a..90e1d7d169 100644 --- a/apps/server/src/project/AgentSessionScanner.ts +++ b/apps/server/src/project/AgentSessionScanner.ts @@ -677,7 +677,7 @@ export const make = Effect.gen(function* () { fileSystem.readDirectory(directory).pipe(Effect.orElseSucceed((): ReadonlyArray => [])); const statOption = (target: string) => - fileSystem.stat(target).pipe(Effect.map(Option.some), Effect.orElseSucceed(Option.none)); + fileSystem.stat(target).pipe(Effect.asSome, Effect.orElseSucceed(Option.none)); /** Match directory aliases without assuming the host volume is case-insensitive. */ const directoryIdentity = Effect.fn("AgentSessionScanner.directoryIdentity")(function* ( diff --git a/apps/server/src/project/ProjectFaviconResolver.ts b/apps/server/src/project/ProjectFaviconResolver.ts index 4fd36cb67b..90cbcb574e 100644 --- a/apps/server/src/project/ProjectFaviconResolver.ts +++ b/apps/server/src/project/ProjectFaviconResolver.ts @@ -143,7 +143,7 @@ const optionOnNotFound = ( effect: Effect.Effect, ): Effect.Effect, PlatformError.PlatformError, R> => effect.pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catchTags({ PlatformError: (error) => error.reason._tag === "NotFound" ? Effect.succeed(Option.none()) : Effect.fail(error), @@ -175,7 +175,7 @@ export const make = Effect.gen(function* () { relativePath, }) ).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catchTags({ WorkspacePathOutsideRootError: () => Effect.succeed( diff --git a/apps/server/src/project/RepositoryIdentityResolver.ts b/apps/server/src/project/RepositoryIdentityResolver.ts index 7a243453a9..ac20777d23 100644 --- a/apps/server/src/project/RepositoryIdentityResolver.ts +++ b/apps/server/src/project/RepositoryIdentityResolver.ts @@ -166,7 +166,7 @@ export const make = Effect.fn("RepositoryIdentityResolver.make")(function* ( Effect.provideService(ProcessRunner.ProcessRunner, processRunner), Effect.flatMap((identity) => identity !== null && options.refine - ? options.refine(identity).pipe(Effect.catch(() => Effect.succeed(identity))) + ? options.refine(identity).pipe(Effect.orElseSucceed(() => identity)) : Effect.succeed(identity), ), ), diff --git a/apps/server/src/project/T3ProjectFileLoader.ts b/apps/server/src/project/T3ProjectFileLoader.ts index 105e6b09a3..4ad874b909 100644 --- a/apps/server/src/project/T3ProjectFileLoader.ts +++ b/apps/server/src/project/T3ProjectFileLoader.ts @@ -68,7 +68,7 @@ export const make = Effect.gen(function* () { function* (workspaceRoot) { const filePath = path.join(workspaceRoot, T3_PROJECT_FILE_NAME); const raw = yield* fileSystem.readFileString(filePath).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catchTags({ PlatformError: (error) => error.reason._tag === "NotFound" @@ -87,7 +87,7 @@ export const make = Effect.gen(function* () { return Option.none(); } return yield* decodeT3ProjectFileJson(raw.value).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catchTags({ SchemaError: (error) => logT3ProjectFileLoadError( diff --git a/apps/server/src/provider/AntigravityInstallation.ts b/apps/server/src/provider/AntigravityInstallation.ts index d1adbc93af..f0d5e7723d 100644 --- a/apps/server/src/provider/AntigravityInstallation.ts +++ b/apps/server/src/provider/AntigravityInstallation.ts @@ -314,7 +314,7 @@ export const makeAntigravityInstallation = Effect.fn("AntigravityInstallation.ma ); } const contents = yield* fs.readFileString(filePath); - return yield* Schema.decodeUnknownEffect(Schema.fromJsonString(schema))(contents); + return yield* Schema.decodeEffect(Schema.fromJsonString(schema))(contents); }); const executableFile = Effect.fn("AntigravityInstallation.executableFile")(function* ( diff --git a/apps/server/src/provider/Drivers/AntigravityDriver.ts b/apps/server/src/provider/Drivers/AntigravityDriver.ts index 412e678ac1..dec1f6fff6 100644 --- a/apps/server/src/provider/Drivers/AntigravityDriver.ts +++ b/apps/server/src/provider/Drivers/AntigravityDriver.ts @@ -393,7 +393,7 @@ export const AntigravityDriver: ProviderDriver { // Native UUIDs are filenames; reject paths and unrelated database names. if (!/^[0-9a-f]{8}(?:-[0-9a-f]{4}){3}-[0-9a-f]{12}$/i.test(sessionId)) - return Effect.succeed(undefined); + return Effect.undefined; return Effect.tryPromise(() => readAntigravityLatestContext( path.join(profileDirectory, "antigravity-acp", "conversations", `${sessionId}.db`), diff --git a/apps/server/src/provider/Drivers/AntigravitySkills.ts b/apps/server/src/provider/Drivers/AntigravitySkills.ts index f9627e72fb..b113964675 100644 --- a/apps/server/src/provider/Drivers/AntigravitySkills.ts +++ b/apps/server/src/provider/Drivers/AntigravitySkills.ts @@ -86,7 +86,7 @@ const readIfPresent = ( Effect.catchTags({ PlatformError: (cause) => cause.reason._tag === "NotFound" - ? Effect.succeed(undefined) + ? Effect.undefined : Effect.fail( new AntigravitySkillsProbeError({ reason: "filesystem-error", path, cause }), ), diff --git a/apps/server/src/provider/Drivers/CodexDriver.ts b/apps/server/src/provider/Drivers/CodexDriver.ts index 5b47008d2e..92e1484bef 100644 --- a/apps/server/src/provider/Drivers/CodexDriver.ts +++ b/apps/server/src/provider/Drivers/CodexDriver.ts @@ -315,13 +315,11 @@ export const CodexDriver: ProviderDriver = { Effect.gen(function* () { const selectedIdentity = authenticatedUsageIdentity((yield* snapshot.getSnapshot).auth); if (!selectedIdentity) { - return yield* Effect.fail( - new ProviderDriverError({ - driver: DRIVER_KIND, - instanceId, - detail: "Codex account identity is not verified.", - }), - ); + return yield* new ProviderDriverError({ + driver: DRIVER_KIND, + instanceId, + detail: "Codex account identity is not verified.", + }); } // A pending or completed attempt belongs to one account, even if the // same CLI home signs in as another account before a retry. @@ -335,13 +333,11 @@ export const CodexDriver: ProviderDriver = { (yield* snapshot.getSnapshot).auth, ); if (identityBefore !== selectedIdentity) { - return yield* Effect.fail( - new ProviderDriverError({ - driver: DRIVER_KIND, - instanceId, - detail: "Codex account changed before the reset credit could be used.", - }), - ); + return yield* new ProviderDriverError({ + driver: DRIVER_KIND, + instanceId, + detail: "Codex account changed before the reset credit could be used.", + }); } const result = yield* Effect.gen(function* () { const { client, sharedHomePath, outcome } = yield* Effect.gen(function* () { @@ -358,13 +354,11 @@ export const CodexDriver: ProviderDriver = { .auth, ); if (!identityBefore || liveIdentity !== identityBefore) { - return yield* Effect.fail( - new ProviderDriverError({ - driver: DRIVER_KIND, - instanceId, - detail: "Codex account changed before the reset credit could be used.", - }), - ); + return yield* new ProviderDriverError({ + driver: DRIVER_KIND, + instanceId, + detail: "Codex account changed before the reset credit could be used.", + }); } const { outcome } = yield* client.request( "account/rateLimitResetCredit/consume", diff --git a/apps/server/src/provider/Layers/AntigravityAdapter.ts b/apps/server/src/provider/Layers/AntigravityAdapter.ts index d14841a128..abdb3b6504 100644 --- a/apps/server/src/provider/Layers/AntigravityAdapter.ts +++ b/apps/server/src/provider/Layers/AntigravityAdapter.ts @@ -973,7 +973,7 @@ export const makeAntigravityAdapter = Effect.fn("makeAntigravityAdapter")(functi yield* applyAntigravityAcpModelSelection({ runtime, model: model ?? context.session.model, - defaultModel: yield* options.defaultModel ?? Effect.succeed(undefined), + defaultModel: yield* options.defaultModel ?? Effect.undefined, mapError: (cause) => cause, }).pipe( Effect.mapError((cause) => mapAntigravityError(context.threadId, "session/model", cause)), @@ -1397,7 +1397,7 @@ export const makeAntigravityAdapter = Effect.fn("makeAntigravityAdapter")(functi const model = yield* applyAntigravityAcpModelSelection({ runtime, model: input.modelSelection?.model, - defaultModel: yield* options.defaultModel ?? Effect.succeed(undefined), + defaultModel: yield* options.defaultModel ?? Effect.undefined, mapError: (cause) => cause, }); yield* runtime.setMode(antigravityPermissionMode(input.runtimeMode)); @@ -1651,7 +1651,7 @@ export const makeAntigravityAdapter = Effect.fn("makeAntigravityAdapter")(functi const model = resolveAntigravityModel({ configOptions, model: requestedModel, - defaultModel: yield* options.defaultModel ?? Effect.succeed(undefined), + defaultModel: yield* options.defaultModel ?? Effect.undefined, }); const availableModels = antigravityModelOptions(configOptions); if (model && !availableModels.some((option) => option.value === model)) { diff --git a/apps/server/src/provider/Layers/AntigravityProvider.ts b/apps/server/src/provider/Layers/AntigravityProvider.ts index 75d862fc47..a6387a8bbc 100644 --- a/apps/server/src/provider/Layers/AntigravityProvider.ts +++ b/apps/server/src/provider/Layers/AntigravityProvider.ts @@ -211,7 +211,7 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func Effect.map(Option.getOrUndefined), Effect.orElseSucceed(() => undefined), ) - : Effect.succeed(undefined); + : Effect.undefined; const freshUsageLimits = yield* probeUsageLimitsEffect; const updatedAt = DateTime.formatIso(yield* DateTime.now); const next = yield* SubscriptionRef.updateAndGet(metadata, (state) => { @@ -305,7 +305,7 @@ export const makeAntigravityProvider = Effect.fn("makeAntigravityProvider")(func Effect.map(Option.getOrUndefined), Effect.orElseSucceed(() => undefined), ) - : Effect.succeed(undefined); + : Effect.undefined; const freshUsageLimits = yield* probeUsageLimitsEffect; const updatedAt = DateTime.formatIso(yield* DateTime.now); yield* SubscriptionRef.update(metadata, (state) => { diff --git a/apps/server/src/provider/Layers/ClaudeAdapter.test.ts b/apps/server/src/provider/Layers/ClaudeAdapter.test.ts index b384925800..ec2a32771a 100644 --- a/apps/server/src/provider/Layers/ClaudeAdapter.test.ts +++ b/apps/server/src/provider/Layers/ClaudeAdapter.test.ts @@ -1,5 +1,6 @@ import * as McpProviderSession from "../../mcp/McpProviderSession.ts"; import { buildRuntimeInstructions } from "../RuntimeInstructions.ts"; +// @effect-diagnostics abortControllerInEffect:off - Tests hand-built AbortSignals to the SDK query stub to exercise cancellation. // @effect-diagnostics nodeBuiltinImport:off import * as NodeFS from "node:fs"; import * as NodeOS from "node:os"; diff --git a/apps/server/src/provider/Layers/ClaudeAdapter.ts b/apps/server/src/provider/Layers/ClaudeAdapter.ts index 3580b1b131..b9b28ff709 100644 --- a/apps/server/src/provider/Layers/ClaudeAdapter.ts +++ b/apps/server/src/provider/Layers/ClaudeAdapter.ts @@ -6360,7 +6360,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( for (const result of results) { if (result._tag === "Failure") { - return yield* Effect.fail(result.failure); + return yield* result.failure; } } }); diff --git a/apps/server/src/provider/Layers/ClaudeProvider.ts b/apps/server/src/provider/Layers/ClaudeProvider.ts index acb8ed19be..f24876692a 100644 --- a/apps/server/src/provider/Layers/ClaudeProvider.ts +++ b/apps/server/src/provider/Layers/ClaudeProvider.ts @@ -477,7 +477,7 @@ export const probeClaudeUsageLimits = Effect.fn("probeClaudeUsageLimits")(functi const [authResult, usageRead] = yield* Effect.all( [ runClaudeCommand(claudeSettings, ["auth", "status", "--json"], environment, runOptions).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.timeoutOption(USAGE_PROBE_TIMEOUT_MS), Effect.map(Option.flatten), Effect.catchCause(() => Effect.succeed(Option.none())), diff --git a/apps/server/src/provider/Layers/CodexAdapter.test.ts b/apps/server/src/provider/Layers/CodexAdapter.test.ts index aa4b0a10f8..873b23f17b 100644 --- a/apps/server/src/provider/Layers/CodexAdapter.test.ts +++ b/apps/server/src/provider/Layers/CodexAdapter.test.ts @@ -238,7 +238,7 @@ const providerSessionDirectoryTestLayer = Layer.succeed(ProviderSessionDirectory recordImportedTranscript: () => Effect.die("unused"), getProvider: () => Effect.die(new Error("ProviderSessionDirectory.getProvider is not used in test")), - getBinding: () => Effect.succeed(Option.none()), + getBinding: () => Effect.succeedNone, removeExact: () => Effect.succeed(false), listThreadIds: () => Effect.succeed([]), listBindings: () => Effect.succeed([]), @@ -390,11 +390,9 @@ validationLayer("CodexAdapterLive validation", (it) => { const relayValidationLayer = it.layer( Layer.effect( CodexAdapter, - Effect.gen(function* () { - return yield* makeCodexAdapter(decodeCodexSettings({}), { - environment: { ...process.env, PYLON_RELAY_CLI: "/tmp/pylon-relay-cli.mjs" }, - makeRuntime: validationRuntimeFactory.factory, - }); + makeCodexAdapter(decodeCodexSettings({}), { + environment: { ...process.env, PYLON_RELAY_CLI: "/tmp/pylon-relay-cli.mjs" }, + makeRuntime: validationRuntimeFactory.factory, }), ).pipe( Layer.provideMerge(ServerConfig.layerTest(process.cwd(), process.cwd())), diff --git a/apps/server/src/provider/Layers/CodexSessionRuntime.ts b/apps/server/src/provider/Layers/CodexSessionRuntime.ts index 6d7fb5b6cf..6105552bbe 100644 --- a/apps/server/src/provider/Layers/CodexSessionRuntime.ts +++ b/apps/server/src/provider/Layers/CodexSessionRuntime.ts @@ -693,7 +693,7 @@ export function resolveCodexSkillNamesForPrompt( E >, ): Effect.Effect | undefined> { - if (!prompt || !hasUnicodeSkillMention(prompt)) return Effect.succeed(undefined); + if (!prompt || !hasUnicodeSkillMention(prompt)) return Effect.undefined; return request.pipe( Effect.timeoutOption("2 seconds"), Effect.flatMap( diff --git a/apps/server/src/provider/Layers/GrokAdapter.ts b/apps/server/src/provider/Layers/GrokAdapter.ts index 328e166c82..6f72a988c8 100644 --- a/apps/server/src/provider/Layers/GrokAdapter.ts +++ b/apps/server/src/provider/Layers/GrokAdapter.ts @@ -796,46 +796,45 @@ export function makeGrokAdapter(grokSettings: GrokSettings, options?: GrokAdapte ); }); - const runTurnLivenessWatchdog = Effect.fn("GrokAdapter.runTurnLivenessWatchdog")( - function* (ctx: GrokSessionContext) { - while (true) { - if (ctx.stopped) { - return; - } - const turnId = ctx.livenessTurnId; - if ( - turnId === undefined || - ctx.interruptedTurnIds.has(turnId) || - !isLiveTurn(ctx, turnId) || - hasLivenessPause(ctx) - ) { - yield* Queue.take(ctx.livenessSignals); - continue; - } + const runTurnLivenessWatchdog = Effect.fn("GrokAdapter.runTurnLivenessWatchdog")(function* ( + ctx: GrokSessionContext, + ) { + while (true) { + if (ctx.stopped) { + return; + } + const turnId = ctx.livenessTurnId; + if ( + turnId === undefined || + ctx.interruptedTurnIds.has(turnId) || + !isLiveTurn(ctx, turnId) || + hasLivenessPause(ctx) + ) { + yield* Queue.take(ctx.livenessSignals); + continue; + } - const lastActivityAtNanos = ctx.lastTurnActivityAtNanos; - if (lastActivityAtNanos === undefined) { - yield* Queue.take(ctx.livenessSignals); - continue; - } - const nowNanos = yield* Clock.monotonicTimeNanos; - const remainingNanos = livenessTimeoutFor(ctx).nanos - (nowNanos - lastActivityAtNanos); - if (remainingNanos <= 0n) { - yield* settleStalledTurn(ctx, turnId); - continue; - } + const lastActivityAtNanos = ctx.lastTurnActivityAtNanos; + if (lastActivityAtNanos === undefined) { + yield* Queue.take(ctx.livenessSignals); + continue; + } + const nowNanos = yield* Clock.monotonicTimeNanos; + const remainingNanos = livenessTimeoutFor(ctx).nanos - (nowNanos - lastActivityAtNanos); + if (remainingNanos <= 0n) { + yield* settleStalledTurn(ctx, turnId); + continue; + } - const wakeReason = yield* Effect.raceFirst( - Effect.sleep(Duration.nanos(remainingNanos)).pipe(Effect.as("timeout" as const)), - Queue.take(ctx.livenessSignals).pipe(Effect.as("activity" as const)), - ); - if (wakeReason === "timeout") { - yield* settleStalledTurn(ctx, turnId); - } + const wakeReason = yield* Effect.raceFirst( + Effect.sleep(Duration.nanos(remainingNanos)).pipe(Effect.as("timeout" as const)), + Queue.take(ctx.livenessSignals).pipe(Effect.as("activity" as const)), + ); + if (wakeReason === "timeout") { + yield* settleStalledTurn(ctx, turnId); } - }, - Effect.catch(() => Effect.void), - ); + } + }, Effect.ignore()); const logNative = (threadId: ThreadId, method: string, payload: unknown) => Effect.gen(function* () { @@ -2081,7 +2080,7 @@ export function makeGrokAdapter(grokSettings: GrokSettings, options?: GrokAdapte }, ), ); - }).pipe(Effect.catch(() => Effect.void)), + }).pipe(Effect.ignore), ), ); }); diff --git a/apps/server/src/provider/Layers/OpenCodeAdapter.test.ts b/apps/server/src/provider/Layers/OpenCodeAdapter.test.ts index 975b25f8b3..bcbe498c30 100644 --- a/apps/server/src/provider/Layers/OpenCodeAdapter.test.ts +++ b/apps/server/src/provider/Layers/OpenCodeAdapter.test.ts @@ -621,7 +621,7 @@ const providerSessionDirectoryTestLayer = Layer.succeed(ProviderSessionDirectory recordImportedTranscript: () => Effect.die("unused"), getProvider: () => Effect.die(new Error("ProviderSessionDirectory.getProvider is not used in test")), - getBinding: () => Effect.succeed(Option.none()), + getBinding: () => Effect.succeedNone, removeExact: () => Effect.succeed(false), listThreadIds: () => Effect.succeed([]), listBindings: () => Effect.succeed([]), diff --git a/apps/server/src/provider/Layers/OpenCodeAdapter.ts b/apps/server/src/provider/Layers/OpenCodeAdapter.ts index 3d38fee965..8b14641f69 100644 --- a/apps/server/src/provider/Layers/OpenCodeAdapter.ts +++ b/apps/server/src/provider/Layers/OpenCodeAdapter.ts @@ -1360,7 +1360,7 @@ export function makeOpenCodeAdapter( readonly observedAt: string; readonly event: Record; }, - ) => writeNativeEvent(threadId, event).pipe(Effect.catchCause(() => Effect.void)); + ) => writeNativeEvent(threadId, event).pipe(Effect.ignoreCause); const cancelIdleReconciliation = Effect.fn("cancelIdleReconciliation")(function* ( context: OpenCodeSessionContext, @@ -1542,7 +1542,7 @@ export function makeOpenCodeAdapter( yield* Effect.sleep(`${delayMs} millis`); } }).pipe( - Effect.catchCause(() => Effect.void), + Effect.ignoreCause, Effect.ensuring( Effect.sync(() => { if (context.pendingIdleReconciliation === pending) { @@ -1754,7 +1754,7 @@ export function makeOpenCodeAdapter( } yield* failPromptAdmissionRecovery(context, promptAdmission); }).pipe( - Effect.catchCause(() => Effect.void), + Effect.ignoreCause, Effect.ensuring( Effect.sync(() => { delete promptAdmission.recoveryFiber; @@ -1967,7 +1967,7 @@ export function makeOpenCodeAdapter( }), Effect.catchIf( (cause) => isOpenCodeNotFound(cause), - () => Effect.succeed(undefined), + () => Effect.undefined, ), ); let sessionId: string | undefined = candidateSessionId; @@ -2353,7 +2353,7 @@ export function makeOpenCodeAdapter( yield* Effect.sleep(`${delayMs} millis`); } }).pipe( - Effect.catchCause(() => Effect.void), + Effect.ignoreCause, Effect.ensuring( Effect.sync(() => { if (context.requestRelationRetries.get(requestId) === retry) { @@ -2473,7 +2473,7 @@ export function makeOpenCodeAdapter( return; } }).pipe( - Effect.catchCause(() => Effect.void), + Effect.ignoreCause, Effect.ensuring( Effect.sync(() => { if (context.pendingRequestRecovery === recovery) { @@ -3051,6 +3051,7 @@ export function makeOpenCodeAdapter( // the scope closes (explicit stop, unexpected exit, or layer // shutdown) and cancels the in-flight `event.subscribe` fetch so // the async iterable unwinds cleanly. + // @effect-diagnostics-next-line abortControllerInEffect:off - aborted by a scope finalizer to cancel the SDK's event.subscribe fetch const eventsAbortController = new AbortController(); let lastStreamError: unknown; let warnedAboutDisconnect = false; diff --git a/apps/server/src/provider/Layers/ProviderService.test.ts b/apps/server/src/provider/Layers/ProviderService.test.ts index 5a7a3fd1ee..5d3d3d1a59 100644 --- a/apps/server/src/provider/Layers/ProviderService.test.ts +++ b/apps/server/src/provider/Layers/ProviderService.test.ts @@ -7546,13 +7546,11 @@ const listThreadIds = vi.fn(() => Effect.succeed([activeSessionThreadId, historicalSessionThreadId]), ); const getBinding = vi.fn((threadId: ThreadId) => - Effect.succeed( - Option.some({ - threadId, - provider: CODEX_DRIVER, - providerInstanceId: codexInstanceId, - }), - ), + Effect.succeedSome({ + threadId, + provider: CODEX_DRIVER, + providerInstanceId: codexInstanceId, + }), ); const boundedListing = makeProviderServiceLayer({ directory: { diff --git a/apps/server/src/provider/Layers/ProviderService.ts b/apps/server/src/provider/Layers/ProviderService.ts index b6cb48239a..df638ef138 100644 --- a/apps/server/src/provider/Layers/ProviderService.ts +++ b/apps/server/src/provider/Layers/ProviderService.ts @@ -1724,15 +1724,13 @@ const makeProviderService = Effect.fn("makeProviderService")(function* ( ) { // Persist native boundaries and exact idle recovery proofs before // publishing completion to checkpoint capture. - yield* Effect.gen(function* () { - yield* persistExactConversationSelection( - canonicalEvent.threadId, - source.adapter, - source.instanceId, - currentIncarnation, - "ProviderService.persistCompletedConversation", - ); - }).pipe( + yield* persistExactConversationSelection( + canonicalEvent.threadId, + source.adapter, + source.instanceId, + currentIncarnation, + "ProviderService.persistCompletedConversation", + ).pipe( Effect.catch((cause) => Effect.logWarning("failed to persist provider completed conversation state", { provider: source.provider, @@ -4635,7 +4633,7 @@ const makeProviderService = Effect.fn("makeProviderService")(function* ( // Snapshot settings once per stop operation, then resolve continuation against // each session's project in both the ordinary and mixed-adapter shutdown paths. const readStopSettings = serverSettings.getSettings.pipe( - Effect.map(Option.some), + Effect.asSome, Effect.orElseSucceed(() => Option.none()), ); const continueAfterRestartFor = Effect.fn("continueAfterRestartFor")(function* ( diff --git a/apps/server/src/provider/Layers/ProviderSessionDirectory.ts b/apps/server/src/provider/Layers/ProviderSessionDirectory.ts index e80b8903e1..99080ca7c7 100644 --- a/apps/server/src/provider/Layers/ProviderSessionDirectory.ts +++ b/apps/server/src/provider/Layers/ProviderSessionDirectory.ts @@ -103,9 +103,7 @@ const makeProviderSessionDirectory = Effect.gen(function* () { Option.match(runtime, { onNone: () => Effect.succeed(Option.none()), onSome: (value) => - toRuntimeBinding(value, "ProviderSessionDirectory.getBinding").pipe( - Effect.map((binding) => Option.some(binding)), - ), + toRuntimeBinding(value, "ProviderSessionDirectory.getBinding").pipe(Effect.asSome), }), ), ); diff --git a/apps/server/src/provider/Layers/cursorUsageLimits.ts b/apps/server/src/provider/Layers/cursorUsageLimits.ts index ae1bc36184..238809edeb 100644 --- a/apps/server/src/provider/Layers/cursorUsageLimits.ts +++ b/apps/server/src/provider/Layers/cursorUsageLimits.ts @@ -127,14 +127,12 @@ export const readCursorUsageLimits = Effect.fn("readCursorUsageLimits")(function return cursorUsageResponseToLimits(body, checkedAt); }).pipe( Effect.timeout("10 seconds"), - Effect.catch(() => - Effect.succeed( - makeUnavailableUsageLimits({ - checkedAt, - reason: "probeFailed", - message: "Cursor could not read usage limits.", - }), - ), + Effect.orElseSucceed(() => + makeUnavailableUsageLimits({ + checkedAt, + reason: "probeFailed", + message: "Cursor could not read usage limits.", + }), ), ); }); diff --git a/apps/server/src/provider/Layers/grokUsageLimits.ts b/apps/server/src/provider/Layers/grokUsageLimits.ts index 84703fee02..d0287a9c75 100644 --- a/apps/server/src/provider/Layers/grokUsageLimits.ts +++ b/apps/server/src/provider/Layers/grokUsageLimits.ts @@ -169,7 +169,7 @@ export const readGrokAccount = Effect.fn("readGrokAccount")(function* ( return grokUsageResponseToLimits(body, checkedAt); }).pipe( Effect.timeout("10 seconds"), - Effect.catch(() => Effect.succeed(probeFailed)), + Effect.orElseSucceed(() => probeFailed), ); return { email, usageLimits }; }); diff --git a/apps/server/src/provider/ModelManifest.ts b/apps/server/src/provider/ModelManifest.ts index c74bb2f7c0..52d8f564f4 100644 --- a/apps/server/src/provider/ModelManifest.ts +++ b/apps/server/src/provider/ModelManifest.ts @@ -466,7 +466,7 @@ export const make = Effect.gen(function* () { Effect.provideService(Path.Path, path), ), ), - Effect.catchCause(() => Effect.void), + Effect.ignoreCause, ); return manifest; }); diff --git a/apps/server/src/provider/ProviderLoginSessions.ts b/apps/server/src/provider/ProviderLoginSessions.ts index 3a6185d92b..a65e983291 100644 --- a/apps/server/src/provider/ProviderLoginSessions.ts +++ b/apps/server/src/provider/ProviderLoginSessions.ts @@ -150,7 +150,7 @@ const make = Effect.gen(function* () { const urlOption = yield* Deferred.await(urlFound).pipe(Effect.timeoutOption(URL_TIMEOUT)); if (urlOption._tag === "None") { yield* close; - return yield* Effect.fail(loginError("The sign-in command did not return a link in time.")); + return yield* loginError("The sign-in command did not return a link in time."); } const url = urlOption.value; @@ -199,7 +199,7 @@ const make = Effect.gen(function* () { Effect.gen(function* () { const session = (yield* Ref.get(sessions)).get(input.sessionId); if (!session) { - return yield* Effect.fail(loginError("That sign-in is no longer running. Start it again.")); + return yield* loginError("That sign-in is no longer running. Start it again."); } yield* forget(input.sessionId); return yield* session.submitCode(input.code); diff --git a/apps/server/src/provider/acp/AcpSessionRuntime.ts b/apps/server/src/provider/acp/AcpSessionRuntime.ts index 44c5f3fb67..e001295ebd 100644 --- a/apps/server/src/provider/acp/AcpSessionRuntime.ts +++ b/apps/server/src/provider/acp/AcpSessionRuntime.ts @@ -895,16 +895,16 @@ export const make = ( acp.agent.resumeSession(resumePayload).pipe( Effect.timeoutOption(options.sessionLoadTimeout ?? defaultSessionLoadTimeout), Effect.flatMap((result) => - Option.isSome(result) - ? Effect.succeed(result.value) - : Effect.fail( - new EffectAcpErrors.AcpTransportError({ - operation: "call-rpc", - method: "session/resume", - detail: "session/resume timed out waiting for the agent response.", - cause: undefined, - }), - ), + Effect.fromOption( + result, + () => + new EffectAcpErrors.AcpTransportError({ + operation: "call-rpc", + method: "session/resume", + detail: "session/resume timed out waiting for the agent response.", + cause: undefined, + }), + ), ), ), ); @@ -949,18 +949,16 @@ export const make = ( Effect.ensuring(Fiber.interrupt(idleFiber).pipe(Effect.ignore)), Effect.timeoutOption(sessionLoadTimeout), Effect.flatMap((result) => - Option.match(result, { - onNone: () => - Effect.fail( - new EffectAcpErrors.AcpTransportError({ - operation: "call-rpc", - method: "session/load", - detail: "session/load timed out waiting for RPC response or replay idle gap", - cause: undefined, - }), - ), - onSome: Effect.succeed, - }), + Effect.fromOption( + result, + () => + new EffectAcpErrors.AcpTransportError({ + operation: "call-rpc", + method: "session/load", + detail: "session/load timed out waiting for RPC response or replay idle gap", + cause: undefined, + }), + ), ), Effect.tap((result) => logRequest({ diff --git a/apps/server/src/provider/antigravityAuthSupport.ts b/apps/server/src/provider/antigravityAuthSupport.ts index 317752ea73..a6fc2feea7 100644 --- a/apps/server/src/provider/antigravityAuthSupport.ts +++ b/apps/server/src/provider/antigravityAuthSupport.ts @@ -281,8 +281,9 @@ const linkAntigravityUserSkills = Effect.fn("linkAntigravityUserSkills")(functio yield* Effect.gen(function* () { const existing = yield* fs.readLink(link).pipe( Effect.map((value): string | undefined => path.resolve(path.dirname(link), value)), - Effect.catch((error) => - error.reason._tag === "NotFound" ? Effect.succeed(undefined) : Effect.fail(error), + Effect.catchIf( + (error) => error.reason._tag === "NotFound", + () => Effect.undefined, ), ); if (existing === target) return; diff --git a/apps/server/src/provider/claudeOAuthUsage.ts b/apps/server/src/provider/claudeOAuthUsage.ts index 7529cdcff8..11d9e2f875 100644 --- a/apps/server/src/provider/claudeOAuthUsage.ts +++ b/apps/server/src/provider/claudeOAuthUsage.ts @@ -153,7 +153,7 @@ const readKeychainAccessToken = Effect.fn("readKeychainAccessToken")(function* ( ); const result = yield* spawnAndCollect("/usr/bin/security", command).pipe( Effect.timeoutOption(KEYCHAIN_READ_TIMEOUT_MS), - Effect.catchCause(() => Effect.succeed(Option.none())), + Effect.catchCause(() => Effect.succeedNone), ); if (Option.isNone(result) || result.value.code !== 0) return undefined; return accessTokenFromKeychainValue(result.value.stdout); @@ -165,7 +165,7 @@ const readFileAccessToken = Effect.fn("readFileAccessToken")(function* ( const fileSystem = yield* FileSystem.FileSystem; const path = yield* Path.Path; const contents = yield* fileSystem.readFileString(path.join(configDir, ".credentials.json")).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catchCause(() => Effect.succeed(Option.none())), ); return Option.isNone(contents) ? undefined : accessTokenFromCredentialsJson(contents.value); @@ -441,7 +441,7 @@ export const fetchOAuthUsageWithToken = Effect.fn("fetchOAuthUsageWithToken")(fu }).pipe( Effect.timeoutOption(OAUTH_USAGE_TIMEOUT_MS), Effect.catchCause((cause) => - Cause.hasInterrupts(cause) ? Effect.interrupt : Effect.succeed(Option.none()), + Cause.hasInterrupts(cause) ? Effect.interrupt : Effect.succeedNone, ), ); if (Option.isNone(attempt) || attempt.value.kind === "failed") return yield* failedRead; diff --git a/apps/server/src/provider/codexAccountIdentity.ts b/apps/server/src/provider/codexAccountIdentity.ts index a4a1f0ba18..5844fc9960 100644 --- a/apps/server/src/provider/codexAccountIdentity.ts +++ b/apps/server/src/provider/codexAccountIdentity.ts @@ -42,7 +42,7 @@ export const readCodexAccountId = Effect.fn("readCodexAccountId")(function* ( const fileSystem = yield* FileSystem.FileSystem; const path = yield* Path.Path; const raw = yield* fileSystem.readFileString(path.join(sharedHomePath, "auth.json")).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catchCause(() => Effect.succeed(Option.none())), ); return Option.isNone(raw) ? undefined : codexAccountIdFromAuthFile(raw.value); diff --git a/apps/server/src/provider/makeManagedServerProvider.ts b/apps/server/src/provider/makeManagedServerProvider.ts index 117a93ce01..eec1212988 100644 --- a/apps/server/src/provider/makeManagedServerProvider.ts +++ b/apps/server/src/provider/makeManagedServerProvider.ts @@ -286,6 +286,7 @@ export const makeManagedServerProvider = Effect.fn("makeManagedServerProvider")( yield* Effect.forever( getRefreshInterval.pipe( Effect.flatMap((refreshInterval) => + // @effect-diagnostics-next-line raceFirstWithSleepToTimeout:off - races the interval against a settings-change signal, not a timeout Effect.raceFirst( Effect.sleep( Duration.toMillis(Duration.fromInputUnsafe(refreshInterval)) <= 0 diff --git a/apps/server/src/provider/prime/PrimeAgentDaemonAdapter.test.ts b/apps/server/src/provider/prime/PrimeAgentDaemonAdapter.test.ts index cc5305ee7b..8f334c3d0e 100644 --- a/apps/server/src/provider/prime/PrimeAgentDaemonAdapter.test.ts +++ b/apps/server/src/provider/prime/PrimeAgentDaemonAdapter.test.ts @@ -10958,10 +10958,10 @@ describe("PrimeAgentDaemonAdapter", () => { } const stopFiber = yield* adapter.stopAll().pipe(Effect.forkChild); - yield* Effect.all( - captures.map((capture) => Queue.take(capture.disposeObserved!)), - { concurrency: "unbounded", discard: true }, - ); + yield* Effect.forEach(captures, (capture) => Queue.take(capture.disposeObserved!), { + concurrency: "unbounded", + discard: true, + }); expect(captures.map((capture) => capture.disposeCount)).toEqual([1, 1, 1, 1]); expect(stopFiber.pollUnsafe()).toBeUndefined(); @@ -11469,7 +11469,7 @@ describe("PrimeAgentDaemonAdapter", () => { runtimeFactory: fakeRuntimeFactory(captures), recoveryLedger: { // Ordinary startup must reject the row before interpreting its authority. - get: () => Effect.succeed(Option.some({ threadId })), + get: () => Effect.succeedSome({ threadId }), } as unknown as PrimeAgentRecoveryLedgerShape, }); const error = yield* adapter @@ -11515,7 +11515,7 @@ describe("PrimeAgentDaemonAdapter", () => { let managedAttempts = 0; let discarded = false; const recoveryLedger = { - get: () => Effect.succeed(Option.none()), + get: () => Effect.succeedNone, discardPrepared: (input: { threadId: string; ownerToken: string }) => Effect.sync(() => { expect(input.threadId).toBe(threadId); @@ -11581,7 +11581,7 @@ describe("PrimeAgentDaemonAdapter", () => { const markIdleCalls: Array<{ readonly threadId: string; readonly ownerToken: string }> = []; const recoveryLedger = { putPrepared: () => Effect.void, - get: () => Effect.succeed(Option.none()), + get: () => Effect.succeedNone, listActive: () => Effect.succeed([]), markAdmitted: () => Effect.sync(() => { @@ -11595,7 +11595,7 @@ describe("PrimeAgentDaemonAdapter", () => { }).pipe(Effect.tap(() => Deferred.succeed(markIdleObserved, undefined))), discardPrepared: () => Effect.succeed(true), updateTranscriptProgress: () => Effect.succeed(true), - claim: () => Effect.succeed(Option.none()), + claim: () => Effect.succeedNone, releaseClaim: () => Effect.succeed(true), commitAdoption: () => Effect.succeed(true), markNativeCleanup: () => Effect.succeed(true), diff --git a/apps/server/src/provider/prime/PrimeAgentDaemonAdapter.ts b/apps/server/src/provider/prime/PrimeAgentDaemonAdapter.ts index 3ecc76033b..246eb15a42 100644 --- a/apps/server/src/provider/prime/PrimeAgentDaemonAdapter.ts +++ b/apps/server/src/provider/prime/PrimeAgentDaemonAdapter.ts @@ -5125,6 +5125,7 @@ export function makePrimeAgentDaemonAdapter( recoveryStart?.kind === "adopt" && recoveryStart.authority.turnId !== null ? { id: TurnId.make(recoveryStart.authority.turnId), + // @effect-diagnostics-next-line abortControllerInEffect:off - owned by the active turn and aborted by Stop/cancel paths outside this fiber controller: new AbortController(), completed: yield* Deferred.make(), correlationId: recoveryStart.authority.correlationId, @@ -6137,6 +6138,7 @@ export function makePrimeAgentDaemonAdapter( : undefined; const turn: PrimeAgentDaemonActiveTurn = { id: turnId, + // @effect-diagnostics-next-line abortControllerInEffect:off - owned by the active turn and aborted by Stop/cancel paths outside this fiber controller: new AbortController(), completed: yield* Deferred.make(), ...(correlationId === undefined @@ -7886,7 +7888,7 @@ export function makePrimeAgentDaemonAdapter( }), ), ), - Effect.catchCause(() => Effect.void), + Effect.ignoreCause, ); yield* Effect.forkIn(runCompaction, reserved.scope); return reserved.compaction; diff --git a/apps/server/src/provider/prime/PrimeAgentDaemonManager.ts b/apps/server/src/provider/prime/PrimeAgentDaemonManager.ts index 3cc0dac4d9..774d1cb1ee 100644 --- a/apps/server/src/provider/prime/PrimeAgentDaemonManager.ts +++ b/apps/server/src/provider/prime/PrimeAgentDaemonManager.ts @@ -1089,11 +1089,10 @@ export const makePrimeAgentDaemonManager = Effect.fn("makePrimeAgentDaemonManage ); if (isRunning) { const healthClient = yield* connectClient({ bridge, socket, timeoutMs }).pipe( - Effect.map(Option.some), - Effect.catch((error) => - error.reason === "readiness-failed" - ? Effect.succeed(Option.none()) - : Effect.fail(error), + Effect.asSome, + Effect.catchIf( + (error) => error.reason === "readiness-failed", + () => Effect.succeedNone, ), ); if (Option.isSome(healthClient)) { diff --git a/apps/server/src/provider/prime/PrimeAgentDaemonSessionRuntime.test.ts b/apps/server/src/provider/prime/PrimeAgentDaemonSessionRuntime.test.ts index 45905c77da..cde6423aba 100644 --- a/apps/server/src/provider/prime/PrimeAgentDaemonSessionRuntime.test.ts +++ b/apps/server/src/provider/prime/PrimeAgentDaemonSessionRuntime.test.ts @@ -1,3 +1,4 @@ +// @effect-diagnostics abortControllerInEffect:off - Tests hand-built AbortSignals to the runtime to exercise cancellation. // @effect-diagnostics nodeBuiltinImport:off import * as NodeFSP from "node:fs/promises"; import * as NodeOS from "node:os"; diff --git a/apps/server/src/provider/prime/PrimeAgentDaemonSessionRuntime.ts b/apps/server/src/provider/prime/PrimeAgentDaemonSessionRuntime.ts index 116388ee56..39ab70b18b 100644 --- a/apps/server/src/provider/prime/PrimeAgentDaemonSessionRuntime.ts +++ b/apps/server/src/provider/prime/PrimeAgentDaemonSessionRuntime.ts @@ -1839,6 +1839,7 @@ export const makePrimeAgentDaemonSessionRuntime = Effect.fn("makePrimeAgentDaemo prompt: NonNullable, ): Promise => { if (prompt.promptAdmissionObserved) return Promise.resolve(true); + // @effect-diagnostics-next-line raceFirstWithSleepToTimeout:off - the grace window expiring is a real outcome (false), not a timeout failure return Effect.raceFirst( Effect.promise(() => prompt.admissionEvidencePromise), Effect.sleep(PRIME_AGENT_PROMPT_ADMISSION_EVIDENCE_GRACE_MS).pipe(Effect.as(false)), @@ -7430,12 +7431,13 @@ export const makePrimeAgentDaemonSessionRuntime = Effect.fn("makePrimeAgentDaemo }, publicationProofEpoch, ).pipe( - Effect.catch((cause) => - cause === CORRELATED_PROOF_FENCE_RETIRED - ? Effect.promise(() => failCorrelatedProofRecovery(undefined, "proof-lost")).pipe( - Effect.flatMap(() => workerRecoveryFailure()), - ) - : Effect.fail(cause), + Effect.catchIf( + (cause): cause is typeof CORRELATED_PROOF_FENCE_RETIRED => + cause === CORRELATED_PROOF_FENCE_RETIRED, + () => + Effect.promise(() => failCorrelatedProofRecovery(undefined, "proof-lost")).pipe( + Effect.flatMap(() => workerRecoveryFailure()), + ), ), ); if ( @@ -7642,10 +7644,10 @@ export const makePrimeAgentDaemonSessionRuntime = Effect.fn("makePrimeAgentDaemo proofEpoch, onCommit, ).pipe( - Effect.catch((cause) => - cause === CORRELATED_PROOF_FENCE_RETIRED - ? correlatedProofUnavailable(operation) - : Effect.fail(cause), + Effect.catchIf( + (cause): cause is typeof CORRELATED_PROOF_FENCE_RETIRED => + cause === CORRELATED_PROOF_FENCE_RETIRED, + () => correlatedProofUnavailable(operation), ), ); diff --git a/apps/server/src/provider/prime/PrimeAgentMultipleInstances.integration.test.ts b/apps/server/src/provider/prime/PrimeAgentMultipleInstances.integration.test.ts index 09be67fbfc..4996c431c1 100644 --- a/apps/server/src/provider/prime/PrimeAgentMultipleInstances.integration.test.ts +++ b/apps/server/src/provider/prime/PrimeAgentMultipleInstances.integration.test.ts @@ -955,19 +955,17 @@ it.live.skipIf(!configuredGraduationArtifact || !runMultipleInstanceProof)( yield* promptAndWait(instances[0]!, "PYLON_NATIVE_A_COLD_OK"); yield* promptAndWait(instances[1]!, "PYLON_NATIVE_B_COLD_OK"); } else { - yield* Effect.all( - instances.map((instance, index) => - promptAndWait(instance, `PYLON_NATIVE_${index}_COLD_OK`), - ), + yield* Effect.forEach( + instances, + (instance, index) => promptAndWait(instance, `PYLON_NATIVE_${index}_COLD_OK`), { concurrency: "unbounded" }, ); } reportSafePhase("overlapping-turns"); - yield* Effect.all( - instances.map((instance, index) => - promptAndWait(instance, `PYLON_NATIVE_${index}_OVERLAP_OK`), - ), + yield* Effect.forEach( + instances, + (instance, index) => promptAndWait(instance, `PYLON_NATIVE_${index}_OVERLAP_OK`), { concurrency: "unbounded" }, ); @@ -1066,10 +1064,9 @@ it.live.skipIf(!configuredGraduationArtifact || !runMultipleInstanceProof)( } reportSafePhase("survivors-after-removal"); - yield* Effect.all( - survivors.map((instance, index) => - promptAndWait(instance, `PYLON_NATIVE_SURVIVOR_${index}_OK`), - ), + yield* Effect.forEach( + survivors, + (instance, index) => promptAndWait(instance, `PYLON_NATIVE_SURVIVOR_${index}_OK`), { concurrency: "unbounded" }, ); expect(removed.map((instance) => instance.openCount.value)).toEqual(removedOpenCounts); diff --git a/apps/server/src/provider/prime/PrimeAgentRealDaemon.integration.test.ts b/apps/server/src/provider/prime/PrimeAgentRealDaemon.integration.test.ts index aee0cb3256..b3d2928d9e 100644 --- a/apps/server/src/provider/prime/PrimeAgentRealDaemon.integration.test.ts +++ b/apps/server/src/provider/prime/PrimeAgentRealDaemon.integration.test.ts @@ -1,3 +1,4 @@ +// @effect-diagnostics abortControllerInEffect:off - Tests hand-built AbortSignals to the runtime to exercise cancellation. // @effect-diagnostics nodeBuiltinImport:off import * as NodeFS from "node:fs"; import * as NodePath from "node:path"; diff --git a/apps/server/src/provider/prime/PrimeAgentRecoveryLedger.ts b/apps/server/src/provider/prime/PrimeAgentRecoveryLedger.ts index a1dd65dfdb..65eb84d2a5 100644 --- a/apps/server/src/provider/prime/PrimeAgentRecoveryLedger.ts +++ b/apps/server/src/provider/prime/PrimeAgentRecoveryLedger.ts @@ -634,9 +634,7 @@ export const make = Effect.gen(function* () { input.expectedOwnerToken, ], options, - ).pipe( - Effect.flatMap((claimed) => (claimed ? get(input.threadId) : Effect.succeed(Option.none()))), - ); + ).pipe(Effect.flatMap((claimed) => (claimed ? get(input.threadId) : Effect.succeedNone))); const beginAdoptionAttempt: PrimeAgentRecoveryLedgerShape["beginAdoptionAttempt"] = ( input, @@ -659,9 +657,7 @@ export const make = Effect.gen(function* () { PRIME_AGENT_RECOVERY_ADOPTION_MAX_ATTEMPTS, ], options, - ).pipe( - Effect.flatMap((started) => (started ? get(input.threadId) : Effect.succeed(Option.none()))), - ); + ).pipe(Effect.flatMap((started) => (started ? get(input.threadId) : Effect.succeedNone))); const releaseClaim: PrimeAgentRecoveryLedgerShape["releaseClaim"] = (input, options) => conditionalUpdate( @@ -733,9 +729,7 @@ export const make = Effect.gen(function* () { PRIME_AGENT_RECOVERY_ADOPTION_MAX_ATTEMPTS, ], options, - ).pipe( - Effect.flatMap((started) => (started ? get(input.threadId) : Effect.succeed(Option.none()))), - ); + ).pipe(Effect.flatMap((started) => (started ? get(input.threadId) : Effect.succeedNone))); const finalizeAdoption: PrimeAgentRecoveryLedgerShape["finalizeAdoption"] = (input, options) => { const proofJson = encodeAdoptionProof(input.proof); diff --git a/apps/server/src/provider/primeAgentBackends.ts b/apps/server/src/provider/primeAgentBackends.ts index 17c23af21d..64c45c430f 100644 --- a/apps/server/src/provider/primeAgentBackends.ts +++ b/apps/server/src/provider/primeAgentBackends.ts @@ -392,7 +392,7 @@ export const readPrimeAgentCapacity = Effect.fn("readPrimeAgentCapacity")(functi const homePath = resolvePrimeAgentHomePath(settings, path, options); if (!homePath) return undefined; const raw = yield* fileSystem.readFileString(path.join(homePath, "auth.json")).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catchCause(() => Effect.succeed(Option.none())), ); if (Option.isNone(raw) || Option.isNone(decodePrimeAuthFile(raw.value))) return undefined; diff --git a/apps/server/src/provider/providerInstallation.ts b/apps/server/src/provider/providerInstallation.ts index 04c6de0566..a4d70c073c 100644 --- a/apps/server/src/provider/providerInstallation.ts +++ b/apps/server/src/provider/providerInstallation.ts @@ -118,7 +118,7 @@ export const makeProviderInstallation = Effect.fn("makeProviderInstallation")(fu env: mergeProviderInstanceEnvironment(entry.environment), }).pipe( Effect.map((resolved) => [binaryPath, resolved]), - Effect.catch(() => Effect.succeed([binaryPath])), + Effect.orElseSucceed(() => [binaryPath]), ); }); yield* installation diff --git a/apps/server/src/provider/providerLoginCoordinator.ts b/apps/server/src/provider/providerLoginCoordinator.ts index 90aacb9596..399d654c2e 100644 --- a/apps/server/src/provider/providerLoginCoordinator.ts +++ b/apps/server/src/provider/providerLoginCoordinator.ts @@ -55,13 +55,13 @@ const resolveInstance = (instanceId: ProviderInstanceId) => ); const instance = settings.providerInstances[instanceId]; if (!instance) { - return yield* Effect.fail(loginError(`Unknown provider instance "${instanceId}".`)); + return yield* loginError(`Unknown provider instance "${instanceId}".`); } if (instance.driver !== CLAUDE_DRIVER) { // Codex has its own login protocol and the rest have none; offering a // flow that cannot work is worse than saying so. - return yield* Effect.fail( - loginError(`Signing in from Pylon is not supported for ${instance.driver} yet.`), + return yield* loginError( + `Signing in from Pylon is not supported for ${instance.driver} yet.`, ); } const config = decodeClaudeSettings(instance.config ?? {}); diff --git a/apps/server/src/provider/providerMaintenanceRunner.ts b/apps/server/src/provider/providerMaintenanceRunner.ts index dde1b95b41..797a3e3b65 100644 --- a/apps/server/src/provider/providerMaintenanceRunner.ts +++ b/apps/server/src/provider/providerMaintenanceRunner.ts @@ -316,7 +316,7 @@ export const make = Effect.fn("ProviderMaintenanceRunner.make")(function* () { provider, ); const runtimeFence = yield* ( - providerRegistry.getProviderRuntimeFence?.(instanceId) ?? Effect.succeed(undefined) + providerRegistry.getProviderRuntimeFence?.(instanceId) ?? Effect.undefined ); const update = capabilities.update; if (!update) { diff --git a/apps/server/src/provider/sharedUsageReadCache.ts b/apps/server/src/provider/sharedUsageReadCache.ts index 5bea6ea7e6..06533749b8 100644 --- a/apps/server/src/provider/sharedUsageReadCache.ts +++ b/apps/server/src/provider/sharedUsageReadCache.ts @@ -199,7 +199,7 @@ export const readSharedUsageEntry = Effect.fn("readSharedUsageEntry")(function* const fileSystem = yield* FileSystem.FileSystem; const path = yield* Path.Path; const raw = yield* fileSystem.readFileString(entryPath(path, dir, key)).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catchCause(() => Effect.succeed(Option.none())), ); if (Option.isNone(raw)) return undefined; @@ -231,7 +231,7 @@ export const writeSharedUsageEntry = Effect.fn("writeSharedUsageEntry")(function return; } yield* fileSystem.rename(temp, target); - }).pipe(Effect.catchCause(() => Effect.void)); + }).pipe(Effect.ignoreCause); }); /** diff --git a/apps/server/src/pullRequest/GitLabPullRequestCli.ts b/apps/server/src/pullRequest/GitLabPullRequestCli.ts index 5a07bb1ae3..c3b6070024 100644 --- a/apps/server/src/pullRequest/GitLabPullRequestCli.ts +++ b/apps/server/src/pullRequest/GitLabPullRequestCli.ts @@ -1250,7 +1250,7 @@ export const make = Effect.gen(function* () { getMergeRequestDiffFileContents: (input) => Effect.gen(function* () { if (input.commit !== undefined && !isCommitSha(input.commit)) { - return yield* Effect.fail(new GitLabDiffCommitError({ command: "glab", cwd: input.cwd })); + return yield* new GitLabDiffCommitError({ command: "glab", cwd: input.cwd }); } const refs = yield* input.commit === undefined ? getDiffRefs(input) diff --git a/apps/server/src/pullRequest/PullRequestReadCache.ts b/apps/server/src/pullRequest/PullRequestReadCache.ts index 1b4ded39b9..724fbe490d 100644 --- a/apps/server/src/pullRequest/PullRequestReadCache.ts +++ b/apps/server/src/pullRequest/PullRequestReadCache.ts @@ -77,7 +77,7 @@ export const make = Effect.gen(function* () { () => backing .get("revisions") - .pipe(Effect.flatMap((raw) => Schema.decodeUnknownEffect(revisionCodec)(raw ?? "{}"))), + .pipe(Effect.flatMap((raw) => Schema.decodeEffect(revisionCodec)(raw ?? "{}"))), { capacity: 1, timeToLive: (exit) => (Exit.isSuccess(exit) ? Duration.infinity : Duration.zero), diff --git a/apps/server/src/pullRequest/PullRequestService.test.ts b/apps/server/src/pullRequest/PullRequestService.test.ts index 88c4b03f86..d9142ddfad 100644 --- a/apps/server/src/pullRequest/PullRequestService.test.ts +++ b/apps/server/src/pullRequest/PullRequestService.test.ts @@ -3099,13 +3099,13 @@ it.effect("shares one cold viewer lookup across distinct concurrent lists", () = ], }); - yield* Effect.all( - ["all", "authored", "reviewing"].map((involvement) => + yield* Effect.forEach( + ["all", "authored", "reviewing"], + (involvement) => service.list({ state: "open", involvement: involvement as "all" | "authored" | "reviewing", }), - ), { concurrency: "unbounded" }, ); diff --git a/apps/server/src/pullRequest/PullRequestService.ts b/apps/server/src/pullRequest/PullRequestService.ts index d434ca71a1..f71a88dea2 100644 --- a/apps/server/src/pullRequest/PullRequestService.ts +++ b/apps/server/src/pullRequest/PullRequestService.ts @@ -1749,15 +1749,13 @@ export const make = Effect.gen(function* () { .getViewer({ cwd: project.project.workspaceRoot, host: project.host }) .pipe( Effect.mapError(toPullRequestError(operation)), - Effect.flatMap((viewer) => - viewer === null || viewer.trim().length === 0 - ? Effect.fail( - new PullRequestOperationError({ - operation, - detail: "The signed-in account could not be verified for viewed files.", - }), - ) - : Effect.succeed(viewer), + Effect.filterOrFail( + (viewer) => viewer !== null && viewer.trim().length > 0, + () => + new PullRequestOperationError({ + operation, + detail: "The signed-in account could not be verified for viewed files.", + }), ), ); }; @@ -2628,7 +2626,7 @@ export const make = Effect.gen(function* () { `project:${input.projectId}`, refScope(input), ]); - const decoded = yield* Schema.decodeUnknownEffect(codec)(payload).pipe(Effect.option); + const decoded = yield* Schema.decodeEffect(codec)(payload).pipe(Effect.option); return Option.isSome(decoded) ? decoded.value : yield* lookup; }); const summaryCodec = Schema.fromJsonString(PullRequestSummary); diff --git a/apps/server/src/relay/AgentAwarenessRelay.test.ts b/apps/server/src/relay/AgentAwarenessRelay.test.ts index 11ac572e92..ba832f1023 100644 --- a/apps/server/src/relay/AgentAwarenessRelay.test.ts +++ b/apps/server/src/relay/AgentAwarenessRelay.test.ts @@ -670,7 +670,7 @@ describe.sequential("signRelayAgentActivityPublishProof", () => { yield* Deferred.await(releaseThreadShell); return Option.some(thread); }), - getProjectShellById: () => Effect.succeed(Option.some(project)), + getProjectShellById: () => Effect.succeedSome(project), } as unknown as ProjectionSnapshotQueryShape; const descriptor = { @@ -887,8 +887,8 @@ describe.sequential("signRelayAgentActivityPublishProof", () => { threads: [thread], updatedAt: now, } satisfies OrchestrationShellSnapshot), - getThreadShellById: () => Effect.succeed(Option.some(thread)), - getProjectShellById: () => Effect.succeed(Option.some(project)), + getThreadShellById: () => Effect.succeedSome(thread), + getProjectShellById: () => Effect.succeedSome(project), } as unknown as ProjectionSnapshotQueryShape), ); diff --git a/apps/server/src/relay/AgentAwarenessRelayStartup.test.ts b/apps/server/src/relay/AgentAwarenessRelayStartup.test.ts index 95887f6342..e4973f3d39 100644 --- a/apps/server/src/relay/AgentAwarenessRelayStartup.test.ts +++ b/apps/server/src/relay/AgentAwarenessRelayStartup.test.ts @@ -216,7 +216,7 @@ describe.sequential("AgentAwarenessRelay startup", () => { currentThread?.id === requestedThreadId ? currentThread : null, ); }), - getProjectShellById: () => Effect.succeed(Option.some(project)), + getProjectShellById: () => Effect.succeedSome(project), } as unknown as ProjectionSnapshotQueryShape), ); diff --git a/apps/server/src/resourceTelemetry/HostResources.ts b/apps/server/src/resourceTelemetry/HostResources.ts index 032832dd48..0f61ac1899 100644 --- a/apps/server/src/resourceTelemetry/HostResources.ts +++ b/apps/server/src/resourceTelemetry/HostResources.ts @@ -60,7 +60,7 @@ export const make = Effect.fn("makeHostResources")(function* () { if (platform === "linux") { const meminfo = yield* fs .readFileString("/proc/meminfo") - .pipe(Effect.catch(() => Effect.succeed(""))); + .pipe(Effect.orElseSucceed(() => "")); const available = /^MemAvailable:\s+(\d+)\s+kB$/m.exec(meminfo)?.[1]; if (available) availableMemoryBytes = Number(available) * 1024; } else if (platform === "darwin") { @@ -68,7 +68,7 @@ export const make = Effect.fn("makeHostResources")(function* () { .string(ChildProcess.make("/usr/bin/vm_stat", [], { stdin: "ignore", stderr: "ignore" })) .pipe( Effect.timeout("1 second"), - Effect.catch(() => Effect.succeed("")), + Effect.orElseSucceed(() => ""), ); availableMemoryBytes = darwinAvailableMemory(output) ?? availableMemoryBytes; } diff --git a/apps/server/src/rollback/RollbackAdmission.test.ts b/apps/server/src/rollback/RollbackAdmission.test.ts index 581ef66d2e..74dfa1f0b7 100644 --- a/apps/server/src/rollback/RollbackAdmission.test.ts +++ b/apps/server/src/rollback/RollbackAdmission.test.ts @@ -159,25 +159,21 @@ const makeHarness = (options: HarnessOptions = {}) => { const repository = { getCheckpointAnchor: (input: { readonly checkpointTurnCount: number }) => - Effect.succeed( - Option.some({ - threadId, - checkpointTurnCount: input.checkpointTurnCount, - turnId: - input.checkpointTurnCount === 0 - ? null - : TurnId.make(`turn-${input.checkpointTurnCount}`), - sourceRevision: input.checkpointTurnCount, - providerInstanceId, - sessionIncarnationId, - checkpointRef: input.checkpointTurnCount === 0 ? baselineRef : turnOneRef, - checkpointOid: input.checkpointTurnCount === 0 ? "0".repeat(40) : "1".repeat(40), - anchor: { leafId: `PRIVATE_TARGET_${input.checkpointTurnCount}` }, - anchorDigest: `target-${input.checkpointTurnCount}`, - capturedAt: now, - }), - ), - getActiveByThread: () => Effect.succeed(Option.none()), + Effect.succeedSome({ + threadId, + checkpointTurnCount: input.checkpointTurnCount, + turnId: + input.checkpointTurnCount === 0 ? null : TurnId.make(`turn-${input.checkpointTurnCount}`), + sourceRevision: input.checkpointTurnCount, + providerInstanceId, + sessionIncarnationId, + checkpointRef: input.checkpointTurnCount === 0 ? baselineRef : turnOneRef, + checkpointOid: input.checkpointTurnCount === 0 ? "0".repeat(40) : "1".repeat(40), + anchor: { leafId: `PRIVATE_TARGET_${input.checkpointTurnCount}` }, + anchorDigest: `target-${input.checkpointTurnCount}`, + capturedAt: now, + }), + getActiveByThread: () => Effect.succeedNone, findLeaseByWorkspace: () => Effect.succeed( options.activeLease === true diff --git a/apps/server/src/server.test.ts b/apps/server/src/server.test.ts index eeef906a3e..5fe6a3d025 100644 --- a/apps/server/src/server.test.ts +++ b/apps/server/src/server.test.ts @@ -787,7 +787,7 @@ const buildAppUnderTest = (options?: { ...options?.layers?.usageLimitSources, }), Layer.mock(ProviderInstanceRegistry)({ - getInstance: () => Effect.succeed(undefined), + getInstance: () => Effect.undefined, ...options?.layers?.providerInstances, }), Layer.mock(ModelManifest.ModelManifest)({ @@ -830,7 +830,7 @@ const buildAppUnderTest = (options?: { }), Layer.mock(ProviderSessionDirectory.ProviderSessionDirectory)({ upsert: () => Effect.void, - getBinding: () => Effect.succeed(Option.none()), + getBinding: () => Effect.succeedNone, listThreadIds: () => Effect.succeed([]), listBindings: () => Effect.succeed([]), ...options?.layers?.providerSessionDirectory, @@ -856,7 +856,7 @@ const buildAppUnderTest = (options?: { Layer.mergeAll( Layer.mock(ExternalLauncher.ExternalLauncher)({ resolveAvailableEditors: () => Effect.succeed([]), - resolveFileManagerRevealKind: () => Effect.sync((): undefined => undefined), + resolveFileManagerRevealKind: () => Effect.undefined, ...options?.layers?.externalLauncher, }), Layer.mock(RemoteOpenTargets.RemoteOpenTargets)({ @@ -1012,19 +1012,19 @@ const buildAppUnderTest = (options?: { withMutationFence: (effect) => effect, withProviderMutationFence: (_providerInstanceIds, effect) => effect, admit: () => Effect.void, - get: () => Effect.succeed(Option.none()), - getByRequestEvent: () => Effect.succeed(Option.none()), - getActiveByThread: () => Effect.succeed(Option.none()), + get: () => Effect.succeedNone, + getByRequestEvent: () => Effect.succeedNone, + getActiveByThread: () => Effect.succeedNone, listNonterminal: () => Effect.succeed([]), listNonterminalForFence: () => Effect.succeed([]), clearOwnersForStartup: () => Effect.void, - claim: () => Effect.succeed(Option.none()), - updateOwned: () => Effect.succeed(Option.none()), + claim: () => Effect.succeedNone, + updateOwned: () => Effect.succeedNone, releaseOwnerOwned: () => Effect.void, - releaseLeaseOwned: () => Effect.succeed(Option.none()), - findLeaseByWorkspace: () => Effect.succeed(Option.none()), + releaseLeaseOwned: () => Effect.succeedNone, + findLeaseByWorkspace: () => Effect.succeedNone, putCheckpointAnchor: () => Effect.void, - getCheckpointAnchor: () => Effect.succeed(Option.none()), + getCheckpointAnchor: () => Effect.succeedNone, deleteCheckpointAnchorsAfter: () => Effect.void, ...options?.layers?.rollbackSagaRepository, }), @@ -1057,20 +1057,20 @@ const buildAppUnderTest = (options?: { }), searchThreads: () => Effect.succeed({ matches: [] }), getSnapshotSequence: () => Effect.succeed({ snapshotSequence: 0 }), - getProjectShellById: () => Effect.succeed(Option.none()), - getThreadShellById: () => Effect.succeed(Option.none()), - getThreadDetailById: () => Effect.succeed(Option.none()), - getThreadDetailSnapshot: () => Effect.succeed(Option.none()), + getProjectShellById: () => Effect.succeedNone, + getThreadShellById: () => Effect.succeedNone, + getThreadDetailById: () => Effect.succeedNone, + getThreadDetailSnapshot: () => Effect.succeedNone, getCounts: () => Effect.succeed({ projectCount: 0, threadCount: 0 }), getEventReplayStats: ({ fromSequenceExclusive, toSequenceInclusive }) => Effect.succeed({ eventCount: Math.max(0, toSequenceInclusive - fromSequenceExclusive), payloadBytes: 0, }), - getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()), - getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()), + getActiveProjectByWorkspaceRoot: () => Effect.succeedNone, + getFirstActiveThreadIdByProjectId: () => Effect.succeedNone, getImportedAgentSessionSources: () => Effect.succeed([]), - getThreadCheckpointContext: () => Effect.succeed(Option.none()), + getThreadCheckpointContext: () => Effect.succeedNone, ...options?.layers?.projectionSnapshotQuery, }), ), @@ -1248,7 +1248,7 @@ const buildAppUnderTest = (options?: { Layer.provide( Layer.mock(CloudCliTokenManager.CloudCliTokenManager)({ get: Effect.die(new Error("Unexpected Pylon Connect CLI authorization request.")), - getExisting: Effect.succeed(Option.none()), + getExisting: Effect.succeedNone, hasCredential: Effect.succeed(false), clear: Effect.void, ...options?.layers?.cloudCliTokenManager, @@ -6205,7 +6205,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { Effect.gen(function* () { const lookup = vi.fn< ProjectionSnapshotQuery.ProjectionSnapshotQuery["Service"]["getActiveProjectByWorkspaceRoot"] - >(() => Effect.succeed(Option.none())); + >(() => Effect.succeedNone); yield* buildAppUnderTest({ layers: { projectionSnapshotQuery: { getActiveProjectByWorkspaceRoot: lookup } }, }); @@ -8971,8 +8971,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { yield* buildAppUnderTest({ layers: { projectionSnapshotQuery: { - getThreadDetailSnapshot: () => - Effect.succeed(Option.some({ snapshotSequence: 1, thread })), + getThreadDetailSnapshot: () => Effect.succeedSome({ snapshotSequence: 1, thread }), }, }, }); @@ -9145,16 +9144,13 @@ it.layer(NodeServices.layer)("server router seam", (it) => { streamDomainEvents: Stream.concat(Stream.make(event), Stream.never), }, projectionSnapshotQuery: { - getThreadDetailSnapshot: () => - Effect.succeed(Option.some({ snapshotSequence: 1, thread })), + getThreadDetailSnapshot: () => Effect.succeedSome({ snapshotSequence: 1, thread }), getThreadShellById: (threadId) => - Effect.succeed( - Option.some({ - ...makeDefaultOrchestrationThreadShell(), - id: threadId, - title: "Build complete", - }), - ), + Effect.succeedSome({ + ...makeDefaultOrchestrationThreadShell(), + id: threadId, + title: "Build complete", + }), }, }, }); @@ -9432,7 +9428,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { }, projectionSnapshotQuery: { getThreadDetailSnapshot: () => - Effect.succeed(Option.some({ snapshotSequence: 100_000, thread })), + Effect.succeedSome({ snapshotSequence: 100_000, thread }), }, }, }); @@ -9750,8 +9746,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { }), }, projectionSnapshotQuery: { - getThreadDetailSnapshot: () => - Effect.succeed(Option.some({ snapshotSequence: 5, thread })), + getThreadDetailSnapshot: () => Effect.succeedSome({ snapshotSequence: 5, thread }), }, }, }); @@ -9839,7 +9834,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { projectionSnapshotQuery: { getThreadDetailSnapshot: (_threadId, options) => { requestedTurnLimit = options?.turnLimit; - return Effect.succeed(Option.some({ snapshotSequence: 5, thread })); + return Effect.succeedSome({ snapshotSequence: 5, thread }); }, }, }, @@ -9932,7 +9927,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { readEvents: store.readFromSequence, }, projectionSnapshotQuery: { - getThreadDetailSnapshot: () => Effect.succeed(Option.none()), + getThreadDetailSnapshot: () => Effect.succeedNone, }, }, }); @@ -10330,8 +10325,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { replayStatsCalls += 1; return { eventCount: 5, payloadBytes: 8 * 1024 * 1024 + 1 }; }), - getThreadDetailSnapshot: () => - Effect.succeed(Option.some({ snapshotSequence: 5, thread })), + getThreadDetailSnapshot: () => Effect.succeedSome({ snapshotSequence: 5, thread }), getShellSnapshot: () => Effect.succeed({ snapshotSequence: 5, @@ -10635,7 +10629,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { ]), }, projectionSnapshotQuery: { - getThreadShellById: () => Effect.succeed(Option.none()), + getThreadShellById: () => Effect.succeedNone, }, }, }); @@ -10693,9 +10687,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { detail: "transient failure", }), ) - : Effect.succeed( - Option.some(makeDefaultOrchestrationThreadShell({ id: threadId })), - ); + : Effect.succeedSome(makeDefaultOrchestrationThreadShell({ id: threadId })); }), }, }, @@ -10755,7 +10747,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { ]), }, projectionSnapshotQuery: { - getProjectShellById: () => Effect.succeed(Option.none()), + getProjectShellById: () => Effect.succeedNone, }, }, }); @@ -10801,22 +10793,20 @@ it.layer(NodeServices.layer)("server router seam", (it) => { }, projectionSnapshotQuery: { getThreadShellById: () => - Effect.succeed( - Option.some( - makeDefaultOrchestrationThreadShell({ - id: threadId, + Effect.succeedSome( + makeDefaultOrchestrationThreadShell({ + id: threadId, + updatedAt: now, + session: { + threadId, + status: "ready", + providerName: "claudeAgent", + runtimeMode: "full-access", + activeTurnId: null, + lastError: null, updatedAt: now, - session: { - threadId, - status: "ready", - providerName: "claudeAgent", - runtimeMode: "full-access", - activeTurnId: null, - lastError: null, - updatedAt: now, - }, - }), - ), + }, + }), ), }, }, @@ -10949,8 +10939,8 @@ it.layer(NodeServices.layer)("server router seam", (it) => { }, projectionSnapshotQuery: { getThreadShellById: () => - Effect.succeed( - Option.some(makeDefaultOrchestrationThreadShell({ id: threadId, session: null })), + Effect.succeedSome( + makeDefaultOrchestrationThreadShell({ id: threadId, session: null }), ), }, }, @@ -11003,22 +10993,20 @@ it.layer(NodeServices.layer)("server router seam", (it) => { }, projectionSnapshotQuery: { getThreadShellById: () => - Effect.succeed( - Option.some( - makeDefaultOrchestrationThreadShell({ - id: threadId, + Effect.succeedSome( + makeDefaultOrchestrationThreadShell({ + id: threadId, + updatedAt: now, + session: { + threadId, + status: "stopped", + providerName: "claudeAgent", + runtimeMode: "full-access", + activeTurnId: null, + lastError: null, updatedAt: now, - session: { - threadId, - status: "stopped", - providerName: "claudeAgent", - runtimeMode: "full-access", - activeTurnId: null, - lastError: null, - updatedAt: now, - }, - }), - ), + }, + }), ), }, }, @@ -11069,22 +11057,20 @@ it.layer(NodeServices.layer)("server router seam", (it) => { }, projectionSnapshotQuery: { getThreadShellById: () => - Effect.succeed( - Option.some( - makeDefaultOrchestrationThreadShell({ - id: threadId, + Effect.succeedSome( + makeDefaultOrchestrationThreadShell({ + id: threadId, + updatedAt: now, + session: { + threadId, + status: "ready", + providerName: "claudeAgent", + runtimeMode: "full-access", + activeTurnId: null, + lastError: null, updatedAt: now, - session: { - threadId, - status: "ready", - providerName: "claudeAgent", - runtimeMode: "full-access", - activeTurnId: null, - lastError: null, - updatedAt: now, - }, - }), - ), + }, + }), ), }, }, @@ -11172,22 +11158,20 @@ it.layer(NodeServices.layer)("server router seam", (it) => { }, projectionSnapshotQuery: { getThreadShellById: () => - Effect.succeed( - Option.some( - makeDefaultOrchestrationThreadShell({ - id: threadId, + Effect.succeedSome( + makeDefaultOrchestrationThreadShell({ + id: threadId, + updatedAt: now, + session: { + threadId, + status: "ready", + providerName: "claudeAgent", + runtimeMode: "full-access", + activeTurnId: null, + lastError: null, updatedAt: now, - session: { - threadId, - status: "ready", - providerName: "claudeAgent", - runtimeMode: "full-access", - activeTurnId: null, - lastError: null, - updatedAt: now, - }, - }), - ), + }, + }), ), }, }, @@ -11244,22 +11228,20 @@ it.layer(NodeServices.layer)("server router seam", (it) => { }, projectionSnapshotQuery: { getThreadShellById: () => - Effect.succeed( - Option.some( - makeDefaultOrchestrationThreadShell({ - id: threadId, + Effect.succeedSome( + makeDefaultOrchestrationThreadShell({ + id: threadId, + updatedAt: now, + session: { + threadId, + status: "ready", + providerName: "claudeAgent", + runtimeMode: "full-access", + activeTurnId: null, + lastError: null, updatedAt: now, - session: { - threadId, - status: "ready", - providerName: "claudeAgent", - runtimeMode: "full-access", - activeTurnId: null, - lastError: null, - updatedAt: now, - }, - }), - ), + }, + }), ), }, }, diff --git a/apps/server/src/serverRuntimeStartup.reconcile.test.ts b/apps/server/src/serverRuntimeStartup.reconcile.test.ts index 7e58870b8e..1151f25083 100644 --- a/apps/server/src/serverRuntimeStartup.reconcile.test.ts +++ b/apps/server/src/serverRuntimeStartup.reconcile.test.ts @@ -492,18 +492,16 @@ it.effect("does not continue archived or deleted marked sessions", () => { directory: { getBinding: (threadId) => { const thread = threadId === archived.id ? archived : deleted; - return Effect.succeed( - Option.some({ - threadId, - provider: ProviderDriverKind.make("codex"), - providerInstanceId, - status: "running" as const, - resumeCursor: { cursor: threadId }, - runtimePayload: { - continueAfterServerUpdate: thread.session.activeTurnId, - }, - }), - ); + return Effect.succeedSome({ + threadId, + provider: ProviderDriverKind.make("codex"), + providerInstanceId, + status: "running" as const, + resumeCursor: { cursor: threadId }, + runtimePayload: { + continueAfterServerUpdate: thread.session.activeTurnId, + }, + }); }, upsert: () => Effect.void, removeExact: () => Effect.die("unused"), @@ -550,18 +548,16 @@ it.effect("retries continuation preparation before settling a persistent failure threads: [thread], directory: { getBinding: () => - Effect.succeed( - Option.some({ - threadId: thread.id, - provider: ProviderDriverKind.make("codex"), - providerInstanceId, - status: "running" as const, - resumeCursor: { cursor: thread.id }, - runtimePayload: { - continueAfterServerUpdate: thread.session.activeTurnId, - }, - }), - ), + Effect.succeedSome({ + threadId: thread.id, + provider: ProviderDriverKind.make("codex"), + providerInstanceId, + status: "running" as const, + resumeCursor: { cursor: thread.id }, + runtimePayload: { + continueAfterServerUpdate: thread.session.activeTurnId, + }, + }), upsert: () => Effect.void, removeExact: () => Effect.die("unused"), recordImportedTranscript: () => Effect.die("unused"), @@ -706,16 +702,14 @@ it.effect( directory: { getBinding: (candidate) => candidate === absent.id - ? Effect.succeed(Option.none()) + ? Effect.succeedNone : candidate === corrupt.id ? Effect.fail(corruptFailure) - : Effect.succeed( - Option.some({ - threadId: candidate, - provider: ProviderDriverKind.make("codex"), - providerInstanceId, - }), - ), + : Effect.succeedSome({ + threadId: candidate, + provider: ProviderDriverKind.make("codex"), + providerInstanceId, + }), upsert: () => Effect.fail(writeFailure), removeExact: () => Effect.succeed(false), recordImportedTranscript: () => Effect.die("unused"), @@ -754,7 +748,7 @@ it.effect("retries failed projections and continues after a persistent failure", return runReconciliation({ threads: [transient, persistent, later], directory: { - getBinding: () => Effect.succeed(Option.none()), + getBinding: () => Effect.succeedNone, upsert: () => Effect.void, removeExact: () => Effect.succeed(false), recordImportedTranscript: () => Effect.die("unused"), @@ -909,19 +903,17 @@ for (const scenario of [ continueAfterRestart: scenario !== "disabled", directory: { getBinding: () => - Effect.succeed( - Option.some({ - threadId: thread.id, - provider: thread.session.providerName, - providerInstanceId, - status: scenario === "stopped binding" ? "stopped" : "running", - ...(scenario.includes("cursor") ? {} : { resumeCursor: { threadId: thread.id } }), - runtimePayload: { - activeTurnId: scenario === "marked superseded turn" ? "another-turn" : turnId, - ...(scenario.startsWith("marked") ? { continueAfterServerUpdate: turnId } : {}), - }, - }), - ), + Effect.succeedSome({ + threadId: thread.id, + provider: thread.session.providerName, + providerInstanceId, + status: scenario === "stopped binding" ? "stopped" : "running", + ...(scenario.includes("cursor") ? {} : { resumeCursor: { threadId: thread.id } }), + runtimePayload: { + activeTurnId: scenario === "marked superseded turn" ? "another-turn" : turnId, + ...(scenario.startsWith("marked") ? { continueAfterServerUpdate: turnId } : {}), + }, + }), upsert: (binding) => Effect.sync(() => { upserts.push(binding); @@ -1099,9 +1091,7 @@ it.effect("settles failed opt-in recovery without retrying the provider turn", ( Effect.gen(function* () { sends.push(input); preparedPayloads.push(binding.runtimePayload); - return yield* Effect.fail( - new ProviderSessionNotFoundError({ threadId: input.threadId }), - ); + return yield* new ProviderSessionNotFoundError({ threadId: input.threadId }); }), }, directory: { diff --git a/apps/server/src/serverRuntimeStartup.test.ts b/apps/server/src/serverRuntimeStartup.test.ts index ca41a029fd..8a0650a5d0 100644 --- a/apps/server/src/serverRuntimeStartup.test.ts +++ b/apps/server/src/serverRuntimeStartup.test.ts @@ -175,27 +175,25 @@ it.effect("resolveAutoBootstrapWelcomeTargets returns existing project and threa getCounts: () => Effect.die("unused"), getEventReplayStats: () => Effect.die("unused"), getActiveProjectByWorkspaceRoot: () => - Effect.succeed( - Option.some({ - id: bootstrapProjectId, - title: "Startup Project", - workspaceRoot: "/tmp/startup-project", - defaultModelSelection: { - instanceId: ProviderInstanceId.make("codex"), - model: DEFAULT_MODEL, - }, - scripts: [], - createdAt: "2026-01-01T00:00:00.000Z", - updatedAt: "2026-01-01T00:00:00.000Z", - deletedAt: null, - }), - ), + Effect.succeedSome({ + id: bootstrapProjectId, + title: "Startup Project", + workspaceRoot: "/tmp/startup-project", + defaultModelSelection: { + instanceId: ProviderInstanceId.make("codex"), + model: DEFAULT_MODEL, + }, + scripts: [], + createdAt: "2026-01-01T00:00:00.000Z", + updatedAt: "2026-01-01T00:00:00.000Z", + deletedAt: null, + }), getProjectShells: () => Effect.die("unused"), getProjectShellById: () => Effect.die("unused"), - getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.some(bootstrapThreadId)), + getFirstActiveThreadIdByProjectId: () => Effect.succeedSome(bootstrapThreadId), getImportedAgentSessionSources: () => Effect.die("unused"), - getThreadCheckpointContext: () => Effect.succeed(Option.none()), - getFullThreadDiffContext: () => Effect.succeed(Option.none()), + getThreadCheckpointContext: () => Effect.succeedNone, + getFullThreadDiffContext: () => Effect.succeedNone, getThreadRuntimeContext: () => Effect.die("unused"), getTurnStartMessage: () => Effect.die("unused"), getThreadShellById: () => Effect.die("unused"), @@ -323,10 +321,10 @@ it.effect.each([ ), getProjectShells: () => Effect.die("unused"), getProjectShellById: () => Effect.die("unused"), - getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()), + getFirstActiveThreadIdByProjectId: () => Effect.succeedNone, getImportedAgentSessionSources: () => Effect.die("unused"), - getThreadCheckpointContext: () => Effect.succeed(Option.none()), - getFullThreadDiffContext: () => Effect.succeed(Option.none()), + getThreadCheckpointContext: () => Effect.succeedNone, + getFullThreadDiffContext: () => Effect.succeedNone, getThreadRuntimeContext: () => Effect.die("unused"), getTurnStartMessage: () => Effect.die("unused"), getThreadShellById: () => Effect.die("unused"), @@ -395,13 +393,13 @@ it.effect( getSnapshotSequence: () => Effect.die("unused"), getCounts: () => Effect.die("unused"), getEventReplayStats: () => Effect.die("unused"), - getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()), + getActiveProjectByWorkspaceRoot: () => Effect.succeedNone, getProjectShells: () => Effect.die("unused"), getProjectShellById: () => Effect.die("unused"), getFirstActiveThreadIdByProjectId: () => Effect.die("thread lookup failed"), getImportedAgentSessionSources: () => Effect.die("unused"), - getThreadCheckpointContext: () => Effect.succeed(Option.none()), - getFullThreadDiffContext: () => Effect.succeed(Option.none()), + getThreadCheckpointContext: () => Effect.succeedNone, + getFullThreadDiffContext: () => Effect.succeedNone, getThreadRuntimeContext: () => Effect.die("unused"), getThreadShellById: () => Effect.die("unused"), getThreadDetailById: () => Effect.die("unused"), @@ -460,13 +458,13 @@ it.effect("resolveAutoBootstrapWelcomeTargets preserves typed UUID generation fa getSnapshotSequence: () => Effect.die("unused"), getCounts: () => Effect.die("unused"), getEventReplayStats: () => Effect.die("unused"), - getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()), + getActiveProjectByWorkspaceRoot: () => Effect.succeedNone, getProjectShells: () => Effect.die("unused"), getProjectShellById: () => Effect.die("unused"), - getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()), + getFirstActiveThreadIdByProjectId: () => Effect.succeedNone, getImportedAgentSessionSources: () => Effect.die("unused"), - getThreadCheckpointContext: () => Effect.succeed(Option.none()), - getFullThreadDiffContext: () => Effect.succeed(Option.none()), + getThreadCheckpointContext: () => Effect.succeedNone, + getFullThreadDiffContext: () => Effect.succeedNone, getThreadRuntimeContext: () => Effect.die("unused"), getTurnStartMessage: () => Effect.die("unused"), getThreadShellById: () => Effect.die("unused"), diff --git a/apps/server/src/serverRuntimeStartup.ts b/apps/server/src/serverRuntimeStartup.ts index 253c05e413..da9b130f31 100644 --- a/apps/server/src/serverRuntimeStartup.ts +++ b/apps/server/src/serverRuntimeStartup.ts @@ -268,13 +268,13 @@ export const resolveAutoBootstrapWelcomeTargets = Effect.gen(function* () { bootstrapThreadId = existingThreadId.value; } }).pipe( - Effect.catchCause((cause) => - Cause.hasInterrupts(cause) - ? Effect.failCause(cause) - : Effect.logWarning("startup thread auto-bootstrap failed", { - bootstrapProjectId: nextProjectId, - cause, - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterrupts(cause), + (cause) => + Effect.logWarning("startup thread auto-bootstrap failed", { + bootstrapProjectId: nextProjectId, + cause, + }), ), ); }); @@ -494,7 +494,7 @@ export const reconcileProviderSessions = Effect.gen(function* () { const rollbackRepository = yield* Effect.serviceOption(RollbackSagaRepository); const settings = yield* ServerSettings.ServerSettingsService; const restartSettings = yield* settings.getSettings.pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catch((cause) => Effect.logWarning("could not read restart continuation preference", { cause }).pipe( Effect.as(Option.none()), @@ -592,13 +592,13 @@ export const reconcileProviderSessions = Effect.gen(function* () { continue; } const binding = yield* directory.getBinding(thread.id).pipe( - Effect.catchCause((cause) => - Cause.hasInterrupts(cause) - ? Effect.failCause(cause) - : Effect.logWarning("failed to read orphaned provider session directory binding", { - threadId: thread.id, - cause, - }).pipe(Effect.as(Option.none())), + Effect.catchCauseIf( + (cause) => !Cause.hasInterrupts(cause), + (cause) => + Effect.logWarning("failed to read orphaned provider session directory binding", { + threadId: thread.id, + cause, + }).pipe(Effect.as(Option.none())), ), ); const continuationMarkerPresent = @@ -653,13 +653,13 @@ export const reconcileProviderSessions = Effect.gen(function* () { }); } }).pipe( - Effect.catchCause((cause) => - Cause.hasInterrupts(cause) - ? Effect.failCause(cause) - : Effect.logWarning( - "failed to reconcile orphaned provider session directory binding", - { threadId: thread.id, cause }, - ), + Effect.catchCauseIf( + (cause) => !Cause.hasInterrupts(cause), + (cause) => + Effect.logWarning("failed to reconcile orphaned provider session directory binding", { + threadId: thread.id, + cause, + }), ), ); @@ -680,13 +680,13 @@ export const reconcileProviderSessions = Effect.gen(function* () { }); }).pipe( Effect.retry({ times: 1 }), - Effect.catchCause((cause) => - Cause.hasInterrupts(cause) - ? Effect.failCause(cause) - : Effect.logWarning("failed to settle orphaned provider session projection", { - threadId: thread.id, - cause, - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterrupts(cause), + (cause) => + Effect.logWarning("failed to settle orphaned provider session projection", { + threadId: thread.id, + cause, + }), ), ); }); @@ -831,10 +831,9 @@ export const reconcileProviderSessions = Effect.gen(function* () { yield* settleAsError(ORPHANED_PROVIDER_SESSION_ERROR); } }).pipe( - Effect.catchCause((cause) => - Cause.hasInterrupts(cause) - ? Effect.failCause(cause) - : Effect.logWarning("provider session startup reconciliation failed", { cause }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterrupts(cause), + (cause) => Effect.logWarning("provider session startup reconciliation failed", { cause }), ), ); @@ -905,21 +904,20 @@ export const reconcileWorktreeSetups = Effect.gen(function* () { createdAt: interruptedAt, }) .pipe( - Effect.catchCause((cause) => - Cause.hasInterrupts(cause) - ? Effect.failCause(cause) - : Effect.logWarning("failed to settle interrupted worktree setup", { - threadId, - cause, - }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterrupts(cause), + (cause) => + Effect.logWarning("failed to settle interrupted worktree setup", { + threadId, + cause, + }), ), ); } }).pipe( - Effect.catchCause((cause) => - Cause.hasInterrupts(cause) - ? Effect.failCause(cause) - : Effect.logWarning("worktree setup startup reconciliation failed", { cause }), + Effect.catchCauseIf( + (cause) => !Cause.hasInterrupts(cause), + (cause) => Effect.logWarning("worktree setup startup reconciliation failed", { cause }), ), ); diff --git a/apps/server/src/serverRuntimeState.ts b/apps/server/src/serverRuntimeState.ts index ac81941bb6..8449710c8a 100644 --- a/apps/server/src/serverRuntimeState.ts +++ b/apps/server/src/serverRuntimeState.ts @@ -134,7 +134,7 @@ export const readPersistedServerRuntimeState = (path: string) => cause, }), ), - onSuccess: (contents) => Effect.succeed(Option.some(contents)), + onSuccess: (contents) => Effect.succeedSome(contents), }), ); if (Option.isNone(raw)) { @@ -147,7 +147,7 @@ export const readPersistedServerRuntimeState = (path: string) => } return yield* decodePersistedServerRuntimeState(trimmed).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.mapError( (cause) => new ServerRuntimeStateError({ diff --git a/apps/server/src/serverSettings.providerInstances.test.ts b/apps/server/src/serverSettings.providerInstances.test.ts index 51d09680b3..fa17606f2e 100644 --- a/apps/server/src/serverSettings.providerInstances.test.ts +++ b/apps/server/src/serverSettings.providerInstances.test.ts @@ -68,7 +68,7 @@ describe("provider instance host CAS receipts", () => { it.effect("serializes two remote clients against one host snapshot", () => Effect.gen(function* () { const settings = yield* ServerSettingsService; - const exits = yield* Effect.all( + const exits = yield* Effect.forEach( [ settings.mutateProviderInstances({ mutationId: mutationId("client-a"), @@ -80,7 +80,8 @@ describe("provider instance host CAS receipts", () => { expectedProviderInstances: {}, patch: { providerInstances: { [bId]: b } }, }), - ].map(Effect.exit), + ], + Effect.exit, { concurrency: "unbounded" }, ); expect(exits.filter(Exit.isSuccess)).toHaveLength(1); diff --git a/apps/server/src/sourceControl/ForgejoSourceControlProvider.ts b/apps/server/src/sourceControl/ForgejoSourceControlProvider.ts index eaa0ae3c5b..2ad8da2ebc 100644 --- a/apps/server/src/sourceControl/ForgejoSourceControlProvider.ts +++ b/apps/server/src/sourceControl/ForgejoSourceControlProvider.ts @@ -2,7 +2,6 @@ import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Schema from "effect/Schema"; import * as Result from "effect/Result"; -import * as Option from "effect/Option"; import { SourceControlProviderError } from "@t3tools/contracts"; import * as VcsProcess from "../vcs/VcsProcess.ts"; import * as ForgejoCli from "./ForgejoCli.ts"; @@ -270,15 +269,15 @@ export const make = Effect.gen(function* () { }).pipe( Effect.timeoutOption(BRANCH_PULL_SCAN_TIMEOUT_MS), Effect.flatMap((result) => - Option.isSome(result) - ? Effect.succeed(result.value) - : Effect.fail( - new ForgejoCli.ForgejoCliError({ - command: "fj", - cwd: input.cwd, - detail: "Forgejo pull request search timed out before finding the branch.", - }), - ), + Effect.fromOption( + result, + () => + new ForgejoCli.ForgejoCliError({ + command: "fj", + cwd: input.cwd, + detail: "Forgejo pull request search timed out before finding the branch.", + }), + ), ), mapError("listChangeRequests", input.cwd), ), diff --git a/apps/server/src/sourceControl/GitHubCli.test.ts b/apps/server/src/sourceControl/GitHubCli.test.ts index c7291cf833..13be5b99d3 100644 --- a/apps/server/src/sourceControl/GitHubCli.test.ts +++ b/apps/server/src/sourceControl/GitHubCli.test.ts @@ -220,8 +220,9 @@ describe("GitHubCli.layer", () => { capacity: 2, timeToLive: "1 minute", }); - const results = yield* Effect.all( - ["github.com", "github.example.test"].map((host, index) => + const results = yield* Effect.forEach( + ["github.com", "github.example.test"], + (host, index) => Cache.get(cache, host).pipe( Effect.provideService(GitHubCli.PinnedGitHubCredential, { host, @@ -229,7 +230,6 @@ describe("GitHubCli.layer", () => { credentialFingerprint: `fingerprint-${index}`, }), ), - ), { concurrency: 2 }, ); expect(results.map((result) => result.stdout)).toEqual(["credential-0", "credential-1"]); diff --git a/apps/server/src/sourceControl/SourceControlProviderRegistry.ts b/apps/server/src/sourceControl/SourceControlProviderRegistry.ts index 57dfc78b66..45ad09149d 100644 --- a/apps/server/src/sourceControl/SourceControlProviderRegistry.ts +++ b/apps/server/src/sourceControl/SourceControlProviderRegistry.ts @@ -280,14 +280,14 @@ export const makeWithProviders = Effect.fn("makeSourceControlProviderRegistryWit get, resolveHandle, resolve: (input) => resolveHandle(input).pipe(Effect.map((handle) => handle.provider)), - discover: Effect.all( - discoverySpecs.map((spec) => + discover: Effect.forEach( + discoverySpecs, + (spec) => probeSourceControlProvider({ spec, process, cwd: config.cwd, }), - ), { concurrency: "unbounded" }, ), }); diff --git a/apps/server/src/telemetry/Identify.ts b/apps/server/src/telemetry/Identify.ts index 2eeb005f53..50f1687bb3 100644 --- a/apps/server/src/telemetry/Identify.ts +++ b/apps/server/src/telemetry/Identify.ts @@ -132,7 +132,7 @@ const readIdentityFile = ( filePath: string, ) => fileSystem.readFileString(filePath).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catchTags({ PlatformError: (cause) => isNotFoundError(cause) @@ -278,7 +278,7 @@ export const getTelemetryIdentifierForHome = Effect.fn("getTelemetryIdentifierFo } const anonymousId = yield* upsertAnonymousId.pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catchTags({ TelemetryIdentityReadError: (error) => logTelemetryIdentityError(error).pipe(Effect.as(Option.none())), diff --git a/apps/server/src/terminal/Manager.ts b/apps/server/src/terminal/Manager.ts index 9e741cbdf3..a9d733802f 100644 --- a/apps/server/src/terminal/Manager.ts +++ b/apps/server/src/terminal/Manager.ts @@ -1958,16 +1958,14 @@ export const makeWithOptions = Effect.fn("TerminalManager.makeWithOptions")(func terminalId: string, ): Effect.fn.Return { return yield* Effect.flatMap(getSession(threadId, terminalId), (session) => - Option.match(session, { - onNone: () => - Effect.fail( - new TerminalSessionLookupError({ - threadId, - terminalId, - }), - ), - onSome: Effect.succeed, - }), + Effect.fromOption( + session, + () => + new TerminalSessionLookupError({ + threadId, + terminalId, + }), + ), ); }); @@ -2397,7 +2395,7 @@ export const makeWithOptions = Effect.fn("TerminalManager.makeWithOptions")(func } const inspectorOption = yield* acquireSubprocessInspector.pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catch((reason) => Effect.logWarning("failed to snapshot processes for terminal subprocess polling", { reason, @@ -2423,7 +2421,7 @@ export const makeWithOptions = Effect.fn("TerminalManager.makeWithOptions")(func ) { const terminalPid = session.pid; const inspectResult = yield* subprocessInspector(terminalPid).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catch((reason) => Effect.logWarning("failed to check terminal subprocess activity", { threadId: session.threadId, diff --git a/apps/server/src/textGeneration/AntigravityTextGeneration.ts b/apps/server/src/textGeneration/AntigravityTextGeneration.ts index f81bb3f71d..bad3a71ed1 100644 --- a/apps/server/src/textGeneration/AntigravityTextGeneration.ts +++ b/apps/server/src/textGeneration/AntigravityTextGeneration.ts @@ -238,7 +238,7 @@ export const makeAntigravityTextGeneration = Effect.fn("makeAntigravityTextGener yield* applyAntigravityAcpModelSelection({ runtime, model: input.modelSelection.model, - defaultModel: yield* options.defaultModel ?? Effect.succeed(undefined), + defaultModel: yield* options.defaultModel ?? Effect.undefined, mapError: (cause) => new TextGenerationError({ operation, diff --git a/apps/server/src/textGeneration/CodexTextGeneration.test.ts b/apps/server/src/textGeneration/CodexTextGeneration.test.ts index 12a327d344..877981ffb9 100644 --- a/apps/server/src/textGeneration/CodexTextGeneration.test.ts +++ b/apps/server/src/textGeneration/CodexTextGeneration.test.ts @@ -538,7 +538,7 @@ it.layer(CodexTextGenerationTestLayer)("CodexTextGeneration", (it) => { }), ), ), - Effect.ensuring(fs.remove(imagePath).pipe(Effect.catch(() => Effect.void))), + Effect.ensuring(fs.remove(imagePath).pipe(Effect.ignore)), ); expect(generated.branch).toBe("fix/ui-regression"); @@ -561,7 +561,7 @@ it.layer(CodexTextGenerationTestLayer)("CodexTextGeneration", (it) => { const { attachmentsDir } = yield* ServerConfig.ServerConfig; const missingAttachmentId = "thread-missing-attachment"; const missingPath = path.join(attachmentsDir, `${missingAttachmentId}.png`); - yield* fs.remove(missingPath).pipe(Effect.catch(() => Effect.void)); + yield* fs.remove(missingPath).pipe(Effect.ignore); const result = yield* textGeneration .generateBranchName({ diff --git a/apps/server/src/textGeneration/CodexTextGeneration.ts b/apps/server/src/textGeneration/CodexTextGeneration.ts index 0f7fb4457d..322980ab98 100644 --- a/apps/server/src/textGeneration/CodexTextGeneration.ts +++ b/apps/server/src/textGeneration/CodexTextGeneration.ts @@ -96,7 +96,7 @@ export const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(func ); const safeUnlink = (filePath: string): Effect.Effect => - fileSystem.remove(filePath).pipe(Effect.catch(() => Effect.void)); + fileSystem.remove(filePath).pipe(Effect.ignore); const encodeJsonForOperation = ( operation: @@ -265,8 +265,9 @@ export const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(func } }); - const cleanup = Effect.all( - [schemaPath, outputPath, ...cleanupPaths].map((filePath) => safeUnlink(filePath)), + const cleanup = Effect.forEach( + [schemaPath, outputPath, ...cleanupPaths], + (filePath) => safeUnlink(filePath), { concurrency: "unbounded", }, diff --git a/apps/server/src/usage/UsageService.ts b/apps/server/src/usage/UsageService.ts index cada5bc573..4e40ea745b 100644 --- a/apps/server/src/usage/UsageService.ts +++ b/apps/server/src/usage/UsageService.ts @@ -251,7 +251,7 @@ export const make = Effect.gen(function* () { yield* encodeRatesCache({ fetchedAtMs: now, document: fetched }).pipe( Effect.flatMap((serialized) => fileSystem.writeFileString(ratesCachePath, serialized)), - Effect.catchCause(() => Effect.void), + Effect.ignoreCause, ); }); @@ -557,7 +557,7 @@ export const make = Effect.gen(function* () { cacheDirty = false; }), // A cache we cannot write is a slower next start, not a failed read. - Effect.catchCause(() => Effect.void), + Effect.ignoreCause, ); }); diff --git a/apps/server/src/vcs/GitVcsDriver.ts b/apps/server/src/vcs/GitVcsDriver.ts index 5808d8ad4e..16505edb2a 100644 --- a/apps/server/src/vcs/GitVcsDriver.ts +++ b/apps/server/src/vcs/GitVcsDriver.ts @@ -1096,7 +1096,7 @@ export const makeVcsDriverShape = Effect.fn("makeGitVcsDriverShape")(function* ( /^warning: failed to remove \.\/: [^\n]+$/.test(cleaned.stderr.trim()) && (yield* fileSystem.readDirectory(input.cwd).pipe( Effect.map((entries) => entries.length === 0), - Effect.catch(() => Effect.succeed(false)), + Effect.orElseSucceed(() => false), )); if (!emptiedWorkspace) return yield* new VcsProcessExitError({ diff --git a/apps/server/src/vcs/GitVcsDriverCore.ts b/apps/server/src/vcs/GitVcsDriverCore.ts index 97b3b3010f..590a1719cb 100644 --- a/apps/server/src/vcs/GitVcsDriverCore.ts +++ b/apps/server/src/vcs/GitVcsDriverCore.ts @@ -947,16 +947,14 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* return yield* execution.pipe( Effect.timeoutOption(timeoutMs), Effect.flatMap((result) => - Option.match(result, { - onNone: () => - Effect.fail( - new GitCommandError({ - ...gitCommandContext(commandInput), - detail: "Git command timed out.", - }), - ), - onSome: Effect.succeed, - }), + Effect.fromOption( + result, + () => + new GitCommandError({ + ...gitCommandContext(commandInput), + detail: "Git command timed out.", + }), + ), ), ); }, @@ -1005,11 +1003,9 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* : {}), ...(options.progress ? { progress: options.progress } : {}), }).pipe( - Effect.flatMap((result) => { - if (options.allowNonZeroExit || result.exitCode === 0) { - return Effect.succeed(result); - } - return Effect.fail( + Effect.filterOrFail( + (result) => options.allowNonZeroExit === true || result.exitCode === 0, + (result) => new GitCommandError({ ...gitCommandContext({ operation, cwd, args }), detail: options.fallbackErrorDetail ?? "Git command exited with a non-zero status.", @@ -1017,8 +1013,7 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function* stdoutLength: result.stdout.length, stderrLength: result.stderr.length, }), - ); - }), + ), ); const executeGitWithStableDiagnostics = ( diff --git a/apps/server/src/vcs/VcsStatusBroadcaster.ts b/apps/server/src/vcs/VcsStatusBroadcaster.ts index c5751c6ef7..e2cf239c05 100644 --- a/apps/server/src/vcs/VcsStatusBroadcaster.ts +++ b/apps/server/src/vcs/VcsStatusBroadcaster.ts @@ -543,13 +543,13 @@ export const make = Effect.gen(function* () { const demandCwds = yield* Ref.get(demandCwdsRef); const shouldRun = needsInitialRefresh || - (yield* Effect.all( - [...demandCwds.keys()].map((demandCwd) => + (yield* Effect.forEach( + [...demandCwds.keys()], + (demandCwd) => backgroundPolicy.shouldRunScopeWork({ type: "vcs-status", cwd: demandCwd, }), - ), { concurrency: "unbounded" }, )).some(Boolean); if (!shouldRun) { diff --git a/apps/server/src/ws.ts b/apps/server/src/ws.ts index 4e498b6b04..821255c5de 100644 --- a/apps/server/src/ws.ts +++ b/apps/server/src/ws.ts @@ -898,27 +898,23 @@ const makeWsRpcLayer = ( case "project.meta-updated": return projectUpsertOrRemove(ProjectId.make(event.aggregateId), event.sequence); case "project.deleted": - return Effect.succeed( - Option.some({ - kind: "project-removed" as const, - sequence: event.sequence, - projectId: ProjectId.make(event.aggregateId), - }), - ); + return Effect.succeedSome({ + kind: "project-removed" as const, + sequence: event.sequence, + projectId: ProjectId.make(event.aggregateId), + }); case "thread.deleted": case "thread.archived": - return Effect.succeed( - Option.some({ - kind: "thread-removed" as const, - sequence: event.sequence, - threadId: ThreadId.make(event.aggregateId), - }), - ); + return Effect.succeedSome({ + kind: "thread-removed" as const, + sequence: event.sequence, + threadId: ThreadId.make(event.aggregateId), + }); case "thread.unarchived": return threadUpsertOrRemove(ThreadId.make(event.aggregateId), event.sequence); default: if (event.aggregateKind !== "thread") { - return Effect.succeed(Option.none()); + return Effect.succeedNone; } return threadUpsertOrRemove(ThreadId.make(event.aggregateId), event.sequence); } @@ -936,7 +932,7 @@ const makeWsRpcLayer = ( ): Effect.Effect, never, never> => read.pipe( Effect.retry({ times: 1 }), - Effect.map(Option.some), + Effect.asSome, Effect.tapError((error) => Effect.logWarning("orchestration shell projection refetch failed", { aggregateKind, @@ -3135,17 +3131,12 @@ const makeWsRpcLayer = ( [WS_METHODS.pullRequestsSummary]: (input) => observeRpcEffect( WS_METHODS.pullRequestsSummary, - pullRequests - .summary(input) - .pipe( - Effect.flatMap((summary) => - !input.supportsForgejo && summary.provider === "forgejo" - ? Effect.fail( - new PullRequestUnavailableError({ reason: "provider-unsupported" }), - ) - : Effect.succeed(summary), - ), + pullRequests.summary(input).pipe( + Effect.filterOrFail( + (summary) => input.supportsForgejo || summary.provider !== "forgejo", + () => new PullRequestUnavailableError({ reason: "provider-unsupported" }), ), + ), { "rpc.aggregate": "pull-requests" }, ), [WS_METHODS.pullRequestsStack]: (input) => @@ -3169,17 +3160,12 @@ const makeWsRpcLayer = ( [WS_METHODS.pullRequestsDetail]: (input) => observeRpcEffect( WS_METHODS.pullRequestsDetail, - pullRequests - .detail(input) - .pipe( - Effect.flatMap((detail) => - !input.supportsForgejo && detail.provider === "forgejo" - ? Effect.fail( - new PullRequestUnavailableError({ reason: "provider-unsupported" }), - ) - : Effect.succeed(detail), - ), + pullRequests.detail(input).pipe( + Effect.filterOrFail( + (detail) => input.supportsForgejo || detail.provider !== "forgejo", + () => new PullRequestUnavailableError({ reason: "provider-unsupported" }), ), + ), { "rpc.aggregate": "pull-requests" }, ), [WS_METHODS.pullRequestsActivity]: (input) => diff --git a/apps/web/src/components/ui/alert-dialog.tsx b/apps/web/src/components/ui/alert-dialog.tsx index 4f57e92011..23bd948021 100644 --- a/apps/web/src/components/ui/alert-dialog.tsx +++ b/apps/web/src/components/ui/alert-dialog.tsx @@ -107,7 +107,7 @@ function AlertDialogFooter({ function AlertDialogTitle({ className, ...props }: AlertDialogPrimitive.Title.Props) { return ( diff --git a/apps/web/src/components/ui/dialog.tsx b/apps/web/src/components/ui/dialog.tsx index 1a7c96e00f..3f70e23241 100644 --- a/apps/web/src/components/ui/dialog.tsx +++ b/apps/web/src/components/ui/dialog.tsx @@ -147,7 +147,7 @@ function DialogFooter({ function DialogTitle({ className, ...props }: DialogPrimitive.Title.Props) { return ( diff --git a/apps/web/src/components/ui/empty.tsx b/apps/web/src/components/ui/empty.tsx index 5390dd6656..61f61648e0 100644 --- a/apps/web/src/components/ui/empty.tsx +++ b/apps/web/src/components/ui/empty.tsx @@ -77,11 +77,7 @@ function EmptyMedia({ function EmptyTitle({ className, ...props }: React.ComponentProps<"div">) { return ( -
+
); } diff --git a/apps/web/src/components/ui/scroll-area.tsx b/apps/web/src/components/ui/scroll-area.tsx index 336e58266f..e7ea5f81aa 100644 --- a/apps/web/src/components/ui/scroll-area.tsx +++ b/apps/web/src/components/ui/scroll-area.tsx @@ -50,7 +50,7 @@ function ScrollArea({ diff --git a/apps/web/src/composerDraftStore.test.ts b/apps/web/src/composerDraftStore.test.ts index 1adafe160a..71a25090e1 100644 --- a/apps/web/src/composerDraftStore.test.ts +++ b/apps/web/src/composerDraftStore.test.ts @@ -203,7 +203,7 @@ function draftByKey(key: string) { describe("PersistedComposerImageAttachment", () => { it("keeps a saved image whose capture metadata this build cannot decode", () => { - const decoded = Schema.decodeUnknownSync(PersistedComposerImageAttachment)({ + const decoded = Schema.decodeSync(PersistedComposerImageAttachment)({ id: "saved-window", name: "window.png", mimeType: "image/png", diff --git a/apps/web/src/connection/platform.ts b/apps/web/src/connection/platform.ts index 7a0ff8350d..fa15fb304b 100644 --- a/apps/web/src/connection/platform.ts +++ b/apps/web/src/connection/platform.ts @@ -210,7 +210,7 @@ const capabilitiesLayer = Layer.effectContext( }), }); const identity = RelayDeviceIdentity.of({ - deviceId: Effect.succeed(Option.none()), + deviceId: Effect.succeedNone, }); const primaryAuth = PrimaryEnvironmentAuth.of({ bearerToken: Effect.tryPromise({ diff --git a/apps/web/src/connection/storage.ts b/apps/web/src/connection/storage.ts index c9179f3f84..73f62284a2 100644 --- a/apps/web/src/connection/storage.ts +++ b/apps/web/src/connection/storage.ts @@ -478,7 +478,7 @@ export const connectionStorageLayer = Layer.effectContext( Effect.tap(() => Effect.promise(() => projectFaviconCache.hydrate())), Effect.flatMap((raw) => { if (typeof raw !== "string") { - return Effect.succeed(Option.none()); + return Effect.succeedNone; } return decodeStoredShellSnapshot(raw).pipe( Effect.mapError((cause) => persistenceError("load-shell", cause)), @@ -520,7 +520,7 @@ export const connectionStorageLayer = Layer.effectContext( readDatabaseValue(database, SERVER_CONFIG_STORE_NAME, environmentId).pipe( Effect.flatMap((raw) => { if (typeof raw !== "string") { - return Effect.succeed(Option.none()); + return Effect.succeedNone; } return decodeStoredServerConfig(raw).pipe( Effect.mapError((cause) => persistenceError("load-server-config", cause)), @@ -558,7 +558,7 @@ export const connectionStorageLayer = Layer.effectContext( ).pipe( Effect.flatMap((raw) => { if (typeof raw !== "string") { - return Effect.succeed(Option.none()); + return Effect.succeedNone; } return decodeStoredThreadSnapshot(raw).pipe( Effect.mapError((cause) => persistenceError("load-thread", cause)), @@ -600,7 +600,7 @@ export const connectionStorageLayer = Layer.effectContext( readDatabaseValue(database, VCS_REFS_STORE_NAME, vcsRefsCacheKey(environmentId, cwd)).pipe( Effect.flatMap((raw) => { if (typeof raw !== "string") { - return Effect.succeed(Option.none()); + return Effect.succeedNone; } return decodeStoredVcsRefs(raw).pipe( Effect.mapError((cause) => persistenceError("load-vcs-refs", cause)), diff --git a/apps/web/src/index.css b/apps/web/src/index.css index 31dfe0c0fd..66b0f533b7 100644 --- a/apps/web/src/index.css +++ b/apps/web/src/index.css @@ -240,6 +240,8 @@ html[data-mobile-composer-route-transition="true"]::view-transition-old(t3-mobil --color-popover: var(--popover); --color-card-foreground: var(--contrast-card-foreground); --color-card: var(--card); + --color-code: var(--code-background); + --color-code-foreground: var(--code-foreground); --color-foreground: var(--contrast-foreground); --color-background: var(--background); --color-surface-raised: var(--surface-raised); diff --git a/packages/client-runtime/src/authorization/layer.test.ts b/packages/client-runtime/src/authorization/layer.test.ts index a037b84226..009f19a33d 100644 --- a/packages/client-runtime/src/authorization/layer.test.ts +++ b/packages/client-runtime/src/authorization/layer.test.ts @@ -199,7 +199,7 @@ const makeHarness = Effect.fn("TestRemoteAuthorization.makeHarness")(function* ( clerkToken: input.clerkToken ?? Effect.succeed("clerk-session"), }), Layer.succeed(ClientCapabilities.RelayDeviceIdentity, { - deviceId: Effect.succeed(Option.some("device-1")), + deviceId: Effect.succeedSome("device-1"), }), Layer.succeed(TokenStore.RemoteDpopAccessTokenStore, tokenStore), Layer.succeed( diff --git a/packages/client-runtime/src/connection/registry.test.ts b/packages/client-runtime/src/connection/registry.test.ts index 23ac8dd545..45cba53ca1 100644 --- a/packages/client-runtime/src/connection/registry.test.ts +++ b/packages/client-runtime/src/connection/registry.test.ts @@ -271,12 +271,12 @@ const makeHarness = Effect.fn("TestEnvironmentRegistry.makeHarness")(function* ( next.set(environmentId, snapshot); return next; }), - loadThread: (_environmentId, _threadId) => Effect.succeed(Option.none()), + loadThread: (_environmentId, _threadId) => Effect.succeedNone, saveThread: (_environmentId, _thread) => Effect.void, removeThread: (_environmentId, _threadId) => Effect.void, - loadServerConfig: () => Effect.succeed(Option.none()), + loadServerConfig: () => Effect.succeedNone, saveServerConfig: () => Effect.void, - loadVcsRefs: () => Effect.succeed(Option.none()), + loadVcsRefs: () => Effect.succeedNone, saveVcsRefs: () => Effect.void, removeVcsRefs: () => Effect.void, clearVcsRefs: () => Effect.void, diff --git a/packages/client-runtime/src/connection/resolver.ts b/packages/client-runtime/src/connection/resolver.ts index f74b5b3c69..2a9e257d89 100644 --- a/packages/client-runtime/src/connection/resolver.ts +++ b/packages/client-runtime/src/connection/resolver.ts @@ -105,10 +105,9 @@ const makeBearerBroker = Effect.fn("clientRuntime.connection.broker.makeBearer") entry: ConnectionCatalogEntry & { readonly target: BearerConnectionTarget }, ) { const target = entry.target; - const profile = yield* Option.match(entry.profile, { - onNone: () => Effect.fail(profileMissingError(target.connectionId)), - onSome: Effect.succeed, - }); + const profile = yield* Effect.fromOption(entry.profile, () => + profileMissingError(target.connectionId), + ); if (!isBearerProfile(profile)) { return yield* new ConnectionBlockedError({ reason: "configuration", @@ -180,10 +179,9 @@ const makeSshBroker = Effect.fn("clientRuntime.connection.broker.makeSsh")(funct entry: ConnectionCatalogEntry & { readonly target: SshConnectionTarget }, ) { const target = entry.target; - const profile = yield* Option.match(entry.profile, { - onNone: () => Effect.fail(profileMissingError(target.connectionId)), - onSome: Effect.succeed, - }); + const profile = yield* Effect.fromOption(entry.profile, () => + profileMissingError(target.connectionId), + ); if (!isSshProfile(profile)) { return yield* new ConnectionBlockedError({ reason: "configuration", diff --git a/packages/client-runtime/src/connection/supervisor.test.ts b/packages/client-runtime/src/connection/supervisor.test.ts index 882e67aac3..7ad709c3a5 100644 --- a/packages/client-runtime/src/connection/supervisor.test.ts +++ b/packages/client-runtime/src/connection/supervisor.test.ts @@ -1290,11 +1290,11 @@ describe("EnvironmentSupervisor", () => { Layer.succeed(ManagedRelayDpopSigner, signer), Layer.succeed(ManagedRelayClient, relay), Layer.succeed(ClientCapabilities.CloudSession, { - identity: Effect.succeed(Option.some({ accountId: "test-account" })), + identity: Effect.succeedSome({ accountId: "test-account" }), clerkToken: Effect.succeed("clerk-token"), }), Layer.succeed(ClientCapabilities.RelayDeviceIdentity, { - deviceId: Effect.succeed(Option.none()), + deviceId: Effect.succeedNone, }), TokenStore.layer({ get: () => Ref.get(token), diff --git a/packages/client-runtime/src/connection/supervisor.ts b/packages/client-runtime/src/connection/supervisor.ts index d4202c856c..36956987b9 100644 --- a/packages/client-runtime/src/connection/supervisor.ts +++ b/packages/client-runtime/src/connection/supervisor.ts @@ -608,6 +608,7 @@ export const make = Effect.fn("EnvironmentSupervisor.make")(function* ( }, Effect.ensuring(clearLease)); const waitForRetrySignal = Effect.fnUntraced(function* (delayMs: number) { + // @effect-diagnostics-next-line raceFirstWithSleepToTimeout:off - the sleep is the retry delay (false), not a timeout around the signal loop return yield* Effect.raceFirst( Effect.sleep(delayMs).pipe(Effect.as(false)), Effect.gen(function* () { diff --git a/packages/client-runtime/src/platform/storageDocument.test.ts b/packages/client-runtime/src/platform/storageDocument.test.ts index ae0f042686..414d58abe9 100644 --- a/packages/client-runtime/src/platform/storageDocument.test.ts +++ b/packages/client-runtime/src/platform/storageDocument.test.ts @@ -75,7 +75,7 @@ describe("ConnectionCatalogDocument", () => { remoteDpopTokens: [token], }; const schema = Schema.fromJsonString(ConnectionCatalogDocument); - const restored = Schema.decodeUnknownSync(schema)(Schema.encodeSync(schema)(document)); + const restored = Schema.decodeSync(schema)(Schema.encodeSync(schema)(document)); expect(restored).toEqual(document); expect(restored.remoteDpopTokens[0]?.accountId).toBe(accountId); diff --git a/packages/client-runtime/src/relay/discovery.test.ts b/packages/client-runtime/src/relay/discovery.test.ts index fdbcceb7df..8251b2dc36 100644 --- a/packages/client-runtime/src/relay/discovery.test.ts +++ b/packages/client-runtime/src/relay/discovery.test.ts @@ -134,15 +134,13 @@ const makeHarness = Effect.fn("RelayDiscoveryTest.makeHarness")(function* () { ), ), clerkToken: Ref.get(clerkToken).pipe( - Effect.flatMap((token) => - token === null - ? Effect.fail( - new ConnectionBlockedError({ - reason: "authentication", - detail: "Signed out.", - }), - ) - : Effect.succeed(token), + Effect.filterOrFail( + (token) => token !== null, + () => + new ConnectionBlockedError({ + reason: "authentication", + detail: "Signed out.", + }), ), ), }), @@ -289,7 +287,7 @@ describe("RelayEnvironmentDiscovery", () => { Layer.mergeAll( Layer.succeed(ManagedRelay.ManagedRelayClient, client), Layer.succeed(ClientCapabilities.CloudSession, { - identity: Effect.succeed(Option.some({ accountId: "account-1" })), + identity: Effect.succeedSome({ accountId: "account-1" }), clerkToken: Effect.succeed("clerk-token"), }), Layer.succeed(Connectivity.Connectivity, { diff --git a/packages/client-runtime/src/relay/discovery.ts b/packages/client-runtime/src/relay/discovery.ts index 8a8eae1d6c..8aee35347e 100644 --- a/packages/client-runtime/src/relay/discovery.ts +++ b/packages/client-runtime/src/relay/discovery.ts @@ -241,7 +241,7 @@ export const make = Effect.fn("RelayEnvironmentDiscovery.make")(function* () { })); return; } - return yield* Effect.fail(failure); + return yield* failure; } const clerkToken = tokenResult.success; if ((yield* Ref.get(accountGeneration)) !== generation) { diff --git a/packages/client-runtime/src/relay/managedRelay.ts b/packages/client-runtime/src/relay/managedRelay.ts index eadece4176..9c414ad9e6 100644 --- a/packages/client-runtime/src/relay/managedRelay.ts +++ b/packages/client-runtime/src/relay/managedRelay.ts @@ -666,11 +666,8 @@ export const make = Effect.fn("ManagedRelayClient.make")(function* ( authorize(input).pipe( Effect.flatMap((authorization) => request(authorization).pipe( - Effect.catch((error) => { - if (!isRejectedDpopAccessToken(error)) { - return Effect.fail(error); - } - return invalidateAccessToken(authorization.accessToken).pipe( + Effect.catchIf(isRejectedDpopAccessToken, (error) => + invalidateAccessToken(authorization.accessToken).pipe( Effect.tap((invalidated) => Effect.annotateCurrentSpan({ "relay.token_cache.invalidated": invalidated, @@ -686,8 +683,8 @@ export const make = Effect.fn("ManagedRelayClient.make")(function* ( : Effect.void, ), Effect.andThen(refreshRejectedToken ? attempt(false) : Effect.fail(error)), - ); - }), + ), + ), ), ), ); diff --git a/packages/client-runtime/src/relay/managedRelayState.ts b/packages/client-runtime/src/relay/managedRelayState.ts index 4ada66d930..19ebdb7666 100644 --- a/packages/client-runtime/src/relay/managedRelayState.ts +++ b/packages/client-runtime/src/relay/managedRelayState.ts @@ -180,14 +180,12 @@ function readSessionClerkToken( session: ManagedRelaySession, ): Effect.Effect { return session.readClerkToken().pipe( - Effect.flatMap((token) => - token - ? Effect.succeed(token) - : Effect.fail( - new ManagedRelaySessionError({ - message: "The Pylon Connect session token is unavailable.", - }), - ), + Effect.filterOrFail( + (token): token is string => Boolean(token), + () => + new ManagedRelaySessionError({ + message: "The Pylon Connect session token is unavailable.", + }), ), ); } diff --git a/packages/client-runtime/src/rpc/session.test.ts b/packages/client-runtime/src/rpc/session.test.ts index d3765b341c..d01e11fe73 100644 --- a/packages/client-runtime/src/rpc/session.test.ts +++ b/packages/client-runtime/src/rpc/session.test.ts @@ -161,7 +161,7 @@ const RpcRequest = Schema.TaggedStruct("Request", { }); const decodeJson = Schema.decodeUnknownSync(Schema.fromJsonString(Schema.Unknown)); const isRpcRequest = Schema.is(RpcRequest); -const isPing = Schema.is(Schema.Struct({ _tag: Schema.Literal("Ping") })); +const isPing = Schema.is(Schema.TaggedStruct("Ping", {})); const encodeJson = Schema.encodeUnknownSync(Schema.fromJsonString(Schema.Unknown)); const encodeServerConfig = Schema.encodeSync(ServerConfig); const encodeServerConfigStreamEvent = Schema.encodeSync(ServerConfigStreamEvent); @@ -823,14 +823,14 @@ describe("RpcSessionFactory", () => { retryNow: Effect.void, } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]); const cache = Persistence.EnvironmentCacheStore.of({ - loadShell: () => Effect.succeed(Option.none()), + loadShell: () => Effect.succeedNone, saveShell: () => Effect.void, - loadThread: () => Effect.succeed(Option.none()), + loadThread: () => Effect.succeedNone, saveThread: () => Effect.void, removeThread: () => Effect.void, - loadServerConfig: () => Effect.succeed(Option.none()), + loadServerConfig: () => Effect.succeedNone, saveServerConfig: () => Effect.void, - loadVcsRefs: () => Effect.succeed(Option.none()), + loadVcsRefs: () => Effect.succeedNone, saveVcsRefs: () => Effect.void, removeVcsRefs: () => Effect.void, clearVcsRefs: () => Effect.void, diff --git a/packages/client-runtime/src/state/pullRequests.test.ts b/packages/client-runtime/src/state/pullRequests.test.ts index fe6ea90a59..1da6b9171f 100644 --- a/packages/client-runtime/src/state/pullRequests.test.ts +++ b/packages/client-runtime/src/state/pullRequests.test.ts @@ -341,7 +341,7 @@ it.effect("updates cached labels after successful edits without rereading the ho if (failDetail) { yield* detailRefreshStarted.open; yield* releaseDetailRefresh.await; - return yield* Effect.fail(new MutationRefused()); + return yield* new MutationRefused(); } return { title: "keep this title", labels: [existing] }; }), diff --git a/packages/client-runtime/src/state/server.test.ts b/packages/client-runtime/src/state/server.test.ts index e3db4fea07..bd0cb9f4f1 100644 --- a/packages/client-runtime/src/state/server.test.ts +++ b/packages/client-runtime/src/state/server.test.ts @@ -841,37 +841,35 @@ describe("server state projection", () => { } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]); const savedConfigs = yield* Queue.unbounded(); const cache = Persistence.EnvironmentCacheStore.of({ - loadShell: () => Effect.succeed(Option.none()), + loadShell: () => Effect.succeedNone, saveShell: () => Effect.void, - loadThread: () => Effect.succeed(Option.none()), + loadThread: () => Effect.succeedNone, saveThread: () => Effect.void, removeThread: () => Effect.void, loadServerConfig: () => - Effect.succeed( - Option.some({ - ...CONFIG, - environmentThemes: [ - { - id: "old", - name: "Old", - appearance: "dark", - canvas: "#111111", - accent: "#ffffff", - }, - ], - usageLimitSources: [ - { - id: UsageLimitSourceId.make("old"), - kind: "cliproxy", - label: "Old", - checkedAt: "2026-09-07T00:00:00.000Z", - accounts: [], - }, - ], - }), - ), + Effect.succeedSome({ + ...CONFIG, + environmentThemes: [ + { + id: "old", + name: "Old", + appearance: "dark", + canvas: "#111111", + accent: "#ffffff", + }, + ], + usageLimitSources: [ + { + id: UsageLimitSourceId.make("old"), + kind: "cliproxy", + label: "Old", + checkedAt: "2026-09-07T00:00:00.000Z", + accounts: [], + }, + ], + }), saveServerConfig: (_environmentId, config) => Queue.offer(savedConfigs, config), - loadVcsRefs: () => Effect.succeed(Option.none()), + loadVcsRefs: () => Effect.succeedNone, saveVcsRefs: () => Effect.void, removeVcsRefs: () => Effect.void, clearVcsRefs: () => Effect.void, @@ -961,16 +959,14 @@ describe("server state projection", () => { expect(Option.getOrThrow(yield* SubscriptionRef.get(state)).sessionOwner).toBe( rpcSessionOwner(firstSession), ); - const secondProjection = yield* SubscriptionRef.changes(state) - .pipe( - Stream.filter( - (value) => - Option.isSome(value) && - value.value.sessionOwner === rpcSessionOwner(secondSession), - ), - Stream.runHead, - ) - .pipe(Effect.forkChild); + const secondProjection = yield* SubscriptionRef.changes(state).pipe( + Stream.filter( + (value) => + Option.isSome(value) && value.value.sessionOwner === rpcSessionOwner(secondSession), + ), + Stream.runHead, + Effect.forkChild, + ); yield* Queue.offer(secondEvents, snapshotEvent(sourceCapableConfig)); const newSessionProjection = Option.getOrThrow( Option.getOrThrow(yield* Fiber.join(secondProjection)), @@ -1003,14 +999,14 @@ describe("server state projection", () => { } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]); const savedConfigs = yield* Queue.unbounded(); const cache = Persistence.EnvironmentCacheStore.of({ - loadShell: () => Effect.succeed(Option.none()), + loadShell: () => Effect.succeedNone, saveShell: () => Effect.void, - loadThread: () => Effect.succeed(Option.none()), + loadThread: () => Effect.succeedNone, saveThread: () => Effect.void, removeThread: () => Effect.void, - loadServerConfig: () => Effect.succeed(Option.some(CONFIG)), + loadServerConfig: () => Effect.succeedSome(CONFIG), saveServerConfig: (_environmentId, config) => Queue.offer(savedConfigs, config), - loadVcsRefs: () => Effect.succeed(Option.none()), + loadVcsRefs: () => Effect.succeedNone, saveVcsRefs: () => Effect.void, removeVcsRefs: () => Effect.void, clearVcsRefs: () => Effect.void, diff --git a/packages/client-runtime/src/state/serverUsage.test.ts b/packages/client-runtime/src/state/serverUsage.test.ts index 9cf2667d8b..2df10f7cf8 100644 --- a/packages/client-runtime/src/state/serverUsage.test.ts +++ b/packages/client-runtime/src/state/serverUsage.test.ts @@ -125,14 +125,14 @@ const makeHarness = Effect.fn("ServerUsageTest.makeHarness")(function* ( Stream.provideService(stream, EnvironmentSupervisor, supervisor), } as EnvironmentRegistry["Service"]); const cache = EnvironmentCacheStore.of({ - loadShell: () => Effect.succeed(Option.none()), + loadShell: () => Effect.succeedNone, saveShell: () => Effect.void, - loadThread: () => Effect.succeed(Option.none()), + loadThread: () => Effect.succeedNone, saveThread: () => Effect.void, removeThread: () => Effect.void, - loadServerConfig: () => Effect.succeed(Option.none()), + loadServerConfig: () => Effect.succeedNone, saveServerConfig: () => Effect.void, - loadVcsRefs: () => Effect.succeed(Option.none()), + loadVcsRefs: () => Effect.succeedNone, saveVcsRefs: () => Effect.void, removeVcsRefs: () => Effect.void, clearVcsRefs: () => Effect.void, diff --git a/packages/client-runtime/src/state/session.ts b/packages/client-runtime/src/state/session.ts index 51785e0f41..42517235f6 100644 --- a/packages/client-runtime/src/state/session.ts +++ b/packages/client-runtime/src/state/session.ts @@ -22,7 +22,7 @@ export function initialConfigOption( initialConfig: Effect.Effect, ): Effect.Effect> { return initialConfig.pipe( - Effect.map(Option.some), + Effect.asSome, Effect.catch((error) => Effect.logWarning("Could not load the initial environment configuration.").pipe( Effect.annotateLogs({ ...safeErrorLogAttributes(error) }), diff --git a/packages/client-runtime/src/state/shell-sync.test.ts b/packages/client-runtime/src/state/shell-sync.test.ts index b665d00990..dc7380003d 100644 --- a/packages/client-runtime/src/state/shell-sync.test.ts +++ b/packages/client-runtime/src/state/shell-sync.test.ts @@ -114,14 +114,14 @@ describe("environment shell synchronization", () => { retryNow: Effect.void, } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]); const cache = Persistence.EnvironmentCacheStore.of({ - loadShell: () => Effect.succeed(Option.none()), + loadShell: () => Effect.succeedNone, saveShell: () => Effect.never, - loadThread: () => Effect.succeed(Option.none()), + loadThread: () => Effect.succeedNone, saveThread: () => Effect.void, removeThread: () => Effect.void, - loadServerConfig: () => Effect.succeed(Option.none()), + loadServerConfig: () => Effect.succeedNone, saveServerConfig: () => Effect.void, - loadVcsRefs: () => Effect.succeed(Option.none()), + loadVcsRefs: () => Effect.succeedNone, saveVcsRefs: () => Effect.void, removeVcsRefs: () => Effect.void, clearVcsRefs: () => Effect.void, @@ -130,7 +130,7 @@ describe("environment shell synchronization", () => { // Cold cache with no HTTP snapshot available → falls back to the // socket-embedded snapshot. const snapshotLoader = ShellSnapshotLoader.of({ - load: () => Effect.succeed(Option.none()), + load: () => Effect.succeedNone, }); const shellState = yield* makeEnvironmentShellState().pipe( Effect.provideService(EnvironmentSupervisor.EnvironmentSupervisor, supervisor), @@ -210,14 +210,14 @@ describe("environment shell synchronization", () => { retryNow: Effect.void, } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]); const cache = Persistence.EnvironmentCacheStore.of({ - loadShell: () => Effect.succeed(Option.none()), + loadShell: () => Effect.succeedNone, saveShell: () => Effect.void, - loadThread: () => Effect.succeed(Option.none()), + loadThread: () => Effect.succeedNone, saveThread: () => Effect.void, removeThread: () => Effect.void, - loadServerConfig: () => Effect.succeed(Option.none()), + loadServerConfig: () => Effect.succeedNone, saveServerConfig: () => Effect.void, - loadVcsRefs: () => Effect.succeed(Option.none()), + loadVcsRefs: () => Effect.succeedNone, saveVcsRefs: () => Effect.void, removeVcsRefs: () => Effect.void, clearVcsRefs: () => Effect.void, @@ -228,7 +228,7 @@ describe("environment shell synchronization", () => { Effect.provideService(Persistence.EnvironmentCacheStore, cache), Effect.provideService( ShellSnapshotLoader, - ShellSnapshotLoader.of({ load: () => Effect.succeed(Option.none()) }), + ShellSnapshotLoader.of({ load: () => Effect.succeedNone }), ), ); yield* SubscriptionRef.set(supervisorState, { @@ -318,14 +318,14 @@ describe("environment shell synchronization", () => { retryNow: Effect.void, } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]); const cache = Persistence.EnvironmentCacheStore.of({ - loadShell: () => Effect.succeed(Option.some(cachedSnapshot)), + loadShell: () => Effect.succeedSome(cachedSnapshot), saveShell: () => Effect.void, - loadThread: () => Effect.succeed(Option.none()), + loadThread: () => Effect.succeedNone, saveThread: () => Effect.void, removeThread: () => Effect.void, - loadServerConfig: () => Effect.succeed(Option.none()), + loadServerConfig: () => Effect.succeedNone, saveServerConfig: () => Effect.void, - loadVcsRefs: () => Effect.succeed(Option.none()), + loadVcsRefs: () => Effect.succeedNone, saveVcsRefs: () => Effect.void, removeVcsRefs: () => Effect.void, clearVcsRefs: () => Effect.void, @@ -400,14 +400,14 @@ describe("environment shell synchronization", () => { retryNow: Effect.void, } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]); const cache = Persistence.EnvironmentCacheStore.of({ - loadShell: () => Effect.succeed(Option.some(LIVE_SHELL_SNAPSHOT)), + loadShell: () => Effect.succeedSome(LIVE_SHELL_SNAPSHOT), saveShell: () => Effect.void, - loadThread: () => Effect.succeed(Option.none()), + loadThread: () => Effect.succeedNone, saveThread: () => Effect.void, removeThread: () => Effect.void, - loadServerConfig: () => Effect.succeed(Option.none()), + loadServerConfig: () => Effect.succeedNone, saveServerConfig: () => Effect.void, - loadVcsRefs: () => Effect.succeed(Option.none()), + loadVcsRefs: () => Effect.succeedNone, saveVcsRefs: () => Effect.void, removeVcsRefs: () => Effect.void, clearVcsRefs: () => Effect.void, diff --git a/packages/client-runtime/src/state/sourceControl.test.ts b/packages/client-runtime/src/state/sourceControl.test.ts index 33c566bf82..ff9824106a 100644 --- a/packages/client-runtime/src/state/sourceControl.test.ts +++ b/packages/client-runtime/src/state/sourceControl.test.ts @@ -101,14 +101,14 @@ describe("source control environment atoms", () => { } as unknown as EnvironmentRegistry.EnvironmentRegistry["Service"]); const removed = new Array(); const cache = Persistence.EnvironmentCacheStore.of({ - loadShell: () => Effect.succeed(Option.none()), + loadShell: () => Effect.succeedNone, saveShell: () => Effect.void, - loadThread: () => Effect.succeed(Option.none()), + loadThread: () => Effect.succeedNone, saveThread: () => Effect.void, removeThread: () => Effect.void, - loadServerConfig: () => Effect.succeed(Option.none()), + loadServerConfig: () => Effect.succeedNone, saveServerConfig: () => Effect.void, - loadVcsRefs: () => Effect.succeed(Option.none()), + loadVcsRefs: () => Effect.succeedNone, saveVcsRefs: () => Effect.void, removeVcsRefs: (environmentId, cwd) => Effect.sync(() => { diff --git a/packages/client-runtime/src/state/threads-atoms.test.ts b/packages/client-runtime/src/state/threads-atoms.test.ts index cc8e00cb10..ed870cf1b7 100644 --- a/packages/client-runtime/src/state/threads-atoms.test.ts +++ b/packages/client-runtime/src/state/threads-atoms.test.ts @@ -186,7 +186,7 @@ const makeHarness = Effect.fn("TestThreadAtoms.makeHarness")(function* (options? Layer.succeed( EnvironmentCacheStore, EnvironmentCacheStore.of({ - loadShell: () => Effect.succeed(Option.none()), + loadShell: () => Effect.succeedNone, saveShell: () => Effect.void, loadThread: () => Effect.sync(() => { @@ -195,9 +195,9 @@ const makeHarness = Effect.fn("TestThreadAtoms.makeHarness")(function* (options? }), saveThread: () => Effect.void, removeThread: () => Effect.void, - loadServerConfig: () => Effect.succeed(Option.none()), + loadServerConfig: () => Effect.succeedNone, saveServerConfig: () => Effect.void, - loadVcsRefs: () => Effect.succeed(Option.none()), + loadVcsRefs: () => Effect.succeedNone, saveVcsRefs: () => Effect.void, removeVcsRefs: () => Effect.void, clearVcsRefs: () => Effect.void, diff --git a/packages/client-runtime/src/state/threads-failures.test.ts b/packages/client-runtime/src/state/threads-failures.test.ts index b3698a0e16..4f7641515f 100644 --- a/packages/client-runtime/src/state/threads-failures.test.ts +++ b/packages/client-runtime/src/state/threads-failures.test.ts @@ -133,14 +133,14 @@ const makeHarness = Effect.fn("TestThreadFailures.makeHarness")(function* (optio retryNow: Effect.void, }); const cache = EnvironmentCacheStore.of({ - loadShell: () => Effect.succeed(Option.none()), + loadShell: () => Effect.succeedNone, saveShell: () => Effect.void, - loadThread: () => Effect.succeed(Option.none()), + loadThread: () => Effect.succeedNone, saveThread: () => Effect.void, removeThread: () => Effect.void, - loadServerConfig: () => Effect.succeed(Option.none()), + loadServerConfig: () => Effect.succeedNone, saveServerConfig: () => Effect.void, - loadVcsRefs: () => Effect.succeed(Option.none()), + loadVcsRefs: () => Effect.succeedNone, saveVcsRefs: () => Effect.void, removeVcsRefs: () => Effect.void, clearVcsRefs: () => Effect.void, diff --git a/packages/client-runtime/src/state/threads-pagination.test.ts b/packages/client-runtime/src/state/threads-pagination.test.ts index a583908e84..deeab75321 100644 --- a/packages/client-runtime/src/state/threads-pagination.test.ts +++ b/packages/client-runtime/src/state/threads-pagination.test.ts @@ -193,16 +193,16 @@ const makeHarness = Effect.fn("TestThreadPagination.makeHarness")(function* (opt retryNow: Effect.void, } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]); const cache = Persistence.EnvironmentCacheStore.of({ - loadShell: () => Effect.succeed(Option.none()), + loadShell: () => Effect.succeedNone, saveShell: () => Effect.void, loadThread: () => Effect.succeed(options?.cached !== undefined ? Option.some(options.cached) : Option.none()), saveThread: (_environmentId, thread) => Ref.update(savedThreads, (current) => [...current, thread]), removeThread: () => Effect.void, - loadServerConfig: () => Effect.succeed(Option.none()), + loadServerConfig: () => Effect.succeedNone, saveServerConfig: () => Effect.void, - loadVcsRefs: () => Effect.succeed(Option.none()), + loadVcsRefs: () => Effect.succeedNone, saveVcsRefs: () => Effect.void, removeVcsRefs: () => Effect.void, clearVcsRefs: () => Effect.void, diff --git a/packages/client-runtime/src/state/threads-sync.test.ts b/packages/client-runtime/src/state/threads-sync.test.ts index 81f861a970..294459720b 100644 --- a/packages/client-runtime/src/state/threads-sync.test.ts +++ b/packages/client-runtime/src/state/threads-sync.test.ts @@ -219,7 +219,7 @@ const makeHarness = Effect.fn("TestEnvironmentThreads.makeHarness")(function* (o retryNow: Ref.update(retryCount, (count) => count + 1), } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]); const cache = Persistence.EnvironmentCacheStore.of({ - loadShell: () => Effect.succeed(Option.none()), + loadShell: () => Effect.succeedNone, saveShell: () => Effect.void, loadThread: (_environmentId, threadId) => options?.loadCached ?? @@ -237,9 +237,9 @@ const makeHarness = Effect.fn("TestEnvironmentThreads.makeHarness")(function* (o ), removeThread: (_environmentId, threadId) => Ref.update(removedThreads, (current) => [...current, threadId]), - loadServerConfig: () => Effect.succeed(Option.none()), + loadServerConfig: () => Effect.succeedNone, saveServerConfig: () => Effect.void, - loadVcsRefs: () => Effect.succeed(Option.none()), + loadVcsRefs: () => Effect.succeedNone, saveVcsRefs: () => Effect.void, removeVcsRefs: () => Effect.void, clearVcsRefs: () => Effect.void, diff --git a/packages/client-runtime/src/state/vcs.test.ts b/packages/client-runtime/src/state/vcs.test.ts index d7a4692fc3..7b11c48f3c 100644 --- a/packages/client-runtime/src/state/vcs.test.ts +++ b/packages/client-runtime/src/state/vcs.test.ts @@ -98,12 +98,12 @@ function cacheWithRefs( overrides: Partial = {}, ) { return Persistence.EnvironmentCacheStore.of({ - loadShell: () => Effect.succeed(Option.none()), + loadShell: () => Effect.succeedNone, saveShell: () => Effect.void, - loadThread: () => Effect.succeed(Option.none()), + loadThread: () => Effect.succeedNone, saveThread: () => Effect.void, removeThread: () => Effect.void, - loadServerConfig: () => Effect.succeed(Option.none()), + loadServerConfig: () => Effect.succeedNone, saveServerConfig: () => Effect.void, loadVcsRefs: () => Effect.succeed(refs), saveVcsRefs: () => Effect.void, diff --git a/packages/client-runtime/src/state/vcsAction.test.ts b/packages/client-runtime/src/state/vcsAction.test.ts index 24aa314b1c..2d840ba71f 100644 --- a/packages/client-runtime/src/state/vcsAction.test.ts +++ b/packages/client-runtime/src/state/vcsAction.test.ts @@ -99,14 +99,14 @@ function progress(event: T): T { function cacheStore(onClearVcsRefs: (environmentId: EnvironmentId) => void) { return Persistence.EnvironmentCacheStore.of({ - loadShell: () => Effect.succeed(Option.none()), + loadShell: () => Effect.succeedNone, saveShell: () => Effect.void, - loadThread: () => Effect.succeed(Option.none()), + loadThread: () => Effect.succeedNone, saveThread: () => Effect.void, removeThread: () => Effect.void, - loadServerConfig: () => Effect.succeed(Option.none()), + loadServerConfig: () => Effect.succeedNone, saveServerConfig: () => Effect.void, - loadVcsRefs: () => Effect.succeed(Option.none()), + loadVcsRefs: () => Effect.succeedNone, saveVcsRefs: () => Effect.void, removeVcsRefs: () => Effect.void, clearVcsRefs: (environmentId) => Effect.sync(() => onClearVcsRefs(environmentId)), diff --git a/packages/contracts/src/effectParseOptionsCompatibility.test.ts b/packages/contracts/src/effectParseOptionsCompatibility.test.ts index 0fdd3f1ab5..724249c0cf 100644 --- a/packages/contracts/src/effectParseOptionsCompatibility.test.ts +++ b/packages/contracts/src/effectParseOptionsCompatibility.test.ts @@ -29,9 +29,9 @@ describe("pinned Effect schema-local parse options", () => { items: [{ kind: "known", value: "ok", extra: true }], }), ).toThrow(); - expect(Schema.decodeUnknownSync(envelope)({ items: [{ kind: "known", value: "ok" }] })).toEqual( - { items: [{ kind: "known", value: "ok" }] }, - ); + expect(Schema.decodeSync(envelope)({ items: [{ kind: "known", value: "ok" }] })).toEqual({ + items: [{ kind: "known", value: "ok" }], + }); }); it("preserves rc.112 check annotation precedence in both directions", () => { diff --git a/packages/contracts/src/project.test.ts b/packages/contracts/src/project.test.ts index fbe9d07415..9e648f8b82 100644 --- a/packages/contracts/src/project.test.ts +++ b/packages/contracts/src/project.test.ts @@ -67,7 +67,7 @@ describe("project directory listing compatibility", () => { directoryCursor: "a.ts", }); expect(oldServerPayload).toEqual({ cwd: "/workspace" }); - const oldResponse = Schema.decodeUnknownSync(ProjectListEntriesResult)({ + const oldResponse = Schema.decodeSync(ProjectListEntriesResult)({ entries: [{ path: "src/a.ts", kind: "file" }], truncated: false, }); diff --git a/packages/contracts/src/pullRequest.test.ts b/packages/contracts/src/pullRequest.test.ts index 7ca24cd2ec..7e9a775a63 100644 --- a/packages/contracts/src/pullRequest.test.ts +++ b/packages/contracts/src/pullRequest.test.ts @@ -143,7 +143,7 @@ describe("PullRequestListResult", () => { it("round-trips through the JSON codec the RPC serializes with", () => { const codec = Schema.toCodecJson(PullRequestListResult); - const decoded = Schema.decodeUnknownSync(codec)(Schema.encodeUnknownSync(codec)(LIST_RESULT)); + const decoded = Schema.decodeSync(codec)(Schema.encodeUnknownSync(codec)(LIST_RESULT)); expect(decoded).toStrictEqual(LIST_RESULT); }); diff --git a/packages/contracts/src/rpc.test.ts b/packages/contracts/src/rpc.test.ts index a233279096..be5f65f447 100644 --- a/packages/contracts/src/rpc.test.ts +++ b/packages/contracts/src/rpc.test.ts @@ -17,7 +17,7 @@ const decodeSubscribeServerConfigPayload = Schema.decodeUnknownSync( describe("subscribeServerConfig payload compatibility", () => { it("is accepted by a server whose schema predates the field", () => { const oldServerPayload = Schema.Struct({}); - const decoded = Schema.decodeUnknownExit(oldServerPayload)({ environmentThemes: true }); + const decoded = Schema.decodeExit(oldServerPayload)({ environmentThemes: true }); expect(Exit.isSuccess(decoded)).toBe(true); }); diff --git a/packages/effect-acp/src/client.ts b/packages/effect-acp/src/client.ts index 27203c20c6..c3f4e7644f 100644 --- a/packages/effect-acp/src/client.ts +++ b/packages/effect-acp/src/client.ts @@ -346,11 +346,9 @@ export const make = Effect.fn("effect-acp/AcpClient.make")(function* ( registration: BufferedNotificationHandler, notification: A, ) => - Effect.forEach( - registration.handlers, - (handler) => handler(notification).pipe(Effect.catch(() => Effect.void)), - { discard: true }, - ); + Effect.forEach(registration.handlers, (handler) => handler(notification).pipe(Effect.ignore), { + discard: true, + }); const flushBufferedNotifications = (registration: BufferedNotificationHandler) => Effect.suspend(() => { diff --git a/packages/effect-acp/src/protocol.ts b/packages/effect-acp/src/protocol.ts index f74a8ea29e..a84c2f5a57 100644 --- a/packages/effect-acp/src/protocol.ts +++ b/packages/effect-acp/src/protocol.ts @@ -216,7 +216,7 @@ export const makeAcpPatchedProtocol = Effect.fn("makeAcpPatchedProtocol")(functi Queue.offer(notificationQueue, notification).pipe( Effect.andThen( options.onNotification - ? options.onNotification(notification).pipe(Effect.catch(() => Effect.void)) + ? options.onNotification(notification).pipe(Effect.ignore) : Effect.void, ), Effect.asVoid, diff --git a/packages/effect-codex-app-server/src/_internal/shared.ts b/packages/effect-codex-app-server/src/_internal/shared.ts index 8bcb59467d..334dc4a43b 100644 --- a/packages/effect-codex-app-server/src/_internal/shared.ts +++ b/packages/effect-codex-app-server/src/_internal/shared.ts @@ -45,7 +45,7 @@ export const encodeOptionalPayload = ( ): Effect.Effect => { if (!schema) { if (payload === undefined) { - return Effect.sync(() => undefined); + return Effect.undefined; } return Effect.fail( CodexError.CodexAppServerRequestError.unexpectedPayload(method, "encode-payload", payload), diff --git a/packages/effect-codex-app-server/src/schema.test.ts b/packages/effect-codex-app-server/src/schema.test.ts index 59a4d3a26a..c44191d4ca 100644 --- a/packages/effect-codex-app-server/src/schema.test.ts +++ b/packages/effect-codex-app-server/src/schema.test.ts @@ -31,7 +31,7 @@ it("keeps async questions in live notifications and thread history", () => { CodexSchema.V2ThreadReadResponse__ThreadItem, CodexSchema.V2ThreadResumeResponse__ThreadItem, ]) { - assert.deepEqual(Schema.decodeUnknownSync(schema)(item), item); + assert.deepEqual(Schema.decodeSync(schema)(item), item); } }); diff --git a/packages/shared/src/httpReadiness.ts b/packages/shared/src/httpReadiness.ts index 5aad9d488a..4aeda1c475 100644 --- a/packages/shared/src/httpReadiness.ts +++ b/packages/shared/src/httpReadiness.ts @@ -106,17 +106,13 @@ export const waitForHttpReady = Effect.fn("shared.httpReadiness.waitForHttpReady Effect.timeoutOption(Duration.millis(probeTimeoutMs)), Effect.mapError((cause) => fail(cause)), ); - return yield* Option.match(responseOption, { - onSome: Effect.succeed, - onNone: () => - Effect.fail( - fail({ - kind: "probe-timeout", - attempt, - probeTimeoutMs, - }), - ), - }); + return yield* Effect.fromOption(responseOption, () => + fail({ + kind: "probe-timeout", + attempt, + probeTimeoutMs, + }), + ); }).pipe( Effect.mapError((cause) => (isMadeError(cause) ? cause : fail(cause))), Effect.tapError((cause) => diff --git a/packages/shared/src/relayClient.ts b/packages/shared/src/relayClient.ts index c7da7d88e2..3683895a3b 100644 --- a/packages/shared/src/relayClient.ts +++ b/packages/shared/src/relayClient.ts @@ -331,9 +331,7 @@ export const makeCloudflaredRelayClient = Effect.fn("cloudflared.make")(function for (let attempt = 0; attempt < INSTALL_LOCK_RETRY_COUNT; attempt += 1) { const acquired = yield* fileSystem.writeFileString(lockPath, "", { flag: "wx" }).pipe( Effect.as(true), - Effect.catch((error) => - isAlreadyExists(error) ? Effect.succeed(false) : Effect.fail(error), - ), + Effect.catchIf(isAlreadyExists, () => Effect.succeed(false)), ); if (acquired) return; @@ -445,16 +443,16 @@ export const makeCloudflaredRelayClient = Effect.fn("cloudflared.make")(function }).pipe( Effect.scoped, Effect.ensuring(fileSystem.remove(lockPath, { force: true }).pipe(Effect.ignore)), - Effect.catch((cause) => - cause instanceof RelayClientInstallError - ? Effect.fail(cause) - : Effect.fail( - new RelayClientInstallError({ - reason: "write_failed", - message: "Could not install the relay client.", - cause, - }), - ), + Effect.catchIf( + (cause) => !(cause instanceof RelayClientInstallError), + (cause) => + Effect.fail( + new RelayClientInstallError({ + reason: "write_failed", + message: "Could not install the relay client.", + cause, + }), + ), ), ); }); diff --git a/packages/shared/src/relayTracing.ts b/packages/shared/src/relayTracing.ts index 1259984ea3..907773bc15 100644 --- a/packages/shared/src/relayTracing.ts +++ b/packages/shared/src/relayTracing.ts @@ -151,6 +151,6 @@ export function makeRelayClientTracingLayer( return Layer.effect( RelayClientTracer, - Tracer.Tracer.pipe(Effect.map(nonInterferingTracer), Effect.map(Option.some)), + Tracer.Tracer.pipe(Effect.map(nonInterferingTracer), Effect.asSome), ).pipe(Layer.provide(tracerLayer)); } diff --git a/packages/shared/src/schemaJson.ts b/packages/shared/src/schemaJson.ts index 076ff67b62..c811c1da10 100644 --- a/packages/shared/src/schemaJson.ts +++ b/packages/shared/src/schemaJson.ts @@ -1,7 +1,6 @@ import * as Cause from "effect/Cause"; import * as Effect from "effect/Effect"; import * as Exit from "effect/Exit"; -import * as Option from "effect/Option"; import * as Result from "effect/Result"; import * as Schema from "effect/Schema"; import * as SchemaGetter from "effect/SchemaGetter"; @@ -187,7 +186,7 @@ const parseLenientJsonGetter = SchemaGetter.onSome((input: string) => { ); return decodeJsonString(stripped).pipe( - Effect.map(Option.some), + Effect.asSome, Effect.mapError((error) => error.issue), ); }); diff --git a/tsconfig.base.json b/tsconfig.base.json index a84f620ba8..7897a92f55 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -50,7 +50,8 @@ "globalTimers": "error", "globalTimersInEffect": "error", "globalFetch": "error", - "globalFetchInEffect": "error" + "globalFetchInEffect": "error", + "schemaNumber": "off" } } ]