authorgravatar for julius0216@outlook.comJulius Marminge <julius0216@outlook.com> 2026-09-24 19:07:01-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2026-09-24 19:07:01-07:00
log568c9bc4d0ef0dddf74d813619c9877bd35624d7
tree3da47ab6e2055fa589b848c137d72096e5e2095b
parent3e2370fbbf1efacb341a68e6f28efb06b695e148
signature Signed by PGP key B5690EEEBB952194

chore: clear Effect language service suggestions (#13536)

Co-authored-by: Claude Opus 5.5 (1M context) <noreply@anthropic.com>

174 files changed, 1152 insertions(+), 1311 deletions(-)

apps/desktop/src/app/DesktopAppIdentity.test.ts+1-1
......@@ -76,7 +76,7 @@ const makeAssetsLayer = (png: Option.Option<string>) =>
7676 icns: Option.none(),
7777 png,
7878 }),
79 resolveResourcePath: () => Effect.succeed(Option.none()),
79 resolveResourcePath: () => Effect.succeedNone,
8080 } satisfies DesktopAssets.DesktopAssets["Service"]);
8181
8282const makeEnvironmentLayer = (overrides: TestEnvironmentInput = {}) => {
apps/desktop/src/app/DesktopConnectionCatalogStore.test.ts+1-1
......@@ -46,7 +46,7 @@ function makeSafeStorageLayer(available: boolean, failDecrypt: Ref.Ref<boolean>
4646 return decoded.slice("encrypted:".length);
4747 });
4848 },
49 selectedStorageBackend: Effect.succeed(Option.none()),
49 selectedStorageBackend: Effect.succeedNone,
5050 } satisfies ElectronSafeStorage.ElectronSafeStorage["Service"]);
5151}
5252
apps/desktop/src/app/DesktopConnectionCatalogStore.ts+1-1
......@@ -205,7 +205,7 @@ const readDocument = (
205205 raw === null
206206 ? Effect.succeed(Option.none<EncryptedConnectionCatalogDocument>())
207207 : decodeEncryptedConnectionCatalogDocumentJson(raw).pipe(
208 Effect.map(Option.some),
208 Effect.asSome,
209209 Effect.mapError(
210210 (cause) =>
211211 new DesktopConnectionCatalogStoreDocumentDecodeError({
apps/desktop/src/backend/DesktopBackendConfiguration.ts+2-2
......@@ -199,11 +199,11 @@ const readPersistedBackendObservabilitySettings = Effect.gen(function* () {
199199 const fileSystem = yield* FileSystem.FileSystem;
200200 const environment = yield* DesktopEnvironment.DesktopEnvironment;
201201 const raw = yield* fileSystem.readFileString(environment.serverSettingsPath).pipe(
202 Effect.map(Option.some),
202 Effect.asSome,
203203 Effect.catchTags({
204204 PlatformError: (cause) =>
205205 cause.reason._tag === "NotFound"
206 ? Effect.succeed(Option.none())
206 ? Effect.succeedNone
207207 : logBackendObservabilitySettingsReadFailure(environment.serverSettingsPath, cause).pipe(
208208 Effect.as(Option.none()),
209209 ),
apps/desktop/src/backend/DesktopBackendManager.test.ts+2-2
......@@ -162,7 +162,7 @@ function makeTestInstance(input: MakeInstanceInput) {
162162 forInstance: () => Effect.succeed(stubLog),
163163 } satisfies DesktopObservability.DesktopBackendOutputLogFactory["Service"]),
164164 Layer.succeed(DesktopTelemetryPublisher.DesktopTelemetryPublisher, {
165 latest: Effect.succeed(Option.none()),
165 latest: Effect.succeedNone,
166166 changes: Stream.empty,
167167 encoded: input.desktopTelemetryStream ?? Stream.empty,
168168 handleControlForSource: () => Effect.void,
......@@ -1545,7 +1545,7 @@ describe("DesktopBackendManager", () => {
15451545
15461546 const mockPool = Layer.succeed(DesktopBackendPool.DesktopBackendPool, {
15471547 list: Effect.succeed([instance1, instance2]),
1548 get: () => Effect.succeed(Option.none()),
1548 get: () => Effect.succeedNone,
15491549 primary: Effect.die(new Error("primary not implemented")),
15501550 register: () => Effect.die(new Error("register not implemented")),
15511551 unregister: () => Effect.die(new Error("unregister not implemented")),
apps/desktop/src/backend/DesktopBackendPool.test.ts+2-4
......@@ -67,7 +67,7 @@ function makePoolLayer(
6767 } satisfies DesktopObservability.DesktopBackendOutputLogShape),
6868 } satisfies DesktopObservability.DesktopBackendOutputLogFactory["Service"]),
6969 Layer.succeed(DesktopTelemetryPublisher.DesktopTelemetryPublisher, {
70 latest: Effect.succeed(Option.none()),
70 latest: Effect.succeedNone,
7171 changes: Stream.empty,
7272 encoded: Stream.empty,
7373 handleControlForSource: () => Effect.void,
......@@ -135,9 +135,7 @@ describe("DesktopBackendPool", () => {
135135
136136 it.effect("layerTest dies when no instances are supplied", () =>
137137 Effect.exit(
138 Effect.gen(function* () {
139 yield* DesktopBackendPool.DesktopBackendPool;
140 }).pipe(Effect.provide(DesktopBackendPool.layerTest([]))),
138 DesktopBackendPool.DesktopBackendPool.pipe(Effect.provide(DesktopBackendPool.layerTest([]))),
141139 ).pipe(Effect.map((exit) => assert.equal(exit._tag, "Failure"))),
142140 );
143141
apps/desktop/src/backend/DesktopLocalEnvironmentAuth.test.ts+1-2
......@@ -1,7 +1,6 @@
11import { assert, describe, it } from "@effect/vitest";
22import * as Effect from "effect/Effect";
33import * as Layer from "effect/Layer";
4import * as Option from "effect/Option";
54import * as Ref from "effect/Ref";
65import * as HttpClient from "effect/unstable/http/HttpClient";
76import * as HttpClientResponse from "effect/unstable/http/HttpClientResponse";
......@@ -60,7 +59,7 @@ describe("DesktopLocalEnvironmentAuth", () => {
6059 {
6160 id: PRIMARY_LOCAL_ENVIRONMENT_ID,
6261 label: Effect.succeed("Windows"),
63 currentConfig: Effect.succeed(Option.some(config)),
62 currentConfig: Effect.succeedSome(config),
6463 },
6564 ]),
6665 } as unknown as DesktopBackendPool.DesktopBackendPool["Service"]);
apps/desktop/src/electron/ElectronMenu.ts+1-1
......@@ -226,7 +226,7 @@ export const make = Effect.gen(function* () {
226226 Effect.callback<Option.Option<string>>((resume) => {
227227 const normalizedItems = normalizeContextMenuItems(input.items);
228228 if (normalizedItems.length === 0) {
229 resume(Effect.succeed(Option.none()));
229 resume(Effect.succeedNone);
230230 return;
231231 }
232232
apps/desktop/src/ipc/methods/snapShot.test.ts+13-15
......@@ -51,7 +51,7 @@ describe("window capture IPC", () => {
5151 Effect.provide(
5252 Layer.mergeAll(
5353 Layer.succeed(ElectronWindow.ElectronWindow, {
54 main: Effect.succeed(Option.some({ webContents: { id: 7 } })),
54 main: Effect.succeedSome({ webContents: { id: 7 } }),
5555 } as ElectronWindow.ElectronWindow["Service"]),
5656 Layer.succeed(DesktopSnapShot.DesktopSnapShot, {
5757 previewConfig: () =>
......@@ -87,7 +87,7 @@ describe("window capture IPC", () => {
8787 Effect.provide(
8888 Layer.mergeAll(
8989 Layer.succeed(ElectronWindow.ElectronWindow, {
90 main: Effect.succeed(Option.some({ webContents: { id: 7 } })),
90 main: Effect.succeedSome({ webContents: { id: 7 } }),
9191 } as ElectronWindow.ElectronWindow["Service"]),
9292 Layer.succeed(DesktopSnapShot.DesktopSnapShot, {
9393 state: Effect.succeed({
......@@ -120,7 +120,7 @@ describe("window capture IPC", () => {
120120 Effect.provide(
121121 Layer.mergeAll(
122122 Layer.succeed(ElectronWindow.ElectronWindow, {
123 main: Effect.succeed(Option.some({ webContents: { id: 7 } })),
123 main: Effect.succeedSome({ webContents: { id: 7 } }),
124124 } as ElectronWindow.ElectronWindow["Service"]),
125125 Layer.succeed(DesktopSnapShot.DesktopSnapShot, {
126126 state: Effect.succeed({ linuxBackend: "niri" }),
......@@ -156,13 +156,11 @@ describe("window capture IPC", () => {
156156 Layer.succeed(
157157 ElectronWindow.ElectronWindow,
158158 ElectronWindow.ElectronWindow.of({
159 main: Effect.succeed(
160 Option.some({
161 getBounds: () => ({ x: 100, y: 80, width: 1_000, height: 700 }),
162 getContentBounds: () => ({ x: 100, y: 118, width: 1_000, height: 662 }),
163 webContents,
164 }),
165 ),
159 main: Effect.succeedSome({
160 getBounds: () => ({ x: 100, y: 80, width: 1_000, height: 700 }),
161 getContentBounds: () => ({ x: 100, y: 118, width: 1_000, height: 662 }),
162 webContents,
163 }),
166164 } as ElectronWindow.ElectronWindow["Service"]),
167165 ),
168166 Layer.succeed(
......@@ -220,7 +218,7 @@ describe("window capture IPC", () => {
220218 Layer.succeed(
221219 ElectronWindow.ElectronWindow,
222220 ElectronWindow.ElectronWindow.of({
223 main: Effect.succeed(Option.some({ webContents })),
221 main: Effect.succeedSome({ webContents }),
224222 } as ElectronWindow.ElectronWindow["Service"]),
225223 ),
226224 Layer.succeed(
......@@ -256,7 +254,7 @@ describe("window capture IPC", () => {
256254 Effect.provideService(
257255 ElectronWindow.ElectronWindow,
258256 ElectronWindow.ElectronWindow.of({
259 main: Effect.succeed(Option.some({ webContents: { id: 7 } })),
257 main: Effect.succeedSome({ webContents: { id: 7 } }),
260258 } as ElectronWindow.ElectronWindow["Service"]),
261259 ),
262260 Effect.provideService(DesktopSnapShot.DesktopSnapShot, null as never),
......@@ -277,7 +275,7 @@ describe("window capture IPC", () => {
277275 Effect.provide(
278276 Layer.mergeAll(
279277 Layer.succeed(ElectronWindow.ElectronWindow, {
280 main: Effect.succeed(Option.some({ webContents: { id: 7 } })),
278 main: Effect.succeedSome({ webContents: { id: 7 } }),
281279 } as ElectronWindow.ElectronWindow["Service"]),
282280 Layer.succeed(DesktopSnapShot.DesktopSnapShot, {
283281 setup: (action: string) =>
......@@ -295,7 +293,7 @@ describe("window capture IPC", () => {
295293 Layer.succeed(
296294 ElectronWindow.ElectronWindow,
297295 ElectronWindow.ElectronWindow.of({
298 main: Effect.succeed(Option.some({ webContents: { id: 7 } })),
296 main: Effect.succeedSome({ webContents: { id: 7 } }),
299297 } as ElectronWindow.ElectronWindow["Service"]),
300298 ),
301299 Layer.succeed(
......@@ -320,7 +318,7 @@ describe("window capture IPC", () => {
320318 Layer.succeed(
321319 ElectronWindow.ElectronWindow,
322320 ElectronWindow.ElectronWindow.of({
323 main: Effect.succeed(Option.some({ webContents: { id: 7 } })),
321 main: Effect.succeedSome({ webContents: { id: 7 } }),
324322 } as ElectronWindow.ElectronWindow["Service"]),
325323 ),
326324 Layer.succeed(
apps/desktop/src/ipc/methods/sshEnvironment.ts+5-7
......@@ -137,13 +137,11 @@ export const ensureSshEnvironment = DesktopIpc.makeIpcMethod({
137137 }) {
138138 const sshEnvironment = yield* DesktopSshEnvironment.DesktopSshEnvironment;
139139 return yield* sshEnvironment.ensureEnvironment(target, options).pipe(
140 Effect.catch((error) =>
141 DesktopSshEnvironment.isDesktopSshPasswordPromptCancellation(error)
142 ? Effect.succeed({
143 type: DesktopSshPasswordPromptCancelledType,
144 message: error.message,
145 })
146 : Effect.fail(error),
140 Effect.catchIf(DesktopSshEnvironment.isDesktopSshPasswordPromptCancellation, (error) =>
141 Effect.succeed({
142 type: DesktopSshPasswordPromptCancelledType,
143 message: error.message,
144 }),
147145 ),
148146 );
149147 }),
apps/desktop/src/ipc/methods/window.test.ts+12-14
......@@ -61,7 +61,7 @@ const defaultWslInstance: DesktopBackendManager.DesktopBackendInstance = {
6161 label: Effect.succeed("WSL (default distro)"),
6262 start: Effect.void,
6363 stop: () => Effect.void,
64 currentConfig: Effect.succeed(Option.some(readyWslConfig)),
64 currentConfig: Effect.succeedSome(readyWslConfig),
6565 snapshot: Effect.succeed({
6666 desiredRunning: true,
6767 ready: true,
......@@ -101,7 +101,7 @@ describe("getLocalEnvironmentBootstraps", () => {
101101 };
102102 const retryingInstance: DesktopBackendManager.DesktopBackendInstance = {
103103 ...defaultWslInstance,
104 currentConfig: Effect.succeed(Option.some(retryingConfig)),
104 currentConfig: Effect.succeedSome(retryingConfig),
105105 snapshot: Effect.succeed({
106106 desiredRunning: true,
107107 ready: false,
......@@ -128,16 +128,14 @@ describe("getLocalEnvironmentBootstraps", () => {
128128 it.effect("omits a bounded transient bootstrap after retries stop", () => {
129129 const stoppedInstance: DesktopBackendManager.DesktopBackendInstance = {
130130 ...defaultWslInstance,
131 currentConfig: Effect.succeed(
132 Option.some({
133 ...readyWslConfig,
134 preflightFailure: Option.some({
135 reason: "WSL probe timed out",
136 fatal: false,
137 retryLimit: 12,
138 }),
131 currentConfig: Effect.succeedSome({
132 ...readyWslConfig,
133 preflightFailure: Option.some({
134 reason: "WSL probe timed out",
135 fatal: false,
136 retryLimit: 12,
139137 }),
140 ),
138 }),
141139 snapshot: Effect.succeed({
142140 desiredRunning: false,
143141 ready: false,
......@@ -163,7 +161,7 @@ describe("getWindowFullscreenState", () => {
163161 }).pipe(
164162 Effect.provide(
165163 Layer.mock(ElectronWindow.ElectronWindow)({
166 currentMainOrFirst: Effect.succeed(Option.some(window)),
164 currentMainOrFirst: Effect.succeedSome(window),
167165 }),
168166 ),
169167 );
......@@ -206,7 +204,7 @@ describe("pasteAsText", () => {
206204 }).pipe(
207205 Effect.provide(
208206 Layer.mock(ElectronWindow.ElectronWindow)({
209 main: Effect.succeed(Option.some(window)),
207 main: Effect.succeedSome(window),
210208 }),
211209 ),
212210 );
......@@ -219,7 +217,7 @@ describe("pickProjectFavicon", () => {
219217 Layer.mergeAll(
220218 Layer.mock(ElectronDialog.ElectronDialog)({ pickFiles }),
221219 Layer.mock(ElectronWindow.ElectronWindow)({
222 focusedMainOrFirst: Effect.succeed(Option.none()),
220 focusedMainOrFirst: Effect.succeedNone,
223221 }),
224222 DesktopAppSettings.layerTest(settings),
225223 );
apps/desktop/src/ipc/methods/wsl.test.ts+1-2
......@@ -2,7 +2,6 @@ import { DesktopWslStateSchema } from "@t3tools/contracts";
22import { assert, describe, it } from "@effect/vitest";
33import * as Effect from "effect/Effect";
44import * as Layer from "effect/Layer";
5import * as Option from "effect/Option";
65import * as Schema from "effect/Schema";
76
87import * as DesktopEnvironment from "../../app/DesktopEnvironment.ts";
......@@ -34,7 +33,7 @@ function makeWslBackendLayer(input: { readonly onReconcile?: Effect.Effect<void>
3433 DesktopWslBackend.DesktopWslBackend,
3534 DesktopWslBackend.DesktopWslBackend.of({
3635 reconcile: input.onReconcile ?? Effect.void,
37 lastPreflightError: Effect.succeed(Option.none()),
36 lastPreflightError: Effect.succeedNone,
3837 }),
3938 );
4039}
apps/desktop/src/preview/BrowserImport/ChromiumKeys.ts+3-2
......@@ -315,8 +315,9 @@ export const resolveChromiumKeys = Effect.fn("ChromiumKeys.resolveChromiumKeys")
315315 // v10 remains importable when Secret Service is absent or does not
316316 // contain a key. An explicit denial/lock/cancel remains a consent
317317 // failure rather than being silently downgraded.
318 Effect.catch((error) =>
319 error.reason === "needsKeychainApproval" ? Effect.fail(error) : Effect.succeed(error),
318 Effect.catchIf(
319 (error) => error.reason !== "needsKeychainApproval",
320 (error) => Effect.succeed(error),
320321 ),
321322 )
322323 : undefined;
apps/desktop/src/preview/BrowserImport/FirefoxCookies.ts+41-42
......@@ -114,56 +114,55 @@ const expiryToSeconds = (expiry: number, schemaVersion: number): number | undefi
114114 return schemaVersion >= FIREFOX_EXPIRY_MILLISECONDS_SCHEMA ? Math.floor(expiry / 1000) : expiry;
115115};
116116
117export const readFirefoxCookies = Effect.fn("FirefoxCookies.readFirefoxCookies")(function* (
118 cookieDatabasePath: string,
119) {
120 const snapshotPath = yield* snapshotCookieDatabase(cookieDatabasePath).pipe(
121 Effect.mapError((cause) => new FirefoxCookieReadError({ cookieDatabasePath, cause })),
122 );
117export const readFirefoxCookies = Effect.fn("FirefoxCookies.readFirefoxCookies")(
118 function* (cookieDatabasePath: string) {
119 const snapshotPath = yield* snapshotCookieDatabase(cookieDatabasePath);
123120
124 const { rows, schemaVersion } = yield* Effect.gen(function* () {
125 const sql = yield* SqlClient.SqlClient;
126 const [versionRow] = yield* decodeUserVersion(yield* sql`pragma user_version`);
127 const schemaVersion = versionRow?.user_version ?? 0;
128 const hasRawSameSite =
129 schemaVersion >= FIREFOX_RAW_SAMESITE_FIRST_SCHEMA &&
130 schemaVersion <= FIREFOX_RAW_SAMESITE_LAST_SCHEMA;
131 // Only the default container. Firefox isolates cookies per container and
132 // per private window via `originAttributes` (`^userContextId=2`,
133 // `^privateBrowsingId=1`); Electron has no equivalent, so importing them
134 // all would collapse several identities onto one host/name/path and hand
135 // the profile an arbitrary container's session.
136 const raw = hasRawSameSite
137 ? yield* sql`
121 const { rows, schemaVersion } = yield* Effect.gen(function* () {
122 const sql = yield* SqlClient.SqlClient;
123 const [versionRow] = yield* decodeUserVersion(yield* sql`pragma user_version`);
124 const schemaVersion = versionRow?.user_version ?? 0;
125 const hasRawSameSite =
126 schemaVersion >= FIREFOX_RAW_SAMESITE_FIRST_SCHEMA &&
127 schemaVersion <= FIREFOX_RAW_SAMESITE_LAST_SCHEMA;
128 // Only the default container. Firefox isolates cookies per container and
129 // per private window via `originAttributes` (`^userContextId=2`,
130 // `^privateBrowsingId=1`); Electron has no equivalent, so importing them
131 // all would collapse several identities onto one host/name/path and hand
132 // the profile an arbitrary container's session.
133 const raw = hasRawSameSite
134 ? yield* sql`
138135 select host, name, value, path, expiry, isSecure, isHttpOnly, sameSite, rawSameSite
139136 from moz_cookies
140137 where originAttributes = ''
141138 `
142 : yield* sql`
139 : yield* sql`
143140 select host, name, value, path, expiry, isSecure, isHttpOnly, sameSite,
144141 null as rawSameSite
145142 from moz_cookies
146143 where originAttributes = ''
147144 `;
148 return { rows: yield* decodeCookieRows(raw), schemaVersion };
149 }).pipe(
150 Effect.provide(NodeSqliteClient.layer({ filename: snapshotPath, readonly: true })),
151 Effect.mapError((cause) => new FirefoxCookieReadError({ cookieDatabasePath, cause })),
152 );
145 return { rows: yield* decodeCookieRows(raw), schemaVersion };
146 }).pipe(Effect.provide(NodeSqliteClient.layer({ filename: snapshotPath, readonly: true })));
153147
154 return rows.map((row) => {
155 const secure = row.isSecure === 1;
156 const scope = cookieScope(row.host, row.path, secure);
157 return {
158 url: scope.url,
159 name: row.name,
160 value: row.value,
161 domain: scope.domain,
162 path: row.path,
163 secure,
164 httpOnly: row.isHttpOnly === 1,
165 expirationDate: expiryToSeconds(row.expiry, schemaVersion),
166 sameSite: sameSiteFromColumn(row.sameSite, row.rawSameSite),
167 } satisfies ImportedCookie;
168 });
169});
148 return rows.map((row) => {
149 const secure = row.isSecure === 1;
150 const scope = cookieScope(row.host, row.path, secure);
151 return {
152 url: scope.url,
153 name: row.name,
154 value: row.value,
155 domain: scope.domain,
156 path: row.path,
157 secure,
158 httpOnly: row.isHttpOnly === 1,
159 expirationDate: expiryToSeconds(row.expiry, schemaVersion),
160 sameSite: sameSiteFromColumn(row.sameSite, row.rawSameSite),
161 } satisfies ImportedCookie;
162 });
163 },
164 (effect, cookieDatabasePath) =>
165 effect.pipe(
166 Effect.mapError((cause) => new FirefoxCookieReadError({ cookieDatabasePath, cause })),
167 ),
168);
apps/desktop/src/preview/BrowserSession.ts+6-6
......@@ -231,8 +231,9 @@ export const make = Effect.gen(function* BrowserSessionMake() {
231231 getSession,
232232 clearCookies: Effect.fn("BrowserSession.clearCookies")(function* (partitions?) {
233233 const sessions = yield* SynchronizedRef.get(sessionsRef);
234 yield* Effect.all(
235 selectSessions(sessions, partitions).map(([partition, browserSession]) =>
234 yield* Effect.forEach(
235 selectSessions(sessions, partitions),
236 ([partition, browserSession]) =>
236237 Effect.tryPromise({
237238 try: () =>
238239 browserSession.clearStorageData({
......@@ -244,14 +245,14 @@ export const make = Effect.gen(function* BrowserSessionMake() {
244245 cause,
245246 }),
246247 }),
247 ),
248248 { concurrency: "unbounded", discard: true },
249249 );
250250 }),
251251 clearCache: Effect.fn("BrowserSession.clearCache")(function* (partitions?) {
252252 const sessions = yield* SynchronizedRef.get(sessionsRef);
253 yield* Effect.all(
254 selectSessions(sessions, partitions).map(([partition, browserSession]) =>
253 yield* Effect.forEach(
254 selectSessions(sessions, partitions),
255 ([partition, browserSession]) =>
255256 Effect.tryPromise({
256257 try: () => browserSession.clearCache(),
257258 catch: (cause) =>
......@@ -260,7 +261,6 @@ export const make = Effect.gen(function* BrowserSessionMake() {
260261 cause,
261262 }),
262263 }),
263 ),
264264 { concurrency: "unbounded", discard: true },
265265 );
266266 }),
apps/desktop/src/preview/Manager.ts+25-28
......@@ -942,14 +942,14 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function
942942 delivery: () => Effect.Effect<void>,
943943 ) =>
944944 Effect.suspend(delivery).pipe(
945 Effect.catchCause((cause) =>
946 Cause.hasInterrupts(cause)
947 ? Effect.failCause(cause)
948 : Effect.logWarning("Desktop preview event listener failed.", {
949 eventKind,
950 tabId,
951 cause,
952 }),
945 Effect.catchCauseIf(
946 (cause) => !Cause.hasInterrupts(cause),
947 (cause) =>
948 Effect.logWarning("Desktop preview event listener failed.", {
949 eventKind,
950 tabId,
951 cause,
952 }),
953953 ),
954954 );
955955
......@@ -1115,15 +1115,13 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function
11151115 }
11161116 return resolvedPath;
11171117 }).pipe(
1118 Effect.flatMap((resolvedPath) =>
1119 resolvedPath === null
1120 ? Effect.fail(
1121 new PreviewArtifactPathOutsideDirectoryError({
1122 artifactPath,
1123 artifactDirectory: resolvedArtifactDirectory,
1124 }),
1125 )
1126 : Effect.succeed(resolvedPath),
1118 Effect.filterOrFail(
1119 (resolvedPath) => resolvedPath !== null,
1120 () =>
1121 new PreviewArtifactPathOutsideDirectoryError({
1122 artifactPath,
1123 artifactDirectory: resolvedArtifactDirectory,
1124 }),
11271125 ),
11281126 );
11291127
......@@ -1404,14 +1402,13 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function
14041402 wcDebugger.on("message", onMessage);
14051403 wcDebugger.attach("1.3");
14061404 });
1407 yield* Effect.all(
1408 ["Runtime.enable", "Accessibility.enable", "Network.enable", "Log.enable"].map(
1409 (method) =>
1410 attemptPromise(
1411 { operation: `initializeDebugger.${method}`, webContentsId: wc.id },
1412 () => wcDebugger.sendCommand(method),
1413 ),
1414 ),
1405 yield* Effect.forEach(
1406 ["Runtime.enable", "Accessibility.enable", "Network.enable", "Log.enable"],
1407 (method) =>
1408 attemptPromise(
1409 { operation: `initializeDebugger.${method}`, webContentsId: wc.id },
1410 () => wcDebugger.sendCommand(method),
1411 ),
14151412 { concurrency: "unbounded", discard: true },
14161413 );
14171414 return [
......@@ -4056,13 +4053,13 @@ const makeNativeOperations = Effect.fn("PreviewManager.makeOperations")(function
40564053 receiptKey: JSON.stringify(`__t3NativeKey_${NodeCrypto.randomUUID()}`),
40574054 })),
40584055 ({ frames, receiptKey }) =>
4059 Effect.all(
4060 frames.map((frame) =>
4056 Effect.forEach(
4057 frames,
4058 (frame) =>
40614059 evaluate(frame, `globalThis[${receiptKey}]?.dispose()`).pipe(
40624060 Effect.timeoutOption(1_000),
40634061 Effect.ignore,
40644062 ),
4065 ),
40664063 { concurrency: "unbounded", discard: true },
40674064 ),
40684065 );
apps/desktop/src/settings/DesktopClientSettings.ts+2-2
......@@ -75,7 +75,7 @@ const readClientSettings = (
7575 settingsPath: string,
7676): Effect.Effect<Option.Option<ClientSettings>, DesktopClientSettingsReadError> =>
7777 fileSystem.readFileString(settingsPath).pipe(
78 Effect.map(Option.some),
78 Effect.asSome,
7979 Effect.catchTags({
8080 PlatformError: (cause) =>
8181 cause.reason._tag === "NotFound"
......@@ -98,7 +98,7 @@ const readClientSettings = (
9898 onNone: () => Effect.succeed(Option.none<ClientSettings>()),
9999 onSome: (raw) =>
100100 decodeClientSettingsJson(raw).pipe(
101 Effect.map((settings) => Option.some(settings)),
101 Effect.asSome,
102102 Effect.catchTags({
103103 SchemaError: (cause) =>
104104 Effect.logWarning("Could not decode desktop client settings.", cause).pipe(
apps/desktop/src/settings/DesktopSavedEnvironments.test.ts+1-1
......@@ -94,7 +94,7 @@ function makeSafeStorageLayer(input: {
9494 }
9595 return Effect.succeed(decoded.slice("enc:".length));
9696 },
97 selectedStorageBackend: Effect.succeed(Option.none()),
97 selectedStorageBackend: Effect.succeedNone,
9898 } satisfies ElectronSafeStorage.ElectronSafeStorage["Service"]);
9999}
100100
apps/desktop/src/snapShot/DesktopSnapShot.ts+6-7
......@@ -820,7 +820,7 @@ export const make = Effect.gen(function* () {
820820 };
821821
822822 const emit = (event: DesktopSnapShotEvent) =>
823 desktopWindow.dispatchSnapShotEvent(event).pipe(Effect.catchCause(() => Effect.void));
823 desktopWindow.dispatchSnapShotEvent(event).pipe(Effect.ignoreCause);
824824 const setFailure = (message: string, captureId?: string) =>
825825 Ref.update(stateRef, (state) => ({ ...state, message })).pipe(
826826 Effect.andThen(
......@@ -846,10 +846,9 @@ export const make = Effect.gen(function* () {
846846 const discardCapture = Effect.fn("desktop.snapShot.discardCapture")(function* (id: string) {
847847 closeLinuxFeedback(id);
848848 transition.dismiss(id);
849 yield* Effect.all(
850 [`${id}.png`, `${id}.tmp.png`, `${id}.json`, `${id}.json.tmp`].map((name) =>
851 fileSystem.remove(path.join(captureDirectory, name), { force: true }),
852 ),
849 yield* Effect.forEach(
850 [`${id}.png`, `${id}.tmp.png`, `${id}.json`, `${id}.json.tmp`],
851 (name) => fileSystem.remove(path.join(captureDirectory, name), { force: true }),
853852 { concurrency: "unbounded", discard: true },
854853 ).pipe(Effect.ignore);
855854 });
......@@ -904,7 +903,7 @@ export const make = Effect.gen(function* () {
904903 if (snapshot.animationStarted) {
905904 yield* emit({ type: "started", id: id as DesktopSnapShotId });
906905 } else {
907 yield* desktopWindow.activate.pipe(Effect.catchCause(() => Effect.void));
906 yield* desktopWindow.activate.pipe(Effect.ignoreCause);
908907 }
909908 return { id, capturedAt, ...snapshot };
910909 }).pipe(Effect.mapError((cause) => captureFailure(cause, id)));
......@@ -1511,7 +1510,7 @@ export const make = Effect.gen(function* () {
15111510 null,
15121511 ),
15131512 ),
1514 Effect.catch(() => Effect.void),
1513 Effect.ignore,
15151514 ),
15161515 ),
15171516 configure,
apps/desktop/src/ssh/DesktopSshPasswordPrompts.test.ts+3-4
......@@ -4,7 +4,6 @@ import * as Duration from "effect/Duration";
44import * as Effect from "effect/Effect";
55import * as Fiber from "effect/Fiber";
66import * as Layer from "effect/Layer";
7import * as Option from "effect/Option";
87import * as TestClock from "effect/testing/TestClock";
98import type * as Electron from "electron";
109
......@@ -92,9 +91,9 @@ function makeElectronWindowLayer(window: ReturnType<typeof makeTestWindow>["wind
9291 ElectronWindow.ElectronWindow,
9392 ElectronWindow.ElectronWindow.of({
9493 create: () => Effect.die("unexpected BrowserWindow creation"),
95 main: Effect.succeed(Option.some(window as Electron.BrowserWindow)),
96 currentMainOrFirst: Effect.succeed(Option.some(window as Electron.BrowserWindow)),
97 focusedMainOrFirst: Effect.succeed(Option.some(window as Electron.BrowserWindow)),
94 main: Effect.succeedSome(window as Electron.BrowserWindow),
95 currentMainOrFirst: Effect.succeedSome(window as Electron.BrowserWindow),
96 focusedMainOrFirst: Effect.succeedSome(window as Electron.BrowserWindow),
9897 setMain: () => Effect.void,
9998 clearMain: () => Effect.void,
10099 prepareReveal: () => Effect.succeed(false),
apps/desktop/src/telemetry/DesktopTelemetryPublisher.ts+7-6
......@@ -289,12 +289,12 @@ export const make = Effect.fn("desktop.telemetryPublisher.make")(function* () {
289289 yield* Ref.set(latest, Option.some(snapshot));
290290 yield* PubSub.publish(changes, snapshot);
291291 }).pipe(
292 Effect.catchCause((cause) =>
293 Cause.hasInterrupts(cause)
294 ? Effect.failCause(cause)
295 : Effect.logWarning("Failed to sample Electron telemetry", {
296 cause: String(cause),
297 }),
292 Effect.catchCauseIf(
293 (cause) => !Cause.hasInterrupts(cause),
294 (cause) =>
295 Effect.logWarning("Failed to sample Electron telemetry", {
296 cause: String(cause),
297 }),
298298 ),
299299 );
300300
......@@ -306,6 +306,7 @@ export const make = Effect.fn("desktop.telemetryPublisher.make")(function* () {
306306 Ref.get(diagnosticsDemandSources).pipe(Effect.map((sources) => sources.size > 0)),
307307 Ref.get(hostPowerIntervals),
308308 ]);
309 // @effect-diagnostics-next-line raceFirstWithSleepToTimeout:off - races a trigger queue against the interval; both arms are real outcomes, not a timeout
309310 const allowSuspendRecovery = yield* Effect.raceFirst(
310311 Queue.take(sampleTriggers).pipe(Effect.as(false)),
311312 Effect.sleep(sampleInterval(currentPower, demand, intervals)).pipe(Effect.as(true)),
apps/desktop/src/updates/DesktopUpdates.ts+16-15
......@@ -668,24 +668,25 @@ export const make = Effect.gen(function* () {
668668 }),
669669 ).pipe(Effect.withSpan("desktop.updates.installDownloadedUpdate"));
670670
671 const installWithExpectedVersion = (expectedVersion?: string) =>
672 Effect.gen(function* () {
673 if (yield* Ref.get(desktopState.quitting)) {
674 return {
675 accepted: false,
676 completed: false,
677 failed: false,
678 state: yield* Ref.get(updateStateRef),
679 };
680 }
681 const result = yield* installDownloadedUpdate(expectedVersion);
671 const installWithExpectedVersion = Effect.fn("desktop.updates.install")(function* (
672 expectedVersion?: string,
673 ) {
674 if (yield* Ref.get(desktopState.quitting)) {
682675 return {
683 accepted: result.accepted,
684 completed: result.completed,
685 failed: result.failed,
676 accepted: false,
677 completed: false,
678 failed: false,
686679 state: yield* Ref.get(updateStateRef),
687680 };
688 }).pipe(Effect.withSpan("desktop.updates.install"));
681 }
682 const result = yield* installDownloadedUpdate(expectedVersion);
683 return {
684 accepted: result.accepted,
685 completed: result.completed,
686 failed: result.failed,
687 state: yield* Ref.get(updateStateRef),
688 };
689 });
689690
690691 const startUpdatePollers: Effect.Effect<void, never, Scope.Scope> = Effect.gen(function* () {
691692 yield* Effect.sleep(AUTO_UPDATE_STARTUP_DELAY).pipe(
apps/desktop/src/updates/updatesTestHarness.ts+5-5
......@@ -107,9 +107,9 @@ export function makeHarness(options: UpdatesHarnessOptions = {}) {
107107
108108 const windowLayer = Layer.succeed(ElectronWindow.ElectronWindow, {
109109 create: () => Effect.die("unexpected BrowserWindow creation"),
110 main: Effect.succeed(Option.none()),
111 currentMainOrFirst: Effect.succeed(Option.none()),
112 focusedMainOrFirst: Effect.succeed(Option.none()),
110 main: Effect.succeedNone,
111 currentMainOrFirst: Effect.succeedNone,
112 focusedMainOrFirst: Effect.succeedNone,
113113 setMain: () => Effect.void,
114114 clearMain: () => Effect.void,
115115 prepareReveal: () => Effect.succeed(false),
......@@ -131,7 +131,7 @@ export function makeHarness(options: UpdatesHarnessOptions = {}) {
131131 installSteps.push("startBackend");
132132 }).pipe(Effect.andThen(options.startBackend ?? Effect.void)),
133133 stop: () => options.stopBackend ?? Effect.void,
134 currentConfig: Effect.succeed(Option.none()),
134 currentConfig: Effect.succeedNone,
135135 snapshot: Effect.succeed({
136136 desiredRunning: false,
137137 ready: false,
......@@ -245,7 +245,7 @@ export function makeHarness(options: UpdatesHarnessOptions = {}) {
245245 installSteps,
246246 updateRestartMarkers,
247247 downloadCount: () => downloadCount,
248 feedUrls: () => feedUrls,
248 feedUrls: (): ElectronUpdater.ElectronUpdaterFeedUrl[] => feedUrls,
249249 fullChangelog: () => fullChangelog,
250250 listenerCount: () =>
251251 Array.from(listeners.values()).reduce(
apps/desktop/src/window/DesktopApplicationMenu.test.ts+3-4
......@@ -3,7 +3,6 @@ import { assert, describe, it } from "@effect/vitest";
33import * as Deferred from "effect/Deferred";
44import * as Effect from "effect/Effect";
55import * as Layer from "effect/Layer";
6import * as Option from "effect/Option";
76
87import type * as Electron from "electron";
98
......@@ -51,7 +50,7 @@ const electronAppLayer = Layer.succeed(ElectronApp.ElectronApp, {
5150} satisfies ElectronApp.ElectronApp["Service"]);
5251
5352const electronDialogLayer = Layer.succeed(ElectronDialog.ElectronDialog, {
54 pickFolder: () => Effect.succeed(Option.none()),
53 pickFolder: () => Effect.succeedNone,
5554 pickFiles: () => Effect.succeed([]),
5655 showMessageBox: () => Effect.succeed({ response: 0, checkboxChecked: false }),
5756 showErrorBox: () => Effect.void,
......@@ -63,7 +62,7 @@ const desktopUpdatesLayer = Layer.succeed(DesktopUpdates.DesktopUpdates, {
6362 isInstallActive: Effect.succeed(false),
6463 subscribe: Effect.die("unexpected subscribe"),
6564 emitState: Effect.void,
66 disabledReason: Effect.succeed(Option.none()),
65 disabledReason: Effect.succeedNone,
6766 configure: Effect.void,
6867 setChannel: () => Effect.die("unexpected setChannel"),
6968 check: () => Effect.die("unexpected check"),
......@@ -98,7 +97,7 @@ const makeElectronMenuLayer = (
9897 setApplicationMenu: (template) =>
9998 Deferred.succeed(applicationMenuTemplate, template).pipe(Effect.asVoid),
10099 popupTemplate: () => Effect.void,
101 showContextMenu: () => Effect.succeed(Option.none()),
100 showContextMenu: () => Effect.succeedNone,
102101 } satisfies ElectronMenu.ElectronMenu["Service"]);
103102
104103const configureMenu = (
apps/desktop/src/window/DesktopWindow.test.ts+3-3
......@@ -151,7 +151,7 @@ function makeFakeBrowserWindow() {
151151}
152152
153153const desktopClientSettingsLayer = Layer.mock(DesktopClientSettings.DesktopClientSettings)({
154 get: Effect.succeed(Option.none()),
154 get: Effect.succeedNone,
155155});
156156
157157const electronAppLayer = Layer.mock(ElectronApp.ElectronApp)({
......@@ -185,7 +185,7 @@ const desktopServerExposureLayer = Layer.succeed(DesktopServerExposure.DesktopSe
185185const electronMenuLayer = Layer.succeed(ElectronMenu.ElectronMenu, {
186186 setApplicationMenu: () => Effect.void,
187187 popupTemplate: () => Effect.void,
188 showContextMenu: () => Effect.succeed(Option.none()),
188 showContextMenu: () => Effect.succeedNone,
189189} satisfies ElectronMenu.ElectronMenu["Service"]);
190190
191191const electronThemeLayer = Layer.succeed(ElectronTheme.ElectronTheme, {
......@@ -294,7 +294,7 @@ function makeTestLayer(input: {
294294 electronAppLayer,
295295 Layer.succeed(ElectronMenu.ElectronMenu, {
296296 setApplicationMenu: () => Effect.void,
297 showContextMenu: () => Effect.succeed(Option.none()),
297 showContextMenu: () => Effect.succeedNone,
298298 popupTemplate: input.onPopupTemplate ?? (() => Effect.void),
299299 }),
300300 Layer.succeed(ElectronShell.ElectronShell, {
apps/desktop/src/wsl/DesktopWslBackend.ts+2-2
......@@ -138,7 +138,7 @@ export const layer = Layer.effect(
138138 const primaryConfig = yield* serverExposure.backendConfig;
139139 const port = yield* scanForWslPort(primaryConfig.port + 1).pipe(
140140 Effect.provideService(NetService.NetService, net),
141 Effect.map((value) => Option.some(value)),
141 Effect.asSome,
142142 Effect.catch((error) =>
143143 logWslBackendWarning("could not allocate port for WSL backend", {
144144 error: error.message,
......@@ -171,7 +171,7 @@ export const layer = Layer.effect(
171171 onReady: () => Ref.set(preflightErrorRef, Option.none()),
172172 })
173173 .pipe(
174 Effect.map((registered) => Option.some(registered)),
174 Effect.asSome,
175175 Effect.catch((error) =>
176176 logWslBackendWarning("WSL backend already registered, skipping start", {
177177 id: targetId,
apps/desktop/src/wsl/DesktopWslEnvironment.ts+9-14
......@@ -1040,11 +1040,7 @@ const preWarmImpl = (
10401040 const handle = yield* spawner.spawn(command);
10411041 yield* handle.exitCode;
10421042 }),
1043 ).pipe(
1044 Effect.timeoutOption(PRE_WARM_TIMEOUT),
1045 Effect.asVoid,
1046 Effect.catch(() => Effect.void),
1047 );
1043 ).pipe(Effect.timeoutOption(PRE_WARM_TIMEOUT), Effect.ignore);
10481044
10491045const windowsToWslPathImpl = (
10501046 distro: string | null,
......@@ -1272,15 +1268,14 @@ export const layer = Layer.effect(
12721268 // distro. Negative results aren't cached so a transient wsl.exe failure
12731269 // doesn't permanently disable tilde expansion.
12741270 const userHomeCache = new Map<string, string>();
1275 const getUserHome = (distro: string | null) =>
1276 Effect.gen(function* () {
1277 const key = distro ?? "__default__";
1278 const cached = userHomeCache.get(key);
1279 if (cached !== undefined) return Option.some(cached);
1280 const resolved = yield* provideSpawner(getUserHomeImpl(distro));
1281 if (Option.isSome(resolved)) userHomeCache.set(key, resolved.value);
1282 return resolved;
1283 }).pipe(Effect.withSpan("desktop.wsl.getUserHome"));
1271 const getUserHome = Effect.fn("desktop.wsl.getUserHome")(function* (distro: string | null) {
1272 const key = distro ?? "__default__";
1273 const cached = userHomeCache.get(key);
1274 if (cached !== undefined) return Option.some(cached);
1275 const resolved = yield* provideSpawner(getUserHomeImpl(distro));
1276 if (Option.isSome(resolved)) userHomeCache.set(key, resolved.value);
1277 return resolved;
1278 });
12841279
12851280 const getDistroIp = (distro: string | null) =>
12861281 provideSpawner(getDistroIpImpl(distro)).pipe(Effect.withSpan("desktop.wsl.getDistroIp"));
apps/server/integration/orphanedProviderSessionStartup.integration.test.ts+1-1
......@@ -100,7 +100,7 @@ const startupDependencies = Layer.mergeAll(
100100 Layer.succeed(ServiceLauncherClient.ServiceLauncherClient, {
101101 managed: false,
102102 requestUpdate: () => Effect.die("unused"),
103 prepareTrial: Effect.sync(() => undefined),
103 prepareTrial: Effect.undefined,
104104 }),
105105 Layer.succeed(
106106 HttpServer.HttpServer,
apps/server/src/assets/AssetAccess.ts+3-3
......@@ -190,7 +190,7 @@ const optionOnNotFound = <A, R>(
190190 effect: Effect.Effect<A, PlatformError.PlatformError, R>,
191191): Effect.Effect<Option.Option<A>, PlatformError.PlatformError, R> =>
192192 effect.pipe(
193 Effect.map(Option.some),
193 Effect.asSome,
194194 Effect.catchTags({
195195 PlatformError: (error) =>
196196 error.reason._tag === "NotFound" ? Effect.succeed(Option.none<A>()) : Effect.fail(error),
......@@ -213,9 +213,9 @@ const resolveCanonicalWorkspaceFile = Effect.fn("AssetAccess.resolveCanonicalWor
213213 const fileSystem = yield* FileSystem.FileSystem;
214214 const workspacePaths = yield* WorkspacePaths.WorkspacePaths;
215215 const resolved = yield* workspacePaths.resolveRelativePathWithinRoot(input).pipe(
216 Effect.map(Option.some),
216 Effect.asSome,
217217 Effect.catchTags({
218 WorkspacePathOutsideRootError: () => Effect.succeed(Option.none()),
218 WorkspacePathOutsideRootError: () => Effect.succeedNone,
219219 }),
220220 );
221221 if (Option.isNone(resolved)) return null;
apps/server/src/assets/NativeAppIconResolver.ts+2-2
......@@ -43,10 +43,10 @@ function appFromCacheKey(key: string): ToolActivityNativeAppReference {
4343const existingFile = Effect.fn("NativeAppIconResolver.existingFile")(function* (filePath: string) {
4444 const fileSystem = yield* FileSystem.FileSystem;
4545 const info = yield* fileSystem.stat(filePath).pipe(
46 Effect.map(Option.some),
46 Effect.asSome,
4747 Effect.catchTags({
4848 PlatformError: (error) =>
49 error.reason._tag === "NotFound" ? Effect.succeed(Option.none()) : Effect.fail(error),
49 error.reason._tag === "NotFound" ? Effect.succeedNone : Effect.fail(error),
5050 }),
5151 );
5252 return Option.isSome(info) && info.value.type === "File" ? filePath : null;
apps/server/src/auth/PairingGrantStore.test.ts+2-3
......@@ -3,7 +3,6 @@ import { expect, it } from "@effect/vitest";
33import * as Duration from "effect/Duration";
44import * as Effect from "effect/Effect";
55import * as Layer from "effect/Layer";
6import * as Option from "effect/Option";
76import * as Stream from "effect/Stream";
87import * as Queue from "effect/Queue";
98import * as TestClock from "effect/testing/TestClock";
......@@ -47,10 +46,10 @@ const makePairingGrantStoreTestLayer = (
4746 AuthPairingLinks.AuthPairingLinkRepository,
4847 AuthPairingLinks.AuthPairingLinkRepository.of({
4948 create: () => Effect.void,
50 consumeAvailable: () => Effect.succeed(Option.none()),
49 consumeAvailable: () => Effect.succeedNone,
5150 listActive: () => Effect.succeed([]),
5251 revoke: () => Effect.succeed(false),
53 getByCredential: () => Effect.succeed(Option.none()),
52 getByCredential: () => Effect.succeedNone,
5453 ...overrides,
5554 }),
5655 ),
apps/server/src/auth/ServerSecretStore.ts+1-1
......@@ -174,7 +174,7 @@ export const make = Effect.gen(function* () {
174174 Effect.map((bytes) => Option.some(Uint8Array.from(bytes))),
175175 Effect.catch((cause) =>
176176 cause.reason._tag === "NotFound"
177 ? Effect.succeed(Option.none())
177 ? Effect.succeedNone
178178 : Effect.fail(
179179 new SecretStoreReadError({
180180 resource: `secret ${name}`,
apps/server/src/auth/dpop.ts+1-1
......@@ -115,7 +115,7 @@ export const verifyRequestDpopProof = (input: {
115115 "environment.dpop.failure_code": mapped.dpopFailureReason,
116116 });
117117 }
118 return yield* Effect.fail(mapped);
118 return yield* mapped;
119119 }),
120120 ),
121121 );
apps/server/src/auth/http.test.ts+1-2
......@@ -5,7 +5,6 @@ import * as Context from "effect/Context";
55import * as Crypto from "effect/Crypto";
66import * as Effect from "effect/Effect";
77import * as Layer from "effect/Layer";
8import * as Option from "effect/Option";
98import * as Redacted from "effect/Redacted";
109import * as Schema from "effect/Schema";
1110import * as Etag from "effect/unstable/http/Etag";
......@@ -69,7 +68,7 @@ it.effect("sets the selected browser session cookies through the HTTP route", ()
6968 Effect.gen(function* () {
7069 const crypto = yield* Crypto.Crypto;
7170 const unusedSecretStore = ServerSecretStore.ServerSecretStore.of({
72 get: () => Effect.succeed(Option.none()),
71 get: () => Effect.succeedNone,
7372 set: () => Effect.void,
7473 create: () => Effect.void,
7574 getOrCreateRandom: () => Effect.die("Not used by these routes."),
apps/server/src/checkpointing/CheckpointDiffQuery.test.ts+35-35
......@@ -89,10 +89,10 @@ describe("CheckpointDiffQuery.layer", () => {
8989 getSnapshotSequence: () => Effect.succeed({ snapshotSequence: 0 }),
9090 getCounts: () => Effect.succeed({ projectCount: 0, threadCount: 0 }),
9191 getEventReplayStats: () => Effect.die("unused"),
92 getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()),
92 getActiveProjectByWorkspaceRoot: () => Effect.succeedNone,
9393 getProjectShells: () => Effect.die("unused"),
94 getProjectShellById: () => Effect.succeed(Option.none()),
95 getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()),
94 getProjectShellById: () => Effect.succeedNone,
95 getFirstActiveThreadIdByProjectId: () => Effect.succeedNone,
9696 getImportedAgentSessionSources: () => Effect.die("unused"),
9797 getThreadCheckpointContext: () =>
9898 Effect.sync(() => {
......@@ -113,9 +113,9 @@ describe("CheckpointDiffQuery.layer", () => {
113113 }),
114114 getThreadRuntimeContext: () => Effect.die("unused"),
115115 getTurnStartMessage: () => Effect.die("unused"),
116 getThreadShellById: () => Effect.succeed(Option.none()),
117 getThreadDetailById: () => Effect.succeed(Option.none()),
118 getThreadDetailSnapshot: () => Effect.succeed(Option.none()),
116 getThreadShellById: () => Effect.succeedNone,
117 getThreadDetailById: () => Effect.succeedNone,
118 getThreadDetailSnapshot: () => Effect.succeedNone,
119119 searchThreads: () => Effect.succeed({ matches: [] }),
120120 }),
121121 ),
......@@ -206,18 +206,18 @@ describe("CheckpointDiffQuery.layer", () => {
206206 getSnapshotSequence: () => Effect.succeed({ snapshotSequence: 0 }),
207207 getCounts: () => Effect.succeed({ projectCount: 0, threadCount: 0 }),
208208 getEventReplayStats: () => Effect.die("unused"),
209 getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()),
209 getActiveProjectByWorkspaceRoot: () => Effect.succeedNone,
210210 getProjectShells: () => Effect.die("unused"),
211 getProjectShellById: () => Effect.succeed(Option.none()),
212 getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()),
211 getProjectShellById: () => Effect.succeedNone,
212 getFirstActiveThreadIdByProjectId: () => Effect.succeedNone,
213213 getImportedAgentSessionSources: () => Effect.die("unused"),
214 getThreadCheckpointContext: () => Effect.succeed(Option.some(threadCheckpointContext)),
214 getThreadCheckpointContext: () => Effect.succeedSome(threadCheckpointContext),
215215 getFullThreadDiffContext: () => Effect.die("unused"),
216216 getThreadRuntimeContext: () => Effect.die("unused"),
217217 getTurnStartMessage: () => Effect.die("unused"),
218 getThreadShellById: () => Effect.succeed(Option.none()),
219 getThreadDetailById: () => Effect.succeed(Option.none()),
220 getThreadDetailSnapshot: () => Effect.succeed(Option.none()),
218 getThreadShellById: () => Effect.succeedNone,
219 getThreadDetailById: () => Effect.succeedNone,
220 getThreadDetailSnapshot: () => Effect.succeedNone,
221221 searchThreads: () => Effect.succeed({ matches: [] }),
222222 }),
223223 ),
......@@ -298,18 +298,18 @@ describe("CheckpointDiffQuery.layer", () => {
298298 getSnapshotSequence: () => Effect.succeed({ snapshotSequence: 0 }),
299299 getCounts: () => Effect.succeed({ projectCount: 0, threadCount: 0 }),
300300 getEventReplayStats: () => Effect.die("unused"),
301 getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()),
301 getActiveProjectByWorkspaceRoot: () => Effect.succeedNone,
302302 getProjectShells: () => Effect.die("unused"),
303 getProjectShellById: () => Effect.succeed(Option.none()),
304 getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()),
303 getProjectShellById: () => Effect.succeedNone,
304 getFirstActiveThreadIdByProjectId: () => Effect.succeedNone,
305305 getImportedAgentSessionSources: () => Effect.die("unused"),
306 getThreadCheckpointContext: () => Effect.succeed(Option.some(threadCheckpointContext)),
306 getThreadCheckpointContext: () => Effect.succeedSome(threadCheckpointContext),
307307 getFullThreadDiffContext: () => Effect.die("unused"),
308308 getThreadRuntimeContext: () => Effect.die("unused"),
309309 getTurnStartMessage: () => Effect.die("unused"),
310 getThreadShellById: () => Effect.succeed(Option.none()),
311 getThreadDetailById: () => Effect.succeed(Option.none()),
312 getThreadDetailSnapshot: () => Effect.succeed(Option.none()),
310 getThreadShellById: () => Effect.succeedNone,
311 getThreadDetailById: () => Effect.succeedNone,
312 getThreadDetailSnapshot: () => Effect.succeedNone,
313313 searchThreads: () => Effect.succeed({ matches: [] }),
314314 }),
315315 ),
......@@ -375,18 +375,18 @@ describe("CheckpointDiffQuery.layer", () => {
375375 getSnapshotSequence: () => Effect.succeed({ snapshotSequence: 0 }),
376376 getCounts: () => Effect.succeed({ projectCount: 0, threadCount: 0 }),
377377 getEventReplayStats: () => Effect.die("unused"),
378 getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()),
378 getActiveProjectByWorkspaceRoot: () => Effect.succeedNone,
379379 getProjectShells: () => Effect.die("unused"),
380 getProjectShellById: () => Effect.succeed(Option.none()),
381 getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()),
380 getProjectShellById: () => Effect.succeedNone,
381 getFirstActiveThreadIdByProjectId: () => Effect.succeedNone,
382382 getImportedAgentSessionSources: () => Effect.die("unused"),
383 getThreadCheckpointContext: () => Effect.succeed(Option.some(threadCheckpointContext)),
383 getThreadCheckpointContext: () => Effect.succeedSome(threadCheckpointContext),
384384 getFullThreadDiffContext: () => Effect.die("unused"),
385385 getThreadRuntimeContext: () => Effect.die("unused"),
386386 getTurnStartMessage: () => Effect.die("unused"),
387 getThreadShellById: () => Effect.succeed(Option.none()),
388 getThreadDetailById: () => Effect.succeed(Option.none()),
389 getThreadDetailSnapshot: () => Effect.succeed(Option.none()),
387 getThreadShellById: () => Effect.succeedNone,
388 getThreadDetailById: () => Effect.succeedNone,
389 getThreadDetailSnapshot: () => Effect.succeedNone,
390390 searchThreads: () => Effect.succeed({ matches: [] }),
391391 }),
392392 ),
......@@ -437,18 +437,18 @@ describe("CheckpointDiffQuery.layer", () => {
437437 getSnapshotSequence: () => Effect.succeed({ snapshotSequence: 0 }),
438438 getCounts: () => Effect.succeed({ projectCount: 0, threadCount: 0 }),
439439 getEventReplayStats: () => Effect.die("unused"),
440 getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()),
440 getActiveProjectByWorkspaceRoot: () => Effect.succeedNone,
441441 getProjectShells: () => Effect.die("unused"),
442 getProjectShellById: () => Effect.succeed(Option.none()),
443 getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()),
442 getProjectShellById: () => Effect.succeedNone,
443 getFirstActiveThreadIdByProjectId: () => Effect.succeedNone,
444444 getImportedAgentSessionSources: () => Effect.die("unused"),
445 getThreadCheckpointContext: () => Effect.succeed(Option.none()),
446 getFullThreadDiffContext: () => Effect.succeed(Option.none()),
445 getThreadCheckpointContext: () => Effect.succeedNone,
446 getFullThreadDiffContext: () => Effect.succeedNone,
447447 getThreadRuntimeContext: () => Effect.die("unused"),
448448 getTurnStartMessage: () => Effect.die("unused"),
449 getThreadShellById: () => Effect.succeed(Option.none()),
450 getThreadDetailById: () => Effect.succeed(Option.none()),
451 getThreadDetailSnapshot: () => Effect.succeed(Option.none()),
449 getThreadShellById: () => Effect.succeedNone,
450 getThreadDetailById: () => Effect.succeedNone,
451 getThreadDetailSnapshot: () => Effect.succeedNone,
452452 searchThreads: () => Effect.succeed({ matches: [] }),
453453 }),
454454 ),
apps/server/src/cli/theme.ts+17-20
......@@ -260,12 +260,10 @@ const writeDefaultTheme = Effect.fn(function* (input: {
260260 // Falling through here would overwrite whatever landed in between, which
261261 // is exactly the loss this loop exists to prevent.
262262 if (attempt >= CONCURRENT_WRITE_ATTEMPTS) {
263 return yield* Effect.fail(
264 new ThemeSettingsBusyError({
265 settingsPath: input.settingsPath,
266 attempts: CONCURRENT_WRITE_ATTEMPTS,
267 }),
268 );
263 return yield* new ThemeSettingsBusyError({
264 settingsPath: input.settingsPath,
265 attempts: CONCURRENT_WRITE_ATTEMPTS,
266 });
269267 }
270268 continue;
271269 }
......@@ -299,12 +297,13 @@ const publishThemeFile = Effect.fn(function* (input: {
299297 Effect.mapError((cause) => new ThemeFileUnreadableError({ filePath: input.filePath, cause })),
300298 );
301299 if (info.type !== "File") {
302 return yield* Effect.fail(new ThemeFileUnreadableError({ filePath: input.filePath }));
300 return yield* new ThemeFileUnreadableError({ filePath: input.filePath });
303301 }
304302 if (Number(info.size) > MAX_THEME_FILE_BYTES) {
305 return yield* Effect.fail(
306 new ThemeFileTooLargeError({ filePath: input.filePath, limit: MAX_THEME_FILE_BYTES }),
307 );
303 return yield* new ThemeFileTooLargeError({
304 filePath: input.filePath,
305 limit: MAX_THEME_FILE_BYTES,
306 });
308307 }
309308
310309 // 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: {
320319 );
321320 const raw = readThemeFileGuarded(resolvedSource, MAX_THEME_FILE_BYTES);
322321 if (raw === null) {
323 return yield* Effect.fail(new ThemeFileUnreadableError({ filePath: input.filePath }));
322 return yield* new ThemeFileUnreadableError({ filePath: input.filePath });
324323 }
325324
326325 const decoded = decodeThemeFileJsonExit(raw);
327326 if (decoded._tag === "Failure") {
328 return yield* Effect.fail(
329 new ThemeFileInvalidError({ filePath: input.filePath, cause: decoded.cause }),
330 );
327 return yield* new ThemeFileInvalidError({ filePath: input.filePath, cause: decoded.cause });
331328 }
332329 if (!environmentThemeFileHasColors(decoded.value)) {
333 return yield* Effect.fail(new ThemeFileColorlessError({ filePath: input.filePath }));
330 return yield* new ThemeFileColorlessError({ filePath: input.filePath });
334331 }
335332
336333 const fileBasename = path.basename(input.filePath, ".json");
......@@ -338,7 +335,7 @@ const publishThemeFile = Effect.fn(function* (input: {
338335 // The same rules the watcher applies when it reads the directory back, so a
339336 // publish cannot report success for a file that will then be skipped.
340337 if (!isEnvironmentThemeId(themeId) || UNPUBLISHABLE_THEME_IDS.has(themeId)) {
341 return yield* Effect.fail(new ThemeFileIdInvalidError({ themeId, filePath: input.filePath }));
338 return yield* new ThemeFileIdInvalidError({ themeId, filePath: input.filePath });
342339 }
343340
344341 const destinationPath = path.join(input.themesDir, `${themeId}.json`);
......@@ -479,7 +476,7 @@ const themeSetCommand = Command.make("set", {
479476 const fs = yield* FileSystem.FileSystem;
480477 const target = yield* expandHomePath(flags.theme.trim());
481478 if (target.length === 0) {
482 return yield* Effect.fail(new ThemeTargetMissingError());
479 return yield* new ThemeTargetMissingError();
483480 }
484481 const paths = yield* resolveThemePaths(flags.baseDir);
485482
......@@ -514,15 +511,15 @@ const themeSetCommand = Command.make("set", {
514511 revertPublish = published.revert;
515512 cleanupPublish = published.cleanup;
516513 } else if (looksLikePath) {
517 return yield* Effect.fail(new ThemeFileUnreadableError({ filePath: target }));
514 return yield* new ThemeFileUnreadableError({ filePath: target });
518515 } else if (isEnvironmentThemeId(target)) {
519516 const known = yield* resolvableThemeIds(paths.themesDir);
520517 if (!known.includes(target)) {
521 return yield* Effect.fail(new ThemeIdUnknownError({ themeId: target, known }));
518 return yield* new ThemeIdUnknownError({ themeId: target, known });
522519 }
523520 themeId = target;
524521 } else {
525 return yield* Effect.fail(new ThemeIdInvalidError({ themeId: target }));
522 return yield* new ThemeIdInvalidError({ themeId: target });
526523 }
527524
528525 // set means set: if the default cannot be written, the publish that
apps/server/src/cloud/CliTokenManager.ts+1-1
......@@ -341,7 +341,7 @@ const pollDeviceToken = Effect.fn("cloud.cli_token.poll_device_token")(function*
341341 const response = yield* HttpClientRequest.post(metadata.tokenEndpoint).pipe(
342342 HttpClientRequest.bodyUrlParams(params),
343343 httpClient.execute,
344 Effect.map(Option.some),
344 Effect.asSome,
345345 Effect.catchIf(isTransportError, () => Effect.succeedNone),
346346 );
347347 // Transport failures and upstream 5xx are transient while the device code
apps/server/src/cloud/ManagedEndpointRuntime.test.ts+1-1
......@@ -40,7 +40,7 @@ const runtimeDependencies = (
4040 Layer.succeed(ChildProcessSpawner.ChildProcessSpawner, spawner),
4141 relayClientLayer,
4242 Layer.mock(ServerSecretStore.ServerSecretStore)({
43 get: () => Effect.succeed(Option.none()),
43 get: () => Effect.succeedNone,
4444 }),
4545 );
4646
apps/server/src/cloud/http.test.ts+2-2
......@@ -252,7 +252,7 @@ describe("reconcileDesiredCloudLink", () => {
252252 CliTokenManager.CloudCliTokenManager,
253253 CliTokenManager.CloudCliTokenManager.of({
254254 get: unusedSecretStoreOperation(),
255 getExisting: Effect.succeed(Option.none()),
255 getExisting: Effect.succeedNone,
256256 hasCredential: unusedSecretStoreOperation(),
257257 store: () => unusedSecretStoreOperation(),
258258 clear: unusedSecretStoreOperation(),
......@@ -411,7 +411,7 @@ describe("releaseManagedTunnelOnShutdown", () => {
411411 CliTokenManager.CloudCliTokenManager,
412412 CliTokenManager.CloudCliTokenManager.of({
413413 get: unusedSecretStoreOperation(),
414 getExisting: Effect.succeed(Option.some(cliToken)),
414 getExisting: Effect.succeedSome(cliToken),
415415 hasCredential: unusedSecretStoreOperation(),
416416 store: () => unusedSecretStoreOperation(),
417417 clear: unusedSecretStoreOperation(),
apps/server/src/cloud/http.ts+3-3
......@@ -152,8 +152,9 @@ export function consumeCloudReplayGuards(input: {
152152 readonly names: ReadonlyArray<string>;
153153 readonly value: Uint8Array;
154154}) {
155 return Effect.all(
156 input.names.map((name) =>
155 return Effect.forEach(
156 input.names,
157 (name) =>
157158 input.secrets.create(name, input.value).pipe(
158159 Effect.as(true),
159160 Effect.catchIf(ServerSecretStore.isSecretStoreError, (error) =>
......@@ -162,7 +163,6 @@ export function consumeCloudReplayGuards(input: {
162163 : Effect.fail(error),
163164 ),
164165 ),
165 ),
166166 { concurrency: input.names.length },
167167 ).pipe(Effect.map((created) => created.every(Boolean)));
168168}
apps/server/src/cloud/managedTunnelStartup.ts+8-7
......@@ -49,19 +49,20 @@ export const retryManagedTunnelRegistration = <A, E, R>(
4949 ),
5050 Schedule.jittered,
5151 );
52 return registration.pipe(
52 const withinWindow = registration.pipe(
5353 Effect.retry({
5454 while: isRetryable,
5555 schedule: schedule.pipe(
5656 Schedule.upTo({ duration: MANAGED_TUNNEL_REGISTRATION_RETRY_WINDOW }),
5757 ),
5858 }),
59 Effect.catch((error) =>
60 onRetryWindowExhausted !== undefined && isRetryable(error)
61 ? onRetryWindowExhausted.pipe(
62 Effect.andThen(registration.pipe(Effect.retry({ while: isRetryable, schedule }))),
63 )
64 : Effect.fail(error),
59 );
60 if (onRetryWindowExhausted === undefined) return withinWindow;
61 return withinWindow.pipe(
62 Effect.catchIf(isRetryable, () =>
63 onRetryWindowExhausted.pipe(
64 Effect.andThen(registration.pipe(Effect.retry({ while: isRetryable, schedule }))),
65 ),
6566 ),
6667 );
6768};
apps/server/src/cloud/selfUpdate.test.ts+1-1
......@@ -105,7 +105,7 @@ const makeHarness = Effect.fn("test.make_self_update_harness")(function* (
105105 order.push("accept");
106106 return "launcher-id";
107107 })),
108 prepareTrial: Effect.sync((): undefined => undefined),
108 prepareTrial: Effect.undefined,
109109 });
110110 const config = yield* ServerConfig.ServerConfig.pipe(
111111 Effect.provide(ServerConfig.layerTest(process.cwd(), baseDir)),
apps/server/src/desktopUpdate/DesktopAppUpdate.ts+1-1
......@@ -106,7 +106,7 @@ export const make = Effect.fn("desktopUpdate.desktopAppUpdate.make")(function* (
106106 ? emitStage(desktopUpdateProgressStage(report.state)).pipe(
107107 Effect.as(Option.none<DesktopUpdateStatusReport>()),
108108 )
109 : Effect.succeed(Option.some(report)),
109 : Effect.succeedSome(report),
110110 ),
111111 Stream.filterMap(
112112 Option.match({
apps/server/src/device/DeviceHubProxy.ts+1-1
......@@ -142,7 +142,7 @@ const proxyWebSocket = Effect.fn("DeviceHubProxy.proxyWebSocket")(function* (
142142 pumpFrames(client, writeToUpstream),
143143 );
144144 }),
145 ).pipe(Effect.catchCause(() => Effect.void));
145 ).pipe(Effect.ignoreCause);
146146 return HttpServerResponse.empty();
147147});
148148
apps/server/src/device/DeviceService.ts+5-7
......@@ -906,13 +906,11 @@ export const makeWithHosts = Effect.fn("DeviceService.makeWithHosts")(function*
906906 lifecycleLock.withPermit(
907907 Effect.gen(function* () {
908908 if (!installTool)
909 return yield* Effect.fail(
910 new DeviceOperationError({
911 operation: "update device tool",
912 reason: "request_failed",
913 cause: new Error("Tool installation is unavailable in this device service."),
914 }),
915 );
909 return yield* new DeviceOperationError({
910 operation: "update device tool",
911 reason: "request_failed",
912 cause: new Error("Tool installation is unavailable in this device service."),
913 });
916914 yield* installTool(tool);
917915 return yield* inspect;
918916 }),
apps/server/src/device/LocalDeviceHost.ts+2-2
......@@ -326,7 +326,7 @@ export const make = Effect.fn("LocalDeviceHost.make")(function* () {
326326 }
327327 }
328328 yield* fs.remove(hubStatePath(), { force: true }).pipe(Effect.ignore);
329 }).pipe(Effect.catchCause(() => Effect.void));
329 }).pipe(Effect.ignoreCause);
330330
331331 const recordHub = (hub: HubProcess, hubTool: DeviceToolPaths) =>
332332 encodeHubStateFile({
......@@ -422,7 +422,7 @@ export const make = Effect.fn("LocalDeviceHost.make")(function* () {
422422 Stream.runForEach((line) =>
423423 Effect.logDebug("Device hub output", { pid: Number(hub.child.pid), output: line }),
424424 ),
425 Effect.catchCause(() => Effect.void),
425 Effect.ignoreCause,
426426 );
427427
428428 /**
apps/server/src/device/deviceToolMaintenance.ts+6-3
......@@ -128,9 +128,12 @@ const runMaintenance = Effect.fn("DeviceToolchain.maintenance")(function* (
128128 ],
129129 });
130130 if (result.code !== 0)
131 return yield* Effect.fail(
132 new DeviceToolMaintenanceError({ operation, tool, exitCode: result.code, cause: result }),
133 );
131 return yield* new DeviceToolMaintenanceError({
132 operation,
133 tool,
134 exitCode: result.code,
135 cause: result,
136 });
134137});
135138
136139export const pruneLocalDeviceTools = Effect.fn("DeviceToolchain.prune")(function* (
apps/server/src/diagnostics/TraceDiagnostics.ts+3-3
......@@ -420,8 +420,9 @@ export const make = Effect.gen(function* () {
420420 const readAt = options.readAt ?? (yield* DateTime.now);
421421 const slowSpanThresholdMs = options.slowSpanThresholdMs ?? DEFAULT_SLOW_SPAN_THRESHOLD_MS;
422422 const paths = toRotatedTracePaths(options.traceFilePath, options.maxFiles);
423 const results = yield* Effect.all(
424 paths.map((path) =>
423 const results = yield* Effect.forEach(
424 paths,
425 (path) =>
425426 readTraceFile(fileSystem, path).pipe(
426427 Effect.tapError((cause) =>
427428 Effect.logWarning("Failed to read local trace file.").pipe(
......@@ -434,7 +435,6 @@ export const make = Effect.gen(function* () {
434435 ),
435436 Effect.result,
436437 ),
437 ),
438438 {
439439 concurrency: 1,
440440 },
apps/server/src/environment/ServerEnvironment.test.ts+1-2
......@@ -6,7 +6,6 @@ import * as Deferred from "effect/Deferred";
66import * as Effect from "effect/Effect";
77import * as FileSystem from "effect/FileSystem";
88import * as Layer from "effect/Layer";
9import * as Option from "effect/Option";
109import * as PlatformError from "effect/PlatformError";
1110import * as Schema from "effect/Schema";
1211
......@@ -35,7 +34,7 @@ const makeServerEnvironmentLayer = (baseDir: string) =>
3534const emptySecretStoreLayer = Layer.succeed(
3635 ServerSecretStore.ServerSecretStore,
3736 ServerSecretStore.ServerSecretStore.of({
38 get: () => Effect.succeed(Option.none()),
37 get: () => Effect.succeedNone,
3938 set: () => Effect.void,
4039 create: () => Effect.void,
4140 getOrCreateRandom: () => Effect.succeed(new Uint8Array()),
apps/server/src/environment/ServerEnvironment.ts+6-7
......@@ -127,13 +127,12 @@ const makeIdentity = Effect.gen(function* () {
127127 });
128128 yield* fileSystem.writeFileString(tempPath, `${value}\n`);
129129 // Publish the completed file without replacing an ID created by another process.
130 yield* fileSystem
131 .link(tempPath, destinationPath)
132 .pipe(
133 Effect.catch((cause) =>
134 cause.reason._tag === "AlreadyExists" ? Effect.void : Effect.fail(cause),
135 ),
136 );
130 yield* fileSystem.link(tempPath, destinationPath).pipe(
131 Effect.catchIf(
132 (cause) => cause.reason._tag === "AlreadyExists",
133 () => Effect.void,
134 ),
135 );
137136 if (mode === "recover") {
138137 // Keep the recovery ID so delayed initializers also publish the same winner.
139138 yield* fileSystem.remove(tempPath);
apps/server/src/environment/ServerEnvironmentLabel.ts+1-1
......@@ -128,7 +128,7 @@ const runFriendlyLabelCommand = Effect.fn("runFriendlyLabelCommand")(function* (
128128 cause,
129129 }),
130130 ),
131 Effect.map(Option.some),
131 Effect.asSome,
132132 Effect.catchTags({
133133 ServerEnvironmentLabelCommandError: (error) =>
134134 Effect.logDebug(error.message).pipe(
apps/server/src/environment/ServerEnvironmentMachine.ts+2-2
......@@ -107,7 +107,7 @@ const readOptionalFile = Effect.fn("readOptionalFile")(function* (path: string)
107107 const fileSystem = yield* FileSystem.FileSystem;
108108 return yield* fileSystem.readFileString(path).pipe(
109109 Effect.map(normalize),
110 Effect.catch(() => Effect.succeed(null)),
110 Effect.orElseSucceed(() => null),
111111 );
112112});
113113
......@@ -125,7 +125,7 @@ const runProbe = Effect.fn("runMachineProbe")(function* (input: {
125125 })
126126 .pipe(
127127 Effect.map((result) => (result.code === 0 ? normalize(result.stdout) : null)),
128 Effect.catch(() => Effect.succeed(null)),
128 Effect.orElseSucceed(() => null),
129129 );
130130});
131131
apps/server/src/git/GitManager.ts+1-1
......@@ -2097,7 +2097,7 @@ export const make = Effect.gen(function* () {
20972097 title: generated.title,
20982098 bodyFile,
20992099 })
2100 .pipe(Effect.ensuring(fileSystem.remove(bodyFile).pipe(Effect.catch(() => Effect.void))));
2100 .pipe(Effect.ensuring(fileSystem.remove(bodyFile).pipe(Effect.ignore)));
21012101
21022102 const created = yield* findOpenPr(cwd, headContext);
21032103 if (!created) {
apps/server/src/git/linkCreatedPullRequest.test.ts+1-1
......@@ -83,7 +83,7 @@ const makeDependencies = (
8383 Layer.mergeAll(
8484 Layer.mock(ProjectionSnapshotQuery)({
8585 getThreadShellById: () => Effect.succeed(Option.fromNullishOr(threadShell)),
86 getProjectShellById: () => Effect.succeed(Option.some(project)),
86 getProjectShellById: () => Effect.succeedSome(project),
8787 }),
8888 Layer.mock(OrchestrationEngineService)({
8989 readEvents: () => Stream.empty,
apps/server/src/keybindings.test.ts+3-3
......@@ -567,13 +567,13 @@ it.layer(NodeServices.layer)("keybindings", (it) => {
567567 );
568568 yield* Effect.gen(function* () {
569569 const keybindings = yield* Keybindings.Keybindings;
570 yield* Effect.all(
571 commands.map((command, index) =>
570 yield* Effect.forEach(
571 commands,
572 (command, index) =>
572573 keybindings.upsertKeybindingRule({
573574 key: `mod+${String.fromCharCode(97 + index)}`,
574575 command,
575576 }),
576 ),
577577 { concurrency: "unbounded", discard: true },
578578 );
579579 });
apps/server/src/mcp/McpHttpServer.test.ts+1-2
......@@ -6,7 +6,6 @@ import * as Deferred from "effect/Deferred";
66import * as Effect from "effect/Effect";
77import * as FileSystem from "effect/FileSystem";
88import * as Layer from "effect/Layer";
9import * as Option from "effect/Option";
109import * as Path from "effect/Path";
1110import * as Schema from "effect/Schema";
1211import * as Stream from "effect/Stream";
......@@ -56,7 +55,7 @@ const PullRequestsTestLayer = McpHttpServer.PullRequestsToolkitRegistrationLive.
5655 Layer.provide(
5756 Layer.mergeAll(
5857 Layer.mock(ProjectionSnapshotQuery)({
59 getThreadShellById: () => Effect.succeed(Option.none()),
58 getThreadShellById: () => Effect.succeedNone,
6059 }),
6160 Layer.mock(OrchestrationEngineService)({}),
6261 NodeServices.layer,
apps/server/src/mcp/McpInvocationContext.ts+8-6
......@@ -47,9 +47,11 @@ const missingCapability = (
4747export const requireMcpCapability = <const C extends McpCapability>(
4848 capability: C,
4949): Effect.Effect<McpInvocationScope, McpCapabilityError<C>, McpInvocationContext> =>
50 Effect.flatMap(McpInvocationContext, (invocation) =>
51 invocation.capabilities.has(capability)
52 ? Effect.succeed(invocation)
53 : // The conditional type narrows what the literal argument decided at runtime.
54 Effect.fail(missingCapability(invocation, capability) as McpCapabilityError<C>),
55 ).pipe(Effect.withSpan("mcp.requireCapability"));
50 McpInvocationContext.pipe(
51 Effect.filterOrFail(
52 (invocation) => invocation.capabilities.has(capability),
53 // The conditional type narrows what the literal argument decided at runtime.
54 (invocation) => missingCapability(invocation, capability) as McpCapabilityError<C>,
55 ),
56 Effect.withSpan("mcp.requireCapability"),
57 );
apps/server/src/mcp/McpSessionRegistry.ts+1-1
......@@ -230,7 +230,7 @@ export const issueActiveMcpCredential = (
230230 ? activeMcpSessionRegistry
231231 .revokeThread(request.threadId)
232232 .pipe(Effect.andThen(activeMcpSessionRegistry.issue(request)))
233 : Effect.sync((): McpIssuedCredential | undefined => undefined);
233 : Effect.undefined;
234234
235235/**
236236 * Refreshes the liveness of a thread's MCP credential. Called on every provider
apps/server/src/mcp/toolkits/preview/handlers.ts+6-5
......@@ -87,7 +87,7 @@ const invoke = Effect.fn("PreviewToolkit.invoke")(function* <A>(
8787 updateCurrentTab: false,
8888 ...(statusTabId === undefined ? {} : { tabId: statusTabId }),
8989 })
90 .pipe(Effect.catch(() => Effect.succeed(null)));
90 .pipe(Effect.orElseSucceed(() => null));
9191 return {
9292 result,
9393 ...(page?.url && /^https?:\/\//i.test(page.url) && page.url.length <= 4096
......@@ -175,10 +175,11 @@ export const claimPreviewRecording = Effect.fn("PreviewToolkit.claimRecording")(
175175 yield* fileSystem.rename(currentPath, finalPath);
176176 }).pipe(
177177 // Another stop may already have claimed this exact upload for this thread.
178 Effect.catch((cause) =>
179 cause._tag !== "PreviewAutomationRecordingTransferError" && cause.reason._tag === "NotFound"
180 ? validateFile(finalPath)
181 : Effect.fail(cause),
178 Effect.catchIf(
179 (cause) =>
180 cause._tag !== "PreviewAutomationRecordingTransferError" &&
181 cause.reason._tag === "NotFound",
182 () => validateFile(finalPath),
182183 ),
183184 Effect.mapError((cause) => new PreviewAutomationRecordingTransferError({ threadId, cause })),
184185 );
apps/server/src/orchestration/Layers/CheckpointReactor.ts+31-37
......@@ -97,12 +97,12 @@ const make = Effect.gen(function* () {
9797 const entryRefreshWorker = yield* makeDrainableWorker((cwd: string) =>
9898 Effect.sync(() => queuedEntryRefreshes.delete(cwd)).pipe(
9999 Effect.andThen(workspaceEntries.refresh(cwd)),
100 Effect.catchCause((cause) =>
101 Cause.hasInterruptsOnly(cause)
102 ? Effect.failCause(cause)
103 : Effect.logWarning("failed to refresh checkpoint workspace entries", {
104 cwd,
105 }),
100 Effect.catchCauseIf(
101 (cause) => !Cause.hasInterruptsOnly(cause),
102 () =>
103 Effect.logWarning("failed to refresh checkpoint workspace entries", {
104 cwd,
105 }),
106106 ),
107107 ),
108108 );
......@@ -625,15 +625,14 @@ const make = Effect.gen(function* () {
625625 branch: checkedOutBranch,
626626 });
627627 }).pipe(
628 Effect.catchCause((cause) => {
629 if (Cause.hasInterruptsOnly(cause)) {
630 return Effect.failCause(cause);
631 }
632 return Effect.logWarning("failed to follow worktree branch drift", {
633 threadId: input.threadId,
634 cause: Cause.pretty(cause),
635 });
636 }),
628 Effect.catchCauseIf(
629 (cause) => !Cause.hasInterruptsOnly(cause),
630 (cause) =>
631 Effect.logWarning("failed to follow worktree branch drift", {
632 threadId: input.threadId,
633 cause: Cause.pretty(cause),
634 }),
635 ),
637636 );
638637 });
639638
......@@ -643,12 +642,12 @@ const make = Effect.gen(function* () {
643642 const statusRefreshWorker = yield* makeDrainableWorker(
644643 (event: Extract<ProviderRuntimeEvent, { type: "turn.completed" }>) =>
645644 refreshLocalGitStatusFromTurnCompletion(event).pipe(
646 Effect.catchCause((cause) =>
647 Cause.hasInterruptsOnly(cause)
648 ? Effect.failCause(cause)
649 : Effect.logWarning("failed to refresh git status after turn completion", {
650 threadId: event.threadId,
651 }),
645 Effect.catchCauseIf(
646 (cause) => !Cause.hasInterruptsOnly(cause),
647 () =>
648 Effect.logWarning("failed to refresh git status after turn completion", {
649 threadId: event.threadId,
650 }),
652651 ),
653652 ),
654653 );
......@@ -749,11 +748,7 @@ const make = Effect.gen(function* () {
749748 for (const candidate of paths) {
750749 const otherCwd = yield* fileSystem
751750 .realPath(candidate)
752 .pipe(
753 Effect.catch((error) =>
754 error.reason._tag === "NotFound" ? Effect.succeed(null) : Effect.fail(error),
755 ),
756 );
751 .pipe(Effect.catchReason("PlatformError", "NotFound", () => Effect.succeed(null)));
757752 if (otherCwd === null) continue;
758753 const isWithin = (parent: string, child: string) => {
759754 const relative = path.relative(parent, child);
......@@ -791,7 +786,7 @@ const make = Effect.gen(function* () {
791786 preferSessionRuntime: true,
792787 }).pipe(
793788 Effect.catch((error) =>
794 event.payload.restoreFiles === false ? Effect.succeed(undefined) : Effect.fail(error),
789 event.payload.restoreFiles === false ? Effect.undefined : Effect.fail(error),
795790 ),
796791 );
797792
......@@ -1014,16 +1009,15 @@ const make = Effect.gen(function* () {
10141009
10151010 const processInputSafely = (input: ReactorInput) =>
10161011 processInput(input).pipe(
1017 Effect.catchCause((cause) => {
1018 if (Cause.hasInterruptsOnly(cause)) {
1019 return Effect.failCause(cause);
1020 }
1021 return Effect.logWarning("checkpoint reactor failed to process input", {
1022 source: input.source,
1023 eventType: input.event.type,
1024 cause: Cause.pretty(cause),
1025 });
1026 }),
1012 Effect.catchCauseIf(
1013 (cause) => !Cause.hasInterruptsOnly(cause),
1014 (cause) =>
1015 Effect.logWarning("checkpoint reactor failed to process input", {
1016 source: input.source,
1017 eventType: input.event.type,
1018 cause: Cause.pretty(cause),
1019 }),
1020 ),
10271021 );
10281022
10291023 const worker = yield* makeDrainableWorker(processInputSafely);
apps/server/src/orchestration/Layers/OrchestrationEngine.test.ts+8-8
......@@ -446,18 +446,18 @@ describe("OrchestrationEngine", () => {
446446 Effect.succeed({ snapshotSequence: projectionSnapshot.snapshotSequence }),
447447 getCounts: () => Effect.succeed({ projectCount: 1, threadCount: 1 }),
448448 getEventReplayStats: () => Effect.die("unused"),
449 getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()),
450 getProjectShellById: () => Effect.succeed(Option.none()),
449 getActiveProjectByWorkspaceRoot: () => Effect.succeedNone,
450 getProjectShellById: () => Effect.succeedNone,
451451 getProjectShells: () => Effect.succeed([]),
452 getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()),
452 getFirstActiveThreadIdByProjectId: () => Effect.succeedNone,
453453 getImportedAgentSessionSources: () => Effect.die("unused"),
454 getThreadCheckpointContext: () => Effect.succeed(Option.none()),
455 getFullThreadDiffContext: () => Effect.succeed(Option.none()),
454 getThreadCheckpointContext: () => Effect.succeedNone,
455 getFullThreadDiffContext: () => Effect.succeedNone,
456456 getThreadRuntimeContext: () => Effect.die("unused"),
457457 getTurnStartMessage: () => Effect.die("unused"),
458 getThreadShellById: () => Effect.succeed(Option.none()),
459 getThreadDetailById: () => Effect.succeed(Option.none()),
460 getThreadDetailSnapshot: () => Effect.succeed(Option.none()),
458 getThreadShellById: () => Effect.succeedNone,
459 getThreadDetailById: () => Effect.succeedNone,
460 getThreadDetailSnapshot: () => Effect.succeedNone,
461461 searchThreads: () => Effect.succeed({ matches: [] }),
462462 }),
463463 ),
apps/server/src/orchestration/Layers/OrchestrationEngine.ts+1-1
......@@ -400,7 +400,7 @@ const makeOrchestrationEngine = Effect.gen(function* () {
400400 status: "rejected",
401401 error: error.message,
402402 })
403 .pipe(Effect.catch(() => Effect.void));
403 .pipe(Effect.ignore);
404404 }
405405 }
406406
apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+29-38
......@@ -511,14 +511,14 @@ const make = Effect.gen(function* () {
511511 Effect.andThen(
512512 gitWorkflow.createWorktree({ cwd, refName: branch, path: worktreePath }, { submodules }),
513513 ),
514 Effect.catchCause((cause) =>
515 Cause.hasInterruptsOnly(cause)
516 ? Effect.failCause(cause)
517 : Effect.logWarning("provider command reactor failed to recreate worktree", {
518 threadId: thread.id,
519 worktreePath,
520 cause: Cause.pretty(cause),
521 }),
514 Effect.catchCauseIf(
515 (cause) => !Cause.hasInterruptsOnly(cause),
516 (cause) =>
517 Effect.logWarning("provider command reactor failed to recreate worktree", {
518 threadId: thread.id,
519 worktreePath,
520 cause: Cause.pretty(cause),
521 }),
522522 ),
523523 );
524524 });
......@@ -1154,15 +1154,14 @@ const make = Effect.gen(function* () {
11541154 return;
11551155 }
11561156 const result = yield* regenerateThreadTitle(event, requestId).pipe(
1157 Effect.catchCause((cause) => {
1158 if (Cause.hasInterruptsOnly(cause)) {
1159 return Effect.failCause(cause);
1160 }
1161 return Effect.logWarning("provider command reactor failed to regenerate thread title", {
1162 threadId: event.payload.threadId,
1163 cause: Cause.pretty(cause),
1164 }).pipe(Effect.as({ _tag: "Completed", title: undefined } as const));
1165 }),
1157 Effect.catchCauseIf(
1158 (cause) => !Cause.hasInterruptsOnly(cause),
1159 (cause) =>
1160 Effect.logWarning("provider command reactor failed to regenerate thread title", {
1161 threadId: event.payload.threadId,
1162 cause: Cause.pretty(cause),
1163 }).pipe(Effect.as({ _tag: "Completed", title: undefined } as const)),
1164 ),
11661165 );
11671166 if (result._tag === "Superseded") {
11681167 return;
......@@ -1174,34 +1173,26 @@ const make = Effect.gen(function* () {
11741173 ...(result.title !== undefined ? { title: result.title } : {}),
11751174 };
11761175 yield* dispatchThreadTitleRegenerationCompletion(completion).pipe(
1177 Effect.catchCause((cause) => {
1178 if (Cause.hasInterruptsOnly(cause)) {
1179 return Effect.failCause(cause);
1180 }
1181 return Effect.logWarning(
1182 "provider command reactor retrying title regeneration completion",
1183 {
1176 Effect.catchCauseIf(
1177 (cause) => !Cause.hasInterruptsOnly(cause),
1178 (cause) =>
1179 Effect.logWarning("provider command reactor retrying title regeneration completion", {
11841180 threadId: event.payload.threadId,
11851181 cause: Cause.pretty(cause),
1186 },
1187 ).pipe(Effect.andThen(dispatchThreadTitleRegenerationCompletion(completion)));
1188 }),
1182 }).pipe(Effect.andThen(dispatchThreadTitleRegenerationCompletion(completion))),
1183 ),
11891184 );
11901185 },
11911186 (effect, event) =>
11921187 effect.pipe(
1193 Effect.catchCause((cause) => {
1194 if (Cause.hasInterruptsOnly(cause)) {
1195 return Effect.failCause(cause);
1196 }
1197 return Effect.logWarning(
1198 "provider command reactor failed to complete title regeneration",
1199 {
1188 Effect.catchCauseIf(
1189 (cause) => !Cause.hasInterruptsOnly(cause),
1190 (cause) =>
1191 Effect.logWarning("provider command reactor failed to complete title regeneration", {
12001192 threadId: event.payload.threadId,
12011193 cause: Cause.pretty(cause),
1202 },
1203 );
1204 }),
1194 }),
1195 ),
12051196 ),
12061197 );
12071198 const threadTitleRegenerationWorker = yield* makeDrainableWorker(
......@@ -1496,7 +1487,7 @@ const make = Effect.gen(function* () {
14961487 interactionMode: event.payload.interactionMode,
14971488 createdAt: event.payload.createdAt,
14981489 }).pipe(
1499 Effect.map(Option.some),
1490 Effect.asSome,
15001491 Effect.catchCause((cause) => handleTurnStartFailure(cause).pipe(Effect.as(Option.none()))),
15011492 );
15021493
apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts+10-11
......@@ -2671,17 +2671,16 @@ const make = Effect.gen(function* () {
26712671 (source: string, event: { readonly eventId: string; readonly type: string }) =>
26722672 <E, R>(effect: Effect.Effect<void, E, R>) =>
26732673 effect.pipe(
2674 Effect.catchCause((cause) => {
2675 if (Cause.hasInterruptsOnly(cause)) {
2676 return Effect.failCause(cause);
2677 }
2678 return Effect.logWarning("provider runtime ingestion failed to process event", {
2679 source,
2680 eventId: event.eventId,
2681 eventType: event.type,
2682 cause: Cause.pretty(cause),
2683 });
2684 }),
2674 Effect.catchCauseIf(
2675 (cause) => !Cause.hasInterruptsOnly(cause),
2676 (cause) =>
2677 Effect.logWarning("provider runtime ingestion failed to process event", {
2678 source,
2679 eventId: event.eventId,
2680 eventType: event.type,
2681 cause: Cause.pretty(cause),
2682 }),
2683 ),
26852684 );
26862685
26872686 const worker = yield* makeDrainableWorker((input: RuntimeIngestionInput) =>
apps/server/src/orchestration/Layers/ThreadDeletionReactor.ts+17-19
......@@ -27,15 +27,14 @@ export const logCleanupCauseUnlessInterrupted = <R, E>({
2727 readonly threadId: ThreadDeletedEvent["payload"]["threadId"];
2828}): Effect.Effect<void, E, R> =>
2929 effect.pipe(
30 Effect.catchCause((cause) => {
31 if (Cause.hasInterruptsOnly(cause)) {
32 return Effect.failCause(cause);
33 }
34 return Effect.logDebug(message, {
35 threadId,
36 cause: Cause.pretty(cause),
37 });
38 }),
30 Effect.catchCauseIf(
31 (cause) => !Cause.hasInterruptsOnly(cause),
32 (cause) =>
33 Effect.logDebug(message, {
34 threadId,
35 cause: Cause.pretty(cause),
36 }),
37 ),
3938 );
4039
4140const make = Effect.gen(function* () {
......@@ -67,16 +66,15 @@ const make = Effect.gen(function* () {
6766
6867 const processThreadDeletedSafely = (event: ThreadDeletedEvent) =>
6968 processThreadDeleted(event).pipe(
70 Effect.catchCause((cause) => {
71 if (Cause.hasInterruptsOnly(cause)) {
72 return Effect.failCause(cause);
73 }
74 return Effect.logWarning("thread deletion reactor failed to process event", {
75 eventType: event.type,
76 threadId: event.payload.threadId,
77 cause: Cause.pretty(cause),
78 });
79 }),
69 Effect.catchCauseIf(
70 (cause) => !Cause.hasInterruptsOnly(cause),
71 (cause) =>
72 Effect.logWarning("thread deletion reactor failed to process event", {
73 eventType: event.type,
74 threadId: event.payload.threadId,
75 cause: Cause.pretty(cause),
76 }),
77 ),
8078 );
8179
8280 const worker = yield* makeDrainableWorker(processThreadDeletedSafely);
apps/server/src/orchestration/PullRequestSyncReactor.ts+6-6
......@@ -259,12 +259,12 @@ export const make = Effect.gen(function* () {
259259 Effect.map((stack) => ({
260260 stack: stack === null ? null : ({ kind: "native", ...stack } as const),
261261 })),
262 Effect.catchCause((cause) =>
263 Cause.hasInterruptsOnly(cause)
264 ? Effect.failCause(cause)
265 : Effect.logWarning("pull request stack lookup failed", {
266 key,
267 }).pipe(Effect.as(null)),
262 Effect.catchCauseIf(
263 (cause) => !Cause.hasInterruptsOnly(cause),
264 () =>
265 Effect.logWarning("pull request stack lookup failed", {
266 key,
267 }).pipe(Effect.as(null)),
268268 ),
269269 )
270270 : null;
apps/server/src/orchestration/ThreadPullRequestReactor.ts+30-30
......@@ -207,16 +207,16 @@ export const make = Effect.gen(function* () {
207207 }
208208 return { thread, branchPullRequest, replacement };
209209 }).pipe(
210 Effect.catchCause((cause) =>
211 Cause.hasInterruptsOnly(cause)
212 ? Effect.failCause(cause)
213 : Effect.logWarning("thread pull request discovery failed", {
214 threadId: thread.id,
215 cause: Cause.pretty(cause),
216 }).pipe(
217 Effect.tap(() => Effect.sync(() => failBackfill([thread]))),
218 Effect.as(null),
219 ),
210 Effect.catchCauseIf(
211 (cause) => !Cause.hasInterruptsOnly(cause),
212 (cause) =>
213 Effect.logWarning("thread pull request discovery failed", {
214 threadId: thread.id,
215 cause: Cause.pretty(cause),
216 }).pipe(
217 Effect.tap(() => Effect.sync(() => failBackfill([thread]))),
218 Effect.as(null),
219 ),
220220 ),
221221 ),
222222 );
......@@ -273,25 +273,25 @@ export const make = Effect.gen(function* () {
273273 OrchestrationCommandInvariantError: () =>
274274 Effect.sync(() => finishBackfill([thread])),
275275 }),
276 Effect.catchCause((cause) =>
277 Cause.hasInterruptsOnly(cause)
278 ? Effect.failCause(cause)
279 : Effect.logWarning("thread pull request update failed", {
280 threadId: thread.id,
281 cause: Cause.pretty(cause),
282 }).pipe(Effect.tap(() => Effect.sync(() => failBackfill([thread])))),
276 Effect.catchCauseIf(
277 (cause) => !Cause.hasInterruptsOnly(cause),
278 (cause) =>
279 Effect.logWarning("thread pull request update failed", {
280 threadId: thread.id,
281 cause: Cause.pretty(cause),
282 }).pipe(Effect.tap(() => Effect.sync(() => failBackfill([thread])))),
283283 ),
284284 ),
285285 { discard: true },
286286 );
287287 }).pipe(
288 Effect.catchCause((cause) =>
289 Cause.hasInterruptsOnly(cause)
290 ? Effect.failCause(cause)
291 : Effect.logWarning("thread branch pull request lookup failed", {
292 threadIds: group.map((thread) => thread.id),
293 cause: Cause.pretty(cause),
294 }).pipe(Effect.tap(() => Effect.sync(() => failBackfill(group)))),
288 Effect.catchCauseIf(
289 (cause) => !Cause.hasInterruptsOnly(cause),
290 (cause) =>
291 Effect.logWarning("thread branch pull request lookup failed", {
292 threadIds: group.map((thread) => thread.id),
293 cause: Cause.pretty(cause),
294 }).pipe(Effect.tap(() => Effect.sync(() => failBackfill(group)))),
295295 ),
296296 ),
297297 { concurrency: 8, discard: true },
......@@ -300,12 +300,12 @@ export const make = Effect.gen(function* () {
300300
301301 const worker = yield* makeDrainableWorker((request: RefreshRequest) =>
302302 synchronize(request).pipe(
303 Effect.catchCause((cause) =>
304 Cause.hasInterruptsOnly(cause)
305 ? Effect.failCause(cause)
306 : Effect.logWarning("thread pull request refresh failed", {
307 cause: Cause.pretty(cause),
308 }),
303 Effect.catchCauseIf(
304 (cause) => !Cause.hasInterruptsOnly(cause),
305 (cause) =>
306 Effect.logWarning("thread pull request refresh failed", {
307 cause: Cause.pretty(cause),
308 }),
309309 ),
310310 ),
311311 );
apps/server/src/orchestration/ThreadSettlementReactor.ts+20-20
......@@ -137,13 +137,13 @@ export const make = Effect.gen(function* () {
137137 },
138138 (effect, thread) =>
139139 effect.pipe(
140 Effect.catchCause((cause) =>
141 Cause.hasInterruptsOnly(cause)
142 ? Effect.failCause(cause)
143 : Effect.logWarning("automatic thread settlement skipped", {
144 threadId: thread.id,
145 cause: Cause.pretty(cause),
146 }).pipe(Effect.as(null)),
140 Effect.catchCauseIf(
141 (cause) => !Cause.hasInterruptsOnly(cause),
142 (cause) =>
143 Effect.logWarning("automatic thread settlement skipped", {
144 threadId: thread.id,
145 cause: Cause.pretty(cause),
146 }).pipe(Effect.as(null)),
147147 ),
148148 ),
149149 );
......@@ -305,13 +305,13 @@ export const make = Effect.gen(function* () {
305305 discard: true,
306306 });
307307 }).pipe(
308 Effect.catchCause((cause) =>
309 Cause.hasInterruptsOnly(cause)
310 ? Effect.failCause(cause)
311 : Effect.logWarning("automatic thread settlement skipped", {
312 threadIds: group.map((thread) => thread.id),
313 cause: Cause.pretty(cause),
314 }),
308 Effect.catchCauseIf(
309 (cause) => !Cause.hasInterruptsOnly(cause),
310 (cause) =>
311 Effect.logWarning("automatic thread settlement skipped", {
312 threadIds: group.map((thread) => thread.id),
313 cause: Cause.pretty(cause),
314 }),
315315 ),
316316 ),
317317 { concurrency: 8, discard: true },
......@@ -323,12 +323,12 @@ export const make = Effect.gen(function* () {
323323 threadId?: ThreadId,
324324 ) =>
325325 sweep(mergedPullRequest, threadId).pipe(
326 Effect.catchCause((cause) =>
327 Cause.hasInterruptsOnly(cause)
328 ? Effect.failCause(cause)
329 : Effect.logWarning("automatic thread settlement sweep failed", {
330 cause: Cause.pretty(cause),
331 }),
326 Effect.catchCauseIf(
327 (cause) => !Cause.hasInterruptsOnly(cause),
328 (cause) =>
329 Effect.logWarning("automatic thread settlement sweep failed", {
330 cause: Cause.pretty(cause),
331 }),
332332 ),
333333 );
334334 const worker = yield* makeDrainableWorker((threadId: ThreadId | undefined) =>
apps/server/src/orchestration/commandInvariants.ts+14-18
......@@ -119,15 +119,13 @@ export function requireThreadArchived(input: {
119119 readonly threadId: ThreadId;
120120}): Effect.Effect<OrchestrationThread, OrchestrationCommandInvariantError> {
121121 return requireThread(input).pipe(
122 Effect.flatMap((thread) =>
123 thread.archivedAt !== null
124 ? Effect.succeed(thread)
125 : Effect.fail(
126 invariantError(
127 input.command.type,
128 `Thread '${input.threadId}' is not archived for command '${input.command.type}'.`,
129 ),
130 ),
122 Effect.filterOrFail(
123 (thread) => thread.archivedAt !== null,
124 () =>
125 invariantError(
126 input.command.type,
127 `Thread '${input.threadId}' is not archived for command '${input.command.type}'.`,
128 ),
131129 ),
132130 );
133131}
......@@ -138,15 +136,13 @@ export function requireThreadNotArchived(input: {
138136 readonly threadId: ThreadId;
139137}): Effect.Effect<OrchestrationThread, OrchestrationCommandInvariantError> {
140138 return requireThread(input).pipe(
141 Effect.flatMap((thread) =>
142 thread.archivedAt === null
143 ? Effect.succeed(thread)
144 : Effect.fail(
145 invariantError(
146 input.command.type,
147 `Thread '${input.threadId}' is already archived and cannot handle command '${input.command.type}'.`,
148 ),
149 ),
139 Effect.filterOrFail(
140 (thread) => thread.archivedAt === null,
141 () =>
142 invariantError(
143 input.command.type,
144 `Thread '${input.threadId}' is already archived and cannot handle command '${input.command.type}'.`,
145 ),
150146 ),
151147 );
152148}
apps/server/src/orchestration/decider.pullRequests.test.ts+1-1
......@@ -295,7 +295,7 @@ it.layer(NodeServices.layer)("pull request link decider", (it) => {
295295 for (const planned of events) {
296296 const event = { ...planned, sequence: model.snapshotSequence + 1 };
297297 const encoded = yield* Schema.encodeEffect(OrchestrationEvent)(event);
298 const decoded = yield* Schema.decodeUnknownEffect(OrchestrationEvent)(encoded);
298 const decoded = yield* Schema.decodeEffect(OrchestrationEvent)(encoded);
299299 // Older detail-event unions must never receive the new PR discriminants.
300300 expect(isThreadDetailEvent(decoded)).toBe(false);
301301 model = yield* projectEvent(model, decoded);
apps/server/src/orchestration/decider.ts+28-42
......@@ -488,12 +488,10 @@ export const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand"
488488 command.type === "thread.auto-settle" &&
489489 (thread.settledOverride !== null || thread.autoSettleDisabledAt != null)
490490 ) {
491 return yield* Effect.fail(
492 new OrchestrationCommandInvariantError({
493 commandType: command.type,
494 detail: `thread ${command.threadId} changed before automatic settlement`,
495 }),
496 );
491 return yield* new OrchestrationCommandInvariantError({
492 commandType: command.type,
493 detail: `thread ${command.threadId} changed before automatic settlement`,
494 });
497495 }
498496 // The server owns settle eligibility. A stale command must not settle
499497 // a thread whose session is coming alive or working.
......@@ -645,36 +643,30 @@ export const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand"
645643 // structurally just a string): NaN fails every comparison, and an
646644 // unparseable snoozedUntil must never persist.
647645 if (!(Date.parse(command.snoozedUntil) > Date.parse(occurredAt))) {
648 return yield* Effect.fail(
649 new OrchestrationCommandInvariantError({
650 commandType: command.type,
651 detail: `thread ${command.threadId} snooze wake time ${command.snoozedUntil} is not in the future`,
652 }),
653 );
646 return yield* new OrchestrationCommandInvariantError({
647 commandType: command.type,
648 detail: `thread ${command.threadId} snooze wake time ${command.snoozedUntil} is not in the future`,
649 });
654650 }
655651 // Blocked-on-you work must not be snoozed away: a pending approval or
656652 // user-input request is the agent waiting on the user, and hiding it
657653 // defeats the request. (A running session IS snoozable — snooze only
658654 // affects visibility, never the agent.)
659655 if (openRequests(thread).size > 0) {
660 return yield* Effect.fail(
661 new OrchestrationCommandInvariantError({
662 commandType: command.type,
663 detail: `thread ${command.threadId} has a pending approval or user-input request and cannot be snoozed`,
664 }),
665 );
656 return yield* new OrchestrationCommandInvariantError({
657 commandType: command.type,
658 detail: `thread ${command.threadId} has a pending approval or user-input request and cannot be snoozed`,
659 });
666660 }
667661 // A queued turn start — a user message no turn has adopted yet — is
668662 // invisible pending work: no session, no pending flags. Snoozing in
669663 // that window would hide a just-requested turn exactly the way settle
670664 // would.
671665 if (hasQueuedTurnStartForThread(thread, occurredAt)) {
672 return yield* Effect.fail(
673 new OrchestrationCommandInvariantError({
674 commandType: command.type,
675 detail: `thread ${command.threadId} has a queued turn start and cannot be snoozed`,
676 }),
677 );
666 return yield* new OrchestrationCommandInvariantError({
667 commandType: command.type,
668 detail: `thread ${command.threadId} has a queued turn start and cannot be snoozed`,
669 });
678670 }
679671 // Re-snoozing an already-snoozed thread to the SAME wake time is a
680672 // duplicate (double-click, raced clients): re-emit with the original
......@@ -836,12 +828,10 @@ export const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand"
836828 // (rather than silently pinning) keeps a raced reorder-after-unpin
837829 // from resurrecting a pin the user just cleared.
838830 if (thread.pinnedAt == null) {
839 return yield* Effect.fail(
840 new OrchestrationCommandInvariantError({
841 commandType: command.type,
842 detail: `thread ${command.threadId} is not pinned and cannot be reordered`,
843 }),
844 );
831 return yield* new OrchestrationCommandInvariantError({
832 commandType: command.type,
833 detail: `thread ${command.threadId} is not pinned and cannot be reordered`,
834 });
845835 }
846836 // Idempotent by re-emission (see thread.settle): a duplicate drop on
847837 // the same slot keeps the existing updatedAt so it projects as a no-op.
......@@ -953,12 +943,10 @@ export const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand"
953943 if (command.linkedPullRequest != null) {
954944 const { linkedPullRequest: linked, ...metadata } = command;
955945 const project = readModel.projects.find((project) => project.id === thread.projectId);
956 let host = project?.repositoryIdentity?.canonicalKey.split("/")[0] ?? "unknown";
957 try {
958 host = new URL(linked.url).hostname;
959 } catch {
960 // Historical clients can send links without a parseable URL.
961 }
946 // Historical clients can send links without a parseable URL.
947 const host = URL.canParse(linked.url)
948 ? new URL(linked.url).hostname
949 : (project?.repositoryIdentity?.canonicalKey.split("/")[0] ?? "unknown");
962950 const hasMetadata = Object.entries(metadata).some(
963951 ([key, value]) => !["type", "commandId", "threadId"].includes(key) && value !== undefined,
964952 );
......@@ -1872,12 +1860,10 @@ export const decideOrchestrationCommand = Effect.fn("decideOrchestrationCommand"
18721860 sessionComingAlive ||
18731861 hasQueuedTurnStartForThread(thread, command.createdAt)
18741862 ) {
1875 return yield* Effect.fail(
1876 new OrchestrationCommandInvariantError({
1877 commandType: command.type,
1878 detail: `thread ${command.threadId} was re-engaged after settle; skipping session stop`,
1879 }),
1880 );
1863 return yield* new OrchestrationCommandInvariantError({
1864 commandType: command.type,
1865 detail: `thread ${command.threadId} was re-engaged after settle; skipping session stop`,
1866 });
18811867 }
18821868 }
18831869 return {
apps/server/src/orchestration/workflowScriptQuery.ts+12-9
......@@ -32,9 +32,10 @@ export const readWorkflowScript = Effect.fn("orchestration.readWorkflowScript")(
3232 const requested = input.scriptPath;
3333
3434 if (!NodePath.isAbsolute(requested) || NodePath.extname(requested) !== ".js") {
35 return yield* Effect.fail(
36 new OrchestrationGetWorkflowScriptError({ reason: "invalid-path", scriptPath: requested }),
37 );
35 return yield* new OrchestrationGetWorkflowScriptError({
36 reason: "invalid-path",
37 scriptPath: requested,
38 });
3839 }
3940
4041 const root = yield* Effect.tryPromise({
......@@ -60,14 +61,16 @@ export const readWorkflowScript = Effect.fn("orchestration.readWorkflowScript")(
6061 });
6162
6263 if (resolved !== root && !resolved.startsWith(`${root}${NodePath.sep}`)) {
63 return yield* Effect.fail(
64 new OrchestrationGetWorkflowScriptError({ reason: "outside-root", scriptPath: resolved }),
65 );
64 return yield* new OrchestrationGetWorkflowScriptError({
65 reason: "outside-root",
66 scriptPath: resolved,
67 });
6668 }
6769 if (NodePath.extname(resolved) !== ".js") {
68 return yield* Effect.fail(
69 new OrchestrationGetWorkflowScriptError({ reason: "not-js", scriptPath: resolved }),
70 );
70 return yield* new OrchestrationGetWorkflowScriptError({
71 reason: "not-js",
72 scriptPath: resolved,
73 });
7174 }
7275
7376 // TOCTOU-safe read (review finding): open FIRST, then verify what was
apps/server/src/persistence/AuthPairingLinks.ts+4-4
......@@ -268,7 +268,7 @@ export const make = Effect.gen(function* () {
268268 ),
269269 Effect.flatMap((rowOption) =>
270270 Option.match(rowOption, {
271 onNone: () => Effect.succeed(Option.none()),
271 onNone: () => Effect.succeedNone,
272272 onSome: (row) =>
273273 decodeAuthPairingLinkDbRow(row).pipe(
274274 Effect.mapError((cause) =>
......@@ -278,7 +278,7 @@ export const make = Effect.gen(function* () {
278278 { pairingLinkId: row.id },
279279 ),
280280 ),
281 Effect.map(Option.some),
281 Effect.asSome,
282282 ),
283283 }),
284284 ),
......@@ -329,7 +329,7 @@ export const make = Effect.gen(function* () {
329329 ),
330330 Effect.flatMap((rowOption) =>
331331 Option.match(rowOption, {
332 onNone: () => Effect.succeed(Option.none()),
332 onNone: () => Effect.succeedNone,
333333 onSome: (row) =>
334334 decodeAuthPairingLinkDbRow(row).pipe(
335335 Effect.mapError((cause) =>
......@@ -339,7 +339,7 @@ export const make = Effect.gen(function* () {
339339 { pairingLinkId: row.id },
340340 ),
341341 ),
342 Effect.map(Option.some),
342 Effect.asSome,
343343 ),
344344 }),
345345 ),
apps/server/src/persistence/AuthSessions.ts+1-1
......@@ -422,7 +422,7 @@ export const make = Effect.gen(function* () {
422422 ),
423423 Effect.flatMap((rowOption) =>
424424 Option.match(rowOption, {
425 onNone: () => Effect.succeed(Option.none()),
425 onNone: () => Effect.succeedNone,
426426 onSome: (row) =>
427427 decodeAuthSessionDbRow(row).pipe(
428428 Effect.mapError((cause) =>
apps/server/src/persistence/Layers/ProjectionTurns.ts+2-3
......@@ -317,9 +317,8 @@ const makeProjectionTurnRepository = Effect.gen(function* () {
317317 ),
318318 Effect.flatMap((rowOption) =>
319319 Option.match(rowOption, {
320 onNone: () => Effect.succeed(Option.none()),
321 onSome: (row) =>
322 Effect.succeed(Option.some(row as Schema.Schema.Type<typeof ProjectionTurnById>)),
320 onNone: () => Effect.succeedNone,
321 onSome: (row) => Effect.succeedSome(row as Schema.Schema.Type<typeof ProjectionTurnById>),
323322 }),
324323 ),
325324 );
apps/server/src/persistence/ProviderSessionRuntime.ts+3-3
......@@ -398,7 +398,7 @@ export const make = Effect.gen(function* () {
398398 ),
399399 Effect.flatMap((runtimeRowOption) =>
400400 Option.match(runtimeRowOption, {
401 onNone: () => Effect.succeed(Option.none()),
401 onNone: () => Effect.succeedNone,
402402 onSome: (row) =>
403403 decodeRuntimeRow(row).pipe(
404404 Effect.mapError((cause) =>
......@@ -408,7 +408,7 @@ export const make = Effect.gen(function* () {
408408 { threadId: input.threadId },
409409 ),
410410 ),
411 Effect.map((runtime) => Option.some(runtime)),
411 Effect.asSome,
412412 ),
413413 }),
414414 ),
......@@ -428,7 +428,7 @@ export const make = Effect.gen(function* () {
428428 // every consumer that enumerates sessions, such as the reaper.
429429 Effect.forEach(rows, (row) =>
430430 decodeRuntimeRow(row).pipe(
431 Effect.map(Option.some),
431 Effect.asSome,
432432 Effect.catch((cause) =>
433433 Effect.logWarning("provider.session.runtime.row-skipped", {
434434 threadId: row.threadId,
apps/server/src/project/AgentSessionImporter.test.ts+3-3
......@@ -232,7 +232,7 @@ it.layer(NodeServices.layer)("AgentSessionImporter", (it) => {
232232 upsert: (binding) => Effect.sync(() => void bindings.push(binding)),
233233 getProvider: () => Effect.die("unused"),
234234 recordImportedTranscript: () => Effect.void,
235 getBinding: () => Effect.succeed(Option.none()),
235 getBinding: () => Effect.succeedNone,
236236 listThreadIds: () => Effect.die("unused"),
237237 listBindings: () => Effect.die("unused"),
238238 });
......@@ -456,7 +456,7 @@ it.layer(NodeServices.layer)("AgentSessionImporter", (it) => {
456456 upsert: () => Effect.die("must not replace an active binding"),
457457 getProvider: () => Effect.die("unused"),
458458 recordImportedTranscript: () => Effect.void,
459 getBinding: () => Effect.succeed(Option.some(runningBinding)),
459 getBinding: () => Effect.succeedSome(runningBinding),
460460 listThreadIds: () => Effect.die("unused"),
461461 listBindings: () => Effect.die("unused"),
462462 });
......@@ -511,7 +511,7 @@ it.layer(NodeServices.layer)("AgentSessionImporter", (it) => {
511511 upsert: () => Effect.die("must not bind malformed or wrong-project sessions"),
512512 getProvider: () => Effect.die("unused"),
513513 recordImportedTranscript: () => Effect.die("unused"),
514 getBinding: () => Effect.succeed(Option.none()),
514 getBinding: () => Effect.succeedNone,
515515 listThreadIds: () => Effect.die("unused"),
516516 listBindings: () => Effect.die("unused"),
517517 });
apps/server/src/project/AgentSessionScanner.ts+1-1
......@@ -662,7 +662,7 @@ export const make = Effect.gen(function* () {
662662 fileSystem.readDirectory(directory).pipe(Effect.orElseSucceed((): ReadonlyArray<string> => []));
663663
664664 const statOption = (target: string) =>
665 fileSystem.stat(target).pipe(Effect.map(Option.some), Effect.orElseSucceed(Option.none));
665 fileSystem.stat(target).pipe(Effect.asSome, Effect.orElseSucceed(Option.none));
666666
667667 /** Match directory aliases without assuming the host volume is case-insensitive. */
668668 const directoryIdentity = Effect.fn("AgentSessionScanner.directoryIdentity")(function* (
apps/server/src/project/ProjectFaviconResolver.ts+2-2
......@@ -143,7 +143,7 @@ const optionOnNotFound = <A, R>(
143143 effect: Effect.Effect<A, PlatformError.PlatformError, R>,
144144): Effect.Effect<Option.Option<A>, PlatformError.PlatformError, R> =>
145145 effect.pipe(
146 Effect.map(Option.some),
146 Effect.asSome,
147147 Effect.catchTags({
148148 PlatformError: (error) =>
149149 error.reason._tag === "NotFound" ? Effect.succeed(Option.none<A>()) : Effect.fail(error),
......@@ -175,7 +175,7 @@ export const make = Effect.gen(function* () {
175175 relativePath,
176176 })
177177 ).pipe(
178 Effect.map(Option.some),
178 Effect.asSome,
179179 Effect.catchTags({
180180 WorkspacePathOutsideRootError: () =>
181181 Effect.succeed(
apps/server/src/project/RepositoryIdentityResolver.ts+4-4
......@@ -141,6 +141,7 @@ export const make = Effect.fn("RepositoryIdentityResolver.make")(function* (
141141) {
142142 const processRunner = yield* ProcessRunner.ProcessRunner;
143143 const cacheCapacity = options.cacheCapacity ?? DEFAULT_REPOSITORY_IDENTITY_CACHE_CAPACITY;
144 const refine = options.refine ?? Effect.succeed;
144145
145146 const repositoryRootCache = yield* Cache.makeWith<string, string | null>(
146147 (cwd) =>
......@@ -161,10 +162,9 @@ export const make = Effect.fn("RepositoryIdentityResolver.make")(function* (
161162 (cacheKey) =>
162163 resolveRepositoryIdentityFromCacheKey(cacheKey).pipe(
163164 Effect.provideService(ProcessRunner.ProcessRunner, processRunner),
164 Effect.flatMap((identity) =>
165 identity !== null && options.refine
166 ? options.refine(identity).pipe(Effect.catch(() => Effect.succeed(identity)))
167 : Effect.succeed(identity),
165 Effect.filterOrElse(
166 (identity): identity is null => identity === null,
167 (identity) => refine(identity).pipe(Effect.orElseSucceed(() => identity)),
168168 ),
169169 ),
170170 {
apps/server/src/project/T3ProjectFileLoader.ts+2-2
......@@ -68,7 +68,7 @@ export const make = Effect.gen(function* () {
6868 function* (workspaceRoot) {
6969 const filePath = path.join(workspaceRoot, T3_PROJECT_FILE_NAME);
7070 const raw = yield* fileSystem.readFileString(filePath).pipe(
71 Effect.map(Option.some),
71 Effect.asSome,
7272 Effect.catchTags({
7373 PlatformError: (error) =>
7474 error.reason._tag === "NotFound"
......@@ -87,7 +87,7 @@ export const make = Effect.gen(function* () {
8787 return Option.none<T3ProjectFile>();
8888 }
8989 return yield* decodeT3ProjectFileJson(raw.value).pipe(
90 Effect.map(Option.some),
90 Effect.asSome,
9191 Effect.catchTags({
9292 SchemaError: (error) =>
9393 logT3ProjectFileLoadError(
apps/server/src/provider/AntigravityInstallation.ts+1-1
......@@ -315,7 +315,7 @@ export const makeAntigravityInstallation = Effect.fn("AntigravityInstallation.ma
315315 );
316316 }
317317 const contents = yield* fs.readFileString(filePath);
318 return yield* Schema.decodeUnknownEffect(Schema.fromJsonString(schema))(contents);
318 return yield* Schema.decodeEffect(Schema.fromJsonString(schema))(contents);
319319 });
320320
321321 const executableFile = Effect.fn("AntigravityInstallation.executableFile")(function* (
apps/server/src/provider/Drivers/AntigravitySkills.ts+1-1
......@@ -86,7 +86,7 @@ const readIfPresent = <A, R>(
8686 Effect.catchTags({
8787 PlatformError: (cause) =>
8888 cause.reason._tag === "NotFound"
89 ? Effect.succeed(undefined)
89 ? Effect.undefined
9090 : Effect.fail(
9191 new AntigravitySkillsProbeError({ reason: "filesystem-error", path, cause }),
9292 ),
apps/server/src/provider/Drivers/CursorDriver.ts+11-6
......@@ -140,12 +140,17 @@ export const CursorDriver: ProviderDriver<CursorSettings, CursorDriverEnv> = {
140140 processEnv,
141141 modelDiscovery.discover,
142142 ).pipe(
143 Effect.flatMap((snapshot) =>
144 effectiveConfig.enabled && snapshot.installed && snapshot.auth.status === "authenticated"
145 ? readCursorUsageLimits(effectiveConfig, processEnv).pipe(
146 Effect.map((usageLimits) => ({ ...snapshot, usageLimits })),
147 )
148 : Effect.succeed(snapshot),
143 Effect.filterOrElse(
144 (snapshot) =>
145 !(
146 effectiveConfig.enabled &&
147 snapshot.installed &&
148 snapshot.auth.status === "authenticated"
149 ),
150 (snapshot) =>
151 readCursorUsageLimits(effectiveConfig, processEnv).pipe(
152 Effect.map((usageLimits) => ({ ...snapshot, usageLimits })),
153 ),
149154 ),
150155 Effect.map(stampIdentity),
151156 Effect.provideService(HttpClient.HttpClient, httpClient),
apps/server/src/provider/Drivers/GrokDriver.ts+16-11
......@@ -131,17 +131,22 @@ export const GrokDriver: ProviderDriver<GrokSettings, GrokDriverEnv> = {
131131 const textGeneration = yield* makeGrokTextGeneration(effectiveConfig, processEnv);
132132
133133 const checkProvider = checkGrokProviderStatus(effectiveConfig, processEnv, cwd).pipe(
134 Effect.flatMap((snapshot) =>
135 effectiveConfig.enabled && snapshot.installed && snapshot.auth.status === "authenticated"
136 ? readGrokAccount(processEnv).pipe(
137 // The email lets clients recognize one account signed in on several environments.
138 Effect.map(({ email, usageLimits }) => ({
139 ...snapshot,
140 auth: email ? { ...snapshot.auth, email } : snapshot.auth,
141 usageLimits,
142 })),
143 )
144 : Effect.succeed(snapshot),
134 Effect.filterOrElse(
135 (snapshot) =>
136 !(
137 effectiveConfig.enabled &&
138 snapshot.installed &&
139 snapshot.auth.status === "authenticated"
140 ),
141 (snapshot) =>
142 readGrokAccount(processEnv).pipe(
143 // The email lets clients recognize one account signed in on several environments.
144 Effect.map(({ email, usageLimits }) => ({
145 ...snapshot,
146 auth: email ? { ...snapshot.auth, email } : snapshot.auth,
147 usageLimits,
148 })),
149 ),
145150 ),
146151 Effect.map(stampIdentity),
147152 Effect.provideService(HttpClient.HttpClient, httpClient),
apps/server/src/provider/Layers/AntigravityAdapter.ts+2-2
......@@ -844,7 +844,7 @@ export const makeAntigravityAdapter = Effect.fn("makeAntigravityAdapter")(functi
844844 const model = yield* applyAntigravityAcpModelSelection({
845845 runtime,
846846 model: input.modelSelection?.model,
847 defaultModel: yield* options.defaultModel ?? Effect.succeed(undefined),
847 defaultModel: yield* options.defaultModel ?? Effect.undefined,
848848 mapError: (cause) => cause,
849849 });
850850 yield* runtime.setMode(antigravityPermissionMode(input.runtimeMode));
......@@ -1035,7 +1035,7 @@ export const makeAntigravityAdapter = Effect.fn("makeAntigravityAdapter")(functi
10351035 const model = resolveAntigravityModel({
10361036 configOptions,
10371037 model: requestedModel,
1038 defaultModel: yield* options.defaultModel ?? Effect.succeed(undefined),
1038 defaultModel: yield* options.defaultModel ?? Effect.undefined,
10391039 });
10401040 const availableModels = antigravityModelOptions(configOptions);
10411041 if (model && !availableModels.some((option) => option.value === model)) {
apps/server/src/provider/Layers/ClaudeAdapter.test.ts+1
......@@ -1,3 +1,4 @@
1// @effect-diagnostics abortControllerInEffect:off - Tests hand-built AbortSignals to the SDK query stub to exercise cancellation.
12import { buildRuntimeInstructions } from "../RuntimeInstructions.ts";
23// @effect-diagnostics nodeBuiltinImport:off
34import * as NodeFS from "node:fs";
apps/server/src/provider/Layers/ClaudeAdapter.ts+2-1
......@@ -5357,6 +5357,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (
53575357 ) => {
53585358 // SDK history helpers read process.env. Isolate the provider's home instead
53595359 // of changing the server's environment while other providers are running.
5360 // @effect-diagnostics-next-line runEffectInsideEffect:off - SDK callback runs outside the fiber; the spawn is self-contained
53605361 const result = await Effect.runPromise(
53615362 spawnAndCollect(
53625363 process.execPath,
......@@ -5547,7 +5548,7 @@ export const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (
55475548
55485549 for (const result of results) {
55495550 if (result._tag === "Failure") {
5550 return yield* Effect.fail(result.failure);
5551 return yield* result.failure;
55515552 }
55525553 }
55535554 });
apps/server/src/provider/Layers/CodexAdapter.test.ts+1-1
......@@ -225,7 +225,7 @@ const providerSessionDirectoryTestLayer = Layer.succeed(ProviderSessionDirectory
225225 recordImportedTranscript: () => Effect.die("unused"),
226226 getProvider: () =>
227227 Effect.die(new Error("ProviderSessionDirectory.getProvider is not used in test")),
228 getBinding: () => Effect.succeed(Option.none()),
228 getBinding: () => Effect.succeedNone,
229229 listThreadIds: () => Effect.succeed([]),
230230 listBindings: () => Effect.succeed([]),
231231});
apps/server/src/provider/Layers/CodexSessionRuntime.ts+1-1
......@@ -1518,7 +1518,7 @@ export const makeCodexSessionRuntime = (
15181518 }
15191519 }),
15201520 ),
1521 Effect.catch(() => Effect.void),
1521 Effect.ignore,
15221522 Effect.forkIn(runtimeScope),
15231523 );
15241524 });
apps/server/src/provider/Layers/GrokAdapter.ts+37-38
......@@ -776,46 +776,45 @@ export function makeGrokAdapter(grokSettings: GrokSettings, options?: GrokAdapte
776776 );
777777 });
778778
779 const runTurnLivenessWatchdog = Effect.fn("GrokAdapter.runTurnLivenessWatchdog")(
780 function* (ctx: GrokSessionContext) {
781 while (true) {
782 if (ctx.stopped) {
783 return;
784 }
785 const turnId = ctx.livenessTurnId;
786 if (
787 turnId === undefined ||
788 ctx.interruptedTurnIds.has(turnId) ||
789 !isLiveTurn(ctx, turnId) ||
790 hasLivenessPause(ctx)
791 ) {
792 yield* Queue.take(ctx.livenessSignals);
793 continue;
794 }
779 const runTurnLivenessWatchdog = Effect.fn("GrokAdapter.runTurnLivenessWatchdog")(function* (
780 ctx: GrokSessionContext,
781 ) {
782 while (true) {
783 if (ctx.stopped) {
784 return;
785 }
786 const turnId = ctx.livenessTurnId;
787 if (
788 turnId === undefined ||
789 ctx.interruptedTurnIds.has(turnId) ||
790 !isLiveTurn(ctx, turnId) ||
791 hasLivenessPause(ctx)
792 ) {
793 yield* Queue.take(ctx.livenessSignals);
794 continue;
795 }
795796
796 const lastActivityAtNanos = ctx.lastTurnActivityAtNanos;
797 if (lastActivityAtNanos === undefined) {
798 yield* Queue.take(ctx.livenessSignals);
799 continue;
800 }
801 const nowNanos = yield* Clock.monotonicTimeNanos;
802 const remainingNanos = livenessTimeoutFor(ctx).nanos - (nowNanos - lastActivityAtNanos);
803 if (remainingNanos <= 0n) {
804 yield* settleStalledTurn(ctx, turnId);
805 continue;
806 }
797 const lastActivityAtNanos = ctx.lastTurnActivityAtNanos;
798 if (lastActivityAtNanos === undefined) {
799 yield* Queue.take(ctx.livenessSignals);
800 continue;
801 }
802 const nowNanos = yield* Clock.monotonicTimeNanos;
803 const remainingNanos = livenessTimeoutFor(ctx).nanos - (nowNanos - lastActivityAtNanos);
804 if (remainingNanos <= 0n) {
805 yield* settleStalledTurn(ctx, turnId);
806 continue;
807 }
807808
808 const wakeReason = yield* Effect.raceFirst(
809 Effect.sleep(Duration.nanos(remainingNanos)).pipe(Effect.as("timeout" as const)),
810 Queue.take(ctx.livenessSignals).pipe(Effect.as("activity" as const)),
811 );
812 if (wakeReason === "timeout") {
813 yield* settleStalledTurn(ctx, turnId);
814 }
809 const wakeReason = yield* Effect.raceFirst(
810 Effect.sleep(Duration.nanos(remainingNanos)).pipe(Effect.as("timeout" as const)),
811 Queue.take(ctx.livenessSignals).pipe(Effect.as("activity" as const)),
812 );
813 if (wakeReason === "timeout") {
814 yield* settleStalledTurn(ctx, turnId);
815815 }
816 },
817 Effect.catch(() => Effect.void),
818 );
816 }
817 }, Effect.ignore());
819818
820819 const logNative = (threadId: ThreadId, method: string, payload: unknown) =>
821820 Effect.gen(function* () {
......@@ -2008,7 +2007,7 @@ export function makeGrokAdapter(grokSettings: GrokSettings, options?: GrokAdapte
20082007 errorMessage: errorMessage ?? "Grok prompt request failed.",
20092008 }),
20102009 );
2011 }).pipe(Effect.catch(() => Effect.void)),
2010 }).pipe(Effect.ignore),
20122011 ),
20132012 );
20142013 });
apps/server/src/provider/Layers/OpenCodeAdapter.test.ts+1-1
......@@ -578,7 +578,7 @@ const providerSessionDirectoryTestLayer = Layer.succeed(ProviderSessionDirectory
578578 recordImportedTranscript: () => Effect.die("unused"),
579579 getProvider: () =>
580580 Effect.die(new Error("ProviderSessionDirectory.getProvider is not used in test")),
581 getBinding: () => Effect.succeed(Option.none()),
581 getBinding: () => Effect.succeedNone,
582582 listThreadIds: () => Effect.succeed([]),
583583 listBindings: () => Effect.succeed([]),
584584});
apps/server/src/provider/Layers/OpenCodeAdapter.ts+8-7
......@@ -822,7 +822,7 @@ const abortOpenCodeDescendants = Effect.fn("abortOpenCodeDescendants")(function*
822822 .pipe(
823823 Effect.catchIf(
824824 (cause) => isOpenCodeNotFound(cause),
825 () => Effect.void,
825 () => Effect.undefined,
826826 ),
827827 Effect.result,
828828 );
......@@ -1097,7 +1097,7 @@ export function makeOpenCodeAdapter(
10971097 readonly observedAt: string;
10981098 readonly event: Record<string, unknown>;
10991099 },
1100 ) => writeNativeEvent(threadId, event).pipe(Effect.catchCause(() => Effect.void));
1100 ) => writeNativeEvent(threadId, event).pipe(Effect.ignoreCause);
11011101
11021102 const cancelIdleReconciliation = Effect.fn("cancelIdleReconciliation")(function* (
11031103 context: OpenCodeSessionContext,
......@@ -1262,7 +1262,7 @@ export function makeOpenCodeAdapter(
12621262 yield* Effect.sleep(`${delayMs} millis`);
12631263 }
12641264 }).pipe(
1265 Effect.catchCause(() => Effect.void),
1265 Effect.ignoreCause,
12661266 Effect.ensuring(
12671267 Effect.sync(() => {
12681268 if (context.pendingIdleReconciliation === pending) {
......@@ -1492,7 +1492,7 @@ export function makeOpenCodeAdapter(
14921492 }
14931493 yield* failPromptAdmissionRecovery(context, promptAdmission);
14941494 }).pipe(
1495 Effect.catchCause(() => Effect.void),
1495 Effect.ignoreCause,
14961496 Effect.ensuring(
14971497 Effect.sync(() => {
14981498 delete promptAdmission.recoveryFiber;
......@@ -1699,7 +1699,7 @@ export function makeOpenCodeAdapter(
16991699 }),
17001700 Effect.catchIf(
17011701 (cause) => isOpenCodeNotFound(cause),
1702 () => Effect.succeed(undefined),
1702 () => Effect.undefined,
17031703 ),
17041704 );
17051705 let sessionId: string | undefined = candidateSessionId;
......@@ -2044,7 +2044,7 @@ export function makeOpenCodeAdapter(
20442044 yield* Effect.sleep(`${delayMs} millis`);
20452045 }
20462046 }).pipe(
2047 Effect.catchCause(() => Effect.void),
2047 Effect.ignoreCause,
20482048 Effect.ensuring(
20492049 Effect.sync(() => {
20502050 if (context.requestRelationRetries.get(requestId) === retry) {
......@@ -2163,7 +2163,7 @@ export function makeOpenCodeAdapter(
21632163 return;
21642164 }
21652165 }).pipe(
2166 Effect.catchCause(() => Effect.void),
2166 Effect.ignoreCause,
21672167 Effect.ensuring(
21682168 Effect.sync(() => {
21692169 if (context.pendingRequestRecovery === recovery) {
......@@ -2730,6 +2730,7 @@ export function makeOpenCodeAdapter(
27302730 // the scope closes (explicit stop, unexpected exit, or layer
27312731 // shutdown) and cancels the in-flight `event.subscribe` fetch so
27322732 // the async iterable unwinds cleanly.
2733 // @effect-diagnostics-next-line abortControllerInEffect:off - aborted by a scope finalizer to cancel the SDK's event.subscribe fetch
27332734 const eventsAbortController = new AbortController();
27342735 let lastStreamError: unknown;
27352736 let warnedAboutDisconnect = false;
apps/server/src/provider/Layers/ProviderService.test.ts+5-7
......@@ -4894,13 +4894,11 @@ const listThreadIds = vi.fn(() =>
48944894 Effect.succeed([activeSessionThreadId, historicalSessionThreadId]),
48954895);
48964896const getBinding = vi.fn((threadId: ThreadId) =>
4897 Effect.succeed(
4898 Option.some({
4899 threadId,
4900 provider: CODEX_DRIVER,
4901 providerInstanceId: codexInstanceId,
4902 }),
4903 ),
4897 Effect.succeedSome({
4898 threadId,
4899 provider: CODEX_DRIVER,
4900 providerInstanceId: codexInstanceId,
4901 }),
49044902);
49054903const boundedListing = makeProviderServiceLayer({
49064904 directory: {
apps/server/src/provider/Layers/ProviderService.ts+1-1
......@@ -2298,7 +2298,7 @@ const makeProviderService = Effect.fn("makeProviderService")(function* (
22982298 // Continuation is project-scopable, so decide it per session's project;
22992299 // without orchestration the environment value is all there is.
23002300 const stopSettings = yield* serverSettings.getSettings.pipe(
2301 Effect.map(Option.some),
2301 Effect.asSome,
23022302 Effect.orElseSucceed(() => Option.none<ServerSettingsValue>()),
23032303 );
23042304 const continueAfterRestartFor = Effect.fn("continueAfterRestartFor")(function* (
apps/server/src/provider/Layers/ProviderSessionDirectory.ts+1-3
......@@ -93,9 +93,7 @@ const makeProviderSessionDirectory = Effect.gen(function* () {
9393 Option.match(runtime, {
9494 onNone: () => Effect.succeed(Option.none<ProviderRuntimeBinding>()),
9595 onSome: (value) =>
96 toRuntimeBinding(value, "ProviderSessionDirectory.getBinding").pipe(
97 Effect.map((binding) => Option.some(binding)),
98 ),
96 toRuntimeBinding(value, "ProviderSessionDirectory.getBinding").pipe(Effect.asSome),
9997 }),
10098 ),
10199 );
apps/server/src/provider/Layers/claudeResetCredits.ts+1-1
......@@ -186,7 +186,7 @@ export const readClaudeResetCredits = Effect.fn("readClaudeResetCredits")(
186186 );
187187 },
188188 Effect.timeout("10 seconds"),
189 Effect.catch(() => Effect.succeed(undefined)),
189 Effect.orElseSucceed(() => undefined),
190190);
191191
192192/** The CLI keeps the account record beside its settings, or in the home directory by default. */
apps/server/src/provider/Layers/cursorUsageLimits.ts+6-8
......@@ -127,14 +127,12 @@ export const readCursorUsageLimits = Effect.fn("readCursorUsageLimits")(function
127127 return cursorUsageResponseToLimits(body, checkedAt);
128128 }).pipe(
129129 Effect.timeout("10 seconds"),
130 Effect.catch(() =>
131 Effect.succeed(
132 makeUnavailableUsageLimits({
133 checkedAt,
134 reason: "probeFailed",
135 message: "Cursor could not read usage limits.",
136 }),
137 ),
130 Effect.orElseSucceed(() =>
131 makeUnavailableUsageLimits({
132 checkedAt,
133 reason: "probeFailed",
134 message: "Cursor could not read usage limits.",
135 }),
138136 ),
139137 );
140138});
apps/server/src/provider/Layers/grokUsageLimits.ts+1-1
......@@ -169,7 +169,7 @@ export const readGrokAccount = Effect.fn("readGrokAccount")(function* (
169169 return grokUsageResponseToLimits(body, checkedAt);
170170 }).pipe(
171171 Effect.timeout("10 seconds"),
172 Effect.catch(() => Effect.succeed(probeFailed)),
172 Effect.orElseSucceed(() => probeFailed),
173173 );
174174 return { email, usageLimits };
175175});
apps/server/src/provider/ModelManifest.ts+1-1
......@@ -408,7 +408,7 @@ export const make = Effect.gen(function* () {
408408 fetchedAtMs = now;
409409 yield* encodeManifestCache({ fetchedAtMs: now, manifest: fetched }).pipe(
410410 Effect.flatMap((serialized) => fileSystem.writeFileString(cachePath, serialized)),
411 Effect.catchCause(() => Effect.void),
411 Effect.ignoreCause,
412412 );
413413 return manifest;
414414 });
apps/server/src/provider/acp/AcpSessionRuntime.ts+27-30
......@@ -780,17 +780,16 @@ export const make = (
780780 resumePayload,
781781 acp.agent.resumeSession(resumePayload).pipe(
782782 Effect.timeoutOption(options.sessionLoadTimeout ?? defaultSessionLoadTimeout),
783 Effect.flatMap((result) =>
784 Option.isSome(result)
785 ? Effect.succeed(result.value)
786 : Effect.fail(
787 new EffectAcpErrors.AcpTransportError({
788 operation: "call-rpc",
789 method: "session/resume",
790 detail: "session/resume timed out waiting for the agent response.",
791 cause: undefined,
792 }),
793 ),
783 Effect.flatMap(
784 Effect.fromOption(
785 () =>
786 new EffectAcpErrors.AcpTransportError({
787 operation: "call-rpc",
788 method: "session/resume",
789 detail: "session/resume timed out waiting for the agent response.",
790 cause: undefined,
791 }),
792 ),
794793 ),
795794 ),
796795 );
......@@ -834,19 +833,16 @@ export const make = (
834833 ).pipe(
835834 Effect.ensuring(Fiber.interrupt(idleFiber).pipe(Effect.ignore)),
836835 Effect.timeoutOption(sessionLoadTimeout),
837 Effect.flatMap((result) =>
838 Option.match(result, {
839 onNone: () =>
840 Effect.fail(
841 new EffectAcpErrors.AcpTransportError({
842 operation: "call-rpc",
843 method: "session/load",
844 detail: "session/load timed out waiting for RPC response or replay idle gap",
845 cause: undefined,
846 }),
847 ),
848 onSome: Effect.succeed,
849 }),
836 Effect.flatMap(
837 Effect.fromOption(
838 () =>
839 new EffectAcpErrors.AcpTransportError({
840 operation: "call-rpc",
841 method: "session/load",
842 detail: "session/load timed out waiting for RPC response or replay idle gap",
843 cause: undefined,
844 }),
845 ),
850846 ),
851847 Effect.tap((result) =>
852848 logRequest({
......@@ -1058,12 +1054,13 @@ export const make = (
10581054 ),
10591055 (activePrompt) =>
10601056 Fiber.join(activePrompt.fiber).pipe(
1061 Effect.catchCause((cause) =>
1062 options.cancelBehavior !== "wait-for-prompt" && Cause.hasInterruptsOnly(cause)
1063 ? Effect.succeed({
1064 stopReason: "cancelled",
1065 } satisfies EffectAcpSchema.PromptResponse)
1066 : Effect.failCause(cause),
1057 Effect.catchCauseIf(
1058 (cause) =>
1059 options.cancelBehavior !== "wait-for-prompt" && Cause.hasInterruptsOnly(cause),
1060 () =>
1061 Effect.succeed({
1062 stopReason: "cancelled",
1063 } satisfies EffectAcpSchema.PromptResponse),
10671064 ),
10681065 Effect.tap(() =>
10691066 closeActiveAssistantSegment({ queue: eventQueue, assistantSegmentRef }),
apps/server/src/provider/antigravityAuthSupport.ts+1-3
......@@ -277,9 +277,7 @@ const linkAntigravityUserSkills = Effect.fn("linkAntigravityUserSkills")(functio
277277 yield* Effect.gen(function* () {
278278 const existing = yield* fs.readLink(link).pipe(
279279 Effect.map((value): string | undefined => path.resolve(path.dirname(link), value)),
280 Effect.catch((error) =>
281 error.reason._tag === "NotFound" ? Effect.succeed(undefined) : Effect.fail(error),
282 ),
280 Effect.catchReason("PlatformError", "NotFound", () => Effect.undefined),
283281 );
284282 if (existing === target) return;
285283 if (existing !== undefined) {
apps/server/src/provider/makeManagedServerProvider.ts+1
......@@ -252,6 +252,7 @@ export const makeManagedServerProvider = Effect.fn("makeManagedServerProvider")(
252252 yield* Effect.forever(
253253 getRefreshInterval.pipe(
254254 Effect.flatMap((refreshInterval) =>
255 // @effect-diagnostics-next-line raceFirstWithSleepToTimeout:off - races the interval against a settings-change signal, not a timeout
255256 Effect.raceFirst(
256257 Effect.sleep(
257258 Duration.toMillis(Duration.fromInputUnsafe(refreshInterval)) <= 0
apps/server/src/provider/providerInstallation.ts+1-1
......@@ -118,7 +118,7 @@ export const makeProviderInstallation = Effect.fn("makeProviderInstallation")(fu
118118 env: mergeProviderInstanceEnvironment(entry.environment),
119119 }).pipe(
120120 Effect.map((resolved) => [binaryPath, resolved]),
121 Effect.catch(() => Effect.succeed([binaryPath])),
121 Effect.orElseSucceed(() => [binaryPath]),
122122 );
123123 });
124124 yield* installation
apps/server/src/pullRequest/GitHubPullRequestCli.ts+26-27
......@@ -1595,31 +1595,30 @@ export const make = Effect.gen(function* () {
15951595 decode: decodePullRequestCoreJson,
15961596 }),
15971597 ),
1598 ).pipe(
1599 Effect.flatMap((core) => {
1600 if (!core.checksTruncated) return Effect.succeed(core);
1601 // gh already pages check contexts. Keep its complete, deduplicated result for
1602 // large check suites instead of letting the first 100 checks imply success.
1603 return readLegacyDetail(input).pipe(
1604 Effect.flatMap((detail) =>
1605 detail.headSha !== core.headSha
1606 ? Effect.fail(
1607 new GitHubPullRequestReadError({
1608 command: "gh",
1609 cwd: input.cwd,
1610 operation: "getPullRequestDetail",
1611 cause: new Error("Pull request head changed while reading checks."),
1612 }),
1613 )
1614 : Effect.succeed({
1615 ...core,
1616 checks: detail.checks,
1617 checksState: detail.checksState,
1618 checksTruncated: false,
1598 // gh already pages check contexts. Keep its complete, deduplicated result for
1599 // large check suites instead of letting the first 100 checks imply success.
1600 Effect.filterOrElse(
1601 (core) => !core.checksTruncated,
1602 (core) =>
1603 readLegacyDetail(input).pipe(
1604 Effect.filterOrFail(
1605 (detail) => detail.headSha === core.headSha,
1606 () =>
1607 new GitHubPullRequestReadError({
1608 command: "gh",
1609 cwd: input.cwd,
1610 operation: "getPullRequestDetail",
1611 cause: new Error("Pull request head changed while reading checks."),
16191612 }),
1613 ),
1614 Effect.map((detail) => ({
1615 ...core,
1616 checks: detail.checks,
1617 checksState: detail.checksState,
1618 checksTruncated: false,
1619 })),
16201620 ),
1621 );
1622 }),
1621 ),
16231622 );
16241623 };
16251624
......@@ -1967,10 +1966,9 @@ export const make = Effect.gen(function* () {
19671966 // the fallback out: an empty answer under one is already the answer.
19681967 const hasQuery = (input.query?.trim().length ?? 0) > 0;
19691968 return read(true).pipe(
1970 Effect.flatMap((batch) =>
1971 batch.items.length === 0 && input.cursor === undefined && !hasQuery
1972 ? read(false)
1973 : Effect.succeed(batch),
1969 Effect.filterOrElse(
1970 (batch) => batch.items.length > 0 || input.cursor !== undefined || hasQuery,
1971 () => read(false),
19741972 ),
19751973 Effect.flatMap((batch) => {
19761974 // Match the search query's host support, and enrich only rows that survived paging.
......@@ -2131,6 +2129,7 @@ export const make = Effect.gen(function* () {
21312129 }),
21322130 );
21332131 }),
2132 // @effect-diagnostics-next-line flatMapConditionalToFilterOrFail:off - the fallback needs a non-null stack, which a predicate that also reads includeDetails cannot refine.
21342133 Effect.flatMap((stack) => {
21352134 if (!input.includeDetails || stack === null) return Effect.succeed(stack);
21362135 return github
apps/server/src/pullRequest/GitLabPullRequestCli.ts+1-1
......@@ -1250,7 +1250,7 @@ export const make = Effect.gen(function* () {
12501250 getMergeRequestDiffFileContents: (input) =>
12511251 Effect.gen(function* () {
12521252 if (input.commit !== undefined && !isCommitSha(input.commit)) {
1253 return yield* Effect.fail(new GitLabDiffCommitError({ command: "glab", cwd: input.cwd }));
1253 return yield* new GitLabDiffCommitError({ command: "glab", cwd: input.cwd });
12541254 }
12551255 const refs = yield* input.commit === undefined
12561256 ? getDiffRefs(input)
apps/server/src/pullRequest/PullRequestReadCache.ts+1-1
......@@ -77,7 +77,7 @@ export const make = Effect.gen(function* () {
7777 () =>
7878 backing
7979 .get("revisions")
80 .pipe(Effect.flatMap((raw) => Schema.decodeUnknownEffect(revisionCodec)(raw ?? "{}"))),
80 .pipe(Effect.flatMap((raw) => Schema.decodeEffect(revisionCodec)(raw ?? "{}"))),
8181 {
8282 capacity: 1,
8383 timeToLive: (exit) => (Exit.isSuccess(exit) ? Duration.infinity : Duration.zero),
apps/server/src/pullRequest/PullRequestService.test.ts+5-3
......@@ -3251,13 +3251,13 @@ it.effect("shares one cold viewer lookup across distinct concurrent lists", () =
32513251 ],
32523252 });
32533253
3254 yield* Effect.all(
3255 ["all", "authored", "reviewing"].map((involvement) =>
3254 yield* Effect.forEach(
3255 ["all", "authored", "reviewing"],
3256 (involvement) =>
32563257 service.list({
32573258 state: "open",
32583259 involvement: involvement as "all" | "authored" | "reviewing",
32593260 }),
3260 ),
32613261 { concurrency: "unbounded" },
32623262 );
32633263
......@@ -4328,6 +4328,7 @@ it.effect("keeps routed reads separate when the GitHub account changes", () =>
43284328 ],
43294329 });
43304330 const readOperation = (input: Parameters<typeof service.diff>[0]) =>
4331 // @effect-diagnostics-next-line unnecessaryEffectGen:off - the generator unifies the per-operation union of Effect types, which Effect.asVoid cannot infer through.
43314332 Effect.gen(function* () {
43324333 yield* service[operation](input);
43334334 });
......@@ -4391,6 +4392,7 @@ it.effect("isolates routed caches for two credentials belonging to the same acco
43914392 ],
43924393 });
43934394 const readOperation = (input: Parameters<typeof service.diff>[0]) =>
4395 // @effect-diagnostics-next-line unnecessaryEffectGen:off - the generator unifies the per-operation union of Effect types, which Effect.asVoid cannot infer through.
43944396 Effect.gen(function* () {
43954397 yield* service[operation](input);
43964398 });
apps/server/src/pullRequest/PullRequestService.ts+1-1
......@@ -2751,7 +2751,7 @@ export const make = Effect.gen(function* () {
27512751 `project:${input.projectId}`,
27522752 refScope(input),
27532753 ]);
2754 const decoded = yield* Schema.decodeUnknownEffect(codec)(payload).pipe(Effect.option);
2754 const decoded = yield* Schema.decodeEffect(codec)(payload).pipe(Effect.option);
27552755 return Option.isSome(decoded) ? decoded.value : yield* lookup;
27562756 });
27572757 const summaryCodec = Schema.fromJsonString(PullRequestSummary);
apps/server/src/relay/AgentAwarenessRelay.test.ts+4-4
......@@ -576,7 +576,7 @@ describe.sequential("signRelayAgentActivityPublishProof", () => {
576576 yield* Deferred.await(releaseThreadShell);
577577 return Option.some(thread);
578578 }),
579 getProjectShellById: () => Effect.succeed(Option.some(project)),
579 getProjectShellById: () => Effect.succeedSome(project),
580580 } as unknown as ProjectionSnapshotQueryShape;
581581
582582 const descriptor = {
......@@ -793,8 +793,8 @@ describe.sequential("signRelayAgentActivityPublishProof", () => {
793793 threads: [thread],
794794 updatedAt: now,
795795 } satisfies OrchestrationShellSnapshot),
796 getThreadShellById: () => Effect.succeed(Option.some(thread)),
797 getProjectShellById: () => Effect.succeed(Option.some(project)),
796 getThreadShellById: () => Effect.succeedSome(thread),
797 getProjectShellById: () => Effect.succeedSome(project),
798798 } as unknown as ProjectionSnapshotQueryShape),
799799 );
800800
......@@ -915,7 +915,7 @@ describe.sequential("signRelayAgentActivityPublishProof", () => {
915915 Layer.succeed(OrchestrationEngineService, {} as OrchestrationEngineShape),
916916 Layer.succeed(ProjectionSnapshotQuery, {
917917 getThreadShellById: () => Effect.sync(() => Option.fromNullishOr(currentThread)),
918 getProjectShellById: () => Effect.succeed(Option.some(project)),
918 getProjectShellById: () => Effect.succeedSome(project),
919919 } as unknown as ProjectionSnapshotQueryShape),
920920 );
921921
apps/server/src/resourceTelemetry/HostResources.ts+2-2
......@@ -60,7 +60,7 @@ export const make = Effect.fn("makeHostResources")(function* () {
6060 if (platform === "linux") {
6161 const meminfo = yield* fs
6262 .readFileString("/proc/meminfo")
63 .pipe(Effect.catch(() => Effect.succeed("")));
63 .pipe(Effect.orElseSucceed(() => ""));
6464 const available = /^MemAvailable:\s+(\d+)\s+kB$/m.exec(meminfo)?.[1];
6565 if (available) availableMemoryBytes = Number(available) * 1024;
6666 } else if (platform === "darwin") {
......@@ -68,7 +68,7 @@ export const make = Effect.fn("makeHostResources")(function* () {
6868 .string(ChildProcess.make("/usr/bin/vm_stat", [], { stdin: "ignore", stderr: "ignore" }))
6969 .pipe(
7070 Effect.timeout("1 second"),
71 Effect.catch(() => Effect.succeed("")),
71 Effect.orElseSucceed(() => ""),
7272 );
7373 availableMemoryBytes = darwinAvailableMemory(output) ?? availableMemoryBytes;
7474 }
apps/server/src/server.test.ts+111-129
......@@ -655,25 +655,25 @@ const buildAppUnderTest = (options?: {
655655 get: () => Effect.succeed(defaultVcsDriver),
656656 detect: (input) =>
657657 defaultVcsDriver.detectRepository(input.cwd).pipe(
658 Effect.flatMap((repository) =>
659 repository
660 ? Effect.succeed(repository)
661 : defaultVcsDriver.isInsideWorkTree(input.cwd).pipe(
662 Effect.map((isInsideWorkTree) =>
663 isInsideWorkTree
664 ? {
665 kind: "git" as const,
666 rootPath: input.cwd,
667 metadataPath: null,
668 freshness: {
669 source: "live-local" as const,
670 observedAt: TEST_EPOCH,
671 expiresAt: Option.none(),
672 },
673 }
674 : null,
675 ),
658 Effect.filterOrElse(
659 (repository) => repository !== null,
660 () =>
661 defaultVcsDriver.isInsideWorkTree(input.cwd).pipe(
662 Effect.map((isInsideWorkTree) =>
663 isInsideWorkTree
664 ? {
665 kind: "git" as const,
666 rootPath: input.cwd,
667 metadataPath: null,
668 freshness: {
669 source: "live-local" as const,
670 observedAt: TEST_EPOCH,
671 expiresAt: Option.none(),
672 },
673 }
674 : null,
676675 ),
676 ),
677677 ),
678678 Effect.map((repository) =>
679679 repository
......@@ -822,7 +822,7 @@ const buildAppUnderTest = (options?: {
822822 ...options?.layers?.providerAuth,
823823 }),
824824 Layer.mock(ProviderInstanceRegistry)({
825 getInstance: () => Effect.succeed(undefined),
825 getInstance: () => Effect.undefined,
826826 listInstances: Effect.succeed([]),
827827 ...options?.layers?.providerInstanceRegistry,
828828 }),
......@@ -832,7 +832,7 @@ const buildAppUnderTest = (options?: {
832832 }),
833833 Layer.mock(ProviderSessionDirectory.ProviderSessionDirectory)({
834834 upsert: () => Effect.void,
835 getBinding: () => Effect.succeed(Option.none()),
835 getBinding: () => Effect.succeedNone,
836836 listThreadIds: () => Effect.succeed([]),
837837 listBindings: () => Effect.succeed([]),
838838 ...options?.layers?.providerSessionDirectory,
......@@ -858,7 +858,7 @@ const buildAppUnderTest = (options?: {
858858 Layer.mergeAll(
859859 Layer.mock(ExternalLauncher.ExternalLauncher)({
860860 resolveAvailableEditors: () => Effect.succeed([]),
861 resolveFileManagerRevealKind: () => Effect.sync((): undefined => undefined),
861 resolveFileManagerRevealKind: () => Effect.undefined,
862862 ...options?.layers?.externalLauncher,
863863 }),
864864 Layer.mock(RemoteOpenTargets.RemoteOpenTargets)({
......@@ -1034,20 +1034,20 @@ const buildAppUnderTest = (options?: {
10341034 }),
10351035 searchThreads: () => Effect.succeed({ matches: [] }),
10361036 getSnapshotSequence: () => Effect.succeed({ snapshotSequence: 0 }),
1037 getProjectShellById: () => Effect.succeed(Option.none()),
1038 getThreadShellById: () => Effect.succeed(Option.none()),
1039 getThreadDetailById: () => Effect.succeed(Option.none()),
1040 getThreadDetailSnapshot: () => Effect.succeed(Option.none()),
1037 getProjectShellById: () => Effect.succeedNone,
1038 getThreadShellById: () => Effect.succeedNone,
1039 getThreadDetailById: () => Effect.succeedNone,
1040 getThreadDetailSnapshot: () => Effect.succeedNone,
10411041 getCounts: () => Effect.succeed({ projectCount: 0, threadCount: 0 }),
10421042 getEventReplayStats: ({ fromSequenceExclusive, toSequenceInclusive }) =>
10431043 Effect.succeed({
10441044 eventCount: Math.max(0, toSequenceInclusive - fromSequenceExclusive),
10451045 payloadBytes: 0,
10461046 }),
1047 getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()),
1048 getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()),
1047 getActiveProjectByWorkspaceRoot: () => Effect.succeedNone,
1048 getFirstActiveThreadIdByProjectId: () => Effect.succeedNone,
10491049 getImportedAgentSessionSources: () => Effect.succeed([]),
1050 getThreadCheckpointContext: () => Effect.succeed(Option.none()),
1050 getThreadCheckpointContext: () => Effect.succeedNone,
10511051 ...options?.layers?.projectionSnapshotQuery,
10521052 }),
10531053 ),
......@@ -1201,7 +1201,7 @@ const buildAppUnderTest = (options?: {
12011201 Layer.provide(
12021202 Layer.mock(CloudCliTokenManager.CloudCliTokenManager)({
12031203 get: Effect.die(new Error("Unexpected T3 Connect CLI authorization request.")),
1204 getExisting: Effect.succeed(Option.none()),
1204 getExisting: Effect.succeedNone,
12051205 hasCredential: Effect.succeed(false),
12061206 clear: Effect.void,
12071207 ...options?.layers?.cloudCliTokenManager,
......@@ -8972,8 +8972,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
89728972 yield* buildAppUnderTest({
89738973 layers: {
89748974 projectionSnapshotQuery: {
8975 getThreadDetailSnapshot: () =>
8976 Effect.succeed(Option.some({ snapshotSequence: 1, thread })),
8975 getThreadDetailSnapshot: () => Effect.succeedSome({ snapshotSequence: 1, thread }),
89778976 },
89788977 },
89798978 });
......@@ -9146,16 +9145,13 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
91469145 streamDomainEvents: Stream.concat(Stream.make(event), Stream.never),
91479146 },
91489147 projectionSnapshotQuery: {
9149 getThreadDetailSnapshot: () =>
9150 Effect.succeed(Option.some({ snapshotSequence: 1, thread })),
9148 getThreadDetailSnapshot: () => Effect.succeedSome({ snapshotSequence: 1, thread }),
91519149 getThreadShellById: (threadId) =>
9152 Effect.succeed(
9153 Option.some({
9154 ...makeDefaultOrchestrationThreadShell(),
9155 id: threadId,
9156 title: "Build complete",
9157 }),
9158 ),
9150 Effect.succeedSome({
9151 ...makeDefaultOrchestrationThreadShell(),
9152 id: threadId,
9153 title: "Build complete",
9154 }),
91599155 },
91609156 },
91619157 });
......@@ -9433,7 +9429,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
94339429 },
94349430 projectionSnapshotQuery: {
94359431 getThreadDetailSnapshot: () =>
9436 Effect.succeed(Option.some({ snapshotSequence: 100_000, thread })),
9432 Effect.succeedSome({ snapshotSequence: 100_000, thread }),
94379433 },
94389434 },
94399435 });
......@@ -9751,8 +9747,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
97519747 }),
97529748 },
97539749 projectionSnapshotQuery: {
9754 getThreadDetailSnapshot: () =>
9755 Effect.succeed(Option.some({ snapshotSequence: 5, thread })),
9750 getThreadDetailSnapshot: () => Effect.succeedSome({ snapshotSequence: 5, thread }),
97569751 },
97579752 },
97589753 });
......@@ -9840,7 +9835,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
98409835 projectionSnapshotQuery: {
98419836 getThreadDetailSnapshot: (_threadId, options) => {
98429837 requestedTurnLimit = options?.turnLimit;
9843 return Effect.succeed(Option.some({ snapshotSequence: 5, thread }));
9838 return Effect.succeedSome({ snapshotSequence: 5, thread });
98449839 },
98459840 },
98469841 },
......@@ -9933,7 +9928,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
99339928 readEvents: store.readFromSequence,
99349929 },
99359930 projectionSnapshotQuery: {
9936 getThreadDetailSnapshot: () => Effect.succeed(Option.none()),
9931 getThreadDetailSnapshot: () => Effect.succeedNone,
99379932 },
99389933 },
99399934 });
......@@ -10163,8 +10158,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
1016310158 replayStatsCalls += 1;
1016410159 return { eventCount: 5, payloadBytes: 8 * 1024 * 1024 + 1 };
1016510160 }),
10166 getThreadDetailSnapshot: () =>
10167 Effect.succeed(Option.some({ snapshotSequence: 5, thread })),
10161 getThreadDetailSnapshot: () => Effect.succeedSome({ snapshotSequence: 5, thread }),
1016810162 getShellSnapshot: () =>
1016910163 Effect.succeed({
1017010164 snapshotSequence: 5,
......@@ -10468,7 +10462,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
1046810462 ]),
1046910463 },
1047010464 projectionSnapshotQuery: {
10471 getThreadShellById: () => Effect.succeed(Option.none()),
10465 getThreadShellById: () => Effect.succeedNone,
1047210466 },
1047310467 },
1047410468 });
......@@ -10526,9 +10520,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
1052610520 detail: "transient failure",
1052710521 }),
1052810522 )
10529 : Effect.succeed(
10530 Option.some(makeDefaultOrchestrationThreadShell({ id: threadId })),
10531 );
10523 : Effect.succeedSome(makeDefaultOrchestrationThreadShell({ id: threadId }));
1053210524 }),
1053310525 },
1053410526 },
......@@ -10588,7 +10580,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
1058810580 ]),
1058910581 },
1059010582 projectionSnapshotQuery: {
10591 getProjectShellById: () => Effect.succeed(Option.none()),
10583 getProjectShellById: () => Effect.succeedNone,
1059210584 },
1059310585 },
1059410586 });
......@@ -10634,22 +10626,20 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
1063410626 },
1063510627 projectionSnapshotQuery: {
1063610628 getThreadShellById: () =>
10637 Effect.succeed(
10638 Option.some(
10639 makeDefaultOrchestrationThreadShell({
10640 id: threadId,
10629 Effect.succeedSome(
10630 makeDefaultOrchestrationThreadShell({
10631 id: threadId,
10632 updatedAt: now,
10633 session: {
10634 threadId,
10635 status: "ready",
10636 providerName: "claudeAgent",
10637 runtimeMode: "full-access",
10638 activeTurnId: null,
10639 lastError: null,
1064110640 updatedAt: now,
10642 session: {
10643 threadId,
10644 status: "ready",
10645 providerName: "claudeAgent",
10646 runtimeMode: "full-access",
10647 activeTurnId: null,
10648 lastError: null,
10649 updatedAt: now,
10650 },
10651 }),
10652 ),
10641 },
10642 }),
1065310643 ),
1065410644 },
1065510645 },
......@@ -10782,8 +10772,8 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
1078210772 },
1078310773 projectionSnapshotQuery: {
1078410774 getThreadShellById: () =>
10785 Effect.succeed(
10786 Option.some(makeDefaultOrchestrationThreadShell({ id: threadId, session: null })),
10775 Effect.succeedSome(
10776 makeDefaultOrchestrationThreadShell({ id: threadId, session: null }),
1078710777 ),
1078810778 },
1078910779 },
......@@ -10836,22 +10826,20 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
1083610826 },
1083710827 projectionSnapshotQuery: {
1083810828 getThreadShellById: () =>
10839 Effect.succeed(
10840 Option.some(
10841 makeDefaultOrchestrationThreadShell({
10842 id: threadId,
10829 Effect.succeedSome(
10830 makeDefaultOrchestrationThreadShell({
10831 id: threadId,
10832 updatedAt: now,
10833 session: {
10834 threadId,
10835 status: "stopped",
10836 providerName: "claudeAgent",
10837 runtimeMode: "full-access",
10838 activeTurnId: null,
10839 lastError: null,
1084310840 updatedAt: now,
10844 session: {
10845 threadId,
10846 status: "stopped",
10847 providerName: "claudeAgent",
10848 runtimeMode: "full-access",
10849 activeTurnId: null,
10850 lastError: null,
10851 updatedAt: now,
10852 },
10853 }),
10854 ),
10841 },
10842 }),
1085510843 ),
1085610844 },
1085710845 },
......@@ -10902,22 +10890,20 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
1090210890 },
1090310891 projectionSnapshotQuery: {
1090410892 getThreadShellById: () =>
10905 Effect.succeed(
10906 Option.some(
10907 makeDefaultOrchestrationThreadShell({
10908 id: threadId,
10893 Effect.succeedSome(
10894 makeDefaultOrchestrationThreadShell({
10895 id: threadId,
10896 updatedAt: now,
10897 session: {
10898 threadId,
10899 status: "ready",
10900 providerName: "claudeAgent",
10901 runtimeMode: "full-access",
10902 activeTurnId: null,
10903 lastError: null,
1090910904 updatedAt: now,
10910 session: {
10911 threadId,
10912 status: "ready",
10913 providerName: "claudeAgent",
10914 runtimeMode: "full-access",
10915 activeTurnId: null,
10916 lastError: null,
10917 updatedAt: now,
10918 },
10919 }),
10920 ),
10905 },
10906 }),
1092110907 ),
1092210908 },
1092310909 },
......@@ -11005,22 +10991,20 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
1100510991 },
1100610992 projectionSnapshotQuery: {
1100710993 getThreadShellById: () =>
11008 Effect.succeed(
11009 Option.some(
11010 makeDefaultOrchestrationThreadShell({
11011 id: threadId,
10994 Effect.succeedSome(
10995 makeDefaultOrchestrationThreadShell({
10996 id: threadId,
10997 updatedAt: now,
10998 session: {
10999 threadId,
11000 status: "ready",
11001 providerName: "claudeAgent",
11002 runtimeMode: "full-access",
11003 activeTurnId: null,
11004 lastError: null,
1101211005 updatedAt: now,
11013 session: {
11014 threadId,
11015 status: "ready",
11016 providerName: "claudeAgent",
11017 runtimeMode: "full-access",
11018 activeTurnId: null,
11019 lastError: null,
11020 updatedAt: now,
11021 },
11022 }),
11023 ),
11006 },
11007 }),
1102411008 ),
1102511009 },
1102611010 },
......@@ -11077,22 +11061,20 @@ it.layer(NodeServices.layer)("server router seam", (it) => {
1107711061 },
1107811062 projectionSnapshotQuery: {
1107911063 getThreadShellById: () =>
11080 Effect.succeed(
11081 Option.some(
11082 makeDefaultOrchestrationThreadShell({
11083 id: threadId,
11064 Effect.succeedSome(
11065 makeDefaultOrchestrationThreadShell({
11066 id: threadId,
11067 updatedAt: now,
11068 session: {
11069 threadId,
11070 status: "ready",
11071 providerName: "claudeAgent",
11072 runtimeMode: "full-access",
11073 activeTurnId: null,
11074 lastError: null,
1108411075 updatedAt: now,
11085 session: {
11086 threadId,
11087 status: "ready",
11088 providerName: "claudeAgent",
11089 runtimeMode: "full-access",
11090 activeTurnId: null,
11091 lastError: null,
11092 updatedAt: now,
11093 },
11094 }),
11095 ),
11076 },
11077 }),
1109611078 ),
1109711079 },
1109811080 },
apps/server/src/serverRuntimeStartup.reconcile.test.ts+39-49
......@@ -399,18 +399,16 @@ it.effect("does not continue archived or deleted marked sessions", () => {
399399 directory: {
400400 getBinding: (threadId) => {
401401 const thread = threadId === archived.id ? archived : deleted;
402 return Effect.succeed(
403 Option.some({
404 threadId,
405 provider: ProviderDriverKind.make("codex"),
406 providerInstanceId,
407 status: "running" as const,
408 resumeCursor: { cursor: threadId },
409 runtimePayload: {
410 continueAfterServerUpdate: thread.session.activeTurnId,
411 },
412 }),
413 );
402 return Effect.succeedSome({
403 threadId,
404 provider: ProviderDriverKind.make("codex"),
405 providerInstanceId,
406 status: "running" as const,
407 resumeCursor: { cursor: threadId },
408 runtimePayload: {
409 continueAfterServerUpdate: thread.session.activeTurnId,
410 },
411 });
414412 },
415413 upsert: () => Effect.void,
416414 recordImportedTranscript: () => Effect.die("unused"),
......@@ -456,18 +454,16 @@ it.effect("retries continuation preparation before settling a persistent failure
456454 threads: [thread],
457455 directory: {
458456 getBinding: () =>
459 Effect.succeed(
460 Option.some({
461 threadId: thread.id,
462 provider: ProviderDriverKind.make("codex"),
463 providerInstanceId,
464 status: "running" as const,
465 resumeCursor: { cursor: thread.id },
466 runtimePayload: {
467 continueAfterServerUpdate: thread.session.activeTurnId,
468 },
469 }),
470 ),
457 Effect.succeedSome({
458 threadId: thread.id,
459 provider: ProviderDriverKind.make("codex"),
460 providerInstanceId,
461 status: "running" as const,
462 resumeCursor: { cursor: thread.id },
463 runtimePayload: {
464 continueAfterServerUpdate: thread.session.activeTurnId,
465 },
466 }),
471467 upsert: () => Effect.void,
472468 recordImportedTranscript: () => Effect.die("unused"),
473469 getProvider: () => Effect.die("unused"),
......@@ -610,16 +606,14 @@ it.effect(
610606 directory: {
611607 getBinding: (candidate) =>
612608 candidate === absent.id
613 ? Effect.succeed(Option.none())
609 ? Effect.succeedNone
614610 : candidate === corrupt.id
615611 ? Effect.fail(corruptFailure)
616 : Effect.succeed(
617 Option.some({
618 threadId: candidate,
619 provider: ProviderDriverKind.make("codex"),
620 providerInstanceId,
621 }),
622 ),
612 : Effect.succeedSome({
613 threadId: candidate,
614 provider: ProviderDriverKind.make("codex"),
615 providerInstanceId,
616 }),
623617 upsert: () => Effect.fail(writeFailure),
624618 recordImportedTranscript: () => Effect.die("unused"),
625619 getProvider: () => Effect.die("unused"),
......@@ -657,7 +651,7 @@ it.effect("retries failed projections and continues after a persistent failure",
657651 return runReconciliation({
658652 threads: [transient, persistent, later],
659653 directory: {
660 getBinding: () => Effect.succeed(Option.none()),
654 getBinding: () => Effect.succeedNone,
661655 upsert: () => Effect.void,
662656 recordImportedTranscript: () => Effect.die("unused"),
663657 getProvider: () => Effect.die("unused"),
......@@ -758,19 +752,17 @@ for (const scenario of [
758752 continueAfterRestart: scenario !== "disabled",
759753 directory: {
760754 getBinding: () =>
761 Effect.succeed(
762 Option.some({
763 threadId: thread.id,
764 provider: ProviderDriverKind.make("codex"),
765 providerInstanceId,
766 status: scenario === "stopped binding" ? "stopped" : "running",
767 ...(scenario.includes("cursor") ? {} : { resumeCursor: { threadId: thread.id } }),
768 runtimePayload: {
769 activeTurnId: scenario === "marked superseded turn" ? "another-turn" : turnId,
770 ...(scenario.startsWith("marked") ? { continueAfterServerUpdate: turnId } : {}),
771 },
772 }),
773 ),
755 Effect.succeedSome({
756 threadId: thread.id,
757 provider: ProviderDriverKind.make("codex"),
758 providerInstanceId,
759 status: scenario === "stopped binding" ? "stopped" : "running",
760 ...(scenario.includes("cursor") ? {} : { resumeCursor: { threadId: thread.id } }),
761 runtimePayload: {
762 activeTurnId: scenario === "marked superseded turn" ? "another-turn" : turnId,
763 ...(scenario.startsWith("marked") ? { continueAfterServerUpdate: turnId } : {}),
764 },
765 }),
774766 upsert: (binding) =>
775767 Effect.sync(() => {
776768 upserts.push(binding);
......@@ -944,9 +936,7 @@ it.effect("settles failed opt-in recovery without retrying the provider turn", (
944936 Effect.gen(function* () {
945937 sends.push(input);
946938 preparedPayloads.push(binding.runtimePayload);
947 return yield* Effect.fail(
948 new ProviderSessionNotFoundError({ threadId: input.threadId }),
949 );
939 return yield* new ProviderSessionNotFoundError({ threadId: input.threadId });
950940 }),
951941 },
952942 directory: {
apps/server/src/serverRuntimeStartup.test.ts+26-28
......@@ -174,27 +174,25 @@ it.effect("resolveAutoBootstrapWelcomeTargets returns existing project and threa
174174 getCounts: () => Effect.die("unused"),
175175 getEventReplayStats: () => Effect.die("unused"),
176176 getActiveProjectByWorkspaceRoot: () =>
177 Effect.succeed(
178 Option.some({
179 id: bootstrapProjectId,
180 title: "Startup Project",
181 workspaceRoot: "/tmp/startup-project",
182 defaultModelSelection: {
183 instanceId: ProviderInstanceId.make("codex"),
184 model: DEFAULT_MODEL,
185 },
186 scripts: [],
187 createdAt: "2026-01-01T00:00:00.000Z",
188 updatedAt: "2026-01-01T00:00:00.000Z",
189 deletedAt: null,
190 }),
191 ),
177 Effect.succeedSome({
178 id: bootstrapProjectId,
179 title: "Startup Project",
180 workspaceRoot: "/tmp/startup-project",
181 defaultModelSelection: {
182 instanceId: ProviderInstanceId.make("codex"),
183 model: DEFAULT_MODEL,
184 },
185 scripts: [],
186 createdAt: "2026-01-01T00:00:00.000Z",
187 updatedAt: "2026-01-01T00:00:00.000Z",
188 deletedAt: null,
189 }),
192190 getProjectShells: () => Effect.die("unused"),
193191 getProjectShellById: () => Effect.die("unused"),
194 getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.some(bootstrapThreadId)),
192 getFirstActiveThreadIdByProjectId: () => Effect.succeedSome(bootstrapThreadId),
195193 getImportedAgentSessionSources: () => Effect.die("unused"),
196 getThreadCheckpointContext: () => Effect.succeed(Option.none()),
197 getFullThreadDiffContext: () => Effect.succeed(Option.none()),
194 getThreadCheckpointContext: () => Effect.succeedNone,
195 getFullThreadDiffContext: () => Effect.succeedNone,
198196 getThreadRuntimeContext: () => Effect.die("unused"),
199197 getTurnStartMessage: () => Effect.die("unused"),
200198 getThreadShellById: () => Effect.die("unused"),
......@@ -321,10 +319,10 @@ it.effect.each([
321319 ),
322320 getProjectShells: () => Effect.die("unused"),
323321 getProjectShellById: () => Effect.die("unused"),
324 getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()),
322 getFirstActiveThreadIdByProjectId: () => Effect.succeedNone,
325323 getImportedAgentSessionSources: () => Effect.die("unused"),
326 getThreadCheckpointContext: () => Effect.succeed(Option.none()),
327 getFullThreadDiffContext: () => Effect.succeed(Option.none()),
324 getThreadCheckpointContext: () => Effect.succeedNone,
325 getFullThreadDiffContext: () => Effect.succeedNone,
328326 getThreadRuntimeContext: () => Effect.die("unused"),
329327 getTurnStartMessage: () => Effect.die("unused"),
330328 getThreadShellById: () => Effect.die("unused"),
......@@ -391,13 +389,13 @@ it.effect(
391389 getSnapshotSequence: () => Effect.die("unused"),
392390 getCounts: () => Effect.die("unused"),
393391 getEventReplayStats: () => Effect.die("unused"),
394 getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()),
392 getActiveProjectByWorkspaceRoot: () => Effect.succeedNone,
395393 getProjectShells: () => Effect.die("unused"),
396394 getProjectShellById: () => Effect.die("unused"),
397395 getFirstActiveThreadIdByProjectId: () => Effect.die("thread lookup failed"),
398396 getImportedAgentSessionSources: () => Effect.die("unused"),
399 getThreadCheckpointContext: () => Effect.succeed(Option.none()),
400 getFullThreadDiffContext: () => Effect.succeed(Option.none()),
397 getThreadCheckpointContext: () => Effect.succeedNone,
398 getFullThreadDiffContext: () => Effect.succeedNone,
401399 getThreadRuntimeContext: () => Effect.die("unused"),
402400 getTurnStartMessage: () => Effect.die("unused"),
403401 getThreadShellById: () => Effect.die("unused"),
......@@ -456,13 +454,13 @@ it.effect("resolveAutoBootstrapWelcomeTargets preserves typed UUID generation fa
456454 getSnapshotSequence: () => Effect.die("unused"),
457455 getCounts: () => Effect.die("unused"),
458456 getEventReplayStats: () => Effect.die("unused"),
459 getActiveProjectByWorkspaceRoot: () => Effect.succeed(Option.none()),
457 getActiveProjectByWorkspaceRoot: () => Effect.succeedNone,
460458 getProjectShells: () => Effect.die("unused"),
461459 getProjectShellById: () => Effect.die("unused"),
462 getFirstActiveThreadIdByProjectId: () => Effect.succeed(Option.none()),
460 getFirstActiveThreadIdByProjectId: () => Effect.succeedNone,
463461 getImportedAgentSessionSources: () => Effect.die("unused"),
464 getThreadCheckpointContext: () => Effect.succeed(Option.none()),
465 getFullThreadDiffContext: () => Effect.succeed(Option.none()),
462 getThreadCheckpointContext: () => Effect.succeedNone,
463 getFullThreadDiffContext: () => Effect.succeedNone,
466464 getThreadRuntimeContext: () => Effect.die("unused"),
467465 getTurnStartMessage: () => Effect.die("unused"),
468466 getThreadShellById: () => Effect.die("unused"),
apps/server/src/serverRuntimeStartup.ts+45-49
......@@ -264,13 +264,13 @@ export const resolveAutoBootstrapWelcomeTargets = Effect.gen(function* () {
264264 bootstrapThreadId = existingThreadId.value;
265265 }
266266 }).pipe(
267 Effect.catchCause((cause) =>
268 Cause.hasInterrupts(cause)
269 ? Effect.failCause(cause)
270 : Effect.logWarning("startup thread auto-bootstrap failed", {
271 bootstrapProjectId: nextProjectId,
272 cause,
273 }),
267 Effect.catchCauseIf(
268 (cause) => !Cause.hasInterrupts(cause),
269 (cause) =>
270 Effect.logWarning("startup thread auto-bootstrap failed", {
271 bootstrapProjectId: nextProjectId,
272 cause,
273 }),
274274 ),
275275 );
276276 });
......@@ -312,11 +312,9 @@ const resolveStartupBrowserTarget = Effect.gen(function* () {
312312 ? `http://${formatHostForUrl(serverConfig.host)}:${serverConfig.port}`
313313 : localUrl;
314314 const baseTarget = serverConfig.devUrl?.toString() ?? bindUrl;
315 return yield* Effect.succeed(serverConfig.mode === "desktop" ? baseTarget : undefined).pipe(
316 Effect.flatMap((target) =>
317 target ? Effect.succeed(target) : serverAuth.issueStartupPairingUrl(baseTarget),
318 ),
319 );
315 return serverConfig.mode === "desktop"
316 ? baseTarget
317 : yield* serverAuth.issueStartupPairingUrl(baseTarget);
320318});
321319
322320const maybeOpenBrowser = (target: string) =>
......@@ -487,7 +485,7 @@ export const reconcileProviderSessions = Effect.gen(function* () {
487485 const query = yield* ProjectionSnapshotQuery.ProjectionSnapshotQuery;
488486 const settings = yield* ServerSettings.ServerSettingsService;
489487 const restartSettings = yield* settings.getSettings.pipe(
490 Effect.map(Option.some),
488 Effect.asSome,
491489 Effect.catch((cause) =>
492490 Effect.logWarning("could not read restart continuation preference", { cause }).pipe(
493491 Effect.as(Option.none()),
......@@ -549,13 +547,13 @@ export const reconcileProviderSessions = Effect.gen(function* () {
549547 continue;
550548 }
551549 const binding = yield* directory.getBinding(thread.id).pipe(
552 Effect.catchCause((cause) =>
553 Cause.hasInterrupts(cause)
554 ? Effect.failCause(cause)
555 : Effect.logWarning("failed to read orphaned provider session directory binding", {
556 threadId: thread.id,
557 cause,
558 }).pipe(Effect.as(Option.none())),
550 Effect.catchCauseIf(
551 (cause) => !Cause.hasInterrupts(cause),
552 (cause) =>
553 Effect.logWarning("failed to read orphaned provider session directory binding", {
554 threadId: thread.id,
555 cause,
556 }).pipe(Effect.as(Option.none())),
559557 ),
560558 );
561559 const continuationMarkerPresent =
......@@ -606,13 +604,13 @@ export const reconcileProviderSessions = Effect.gen(function* () {
606604 });
607605 }
608606 }).pipe(
609 Effect.catchCause((cause) =>
610 Cause.hasInterrupts(cause)
611 ? Effect.failCause(cause)
612 : Effect.logWarning(
613 "failed to reconcile orphaned provider session directory binding",
614 { threadId: thread.id, cause },
615 ),
607 Effect.catchCauseIf(
608 (cause) => !Cause.hasInterrupts(cause),
609 (cause) =>
610 Effect.logWarning("failed to reconcile orphaned provider session directory binding", {
611 threadId: thread.id,
612 cause,
613 }),
616614 ),
617615 );
618616
......@@ -633,13 +631,13 @@ export const reconcileProviderSessions = Effect.gen(function* () {
633631 });
634632 }).pipe(
635633 Effect.retry({ times: 1 }),
636 Effect.catchCause((cause) =>
637 Cause.hasInterrupts(cause)
638 ? Effect.failCause(cause)
639 : Effect.logWarning("failed to settle orphaned provider session projection", {
640 threadId: thread.id,
641 cause,
642 }),
634 Effect.catchCauseIf(
635 (cause) => !Cause.hasInterrupts(cause),
636 (cause) =>
637 Effect.logWarning("failed to settle orphaned provider session projection", {
638 threadId: thread.id,
639 cause,
640 }),
643641 ),
644642 );
645643 });
......@@ -739,10 +737,9 @@ export const reconcileProviderSessions = Effect.gen(function* () {
739737 yield* settleAsError(ORPHANED_PROVIDER_SESSION_ERROR);
740738 }
741739}).pipe(
742 Effect.catchCause((cause) =>
743 Cause.hasInterrupts(cause)
744 ? Effect.failCause(cause)
745 : Effect.logWarning("provider session startup reconciliation failed", { cause }),
740 Effect.catchCauseIf(
741 (cause) => !Cause.hasInterrupts(cause),
742 (cause) => Effect.logWarning("provider session startup reconciliation failed", { cause }),
746743 ),
747744);
748745
......@@ -813,21 +810,20 @@ export const reconcileWorktreeSetups = Effect.gen(function* () {
813810 createdAt: interruptedAt,
814811 })
815812 .pipe(
816 Effect.catchCause((cause) =>
817 Cause.hasInterrupts(cause)
818 ? Effect.failCause(cause)
819 : Effect.logWarning("failed to settle interrupted worktree setup", {
820 threadId,
821 cause,
822 }),
813 Effect.catchCauseIf(
814 (cause) => !Cause.hasInterrupts(cause),
815 (cause) =>
816 Effect.logWarning("failed to settle interrupted worktree setup", {
817 threadId,
818 cause,
819 }),
823820 ),
824821 );
825822 }
826823}).pipe(
827 Effect.catchCause((cause) =>
828 Cause.hasInterrupts(cause)
829 ? Effect.failCause(cause)
830 : Effect.logWarning("worktree setup startup reconciliation failed", { cause }),
824 Effect.catchCauseIf(
825 (cause) => !Cause.hasInterrupts(cause),
826 (cause) => Effect.logWarning("worktree setup startup reconciliation failed", { cause }),
831827 ),
832828);
833829
apps/server/src/serverRuntimeState.ts+2-2
......@@ -142,7 +142,7 @@ export const readPersistedServerRuntimeState = (path: string) =>
142142 cause,
143143 }),
144144 ),
145 onSuccess: (contents) => Effect.succeed(Option.some(contents)),
145 onSuccess: (contents) => Effect.succeedSome(contents),
146146 }),
147147 );
148148 if (Option.isNone(raw)) {
......@@ -155,7 +155,7 @@ export const readPersistedServerRuntimeState = (path: string) =>
155155 }
156156
157157 return yield* decodePersistedServerRuntimeState(trimmed).pipe(
158 Effect.map(Option.some),
158 Effect.asSome,
159159 Effect.mapError(
160160 (cause) =>
161161 new ServerRuntimeStateError({
apps/server/src/sourceControl/GitHubCli.test.ts+3-3
......@@ -155,8 +155,9 @@ describe("GitHubCli.layer", () => {
155155 capacity: 2,
156156 timeToLive: "1 minute",
157157 });
158 const results = yield* Effect.all(
159 ["github.com", "github.example.test"].map((host, index) =>
158 const results = yield* Effect.forEach(
159 ["github.com", "github.example.test"],
160 (host, index) =>
160161 Cache.get(cache, host).pipe(
161162 Effect.provideService(GitHubCli.PinnedGitHubCredential, {
162163 host,
......@@ -164,7 +165,6 @@ describe("GitHubCli.layer", () => {
164165 credentialFingerprint: `fingerprint-${index}`,
165166 }),
166167 ),
167 ),
168168 { concurrency: 2 },
169169 );
170170 expect(results.map((result) => result.stdout)).toEqual(["credential-0", "credential-1"]);
apps/server/src/sourceControl/SourceControlProviderRegistry.ts+3-3
......@@ -289,14 +289,14 @@ export const makeWithProviders = Effect.fn("makeSourceControlProviderRegistryWit
289289 get,
290290 resolveHandle,
291291 resolve: (input) => resolveHandle(input).pipe(Effect.map((handle) => handle.provider)),
292 discover: Effect.all(
293 discoverySpecs.map((spec) =>
292 discover: Effect.forEach(
293 discoverySpecs,
294 (spec) =>
294295 probeSourceControlProvider({
295296 spec,
296297 process,
297298 cwd: config.cwd,
298299 }),
299 ),
300300 { concurrency: "unbounded" },
301301 ),
302302 });
apps/server/src/storageCleanup.ts+3-4
......@@ -419,10 +419,9 @@ export const make = Effect.gen(function* () {
419419 });
420420 const worker = yield* makeDrainableWorker(() =>
421421 sweep().pipe(
422 Effect.catchCause((cause) =>
423 Cause.hasInterruptsOnly(cause)
424 ? Effect.failCause(cause)
425 : Effect.logWarning("storage cleanup failed", { cause }),
422 Effect.catchCauseIf(
423 (cause) => !Cause.hasInterruptsOnly(cause),
424 (cause) => Effect.logWarning("storage cleanup failed", { cause }),
426425 ),
427426 ),
428427 );
apps/server/src/telemetry/Identify.ts+2-2
......@@ -132,7 +132,7 @@ const readIdentityFile = (
132132 filePath: string,
133133) =>
134134 fileSystem.readFileString(filePath).pipe(
135 Effect.map(Option.some),
135 Effect.asSome,
136136 Effect.catchTags({
137137 PlatformError: (cause) =>
138138 isNotFoundError(cause)
......@@ -278,7 +278,7 @@ export const getTelemetryIdentifierForHome = Effect.fn("getTelemetryIdentifierFo
278278 }
279279
280280 const anonymousId = yield* upsertAnonymousId.pipe(
281 Effect.map(Option.some),
281 Effect.asSome,
282282 Effect.catchTags({
283283 TelemetryIdentityReadError: (error) =>
284284 logTelemetryIdentityError(error).pipe(Effect.as(Option.none<string>())),
apps/server/src/terminal/Manager.ts+3-12
......@@ -1934,16 +1934,7 @@ export const makeWithOptions = Effect.fn("TerminalManager.makeWithOptions")(func
19341934 terminalId: string,
19351935 ): Effect.fn.Return<TerminalSessionState, TerminalSessionLookupError> {
19361936 return yield* Effect.flatMap(getSession(threadId, terminalId), (session) =>
1937 Option.match(session, {
1938 onNone: () =>
1939 Effect.fail(
1940 new TerminalSessionLookupError({
1941 threadId,
1942 terminalId,
1943 }),
1944 ),
1945 onSome: Effect.succeed,
1946 }),
1937 Effect.fromOption(session, () => new TerminalSessionLookupError({ threadId, terminalId })),
19471938 );
19481939 });
19491940
......@@ -2367,7 +2358,7 @@ export const makeWithOptions = Effect.fn("TerminalManager.makeWithOptions")(func
23672358 }
23682359
23692360 const inspectorOption = yield* acquireSubprocessInspector.pipe(
2370 Effect.map(Option.some),
2361 Effect.asSome,
23712362 Effect.catch((reason) =>
23722363 Effect.logWarning("failed to snapshot processes for terminal subprocess polling", {
23732364 reason,
......@@ -2393,7 +2384,7 @@ export const makeWithOptions = Effect.fn("TerminalManager.makeWithOptions")(func
23932384 ) {
23942385 const terminalPid = session.pid;
23952386 const inspectResult = yield* subprocessInspector(terminalPid).pipe(
2396 Effect.map(Option.some),
2387 Effect.asSome,
23972388 Effect.catch((reason) =>
23982389 Effect.logWarning("failed to check terminal subprocess activity", {
23992390 threadId: session.threadId,
apps/server/src/textGeneration/AntigravityTextGeneration.ts+1-1
......@@ -238,7 +238,7 @@ export const makeAntigravityTextGeneration = Effect.fn("makeAntigravityTextGener
238238 yield* applyAntigravityAcpModelSelection({
239239 runtime,
240240 model: input.modelSelection.model,
241 defaultModel: yield* options.defaultModel ?? Effect.succeed(undefined),
241 defaultModel: yield* options.defaultModel ?? Effect.undefined,
242242 mapError: (cause) =>
243243 new TextGenerationError({
244244 operation,
apps/server/src/textGeneration/CodexTextGeneration.test.ts+2-2
......@@ -556,7 +556,7 @@ it.layer(CodexTextGenerationTestLayer)("CodexTextGeneration", (it) => {
556556 }),
557557 ),
558558 ),
559 Effect.ensuring(fs.remove(imagePath).pipe(Effect.catch(() => Effect.void))),
559 Effect.ensuring(fs.remove(imagePath).pipe(Effect.ignore)),
560560 );
561561
562562 expect(generated.branch).toBe("fix/ui-regression");
......@@ -579,7 +579,7 @@ it.layer(CodexTextGenerationTestLayer)("CodexTextGeneration", (it) => {
579579 const { attachmentsDir } = yield* ServerConfig.ServerConfig;
580580 const missingAttachmentId = "thread-missing-attachment";
581581 const missingPath = path.join(attachmentsDir, `${missingAttachmentId}.png`);
582 yield* fs.remove(missingPath).pipe(Effect.catch(() => Effect.void));
582 yield* fs.remove(missingPath).pipe(Effect.ignore);
583583
584584 const result = yield* textGeneration
585585 .generateBranchName({
apps/server/src/textGeneration/CodexTextGeneration.ts+4-3
......@@ -96,7 +96,7 @@ export const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(func
9696 );
9797
9898 const safeUnlink = (filePath: string): Effect.Effect<void, never> =>
99 fileSystem.remove(filePath).pipe(Effect.catch(() => Effect.void));
99 fileSystem.remove(filePath).pipe(Effect.ignore);
100100
101101 const encodeJsonForOperation = (
102102 operation:
......@@ -263,8 +263,9 @@ export const makeCodexTextGeneration = Effect.fn("makeCodexTextGeneration")(func
263263 }
264264 });
265265
266 const cleanup = Effect.all(
267 [schemaPath, outputPath, ...cleanupPaths].map((filePath) => safeUnlink(filePath)),
266 const cleanup = Effect.forEach(
267 [schemaPath, outputPath, ...cleanupPaths],
268 (filePath) => safeUnlink(filePath),
268269 {
269270 concurrency: "unbounded",
270271 },
apps/server/src/textGeneration/ThreadTitleLinks.ts+4-7
......@@ -14,12 +14,9 @@ export const resolveThreadTitleLinks = Effect.fn("resolveThreadTitleLinks")(func
1414 const providers = yield* SourceControlProviderRegistry.SourceControlProviderRegistry;
1515 const links = new Map<string, NonNullable<ReturnType<typeof providers.resolveLink>>>();
1616 for (const match of input.message.matchAll(/https:\/\/[^\s<>"')\]`]+/g)) {
17 let url: URL;
18 try {
19 url = new URL(match[0].replace(/[.,;!?]+$/, ""));
20 } catch {
21 continue;
22 }
17 const candidate = match[0].replace(/[.,;!?]+$/, "");
18 if (!URL.canParse(candidate)) continue;
19 const url = new URL(candidate);
2320 url.hash = "";
2421 url.search = "";
2522 if (links.has(url.href)) continue;
......@@ -40,7 +37,7 @@ export const resolveThreadTitleLinks = Effect.fn("resolveThreadTitleLinks")(func
4037 ),
4138 Effect.map((summary) => `${url}\n${summary}`),
4239 Effect.timeout("3 seconds"),
43 Effect.catch(() => Effect.succeed(`${url}: unavailable`)),
40 Effect.orElseSucceed(() => `${url}: unavailable`),
4441 ),
4542 { concurrency: 2 },
4643 );
apps/server/src/usage/UsageService.ts+2-2
......@@ -225,7 +225,7 @@ export const make = Effect.gen(function* () {
225225
226226 yield* encodeRatesCache({ fetchedAtMs: now, document: fetched }).pipe(
227227 Effect.flatMap((serialized) => fileSystem.writeFileString(ratesCachePath, serialized)),
228 Effect.catchCause(() => Effect.void),
228 Effect.ignoreCause,
229229 );
230230 });
231231
......@@ -372,7 +372,7 @@ export const make = Effect.gen(function* () {
372372 cacheDirty = false;
373373 }),
374374 // A cache we cannot write is a slower next start, not a failed read.
375 Effect.catchCause(() => Effect.void),
375 Effect.ignoreCause,
376376 );
377377 });
378378
apps/server/src/vcs/GitVcsDriver.ts+1-1
......@@ -1101,7 +1101,7 @@ export const makeVcsDriverShape = Effect.fn("makeGitVcsDriverShape")(function* (
11011101 /^warning: failed to remove \.\/: [^\n]+$/.test(cleaned.stderr.trim()) &&
11021102 (yield* fileSystem.readDirectory(input.cwd).pipe(
11031103 Effect.map((entries) => entries.length === 0),
1104 Effect.catch(() => Effect.succeed(false)),
1104 Effect.orElseSucceed(() => false),
11051105 ));
11061106 if (!emptiedWorkspace)
11071107 return yield* new VcsProcessExitError({
apps/server/src/vcs/GitVcsDriverCore.ts+12-17
......@@ -946,16 +946,14 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*
946946 return yield* execution.pipe(
947947 Effect.timeoutOption(timeoutMs),
948948 Effect.flatMap((result) =>
949 Option.match(result, {
950 onNone: () =>
951 Effect.fail(
952 new GitCommandError({
953 ...gitCommandContext(commandInput),
954 detail: "Git command timed out.",
955 }),
956 ),
957 onSome: Effect.succeed,
958 }),
949 Effect.fromOption(
950 result,
951 () =>
952 new GitCommandError({
953 ...gitCommandContext(commandInput),
954 detail: "Git command timed out.",
955 }),
956 ),
959957 ),
960958 );
961959 },
......@@ -1004,11 +1002,9 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*
10041002 : {}),
10051003 ...(options.progress ? { progress: options.progress } : {}),
10061004 }).pipe(
1007 Effect.flatMap((result) => {
1008 if (options.allowNonZeroExit || result.exitCode === 0) {
1009 return Effect.succeed(result);
1010 }
1011 return Effect.fail(
1005 Effect.filterOrFail(
1006 (result) => options.allowNonZeroExit || result.exitCode === 0,
1007 (result) =>
10121008 new GitCommandError({
10131009 ...gitCommandContext({ operation, cwd, args }),
10141010 detail: options.fallbackErrorDetail ?? "Git command exited with a non-zero status.",
......@@ -1016,8 +1012,7 @@ export const makeGitVcsDriverCore = Effect.fn("makeGitVcsDriverCore")(function*
10161012 stdoutLength: result.stdout.length,
10171013 stderrLength: result.stderr.length,
10181014 }),
1019 );
1020 }),
1015 ),
10211016 );
10221017
10231018 const executeGitWithStableDiagnostics = (
apps/server/src/vcs/VcsStatusBroadcaster.ts+3-3
......@@ -541,13 +541,13 @@ export const make = Effect.gen(function* () {
541541 const demandCwds = yield* Ref.get(demandCwdsRef);
542542 const shouldRun =
543543 needsInitialRefresh ||
544 (yield* Effect.all(
545 [...demandCwds.keys()].map((demandCwd) =>
544 (yield* Effect.forEach(
545 [...demandCwds.keys()],
546 (demandCwd) =>
546547 backgroundPolicy.shouldRunScopeWork({
547548 type: "vcs-status",
548549 cwd: demandCwd,
549550 }),
550 ),
551551 { concurrency: "unbounded" },
552552 )).some(Boolean);
553553 if (!shouldRun) {
apps/server/src/ws.ts+12-16
......@@ -854,27 +854,23 @@ const makeWsRpcLayer = (
854854 case "project.meta-updated":
855855 return projectUpsertOrRemove(ProjectId.make(event.aggregateId), event.sequence);
856856 case "project.deleted":
857 return Effect.succeed(
858 Option.some({
859 kind: "project-removed" as const,
860 sequence: event.sequence,
861 projectId: ProjectId.make(event.aggregateId),
862 }),
863 );
857 return Effect.succeedSome({
858 kind: "project-removed" as const,
859 sequence: event.sequence,
860 projectId: ProjectId.make(event.aggregateId),
861 });
864862 case "thread.deleted":
865863 case "thread.archived":
866 return Effect.succeed(
867 Option.some({
868 kind: "thread-removed" as const,
869 sequence: event.sequence,
870 threadId: ThreadId.make(event.aggregateId),
871 }),
872 );
864 return Effect.succeedSome({
865 kind: "thread-removed" as const,
866 sequence: event.sequence,
867 threadId: ThreadId.make(event.aggregateId),
868 });
873869 case "thread.unarchived":
874870 return threadUpsertOrRemove(ThreadId.make(event.aggregateId), event.sequence);
875871 default:
876872 if (event.aggregateKind !== "thread") {
877 return Effect.succeed(Option.none());
873 return Effect.succeedNone;
878874 }
879875 return threadUpsertOrRemove(ThreadId.make(event.aggregateId), event.sequence);
880876 }
......@@ -892,7 +888,7 @@ const makeWsRpcLayer = (
892888 ): Effect.Effect<Option.Option<A>, never, never> =>
893889 read.pipe(
894890 Effect.retry({ times: 1 }),
895 Effect.map(Option.some),
891 Effect.asSome,
896892 Effect.tapError((error) =>
897893 Effect.logWarning("orchestration shell projection refetch failed", {
898894 aggregateKind,
apps/web/src/connection/platform.ts+1-1
......@@ -213,7 +213,7 @@ const capabilitiesLayer = Layer.effectContext(
213213 }),
214214 });
215215 const identity = RelayDeviceIdentity.of({
216 deviceId: Effect.succeed(Option.none()),
216 deviceId: Effect.succeedNone,
217217 });
218218 const primaryAuth = PrimaryEnvironmentAuth.of({
219219 bearerToken: Effect.tryPromise({
apps/web/src/connection/storage.ts+4-4
......@@ -587,7 +587,7 @@ export const connectionStorageLayer = Layer.effectContext(
587587 Effect.tap(() => Effect.promise(() => projectFaviconCache.hydrate())),
588588 Effect.flatMap((raw) => {
589589 if (typeof raw !== "string") {
590 return Effect.succeed(Option.none());
590 return Effect.succeedNone;
591591 }
592592 return decodeStoredShellSnapshot(raw).pipe(
593593 Effect.mapError((cause) => persistenceError("load-shell", cause)),
......@@ -623,7 +623,7 @@ export const connectionStorageLayer = Layer.effectContext(
623623 readDatabaseValue(database, SERVER_CONFIG_STORE_NAME, environmentId).pipe(
624624 Effect.flatMap((raw) => {
625625 if (typeof raw !== "string") {
626 return Effect.succeed(Option.none());
626 return Effect.succeedNone;
627627 }
628628 return decodeStoredServerConfig(raw).pipe(
629629 Effect.mapError((cause) => persistenceError("load-server-config", cause)),
......@@ -661,7 +661,7 @@ export const connectionStorageLayer = Layer.effectContext(
661661 ).pipe(
662662 Effect.flatMap((raw) => {
663663 if (typeof raw !== "string") {
664 return Effect.succeed(Option.none());
664 return Effect.succeedNone;
665665 }
666666 return decodeStoredThreadSnapshot(raw).pipe(
667667 Effect.mapError((cause) => persistenceError("load-thread", cause)),
......@@ -703,7 +703,7 @@ export const connectionStorageLayer = Layer.effectContext(
703703 readDatabaseValue(database, VCS_REFS_STORE_NAME, vcsRefsCacheKey(environmentId, cwd)).pipe(
704704 Effect.flatMap((raw) => {
705705 if (typeof raw !== "string") {
706 return Effect.succeed(Option.none());
706 return Effect.succeedNone;
707707 }
708708 return decodeStoredVcsRefs(raw).pipe(
709709 Effect.mapError((cause) => persistenceError("load-vcs-refs", cause)),
infra/relay/src/agentActivity/LiveActivities.test.ts+3-2
......@@ -276,7 +276,7 @@ describe("LiveActivities", () => {
276276 liveActivities.register({ userId: "user-1", registration }),
277277 );
278278 const targetListError = yield* Effect.flip(liveActivities.listTargets({ userId: "user-1" }));
279 const deliveryErrors = yield* Effect.all(
279 const deliveryErrors = yield* Effect.forEach(
280280 [
281281 liveActivities.markDelivery({
282282 userId: "user-1",
......@@ -297,7 +297,8 @@ describe("LiveActivities", () => {
297297 kind: "push_notification",
298298 invalidatedAt: "2026-05-25T00:00:10.000Z",
299299 }),
300 ].map(Effect.flip),
300 ],
301 (effect) => Effect.flip(effect),
301302 { concurrency: 1 },
302303 );
303304
infra/relay/src/clientConfig.test.ts+7-31
......@@ -82,13 +82,7 @@ describe("PublishClientConfig", () => {
8282 ),
8383 );
8484
85 yield* stack
86 .deploy(
87 Effect.gen(function* () {
88 return yield* PublishClientConfig(clientConfig("v1"));
89 }),
90 )
91 .pipe(configured);
85 yield* stack.deploy(PublishClientConfig(clientConfig("v1"))).pipe(configured);
9286 const first = yield* fs.readFileString(target);
9387 expect(first).toContain("KEEP=yes\n");
9488 expect(first).toContain("T3CODE_RELAY_URL=https://relay.example.com\n");
......@@ -97,23 +91,11 @@ describe("PublishClientConfig", () => {
9791
9892 // Same input: the action is skipped, so a change made by hand survives.
9993 yield* fs.writeFileString(target, `${first}MANUAL=1\n`);
100 yield* stack
101 .deploy(
102 Effect.gen(function* () {
103 return yield* PublishClientConfig(clientConfig("v1"));
104 }),
105 )
106 .pipe(configured);
94 yield* stack.deploy(PublishClientConfig(clientConfig("v1"))).pipe(configured);
10795 expect(yield* fs.readFileString(target)).toContain("MANUAL=1\n");
10896
10997 // A rotated token changes the input, so it runs again and replaces the line.
110 yield* stack
111 .deploy(
112 Effect.gen(function* () {
113 return yield* PublishClientConfig(clientConfig("v2"));
114 }),
115 )
116 .pipe(configured);
98 yield* stack.deploy(PublishClientConfig(clientConfig("v2"))).pipe(configured);
11799 const third = yield* fs.readFileString(target);
118100 expect(third).toContain("T3CODE_RELAY_CLIENT_OTLP_TRACES_TOKEN=client-v2\n");
119101 expect(third).not.toContain("client-v1");
......@@ -128,11 +110,7 @@ describe("PublishClientConfig", () => {
128110 const dir = yield* fs.makeTempDirectoryScoped({ prefix: "t3-relay-client-config-" });
129111 const target = path.join(dir, "client.env");
130112 const exit = yield* stack
131 .deploy(
132 Effect.gen(function* () {
133 return yield* PublishClientConfig({ ...clientConfig("v1"), url: undefined });
134 }),
135 )
113 .deploy(PublishClientConfig({ ...clientConfig("v1"), url: undefined }))
136114 .pipe(
137115 Effect.provide(
138116 ConfigProvider.layer(
......@@ -155,11 +133,9 @@ describe("PublishClientConfig", () => {
155133 const target = path.join(dir, "client.env");
156134 const exit = yield* stack
157135 .deploy(
158 Effect.gen(function* () {
159 return yield* PublishClientConfig({
160 ...clientConfig("v1"),
161 clientTracingDataset: "relay-traces\nINJECTED=1",
162 });
136 PublishClientConfig({
137 ...clientConfig("v1"),
138 clientTracingDataset: "relay-traces\nINJECTED=1",
163139 }),
164140 )
165141 .pipe(
infra/relay/src/environments/ManagedEndpointAllocations.ts+1-3
......@@ -567,9 +567,7 @@ export const make = Effect.gen(function* () {
567567 .pipe(
568568 Effect.mapError(lockError),
569569 Effect.flatMap((rows) =>
570 rows.length === 0
571 ? Effect.succeed(Option.none())
572 : effect.pipe(Effect.map(Option.some)),
570 rows.length === 0 ? Effect.succeedNone : Effect.asSome(effect),
573571 ),
574572 ),
575573 )
infra/relay/src/environments/ManagedEndpointProvider.test.ts+5-8
......@@ -6,7 +6,6 @@ import * as Alchemy from "alchemy";
66import * as Cloudflare from "alchemy/Cloudflare";
77import * as Effect from "effect/Effect";
88import * as Layer from "effect/Layer";
9import * as Option from "effect/Option";
109import * as Redacted from "effect/Redacted";
1110
1211import * as RelayConfiguration from "../Config.ts";
......@@ -302,8 +301,8 @@ function makeAllocations(calls: AllocationCall[] = []) {
302301 Effect.suspend(() => {
303302 const current = allocations.get(allocationKey(input));
304303 return current?.tunnelId === input.tunnelId && current.generation === input.generation
305 ? effect.pipe(Effect.map(Option.some))
306 : Effect.succeed(Option.none());
304 ? Effect.asSome(effect)
305 : Effect.succeedNone;
307306 }),
308307 claimDeprovision: (input) =>
309308 Effect.sync(() => {
......@@ -1189,7 +1188,7 @@ describe("ManagedEndpointProvider", () => {
11891188 const changed = ManagedEndpointAllocations.ManagedEndpointAllocations.of({
11901189 ...allocations,
11911190 withClaimedTunnel: (input, effect) =>
1192 loseClaim ? Effect.succeed(Option.none()) : allocations.withClaimedTunnel(input, effect),
1191 loseClaim ? Effect.succeedNone : allocations.withClaimedTunnel(input, effect),
11931192 });
11941193 const layer = providerLayer(makePersistentTunnelClient(), makeDnsClient(), changed);
11951194
......@@ -1320,7 +1319,7 @@ describe("ManagedEndpointProvider", () => {
13201319 const allocations = makeAllocations();
13211320 const changed = ManagedEndpointAllocations.ManagedEndpointAllocations.of({
13221321 ...allocations,
1323 withClaimedTunnel: () => Effect.succeed(Option.none()),
1322 withClaimedTunnel: () => Effect.succeedNone,
13241323 });
13251324 const layer = providerLayer(makePersistentTunnelClient(tunnelCalls), makeDnsClient(), changed);
13261325
......@@ -1349,9 +1348,7 @@ describe("ManagedEndpointProvider", () => {
13491348 const changed = ManagedEndpointAllocations.ManagedEndpointAllocations.of({
13501349 ...allocations,
13511350 withClaimedTunnel: (input, effect) =>
1352 ++lockCount === 1
1353 ? allocations.withClaimedTunnel(input, effect)
1354 : Effect.succeed(Option.none()),
1351 ++lockCount === 1 ? allocations.withClaimedTunnel(input, effect) : Effect.succeedNone,
13551352 });
13561353 const layer = providerLayer(makePersistentTunnelClient(), makeDnsClient(dnsCalls), changed);
13571354
infra/relay/src/environments/ManagedEndpointProvider.ts+17-16
......@@ -471,8 +471,9 @@ export const make = Effect.gen(function* () {
471471 ? updateExistingDnsRecords(records, preferredDnsRecordId, dnsRecord)
472472 : Effect.fail(createError),
473473 ),
474 Effect.flatMap((dnsRecordId) =>
475 dnsRecordId === null ? Effect.fail(createError) : Effect.succeed(dnsRecordId),
474 Effect.filterOrFail(
475 (dnsRecordId) => dnsRecordId !== null,
476 () => createError,
476477 ),
477478 ),
478479 }),
......@@ -578,19 +579,19 @@ export const make = Effect.gen(function* () {
578579 ? Effect.succeed("missing" as const)
579580 : Effect.fail(error),
580581 }),
581 Effect.flatMap((result) =>
582 result === "missing"
583 ? Effect.succeed(result)
584 : allocations
585 .markReady({
586 ...input,
587 generation: allocation.generation,
588 })
589 .pipe(
590 Effect.map((updated) =>
591 updated ? ("configured" as const) : ("stale" as const),
592 ),
582 Effect.filterOrElse(
583 (result): result is "missing" => result === "missing",
584 () =>
585 allocations
586 .markReady({
587 ...input,
588 generation: allocation.generation,
589 })
590 .pipe(
591 Effect.map((updated) =>
592 updated ? ("configured" as const) : ("stale" as const),
593593 ),
594 ),
594595 ),
595596 ),
596597 )
......@@ -791,11 +792,11 @@ export const make = Effect.gen(function* () {
791792 const expectedStatus = input.expectedStatus;
792793 const inactiveBefore = input.expectedInactiveBefore;
793794 const currentTunnel = yield* tunnels.get(tunnelId).pipe(
794 Effect.map(Option.some),
795 Effect.asSome,
795796 Effect.catchTags({
796797 ManagedEndpointTunnelClientError: (cause) =>
797798 isManagedEndpointNotFound(cause.cause)
798 ? Effect.succeed(Option.none())
799 ? Effect.succeedNone
799800 : Effect.fail(
800801 new ManagedEndpointDeprovisioningFailed({
801802 ...input,
packages/client-runtime/src/authorization/layer.test.ts+1-1
......@@ -199,7 +199,7 @@ const makeHarness = Effect.fn("TestRemoteAuthorization.makeHarness")(function* (
199199 clerkToken: input.clerkToken ?? Effect.succeed("clerk-session"),
200200 }),
201201 Layer.succeed(ClientCapabilities.RelayDeviceIdentity, {
202 deviceId: Effect.succeed(Option.some("device-1")),
202 deviceId: Effect.succeedSome("device-1"),
203203 }),
204204 Layer.succeed(TokenStore.RemoteDpopAccessTokenStore, tokenStore),
205205 Layer.succeed(
packages/client-runtime/src/connection/registry.test.ts+3-3
......@@ -275,12 +275,12 @@ const makeHarness = Effect.fn("TestEnvironmentRegistry.makeHarness")(function* (
275275 next.set(environmentId, snapshot);
276276 return next;
277277 }),
278 loadThread: (_environmentId, _threadId) => Effect.succeed(Option.none()),
278 loadThread: (_environmentId, _threadId) => Effect.succeedNone,
279279 saveThread: (_environmentId, _thread) => Effect.void,
280280 removeThread: (_environmentId, _threadId) => Effect.void,
281 loadServerConfig: () => Effect.succeed(Option.none()),
281 loadServerConfig: () => Effect.succeedNone,
282282 saveServerConfig: () => Effect.void,
283 loadVcsRefs: () => Effect.succeed(Option.none()),
283 loadVcsRefs: () => Effect.succeedNone,
284284 saveVcsRefs: () => Effect.void,
285285 removeVcsRefs: () => Effect.void,
286286 clearVcsRefs: () => Effect.void,
packages/client-runtime/src/connection/resolver.ts+6-8
......@@ -110,10 +110,9 @@ const makeBearerBroker = Effect.fn("clientRuntime.connection.broker.makeBearer")
110110 entry: ConnectionCatalogEntry & { readonly target: BearerConnectionTarget },
111111 ) {
112112 const target = entry.target;
113 const profile = yield* Option.match(entry.profile, {
114 onNone: () => Effect.fail(profileMissingError(target.connectionId)),
115 onSome: Effect.succeed,
116 });
113 const profile = yield* Effect.fromOption(entry.profile, () =>
114 profileMissingError(target.connectionId),
115 );
117116 if (!isBearerProfile(profile)) {
118117 return yield* new ConnectionBlockedError({
119118 reason: "configuration",
......@@ -186,10 +185,9 @@ const makeSshBroker = Effect.fn("clientRuntime.connection.broker.makeSsh")(funct
186185 entry: ConnectionCatalogEntry & { readonly target: SshConnectionTarget },
187186 ) {
188187 const target = entry.target;
189 const profile = yield* Option.match(entry.profile, {
190 onNone: () => Effect.fail(profileMissingError(target.connectionId)),
191 onSome: Effect.succeed,
192 });
188 const profile = yield* Effect.fromOption(entry.profile, () =>
189 profileMissingError(target.connectionId),
190 );
193191 if (!isSshProfile(profile)) {
194192 return yield* new ConnectionBlockedError({
195193 reason: "configuration",
packages/client-runtime/src/connection/supervisor.test.ts+2-2
......@@ -1290,11 +1290,11 @@ describe("EnvironmentSupervisor", () => {
12901290 Layer.succeed(ManagedRelayDpopSigner, signer),
12911291 Layer.succeed(ManagedRelayClient, relay),
12921292 Layer.succeed(ClientCapabilities.CloudSession, {
1293 identity: Effect.succeed(Option.some({ accountId: "test-account" })),
1293 identity: Effect.succeedSome({ accountId: "test-account" }),
12941294 clerkToken: Effect.succeed("clerk-token"),
12951295 }),
12961296 Layer.succeed(ClientCapabilities.RelayDeviceIdentity, {
1297 deviceId: Effect.succeed(Option.none()),
1297 deviceId: Effect.succeedNone,
12981298 }),
12991299 TokenStore.layer({
13001300 get: () => Ref.get(token),
packages/client-runtime/src/connection/supervisor.ts+1
......@@ -606,6 +606,7 @@ export const make = Effect.fn("EnvironmentSupervisor.make")(function* (
606606 }, Effect.ensuring(clearLease));
607607
608608 const waitForRetrySignal = Effect.fnUntraced(function* (delayMs: number) {
609 // @effect-diagnostics-next-line raceFirstWithSleepToTimeout:off - the sleep is the retry delay (false), not a timeout around the signal loop
609610 return yield* Effect.raceFirst(
610611 Effect.sleep(delayMs).pipe(Effect.as(false)),
611612 Effect.gen(function* () {
packages/client-runtime/src/platform/storageDocument.test.ts+1-1
......@@ -207,7 +207,7 @@ describe("ConnectionCatalogDocument", () => {
207207 remoteDpopTokens: [token],
208208 };
209209 const schema = Schema.fromJsonString(ConnectionCatalogDocument);
210 const restored = Schema.decodeUnknownSync(schema)(Schema.encodeSync(schema)(document));
210 const restored = Schema.decodeSync(schema)(Schema.encodeSync(schema)(document));
211211
212212 expect(restored).toEqual(document);
213213 expect(restored.remoteDpopTokens[0]?.accountId).toBe(accountId);
packages/client-runtime/src/relay/discovery.test.ts+8-10
......@@ -134,15 +134,13 @@ const makeHarness = Effect.fn("RelayDiscoveryTest.makeHarness")(function* () {
134134 ),
135135 ),
136136 clerkToken: Ref.get(clerkToken).pipe(
137 Effect.flatMap((token) =>
138 token === null
139 ? Effect.fail(
140 new ConnectionBlockedError({
141 reason: "authentication",
142 detail: "Signed out.",
143 }),
144 )
145 : Effect.succeed(token),
137 Effect.filterOrFail(
138 (token) => token !== null,
139 () =>
140 new ConnectionBlockedError({
141 reason: "authentication",
142 detail: "Signed out.",
143 }),
146144 ),
147145 ),
148146 }),
......@@ -289,7 +287,7 @@ describe("RelayEnvironmentDiscovery", () => {
289287 Layer.mergeAll(
290288 Layer.succeed(ManagedRelay.ManagedRelayClient, client),
291289 Layer.succeed(ClientCapabilities.CloudSession, {
292 identity: Effect.succeed(Option.some({ accountId: "account-1" })),
290 identity: Effect.succeedSome({ accountId: "account-1" }),
293291 clerkToken: Effect.succeed("clerk-token"),
294292 }),
295293 Layer.succeed(Connectivity.Connectivity, {
packages/client-runtime/src/relay/discovery.ts+1-1
......@@ -241,7 +241,7 @@ export const make = Effect.fn("RelayEnvironmentDiscovery.make")(function* () {
241241 }));
242242 return;
243243 }
244 return yield* Effect.fail(failure);
244 return yield* failure;
245245 }
246246 const clerkToken = tokenResult.success;
247247 if ((yield* Ref.get(accountGeneration)) !== generation) {
packages/client-runtime/src/relay/managedRelay.ts+4-7
......@@ -666,11 +666,8 @@ export const make = Effect.fn("ManagedRelayClient.make")(function* (
666666 authorize(input).pipe(
667667 Effect.flatMap((authorization) =>
668668 request(authorization).pipe(
669 Effect.catch((error) => {
670 if (!isRejectedDpopAccessToken(error)) {
671 return Effect.fail(error);
672 }
673 return invalidateAccessToken(authorization.accessToken).pipe(
669 Effect.catchIf(isRejectedDpopAccessToken, (error) =>
670 invalidateAccessToken(authorization.accessToken).pipe(
674671 Effect.tap((invalidated) =>
675672 Effect.annotateCurrentSpan({
676673 "relay.token_cache.invalidated": invalidated,
......@@ -686,8 +683,8 @@ export const make = Effect.fn("ManagedRelayClient.make")(function* (
686683 : Effect.void,
687684 ),
688685 Effect.andThen(refreshRejectedToken ? attempt(false) : Effect.fail(error)),
689 );
690 }),
686 ),
687 ),
691688 ),
692689 ),
693690 );
packages/client-runtime/src/relay/managedRelayState.ts+6-8
......@@ -180,14 +180,12 @@ function readSessionClerkToken(
180180 session: ManagedRelaySession,
181181): Effect.Effect<string, ManagedRelaySessionError> {
182182 return session.readClerkToken().pipe(
183 Effect.flatMap((token) =>
184 token
185 ? Effect.succeed(token)
186 : Effect.fail(
187 new ManagedRelaySessionError({
188 message: "The T3 Connect session token is unavailable.",
189 }),
190 ),
183 Effect.filterOrFail(
184 (token): token is string => Boolean(token),
185 () =>
186 new ManagedRelaySessionError({
187 message: "The T3 Connect session token is unavailable.",
188 }),
191189 ),
192190 );
193191}
packages/client-runtime/src/rpc/session.test.ts+5-5
......@@ -161,7 +161,7 @@ const RpcRequest = Schema.TaggedStruct("Request", {
161161});
162162const decodeJson = Schema.decodeUnknownSync(Schema.fromJsonString(Schema.Unknown));
163163const isRpcRequest = Schema.is(RpcRequest);
164const isPing = Schema.is(Schema.Struct({ _tag: Schema.Literal("Ping") }));
164const isPing = Schema.is(Schema.TaggedStruct("Ping", {}));
165165const encodeJson = Schema.encodeUnknownSync(Schema.fromJsonString(Schema.Unknown));
166166const encodeServerConfig = Schema.encodeSync(ServerConfig);
167167const encodeServerConfigStreamEvent = Schema.encodeSync(ServerConfigStreamEvent);
......@@ -823,14 +823,14 @@ describe("RpcSessionFactory", () => {
823823 retryNow: Effect.void,
824824 } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]);
825825 const cache = Persistence.EnvironmentCacheStore.of({
826 loadShell: () => Effect.succeed(Option.none()),
826 loadShell: () => Effect.succeedNone,
827827 saveShell: () => Effect.void,
828 loadThread: () => Effect.succeed(Option.none()),
828 loadThread: () => Effect.succeedNone,
829829 saveThread: () => Effect.void,
830830 removeThread: () => Effect.void,
831 loadServerConfig: () => Effect.succeed(Option.none()),
831 loadServerConfig: () => Effect.succeedNone,
832832 saveServerConfig: () => Effect.void,
833 loadVcsRefs: () => Effect.succeed(Option.none()),
833 loadVcsRefs: () => Effect.succeedNone,
834834 saveVcsRefs: () => Effect.void,
835835 removeVcsRefs: () => Effect.void,
836836 clearVcsRefs: () => Effect.void,
packages/client-runtime/src/rpc/session.ts+7-7
......@@ -291,13 +291,13 @@ export const make = Effect.fn("RpcSessionFactory.make")(function* (
291291 Effect.flatMap(() => Effect.fail(configSubscriptionEndedError)),
292292 ),
293293 ).pipe(
294 Effect.flatMap((config) =>
295 config.environment.environmentId === connection.environmentId
296 ? Effect.succeed(config)
297 : environmentMismatchError({
298 expected: connection.environmentId,
299 actual: config.environment.environmentId,
300 }),
294 Effect.filterOrElse(
295 (config) => config.environment.environmentId === connection.environmentId,
296 (config) =>
297 environmentMismatchError({
298 expected: connection.environmentId,
299 actual: config.environment.environmentId,
300 }),
301301 ),
302302 Effect.withSpan("environment.initialSync"),
303303 );
packages/client-runtime/src/state/pullRequestRouting.ts+5-9
......@@ -339,15 +339,11 @@ export function createPullRequestRouter() {
339339 }
340340 const operation = run(id);
341341 return yield* (reads.has(tag) ? operation.pipe(readTimeout(id)) : operation).pipe(
342 Effect.catch((error) => {
343 if (
344 (reads.has(tag) || rejectedBeforeDispatch(error)) &&
345 index + 1 < candidates.length
346 ) {
347 return visit(index + 1);
348 }
349 return Effect.fail(error);
350 }),
342 Effect.catchIf(
343 (error) =>
344 (reads.has(tag) || rejectedBeforeDispatch(error)) && index + 1 < candidates.length,
345 () => visit(index + 1),
346 ),
351347 Effect.map((result) =>
352348 typeof result === "object" && result !== null && "projectId" in result
353349 ? {
packages/client-runtime/src/state/pullRequests.test.ts+1-1
......@@ -1171,7 +1171,7 @@ it.effect("updates cached labels after successful edits without rereading the ho
11711171 if (failDetail) {
11721172 yield* detailRefreshStarted.open;
11731173 yield* releaseDetailRefresh.await;
1174 return yield* Effect.fail(new MutationRefused());
1174 return yield* new MutationRefused();
11751175 }
11761176 return { title: "keep this title", labels: [existing] };
11771177 }),
packages/client-runtime/src/state/server.test.ts+8-8
......@@ -778,14 +778,14 @@ describe("server state projection", () => {
778778 } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]);
779779 const savedConfigs = yield* Queue.unbounded<ServerConfig>();
780780 const cache = Persistence.EnvironmentCacheStore.of({
781 loadShell: () => Effect.succeed(Option.none()),
781 loadShell: () => Effect.succeedNone,
782782 saveShell: () => Effect.void,
783 loadThread: () => Effect.succeed(Option.none()),
783 loadThread: () => Effect.succeedNone,
784784 saveThread: () => Effect.void,
785785 removeThread: () => Effect.void,
786 loadServerConfig: () => Effect.succeed(Option.some(CONFIG)),
786 loadServerConfig: () => Effect.succeedSome(CONFIG),
787787 saveServerConfig: (_environmentId, config) => Queue.offer(savedConfigs, config),
788 loadVcsRefs: () => Effect.succeed(Option.none()),
788 loadVcsRefs: () => Effect.succeedNone,
789789 saveVcsRefs: () => Effect.void,
790790 removeVcsRefs: () => Effect.void,
791791 clearVcsRefs: () => Effect.void,
......@@ -839,14 +839,14 @@ describe("server state projection", () => {
839839 } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]);
840840 const savedConfigs = yield* Queue.unbounded<ServerConfig>();
841841 const cache = Persistence.EnvironmentCacheStore.of({
842 loadShell: () => Effect.succeed(Option.none()),
842 loadShell: () => Effect.succeedNone,
843843 saveShell: () => Effect.void,
844 loadThread: () => Effect.succeed(Option.none()),
844 loadThread: () => Effect.succeedNone,
845845 saveThread: () => Effect.void,
846846 removeThread: () => Effect.void,
847 loadServerConfig: () => Effect.succeed(Option.some(CONFIG)),
847 loadServerConfig: () => Effect.succeedSome(CONFIG),
848848 saveServerConfig: (_environmentId, config) => Queue.offer(savedConfigs, config),
849 loadVcsRefs: () => Effect.succeed(Option.none()),
849 loadVcsRefs: () => Effect.succeedNone,
850850 saveVcsRefs: () => Effect.void,
851851 removeVcsRefs: () => Effect.void,
852852 clearVcsRefs: () => Effect.void,
packages/client-runtime/src/state/serverUsage.test.ts+4-4
......@@ -125,14 +125,14 @@ const makeHarness = Effect.fn("ServerUsageTest.makeHarness")(function* (
125125 Stream.provideService(stream, EnvironmentSupervisor, supervisor),
126126 } as EnvironmentRegistry["Service"]);
127127 const cache = EnvironmentCacheStore.of({
128 loadShell: () => Effect.succeed(Option.none()),
128 loadShell: () => Effect.succeedNone,
129129 saveShell: () => Effect.void,
130 loadThread: () => Effect.succeed(Option.none()),
130 loadThread: () => Effect.succeedNone,
131131 saveThread: () => Effect.void,
132132 removeThread: () => Effect.void,
133 loadServerConfig: () => Effect.succeed(Option.none()),
133 loadServerConfig: () => Effect.succeedNone,
134134 saveServerConfig: () => Effect.void,
135 loadVcsRefs: () => Effect.succeed(Option.none()),
135 loadVcsRefs: () => Effect.succeedNone,
136136 saveVcsRefs: () => Effect.void,
137137 removeVcsRefs: () => Effect.void,
138138 clearVcsRefs: () => Effect.void,
packages/client-runtime/src/state/session.ts+1-1
......@@ -20,7 +20,7 @@ function initialConfigOption<E>(
2020 initialConfig: Effect.Effect<ServerConfig, E>,
2121): Effect.Effect<Option.Option<ServerConfig>> {
2222 return initialConfig.pipe(
23 Effect.map(Option.some),
23 Effect.asSome,
2424 Effect.catch((error) =>
2525 Effect.logWarning("Could not load the initial environment configuration.").pipe(
2626 Effect.annotateLogs({ ...safeErrorLogAttributes(error) }),
packages/client-runtime/src/state/shell-sync.test.ts+18-18
......@@ -80,14 +80,14 @@ describe("environment shell synchronization", () => {
8080 retryNow: Effect.void,
8181 } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]);
8282 const cache = Persistence.EnvironmentCacheStore.of({
83 loadShell: () => Effect.succeed(Option.none()),
83 loadShell: () => Effect.succeedNone,
8484 saveShell: () => Effect.never,
85 loadThread: () => Effect.succeed(Option.none()),
85 loadThread: () => Effect.succeedNone,
8686 saveThread: () => Effect.void,
8787 removeThread: () => Effect.void,
88 loadServerConfig: () => Effect.succeed(Option.none()),
88 loadServerConfig: () => Effect.succeedNone,
8989 saveServerConfig: () => Effect.void,
90 loadVcsRefs: () => Effect.succeed(Option.none()),
90 loadVcsRefs: () => Effect.succeedNone,
9191 saveVcsRefs: () => Effect.void,
9292 removeVcsRefs: () => Effect.void,
9393 clearVcsRefs: () => Effect.void,
......@@ -96,7 +96,7 @@ describe("environment shell synchronization", () => {
9696 // Cold cache with no HTTP snapshot available → falls back to the
9797 // socket-embedded snapshot.
9898 const snapshotLoader = ShellSnapshotLoader.of({
99 load: () => Effect.succeed(Option.none()),
99 load: () => Effect.succeedNone,
100100 });
101101 const shellState = yield* makeEnvironmentShellState().pipe(
102102 Effect.provideService(EnvironmentSupervisor.EnvironmentSupervisor, supervisor),
......@@ -176,14 +176,14 @@ describe("environment shell synchronization", () => {
176176 retryNow: Effect.void,
177177 } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]);
178178 const cache = Persistence.EnvironmentCacheStore.of({
179 loadShell: () => Effect.succeed(Option.none()),
179 loadShell: () => Effect.succeedNone,
180180 saveShell: () => Effect.void,
181 loadThread: () => Effect.succeed(Option.none()),
181 loadThread: () => Effect.succeedNone,
182182 saveThread: () => Effect.void,
183183 removeThread: () => Effect.void,
184 loadServerConfig: () => Effect.succeed(Option.none()),
184 loadServerConfig: () => Effect.succeedNone,
185185 saveServerConfig: () => Effect.void,
186 loadVcsRefs: () => Effect.succeed(Option.none()),
186 loadVcsRefs: () => Effect.succeedNone,
187187 saveVcsRefs: () => Effect.void,
188188 removeVcsRefs: () => Effect.void,
189189 clearVcsRefs: () => Effect.void,
......@@ -194,7 +194,7 @@ describe("environment shell synchronization", () => {
194194 Effect.provideService(Persistence.EnvironmentCacheStore, cache),
195195 Effect.provideService(
196196 ShellSnapshotLoader,
197 ShellSnapshotLoader.of({ load: () => Effect.succeed(Option.none()) }),
197 ShellSnapshotLoader.of({ load: () => Effect.succeedNone }),
198198 ),
199199 );
200200 yield* SubscriptionRef.set(supervisorState, {
......@@ -284,14 +284,14 @@ describe("environment shell synchronization", () => {
284284 retryNow: Effect.void,
285285 } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]);
286286 const cache = Persistence.EnvironmentCacheStore.of({
287 loadShell: () => Effect.succeed(Option.some(cachedSnapshot)),
287 loadShell: () => Effect.succeedSome(cachedSnapshot),
288288 saveShell: () => Effect.void,
289 loadThread: () => Effect.succeed(Option.none()),
289 loadThread: () => Effect.succeedNone,
290290 saveThread: () => Effect.void,
291291 removeThread: () => Effect.void,
292 loadServerConfig: () => Effect.succeed(Option.none()),
292 loadServerConfig: () => Effect.succeedNone,
293293 saveServerConfig: () => Effect.void,
294 loadVcsRefs: () => Effect.succeed(Option.none()),
294 loadVcsRefs: () => Effect.succeedNone,
295295 saveVcsRefs: () => Effect.void,
296296 removeVcsRefs: () => Effect.void,
297297 clearVcsRefs: () => Effect.void,
......@@ -364,14 +364,14 @@ describe("environment shell synchronization", () => {
364364 retryNow: Effect.void,
365365 } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]);
366366 const cache = Persistence.EnvironmentCacheStore.of({
367 loadShell: () => Effect.succeed(Option.some(LIVE_SHELL_SNAPSHOT)),
367 loadShell: () => Effect.succeedSome(LIVE_SHELL_SNAPSHOT),
368368 saveShell: () => Effect.void,
369 loadThread: () => Effect.succeed(Option.none()),
369 loadThread: () => Effect.succeedNone,
370370 saveThread: () => Effect.void,
371371 removeThread: () => Effect.void,
372 loadServerConfig: () => Effect.succeed(Option.none()),
372 loadServerConfig: () => Effect.succeedNone,
373373 saveServerConfig: () => Effect.void,
374 loadVcsRefs: () => Effect.succeed(Option.none()),
374 loadVcsRefs: () => Effect.succeedNone,
375375 saveVcsRefs: () => Effect.void,
376376 removeVcsRefs: () => Effect.void,
377377 clearVcsRefs: () => Effect.void,
packages/client-runtime/src/state/sourceControl.test.ts+4-4
......@@ -101,14 +101,14 @@ describe("source control environment atoms", () => {
101101 } as unknown as EnvironmentRegistry.EnvironmentRegistry["Service"]);
102102 const removed = new Array<string>();
103103 const cache = Persistence.EnvironmentCacheStore.of({
104 loadShell: () => Effect.succeed(Option.none()),
104 loadShell: () => Effect.succeedNone,
105105 saveShell: () => Effect.void,
106 loadThread: () => Effect.succeed(Option.none()),
106 loadThread: () => Effect.succeedNone,
107107 saveThread: () => Effect.void,
108108 removeThread: () => Effect.void,
109 loadServerConfig: () => Effect.succeed(Option.none()),
109 loadServerConfig: () => Effect.succeedNone,
110110 saveServerConfig: () => Effect.void,
111 loadVcsRefs: () => Effect.succeed(Option.none()),
111 loadVcsRefs: () => Effect.succeedNone,
112112 saveVcsRefs: () => Effect.void,
113113 removeVcsRefs: (environmentId, cwd) =>
114114 Effect.sync(() => {
packages/client-runtime/src/state/threads-atoms.test.ts+3-3
......@@ -200,7 +200,7 @@ const makeHarness = Effect.fn("TestThreadAtoms.makeHarness")(function* (options?
200200 Layer.succeed(
201201 EnvironmentCacheStore,
202202 EnvironmentCacheStore.of({
203 loadShell: () => Effect.succeed(Option.none()),
203 loadShell: () => Effect.succeedNone,
204204 saveShell: () => Effect.void,
205205 loadThread: () =>
206206 Effect.sync(() => {
......@@ -209,9 +209,9 @@ const makeHarness = Effect.fn("TestThreadAtoms.makeHarness")(function* (options?
209209 }),
210210 saveThread: () => Effect.void,
211211 removeThread: () => Effect.void,
212 loadServerConfig: () => Effect.succeed(Option.none()),
212 loadServerConfig: () => Effect.succeedNone,
213213 saveServerConfig: () => Effect.void,
214 loadVcsRefs: () => Effect.succeed(Option.none()),
214 loadVcsRefs: () => Effect.succeedNone,
215215 saveVcsRefs: () => Effect.void,
216216 removeVcsRefs: () => Effect.void,
217217 clearVcsRefs: () => Effect.void,
packages/client-runtime/src/state/threads-pagination.test.ts+3-3
......@@ -197,16 +197,16 @@ const makeHarness = Effect.fn("TestThreadPagination.makeHarness")(function* (opt
197197 retryNow: Effect.void,
198198 } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]);
199199 const cache = Persistence.EnvironmentCacheStore.of({
200 loadShell: () => Effect.succeed(Option.none()),
200 loadShell: () => Effect.succeedNone,
201201 saveShell: () => Effect.void,
202202 loadThread: () =>
203203 Effect.succeed(options?.cached !== undefined ? Option.some(options.cached) : Option.none()),
204204 saveThread: (_environmentId, thread) =>
205205 Ref.update(savedThreads, (current) => [...current, thread]),
206206 removeThread: () => Effect.void,
207 loadServerConfig: () => Effect.succeed(Option.none()),
207 loadServerConfig: () => Effect.succeedNone,
208208 saveServerConfig: () => Effect.void,
209 loadVcsRefs: () => Effect.succeed(Option.none()),
209 loadVcsRefs: () => Effect.succeedNone,
210210 saveVcsRefs: () => Effect.void,
211211 removeVcsRefs: () => Effect.void,
212212 clearVcsRefs: () => Effect.void,
packages/client-runtime/src/state/threads-sync.test.ts+3-3
......@@ -216,7 +216,7 @@ const makeHarness = Effect.fn("TestEnvironmentThreads.makeHarness")(function* (o
216216 retryNow: Ref.update(retryCount, (count) => count + 1),
217217 } satisfies EnvironmentSupervisor.EnvironmentSupervisor["Service"]);
218218 const cache = Persistence.EnvironmentCacheStore.of({
219 loadShell: () => Effect.succeed(Option.none()),
219 loadShell: () => Effect.succeedNone,
220220 saveShell: () => Effect.void,
221221 loadThread: (_environmentId, threadId) =>
222222 options?.loadCached ??
......@@ -234,9 +234,9 @@ const makeHarness = Effect.fn("TestEnvironmentThreads.makeHarness")(function* (o
234234 ),
235235 removeThread: (_environmentId, threadId) =>
236236 Ref.update(removedThreads, (current) => [...current, threadId]),
237 loadServerConfig: () => Effect.succeed(Option.none()),
237 loadServerConfig: () => Effect.succeedNone,
238238 saveServerConfig: () => Effect.void,
239 loadVcsRefs: () => Effect.succeed(Option.none()),
239 loadVcsRefs: () => Effect.succeedNone,
240240 saveVcsRefs: () => Effect.void,
241241 removeVcsRefs: () => Effect.void,
242242 clearVcsRefs: () => Effect.void,
packages/client-runtime/src/state/vcs.test.ts+3-3
......@@ -98,12 +98,12 @@ function cacheWithRefs(
9898 overrides: Partial<Persistence.EnvironmentCacheStore["Service"]> = {},
9999) {
100100 return Persistence.EnvironmentCacheStore.of({
101 loadShell: () => Effect.succeed(Option.none()),
101 loadShell: () => Effect.succeedNone,
102102 saveShell: () => Effect.void,
103 loadThread: () => Effect.succeed(Option.none()),
103 loadThread: () => Effect.succeedNone,
104104 saveThread: () => Effect.void,
105105 removeThread: () => Effect.void,
106 loadServerConfig: () => Effect.succeed(Option.none()),
106 loadServerConfig: () => Effect.succeedNone,
107107 saveServerConfig: () => Effect.void,
108108 loadVcsRefs: () => Effect.succeed(refs),
109109 saveVcsRefs: () => Effect.void,
packages/client-runtime/src/state/vcsAction.test.ts+4-4
......@@ -99,14 +99,14 @@ function progress<T extends GitActionProgressEvent>(event: T): T {
9999
100100function cacheStore(onClearVcsRefs: (environmentId: EnvironmentId) => void) {
101101 return Persistence.EnvironmentCacheStore.of({
102 loadShell: () => Effect.succeed(Option.none()),
102 loadShell: () => Effect.succeedNone,
103103 saveShell: () => Effect.void,
104 loadThread: () => Effect.succeed(Option.none()),
104 loadThread: () => Effect.succeedNone,
105105 saveThread: () => Effect.void,
106106 removeThread: () => Effect.void,
107 loadServerConfig: () => Effect.succeed(Option.none()),
107 loadServerConfig: () => Effect.succeedNone,
108108 saveServerConfig: () => Effect.void,
109 loadVcsRefs: () => Effect.succeed(Option.none()),
109 loadVcsRefs: () => Effect.succeedNone,
110110 saveVcsRefs: () => Effect.void,
111111 removeVcsRefs: () => Effect.void,
112112 clearVcsRefs: (environmentId) => Effect.sync(() => onClearVcsRefs(environmentId)),
packages/contracts/src/pullRequest.test.ts+1-1
......@@ -92,7 +92,7 @@ describe("PullRequestListResult", () => {
9292 it("round-trips through the JSON codec the RPC serializes with", () => {
9393 const codec = Schema.toCodecJson(PullRequestListResult);
9494
95 const decoded = Schema.decodeUnknownSync(codec)(Schema.encodeUnknownSync(codec)(LIST_RESULT));
95 const decoded = Schema.decodeSync(codec)(Schema.encodeUnknownSync(codec)(LIST_RESULT));
9696
9797 expect(decoded).toStrictEqual(LIST_RESULT);
9898 });
packages/contracts/src/rpc.test.ts+3-3
......@@ -13,19 +13,19 @@ import { WsSubscribeServerConfigRpc } from "./rpc.ts";
1313describe("subscribeServerConfig payload compatibility", () => {
1414 it("is accepted by a server whose schema predates the field", () => {
1515 const oldServerPayload = Schema.Struct({});
16 const decoded = Schema.decodeUnknownExit(oldServerPayload)({ environmentThemes: true });
16 const decoded = Schema.decodeExit(oldServerPayload)({ environmentThemes: true });
1717 expect(Exit.isSuccess(decoded)).toBe(true);
1818 });
1919
2020 it("is carried by a server that declares it", () => {
21 const decoded = Schema.decodeUnknownSync(WsSubscribeServerConfigRpc.payloadSchema)({
21 const decoded = Schema.decodeSync(WsSubscribeServerConfigRpc.payloadSchema)({
2222 environmentThemes: true,
2323 });
2424 expect(decoded).toEqual({ environmentThemes: true });
2525 });
2626
2727 it("stays optional, so a client that never sends it still subscribes", () => {
28 const decoded = Schema.decodeUnknownSync(WsSubscribeServerConfigRpc.payloadSchema)({});
28 const decoded = Schema.decodeSync(WsSubscribeServerConfigRpc.payloadSchema)({});
2929 expect(decoded).toEqual({});
3030 });
3131});
packages/contracts/src/settings.ts+1-3
......@@ -1082,9 +1082,7 @@ export type StorageCleanupSettings = typeof StorageCleanupSettings.Type;
10821082export const ServerSettings = Schema.Struct({
10831083 worktreeCleanup: WorktreeCleanup.pipe(Schema.withDecodingDefault(Effect.succeed(null))),
10841084 storageCleanup: StorageCleanupSettings.pipe(
1085 Schema.withDecodingDefault(
1086 Effect.succeed(Schema.decodeUnknownSync(StorageCleanupSettings)({})),
1087 ),
1085 Schema.withDecodingDefault(Effect.succeed(Schema.decodeSync(StorageCleanupSettings)({}))),
10881086 ),
10891087 // How assistant text reaches clients during a turn. Deliberately a fresh
10901088 // key (was `enableLegacyTokenStreaming`, before that
packages/effect-acp/src/client.ts+3-5
......@@ -346,11 +346,9 @@ export const make = Effect.fn("effect-acp/AcpClient.make")(function* (
346346 registration: BufferedNotificationHandler<A>,
347347 notification: A,
348348 ) =>
349 Effect.forEach(
350 registration.handlers,
351 (handler) => handler(notification).pipe(Effect.catch(() => Effect.void)),
352 { discard: true },
353 );
349 Effect.forEach(registration.handlers, (handler) => handler(notification).pipe(Effect.ignore), {
350 discard: true,
351 });
354352
355353 const flushBufferedNotifications = <A>(registration: BufferedNotificationHandler<A>) =>
356354 Effect.suspend(() => {
packages/effect-acp/src/protocol.ts+1-1
......@@ -216,7 +216,7 @@ export const makeAcpPatchedProtocol = Effect.fn("makeAcpPatchedProtocol")(functi
216216 Queue.offer(notificationQueue, notification).pipe(
217217 Effect.andThen(
218218 options.onNotification
219 ? options.onNotification(notification).pipe(Effect.catch(() => Effect.void))
219 ? options.onNotification(notification).pipe(Effect.ignore)
220220 : Effect.void,
221221 ),
222222 Effect.asVoid,
packages/effect-codex-app-server/src/_internal/shared.ts+1-1
......@@ -45,7 +45,7 @@ export const encodeOptionalPayload = <A, I>(
4545): Effect.Effect<I | undefined, CodexError.CodexAppServerRequestError> => {
4646 if (!schema) {
4747 if (payload === undefined) {
48 return Effect.sync(() => undefined);
48 return Effect.undefined;
4949 }
5050 return Effect.fail(
5151 CodexError.CodexAppServerRequestError.unexpectedPayload(method, "encode-payload", payload),
packages/effect-codex-app-server/src/client.ts+2-4
......@@ -153,14 +153,12 @@ const make = Effect.fn("effect-codex-app-server/CodexAppServerClient.make")(func
153153 Effect.flatMap((decoded) =>
154154 Effect.forEach(handlers, (handler) => handler(decoded), { discard: true }),
155155 ),
156 Effect.catch(() => Effect.void),
156 Effect.ignore,
157157 );
158158 }
159159
160160 return unknownNotificationHandler
161 ? unknownNotificationHandler(notification.method, notification.params).pipe(
162 Effect.catch(() => Effect.void),
163 )
161 ? unknownNotificationHandler(notification.method, notification.params).pipe(Effect.ignore)
164162 : Effect.void;
165163 };
166164
packages/effect-codex-app-server/src/schema.test.ts+1-1
......@@ -29,7 +29,7 @@ it("keeps async questions in live notifications and thread history", () => {
2929 CodexSchema.V2ThreadReadResponse__ThreadItem,
3030 CodexSchema.V2ThreadResumeResponse__ThreadItem,
3131 ]) {
32 assert.deepEqual(Schema.decodeUnknownSync(schema)(item), item);
32 assert.deepEqual(Schema.decodeSync(schema)(item), item);
3333 }
3434});
3535
packages/shared/src/httpReadiness.ts+7-11
......@@ -106,17 +106,13 @@ export const waitForHttpReady = Effect.fn("shared.httpReadiness.waitForHttpReady
106106 Effect.timeoutOption(Duration.millis(probeTimeoutMs)),
107107 Effect.mapError((cause) => fail(cause)),
108108 );
109 return yield* Option.match(responseOption, {
110 onSome: Effect.succeed,
111 onNone: () =>
112 Effect.fail(
113 fail({
114 kind: "probe-timeout",
115 attempt,
116 probeTimeoutMs,
117 }),
118 ),
119 });
109 return yield* Effect.fromOption(responseOption, () =>
110 fail({
111 kind: "probe-timeout",
112 attempt,
113 probeTimeoutMs,
114 }),
115 );
120116 }).pipe(
121117 Effect.mapError((cause) => (isMadeError(cause) ? cause : fail(cause))),
122118 Effect.tapError((cause) =>
packages/shared/src/relayClient.ts+11-13
......@@ -331,9 +331,7 @@ export const makeCloudflaredRelayClient = Effect.fn("cloudflared.make")(function
331331 for (let attempt = 0; attempt < INSTALL_LOCK_RETRY_COUNT; attempt += 1) {
332332 const acquired = yield* fileSystem.writeFileString(lockPath, "", { flag: "wx" }).pipe(
333333 Effect.as(true),
334 Effect.catch((error) =>
335 isAlreadyExists(error) ? Effect.succeed(false) : Effect.fail(error),
336 ),
334 Effect.catchIf(isAlreadyExists, () => Effect.succeed(false)),
337335 );
338336 if (acquired) return;
339337
......@@ -445,16 +443,16 @@ export const makeCloudflaredRelayClient = Effect.fn("cloudflared.make")(function
445443 }).pipe(
446444 Effect.scoped,
447445 Effect.ensuring(fileSystem.remove(lockPath, { force: true }).pipe(Effect.ignore)),
448 Effect.catch((cause) =>
449 cause instanceof RelayClientInstallError
450 ? Effect.fail(cause)
451 : Effect.fail(
452 new RelayClientInstallError({
453 reason: "write_failed",
454 message: "Could not install the relay client.",
455 cause,
456 }),
457 ),
446 Effect.catchIf(
447 (cause) => !(cause instanceof RelayClientInstallError),
448 (cause) =>
449 Effect.fail(
450 new RelayClientInstallError({
451 reason: "write_failed",
452 message: "Could not install the relay client.",
453 cause,
454 }),
455 ),
458456 ),
459457 );
460458 });
packages/shared/src/relayTracing.ts+1-1
......@@ -151,6 +151,6 @@ export function makeRelayClientTracingLayer(
151151
152152 return Layer.effect(
153153 RelayClientTracer,
154 Tracer.Tracer.pipe(Effect.map(nonInterferingTracer), Effect.map(Option.some)),
154 Tracer.Tracer.pipe(Effect.map(nonInterferingTracer), Effect.asSome),
155155 ).pipe(Layer.provide(tracerLayer));
156156}
packages/shared/src/schemaJson.ts+1-2
......@@ -1,7 +1,6 @@
11import * as Cause from "effect/Cause";
22import * as Effect from "effect/Effect";
33import * as Exit from "effect/Exit";
4import * as Option from "effect/Option";
54import * as Result from "effect/Result";
65import * as Schema from "effect/Schema";
76import * as SchemaGetter from "effect/SchemaGetter";
......@@ -187,7 +186,7 @@ const parseLenientJsonGetter = SchemaGetter.onSome((input: string) => {
187186 );
188187
189188 return decodeJsonString(stripped).pipe(
190 Effect.map(Option.some),
189 Effect.asSome,
191190 Effect.mapError((error) => error.issue),
192191 );
193192});
tsconfig.base.json+2-1
......@@ -50,7 +50,8 @@
5050 "globalTimers": "error",
5151 "globalTimersInEffect": "error",
5252 "globalFetch": "error",
53 "globalFetchInEffect": "error"
53 "globalFetchInEffect": "error",
54 "schemaNumber": "off"
5455 }
5556 }
5657 ]