Skip to content

Commit 4af9463

Browse files
remove unnecessary instanceof checks
1 parent 73ba21e commit 4af9463

14 files changed

Lines changed: 87 additions & 114 deletions

File tree

apps/server/src/git/Layers/GitCore.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2002,7 +2002,7 @@ export const makeGitCore = Effect.fn("makeGitCore")(function* (options?: {
20022002
"GitCore.removeWorktree",
20032003
input.cwd,
20042004
args,
2005-
`${commandLabel(args)} failed (cwd: ${input.cwd}): ${error instanceof Error ? error.message : String(error)}`,
2005+
`${commandLabel(args)} failed (cwd: ${input.cwd}): ${error.message}`,
20062006
error,
20072007
),
20082008
),

apps/server/src/git/Layers/GitHubCli.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Effect, Layer, Schema } from "effect";
1+
import { Effect, Layer, Schema, SchemaIssue } from "effect";
22
import { PositiveInt, TrimmedNonEmptyString } from "@t3tools/contracts";
33

44
import { runProcess } from "../../processRunner";
@@ -154,7 +154,7 @@ function decodeGitHubJson<S extends Schema.Top>(
154154
(error) =>
155155
new GitHubCliError({
156156
operation,
157-
detail: error instanceof Error ? `${invalidDetail}: ${error.message}` : invalidDetail,
157+
detail: `${invalidDetail}: ${SchemaIssue.makeFormatterDefault()(error.issue)}`,
158158
cause: error,
159159
}),
160160
),

apps/server/src/provider/Layers/ClaudeAdapter.test.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1228,11 +1228,9 @@ describe("ClaudeAdapterLive", () => {
12281228

12291229
runtimeEventsFiber.interruptUnsafe();
12301230

1231-
assert.equal(
1231+
assert.isUndefined(
12321232
promptConsumerError,
1233-
undefined,
1234-
`Prompt consumer should not receive a thrown error on session stop, ` +
1235-
`but got: "${promptConsumerError instanceof Error ? promptConsumerError.message : String(promptConsumerError)}"`,
1233+
"Prompt consumer should not receive a thrown error on session stop",
12361234
);
12371235
}).pipe(
12381236
Effect.provideService(Random.Random, makeDeterministicRandomService()),

apps/server/src/provider/Layers/ClaudeAdapter.ts

Lines changed: 19 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ import {
5959
Random,
6060
Ref,
6161
Stream,
62+
Schema,
6263
} from "effect";
6364

6465
import { resolveAttachmentPath } from "../../attachmentStore.ts";
@@ -182,6 +183,11 @@ export interface ClaudeAdapterLiveOptions {
182183
readonly nativeEventLogger?: EventNdjsonLogger;
183184
}
184185

186+
class ClaudeStreamError extends Schema.TaggedErrorClass<ClaudeStreamError>()("ClaudeStreamError", {
187+
message: Schema.String,
188+
cause: Schema.optional(Schema.Defect),
189+
}) {}
190+
185191
function isUuid(value: string): boolean {
186192
return /^[0-9a-f]{8}-[0-9a-f]{4}-[1-8][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i.test(value);
187193
}
@@ -190,17 +196,6 @@ function isSyntheticClaudeThreadId(value: string): boolean {
190196
return value.startsWith("claude-thread-");
191197
}
192198

193-
function toMessage(cause: unknown, fallback: string): string {
194-
if (cause instanceof Error && cause.message.length > 0) {
195-
return cause.message;
196-
}
197-
return fallback;
198-
}
199-
200-
function toError(cause: unknown, fallback: string): Error {
201-
return cause instanceof Error ? cause : new Error(toMessage(cause, fallback));
202-
}
203-
204199
function normalizeClaudeStreamMessages(cause: Cause.Cause<Error>): ReadonlyArray<string> {
205200
const errors = Cause.prettyErrors(cause)
206201
.map((error) => error.message.trim())
@@ -209,8 +204,7 @@ function normalizeClaudeStreamMessages(cause: Cause.Cause<Error>): ReadonlyArray
209204
return errors;
210205
}
211206

212-
const squashed = toMessage(Cause.squash(cause), "").trim();
213-
return squashed.length > 0 ? [squashed] : [];
207+
return [Cause.pretty(cause)];
214208
}
215209

216210
function getEffectiveClaudeCodeEffort(
@@ -597,7 +591,7 @@ const buildUserMessageEffect = Effect.fn("buildUserMessageEffect")(function* (
597591
new ProviderAdapterRequestError({
598592
provider: PROVIDER,
599593
method: "turn/start",
600-
detail: toMessage(cause, "Failed to read attachment file."),
594+
detail: `Failed to read attachment file: ${cause.message}.`,
601595
cause,
602596
}),
603597
),
@@ -813,7 +807,7 @@ function toSessionError(
813807
threadId: ThreadId,
814808
cause: unknown,
815809
): ProviderAdapterSessionNotFoundError | ProviderAdapterSessionClosedError | undefined {
816-
const normalized = toMessage(cause, "").toLowerCase();
810+
const normalized = cause instanceof Error ? cause.message.toLowerCase() : "";
817811
if (normalized.includes("unknown session") || normalized.includes("not found")) {
818812
return new ProviderAdapterSessionNotFoundError({
819813
provider: PROVIDER,
@@ -839,7 +833,7 @@ function toRequestError(threadId: ThreadId, method: string, cause: unknown): Pro
839833
return new ProviderAdapterRequestError({
840834
provider: PROVIDER,
841835
method,
842-
detail: toMessage(cause, `${method} failed`),
836+
detail: cause instanceof Error ? `${method} failed: ${cause.message}` : `${method} failed`,
843837
cause,
844838
});
845839
}
@@ -2226,9 +2220,14 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (
22262220
}
22272221
});
22282222

2229-
const runSdkStream = (context: ClaudeSessionContext): Effect.Effect<void, Error> =>
2230-
Stream.fromAsyncIterable(context.query, (cause) =>
2231-
toError(cause, "Claude runtime stream failed."),
2223+
const runSdkStream = (context: ClaudeSessionContext) =>
2224+
Stream.fromAsyncIterable(
2225+
context.query,
2226+
(cause) =>
2227+
new ClaudeStreamError({
2228+
message: "An error occurred while running the Claude SDK stream.",
2229+
cause,
2230+
}),
22322231
).pipe(
22332232
Stream.takeWhile(() => !context.stopped),
22342233
Stream.runForEach((message) => handleSdkMessage(context, message)),
@@ -2732,7 +2731,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* (
27322731
new ProviderAdapterProcessError({
27332732
provider: PROVIDER,
27342733
threadId,
2735-
detail: toMessage(cause, "Failed to start Claude runtime session."),
2734+
detail: `Failed to create Claude runtime query: ${String(cause)}.`,
27362735
cause,
27372736
}),
27382737
});

apps/server/src/provider/Layers/ClaudeProvider.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -495,7 +495,7 @@ export const checkClaudeProviderStatus = Effect.fn("checkClaudeProviderStatus")(
495495
auth: { status: "unknown" },
496496
message: isCommandMissingCause(error)
497497
? "Claude Agent CLI (`claude`) is not installed or not on PATH."
498-
: `Failed to execute Claude Agent CLI health check: ${error instanceof Error ? error.message : String(error)}.`,
498+
: `Failed to execute Claude Agent CLI health check: ${error.message}.`,
499499
},
500500
});
501501
}
@@ -579,10 +579,7 @@ export const checkClaudeProviderStatus = Effect.fn("checkClaudeProviderStatus")(
579579
version: parsedVersion,
580580
status: "warning",
581581
auth: { status: "unknown" },
582-
message:
583-
error instanceof Error
584-
? `Could not verify Claude authentication status: ${error.message}.`
585-
: "Could not verify Claude authentication status.",
582+
message: `Could not verify Claude authentication status: ${error.message}.`,
586583
},
587584
});
588585
}

apps/server/src/provider/Layers/CodexAdapter.test.ts

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -238,14 +238,7 @@ sessionErrorLayer("CodexAdapterLive session errors", (it) => {
238238
.pipe(Effect.result);
239239

240240
assert.equal(result._tag, "Failure");
241-
if (result._tag !== "Failure") {
242-
return;
243-
}
244-
245241
assert.equal(result.failure._tag, "ProviderAdapterSessionNotFoundError");
246-
if (result.failure._tag !== "ProviderAdapterSessionNotFoundError") {
247-
return;
248-
}
249242
assert.equal(result.failure.provider, "codex");
250243
assert.equal(result.failure.threadId, "sess-missing");
251244
assert.equal(result.failure.cause instanceof Error, true);

apps/server/src/provider/Layers/CodexAdapter.ts

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -51,18 +51,11 @@ export interface CodexAdapterLiveOptions {
5151
readonly nativeEventLogger?: EventNdjsonLogger;
5252
}
5353

54-
function toMessage(cause: unknown, fallback: string): string {
55-
if (cause instanceof Error && cause.message.length > 0) {
56-
return cause.message;
57-
}
58-
return fallback;
59-
}
60-
6154
function toSessionError(
6255
threadId: ThreadId,
6356
cause: unknown,
6457
): ProviderAdapterSessionNotFoundError | ProviderAdapterSessionClosedError | undefined {
65-
const normalized = toMessage(cause, "").toLowerCase();
58+
const normalized = cause instanceof Error ? cause.message.toLowerCase() : "";
6659
if (normalized.includes("unknown session") || normalized.includes("unknown provider session")) {
6760
return new ProviderAdapterSessionNotFoundError({
6861
provider: PROVIDER,
@@ -88,7 +81,7 @@ function toRequestError(threadId: ThreadId, method: string, cause: unknown): Pro
8881
return new ProviderAdapterRequestError({
8982
provider: PROVIDER,
9083
method,
91-
detail: toMessage(cause, `${method} failed`),
84+
detail: cause instanceof Error ? `${method} failed: ${cause.message}` : `${method} failed`,
9285
cause,
9386
});
9487
}
@@ -1427,7 +1420,7 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (
14271420
new ProviderAdapterProcessError({
14281421
provider: PROVIDER,
14291422
threadId: input.threadId,
1430-
detail: toMessage(cause, "Failed to start Codex adapter session."),
1423+
detail: `Failed to start Codex adapter session: ${cause instanceof Error ? cause.message : String(cause)}.`,
14311424
cause,
14321425
}),
14331426
});
@@ -1455,7 +1448,7 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* (
14551448
new ProviderAdapterRequestError({
14561449
provider: PROVIDER,
14571450
method: "turn/start",
1458-
detail: toMessage(cause, "Failed to read attachment file."),
1451+
detail: `Failed to read attachment file: ${cause.message}.`,
14591452
cause,
14601453
}),
14611454
),

apps/server/src/provider/Layers/CodexProvider.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -389,7 +389,7 @@ export const checkCodexProviderStatus = Effect.fn("checkCodexProviderStatus")(fu
389389
auth: { status: "unknown" },
390390
message: isCommandMissingCause(error)
391391
? "Codex CLI (`codex`) is not installed or not on PATH."
392-
: `Failed to execute Codex CLI health check: ${error instanceof Error ? error.message : String(error)}.`,
392+
: `Failed to execute Codex CLI health check: ${error.message}.`,
393393
},
394394
});
395395
}
@@ -489,10 +489,7 @@ export const checkCodexProviderStatus = Effect.fn("checkCodexProviderStatus")(fu
489489
version: parsedVersion,
490490
status: "warning",
491491
auth: { status: "unknown" },
492-
message:
493-
error instanceof Error
494-
? `Could not verify Codex authentication status: ${error.message}.`
495-
: "Could not verify Codex authentication status.",
492+
message: `Could not verify Codex authentication status: ${error.message}.`,
496493
},
497494
});
498495
}

apps/server/src/provider/providerSnapshot.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,7 @@ export function nonEmptyTrimmed(value: string | undefined): string | undefined {
3232
return trimmed.length > 0 ? trimmed : undefined;
3333
}
3434

35-
export function isCommandMissingCause(error: unknown): boolean {
36-
if (!(error instanceof Error)) return false;
35+
export function isCommandMissingCause(error: Error): boolean {
3736
const lower = error.message.toLowerCase();
3837
return lower.includes("enoent") || lower.includes("notfound");
3938
}

apps/server/src/terminal/Layers/Manager.ts

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@ import {
88
} from "@t3tools/contracts";
99
import { makeKeyedCoalescingWorker } from "@t3tools/shared/KeyedCoalescingWorker";
1010
import {
11-
Data,
1211
Effect,
1312
Encoding,
1413
Equal,
@@ -17,6 +16,7 @@ import {
1716
FileSystem,
1817
Layer,
1918
Option,
19+
Schema,
2020
Scope,
2121
Semaphore,
2222
SynchronizedRef,
@@ -54,22 +54,28 @@ const DEFAULT_OPEN_COLS = 120;
5454
const DEFAULT_OPEN_ROWS = 30;
5555
const TERMINAL_ENV_BLOCKLIST = new Set(["PORT", "ELECTRON_RENDERER_PORT", "ELECTRON_RUN_AS_NODE"]);
5656

57-
type TerminalSubprocessChecker = (
58-
terminalPid: number,
59-
) => Effect.Effect<boolean, TerminalSubprocessCheckError>;
60-
61-
class TerminalSubprocessCheckError extends Data.TaggedError("TerminalSubprocessCheckError")<{
62-
readonly message: string;
63-
readonly cause?: unknown;
64-
readonly terminalPid: number;
65-
readonly command: "powershell" | "pgrep" | "ps";
66-
}> {}
57+
class TerminalSubprocessCheckError extends Schema.TaggedErrorClass<TerminalSubprocessCheckError>()(
58+
"TerminalSubprocessCheckError",
59+
{
60+
message: Schema.String,
61+
cause: Schema.optional(Schema.Defect),
62+
terminalPid: Schema.Number,
63+
command: Schema.Literals(["powershell", "pgrep", "ps"]),
64+
},
65+
) {}
66+
67+
class TerminalProcessSignalError extends Schema.TaggedErrorClass<TerminalProcessSignalError>()(
68+
"TerminalProcessSignalError",
69+
{
70+
message: Schema.String,
71+
cause: Schema.optional(Schema.Defect),
72+
signal: Schema.Literals(["SIGTERM", "SIGKILL"]),
73+
},
74+
) {}
6775

68-
class TerminalProcessSignalError extends Data.TaggedError("TerminalProcessSignalError")<{
69-
readonly message: string;
70-
readonly cause?: unknown;
71-
readonly signal: "SIGTERM" | "SIGKILL";
72-
}> {}
76+
interface TerminalSubprocessChecker {
77+
(terminalPid: number): Effect.Effect<boolean, TerminalSubprocessCheckError>;
78+
}
7379

7480
interface ShellCandidate {
7581
shell: string;
@@ -271,9 +277,8 @@ function isRetryableShellSpawnError(error: PtySpawnError): boolean {
271277

272278
if (current instanceof Error) {
273279
messages.push(current.message);
274-
const cause = (current as { cause?: unknown }).cause;
275-
if (cause) {
276-
queue.push(cause);
280+
if (current.cause) {
281+
queue.push(current.cause);
277282
}
278283
continue;
279284
}
@@ -876,7 +881,7 @@ export const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWith
876881
Effect.logWarning("failed to persist terminal history", {
877882
threadId,
878883
terminalId,
879-
error: error instanceof Error ? error.message : String(error),
884+
error,
880885
}),
881886
),
882887
);
@@ -959,7 +964,7 @@ export const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWith
959964
Effect.catch((cleanupError) =>
960965
Effect.logWarning("failed to remove legacy terminal history", {
961966
threadId,
962-
error: cleanupError instanceof Error ? cleanupError.message : String(cleanupError),
967+
error: cleanupError,
963968
}),
964969
),
965970
);
@@ -975,7 +980,7 @@ export const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWith
975980
Effect.logWarning("failed to delete terminal history", {
976981
threadId,
977982
terminalId,
978-
error: error instanceof Error ? error.message : String(error),
983+
error,
979984
}),
980985
),
981986
);
@@ -985,7 +990,7 @@ export const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWith
985990
Effect.logWarning("failed to delete terminal history", {
986991
threadId,
987992
terminalId,
988-
error: error instanceof Error ? error.message : String(error),
993+
error,
989994
}),
990995
),
991996
);
@@ -1011,7 +1016,7 @@ export const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWith
10111016
Effect.catch((error) =>
10121017
Effect.logWarning("failed to delete terminal histories for thread", {
10131018
threadId,
1014-
error: error instanceof Error ? error.message : String(error),
1019+
error,
10151020
}),
10161021
),
10171022
),
@@ -1463,12 +1468,12 @@ export const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWith
14631468
const terminalPid = session.pid;
14641469
const hasRunningSubprocess = yield* subprocessChecker(terminalPid).pipe(
14651470
Effect.map(Option.some),
1466-
Effect.catch((error) =>
1471+
Effect.catch((reason) =>
14671472
Effect.logWarning("failed to check terminal subprocess activity", {
14681473
threadId: session.threadId,
14691474
terminalId: session.terminalId,
14701475
terminalPid,
1471-
error: error instanceof Error ? error.message : String(error),
1476+
reason,
14721477
}).pipe(Effect.as(Option.none<boolean>())),
14731478
),
14741479
);

0 commit comments

Comments
 (0)