diff --git a/apps/desktop/src/clientPersistence.test.ts b/apps/desktop/src/clientPersistence.test.ts index 5a8410c8d9b2e1bc52f025939eeb7acb208aaed5..df2178c0b0dd1378ad758b2b238aaf10e907e7a0 100644 --- a/apps/desktop/src/clientPersistence.test.ts +++ b/apps/desktop/src/clientPersistence.test.ts @@ -58,7 +58,7 @@ const clientSettings: ClientSettings = { }; const savedRegistryRecord: PersistedSavedEnvironmentRecord = { - environmentId: EnvironmentId.makeUnsafe("environment-1"), + environmentId: EnvironmentId.make("environment-1"), label: "Remote environment", httpBaseUrl: "https://remote.example.com/", wsBaseUrl: "wss://remote.example.com/", diff --git a/apps/server/integration/OrchestrationEngineHarness.integration.ts b/apps/server/integration/OrchestrationEngineHarness.integration.ts index 5239cf103f93fc7c75f75a78d90304042bcb7583..6daa43ca42ab17b6d764a7b7e4c328dad4d5c56f 100644 --- a/apps/server/integration/OrchestrationEngineHarness.integration.ts +++ b/apps/server/integration/OrchestrationEngineHarness.integration.ts @@ -438,7 +438,7 @@ export const makeOrchestrationIntegrationHarness = ( ) => waitFor( pendingApprovalRepository - .getByRequestId({ requestId: ApprovalRequestId.makeUnsafe(requestId) }) + .getByRequestId({ requestId: ApprovalRequestId.make(requestId) }) .pipe( Effect.map((row) => Option.match(row, { diff --git a/apps/server/integration/TestProviderAdapter.integration.ts b/apps/server/integration/TestProviderAdapter.integration.ts index 9c87d9821a6f59566ad0dce00b3f1781ac2d6fa7..f4973953078d754ed4e00f25e0be685f0d07963c 100644 --- a/apps/server/integration/TestProviderAdapter.integration.ts +++ b/apps/server/integration/TestProviderAdapter.integration.ts @@ -289,7 +289,7 @@ export const makeTestProviderAdapterHarness = (options?: MakeTestProviderAdapter state.turnCount += 1; const turnCount = state.turnCount; - const turnId = TurnId.makeUnsafe(`turn-${turnCount}`); + const turnId = TurnId.make(`turn-${turnCount}`); const response = state.queuedResponses.shift(); if (!response) { @@ -307,7 +307,7 @@ export const makeTestProviderAdapterHarness = (options?: MakeTestProviderAdapter ...(fixtureEvent as Record), eventId: randomUUID(), provider, - sessionId: RuntimeSessionId.makeUnsafe(String(input.threadId)), + sessionId: RuntimeSessionId.make(String(input.threadId)), createdAt: nowIso(), }; rawEvent.threadId = state.snapshot.threadId; @@ -363,7 +363,7 @@ export const makeTestProviderAdapterHarness = (options?: MakeTestProviderAdapter if (deferredTurnCompletedEvents.length === 0) { yield* emit({ type: "turn.completed", - eventId: EventId.makeUnsafe(randomUUID()), + eventId: EventId.make(randomUUID()), provider, createdAt: nowIso(), threadId: state.snapshot.threadId, diff --git a/apps/server/integration/fixtures/providerRuntime.ts b/apps/server/integration/fixtures/providerRuntime.ts index 42e7ecd87dbb9beedda1f9ca47294ee0f27ecb9f..14a45518c3c625e0618b827aa29cf92e3c74782f 100644 --- a/apps/server/integration/fixtures/providerRuntime.ts +++ b/apps/server/integration/fixtures/providerRuntime.ts @@ -5,14 +5,14 @@ const PROVIDER = "codex" as const; const SESSION_ID = "fixture-session"; const THREAD_ID = "fixture-thread"; const TURN_ID = "fixture-turn"; -const REQUEST_ID = RuntimeRequestId.makeUnsafe("req-1"); +const REQUEST_ID = RuntimeRequestId.make("req-1"); function baseEvent( eventId: string, createdAt: string, ): Pick { return { - eventId: EventId.makeUnsafe(eventId), + eventId: EventId.make(eventId), provider: PROVIDER, sessionId: SESSION_ID, createdAt, diff --git a/apps/server/integration/orchestrationEngine.integration.test.ts b/apps/server/integration/orchestrationEngine.integration.test.ts index a5cc8f8cc6f9e29d771638dfec9e2d0e679d8046..a7f845672cadee9cb2753eb88a4b443eaf93c32b 100644 --- a/apps/server/integration/orchestrationEngine.integration.test.ts +++ b/apps/server/integration/orchestrationEngine.integration.test.ts @@ -30,14 +30,13 @@ import type { } from "../src/orchestration/Services/RuntimeReceiptBus.ts"; import * as NodeServices from "@effect/platform-node/NodeServices"; -const asMessageId = (value: string): MessageId => MessageId.makeUnsafe(value); -const asProjectId = (value: string): ProjectId => ProjectId.makeUnsafe(value); -const asEventId = (value: string): EventId => EventId.makeUnsafe(value); -const asApprovalRequestId = (value: string): ApprovalRequestId => - ApprovalRequestId.makeUnsafe(value); +const asMessageId = (value: string): MessageId => MessageId.make(value); +const asProjectId = (value: string): ProjectId => ProjectId.make(value); +const asEventId = (value: string): EventId => EventId.make(value); +const asApprovalRequestId = (value: string): ApprovalRequestId => ApprovalRequestId.make(value); const PROJECT_ID = asProjectId("project-1"); -const THREAD_ID = ThreadId.makeUnsafe("thread-1"); +const THREAD_ID = ThreadId.make("thread-1"); const FIXTURE_TURN_ID = "fixture-turn"; const APPROVAL_REQUEST_ID = asApprovalRequestId("req-approval-1"); type IntegrationProvider = ProviderKind; @@ -112,7 +111,7 @@ const seedProjectAndThread = (harness: OrchestrationIntegrationHarness) => yield* harness.engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-project-create"), + commandId: CommandId.make("cmd-project-create"), projectId: PROJECT_ID, title: "Integration Project", workspaceRoot: harness.workspaceDir, @@ -125,7 +124,7 @@ const seedProjectAndThread = (harness: OrchestrationIntegrationHarness) => yield* harness.engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-create"), + commandId: CommandId.make("cmd-thread-create"), threadId: THREAD_ID, projectId: PROJECT_ID, title: "Integration Thread", @@ -150,7 +149,7 @@ const startTurn = (input: { }) => input.harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe(input.commandId), + commandId: CommandId.make(input.commandId), threadId: THREAD_ID, message: { messageId: asMessageId(input.messageId), @@ -261,7 +260,7 @@ it.live.skipIf(!process.env.CODEX_BINARY_PATH)( yield* harness.engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-project-create-real-codex"), + commandId: CommandId.make("cmd-project-create-real-codex"), projectId: PROJECT_ID, title: "Integration Project", workspaceRoot: harness.workspaceDir, @@ -274,7 +273,7 @@ it.live.skipIf(!process.env.CODEX_BINARY_PATH)( yield* harness.engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-create-real-codex"), + commandId: CommandId.make("cmd-thread-create-real-codex"), threadId: THREAD_ID, projectId: PROJECT_ID, title: "Integration Thread", @@ -291,7 +290,7 @@ it.live.skipIf(!process.env.CODEX_BINARY_PATH)( yield* harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-real-codex-1"), + commandId: CommandId.make("cmd-turn-start-real-codex-1"), threadId: THREAD_ID, message: { messageId: asMessageId("msg-real-codex-1"), @@ -318,7 +317,7 @@ it.live.skipIf(!process.env.CODEX_BINARY_PATH)( yield* harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-real-codex-2"), + commandId: CommandId.make("cmd-turn-start-real-codex-2"), threadId: THREAD_ID, message: { messageId: asMessageId("msg-real-codex-2"), @@ -583,7 +582,7 @@ it.live("tracks approval requests and resolves pending approvals on user respons yield* harness.engine.dispatch({ type: "thread.approval.respond", - commandId: CommandId.makeUnsafe("cmd-approval-respond"), + commandId: CommandId.make("cmd-approval-respond"), threadId: THREAD_ID, requestId: APPROVAL_REQUEST_ID, decision: "accept", @@ -815,7 +814,7 @@ it.live("reverts to an earlier checkpoint and trims checkpoint projections + git yield* harness.engine.dispatch({ type: "thread.checkpoint.revert", - commandId: CommandId.makeUnsafe("cmd-checkpoint-revert"), + commandId: CommandId.make("cmd-checkpoint-revert"), threadId: THREAD_ID, turnCount: 1, createdAt: nowIso(), @@ -875,7 +874,7 @@ it.live( yield* harness.engine.dispatch({ type: "thread.checkpoint.revert", - commandId: CommandId.makeUnsafe("cmd-checkpoint-revert-no-session"), + commandId: CommandId.make("cmd-checkpoint-revert-no-session"), threadId: THREAD_ID, turnCount: 0, createdAt: nowIso(), @@ -1119,7 +1118,7 @@ it.live("forwards claudeAgent approval responses to the provider session", () => yield* harness.engine.dispatch({ type: "thread.approval.respond", - commandId: CommandId.makeUnsafe("cmd-claude-approval-respond"), + commandId: CommandId.make("cmd-claude-approval-respond"), threadId: THREAD_ID, requestId: APPROVAL_REQUEST_ID, decision: "accept", @@ -1192,7 +1191,7 @@ it.live("forwards thread.turn.interrupt to claudeAgent provider sessions", () => yield* harness.engine.dispatch({ type: "thread.turn.interrupt", - commandId: CommandId.makeUnsafe("cmd-turn-interrupt-claude"), + commandId: CommandId.make("cmd-turn-interrupt-claude"), threadId: THREAD_ID, createdAt: nowIso(), }); @@ -1309,7 +1308,7 @@ it.live("reverts claudeAgent turns and rolls back provider conversation state", yield* harness.engine.dispatch({ type: "thread.checkpoint.revert", - commandId: CommandId.makeUnsafe("cmd-checkpoint-revert-claude"), + commandId: CommandId.make("cmd-checkpoint-revert-claude"), threadId: THREAD_ID, turnCount: 1, createdAt: nowIso(), diff --git a/apps/server/integration/providerService.integration.test.ts b/apps/server/integration/providerService.integration.test.ts index 1ca6fa1b836c8c70b46e9d46a7ec774609175ab7..89cf6ac153d9f250df376fc6880636b9c13bc5e0 100644 --- a/apps/server/integration/providerService.integration.test.ts +++ b/apps/server/integration/providerService.integration.test.ts @@ -122,15 +122,12 @@ it.live("replays typed runtime fixture events", () => yield* Effect.gen(function* () { const provider = yield* ProviderService; - const session = yield* provider.startSession( - ThreadId.makeUnsafe("thread-integration-typed"), - { - threadId: ThreadId.makeUnsafe("thread-integration-typed"), - provider: "codex", - cwd: fixture.cwd, - runtimeMode: "full-access", - }, - ); + const session = yield* provider.startSession(ThreadId.make("thread-integration-typed"), { + threadId: ThreadId.make("thread-integration-typed"), + provider: "codex", + cwd: fixture.cwd, + runtimeMode: "full-access", + }); assert.equal((session.threadId ?? "").length > 0, true); const observedEvents = yield* runTurn({ @@ -157,15 +154,12 @@ it.live("replays file-changing fixture turn events", () => yield* Effect.gen(function* () { const provider = yield* ProviderService; - const session = yield* provider.startSession( - ThreadId.makeUnsafe("thread-integration-tools"), - { - threadId: ThreadId.makeUnsafe("thread-integration-tools"), - provider: "codex", - cwd: fixture.cwd, - runtimeMode: "full-access", - }, - ); + const session = yield* provider.startSession(ThreadId.make("thread-integration-tools"), { + threadId: ThreadId.make("thread-integration-tools"), + provider: "codex", + cwd: fixture.cwd, + runtimeMode: "full-access", + }); assert.equal((session.threadId ?? "").length > 0, true); const observedEvents = yield* runTurn({ @@ -196,15 +190,12 @@ it.live("runs multi-turn tool/approval flow", () => yield* Effect.gen(function* () { const provider = yield* ProviderService; - const session = yield* provider.startSession( - ThreadId.makeUnsafe("thread-integration-multi"), - { - threadId: ThreadId.makeUnsafe("thread-integration-multi"), - provider: "codex", - cwd: fixture.cwd, - runtimeMode: "full-access", - }, - ); + const session = yield* provider.startSession(ThreadId.make("thread-integration-multi"), { + threadId: ThreadId.make("thread-integration-multi"), + provider: "codex", + cwd: fixture.cwd, + runtimeMode: "full-access", + }); assert.equal((session.threadId ?? "").length > 0, true); const firstTurnEvents = yield* runTurn({ @@ -250,15 +241,12 @@ it.live("rolls back provider conversation state only", () => yield* Effect.gen(function* () { const provider = yield* ProviderService; - const session = yield* provider.startSession( - ThreadId.makeUnsafe("thread-integration-rollback"), - { - threadId: ThreadId.makeUnsafe("thread-integration-rollback"), - provider: "codex", - cwd: fixture.cwd, - runtimeMode: "full-access", - }, - ); + const session = yield* provider.startSession(ThreadId.make("thread-integration-rollback"), { + threadId: ThreadId.make("thread-integration-rollback"), + provider: "codex", + cwd: fixture.cwd, + runtimeMode: "full-access", + }); assert.equal((session.threadId ?? "").length > 0, true); yield* runTurn({ diff --git a/apps/server/src/auth/Layers/SessionCredentialService.ts b/apps/server/src/auth/Layers/SessionCredentialService.ts index 53b6ae2abf188b16e873726cec46852b8bdbb613..7fc8178a08df2f2980cb9c7532bbfcdf1784271c 100644 --- a/apps/server/src/auth/Layers/SessionCredentialService.ts +++ b/apps/server/src/auth/Layers/SessionCredentialService.ts @@ -188,7 +188,7 @@ export const makeSessionCredentialService = Effect.gen(function* () { const issue: SessionCredentialServiceShape["issue"] = (input) => Effect.gen(function* () { - const sessionId = AuthSessionId.makeUnsafe(crypto.randomUUID()); + const sessionId = AuthSessionId.make(crypto.randomUUID()); const issuedAt = yield* DateTime.now; const expiresAt = DateTime.add(issuedAt, { milliseconds: Duration.toMillis(input?.ttl ?? DEFAULT_SESSION_TTL), diff --git a/apps/server/src/auth/Services/AuthControlPlane.ts b/apps/server/src/auth/Services/AuthControlPlane.ts index cbaaf98fd341b71c6d52560b2359f474f5e578ca..b59e330bcaa41ecb1d2fb56f45d5eeb100edce63 100644 --- a/apps/server/src/auth/Services/AuthControlPlane.ts +++ b/apps/server/src/auth/Services/AuthControlPlane.ts @@ -4,7 +4,7 @@ import type { AuthPairingLink, AuthSessionId, } from "@t3tools/contracts"; -import { Data, DateTime, Duration, Effect, ServiceMap } from "effect"; +import { Data, DateTime, Duration, Effect, Context } from "effect"; import { SessionRole } from "./SessionCredentialService"; export const DEFAULT_SESSION_SUBJECT = "cli-issued-session"; @@ -64,6 +64,6 @@ export interface AuthControlPlaneShape { ) => Effect.Effect; } -export class AuthControlPlane extends ServiceMap.Service()( +export class AuthControlPlane extends Context.Service()( "t3/AuthControlPlane", ) {} diff --git a/apps/server/src/auth/Services/BootstrapCredentialService.ts b/apps/server/src/auth/Services/BootstrapCredentialService.ts index 4f5cf4fdab179098f3f79af568be0d7247fa224a..bcb6119a22e188dbebb51604b6b07a01ea34a0bd 100644 --- a/apps/server/src/auth/Services/BootstrapCredentialService.ts +++ b/apps/server/src/auth/Services/BootstrapCredentialService.ts @@ -1,5 +1,5 @@ import type { AuthPairingLink, ServerAuthBootstrapMethod } from "@t3tools/contracts"; -import { Data, DateTime, Duration, ServiceMap } from "effect"; +import { Data, DateTime, Duration, Context } from "effect"; import type { Effect, Stream } from "effect"; export type BootstrapCredentialRole = "owner" | "client"; @@ -51,7 +51,7 @@ export interface BootstrapCredentialServiceShape { readonly consume: (credential: string) => Effect.Effect; } -export class BootstrapCredentialService extends ServiceMap.Service< +export class BootstrapCredentialService extends Context.Service< BootstrapCredentialService, BootstrapCredentialServiceShape >()("t3/auth/Services/BootstrapCredentialService") {} diff --git a/apps/server/src/auth/Services/ServerAuth.ts b/apps/server/src/auth/Services/ServerAuth.ts index 0e38679b85ec535658bf3aaa1a6b8c4cddbd828e..07be98269bf9e02483e3953a062033ef651b9fcc 100644 --- a/apps/server/src/auth/Services/ServerAuth.ts +++ b/apps/server/src/auth/Services/ServerAuth.ts @@ -12,7 +12,7 @@ import type { ServerAuthSessionMethod, AuthWebSocketTokenResult, } from "@t3tools/contracts"; -import { Data, DateTime, ServiceMap } from "effect"; +import { Data, DateTime, Context } from "effect"; import type { Effect } from "effect"; import type * as HttpServerRequest from "effect/unstable/http/HttpServerRequest"; import type { SessionRole } from "./SessionCredentialService.ts"; @@ -79,6 +79,6 @@ export interface ServerAuthShape { readonly issueStartupPairingUrl: (baseUrl: string) => Effect.Effect; } -export class ServerAuth extends ServiceMap.Service()( +export class ServerAuth extends Context.Service()( "t3/auth/Services/ServerAuth", ) {} diff --git a/apps/server/src/auth/Services/ServerAuthPolicy.ts b/apps/server/src/auth/Services/ServerAuthPolicy.ts index 43dae6ca698c8aef87eecd24745ee3aad4fc8b78..530d776998c16fcfe9f76c8fa641feab6a439cfa 100644 --- a/apps/server/src/auth/Services/ServerAuthPolicy.ts +++ b/apps/server/src/auth/Services/ServerAuthPolicy.ts @@ -1,11 +1,11 @@ import type { ServerAuthDescriptor } from "@t3tools/contracts"; -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect } from "effect"; export interface ServerAuthPolicyShape { readonly getDescriptor: () => Effect.Effect; } -export class ServerAuthPolicy extends ServiceMap.Service()( +export class ServerAuthPolicy extends Context.Service()( "t3/auth/Services/ServerAuthPolicy", ) {} diff --git a/apps/server/src/auth/Services/ServerSecretStore.ts b/apps/server/src/auth/Services/ServerSecretStore.ts index 376527aea31fbc6f921cc0ba13f2584eae2c969a..7d97b4c3a101d5078acc056b1038be1c1500525b 100644 --- a/apps/server/src/auth/Services/ServerSecretStore.ts +++ b/apps/server/src/auth/Services/ServerSecretStore.ts @@ -1,4 +1,4 @@ -import { Data, ServiceMap } from "effect"; +import { Data, Context } from "effect"; import type { Effect } from "effect"; export class SecretStoreError extends Data.TaggedError("SecretStoreError")<{ @@ -16,7 +16,6 @@ export interface ServerSecretStoreShape { readonly remove: (name: string) => Effect.Effect; } -export class ServerSecretStore extends ServiceMap.Service< - ServerSecretStore, - ServerSecretStoreShape ->()("t3/auth/Services/ServerSecretStore") {} +export class ServerSecretStore extends Context.Service()( + "t3/auth/Services/ServerSecretStore", +) {} diff --git a/apps/server/src/auth/Services/SessionCredentialService.ts b/apps/server/src/auth/Services/SessionCredentialService.ts index 591504766ea2d797c2f06f9e2781e9bb5e387323..3d72b5a636cb7ac8ba735ef6a655270bb4adc08a 100644 --- a/apps/server/src/auth/Services/SessionCredentialService.ts +++ b/apps/server/src/auth/Services/SessionCredentialService.ts @@ -4,7 +4,7 @@ import type { AuthSessionId, ServerAuthSessionMethod, } from "@t3tools/contracts"; -import { Data, DateTime, Duration, ServiceMap } from "effect"; +import { Data, DateTime, Duration, Context } from "effect"; import type { Effect, Stream } from "effect"; export type SessionRole = "owner" | "client"; @@ -81,7 +81,7 @@ export interface SessionCredentialServiceShape { readonly markDisconnected: (sessionId: AuthSessionId) => Effect.Effect; } -export class SessionCredentialService extends ServiceMap.Service< +export class SessionCredentialService extends Context.Service< SessionCredentialService, SessionCredentialServiceShape >()("t3/auth/Services/SessionCredentialService") {} diff --git a/apps/server/src/checkpointing/Layers/CheckpointDiffQuery.test.ts b/apps/server/src/checkpointing/Layers/CheckpointDiffQuery.test.ts index c66c529b9aae6d549e8b4e2f7c03ee3a1919462a..21cbe1509aa4553ab9df93a13fcfed06159b4e0c 100644 --- a/apps/server/src/checkpointing/Layers/CheckpointDiffQuery.test.ts +++ b/apps/server/src/checkpointing/Layers/CheckpointDiffQuery.test.ts @@ -26,7 +26,7 @@ function makeThreadCheckpointContext(input: { worktreePath: input.worktreePath, checkpoints: [ { - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), checkpointTurnCount: input.checkpointTurnCount, checkpointRef: input.checkpointRef, status: "ready", @@ -40,8 +40,8 @@ function makeThreadCheckpointContext(input: { describe("CheckpointDiffQueryLive", () => { it("computes diffs using canonical turn-0 checkpoint refs", async () => { - const projectId = ProjectId.makeUnsafe("project-1"); - const threadId = ThreadId.makeUnsafe("thread-1"); + const projectId = ProjectId.make("project-1"); + const threadId = ThreadId.make("thread-1"); const toCheckpointRef = checkpointRefForThreadTurn(threadId, 1); const hasCheckpointRefCalls: Array = []; const diffCheckpointsCalls: Array<{ @@ -119,7 +119,7 @@ describe("CheckpointDiffQueryLive", () => { }); it("fails when the thread is missing from the snapshot", async () => { - const threadId = ThreadId.makeUnsafe("thread-missing"); + const threadId = ThreadId.make("thread-missing"); const checkpointStore: CheckpointStoreShape = { isGitRepository: () => Effect.succeed(true), diff --git a/apps/server/src/checkpointing/Layers/CheckpointStore.test.ts b/apps/server/src/checkpointing/Layers/CheckpointStore.test.ts index 6e7b18277cfa4d19c5b18a00df6c077462ef1ecb..fe377eb1ec3f147c39e274560b37b32416f87d1c 100644 --- a/apps/server/src/checkpointing/Layers/CheckpointStore.test.ts +++ b/apps/server/src/checkpointing/Layers/CheckpointStore.test.ts @@ -93,7 +93,7 @@ it.layer(TestLayer)("CheckpointStoreLive", (it) => { const tmp = yield* makeTmpDir(); yield* initRepoWithCommit(tmp); const checkpointStore = yield* CheckpointStore; - const threadId = ThreadId.makeUnsafe("thread-checkpoint-store"); + const threadId = ThreadId.make("thread-checkpoint-store"); const fromCheckpointRef = checkpointRefForThreadTurn(threadId, 0); const toCheckpointRef = checkpointRefForThreadTurn(threadId, 1); diff --git a/apps/server/src/checkpointing/Services/CheckpointDiffQuery.ts b/apps/server/src/checkpointing/Services/CheckpointDiffQuery.ts index 2204294a435d2abef0e0e35c03e33e1193d9d0db..d865256ac5958ad2b71e6f3d1c55066b5a04c4fa 100644 --- a/apps/server/src/checkpointing/Services/CheckpointDiffQuery.ts +++ b/apps/server/src/checkpointing/Services/CheckpointDiffQuery.ts @@ -12,7 +12,7 @@ import type { OrchestrationGetTurnDiffInput, OrchestrationGetTurnDiffResult, } from "@t3tools/contracts"; -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect } from "effect"; import type { CheckpointServiceError } from "../Errors.ts"; @@ -43,7 +43,7 @@ export interface CheckpointDiffQueryShape { /** * CheckpointDiffQuery - Service tag for checkpoint diff queries. */ -export class CheckpointDiffQuery extends ServiceMap.Service< +export class CheckpointDiffQuery extends Context.Service< CheckpointDiffQuery, CheckpointDiffQueryShape >()("t3/checkpointing/Services/CheckpointDiffQuery") {} diff --git a/apps/server/src/checkpointing/Services/CheckpointStore.ts b/apps/server/src/checkpointing/Services/CheckpointStore.ts index 284198c1456a662f589b8782a357dca4666b05d6..d9a43fa4e9524f7cee7a23b80e65ee46bc4fc4b7 100644 --- a/apps/server/src/checkpointing/Services/CheckpointStore.ts +++ b/apps/server/src/checkpointing/Services/CheckpointStore.ts @@ -5,12 +5,12 @@ * workspace thread timeline. It does not store user-facing checkpoint metadata * and does not coordinate provider conversation rollback. * - * Uses Effect `ServiceMap.Service` for dependency injection and exposes typed + * Uses Effect `Context.Service` for dependency injection and exposes typed * domain errors for checkpoint storage operations. * * @module CheckpointStore */ -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect } from "effect"; import type { CheckpointStoreError } from "../Errors.ts"; @@ -95,6 +95,6 @@ export interface CheckpointStoreShape { /** * CheckpointStore - Service tag for checkpoint persistence and restore operations. */ -export class CheckpointStore extends ServiceMap.Service()( +export class CheckpointStore extends Context.Service()( "t3/checkpointing/Services/CheckpointStore", ) {} diff --git a/apps/server/src/checkpointing/Utils.ts b/apps/server/src/checkpointing/Utils.ts index 3cd92f8510d418c3cf5a997e14b951a82843bd23..c709aa3735cdb561ba2b7468c6e39a4b38998371 100644 --- a/apps/server/src/checkpointing/Utils.ts +++ b/apps/server/src/checkpointing/Utils.ts @@ -4,7 +4,7 @@ import { CheckpointRef, ProjectId, type ThreadId } from "@t3tools/contracts"; export const CHECKPOINT_REFS_PREFIX = "refs/t3/checkpoints"; export function checkpointRefForThreadTurn(threadId: ThreadId, turnCount: number): CheckpointRef { - return CheckpointRef.makeUnsafe( + return CheckpointRef.make( `${CHECKPOINT_REFS_PREFIX}/${Encoding.encodeBase64Url(threadId)}/turn/${turnCount}`, ); } diff --git a/apps/server/src/cli-config.test.ts b/apps/server/src/cli-config.test.ts index a49d9ac5ac57c24c7d660bbeb37017105c3329aa..6fa6e0c96b67df52a12c54a1984cf8227f8aa655 100644 --- a/apps/server/src/cli-config.test.ts +++ b/apps/server/src/cli-config.test.ts @@ -153,6 +153,69 @@ it.layer(NodeServices.layer)("cli config resolution", (it) => { }), ); + it.effect("preserves explicit false CLI boolean flags over env and bootstrap values", () => + Effect.gen(function* () { + const { join } = yield* Path.Path; + const baseDir = join(os.tmpdir(), "t3-cli-config-false-flags"); + const fd = yield* openBootstrapFd({ + noBrowser: true, + autoBootstrapProjectFromCwd: true, + logWebSocketEvents: true, + }); + const derivedPaths = yield* deriveServerPaths(baseDir, new URL("http://127.0.0.1:4173")); + + const resolved = yield* resolveServerConfig( + { + mode: Option.some("web"), + port: Option.some(8788), + host: Option.some("127.0.0.1"), + baseDir: Option.some(baseDir), + cwd: Option.none(), + devUrl: Option.some(new URL("http://127.0.0.1:4173")), + noBrowser: Option.some(false), + bootstrapFd: Option.none(), + autoBootstrapProjectFromCwd: Option.some(false), + logWebSocketEvents: Option.some(false), + }, + Option.none(), + ).pipe( + Effect.provide( + Layer.mergeAll( + ConfigProvider.layer( + ConfigProvider.fromEnv({ + env: { + T3CODE_BOOTSTRAP_FD: String(fd), + T3CODE_NO_BROWSER: "true", + T3CODE_AUTO_BOOTSTRAP_PROJECT_FROM_CWD: "true", + T3CODE_LOG_WS_EVENTS: "true", + }, + }), + ), + NetService.layer, + ), + ), + ); + + expect(resolved).toEqual({ + logLevel: "Info", + ...defaultObservabilityConfig, + mode: "web", + port: 8788, + cwd: process.cwd(), + baseDir, + ...derivedPaths, + host: "127.0.0.1", + staticDir: undefined, + devUrl: new URL("http://127.0.0.1:4173"), + noBrowser: false, + startupPresentation: "browser", + desktopBootstrapToken: undefined, + autoBootstrapProjectFromCwd: false, + logWebSocketEvents: false, + }); + }), + ); + it.effect("uses bootstrap envelope values as fallbacks when flags and env are absent", () => Effect.gen(function* () { const { join } = yield* Path.Path; diff --git a/apps/server/src/cli.test.ts b/apps/server/src/cli.test.ts index e739684c6b19fa351746a361b17567f23884b7b1..7ebde01067a7c14e5e7fe4ccc14a320751d162ab 100644 --- a/apps/server/src/cli.test.ts +++ b/apps/server/src/cli.test.ts @@ -152,6 +152,10 @@ it.layer(NodeServices.layer)("cli log-level parsing", (it) => { runCliWithRuntime(["--log-level", "debug", "--version"]), ); + it.effect("accepts canonical --no- boolean negation", () => + runCliWithRuntime(["--no-log-websocket-events", "--version"]), + ); + it.effect("rejects invalid log-level casing before launching the server", () => Effect.gen(function* () { const error = yield* runCliWithRuntime(["--log-level", "Debug"]).pipe(Effect.flip); diff --git a/apps/server/src/cli.ts b/apps/server/src/cli.ts index 4843419ba9e8294e5c633a53970bfa5492b4d84d..5f737509202bef7e9333cc290d0cb41c78bbb63c 100644 --- a/apps/server/src/cli.ts +++ b/apps/server/src/cli.ts @@ -193,9 +193,6 @@ interface CliAuthLocationFlags { readonly devUrl?: Option.Option; } -const resolveBooleanFlag = (flag: Option.Option, envValue: boolean) => - Option.getOrElse(Option.filter(flag, Boolean), () => envValue); - const resolveOptionPrecedence = ( ...values: ReadonlyArray> ): Option.Option => Option.firstSomeOf(values); @@ -241,12 +238,13 @@ export const resolveServerConfig = ( bootstrapFd !== undefined ? yield* readBootstrapEnvelope(BootstrapEnvelopeSchema, bootstrapFd) : Option.none(); + const bootstrap = Option.getOrUndefined(bootstrapEnvelope); const mode: RuntimeMode = Option.getOrElse( resolveOptionPrecedence( normalizedFlags.mode, Option.fromUndefinedOr(env.mode), - Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.mode)), + Option.fromUndefinedOr(bootstrap?.mode), ), () => "web", ); @@ -255,7 +253,7 @@ export const resolveServerConfig = ( resolveOptionPrecedence( normalizedFlags.port, Option.fromUndefinedOr(env.port), - Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.port)), + Option.fromUndefinedOr(bootstrap?.port), ), { onSome: (value) => Effect.succeed(value), @@ -271,7 +269,7 @@ export const resolveServerConfig = ( resolveOptionPrecedence( normalizedFlags.devUrl, Option.fromUndefinedOr(env.devUrl), - Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.devUrl)), + Option.fromUndefinedOr(bootstrap?.devUrl), ), () => undefined, ); @@ -280,9 +278,7 @@ export const resolveServerConfig = ( resolveOptionPrecedence( normalizedFlags.baseDir, Option.fromUndefinedOr(env.t3Home), - Option.flatMap(bootstrapEnvelope, (bootstrap) => - Option.fromUndefinedOr(bootstrap.t3Home), - ), + Option.fromUndefinedOr(bootstrap?.t3Home), ), ), ); @@ -297,60 +293,41 @@ export const resolveServerConfig = ( const serverTracePath = env.traceFile ?? derivedPaths.serverTracePath; yield* fs.makeDirectory(path.dirname(serverTracePath), { recursive: true }); const startupPresentation = options?.startupPresentation ?? "browser"; - const noBrowser = - startupPresentation === "headless" - ? true - : resolveBooleanFlag( - normalizedFlags.noBrowser, - Option.getOrElse( - resolveOptionPrecedence( - Option.fromUndefinedOr(env.noBrowser), - Option.flatMap(bootstrapEnvelope, (bootstrap) => - Option.fromUndefinedOr(bootstrap.noBrowser), - ), - ), - () => mode === "desktop", - ), - ); - const desktopBootstrapToken = Option.getOrUndefined( - Option.flatMap(bootstrapEnvelope, (bootstrap) => - Option.fromUndefinedOr(bootstrap.desktopBootstrapToken), + const isHeadlessStartup = startupPresentation === "headless"; + const noBrowser = Option.getOrElse( + resolveOptionPrecedence( + isHeadlessStartup ? Option.some(true) : Option.none(), + normalizedFlags.noBrowser, + Option.fromUndefinedOr(env.noBrowser), + Option.fromUndefinedOr(bootstrap?.noBrowser), ), + () => mode === "desktop", ); - const autoBootstrapProjectFromCwd = - options?.forceAutoBootstrapProjectFromCwd ?? - (startupPresentation === "headless" - ? false - : resolveBooleanFlag( - normalizedFlags.autoBootstrapProjectFromCwd, - Option.getOrElse( - resolveOptionPrecedence( - Option.fromUndefinedOr(env.autoBootstrapProjectFromCwd), - Option.flatMap(bootstrapEnvelope, (bootstrap) => - Option.fromUndefinedOr(bootstrap.autoBootstrapProjectFromCwd), - ), - ), - () => mode === "web", - ), - )); - const logWebSocketEvents = resolveBooleanFlag( - normalizedFlags.logWebSocketEvents, - Option.getOrElse( - resolveOptionPrecedence( - Option.fromUndefinedOr(env.logWebSocketEvents), - Option.flatMap(bootstrapEnvelope, (bootstrap) => - Option.fromUndefinedOr(bootstrap.logWebSocketEvents), - ), - ), - () => Boolean(devUrl), + const desktopBootstrapToken = bootstrap?.desktopBootstrapToken; + const autoBootstrapProjectFromCwd = Option.getOrElse( + resolveOptionPrecedence( + Option.fromUndefinedOr(options?.forceAutoBootstrapProjectFromCwd), + isHeadlessStartup ? Option.some(false) : Option.none(), + normalizedFlags.autoBootstrapProjectFromCwd, + Option.fromUndefinedOr(env.autoBootstrapProjectFromCwd), + Option.fromUndefinedOr(bootstrap?.autoBootstrapProjectFromCwd), ), + () => mode === "web", + ); + const logWebSocketEvents = Option.getOrElse( + resolveOptionPrecedence( + normalizedFlags.logWebSocketEvents, + Option.fromUndefinedOr(env.logWebSocketEvents), + Option.fromUndefinedOr(bootstrap?.logWebSocketEvents), + ), + () => Boolean(devUrl), ); const staticDir = devUrl ? undefined : yield* resolveStaticDir(); const host = Option.getOrElse( resolveOptionPrecedence( normalizedFlags.host, Option.fromUndefinedOr(env.host), - Option.flatMap(bootstrapEnvelope, (bootstrap) => Option.fromUndefinedOr(bootstrap.host)), + Option.fromUndefinedOr(bootstrap?.host), ), () => (mode === "desktop" ? "127.0.0.1" : undefined), ); @@ -365,19 +342,11 @@ export const resolveServerConfig = ( traceMaxFiles: env.traceMaxFiles, otlpTracesUrl: env.otlpTracesUrl ?? - Option.getOrUndefined( - Option.flatMap(bootstrapEnvelope, (bootstrap) => - Option.fromUndefinedOr(bootstrap.otlpTracesUrl), - ), - ) ?? + bootstrap?.otlpTracesUrl ?? persistedObservabilitySettings.otlpTracesUrl, otlpMetricsUrl: env.otlpMetricsUrl ?? - Option.getOrUndefined( - Option.flatMap(bootstrapEnvelope, (bootstrap) => - Option.fromUndefinedOr(bootstrap.otlpMetricsUrl), - ), - ) ?? + bootstrap?.otlpMetricsUrl ?? persistedObservabilitySettings.otlpMetricsUrl, otlpExportIntervalMs: env.otlpExportIntervalMs, otlpServiceName: env.otlpServiceName, @@ -1030,10 +999,10 @@ const projectAddCommand = Command.make("add", { } const title = yield* resolveProjectTitle(workspaceRoot, Option.getOrUndefined(flags.title)); - const projectId = ProjectId.makeUnsafe(crypto.randomUUID()); + const projectId = ProjectId.make(crypto.randomUUID()); yield* dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe(crypto.randomUUID()), + commandId: CommandId.make(crypto.randomUUID()), projectId, title, workspaceRoot, @@ -1071,7 +1040,7 @@ const projectRemoveCommand = Command.make("remove", { }); yield* dispatch({ type: "project.delete", - commandId: CommandId.makeUnsafe(crypto.randomUUID()), + commandId: CommandId.make(crypto.randomUUID()), projectId: project.id, }); return `Removed project ${project.id} (${project.title}).`; @@ -1111,7 +1080,7 @@ const projectRenameCommand = Command.make("rename", { yield* dispatch({ type: "project.meta.update", - commandId: CommandId.makeUnsafe(crypto.randomUUID()), + commandId: CommandId.make(crypto.randomUUID()), projectId: project.id, title: nextTitle, }); diff --git a/apps/server/src/codexAppServerManager.test.ts b/apps/server/src/codexAppServerManager.test.ts index 2f740a74077913dcfa080e073215e2009a576c0c..ab3b7a569dec50e5bfe21c209e69e56d1e95cc6e 100644 --- a/apps/server/src/codexAppServerManager.test.ts +++ b/apps/server/src/codexAppServerManager.test.ts @@ -17,7 +17,7 @@ import { resolveCodexModelForAccount, } from "./codexAppServerManager"; -const asThreadId = (value: string): ThreadId => ThreadId.makeUnsafe(value); +const asThreadId = (value: string): ThreadId => ThreadId.make(value); function createSendTurnHarness() { const manager = new CodexAppServerManager(); @@ -111,9 +111,9 @@ function createPendingUserInputHarness() { }, pendingUserInputs: new Map([ [ - ApprovalRequestId.makeUnsafe("req-user-input-1"), + ApprovalRequestId.make("req-user-input-1"), { - requestId: ApprovalRequestId.makeUnsafe("req-user-input-1"), + requestId: ApprovalRequestId.make("req-user-input-1"), jsonRpcId: 42, threadId: asThreadId("thread_1"), }, @@ -743,7 +743,7 @@ describe("respondToUserInput", () => { await manager.respondToUserInput( asThreadId("thread_1"), - ApprovalRequestId.makeUnsafe("req-user-input-1"), + ApprovalRequestId.make("req-user-input-1"), { scope: "All request methods", compat: "Keep current envelope", @@ -780,7 +780,7 @@ describe("respondToUserInput", () => { await manager.respondToUserInput( asThreadId("thread_1"), - ApprovalRequestId.makeUnsafe("req-user-input-1"), + ApprovalRequestId.make("req-user-input-1"), { scope: [], }, diff --git a/apps/server/src/codexAppServerManager.ts b/apps/server/src/codexAppServerManager.ts index bea28168a617d2d142c7075049d71dafec0d61d1..230ba8e36412438d34c2c5871833c97f14ff0ea7 100644 --- a/apps/server/src/codexAppServerManager.ts +++ b/apps/server/src/codexAppServerManager.ts @@ -19,7 +19,7 @@ import { ProviderInteractionMode, } from "@t3tools/contracts"; import { normalizeModelSlug } from "@t3tools/shared/model"; -import { Effect, ServiceMap } from "effect"; +import { Effect, Context } from "effect"; import { formatCodexCliUpgradeMessage, @@ -439,7 +439,7 @@ export class CodexAppServerManager extends EventEmitter(); private runPromise: (effect: Effect.Effect) => Promise; - constructor(services?: ServiceMap.ServiceMap) { + constructor(services?: Context.Context) { super(); this.runPromise = services ? Effect.runPromiseWith(services) : Effect.runPromise; } @@ -640,7 +640,7 @@ export class CodexAppServerManager extends EventEmitter { const turn = this.readObject(turnValue); const turnIdRaw = this.readString(turn, "id") ?? `${threadIdRaw}:turn:${index + 1}`; - const turnId = TurnId.makeUnsafe(turnIdRaw); + const turnId = TurnId.make(turnIdRaw); const items = this.readArray(turn, "items") ?? []; return { id: turnId, @@ -1590,9 +1590,9 @@ function readResumeThreadId(input: { } function toTurnId(value: string | undefined): TurnId | undefined { - return brandIfNonEmpty(value, TurnId.makeUnsafe); + return brandIfNonEmpty(value, TurnId.make); } function toProviderItemId(value: string | undefined): ProviderItemId | undefined { - return brandIfNonEmpty(value, ProviderItemId.makeUnsafe); + return brandIfNonEmpty(value, ProviderItemId.make); } diff --git a/apps/server/src/config.ts b/apps/server/src/config.ts index 980b9330bf9bf976b692ec768a6c6405aa16d24a..c2e5ecee459543ced57ce88ca25ae639ee564022 100644 --- a/apps/server/src/config.ts +++ b/apps/server/src/config.ts @@ -6,7 +6,7 @@ * * @module ServerConfig */ -import { Effect, FileSystem, Layer, LogLevel, Path, Schema, ServiceMap } from "effect"; +import { Effect, FileSystem, Layer, LogLevel, Path, Schema, Context } from "effect"; export const DEFAULT_PORT = 3773; @@ -120,7 +120,7 @@ export const ensureServerDirectories = Effect.fn(function* (derivedPaths: Server /** * ServerConfig - Service tag for server runtime configuration. */ -export class ServerConfig extends ServiceMap.Service()( +export class ServerConfig extends Context.Service()( "t3/config/ServerConfig", ) { static readonly layerTest = (cwd: string, baseDirOrPrefix: string | { prefix: string }) => diff --git a/apps/server/src/environment/Layers/ServerEnvironment.ts b/apps/server/src/environment/Layers/ServerEnvironment.ts index 58102378c65dbbe5a6de87cd0865727683a57a0b..506fc45af795962f69be9e558c9d4467fa67ac5b 100644 --- a/apps/server/src/environment/Layers/ServerEnvironment.ts +++ b/apps/server/src/environment/Layers/ServerEnvironment.ts @@ -64,7 +64,7 @@ export const makeServerEnvironment = Effect.fn("makeServerEnvironment")(function return generated; }); - const environmentId = EnvironmentId.makeUnsafe(environmentIdRaw); + const environmentId = EnvironmentId.make(environmentIdRaw); const cwdBaseName = path.basename(serverConfig.cwd).trim(); const label = yield* resolveServerEnvironmentLabel({ cwdBaseName, diff --git a/apps/server/src/environment/Layers/ServerEnvironmentLabel.ts b/apps/server/src/environment/Layers/ServerEnvironmentLabel.ts index a5f77c5093bd59e0d1be37706f6409d55cf6837d..dc776583262596529bef7fb5b12c95592312d54e 100644 --- a/apps/server/src/environment/Layers/ServerEnvironmentLabel.ts +++ b/apps/server/src/environment/Layers/ServerEnvironmentLabel.ts @@ -51,11 +51,13 @@ const runFriendlyLabelCommand = Effect.fn("runFriendlyLabelCommand")(function* ( command: string, args: readonly string[], ) { - const result = yield* Effect.tryPromise(() => - runProcess(command, args, { - allowNonZeroExit: true, - }), - ).pipe(Effect.orElseSucceed(() => null)); + const result = yield* Effect.tryPromise({ + try: () => + runProcess(command, args, { + allowNonZeroExit: true, + }), + catch: () => null, + }).pipe(Effect.orElseSucceed(() => null)); if (!result || result.code !== 0) { return null; diff --git a/apps/server/src/environment/Services/ServerEnvironment.ts b/apps/server/src/environment/Services/ServerEnvironment.ts index 9cf432ca727631ce0296f4f93ec40e518095ba9e..4858680333281e020da450d9dfef8433b3f3adbe 100644 --- a/apps/server/src/environment/Services/ServerEnvironment.ts +++ b/apps/server/src/environment/Services/ServerEnvironment.ts @@ -1,5 +1,5 @@ import type { EnvironmentId, ExecutionEnvironmentDescriptor } from "@t3tools/contracts"; -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect } from "effect"; export interface ServerEnvironmentShape { @@ -7,7 +7,6 @@ export interface ServerEnvironmentShape { readonly getDescriptor: Effect.Effect; } -export class ServerEnvironment extends ServiceMap.Service< - ServerEnvironment, - ServerEnvironmentShape ->()("t3/environment/Services/ServerEnvironment") {} +export class ServerEnvironment extends Context.Service()( + "t3/environment/Services/ServerEnvironment", +) {} diff --git a/apps/server/src/git/Layers/GitCore.test.ts b/apps/server/src/git/Layers/GitCore.test.ts index 39576341049236e5bf73121431ccf6fac453462d..53b881b66664eee823c220896a4311698d185fb3 100644 --- a/apps/server/src/git/Layers/GitCore.test.ts +++ b/apps/server/src/git/Layers/GitCore.test.ts @@ -649,8 +649,8 @@ it.layer(TestLayer)("git integration", (it) => { it.effect("refreshes upstream behind count after checkout when remote branch advanced", () => Effect.gen(function* () { - const services = yield* Effect.services(); - const runPromise = Effect.runPromiseWith(services); + const context = yield* Effect.context(); + const runPromise = Effect.runPromiseWith(context); const remote = yield* makeTmpDir(); const source = yield* makeTmpDir(); diff --git a/apps/server/src/git/Layers/GitCore.ts b/apps/server/src/git/Layers/GitCore.ts index 394293593257cffebba4bc6334ddf302edbed6ba..e5547377b416caab2b7c4a024e6c53941ed9c6f8 100644 --- a/apps/server/src/git/Layers/GitCore.ts +++ b/apps/server/src/git/Layers/GitCore.ts @@ -933,9 +933,8 @@ export const makeGitCore = Effect.fn("makeGitCore")(function* (options?: { return true as const; }); - const statusUpstreamRefreshCache = yield* Cache.makeWith({ + const statusUpstreamRefreshCache = yield* Cache.makeWith(refreshStatusUpstreamCacheEntry, { capacity: STATUS_UPSTREAM_REFRESH_CACHE_CAPACITY, - lookup: refreshStatusUpstreamCacheEntry, // Keep successful refreshes warm and briefly back off failed refreshes to avoid retry storms. timeToLive: (exit) => Exit.isSuccess(exit) diff --git a/apps/server/src/git/Layers/GitManager.ts b/apps/server/src/git/Layers/GitManager.ts index d5e7eca2174d54d33529c181ef7f7f713ef04816..33e9719804bcade0cc3f1b6e2789d4276f5f37e0 100644 --- a/apps/server/src/git/Layers/GitManager.ts +++ b/apps/server/src/git/Layers/GitManager.ts @@ -731,9 +731,8 @@ export const makeGitManager = Effect.fn("makeGitManager")(function* () { workingTree: details.workingTree, } satisfies GitStatusLocalResult; }); - const localStatusResultCache = yield* Cache.makeWith({ + const localStatusResultCache = yield* Cache.makeWith(readLocalStatus, { capacity: STATUS_RESULT_CACHE_CAPACITY, - lookup: readLocalStatus, timeToLive: (exit) => (Exit.isSuccess(exit) ? STATUS_RESULT_CACHE_TTL : Duration.zero), }); const invalidateLocalStatusResultCache = (cwd: string) => @@ -764,9 +763,8 @@ export const makeGitManager = Effect.fn("makeGitManager")(function* () { pr, } satisfies GitStatusRemoteResult; }); - const remoteStatusResultCache = yield* Cache.makeWith({ + const remoteStatusResultCache = yield* Cache.makeWith(readRemoteStatus, { capacity: STATUS_RESULT_CACHE_CAPACITY, - lookup: readRemoteStatus, timeToLive: (exit) => (Exit.isSuccess(exit) ? STATUS_RESULT_CACHE_TTL : Duration.zero), }); const invalidateRemoteStatusResultCache = (cwd: string) => diff --git a/apps/server/src/git/Layers/RoutingTextGeneration.ts b/apps/server/src/git/Layers/RoutingTextGeneration.ts index dee12a3e0e790591690d63ebd1c75a614103525f..5372bc134915c62d421937e5faf0fdf6f7acc346 100644 --- a/apps/server/src/git/Layers/RoutingTextGeneration.ts +++ b/apps/server/src/git/Layers/RoutingTextGeneration.ts @@ -9,7 +9,7 @@ * * @module RoutingTextGeneration */ -import { Effect, Layer, ServiceMap } from "effect"; +import { Effect, Layer, Context } from "effect"; import { TextGeneration, @@ -23,11 +23,11 @@ import { ClaudeTextGenerationLive } from "./ClaudeTextGeneration.ts"; // Internal service tags so both concrete layers can coexist. // --------------------------------------------------------------------------- -class CodexTextGen extends ServiceMap.Service()( +class CodexTextGen extends Context.Service()( "t3/git/Layers/RoutingTextGeneration/CodexTextGen", ) {} -class ClaudeTextGen extends ServiceMap.Service()( +class ClaudeTextGen extends Context.Service()( "t3/git/Layers/RoutingTextGeneration/ClaudeTextGen", ) {} diff --git a/apps/server/src/git/Services/GitCore.ts b/apps/server/src/git/Services/GitCore.ts index 015efa8bbdba63df02b7a84469d21ca3db7ec3cd..9f3bc0b9b9168499a791098a470f9d1c3ac37ebb 100644 --- a/apps/server/src/git/Services/GitCore.ts +++ b/apps/server/src/git/Services/GitCore.ts @@ -6,7 +6,7 @@ * * @module GitCore */ -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect } from "effect"; import type { GitCheckoutInput, @@ -310,6 +310,4 @@ export interface GitCoreShape { /** * GitCore - Service tag for low-level Git repository operations. */ -export class GitCore extends ServiceMap.Service()( - "t3/git/Services/GitCore", -) {} +export class GitCore extends Context.Service()("t3/git/Services/GitCore") {} diff --git a/apps/server/src/git/Services/GitHubCli.ts b/apps/server/src/git/Services/GitHubCli.ts index 38afdd5f9211a7d96d15783f03cab01330eb5592..216c24bf7c5b09e837eb8b529f921475554a4868 100644 --- a/apps/server/src/git/Services/GitHubCli.ts +++ b/apps/server/src/git/Services/GitHubCli.ts @@ -5,7 +5,7 @@ * * @module GitHubCli */ -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect } from "effect"; import type { ProcessRunResult } from "../../processRunner"; @@ -98,6 +98,6 @@ export interface GitHubCliShape { /** * GitHubCli - Service tag for GitHub CLI process execution. */ -export class GitHubCli extends ServiceMap.Service()( +export class GitHubCli extends Context.Service()( "t3/git/Services/GitHubCli", ) {} diff --git a/apps/server/src/git/Services/GitManager.ts b/apps/server/src/git/Services/GitManager.ts index 0e04ceedcb28e0284db680e8fb996c3229f611c6..29c762195e57a41fcc197203aff4cd45c47d92d2 100644 --- a/apps/server/src/git/Services/GitManager.ts +++ b/apps/server/src/git/Services/GitManager.ts @@ -19,7 +19,7 @@ import { GitStatusInput, GitStatusResult, } from "@t3tools/contracts"; -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect } from "effect"; import type { GitManagerServiceError } from "@t3tools/contracts"; @@ -99,6 +99,6 @@ export interface GitManagerShape { /** * GitManager - Service tag for stacked Git workflow orchestration. */ -export class GitManager extends ServiceMap.Service()( +export class GitManager extends Context.Service()( "t3/git/Services/GitManager", ) {} diff --git a/apps/server/src/git/Services/GitStatusBroadcaster.ts b/apps/server/src/git/Services/GitStatusBroadcaster.ts index b898b03f56a75226d4215e32bdbfcf97a59da5c5..647f840824228d967fb64285ed45cc826952819f 100644 --- a/apps/server/src/git/Services/GitStatusBroadcaster.ts +++ b/apps/server/src/git/Services/GitStatusBroadcaster.ts @@ -1,4 +1,4 @@ -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect, Stream } from "effect"; import type { GitManagerServiceError, @@ -21,7 +21,7 @@ export interface GitStatusBroadcasterShape { ) => Stream.Stream; } -export class GitStatusBroadcaster extends ServiceMap.Service< +export class GitStatusBroadcaster extends Context.Service< GitStatusBroadcaster, GitStatusBroadcasterShape >()("t3/git/Services/GitStatusBroadcaster") {} diff --git a/apps/server/src/git/Services/TextGeneration.ts b/apps/server/src/git/Services/TextGeneration.ts index f4354c7a9945f669be999ba04fbba168226dd672..6062d552d95bf034a4f11d55add5354949fc1213 100644 --- a/apps/server/src/git/Services/TextGeneration.ts +++ b/apps/server/src/git/Services/TextGeneration.ts @@ -6,7 +6,7 @@ * * @module TextGeneration */ -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect } from "effect"; import type { ChatAttachment, ModelSelection } from "@t3tools/contracts"; @@ -118,6 +118,6 @@ export interface TextGenerationShape { /** * TextGeneration - Service tag for commit and PR text generation. */ -export class TextGeneration extends ServiceMap.Service()( +export class TextGeneration extends Context.Service()( "t3/git/Services/TextGeneration", ) {} diff --git a/apps/server/src/keybindings.ts b/apps/server/src/keybindings.ts index 1d0ab812f2771d14251f144f765029d8250543e7..19c96bd5471b79bb803feca9b7b40c45a3b8fe8b 100644 --- a/apps/server/src/keybindings.ts +++ b/apps/server/src/keybindings.ts @@ -39,7 +39,7 @@ import { SchemaIssue, SchemaTransformation, Ref, - ServiceMap, + Context, Scope, Stream, } from "effect"; @@ -521,7 +521,7 @@ export interface KeybindingsShape { /** * Keybindings - Service tag for keybinding configuration operations. */ -export class Keybindings extends ServiceMap.Service()( +export class Keybindings extends Context.Service()( "t3/keybindings", ) {} diff --git a/apps/server/src/observability/Services/BrowserTraceCollector.ts b/apps/server/src/observability/Services/BrowserTraceCollector.ts index 60e8f5fa13ea1d0bda91ab74d1ee76c9f0a7d368..e27a53c9c34d388b5aa7d11a69fedb957492fdfd 100644 --- a/apps/server/src/observability/Services/BrowserTraceCollector.ts +++ b/apps/server/src/observability/Services/BrowserTraceCollector.ts @@ -1,4 +1,4 @@ -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect } from "effect"; import type { TraceRecord } from "../TraceRecord.ts"; @@ -7,7 +7,7 @@ export interface BrowserTraceCollectorShape { readonly record: (records: ReadonlyArray) => Effect.Effect; } -export class BrowserTraceCollector extends ServiceMap.Service< +export class BrowserTraceCollector extends Context.Service< BrowserTraceCollector, BrowserTraceCollectorShape >()("t3/observability/Services/BrowserTraceCollector") {} diff --git a/apps/server/src/open.ts b/apps/server/src/open.ts index ef50d3a5b8da41776f5818da778a09cb499e916f..dd7d8c3849bd4b15af84803e44ed34f70376451e 100644 --- a/apps/server/src/open.ts +++ b/apps/server/src/open.ts @@ -11,7 +11,7 @@ import { accessSync, constants, statSync } from "node:fs"; import { extname, join } from "node:path"; import { EDITORS, OpenError, type EditorId } from "@t3tools/contracts"; -import { ServiceMap, Effect, Layer } from "effect"; +import { Context, Effect, Layer } from "effect"; // ============================== // Definitions @@ -247,7 +247,7 @@ export interface OpenShape { /** * Open - Service tag for browser/editor launch operations. */ -export class Open extends ServiceMap.Service()("t3/open") {} +export class Open extends Context.Service()("t3/open") {} // ============================== // Implementations diff --git a/apps/server/src/orchestration/Layers/CheckpointReactor.test.ts b/apps/server/src/orchestration/Layers/CheckpointReactor.test.ts index 2e1d078f81ea34747849d5266cc0e771d88dc9ba..12e11450dd34636e53f0e0e7eb7bbeafcbb55437 100644 --- a/apps/server/src/orchestration/Layers/CheckpointReactor.test.ts +++ b/apps/server/src/orchestration/Layers/CheckpointReactor.test.ts @@ -44,8 +44,8 @@ import { ServerConfig } from "../../config.ts"; import { WorkspaceEntriesLive } from "../../workspace/Layers/WorkspaceEntries.ts"; import { WorkspacePathsLive } from "../../workspace/Layers/WorkspacePaths.ts"; -const asProjectId = (value: string): ProjectId => ProjectId.makeUnsafe(value); -const asTurnId = (value: string): TurnId => TurnId.makeUnsafe(value); +const asProjectId = (value: string): ProjectId => ProjectId.make(value); +const asTurnId = (value: string): TurnId => TurnId.make(value); type LegacyProviderRuntimeEvent = { readonly type: string; @@ -81,7 +81,7 @@ function createProviderServiceHarness( provider: providerName, status: "ready", runtimeMode: "full-access", - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), cwd: sessionCwd, createdAt: now, updatedAt: now, @@ -130,7 +130,7 @@ async function waitForThread( activities: ReadonlyArray<{ kind: string }>; }> => { const readModel = await Effect.runPromise(engine.getReadModel()); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); if (thread && predicate(thread)) { return thread; } @@ -310,7 +310,7 @@ describe("CheckpointReactor", () => { await Effect.runPromise( engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-project-create"), + commandId: CommandId.make("cmd-project-create"), projectId: asProjectId("project-1"), title: "Test Project", workspaceRoot: options?.projectWorkspaceRoot ?? cwd, @@ -324,8 +324,8 @@ describe("CheckpointReactor", () => { await Effect.runPromise( engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-create"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-thread-create"), + threadId: ThreadId.make("thread-1"), projectId: asProjectId("project-1"), title: "Thread", modelSelection: { @@ -344,21 +344,21 @@ describe("CheckpointReactor", () => { await runtime.runPromise( checkpointStore.captureCheckpoint({ cwd, - checkpointRef: checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0), + checkpointRef: checkpointRefForThreadTurn(ThreadId.make("thread-1"), 0), }), ); fs.writeFileSync(path.join(cwd, "README.md"), "v2\n", "utf8"); await runtime.runPromise( checkpointStore.captureCheckpoint({ cwd, - checkpointRef: checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 1), + checkpointRef: checkpointRefForThreadTurn(ThreadId.make("thread-1"), 1), }), ); fs.writeFileSync(path.join(cwd, "README.md"), "v3\n", "utf8"); await runtime.runPromise( checkpointStore.captureCheckpoint({ cwd, - checkpointRef: checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 2), + checkpointRef: checkpointRefForThreadTurn(ThreadId.make("thread-1"), 2), }), ); } @@ -378,10 +378,10 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-capture"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set-capture"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "ready", providerName: "codex", runtimeMode: "approval-required", @@ -395,26 +395,26 @@ describe("CheckpointReactor", () => { harness.provider.emit({ type: "turn.started", - eventId: EventId.makeUnsafe("evt-turn-started-1"), + eventId: EventId.make("evt-turn-started-1"), provider: "codex", createdAt: new Date().toISOString(), - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-1"), }); await waitForGitRefExists( harness.cwd, - checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0), + checkpointRefForThreadTurn(ThreadId.make("thread-1"), 0), ); fs.writeFileSync(path.join(harness.cwd, "README.md"), "v2\n", "utf8"); harness.provider.emit({ type: "turn.completed", - eventId: EventId.makeUnsafe("evt-turn-completed-1"), + eventId: EventId.make("evt-turn-completed-1"), provider: "codex", createdAt: new Date().toISOString(), - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-1"), payload: { state: "completed" }, }); @@ -426,22 +426,22 @@ describe("CheckpointReactor", () => { ); expect(thread.checkpoints[0]?.checkpointTurnCount).toBe(1); expect( - gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0)), + gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.make("thread-1"), 0)), ).toBe(true); expect( - gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 1)), + gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.make("thread-1"), 1)), ).toBe(true); expect( gitShowFileAtRef( harness.cwd, - checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0), + checkpointRefForThreadTurn(ThreadId.make("thread-1"), 0), "README.md", ), ).toBe("v1\n"); expect( gitShowFileAtRef( harness.cwd, - checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 1), + checkpointRefForThreadTurn(ThreadId.make("thread-1"), 1), "README.md", ), ).toBe("v2\n"); @@ -456,10 +456,10 @@ describe("CheckpointReactor", () => { harness.provider.emit({ type: "turn.completed", - eventId: EventId.makeUnsafe("evt-turn-completed-refresh-local-status"), + eventId: EventId.make("evt-turn-completed-refresh-local-status"), provider: "codex", createdAt: new Date().toISOString(), - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-refresh-local-status"), payload: { state: "completed" }, }); @@ -476,10 +476,10 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-primary-running"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set-primary-running"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "running", providerName: "codex", runtimeMode: "approval-required", @@ -493,45 +493,43 @@ describe("CheckpointReactor", () => { harness.provider.emit({ type: "turn.started", - eventId: EventId.makeUnsafe("evt-turn-started-main"), + eventId: EventId.make("evt-turn-started-main"), provider: "codex", createdAt: new Date().toISOString(), - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-main"), }); await waitForGitRefExists( harness.cwd, - checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0), + checkpointRefForThreadTurn(ThreadId.make("thread-1"), 0), ); fs.writeFileSync(path.join(harness.cwd, "README.md"), "v2\n", "utf8"); harness.provider.emit({ type: "turn.completed", - eventId: EventId.makeUnsafe("evt-turn-completed-aux"), + eventId: EventId.make("evt-turn-completed-aux"), provider: "codex", createdAt: new Date().toISOString(), - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-aux"), payload: { state: "completed" }, }); await harness.drain(); const midReadModel = await Effect.runPromise(harness.engine.getReadModel()); - const midThread = midReadModel.threads.find( - (entry) => entry.id === ThreadId.makeUnsafe("thread-1"), - ); + const midThread = midReadModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(midThread?.checkpoints).toHaveLength(0); harness.provider.emit({ type: "turn.completed", - eventId: EventId.makeUnsafe("evt-turn-completed-main"), + eventId: EventId.make("evt-turn-completed-main"), provider: "codex", createdAt: new Date().toISOString(), - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-main"), payload: { state: "completed" }, }); @@ -553,10 +551,10 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-capture-claude"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set-capture-claude"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "ready", providerName: "claudeAgent", runtimeMode: "approval-required", @@ -570,24 +568,24 @@ describe("CheckpointReactor", () => { harness.provider.emit({ type: "turn.started", - eventId: EventId.makeUnsafe("evt-turn-started-claude-1"), + eventId: EventId.make("evt-turn-started-claude-1"), provider: "claudeAgent", createdAt: new Date().toISOString(), - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-claude-1"), }); await waitForGitRefExists( harness.cwd, - checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0), + checkpointRefForThreadTurn(ThreadId.make("thread-1"), 0), ); fs.writeFileSync(path.join(harness.cwd, "README.md"), "v2\n", "utf8"); harness.provider.emit({ type: "turn.completed", - eventId: EventId.makeUnsafe("evt-turn-completed-claude-1"), + eventId: EventId.make("evt-turn-completed-claude-1"), provider: "claudeAgent", createdAt: new Date().toISOString(), - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-claude-1"), payload: { state: "completed" }, }); @@ -600,7 +598,7 @@ describe("CheckpointReactor", () => { expect(thread.checkpoints[0]?.checkpointTurnCount).toBe(1); expect( - gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 1)), + gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.make("thread-1"), 1)), ).toBe(true); }); @@ -611,10 +609,10 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-missing-baseline-diff"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set-missing-baseline-diff"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "ready", providerName: "codex", runtimeMode: "approval-required", @@ -628,11 +626,11 @@ describe("CheckpointReactor", () => { harness.provider.emit({ type: "turn.completed", - eventId: EventId.makeUnsafe("evt-turn-completed-missing-baseline"), + eventId: EventId.make("evt-turn-completed-missing-baseline"), provider: "codex", createdAt: new Date().toISOString(), - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-missing-baseline"), payload: { state: "completed" }, }); @@ -661,10 +659,10 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-for-baseline"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-for-baseline"), + threadId: ThreadId.make("thread-1"), message: { - messageId: MessageId.makeUnsafe("message-user-1"), + messageId: MessageId.make("message-user-1"), role: "user", text: "start turn", attachments: [], @@ -677,12 +675,12 @@ describe("CheckpointReactor", () => { await waitForGitRefExists( harness.cwd, - checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0), + checkpointRefForThreadTurn(ThreadId.make("thread-1"), 0), ); expect( gitShowFileAtRef( harness.cwd, - checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0), + checkpointRefForThreadTurn(ThreadId.make("thread-1"), 0), "README.md", ), ).toBe("v1\n"); @@ -699,10 +697,10 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-missing-provider-cwd"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set-missing-provider-cwd"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "running", providerName: "codex", runtimeMode: "approval-required", @@ -717,23 +715,23 @@ describe("CheckpointReactor", () => { fs.writeFileSync(path.join(harness.cwd, "README.md"), "v2\n", "utf8"); harness.provider.emit({ type: "turn.completed", - eventId: EventId.makeUnsafe("evt-turn-completed-missing-provider-cwd"), + eventId: EventId.make("evt-turn-completed-missing-provider-cwd"), provider: "codex", createdAt: new Date().toISOString(), - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-missing-cwd"), payload: { state: "completed" }, }); await waitForEvent(harness.engine, (event) => event.type === "thread.turn-diff-completed"); expect( - gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 1)), + gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.make("thread-1"), 1)), ).toBe(true); expect( gitShowFileAtRef( harness.cwd, - checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 1), + checkpointRefForThreadTurn(ThreadId.make("thread-1"), 1), "README.md", ), ).toBe("v2\n"); @@ -746,10 +744,10 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-checkpoint-captured"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set-checkpoint-captured"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "ready", providerName: "codex", runtimeMode: "approval-required", @@ -763,11 +761,11 @@ describe("CheckpointReactor", () => { harness.provider.emit({ type: "checkpoint.captured", - eventId: EventId.makeUnsafe("evt-checkpoint-captured-3"), + eventId: EventId.make("evt-checkpoint-captured-3"), provider: "codex", createdAt: new Date().toISOString(), - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-3"), turnCount: 3, status: "completed", @@ -775,7 +773,7 @@ describe("CheckpointReactor", () => { await harness.drain(); const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(thread?.checkpoints.some((checkpoint) => checkpoint.checkpointTurnCount === 3)).toBe( false, ); @@ -796,10 +794,10 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-non-repo-runtime"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set-non-repo-runtime"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "ready", providerName: "codex", runtimeMode: "approval-required", @@ -813,31 +811,31 @@ describe("CheckpointReactor", () => { harness.provider.emit({ type: "turn.completed", - eventId: EventId.makeUnsafe("evt-runtime-capture-failure"), + eventId: EventId.make("evt-runtime-capture-failure"), provider: "codex", createdAt: new Date().toISOString(), - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-runtime-failure"), payload: { state: "completed" }, }); harness.provider.emit({ type: "turn.started", - eventId: EventId.makeUnsafe("evt-turn-started-after-runtime-failure"), + eventId: EventId.make("evt-turn-started-after-runtime-failure"), provider: "codex", createdAt: new Date().toISOString(), - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-after-runtime-failure"), }); await waitForGitRefExists( harness.cwd, - checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0), + checkpointRefForThreadTurn(ThreadId.make("thread-1"), 0), ); expect( - gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 0)), + gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.make("thread-1"), 0)), ).toBe(true); }); @@ -848,10 +846,10 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "ready", providerName: "codex", runtimeMode: "approval-required", @@ -866,11 +864,11 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.diff.complete", - commandId: CommandId.makeUnsafe("cmd-diff-1"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-diff-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-1"), completedAt: createdAt, - checkpointRef: checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 1), + checkpointRef: checkpointRefForThreadTurn(ThreadId.make("thread-1"), 1), status: "ready", files: [], checkpointTurnCount: 1, @@ -880,11 +878,11 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.diff.complete", - commandId: CommandId.makeUnsafe("cmd-diff-2"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-diff-2"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-2"), completedAt: createdAt, - checkpointRef: checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 2), + checkpointRef: checkpointRefForThreadTurn(ThreadId.make("thread-1"), 2), status: "ready", files: [], checkpointTurnCount: 2, @@ -895,8 +893,8 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.checkpoint.revert", - commandId: CommandId.makeUnsafe("cmd-revert-request"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-revert-request"), + threadId: ThreadId.make("thread-1"), turnCount: 1, createdAt, }), @@ -910,12 +908,12 @@ describe("CheckpointReactor", () => { expect(thread.checkpoints[0]?.checkpointTurnCount).toBe(1); expect(harness.provider.rollbackConversation).toHaveBeenCalledTimes(1); expect(harness.provider.rollbackConversation).toHaveBeenCalledWith({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), numTurns: 1, }); expect(fs.readFileSync(path.join(harness.cwd, "README.md"), "utf8")).toBe("v2\n"); expect( - gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 2)), + gitRefExists(harness.cwd, checkpointRefForThreadTurn(ThreadId.make("thread-1"), 2)), ).toBe(false); }); @@ -926,10 +924,10 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-claude"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set-claude"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "ready", providerName: "claudeAgent", runtimeMode: "approval-required", @@ -944,11 +942,11 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.diff.complete", - commandId: CommandId.makeUnsafe("cmd-diff-claude-1"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-diff-claude-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-claude-1"), completedAt: createdAt, - checkpointRef: checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 1), + checkpointRef: checkpointRefForThreadTurn(ThreadId.make("thread-1"), 1), status: "ready", files: [], checkpointTurnCount: 1, @@ -958,11 +956,11 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.diff.complete", - commandId: CommandId.makeUnsafe("cmd-diff-claude-2"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-diff-claude-2"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-claude-2"), completedAt: createdAt, - checkpointRef: checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 2), + checkpointRef: checkpointRefForThreadTurn(ThreadId.make("thread-1"), 2), status: "ready", files: [], checkpointTurnCount: 2, @@ -973,8 +971,8 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.checkpoint.revert", - commandId: CommandId.makeUnsafe("cmd-revert-request-claude"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-revert-request-claude"), + threadId: ThreadId.make("thread-1"), turnCount: 1, createdAt, }), @@ -983,7 +981,7 @@ describe("CheckpointReactor", () => { await waitForEvent(harness.engine, (event) => event.type === "thread.reverted"); expect(harness.provider.rollbackConversation).toHaveBeenCalledTimes(1); expect(harness.provider.rollbackConversation).toHaveBeenCalledWith({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), numTurns: 1, }); }); @@ -995,10 +993,10 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-inline-revert"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set-inline-revert"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "ready", providerName: "codex", runtimeMode: "approval-required", @@ -1013,11 +1011,11 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.diff.complete", - commandId: CommandId.makeUnsafe("cmd-inline-revert-diff-1"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-inline-revert-diff-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-1"), completedAt: createdAt, - checkpointRef: checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 1), + checkpointRef: checkpointRefForThreadTurn(ThreadId.make("thread-1"), 1), status: "ready", files: [], checkpointTurnCount: 1, @@ -1027,11 +1025,11 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.diff.complete", - commandId: CommandId.makeUnsafe("cmd-inline-revert-diff-2"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-inline-revert-diff-2"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-2"), completedAt: createdAt, - checkpointRef: checkpointRefForThreadTurn(ThreadId.makeUnsafe("thread-1"), 2), + checkpointRef: checkpointRefForThreadTurn(ThreadId.make("thread-1"), 2), status: "ready", files: [], checkpointTurnCount: 2, @@ -1042,8 +1040,8 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.checkpoint.revert", - commandId: CommandId.makeUnsafe("cmd-sequenced-revert-request-1"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-sequenced-revert-request-1"), + threadId: ThreadId.make("thread-1"), turnCount: 1, createdAt, }), @@ -1051,8 +1049,8 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.checkpoint.revert", - commandId: CommandId.makeUnsafe("cmd-sequenced-revert-request-0"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-sequenced-revert-request-0"), + threadId: ThreadId.make("thread-1"), turnCount: 0, createdAt, }), @@ -1062,11 +1060,11 @@ describe("CheckpointReactor", () => { expect(harness.provider.rollbackConversation).toHaveBeenCalledTimes(2); expect(harness.provider.rollbackConversation.mock.calls[0]?.[0]).toEqual({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), numTurns: 1, }); expect(harness.provider.rollbackConversation.mock.calls[1]?.[0]).toEqual({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), numTurns: 1, }); }); @@ -1078,8 +1076,8 @@ describe("CheckpointReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.checkpoint.revert", - commandId: CommandId.makeUnsafe("cmd-revert-no-session"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-revert-no-session"), + threadId: ThreadId.make("thread-1"), turnCount: 1, createdAt, }), diff --git a/apps/server/src/orchestration/Layers/CheckpointReactor.ts b/apps/server/src/orchestration/Layers/CheckpointReactor.ts index 3ed4dacd2b851d589a6a23e21aa688d5beb105d2..0b1b203ba24cb5c80b4e78da249dab06654b5d73 100644 --- a/apps/server/src/orchestration/Layers/CheckpointReactor.ts +++ b/apps/server/src/orchestration/Layers/CheckpointReactor.ts @@ -38,7 +38,7 @@ type ReactorInput = }; function toTurnId(value: string | undefined): TurnId | null { - return value === undefined ? null : TurnId.makeUnsafe(String(value)); + return value === undefined ? null : TurnId.make(String(value)); } function sameId(left: string | null | undefined, right: string | null | undefined): boolean { @@ -62,7 +62,7 @@ function checkpointStatusFromRuntime(status: string | undefined): "ready" | "mis } const serverCommandId = (tag: string): CommandId => - CommandId.makeUnsafe(`server:${tag}:${crypto.randomUUID()}`); + CommandId.make(`server:${tag}:${crypto.randomUUID()}`); const make = Effect.gen(function* () { const orchestrationEngine = yield* OrchestrationEngineService; @@ -83,7 +83,7 @@ const make = Effect.gen(function* () { commandId: serverCommandId("checkpoint-revert-failure"), threadId: input.threadId, activity: { - id: EventId.makeUnsafe(crypto.randomUUID()), + id: EventId.make(crypto.randomUUID()), tone: "error", kind: "checkpoint.revert.failed", summary: "Checkpoint revert failed", @@ -108,7 +108,7 @@ const make = Effect.gen(function* () { commandId: serverCommandId("checkpoint-capture-failure"), threadId: input.threadId, activity: { - id: EventId.makeUnsafe(crypto.randomUUID()), + id: EventId.make(crypto.randomUUID()), tone: "error", kind: "checkpoint.capture.failed", summary: "Checkpoint capture failed", @@ -270,7 +270,7 @@ const make = Effect.gen(function* () { input.thread.messages .toReversed() .find((entry) => entry.role === "assistant" && entry.turnId === input.turnId)?.id ?? - MessageId.makeUnsafe(`assistant:${input.turnId}`); + MessageId.make(`assistant:${input.turnId}`); yield* orchestrationEngine.dispatch({ type: "thread.turn.diff.complete", @@ -307,7 +307,7 @@ const make = Effect.gen(function* () { commandId: serverCommandId("checkpoint-captured-activity"), threadId: input.threadId, activity: { - id: EventId.makeUnsafe(crypto.randomUUID()), + id: EventId.make(crypto.randomUUID()), tone: "info", kind: "checkpoint.captured", summary: "Checkpoint captured", diff --git a/apps/server/src/orchestration/Layers/OrchestrationEngine.test.ts b/apps/server/src/orchestration/Layers/OrchestrationEngine.test.ts index 77b12e86aecc7a5063e36aa3252f2cc9f5d48fba..eaf66f3971dca8eea356a46c58c86c50702eccd9 100644 --- a/apps/server/src/orchestration/Layers/OrchestrationEngine.test.ts +++ b/apps/server/src/orchestration/Layers/OrchestrationEngine.test.ts @@ -32,10 +32,10 @@ import { ProjectionSnapshotQuery } from "../Services/ProjectionSnapshotQuery.ts" import { ServerConfig } from "../../config.ts"; import * as NodeServices from "@effect/platform-node/NodeServices"; -const asProjectId = (value: string): ProjectId => ProjectId.makeUnsafe(value); -const asMessageId = (value: string): MessageId => MessageId.makeUnsafe(value); -const asTurnId = (value: string): TurnId => TurnId.makeUnsafe(value); -const asCheckpointRef = (value: string): CheckpointRef => CheckpointRef.makeUnsafe(value); +const asProjectId = (value: string): ProjectId => ProjectId.make(value); +const asMessageId = (value: string): MessageId => MessageId.make(value); +const asTurnId = (value: string): TurnId => TurnId.make(value); +const asCheckpointRef = (value: string): CheckpointRef => CheckpointRef.make(value); async function createOrchestrationSystem() { const ServerConfigLayer = ServerConfig.layerTest(process.cwd(), { @@ -115,7 +115,7 @@ describe("OrchestrationEngine", () => { ], threads: [ { - id: ThreadId.makeUnsafe("thread-bootstrap"), + id: ThreadId.make("thread-bootstrap"), projectId: asProjectId("project-bootstrap"), title: "Bootstrap Thread", modelSelection: { @@ -183,7 +183,7 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-project-1-create"), + commandId: CommandId.make("cmd-project-1-create"), projectId: asProjectId("project-1"), title: "Project 1", workspaceRoot: "/tmp/project-1", @@ -197,8 +197,8 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-1-create"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-thread-1-create"), + threadId: ThreadId.make("thread-1"), projectId: asProjectId("project-1"), title: "Thread", modelSelection: { @@ -215,8 +215,8 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-1"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-1"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("msg-1"), role: "user", @@ -243,7 +243,7 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-project-archive-create"), + commandId: CommandId.make("cmd-project-archive-create"), projectId: asProjectId("project-archive"), title: "Project Archive", workspaceRoot: "/tmp/project-archive", @@ -257,8 +257,8 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-archive-create"), - threadId: ThreadId.makeUnsafe("thread-archive"), + commandId: CommandId.make("cmd-thread-archive-create"), + threadId: ThreadId.make("thread-archive"), projectId: asProjectId("project-archive"), title: "Archive me", modelSelection: { @@ -276,8 +276,8 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "thread.archive", - commandId: CommandId.makeUnsafe("cmd-thread-archive"), - threadId: ThreadId.makeUnsafe("thread-archive"), + commandId: CommandId.make("cmd-thread-archive"), + threadId: ThreadId.make("thread-archive"), }), ); expect( @@ -289,8 +289,8 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "thread.unarchive", - commandId: CommandId.makeUnsafe("cmd-thread-unarchive"), - threadId: ThreadId.makeUnsafe("thread-archive"), + commandId: CommandId.make("cmd-thread-unarchive"), + threadId: ThreadId.make("thread-archive"), }), ); expect( @@ -310,7 +310,7 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-project-replay-create"), + commandId: CommandId.make("cmd-project-replay-create"), projectId: asProjectId("project-replay"), title: "Replay Project", workspaceRoot: "/tmp/project-replay", @@ -324,8 +324,8 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-replay-create"), - threadId: ThreadId.makeUnsafe("thread-replay"), + commandId: CommandId.make("cmd-thread-replay-create"), + threadId: ThreadId.make("thread-replay"), projectId: asProjectId("project-replay"), title: "replay", modelSelection: { @@ -342,8 +342,8 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "thread.delete", - commandId: CommandId.makeUnsafe("cmd-thread-replay-delete"), - threadId: ThreadId.makeUnsafe("thread-replay"), + commandId: CommandId.make("cmd-thread-replay-delete"), + threadId: ThreadId.make("thread-replay"), }), ); @@ -368,7 +368,7 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-project-stream-create"), + commandId: CommandId.make("cmd-project-stream-create"), projectId: asProjectId("project-stream"), title: "Stream Project", workspaceRoot: "/tmp/project-stream", @@ -392,8 +392,8 @@ describe("OrchestrationEngine", () => { yield* Effect.sleep("10 millis"); yield* engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-stream-thread-create"), - threadId: ThreadId.makeUnsafe("thread-stream"), + commandId: CommandId.make("cmd-stream-thread-create"), + threadId: ThreadId.make("thread-stream"), projectId: asProjectId("project-stream"), title: "domain-stream", modelSelection: { @@ -408,8 +408,8 @@ describe("OrchestrationEngine", () => { }); yield* engine.dispatch({ type: "thread.meta.update", - commandId: CommandId.makeUnsafe("cmd-stream-thread-update"), - threadId: ThreadId.makeUnsafe("thread-stream"), + commandId: CommandId.make("cmd-stream-thread-update"), + threadId: ThreadId.make("thread-stream"), title: "domain-stream-updated", }); eventTypes.push((yield* Queue.take(eventQueue)).type); @@ -429,7 +429,7 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-project-ack-create"), + commandId: CommandId.make("cmd-project-ack-create"), projectId: asProjectId("project-ack"), title: "Ack Project", workspaceRoot: "/tmp/project-ack", @@ -444,8 +444,8 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-ack-create"), - threadId: ThreadId.makeUnsafe("thread-ack"), + commandId: CommandId.make("cmd-thread-ack-create"), + threadId: ThreadId.make("thread-ack"), projectId: asProjectId("project-ack"), title: "Ack Thread", modelSelection: { @@ -481,8 +481,8 @@ describe("OrchestrationEngine", () => { system.run( engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-missing-project"), - threadId: ThreadId.makeUnsafe("thread-missing-project"), + commandId: CommandId.make("cmd-thread-missing-project"), + threadId: ThreadId.make("thread-missing-project"), projectId: asProjectId("project-missing"), title: "Missing Project Thread", modelSelection: { @@ -518,7 +518,7 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-project-turn-diff-create"), + commandId: CommandId.make("cmd-project-turn-diff-create"), projectId: asProjectId("project-turn-diff"), title: "Turn Diff Project", workspaceRoot: "/tmp/project-turn-diff", @@ -532,8 +532,8 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-turn-diff-create"), - threadId: ThreadId.makeUnsafe("thread-turn-diff"), + commandId: CommandId.make("cmd-thread-turn-diff-create"), + threadId: ThreadId.make("thread-turn-diff"), projectId: asProjectId("project-turn-diff"), title: "Turn diff thread", modelSelection: { @@ -550,8 +550,8 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "thread.turn.diff.complete", - commandId: CommandId.makeUnsafe("cmd-turn-diff-complete"), - threadId: ThreadId.makeUnsafe("thread-turn-diff"), + commandId: CommandId.make("cmd-turn-diff-complete"), + threadId: ThreadId.make("thread-turn-diff"), turnId: asTurnId("turn-1"), completedAt: createdAt, checkpointRef: asCheckpointRef("refs/t3/checkpoints/thread-turn-diff/turn/1"), @@ -590,7 +590,7 @@ describe("OrchestrationEngine", () => { const flakyStore: OrchestrationEventStoreShape = { append(event) { - if (shouldFailFirstAppend && event.commandId === CommandId.makeUnsafe("cmd-flaky-1")) { + if (shouldFailFirstAppend && event.commandId === CommandId.make("cmd-flaky-1")) { shouldFailFirstAppend = false; return Effect.fail( new PersistenceSqlError({ @@ -637,7 +637,7 @@ describe("OrchestrationEngine", () => { await runtime.runPromise( engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-project-flaky-create"), + commandId: CommandId.make("cmd-project-flaky-create"), projectId: asProjectId("project-flaky"), title: "Flaky Project", workspaceRoot: "/tmp/project-flaky", @@ -653,8 +653,8 @@ describe("OrchestrationEngine", () => { runtime.runPromise( engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-flaky-1"), - threadId: ThreadId.makeUnsafe("thread-flaky-fail"), + commandId: CommandId.make("cmd-flaky-1"), + threadId: ThreadId.make("thread-flaky-fail"), projectId: asProjectId("project-flaky"), title: "flaky-fail", modelSelection: { @@ -673,8 +673,8 @@ describe("OrchestrationEngine", () => { const result = await runtime.runPromise( engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-flaky-2"), - threadId: ThreadId.makeUnsafe("thread-flaky-ok"), + commandId: CommandId.make("cmd-flaky-2"), + threadId: ThreadId.make("thread-flaky-ok"), projectId: asProjectId("project-flaky"), title: "flaky-ok", modelSelection: { @@ -701,7 +701,7 @@ describe("OrchestrationEngine", () => { projectEvent: (event) => { if ( shouldFailRequestedProjection && - event.commandId === CommandId.makeUnsafe("cmd-turn-start-atomic") && + event.commandId === CommandId.make("cmd-turn-start-atomic") && event.type === "thread.turn-start-requested" ) { shouldFailRequestedProjection = false; @@ -732,7 +732,7 @@ describe("OrchestrationEngine", () => { await runtime.runPromise( engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-project-atomic-create"), + commandId: CommandId.make("cmd-project-atomic-create"), projectId: asProjectId("project-atomic"), title: "Atomic Project", workspaceRoot: "/tmp/project-atomic", @@ -746,8 +746,8 @@ describe("OrchestrationEngine", () => { await runtime.runPromise( engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-atomic-create"), - threadId: ThreadId.makeUnsafe("thread-atomic"), + commandId: CommandId.make("cmd-thread-atomic-create"), + threadId: ThreadId.make("thread-atomic"), projectId: asProjectId("project-atomic"), title: "atomic", modelSelection: { @@ -764,8 +764,8 @@ describe("OrchestrationEngine", () => { const turnStartCommand = { type: "thread.turn.start" as const, - commandId: CommandId.makeUnsafe("cmd-turn-start-atomic"), - threadId: ThreadId.makeUnsafe("thread-atomic"), + commandId: CommandId.make("cmd-turn-start-atomic"), + threadId: ThreadId.make("thread-atomic"), message: { messageId: asMessageId("msg-atomic-1"), role: "user" as const, @@ -845,7 +845,7 @@ describe("OrchestrationEngine", () => { projectEvent: (event) => { if ( shouldFailProjection && - event.commandId === CommandId.makeUnsafe("cmd-thread-meta-sync-fail") + event.commandId === CommandId.make("cmd-thread-meta-sync-fail") ) { shouldFailProjection = false; return Effect.fail( @@ -875,7 +875,7 @@ describe("OrchestrationEngine", () => { await runtime.runPromise( engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-project-sync-create"), + commandId: CommandId.make("cmd-project-sync-create"), projectId: asProjectId("project-sync"), title: "Sync Project", workspaceRoot: "/tmp/project-sync", @@ -889,8 +889,8 @@ describe("OrchestrationEngine", () => { await runtime.runPromise( engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-sync-create"), - threadId: ThreadId.makeUnsafe("thread-sync"), + commandId: CommandId.make("cmd-thread-sync-create"), + threadId: ThreadId.make("thread-sync"), projectId: asProjectId("project-sync"), title: "sync-before", modelSelection: { @@ -909,8 +909,8 @@ describe("OrchestrationEngine", () => { runtime.runPromise( engine.dispatch({ type: "thread.meta.update", - commandId: CommandId.makeUnsafe("cmd-thread-meta-sync-fail"), - threadId: ThreadId.makeUnsafe("thread-sync"), + commandId: CommandId.make("cmd-thread-meta-sync-fail"), + threadId: ThreadId.make("thread-sync"), title: "sync-after-failed-projection", }), ), @@ -934,8 +934,8 @@ describe("OrchestrationEngine", () => { system.run( engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-invariant-missing-thread"), - threadId: ThreadId.makeUnsafe("thread-missing"), + commandId: CommandId.make("cmd-invariant-missing-thread"), + threadId: ThreadId.make("thread-missing"), message: { messageId: asMessageId("msg-missing"), role: "user", @@ -960,7 +960,7 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-project-duplicate-create"), + commandId: CommandId.make("cmd-project-duplicate-create"), projectId: asProjectId("project-duplicate"), title: "Duplicate Project", workspaceRoot: "/tmp/project-duplicate", @@ -975,8 +975,8 @@ describe("OrchestrationEngine", () => { await system.run( engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-duplicate-1"), - threadId: ThreadId.makeUnsafe("thread-duplicate"), + commandId: CommandId.make("cmd-thread-duplicate-1"), + threadId: ThreadId.make("thread-duplicate"), projectId: asProjectId("project-duplicate"), title: "duplicate", modelSelection: { @@ -995,8 +995,8 @@ describe("OrchestrationEngine", () => { system.run( engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-duplicate-2"), - threadId: ThreadId.makeUnsafe("thread-duplicate"), + commandId: CommandId.make("cmd-thread-duplicate-2"), + threadId: ThreadId.make("thread-duplicate"), projectId: asProjectId("project-duplicate"), title: "duplicate", modelSelection: { diff --git a/apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts b/apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts index 6835f79d010c977a940714c6dccc21e2fbc0dd3e..0796cb490566f74ba9479416438723ae6925ab73 100644 --- a/apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts +++ b/apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts @@ -58,16 +58,16 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* eventStore.append({ type: "project.created", - eventId: EventId.makeUnsafe("evt-1"), + eventId: EventId.make("evt-1"), aggregateKind: "project", - aggregateId: ProjectId.makeUnsafe("project-1"), + aggregateId: ProjectId.make("project-1"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-1"), + commandId: CommandId.make("cmd-1"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-1"), + correlationId: CommandId.make("cmd-1"), metadata: {}, payload: { - projectId: ProjectId.makeUnsafe("project-1"), + projectId: ProjectId.make("project-1"), title: "Project 1", workspaceRoot: "/tmp/project-1", defaultModelSelection: null, @@ -79,17 +79,17 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* eventStore.append({ type: "thread.created", - eventId: EventId.makeUnsafe("evt-2"), + eventId: EventId.make("evt-2"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-1"), + aggregateId: ThreadId.make("thread-1"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-2"), + commandId: CommandId.make("cmd-2"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-2"), + correlationId: CommandId.make("cmd-2"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-1"), - projectId: ProjectId.makeUnsafe("project-1"), + threadId: ThreadId.make("thread-1"), + projectId: ProjectId.make("project-1"), title: "Thread 1", modelSelection: { provider: "codex", @@ -105,17 +105,17 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* eventStore.append({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-3"), + eventId: EventId.make("evt-3"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-1"), + aggregateId: ThreadId.make("thread-1"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-3"), + commandId: CommandId.make("cmd-3"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-3"), + correlationId: CommandId.make("cmd-3"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-1"), - messageId: MessageId.makeUnsafe("message-1"), + threadId: ThreadId.make("thread-1"), + messageId: MessageId.make("message-1"), role: "assistant", text: "hello", turnId: null, @@ -183,17 +183,17 @@ it.layer(Layer.fresh(makeProjectionPipelinePrefixedTestLayer("t3-base-")))( yield* eventStore.append({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-attachments"), + eventId: EventId.make("evt-attachments"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-attachments"), + aggregateId: ThreadId.make("thread-attachments"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-attachments"), + commandId: CommandId.make("cmd-attachments"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-attachments"), + correlationId: CommandId.make("cmd-attachments"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-attachments"), - messageId: MessageId.makeUnsafe("message-attachments"), + threadId: ThreadId.make("thread-attachments"), + messageId: MessageId.make("message-attachments"), role: "user", text: "Inspect this", attachments: [ @@ -249,17 +249,17 @@ it.layer(Layer.fresh(makeProjectionPipelinePrefixedTestLayer("t3-projection-atta yield* eventStore.append({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-attachments-safe"), + eventId: EventId.make("evt-attachments-safe"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-attachments-safe"), + aggregateId: ThreadId.make("thread-attachments-safe"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-attachments-safe"), + commandId: CommandId.make("cmd-attachments-safe"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-attachments-safe"), + correlationId: CommandId.make("cmd-attachments-safe"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-attachments-safe"), - messageId: MessageId.makeUnsafe("message-attachments-safe"), + threadId: ThreadId.make("thread-attachments-safe"), + messageId: MessageId.make("message-attachments-safe"), role: "user", text: "Inspect this", attachments: [ @@ -330,16 +330,16 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* eventStore.append({ type: "project.created", - eventId: EventId.makeUnsafe("evt-clear-attachments-1"), + eventId: EventId.make("evt-clear-attachments-1"), aggregateKind: "project", - aggregateId: ProjectId.makeUnsafe("project-clear-attachments"), + aggregateId: ProjectId.make("project-clear-attachments"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-clear-attachments-1"), + commandId: CommandId.make("cmd-clear-attachments-1"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-clear-attachments-1"), + correlationId: CommandId.make("cmd-clear-attachments-1"), metadata: {}, payload: { - projectId: ProjectId.makeUnsafe("project-clear-attachments"), + projectId: ProjectId.make("project-clear-attachments"), title: "Project Clear Attachments", workspaceRoot: "/tmp/project-clear-attachments", defaultModelSelection: null, @@ -351,17 +351,17 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* eventStore.append({ type: "thread.created", - eventId: EventId.makeUnsafe("evt-clear-attachments-2"), + eventId: EventId.make("evt-clear-attachments-2"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-clear-attachments"), + aggregateId: ThreadId.make("thread-clear-attachments"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-clear-attachments-2"), + commandId: CommandId.make("cmd-clear-attachments-2"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-clear-attachments-2"), + correlationId: CommandId.make("cmd-clear-attachments-2"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-clear-attachments"), - projectId: ProjectId.makeUnsafe("project-clear-attachments"), + threadId: ThreadId.make("thread-clear-attachments"), + projectId: ProjectId.make("project-clear-attachments"), title: "Thread Clear Attachments", modelSelection: { provider: "codex", @@ -377,17 +377,17 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* eventStore.append({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-clear-attachments-3"), + eventId: EventId.make("evt-clear-attachments-3"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-clear-attachments"), + aggregateId: ThreadId.make("thread-clear-attachments"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-clear-attachments-3"), + commandId: CommandId.make("cmd-clear-attachments-3"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-clear-attachments-3"), + correlationId: CommandId.make("cmd-clear-attachments-3"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-clear-attachments"), - messageId: MessageId.makeUnsafe("message-clear-attachments"), + threadId: ThreadId.make("thread-clear-attachments"), + messageId: MessageId.make("message-clear-attachments"), role: "user", text: "Has attachments", attachments: [ @@ -408,17 +408,17 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* eventStore.append({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-clear-attachments-4"), + eventId: EventId.make("evt-clear-attachments-4"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-clear-attachments"), + aggregateId: ThreadId.make("thread-clear-attachments"), occurredAt: later, - commandId: CommandId.makeUnsafe("cmd-clear-attachments-4"), + commandId: CommandId.make("cmd-clear-attachments-4"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-clear-attachments-4"), + correlationId: CommandId.make("cmd-clear-attachments-4"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-clear-attachments"), - messageId: MessageId.makeUnsafe("message-clear-attachments"), + threadId: ThreadId.make("thread-clear-attachments"), + messageId: MessageId.make("message-clear-attachments"), role: "user", text: "", attachments: [], @@ -458,16 +458,16 @@ it.layer( yield* eventStore.append({ type: "project.created", - eventId: EventId.makeUnsafe("evt-overwrite-1"), + eventId: EventId.make("evt-overwrite-1"), aggregateKind: "project", - aggregateId: ProjectId.makeUnsafe("project-overwrite"), + aggregateId: ProjectId.make("project-overwrite"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-overwrite-1"), + commandId: CommandId.make("cmd-overwrite-1"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-overwrite-1"), + correlationId: CommandId.make("cmd-overwrite-1"), metadata: {}, payload: { - projectId: ProjectId.makeUnsafe("project-overwrite"), + projectId: ProjectId.make("project-overwrite"), title: "Project Overwrite", workspaceRoot: "/tmp/project-overwrite", defaultModelSelection: null, @@ -479,17 +479,17 @@ it.layer( yield* eventStore.append({ type: "thread.created", - eventId: EventId.makeUnsafe("evt-overwrite-2"), + eventId: EventId.make("evt-overwrite-2"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-overwrite"), + aggregateId: ThreadId.make("thread-overwrite"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-overwrite-2"), + commandId: CommandId.make("cmd-overwrite-2"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-overwrite-2"), + correlationId: CommandId.make("cmd-overwrite-2"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-overwrite"), - projectId: ProjectId.makeUnsafe("project-overwrite"), + threadId: ThreadId.make("thread-overwrite"), + projectId: ProjectId.make("project-overwrite"), title: "Thread Overwrite", modelSelection: { provider: "codex", @@ -505,17 +505,17 @@ it.layer( yield* eventStore.append({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-overwrite-3"), + eventId: EventId.make("evt-overwrite-3"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-overwrite"), + aggregateId: ThreadId.make("thread-overwrite"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-overwrite-3"), + commandId: CommandId.make("cmd-overwrite-3"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-overwrite-3"), + correlationId: CommandId.make("cmd-overwrite-3"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-overwrite"), - messageId: MessageId.makeUnsafe("message-overwrite"), + threadId: ThreadId.make("thread-overwrite"), + messageId: MessageId.make("message-overwrite"), role: "user", text: "first image", attachments: [ @@ -536,17 +536,17 @@ it.layer( yield* eventStore.append({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-overwrite-4"), + eventId: EventId.make("evt-overwrite-4"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-overwrite"), + aggregateId: ThreadId.make("thread-overwrite"), occurredAt: later, - commandId: CommandId.makeUnsafe("cmd-overwrite-4"), + commandId: CommandId.make("cmd-overwrite-4"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-overwrite-4"), + correlationId: CommandId.make("cmd-overwrite-4"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-overwrite"), - messageId: MessageId.makeUnsafe("message-overwrite"), + threadId: ThreadId.make("thread-overwrite"), + messageId: MessageId.make("message-overwrite"), role: "user", text: "", attachments: [ @@ -606,16 +606,16 @@ it.layer( yield* appendAndProject({ type: "project.created", - eventId: EventId.makeUnsafe("evt-rollback-1"), + eventId: EventId.make("evt-rollback-1"), aggregateKind: "project", - aggregateId: ProjectId.makeUnsafe("project-rollback"), + aggregateId: ProjectId.make("project-rollback"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-rollback-1"), + commandId: CommandId.make("cmd-rollback-1"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-rollback-1"), + correlationId: CorrelationId.make("cmd-rollback-1"), metadata: {}, payload: { - projectId: ProjectId.makeUnsafe("project-rollback"), + projectId: ProjectId.make("project-rollback"), title: "Project Rollback", workspaceRoot: "/tmp/project-rollback", defaultModelSelection: null, @@ -627,17 +627,17 @@ it.layer( yield* appendAndProject({ type: "thread.created", - eventId: EventId.makeUnsafe("evt-rollback-2"), + eventId: EventId.make("evt-rollback-2"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-rollback"), + aggregateId: ThreadId.make("thread-rollback"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-rollback-2"), + commandId: CommandId.make("cmd-rollback-2"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-rollback-2"), + correlationId: CorrelationId.make("cmd-rollback-2"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-rollback"), - projectId: ProjectId.makeUnsafe("project-rollback"), + threadId: ThreadId.make("thread-rollback"), + projectId: ProjectId.make("project-rollback"), title: "Thread Rollback", modelSelection: { provider: "codex", @@ -663,17 +663,17 @@ it.layer( const result = yield* Effect.result( appendAndProject({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-rollback-3"), + eventId: EventId.make("evt-rollback-3"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-rollback"), + aggregateId: ThreadId.make("thread-rollback"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-rollback-3"), + commandId: CommandId.make("cmd-rollback-3"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-rollback-3"), + correlationId: CorrelationId.make("cmd-rollback-3"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-rollback"), - messageId: MessageId.makeUnsafe("message-rollback"), + threadId: ThreadId.make("thread-rollback"), + messageId: MessageId.make("message-rollback"), role: "user", text: "Rollback me", attachments: [ @@ -722,7 +722,7 @@ it.layer( const eventStore = yield* OrchestrationEventStore; const { attachmentsDir } = yield* ServerConfig; const now = new Date().toISOString(); - const threadId = ThreadId.makeUnsafe("Thread Revert.Files"); + const threadId = ThreadId.make("Thread Revert.Files"); const keepAttachmentId = "thread-revert-files-00000000-0000-4000-8000-000000000001"; const removeAttachmentId = "thread-revert-files-00000000-0000-4000-8000-000000000002"; const otherThreadAttachmentId = @@ -735,16 +735,16 @@ it.layer( yield* appendAndProject({ type: "project.created", - eventId: EventId.makeUnsafe("evt-revert-files-1"), + eventId: EventId.make("evt-revert-files-1"), aggregateKind: "project", - aggregateId: ProjectId.makeUnsafe("project-revert-files"), + aggregateId: ProjectId.make("project-revert-files"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-revert-files-1"), + commandId: CommandId.make("cmd-revert-files-1"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-revert-files-1"), + correlationId: CorrelationId.make("cmd-revert-files-1"), metadata: {}, payload: { - projectId: ProjectId.makeUnsafe("project-revert-files"), + projectId: ProjectId.make("project-revert-files"), title: "Project Revert Files", workspaceRoot: "/tmp/project-revert-files", defaultModelSelection: null, @@ -756,17 +756,17 @@ it.layer( yield* appendAndProject({ type: "thread.created", - eventId: EventId.makeUnsafe("evt-revert-files-2"), + eventId: EventId.make("evt-revert-files-2"), aggregateKind: "thread", aggregateId: threadId, occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-revert-files-2"), + commandId: CommandId.make("cmd-revert-files-2"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-revert-files-2"), + correlationId: CorrelationId.make("cmd-revert-files-2"), metadata: {}, payload: { threadId, - projectId: ProjectId.makeUnsafe("project-revert-files"), + projectId: ProjectId.make("project-revert-files"), title: "Thread Revert Files", modelSelection: { provider: "codex", @@ -782,39 +782,39 @@ it.layer( yield* appendAndProject({ type: "thread.turn-diff-completed", - eventId: EventId.makeUnsafe("evt-revert-files-3"), + eventId: EventId.make("evt-revert-files-3"), aggregateKind: "thread", aggregateId: threadId, occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-revert-files-3"), + commandId: CommandId.make("cmd-revert-files-3"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-revert-files-3"), + correlationId: CorrelationId.make("cmd-revert-files-3"), metadata: {}, payload: { threadId, - turnId: TurnId.makeUnsafe("turn-keep"), + turnId: TurnId.make("turn-keep"), checkpointTurnCount: 1, - checkpointRef: CheckpointRef.makeUnsafe("refs/t3/checkpoints/thread-revert-files/turn/1"), + checkpointRef: CheckpointRef.make("refs/t3/checkpoints/thread-revert-files/turn/1"), status: "ready", files: [], - assistantMessageId: MessageId.makeUnsafe("message-keep"), + assistantMessageId: MessageId.make("message-keep"), completedAt: now, }, }); yield* appendAndProject({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-revert-files-4"), + eventId: EventId.make("evt-revert-files-4"), aggregateKind: "thread", aggregateId: threadId, occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-revert-files-4"), + commandId: CommandId.make("cmd-revert-files-4"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-revert-files-4"), + correlationId: CorrelationId.make("cmd-revert-files-4"), metadata: {}, payload: { threadId, - messageId: MessageId.makeUnsafe("message-keep"), + messageId: MessageId.make("message-keep"), role: "assistant", text: "Keep", attachments: [ @@ -826,7 +826,7 @@ it.layer( sizeBytes: 5, }, ], - turnId: TurnId.makeUnsafe("turn-keep"), + turnId: TurnId.make("turn-keep"), streaming: false, createdAt: now, updatedAt: now, @@ -835,39 +835,39 @@ it.layer( yield* appendAndProject({ type: "thread.turn-diff-completed", - eventId: EventId.makeUnsafe("evt-revert-files-5"), + eventId: EventId.make("evt-revert-files-5"), aggregateKind: "thread", aggregateId: threadId, occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-revert-files-5"), + commandId: CommandId.make("cmd-revert-files-5"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-revert-files-5"), + correlationId: CorrelationId.make("cmd-revert-files-5"), metadata: {}, payload: { threadId, - turnId: TurnId.makeUnsafe("turn-remove"), + turnId: TurnId.make("turn-remove"), checkpointTurnCount: 2, - checkpointRef: CheckpointRef.makeUnsafe("refs/t3/checkpoints/thread-revert-files/turn/2"), + checkpointRef: CheckpointRef.make("refs/t3/checkpoints/thread-revert-files/turn/2"), status: "ready", files: [], - assistantMessageId: MessageId.makeUnsafe("message-remove"), + assistantMessageId: MessageId.make("message-remove"), completedAt: now, }, }); yield* appendAndProject({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-revert-files-6"), + eventId: EventId.make("evt-revert-files-6"), aggregateKind: "thread", aggregateId: threadId, occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-revert-files-6"), + commandId: CommandId.make("cmd-revert-files-6"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-revert-files-6"), + correlationId: CorrelationId.make("cmd-revert-files-6"), metadata: {}, payload: { threadId, - messageId: MessageId.makeUnsafe("message-remove"), + messageId: MessageId.make("message-remove"), role: "assistant", text: "Remove", attachments: [ @@ -879,7 +879,7 @@ it.layer( sizeBytes: 5, }, ], - turnId: TurnId.makeUnsafe("turn-remove"), + turnId: TurnId.make("turn-remove"), streaming: false, createdAt: now, updatedAt: now, @@ -899,13 +899,13 @@ it.layer( yield* appendAndProject({ type: "thread.reverted", - eventId: EventId.makeUnsafe("evt-revert-files-7"), + eventId: EventId.make("evt-revert-files-7"), aggregateKind: "thread", aggregateId: threadId, occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-revert-files-7"), + commandId: CommandId.make("cmd-revert-files-7"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-revert-files-7"), + correlationId: CorrelationId.make("cmd-revert-files-7"), metadata: {}, payload: { threadId, @@ -931,7 +931,7 @@ it.layer(Layer.fresh(makeProjectionPipelinePrefixedTestLayer("t3-projection-atta const eventStore = yield* OrchestrationEventStore; const { attachmentsDir } = yield* ServerConfig; const now = new Date().toISOString(); - const threadId = ThreadId.makeUnsafe("Thread Delete.Files"); + const threadId = ThreadId.make("Thread Delete.Files"); const attachmentId = "thread-delete-files-00000000-0000-4000-8000-000000000001"; const otherThreadAttachmentId = "thread-delete-files-extra-00000000-0000-4000-8000-000000000002"; @@ -943,16 +943,16 @@ it.layer(Layer.fresh(makeProjectionPipelinePrefixedTestLayer("t3-projection-atta yield* appendAndProject({ type: "project.created", - eventId: EventId.makeUnsafe("evt-delete-files-1"), + eventId: EventId.make("evt-delete-files-1"), aggregateKind: "project", - aggregateId: ProjectId.makeUnsafe("project-delete-files"), + aggregateId: ProjectId.make("project-delete-files"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-delete-files-1"), + commandId: CommandId.make("cmd-delete-files-1"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-delete-files-1"), + correlationId: CorrelationId.make("cmd-delete-files-1"), metadata: {}, payload: { - projectId: ProjectId.makeUnsafe("project-delete-files"), + projectId: ProjectId.make("project-delete-files"), title: "Project Delete Files", workspaceRoot: "/tmp/project-delete-files", defaultModelSelection: null, @@ -964,17 +964,17 @@ it.layer(Layer.fresh(makeProjectionPipelinePrefixedTestLayer("t3-projection-atta yield* appendAndProject({ type: "thread.created", - eventId: EventId.makeUnsafe("evt-delete-files-2"), + eventId: EventId.make("evt-delete-files-2"), aggregateKind: "thread", aggregateId: threadId, occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-delete-files-2"), + commandId: CommandId.make("cmd-delete-files-2"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-delete-files-2"), + correlationId: CorrelationId.make("cmd-delete-files-2"), metadata: {}, payload: { threadId, - projectId: ProjectId.makeUnsafe("project-delete-files"), + projectId: ProjectId.make("project-delete-files"), title: "Thread Delete Files", modelSelection: { provider: "codex", @@ -990,17 +990,17 @@ it.layer(Layer.fresh(makeProjectionPipelinePrefixedTestLayer("t3-projection-atta yield* appendAndProject({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-delete-files-3"), + eventId: EventId.make("evt-delete-files-3"), aggregateKind: "thread", aggregateId: threadId, occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-delete-files-3"), + commandId: CommandId.make("cmd-delete-files-3"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-delete-files-3"), + correlationId: CorrelationId.make("cmd-delete-files-3"), metadata: {}, payload: { threadId, - messageId: MessageId.makeUnsafe("message-delete-files"), + messageId: MessageId.make("message-delete-files"), role: "user", text: "Delete", attachments: [ @@ -1032,13 +1032,13 @@ it.layer(Layer.fresh(makeProjectionPipelinePrefixedTestLayer("t3-projection-atta yield* appendAndProject({ type: "thread.deleted", - eventId: EventId.makeUnsafe("evt-delete-files-4"), + eventId: EventId.make("evt-delete-files-4"), aggregateKind: "thread", aggregateId: threadId, occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-delete-files-4"), + commandId: CommandId.make("cmd-delete-files-4"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-delete-files-4"), + correlationId: CorrelationId.make("cmd-delete-files-4"), metadata: {}, payload: { threadId, @@ -1072,16 +1072,16 @@ it.layer(Layer.fresh(makeProjectionPipelinePrefixedTestLayer("t3-projection-atta yield* eventStore.append({ type: "thread.deleted", - eventId: EventId.makeUnsafe("evt-unsafe-thread-delete"), + eventId: EventId.make("evt-unsafe-thread-delete"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe(".."), + aggregateId: ThreadId.make(".."), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-unsafe-thread-delete"), + commandId: CommandId.make("cmd-unsafe-thread-delete"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-unsafe-thread-delete"), + correlationId: CorrelationId.make("cmd-unsafe-thread-delete"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe(".."), + threadId: ThreadId.make(".."), deletedAt: now, }, }); @@ -1106,16 +1106,16 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* eventStore.append({ type: "project.created", - eventId: EventId.makeUnsafe("evt-a1"), + eventId: EventId.make("evt-a1"), aggregateKind: "project", - aggregateId: ProjectId.makeUnsafe("project-a"), + aggregateId: ProjectId.make("project-a"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-a1"), + commandId: CommandId.make("cmd-a1"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-a1"), + correlationId: CorrelationId.make("cmd-a1"), metadata: {}, payload: { - projectId: ProjectId.makeUnsafe("project-a"), + projectId: ProjectId.make("project-a"), title: "Project A", workspaceRoot: "/tmp/project-a", defaultModelSelection: null, @@ -1127,17 +1127,17 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* eventStore.append({ type: "thread.created", - eventId: EventId.makeUnsafe("evt-a2"), + eventId: EventId.make("evt-a2"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-a"), + aggregateId: ThreadId.make("thread-a"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-a2"), + commandId: CommandId.make("cmd-a2"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-a2"), + correlationId: CorrelationId.make("cmd-a2"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-a"), - projectId: ProjectId.makeUnsafe("project-a"), + threadId: ThreadId.make("thread-a"), + projectId: ProjectId.make("project-a"), title: "Thread A", modelSelection: { provider: "codex", @@ -1153,17 +1153,17 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* eventStore.append({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-a3"), + eventId: EventId.make("evt-a3"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-a"), + aggregateId: ThreadId.make("thread-a"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-a3"), + commandId: CommandId.make("cmd-a3"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-a3"), + correlationId: CorrelationId.make("cmd-a3"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-a"), - messageId: MessageId.makeUnsafe("message-a"), + threadId: ThreadId.make("thread-a"), + messageId: MessageId.make("message-a"), role: "assistant", text: "hello", turnId: null, @@ -1177,17 +1177,17 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* eventStore.append({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-a4"), + eventId: EventId.make("evt-a4"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-a"), + aggregateId: ThreadId.make("thread-a"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-a4"), + commandId: CommandId.make("cmd-a4"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-a4"), + correlationId: CorrelationId.make("cmd-a4"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-a"), - messageId: MessageId.makeUnsafe("message-a"), + threadId: ThreadId.make("thread-a"), + messageId: MessageId.make("message-a"), role: "assistant", text: " world", turnId: null, @@ -1233,16 +1233,16 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* eventStore.append({ type: "project.created", - eventId: EventId.makeUnsafe("evt-empty-1"), + eventId: EventId.make("evt-empty-1"), aggregateKind: "project", - aggregateId: ProjectId.makeUnsafe("project-empty"), + aggregateId: ProjectId.make("project-empty"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-empty-1"), + commandId: CommandId.make("cmd-empty-1"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-empty-1"), + correlationId: CorrelationId.make("cmd-empty-1"), metadata: {}, payload: { - projectId: ProjectId.makeUnsafe("project-empty"), + projectId: ProjectId.make("project-empty"), title: "Project Empty", workspaceRoot: "/tmp/project-empty", defaultModelSelection: null, @@ -1254,17 +1254,17 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* eventStore.append({ type: "thread.created", - eventId: EventId.makeUnsafe("evt-empty-2"), + eventId: EventId.make("evt-empty-2"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-empty"), + aggregateId: ThreadId.make("thread-empty"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-empty-2"), + commandId: CommandId.make("cmd-empty-2"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-empty-2"), + correlationId: CorrelationId.make("cmd-empty-2"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-empty"), - projectId: ProjectId.makeUnsafe("project-empty"), + threadId: ThreadId.make("thread-empty"), + projectId: ProjectId.make("project-empty"), title: "Thread Empty", modelSelection: { provider: "codex", @@ -1280,17 +1280,17 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* eventStore.append({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-empty-3"), + eventId: EventId.make("evt-empty-3"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-empty"), + aggregateId: ThreadId.make("thread-empty"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-empty-3"), + commandId: CommandId.make("cmd-empty-3"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-empty-3"), + correlationId: CorrelationId.make("cmd-empty-3"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-empty"), - messageId: MessageId.makeUnsafe("assistant-empty"), + threadId: ThreadId.make("thread-empty"), + messageId: MessageId.make("assistant-empty"), role: "assistant", text: "Hello", turnId: null, @@ -1302,17 +1302,17 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* eventStore.append({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-empty-4"), + eventId: EventId.make("evt-empty-4"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-empty"), + aggregateId: ThreadId.make("thread-empty"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-empty-4"), + commandId: CommandId.make("cmd-empty-4"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-empty-4"), + correlationId: CorrelationId.make("cmd-empty-4"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-empty"), - messageId: MessageId.makeUnsafe("assistant-empty"), + threadId: ThreadId.make("thread-empty"), + messageId: MessageId.make("assistant-empty"), role: "assistant", text: " world", turnId: null, @@ -1324,17 +1324,17 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* eventStore.append({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-empty-5"), + eventId: EventId.make("evt-empty-5"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-empty"), + aggregateId: ThreadId.make("thread-empty"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-empty-5"), + commandId: CommandId.make("cmd-empty-5"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-empty-5"), + correlationId: CorrelationId.make("cmd-empty-5"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-empty"), - messageId: MessageId.makeUnsafe("assistant-empty"), + threadId: ThreadId.make("thread-empty"), + messageId: MessageId.make("assistant-empty"), role: "assistant", text: "", turnId: null, @@ -1373,16 +1373,16 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* appendAndProject({ type: "project.created", - eventId: EventId.makeUnsafe("evt-conflict-1"), + eventId: EventId.make("evt-conflict-1"), aggregateKind: "project", - aggregateId: ProjectId.makeUnsafe("project-conflict"), + aggregateId: ProjectId.make("project-conflict"), occurredAt: "2026-02-26T13:00:00.000Z", - commandId: CommandId.makeUnsafe("cmd-conflict-1"), + commandId: CommandId.make("cmd-conflict-1"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-conflict-1"), + correlationId: CorrelationId.make("cmd-conflict-1"), metadata: {}, payload: { - projectId: ProjectId.makeUnsafe("project-conflict"), + projectId: ProjectId.make("project-conflict"), title: "Project Conflict", workspaceRoot: "/tmp/project-conflict", defaultModelSelection: null, @@ -1394,17 +1394,17 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* appendAndProject({ type: "thread.created", - eventId: EventId.makeUnsafe("evt-conflict-2"), + eventId: EventId.make("evt-conflict-2"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-conflict"), + aggregateId: ThreadId.make("thread-conflict"), occurredAt: "2026-02-26T13:00:01.000Z", - commandId: CommandId.makeUnsafe("cmd-conflict-2"), + commandId: CommandId.make("cmd-conflict-2"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-conflict-2"), + correlationId: CorrelationId.make("cmd-conflict-2"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-conflict"), - projectId: ProjectId.makeUnsafe("project-conflict"), + threadId: ThreadId.make("thread-conflict"), + projectId: ProjectId.make("project-conflict"), title: "Thread Conflict", modelSelection: { provider: "codex", @@ -1420,37 +1420,37 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* appendAndProject({ type: "thread.turn-interrupt-requested", - eventId: EventId.makeUnsafe("evt-conflict-3"), + eventId: EventId.make("evt-conflict-3"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-conflict"), + aggregateId: ThreadId.make("thread-conflict"), occurredAt: "2026-02-26T13:00:02.000Z", - commandId: CommandId.makeUnsafe("cmd-conflict-3"), + commandId: CommandId.make("cmd-conflict-3"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-conflict-3"), + correlationId: CorrelationId.make("cmd-conflict-3"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-conflict"), - turnId: TurnId.makeUnsafe("turn-interrupted"), + threadId: ThreadId.make("thread-conflict"), + turnId: TurnId.make("turn-interrupted"), createdAt: "2026-02-26T13:00:02.000Z", }, }); yield* appendAndProject({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-conflict-4"), + eventId: EventId.make("evt-conflict-4"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-conflict"), + aggregateId: ThreadId.make("thread-conflict"), occurredAt: "2026-02-26T13:00:03.000Z", - commandId: CommandId.makeUnsafe("cmd-conflict-4"), + commandId: CommandId.make("cmd-conflict-4"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-conflict-4"), + correlationId: CorrelationId.make("cmd-conflict-4"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-conflict"), - messageId: MessageId.makeUnsafe("assistant-conflict"), + threadId: ThreadId.make("thread-conflict"), + messageId: MessageId.make("assistant-conflict"), role: "assistant", text: "done", - turnId: TurnId.makeUnsafe("turn-completed"), + turnId: TurnId.make("turn-completed"), streaming: false, createdAt: "2026-02-26T13:00:03.000Z", updatedAt: "2026-02-26T13:00:03.000Z", @@ -1459,22 +1459,22 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* appendAndProject({ type: "thread.turn-diff-completed", - eventId: EventId.makeUnsafe("evt-conflict-5"), + eventId: EventId.make("evt-conflict-5"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-conflict"), + aggregateId: ThreadId.make("thread-conflict"), occurredAt: "2026-02-26T13:00:04.000Z", - commandId: CommandId.makeUnsafe("cmd-conflict-5"), + commandId: CommandId.make("cmd-conflict-5"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-conflict-5"), + correlationId: CorrelationId.make("cmd-conflict-5"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-conflict"), - turnId: TurnId.makeUnsafe("turn-completed"), + threadId: ThreadId.make("thread-conflict"), + turnId: TurnId.make("turn-completed"), checkpointTurnCount: 1, - checkpointRef: CheckpointRef.makeUnsafe("refs/t3/checkpoints/thread-conflict/turn/1"), + checkpointRef: CheckpointRef.make("refs/t3/checkpoints/thread-conflict/turn/1"), status: "ready", files: [], - assistantMessageId: MessageId.makeUnsafe("assistant-conflict"), + assistantMessageId: MessageId.make("assistant-conflict"), completedAt: "2026-02-26T13:00:04.000Z", }, }); @@ -1517,16 +1517,16 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* appendAndProject({ type: "project.created", - eventId: EventId.makeUnsafe("evt-revert-1"), + eventId: EventId.make("evt-revert-1"), aggregateKind: "project", - aggregateId: ProjectId.makeUnsafe("project-revert"), + aggregateId: ProjectId.make("project-revert"), occurredAt: "2026-02-26T12:00:00.000Z", - commandId: CommandId.makeUnsafe("cmd-revert-1"), + commandId: CommandId.make("cmd-revert-1"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-revert-1"), + correlationId: CorrelationId.make("cmd-revert-1"), metadata: {}, payload: { - projectId: ProjectId.makeUnsafe("project-revert"), + projectId: ProjectId.make("project-revert"), title: "Project Revert", workspaceRoot: "/tmp/project-revert", defaultModelSelection: null, @@ -1538,17 +1538,17 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* appendAndProject({ type: "thread.created", - eventId: EventId.makeUnsafe("evt-revert-2"), + eventId: EventId.make("evt-revert-2"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-revert"), + aggregateId: ThreadId.make("thread-revert"), occurredAt: "2026-02-26T12:00:01.000Z", - commandId: CommandId.makeUnsafe("cmd-revert-2"), + commandId: CommandId.make("cmd-revert-2"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-revert-2"), + correlationId: CorrelationId.make("cmd-revert-2"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-revert"), - projectId: ProjectId.makeUnsafe("project-revert"), + threadId: ThreadId.make("thread-revert"), + projectId: ProjectId.make("project-revert"), title: "Thread Revert", modelSelection: { provider: "codex", @@ -1564,42 +1564,42 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* appendAndProject({ type: "thread.turn-diff-completed", - eventId: EventId.makeUnsafe("evt-revert-3"), + eventId: EventId.make("evt-revert-3"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-revert"), + aggregateId: ThreadId.make("thread-revert"), occurredAt: "2026-02-26T12:00:02.000Z", - commandId: CommandId.makeUnsafe("cmd-revert-3"), + commandId: CommandId.make("cmd-revert-3"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-revert-3"), + correlationId: CorrelationId.make("cmd-revert-3"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-revert"), - turnId: TurnId.makeUnsafe("turn-1"), + threadId: ThreadId.make("thread-revert"), + turnId: TurnId.make("turn-1"), checkpointTurnCount: 1, - checkpointRef: CheckpointRef.makeUnsafe("refs/t3/checkpoints/thread-revert/turn/1"), + checkpointRef: CheckpointRef.make("refs/t3/checkpoints/thread-revert/turn/1"), status: "ready", files: [], - assistantMessageId: MessageId.makeUnsafe("assistant-keep"), + assistantMessageId: MessageId.make("assistant-keep"), completedAt: "2026-02-26T12:00:02.000Z", }, }); yield* appendAndProject({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-revert-4"), + eventId: EventId.make("evt-revert-4"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-revert"), + aggregateId: ThreadId.make("thread-revert"), occurredAt: "2026-02-26T12:00:02.100Z", - commandId: CommandId.makeUnsafe("cmd-revert-4"), + commandId: CommandId.make("cmd-revert-4"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-revert-4"), + correlationId: CorrelationId.make("cmd-revert-4"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-revert"), - messageId: MessageId.makeUnsafe("assistant-keep"), + threadId: ThreadId.make("thread-revert"), + messageId: MessageId.make("assistant-keep"), role: "assistant", text: "kept", - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), streaming: false, createdAt: "2026-02-26T12:00:02.100Z", updatedAt: "2026-02-26T12:00:02.100Z", @@ -1608,42 +1608,42 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* appendAndProject({ type: "thread.turn-diff-completed", - eventId: EventId.makeUnsafe("evt-revert-5"), + eventId: EventId.make("evt-revert-5"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-revert"), + aggregateId: ThreadId.make("thread-revert"), occurredAt: "2026-02-26T12:00:03.000Z", - commandId: CommandId.makeUnsafe("cmd-revert-5"), + commandId: CommandId.make("cmd-revert-5"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-revert-5"), + correlationId: CorrelationId.make("cmd-revert-5"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-revert"), - turnId: TurnId.makeUnsafe("turn-2"), + threadId: ThreadId.make("thread-revert"), + turnId: TurnId.make("turn-2"), checkpointTurnCount: 2, - checkpointRef: CheckpointRef.makeUnsafe("refs/t3/checkpoints/thread-revert/turn/2"), + checkpointRef: CheckpointRef.make("refs/t3/checkpoints/thread-revert/turn/2"), status: "ready", files: [], - assistantMessageId: MessageId.makeUnsafe("assistant-remove"), + assistantMessageId: MessageId.make("assistant-remove"), completedAt: "2026-02-26T12:00:03.000Z", }, }); yield* appendAndProject({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-revert-6"), + eventId: EventId.make("evt-revert-6"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-revert"), + aggregateId: ThreadId.make("thread-revert"), occurredAt: "2026-02-26T12:00:03.050Z", - commandId: CommandId.makeUnsafe("cmd-revert-6"), + commandId: CommandId.make("cmd-revert-6"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-revert-6"), + correlationId: CorrelationId.make("cmd-revert-6"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-revert"), - messageId: MessageId.makeUnsafe("user-remove"), + threadId: ThreadId.make("thread-revert"), + messageId: MessageId.make("user-remove"), role: "user", text: "removed", - turnId: TurnId.makeUnsafe("turn-2"), + turnId: TurnId.make("turn-2"), streaming: false, createdAt: "2026-02-26T12:00:03.050Z", updatedAt: "2026-02-26T12:00:03.050Z", @@ -1652,20 +1652,20 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* appendAndProject({ type: "thread.message-sent", - eventId: EventId.makeUnsafe("evt-revert-7"), + eventId: EventId.make("evt-revert-7"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-revert"), + aggregateId: ThreadId.make("thread-revert"), occurredAt: "2026-02-26T12:00:03.100Z", - commandId: CommandId.makeUnsafe("cmd-revert-7"), + commandId: CommandId.make("cmd-revert-7"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-revert-7"), + correlationId: CorrelationId.make("cmd-revert-7"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-revert"), - messageId: MessageId.makeUnsafe("assistant-remove"), + threadId: ThreadId.make("thread-revert"), + messageId: MessageId.make("assistant-remove"), role: "assistant", text: "removed", - turnId: TurnId.makeUnsafe("turn-2"), + turnId: TurnId.make("turn-2"), streaming: false, createdAt: "2026-02-26T12:00:03.100Z", updatedAt: "2026-02-26T12:00:03.100Z", @@ -1674,16 +1674,16 @@ it.layer(BaseTestLayer)("OrchestrationProjectionPipeline", (it) => { yield* appendAndProject({ type: "thread.reverted", - eventId: EventId.makeUnsafe("evt-revert-8"), + eventId: EventId.make("evt-revert-8"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-revert"), + aggregateId: ThreadId.make("thread-revert"), occurredAt: "2026-02-26T12:00:04.000Z", - commandId: CommandId.makeUnsafe("cmd-revert-8"), + commandId: CommandId.make("cmd-revert-8"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-revert-8"), + correlationId: CorrelationId.make("cmd-revert-8"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-revert"), + threadId: ThreadId.make("thread-revert"), turnCount: 1, }, }); @@ -1725,10 +1725,10 @@ it.effect("restores pending turn-start metadata across projection pipeline resta Layer.provideMerge(persistenceLayer), ); - const threadId = ThreadId.makeUnsafe("thread-restart"); - const turnId = TurnId.makeUnsafe("turn-restart"); - const messageId = MessageId.makeUnsafe("message-restart"); - const sourcePlanThreadId = ThreadId.makeUnsafe("thread-plan-source"); + const threadId = ThreadId.make("thread-restart"); + const turnId = TurnId.make("turn-restart"); + const messageId = MessageId.make("message-restart"); + const sourcePlanThreadId = ThreadId.make("thread-plan-source"); const sourcePlanId = "plan-source"; const turnStartedAt = "2026-02-26T14:00:00.000Z"; const sessionSetAt = "2026-02-26T14:00:05.000Z"; @@ -1739,13 +1739,13 @@ it.effect("restores pending turn-start metadata across projection pipeline resta yield* eventStore.append({ type: "thread.turn-start-requested", - eventId: EventId.makeUnsafe("evt-restart-1"), + eventId: EventId.make("evt-restart-1"), aggregateKind: "thread", aggregateId: threadId, occurredAt: turnStartedAt, - commandId: CommandId.makeUnsafe("cmd-restart-1"), + commandId: CommandId.make("cmd-restart-1"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-restart-1"), + correlationId: CorrelationId.make("cmd-restart-1"), metadata: {}, payload: { threadId, @@ -1769,13 +1769,13 @@ it.effect("restores pending turn-start metadata across projection pipeline resta yield* eventStore.append({ type: "thread.session-set", - eventId: EventId.makeUnsafe("evt-restart-2"), + eventId: EventId.make("evt-restart-2"), aggregateKind: "thread", aggregateId: threadId, occurredAt: sessionSetAt, - commandId: CommandId.makeUnsafe("cmd-restart-2"), + commandId: CommandId.make("cmd-restart-2"), causationEventId: null, - correlationId: CorrelationId.makeUnsafe("cmd-restart-2"), + correlationId: CorrelationId.make("cmd-restart-2"), metadata: {}, payload: { threadId, @@ -1867,8 +1867,8 @@ engineLayer("OrchestrationProjectionPipeline via engine dispatch", (it) => { yield* engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-live-project"), - projectId: ProjectId.makeUnsafe("project-live"), + commandId: CommandId.make("cmd-live-project"), + projectId: ProjectId.make("project-live"), title: "Live Project", workspaceRoot: "/tmp/project-live", defaultModelSelection: { @@ -1905,8 +1905,8 @@ engineLayer("OrchestrationProjectionPipeline via engine dispatch", (it) => { yield* engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-scripts-project-create"), - projectId: ProjectId.makeUnsafe("project-scripts"), + commandId: CommandId.make("cmd-scripts-project-create"), + projectId: ProjectId.make("project-scripts"), title: "Scripts Project", workspaceRoot: "/tmp/project-scripts", defaultModelSelection: { @@ -1918,8 +1918,8 @@ engineLayer("OrchestrationProjectionPipeline via engine dispatch", (it) => { yield* engine.dispatch({ type: "project.meta.update", - commandId: CommandId.makeUnsafe("cmd-scripts-project-update"), - projectId: ProjectId.makeUnsafe("project-scripts"), + commandId: CommandId.make("cmd-scripts-project-update"), + projectId: ProjectId.make("project-scripts"), scripts: [ { id: "script-1", diff --git a/apps/server/src/orchestration/Layers/ProjectionPipeline.ts b/apps/server/src/orchestration/Layers/ProjectionPipeline.ts index 0844cf8bb0243fae683331649563fd0de048c9a1..bdc6fac6d1caa0216e42439b744bd953ba3cf47d 100644 --- a/apps/server/src/orchestration/Layers/ProjectionPipeline.ts +++ b/apps/server/src/orchestration/Layers/ProjectionPipeline.ts @@ -86,7 +86,7 @@ function extractActivityRequestId(payload: unknown): ApprovalRequestId | null { return null; } const requestId = (payload as Record).requestId; - return typeof requestId === "string" ? ApprovalRequestId.makeUnsafe(requestId) : null; + return typeof requestId === "string" ? ApprovalRequestId.make(requestId) : null; } function retainProjectionMessagesAfterRevert( diff --git a/apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.test.ts b/apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.test.ts index 0a9d90107f9551594cfc109a94f24eebec196fdc..0eb312cbfdc1649dc6e170f9da0fa2357f953ee2 100644 --- a/apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.test.ts +++ b/apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.test.ts @@ -9,11 +9,11 @@ import { ORCHESTRATION_PROJECTOR_NAMES } from "./ProjectionPipeline.ts"; import { OrchestrationProjectionSnapshotQueryLive } from "./ProjectionSnapshotQuery.ts"; import { ProjectionSnapshotQuery } from "../Services/ProjectionSnapshotQuery.ts"; -const asProjectId = (value: string): ProjectId => ProjectId.makeUnsafe(value); -const asTurnId = (value: string): TurnId => TurnId.makeUnsafe(value); -const asMessageId = (value: string): MessageId => MessageId.makeUnsafe(value); -const asEventId = (value: string): EventId => EventId.makeUnsafe(value); -const asCheckpointRef = (value: string): CheckpointRef => CheckpointRef.makeUnsafe(value); +const asProjectId = (value: string): ProjectId => ProjectId.make(value); +const asTurnId = (value: string): TurnId => TurnId.make(value); +const asMessageId = (value: string): MessageId => MessageId.make(value); +const asEventId = (value: string): EventId => EventId.make(value); +const asCheckpointRef = (value: string): CheckpointRef => CheckpointRef.make(value); const projectionSnapshotLayer = it.layer( OrchestrationProjectionSnapshotQueryLive.pipe( @@ -259,7 +259,7 @@ projectionSnapshotLayer("ProjectionSnapshotQuery", (it) => { ]); assert.deepEqual(snapshot.threads, [ { - id: ThreadId.makeUnsafe("thread-1"), + id: ThreadId.make("thread-1"), projectId: asProjectId("project-1"), title: "Thread 1", modelSelection: { @@ -278,7 +278,7 @@ projectionSnapshotLayer("ProjectionSnapshotQuery", (it) => { completedAt: "2026-02-24T00:00:08.000Z", assistantMessageId: asMessageId("message-1"), sourceProposedPlan: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), planId: "plan-1", }, }, @@ -303,7 +303,7 @@ projectionSnapshotLayer("ProjectionSnapshotQuery", (it) => { turnId: asTurnId("turn-1"), planMarkdown: "# Ship it", implementedAt: "2026-02-24T00:00:05.500Z", - implementationThreadId: ThreadId.makeUnsafe("thread-2"), + implementationThreadId: ThreadId.make("thread-2"), createdAt: "2026-02-24T00:00:05.000Z", updatedAt: "2026-02-24T00:00:05.500Z", }, @@ -331,7 +331,7 @@ projectionSnapshotLayer("ProjectionSnapshotQuery", (it) => { }, ], session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "running", providerName: "codex", runtimeMode: "approval-required", @@ -473,7 +473,7 @@ projectionSnapshotLayer("ProjectionSnapshotQuery", (it) => { ); assert.equal(firstThreadId._tag, "Some"); if (firstThreadId._tag === "Some") { - assert.equal(firstThreadId.value, ThreadId.makeUnsafe("thread-first")); + assert.equal(firstThreadId.value, ThreadId.make("thread-first")); } }), ); @@ -596,12 +596,12 @@ projectionSnapshotLayer("ProjectionSnapshotQuery", (it) => { `; const context = yield* snapshotQuery.getThreadCheckpointContext( - ThreadId.makeUnsafe("thread-context"), + ThreadId.make("thread-context"), ); assert.equal(context._tag, "Some"); if (context._tag === "Some") { assert.deepEqual(context.value, { - threadId: ThreadId.makeUnsafe("thread-context"), + threadId: ThreadId.make("thread-context"), projectId: asProjectId("project-context"), workspaceRoot: "/tmp/context-workspace", worktreePath: "/tmp/context-worktree", diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts index f41a596cebcfb866d98eb6838425e9a5fc8ada42..ded64fb9e6c397df8d44142773c9ef450d885d3d 100644 --- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts +++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts @@ -38,11 +38,10 @@ import { ProviderCommandReactor } from "../Services/ProviderCommandReactor.ts"; import * as NodeServices from "@effect/platform-node/NodeServices"; import { ServerSettingsService } from "../../serverSettings.ts"; -const asProjectId = (value: string): ProjectId => ProjectId.makeUnsafe(value); -const asApprovalRequestId = (value: string): ApprovalRequestId => - ApprovalRequestId.makeUnsafe(value); -const asMessageId = (value: string): MessageId => MessageId.makeUnsafe(value); -const asTurnId = (value: string): TurnId => TurnId.makeUnsafe(value); +const asProjectId = (value: string): ProjectId => ProjectId.make(value); +const asApprovalRequestId = (value: string): ApprovalRequestId => ApprovalRequestId.make(value); +const asMessageId = (value: string): MessageId => MessageId.make(value); +const asTurnId = (value: string): TurnId => TurnId.make(value); const deriveServerPathsSync = (baseDir: string, devUrl: URL | undefined) => Effect.runSync(deriveServerPaths(baseDir, devUrl).pipe(Effect.provide(NodeServices.layer))); @@ -122,8 +121,8 @@ describe("ProviderCommandReactor", () => { input !== null && "threadId" in input && typeof input.threadId === "string" - ? ThreadId.makeUnsafe(input.threadId) - : ThreadId.makeUnsafe(`thread-${sessionIndex}`); + ? ThreadId.make(input.threadId) + : ThreadId.make(`thread-${sessionIndex}`); const session: ProviderSession = { provider: modelSelection.provider, status: "ready" as const, @@ -145,7 +144,7 @@ describe("ProviderCommandReactor", () => { }); const sendTurn = vi.fn((_: unknown) => Effect.succeed({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-1"), }), ); @@ -247,7 +246,7 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-project-create"), + commandId: CommandId.make("cmd-project-create"), projectId: asProjectId("project-1"), title: "Provider Project", workspaceRoot: "/tmp/provider-project", @@ -258,8 +257,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-create"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-thread-create"), + threadId: ThreadId.make("thread-1"), projectId: asProjectId("project-1"), title: "Thread", modelSelection: modelSelection, @@ -294,8 +293,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-1"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-1"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-1"), role: "user", @@ -310,7 +309,7 @@ describe("ProviderCommandReactor", () => { await waitFor(() => harness.startSession.mock.calls.length === 1); await waitFor(() => harness.sendTurn.mock.calls.length === 1); - expect(harness.startSession.mock.calls[0]?.[0]).toEqual(ThreadId.makeUnsafe("thread-1")); + expect(harness.startSession.mock.calls[0]?.[0]).toEqual(ThreadId.make("thread-1")); expect(harness.startSession.mock.calls[0]?.[1]).toMatchObject({ cwd: "/tmp/provider-project", modelSelection: { @@ -321,7 +320,7 @@ describe("ProviderCommandReactor", () => { }); const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(thread?.session?.threadId).toBe("thread-1"); expect(thread?.session?.runtimeMode).toBe("approval-required"); }); @@ -335,8 +334,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.meta.update", - commandId: CommandId.makeUnsafe("cmd-thread-title-seed"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-thread-title-seed"), + threadId: ThreadId.make("thread-1"), title: seededTitle, }), ); @@ -344,8 +343,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-title"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-title"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-title"), role: "user", @@ -367,12 +366,12 @@ describe("ProviderCommandReactor", () => { await waitFor(async () => { const readModel = await Effect.runPromise(harness.engine.getReadModel()); return ( - readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1"))?.title === + readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1"))?.title === "Generated title" ); }); const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(thread?.title).toBe("Generated title"); }); @@ -384,8 +383,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.meta.update", - commandId: CommandId.makeUnsafe("cmd-thread-title-custom"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-thread-title-custom"), + threadId: ThreadId.make("thread-1"), title: "Keep this custom title", }), ); @@ -393,8 +392,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-title-preserve"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-title-preserve"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-title-preserve"), role: "user", @@ -412,7 +411,7 @@ describe("ProviderCommandReactor", () => { expect(harness.generateThreadTitle).not.toHaveBeenCalled(); const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(thread?.title).toBe("Keep this custom title"); }); @@ -429,8 +428,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.meta.update", - commandId: CommandId.makeUnsafe("cmd-thread-title-formatted-seed"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-thread-title-formatted-seed"), + threadId: ThreadId.make("thread-1"), title: seededTitle, }), ); @@ -438,8 +437,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-title-formatted"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-title-formatted"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-title-formatted"), role: "user", @@ -457,13 +456,13 @@ describe("ProviderCommandReactor", () => { await waitFor(async () => { const readModel = await Effect.runPromise(harness.engine.getReadModel()); return ( - readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1"))?.title === + readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1"))?.title === "Reconnect spinner resume bug" ); }); const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(thread?.title).toBe("Reconnect spinner resume bug"); }); @@ -474,8 +473,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.meta.update", - commandId: CommandId.makeUnsafe("cmd-thread-branch"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-thread-branch"), + threadId: ThreadId.make("thread-1"), branch: "t3code/1234abcd", worktreePath: "/tmp/provider-project-worktree", }), @@ -499,8 +498,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-branch-model"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-branch-model"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-branch-model"), role: "user", @@ -526,8 +525,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-fast"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-fast"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-fast"), role: "user", @@ -561,7 +560,7 @@ describe("ProviderCommandReactor", () => { }, }); expect(harness.sendTurn.mock.calls[0]?.[0]).toMatchObject({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), modelSelection: { provider: "codex", model: "gpt-5.3-codex", @@ -582,8 +581,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-claude-effort"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-claude-effort"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-claude-effort"), role: "user", @@ -615,7 +614,7 @@ describe("ProviderCommandReactor", () => { }, }); expect(harness.sendTurn.mock.calls[0]?.[0]).toMatchObject({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), modelSelection: { provider: "claudeAgent", model: "claude-sonnet-4-6", @@ -635,8 +634,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-claude-fast-mode"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-claude-fast-mode"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-claude-fast-mode"), role: "user", @@ -668,7 +667,7 @@ describe("ProviderCommandReactor", () => { }, }); expect(harness.sendTurn.mock.calls[0]?.[0]).toMatchObject({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), modelSelection: { provider: "claudeAgent", model: "claude-opus-4-6", @@ -686,8 +685,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.interaction-mode.set", - commandId: CommandId.makeUnsafe("cmd-interaction-mode-set-plan"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-interaction-mode-set-plan"), + threadId: ThreadId.make("thread-1"), interactionMode: "plan", createdAt: now, }), @@ -696,8 +695,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-plan"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-plan"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-plan"), role: "user", @@ -712,7 +711,7 @@ describe("ProviderCommandReactor", () => { await waitFor(() => harness.sendTurn.mock.calls.length === 1); expect(harness.sendTurn.mock.calls[0]?.[0]).toMatchObject({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), interactionMode: "plan", }); }); @@ -726,8 +725,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-provider-first"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-provider-first"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-provider-first"), role: "user", @@ -746,9 +745,7 @@ describe("ProviderCommandReactor", () => { await waitFor(async () => { const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find( - (entry) => entry.id === ThreadId.makeUnsafe("thread-1"), - ); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); return ( thread?.activities.some((activity) => activity.kind === "provider.turn.start.failed") ?? false @@ -759,7 +756,7 @@ describe("ProviderCommandReactor", () => { expect(harness.sendTurn).not.toHaveBeenCalled(); const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(thread?.session).toBeNull(); expect( thread?.activities.find((activity) => activity.kind === "provider.turn.start.failed"), @@ -778,8 +775,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-unsupported-1"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-unsupported-1"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-unsupported-1"), role: "user", @@ -797,8 +794,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-unsupported-2"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-unsupported-2"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-unsupported-2"), role: "user", @@ -814,7 +811,7 @@ describe("ProviderCommandReactor", () => { await waitFor(() => harness.sendTurn.mock.calls.length === 2); expect(harness.sendTurn.mock.calls[1]?.[0]).toMatchObject({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), modelSelection: { provider: "codex", model: "gpt-5-codex", @@ -829,8 +826,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-unchanged-1"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-unchanged-1"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-unchanged-1"), role: "user", @@ -849,8 +846,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-unchanged-2"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-unchanged-2"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-unchanged-2"), role: "user", @@ -877,8 +874,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-claude-effort-1"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-claude-effort-1"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-claude-effort-1"), role: "user", @@ -904,8 +901,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-claude-effort-2"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-claude-effort-2"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-claude-effort-2"), role: "user", @@ -946,8 +943,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.runtime-mode.set", - commandId: CommandId.makeUnsafe("cmd-runtime-mode-set-initial-full-access"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-runtime-mode-set-initial-full-access"), + threadId: ThreadId.make("thread-1"), runtimeMode: "full-access", createdAt: now, }), @@ -956,8 +953,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-runtime-mode-1"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-runtime-mode-1"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-runtime-mode-1"), role: "user", @@ -976,8 +973,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.runtime-mode.set", - commandId: CommandId.makeUnsafe("cmd-runtime-mode-set-1"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-runtime-mode-set-1"), + threadId: ThreadId.make("thread-1"), runtimeMode: "approval-required", createdAt: now, }), @@ -985,17 +982,15 @@ describe("ProviderCommandReactor", () => { await waitFor(async () => { const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find( - (entry) => entry.id === ThreadId.makeUnsafe("thread-1"), - ); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); return thread?.runtimeMode === "approval-required"; }); await waitFor(() => harness.startSession.mock.calls.length === 2); await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-runtime-mode-2"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-runtime-mode-2"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-runtime-mode-2"), role: "user", @@ -1012,16 +1007,16 @@ describe("ProviderCommandReactor", () => { expect(harness.stopSession.mock.calls.length).toBe(0); expect(harness.startSession.mock.calls[1]?.[1]).toMatchObject({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), resumeCursor: { opaque: "resume-1" }, runtimeMode: "approval-required", }); expect(harness.sendTurn.mock.calls[1]?.[0]).toMatchObject({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), }); const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(thread?.session?.threadId).toBe("thread-1"); expect(thread?.session?.runtimeMode).toBe("approval-required"); }); @@ -1035,10 +1030,10 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-runtime-mode-claude"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set-runtime-mode-claude"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "ready", providerName: "claudeAgent", runtimeMode: "full-access", @@ -1053,8 +1048,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.runtime-mode.set", - commandId: CommandId.makeUnsafe("cmd-runtime-mode-set-claude-no-options"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-runtime-mode-set-claude-no-options"), + threadId: ThreadId.make("thread-1"), runtimeMode: "approval-required", createdAt: now, }), @@ -1078,8 +1073,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-provider-switch-1"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-provider-switch-1"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-provider-switch-1"), role: "user", @@ -1098,8 +1093,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-provider-switch-2"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-provider-switch-2"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-provider-switch-2"), role: "user", @@ -1118,9 +1113,7 @@ describe("ProviderCommandReactor", () => { await waitFor(async () => { const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find( - (entry) => entry.id === ThreadId.makeUnsafe("thread-1"), - ); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); return ( thread?.activities.some((activity) => activity.kind === "provider.turn.start.failed") ?? false @@ -1132,7 +1125,7 @@ describe("ProviderCommandReactor", () => { expect(harness.stopSession.mock.calls.length).toBe(0); const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(thread?.session?.threadId).toBe("thread-1"); expect(thread?.session?.providerName).toBe("codex"); expect(thread?.session?.runtimeMode).toBe("approval-required"); @@ -1152,8 +1145,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.runtime-mode.set", - commandId: CommandId.makeUnsafe("cmd-runtime-mode-set-initial-full-access-2"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-runtime-mode-set-initial-full-access-2"), + threadId: ThreadId.make("thread-1"), runtimeMode: "full-access", createdAt: now, }), @@ -1162,8 +1155,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-restart-failure-1"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-restart-failure-1"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("user-message-restart-failure-1"), role: "user", @@ -1186,8 +1179,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.runtime-mode.set", - commandId: CommandId.makeUnsafe("cmd-runtime-mode-set-restart-failure"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-runtime-mode-set-restart-failure"), + threadId: ThreadId.make("thread-1"), runtimeMode: "approval-required", createdAt: now, }), @@ -1195,9 +1188,7 @@ describe("ProviderCommandReactor", () => { await waitFor(async () => { const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find( - (entry) => entry.id === ThreadId.makeUnsafe("thread-1"), - ); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); return thread?.runtimeMode === "approval-required"; }); await waitFor(() => harness.startSession.mock.calls.length === 2); @@ -1207,7 +1198,7 @@ describe("ProviderCommandReactor", () => { expect(harness.sendTurn.mock.calls.length).toBe(1); const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(thread?.session?.threadId).toBe("thread-1"); expect(thread?.session?.runtimeMode).toBe("full-access"); }); @@ -1219,10 +1210,10 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "running", providerName: "codex", runtimeMode: "approval-required", @@ -1237,8 +1228,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.interrupt", - commandId: CommandId.makeUnsafe("cmd-turn-interrupt"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-interrupt"), + threadId: ThreadId.make("thread-1"), turnId: asTurnId("turn-1"), createdAt: now, }), @@ -1257,10 +1248,10 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-for-approval"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set-for-approval"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "running", providerName: "codex", runtimeMode: "approval-required", @@ -1275,8 +1266,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.approval.respond", - commandId: CommandId.makeUnsafe("cmd-approval-respond"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-approval-respond"), + threadId: ThreadId.make("thread-1"), requestId: asApprovalRequestId("approval-request-1"), decision: "accept", createdAt: now, @@ -1298,10 +1289,10 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-for-user-input"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set-for-user-input"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "running", providerName: "codex", runtimeMode: "approval-required", @@ -1316,8 +1307,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.user-input.respond", - commandId: CommandId.makeUnsafe("cmd-user-input-respond"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-user-input-respond"), + threadId: ThreadId.make("thread-1"), requestId: asApprovalRequestId("user-input-request-1"), answers: { sandbox_mode: "workspace-write", @@ -1352,10 +1343,10 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-for-approval-error"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set-for-approval-error"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "running", providerName: "codex", runtimeMode: "approval-required", @@ -1370,10 +1361,10 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.activity.append", - commandId: CommandId.makeUnsafe("cmd-approval-requested"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-approval-requested"), + threadId: ThreadId.make("thread-1"), activity: { - id: EventId.makeUnsafe("activity-approval-requested"), + id: EventId.make("activity-approval-requested"), tone: "approval", kind: "approval.requested", summary: "Command approval requested", @@ -1391,8 +1382,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.approval.respond", - commandId: CommandId.makeUnsafe("cmd-approval-respond-stale"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-approval-respond-stale"), + threadId: ThreadId.make("thread-1"), requestId: asApprovalRequestId("approval-request-1"), decision: "acceptForSession", createdAt: now, @@ -1401,9 +1392,7 @@ describe("ProviderCommandReactor", () => { await waitFor(async () => { const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find( - (entry) => entry.id === ThreadId.makeUnsafe("thread-1"), - ); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); if (!thread) return false; return thread.activities.some( (activity) => activity.kind === "provider.approval.respond.failed", @@ -1411,7 +1400,7 @@ describe("ProviderCommandReactor", () => { }); const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(thread).toBeDefined(); const failureActivity = thread?.activities.find( @@ -1449,10 +1438,10 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-for-user-input-error"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set-for-user-input-error"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "running", providerName: "claudeAgent", runtimeMode: "approval-required", @@ -1467,10 +1456,10 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.activity.append", - commandId: CommandId.makeUnsafe("cmd-user-input-requested"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-user-input-requested"), + threadId: ThreadId.make("thread-1"), activity: { - id: EventId.makeUnsafe("activity-user-input-requested"), + id: EventId.make("activity-user-input-requested"), tone: "info", kind: "user-input.requested", summary: "User input requested", @@ -1500,8 +1489,8 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.user-input.respond", - commandId: CommandId.makeUnsafe("cmd-user-input-respond-stale"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-user-input-respond-stale"), + threadId: ThreadId.make("thread-1"), requestId: asApprovalRequestId("user-input-request-1"), answers: { sandbox_mode: "workspace-write", @@ -1512,9 +1501,7 @@ describe("ProviderCommandReactor", () => { await waitFor(async () => { const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find( - (entry) => entry.id === ThreadId.makeUnsafe("thread-1"), - ); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); if (!thread) return false; return thread.activities.some( (activity) => activity.kind === "provider.user-input.respond.failed", @@ -1522,7 +1509,7 @@ describe("ProviderCommandReactor", () => { }); const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(thread).toBeDefined(); const failureActivity = thread?.activities.find( @@ -1551,10 +1538,10 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-for-stop"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-set-for-stop"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "ready", providerName: "codex", runtimeMode: "approval-required", @@ -1569,15 +1556,15 @@ describe("ProviderCommandReactor", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.stop", - commandId: CommandId.makeUnsafe("cmd-session-stop"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-stop"), + threadId: ThreadId.make("thread-1"), createdAt: now, }), ); await waitFor(() => harness.stopSession.mock.calls.length === 1); const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(thread?.session).not.toBeNull(); expect(thread?.session?.status).toBe("stopped"); expect(thread?.session?.threadId).toBe("thread-1"); diff --git a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts index 419e3f3bf23b7f9a7ee6b37c9e29d17273d730f3..a1a69f0efaa7888e506917d2b66715f66e04fe84 100644 --- a/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts +++ b/apps/server/src/orchestration/Layers/ProviderCommandReactor.ts @@ -67,7 +67,7 @@ const turnStartKeyForEvent = (event: ProviderIntentEvent): string => event.commandId !== null ? `command:${event.commandId}` : `event:${event.eventId}`; const serverCommandId = (tag: string): CommandId => - CommandId.makeUnsafe(`server:${tag}:${crypto.randomUUID()}`); + CommandId.make(`server:${tag}:${crypto.randomUUID()}`); const HANDLED_TURN_START_KEY_MAX = 10_000; const HANDLED_TURN_START_KEY_TTL = Duration.minutes(30); @@ -186,7 +186,7 @@ const make = Effect.gen(function* () { commandId: serverCommandId("provider-failure-activity"), threadId: input.threadId, activity: { - id: EventId.makeUnsafe(crypto.randomUUID()), + id: EventId.make(crypto.randomUUID()), tone: "error", kind: input.kind, summary: input.summary, diff --git a/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts b/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts index 30f43365d906b953c697a1570a3a99acd0a00984..2a330a36b530dd9ac0c1a088b7ed49388cc6dc51 100644 --- a/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts +++ b/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.test.ts @@ -47,12 +47,12 @@ function makeTestServerSettingsLayer(overrides: Partial = {}) { return ServerSettingsService.layerTest(overrides); } -const asProjectId = (value: string): ProjectId => ProjectId.makeUnsafe(value); -const asItemId = (value: string): ProviderItemId => ProviderItemId.makeUnsafe(value); -const asEventId = (value: string): EventId => EventId.makeUnsafe(value); -const asMessageId = (value: string): MessageId => MessageId.makeUnsafe(value); -const asThreadId = (value: string): ThreadId => ThreadId.makeUnsafe(value); -const asTurnId = (value: string): TurnId => TurnId.makeUnsafe(value); +const asProjectId = (value: string): ProjectId => ProjectId.make(value); +const asItemId = (value: string): ProviderItemId => ProviderItemId.make(value); +const asEventId = (value: string): EventId => EventId.make(value); +const asMessageId = (value: string): MessageId => MessageId.make(value); +const asThreadId = (value: string): ThreadId => ThreadId.make(value); +const asTurnId = (value: string): TurnId => TurnId.make(value); type LegacyProviderRuntimeEvent = { readonly type: string; @@ -227,7 +227,7 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( engine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe("cmd-provider-project-create"), + commandId: CommandId.make("cmd-provider-project-create"), projectId: asProjectId("project-1"), title: "Provider Project", workspaceRoot, @@ -241,8 +241,8 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-create"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-thread-create"), + threadId: ThreadId.make("thread-1"), projectId: asProjectId("project-1"), title: "Thread", modelSelection: { @@ -259,10 +259,10 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-seed"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-seed"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "ready", providerName: "codex", runtimeMode: "approval-required", @@ -277,7 +277,7 @@ describe("ProviderRuntimeIngestion", () => { provider: "codex", status: "ready", runtimeMode: "approval-required", - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), createdAt, updatedAt: createdAt, }); @@ -457,9 +457,7 @@ describe("ProviderRuntimeIngestion", () => { await harness.drain(); const midReadModel = await Effect.runPromise(harness.engine.getReadModel()); - const midThread = midReadModel.threads.find( - (entry) => entry.id === ThreadId.makeUnsafe("thread-1"), - ); + const midThread = midReadModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(midThread?.session?.status).toBe("running"); expect(midThread?.session?.activeTurnId).toBe("turn-midturn-lifecycle"); @@ -486,10 +484,10 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-seed-claude-placeholder"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-session-seed-claude-placeholder"), + threadId: ThreadId.make("thread-1"), session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "ready", providerName: "claudeAgent", runtimeMode: "approval-required", @@ -564,9 +562,7 @@ describe("ProviderRuntimeIngestion", () => { await harness.drain(); const midReadModel = await Effect.runPromise(harness.engine.getReadModel()); - const midThread = midReadModel.threads.find( - (entry) => entry.id === ThreadId.makeUnsafe("thread-1"), - ); + const midThread = midReadModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(midThread?.session?.status).toBe("running"); expect(midThread?.session?.activeTurnId).toBe("turn-primary"); @@ -618,9 +614,7 @@ describe("ProviderRuntimeIngestion", () => { await harness.drain(); const midReadModel = await Effect.runPromise(harness.engine.getReadModel()); - const midThread = midReadModel.threads.find( - (entry) => entry.id === ThreadId.makeUnsafe("thread-1"), - ); + const midThread = midReadModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(midThread?.session?.status).toBe("running"); expect(midThread?.session?.activeTurnId).toBe("turn-guarded-main"); @@ -770,7 +764,7 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-create-plan-source"), + commandId: CommandId.make("cmd-thread-create-plan-source"), threadId: sourceThreadId, projectId: asProjectId("project-1"), title: "Plan Source", @@ -788,7 +782,7 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-plan-source"), + commandId: CommandId.make("cmd-session-set-plan-source"), threadId: sourceThreadId, session: { threadId: sourceThreadId, @@ -805,7 +799,7 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-create-plan-target"), + commandId: CommandId.make("cmd-thread-create-plan-target"), threadId: targetThreadId, projectId: asProjectId("project-1"), title: "Plan Target", @@ -823,7 +817,7 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-plan-target"), + commandId: CommandId.make("cmd-session-set-plan-target"), threadId: targetThreadId, session: { threadId: targetThreadId, @@ -882,7 +876,7 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-plan-target"), + commandId: CommandId.make("cmd-turn-start-plan-target"), threadId: targetThreadId, message: { messageId: asMessageId("msg-plan-target"), @@ -957,7 +951,7 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-create-plan-source-guarded"), + commandId: CommandId.make("cmd-thread-create-plan-source-guarded"), threadId: sourceThreadId, projectId: asProjectId("project-1"), title: "Plan Source", @@ -975,7 +969,7 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-plan-source-guarded"), + commandId: CommandId.make("cmd-session-set-plan-source-guarded"), threadId: sourceThreadId, session: { threadId: sourceThreadId, @@ -1051,7 +1045,7 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-plan-target-guarded"), + commandId: CommandId.make("cmd-turn-start-plan-target-guarded"), threadId: targetThreadId, message: { messageId: asMessageId("msg-plan-target-guarded"), @@ -1110,7 +1104,7 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-create-plan-source-unrelated"), + commandId: CommandId.make("cmd-thread-create-plan-source-unrelated"), threadId: sourceThreadId, projectId: asProjectId("project-1"), title: "Plan Source", @@ -1128,7 +1122,7 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-plan-source-unrelated"), + commandId: CommandId.make("cmd-session-set-plan-source-unrelated"), threadId: sourceThreadId, session: { threadId: sourceThreadId, @@ -1145,7 +1139,7 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-thread-create-plan-target-unrelated"), + commandId: CommandId.make("cmd-thread-create-plan-target-unrelated"), threadId: targetThreadId, projectId: asProjectId("project-1"), title: "Plan Target", @@ -1163,7 +1157,7 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.session.set", - commandId: CommandId.makeUnsafe("cmd-session-set-plan-target-unrelated"), + commandId: CommandId.make("cmd-session-set-plan-target-unrelated"), threadId: targetThreadId, session: { threadId: targetThreadId, @@ -1213,7 +1207,7 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-plan-target-unrelated"), + commandId: CommandId.make("cmd-turn-start-plan-target-unrelated"), threadId: targetThreadId, message: { messageId: asMessageId("msg-plan-target-unrelated"), @@ -1364,9 +1358,7 @@ describe("ProviderRuntimeIngestion", () => { await harness.drain(); const midReadModel = await Effect.runPromise(harness.engine.getReadModel()); - const midThread = midReadModel.threads.find( - (entry) => entry.id === ThreadId.makeUnsafe("thread-1"), - ); + const midThread = midReadModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect( midThread?.messages.some( (message: ProviderRuntimeTestMessage) => message.id === "assistant:item-buffered", @@ -1407,8 +1399,8 @@ describe("ProviderRuntimeIngestion", () => { await Effect.runPromise( harness.engine.dispatch({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start-streaming-mode"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start-streaming-mode"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("message-streaming-mode"), role: "user", @@ -1649,7 +1641,7 @@ describe("ProviderRuntimeIngestion", () => { provider: "codex", createdAt: now, threadId: asThreadId("thread-1"), - requestId: ApprovalRequestId.makeUnsafe("req-open"), + requestId: ApprovalRequestId.make("req-open"), payload: { requestType: "command_execution_approval", detail: "pwd", @@ -1662,7 +1654,7 @@ describe("ProviderRuntimeIngestion", () => { provider: "codex", createdAt: now, threadId: asThreadId("thread-1"), - requestId: ApprovalRequestId.makeUnsafe("req-open"), + requestId: ApprovalRequestId.make("req-open"), payload: { requestType: "command_execution_approval", decision: "accept", @@ -1681,7 +1673,7 @@ describe("ProviderRuntimeIngestion", () => { ); const readModel = await Effect.runPromise(harness.engine.getReadModel()); - const thread = readModel.threads.find((entry) => entry.id === ThreadId.makeUnsafe("thread-1")); + const thread = readModel.threads.find((entry) => entry.id === ThreadId.make("thread-1")); expect(thread).toBeDefined(); const requested = thread?.activities.find( @@ -2286,7 +2278,7 @@ describe("ProviderRuntimeIngestion", () => { createdAt: now, threadId: asThreadId("thread-1"), turnId: asTurnId("turn-user-input"), - requestId: ApprovalRequestId.makeUnsafe("req-user-input-1"), + requestId: ApprovalRequestId.make("req-user-input-1"), payload: { questions: [ { @@ -2311,7 +2303,7 @@ describe("ProviderRuntimeIngestion", () => { createdAt: new Date().toISOString(), threadId: asThreadId("thread-1"), turnId: asTurnId("turn-user-input"), - requestId: ApprovalRequestId.makeUnsafe("req-user-input-1"), + requestId: ApprovalRequestId.make("req-user-input-1"), payload: { answers: { sandbox_mode: "workspace-write", diff --git a/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts b/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts index 8d3fb5d75201ecefbc624f629d17e4f3bd38bf5b..c1241241ccee9328ae7bafa6818a657c1e9ef905 100644 --- a/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts +++ b/apps/server/src/orchestration/Layers/ProviderRuntimeIngestion.ts @@ -30,7 +30,7 @@ import { ServerSettingsService } from "../../serverSettings.ts"; const providerTurnKey = (threadId: ThreadId, turnId: TurnId) => `${threadId}:${turnId}`; const providerCommandId = (event: ProviderRuntimeEvent, tag: string): CommandId => - CommandId.makeUnsafe(`provider:${event.eventId}:${tag}:${crypto.randomUUID()}`); + CommandId.make(`provider:${event.eventId}:${tag}:${crypto.randomUUID()}`); const TURN_MESSAGE_IDS_BY_TURN_CACHE_CAPACITY = 10_000; const TURN_MESSAGE_IDS_BY_TURN_TTL = Duration.minutes(120); @@ -57,11 +57,11 @@ type RuntimeIngestionInput = }; function toTurnId(value: TurnId | string | undefined): TurnId | undefined { - return value === undefined ? undefined : TurnId.makeUnsafe(String(value)); + return value === undefined ? undefined : TurnId.make(String(value)); } function toApprovalRequestId(value: string | undefined): ApprovalRequestId | undefined { - return value === undefined ? undefined : ApprovalRequestId.makeUnsafe(value); + return value === undefined ? undefined : ApprovalRequestId.make(value); } function sameId(left: string | null | undefined, right: string | null | undefined): boolean { @@ -857,7 +857,7 @@ const make = Effect.fn("make")(function* () { yield* orchestrationEngine.dispatch({ type: "thread.proposed-plan.upsert", - commandId: CommandId.makeUnsafe( + commandId: CommandId.make( `provider:source-proposed-plan-implemented:${implementationThreadId}:${crypto.randomUUID()}`, ), threadId: sourceThread.id, @@ -1003,7 +1003,7 @@ const make = Effect.fn("make")(function* () { event.type === "turn.proposed.delta" ? event.payload.delta : undefined; if (assistantDelta && assistantDelta.length > 0) { - const assistantMessageId = MessageId.makeUnsafe( + const assistantMessageId = MessageId.make( `assistant:${event.itemId ?? event.turnId ?? event.eventId}`, ); const turnId = toTurnId(event.turnId); @@ -1049,9 +1049,7 @@ const make = Effect.fn("make")(function* () { const assistantCompletion = event.type === "item.completed" && event.payload.itemType === "assistant_message" ? { - messageId: MessageId.makeUnsafe( - `assistant:${event.itemId ?? event.turnId ?? event.eventId}`, - ), + messageId: MessageId.make(`assistant:${event.itemId ?? event.turnId ?? event.eventId}`), fallbackText: event.payload.detail, } : undefined; @@ -1186,7 +1184,7 @@ const make = Effect.fn("make")(function* () { if (thread.checkpoints.some((c) => c.turnId === turnId)) { // Already tracked; no-op. } else { - const assistantMessageId = MessageId.makeUnsafe( + const assistantMessageId = MessageId.make( `assistant:${event.itemId ?? event.turnId ?? event.eventId}`, ); const maxTurnCount = thread.checkpoints.reduce( @@ -1199,7 +1197,7 @@ const make = Effect.fn("make")(function* () { threadId: thread.id, turnId, completedAt: now, - checkpointRef: CheckpointRef.makeUnsafe(`provider-diff:${event.eventId}`), + checkpointRef: CheckpointRef.make(`provider-diff:${event.eventId}`), status: "missing", files: [], assistantMessageId, diff --git a/apps/server/src/orchestration/Services/CheckpointReactor.ts b/apps/server/src/orchestration/Services/CheckpointReactor.ts index 539ac784cd963bf5b3d5f163738a60800dbd7242..9e9c83beb47068a9eeaeaaa7b30635c0365042f0 100644 --- a/apps/server/src/orchestration/Services/CheckpointReactor.ts +++ b/apps/server/src/orchestration/Services/CheckpointReactor.ts @@ -6,7 +6,7 @@ * * @module CheckpointReactor */ -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect, Scope } from "effect"; /** @@ -34,7 +34,6 @@ export interface CheckpointReactorShape { /** * CheckpointReactor - Service tag for checkpoint reactor workers. */ -export class CheckpointReactor extends ServiceMap.Service< - CheckpointReactor, - CheckpointReactorShape ->()("t3/orchestration/Services/CheckpointReactor") {} +export class CheckpointReactor extends Context.Service()( + "t3/orchestration/Services/CheckpointReactor", +) {} diff --git a/apps/server/src/orchestration/Services/OrchestrationEngine.ts b/apps/server/src/orchestration/Services/OrchestrationEngine.ts index 33ac75049f8c9a037f8c2f81df739fa9aa29d1e9..376b87d30a00fc2b9cc87a6487a80c803b1149e3 100644 --- a/apps/server/src/orchestration/Services/OrchestrationEngine.ts +++ b/apps/server/src/orchestration/Services/OrchestrationEngine.ts @@ -5,7 +5,7 @@ * `OrchestrationEventStore` persistence. It does not own provider process * management or transport concerns (e.g. websocket request parsing). * - * Uses Effect `ServiceMap.Service` for dependency injection. Command dispatch, + * Uses Effect `Context.Service` for dependency injection. Command dispatch, * replay, and unknown-input decoding all return typed domain errors. * * @module OrchestrationEngineService @@ -15,7 +15,7 @@ import type { OrchestrationEvent, OrchestrationReadModel, } from "@t3tools/contracts"; -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect, Stream } from "effect"; import type { OrchestrationDispatchError } from "../Errors.ts"; @@ -74,7 +74,7 @@ export interface OrchestrationEngineShape { * }) * ``` */ -export class OrchestrationEngineService extends ServiceMap.Service< +export class OrchestrationEngineService extends Context.Service< OrchestrationEngineService, OrchestrationEngineShape >()("t3/orchestration/Services/OrchestrationEngine/OrchestrationEngineService") {} diff --git a/apps/server/src/orchestration/Services/OrchestrationReactor.ts b/apps/server/src/orchestration/Services/OrchestrationReactor.ts index 9b628eebda31126e92b3572cc48ce27437adeecc..a3edeaac61dd9e1964fc7a7b941ead46d40b5825 100644 --- a/apps/server/src/orchestration/Services/OrchestrationReactor.ts +++ b/apps/server/src/orchestration/Services/OrchestrationReactor.ts @@ -6,7 +6,7 @@ * * @module OrchestrationReactor */ -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect, Scope } from "effect"; /** @@ -25,7 +25,7 @@ export interface OrchestrationReactorShape { /** * OrchestrationReactor - Service tag for orchestration reactor coordination. */ -export class OrchestrationReactor extends ServiceMap.Service< +export class OrchestrationReactor extends Context.Service< OrchestrationReactor, OrchestrationReactorShape >()("t3/orchestration/Services/OrchestrationReactor") {} diff --git a/apps/server/src/orchestration/Services/ProjectionPipeline.ts b/apps/server/src/orchestration/Services/ProjectionPipeline.ts index f8c86bf09b8dd26516d4e7648f47b0c18ead518e..349f3430ad6dee2ce710787aa1c03ec1dea173c4 100644 --- a/apps/server/src/orchestration/Services/ProjectionPipeline.ts +++ b/apps/server/src/orchestration/Services/ProjectionPipeline.ts @@ -7,7 +7,7 @@ * @module OrchestrationProjectionPipeline */ import type { OrchestrationEvent } from "@t3tools/contracts"; -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect } from "effect"; import type { ProjectionRepositoryError } from "../../persistence/Errors.ts"; @@ -36,7 +36,7 @@ export interface OrchestrationProjectionPipelineShape { /** * OrchestrationProjectionPipeline - Service tag for orchestration projections. */ -export class OrchestrationProjectionPipeline extends ServiceMap.Service< +export class OrchestrationProjectionPipeline extends Context.Service< OrchestrationProjectionPipeline, OrchestrationProjectionPipelineShape >()("t3/orchestration/Services/ProjectionPipeline/OrchestrationProjectionPipeline") {} diff --git a/apps/server/src/orchestration/Services/ProjectionSnapshotQuery.ts b/apps/server/src/orchestration/Services/ProjectionSnapshotQuery.ts index a7673dc32e055e84303f5e10790fb494234a8025..36bbf5028b4c402624318d80cae21aa68d90268c 100644 --- a/apps/server/src/orchestration/Services/ProjectionSnapshotQuery.ts +++ b/apps/server/src/orchestration/Services/ProjectionSnapshotQuery.ts @@ -13,7 +13,7 @@ import type { ProjectId, ThreadId, } from "@t3tools/contracts"; -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Option } from "effect"; import type { Effect } from "effect"; @@ -74,7 +74,7 @@ export interface ProjectionSnapshotQueryShape { /** * ProjectionSnapshotQuery - Service tag for projection snapshot queries. */ -export class ProjectionSnapshotQuery extends ServiceMap.Service< +export class ProjectionSnapshotQuery extends Context.Service< ProjectionSnapshotQuery, ProjectionSnapshotQueryShape >()("t3/orchestration/Services/ProjectionSnapshotQuery") {} diff --git a/apps/server/src/orchestration/Services/ProviderCommandReactor.ts b/apps/server/src/orchestration/Services/ProviderCommandReactor.ts index 8f96d8fb99d01604153971ab62c229f4fbf74e45..c8b8580682ad893df33dad6ed96639766b7ea5da 100644 --- a/apps/server/src/orchestration/Services/ProviderCommandReactor.ts +++ b/apps/server/src/orchestration/Services/ProviderCommandReactor.ts @@ -6,7 +6,7 @@ * * @module ProviderCommandReactor */ -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect, Scope } from "effect"; /** @@ -34,7 +34,7 @@ export interface ProviderCommandReactorShape { /** * ProviderCommandReactor - Service tag for provider command reaction workers. */ -export class ProviderCommandReactor extends ServiceMap.Service< +export class ProviderCommandReactor extends Context.Service< ProviderCommandReactor, ProviderCommandReactorShape >()("t3/orchestration/Services/ProviderCommandReactor") {} diff --git a/apps/server/src/orchestration/Services/ProviderRuntimeIngestion.ts b/apps/server/src/orchestration/Services/ProviderRuntimeIngestion.ts index f1b95762a253600539a2eb904027858aad220410..831ce3a6f0cd0e604dff2c02329ed34167fc6326 100644 --- a/apps/server/src/orchestration/Services/ProviderRuntimeIngestion.ts +++ b/apps/server/src/orchestration/Services/ProviderRuntimeIngestion.ts @@ -6,7 +6,7 @@ * * @module ProviderRuntimeIngestionService */ -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect, Scope } from "effect"; /** @@ -34,7 +34,7 @@ export interface ProviderRuntimeIngestionShape { /** * ProviderRuntimeIngestionService - Service tag for runtime ingestion workers. */ -export class ProviderRuntimeIngestionService extends ServiceMap.Service< +export class ProviderRuntimeIngestionService extends Context.Service< ProviderRuntimeIngestionService, ProviderRuntimeIngestionShape >()("t3/orchestration/Services/ProviderRuntimeIngestion/ProviderRuntimeIngestionService") {} diff --git a/apps/server/src/orchestration/Services/RuntimeReceiptBus.ts b/apps/server/src/orchestration/Services/RuntimeReceiptBus.ts index bf5c94f3a0b5c1831b11d71637671f1598f9f6ab..53038006dea5bb7f1566ca131858f5f18388f978 100644 --- a/apps/server/src/orchestration/Services/RuntimeReceiptBus.ts +++ b/apps/server/src/orchestration/Services/RuntimeReceiptBus.ts @@ -15,7 +15,7 @@ * @module RuntimeReceiptBus */ import { CheckpointRef, IsoDateTime, NonNegativeInt, ThreadId, TurnId } from "@t3tools/contracts"; -import { Schema, ServiceMap } from "effect"; +import { Schema, Context } from "effect"; import type { Effect, Stream } from "effect"; export const CheckpointBaselineCapturedReceipt = Schema.Struct({ @@ -59,7 +59,6 @@ export interface RuntimeReceiptBusShape { readonly streamEventsForTest: Stream.Stream; } -export class RuntimeReceiptBus extends ServiceMap.Service< - RuntimeReceiptBus, - RuntimeReceiptBusShape ->()("t3/orchestration/Services/RuntimeReceiptBus") {} +export class RuntimeReceiptBus extends Context.Service()( + "t3/orchestration/Services/RuntimeReceiptBus", +) {} diff --git a/apps/server/src/orchestration/commandInvariants.test.ts b/apps/server/src/orchestration/commandInvariants.test.ts index 43d665a2c9b773bf02c76a726df9909811ab4139..a678bcea1666057011733922f3bf123b74e3e453 100644 --- a/apps/server/src/orchestration/commandInvariants.test.ts +++ b/apps/server/src/orchestration/commandInvariants.test.ts @@ -25,7 +25,7 @@ const readModel: OrchestrationReadModel = { updatedAt: now, projects: [ { - id: ProjectId.makeUnsafe("project-a"), + id: ProjectId.make("project-a"), title: "Project A", workspaceRoot: "/tmp/project-a", defaultModelSelection: { @@ -38,7 +38,7 @@ const readModel: OrchestrationReadModel = { deletedAt: null, }, { - id: ProjectId.makeUnsafe("project-b"), + id: ProjectId.make("project-b"), title: "Project B", workspaceRoot: "/tmp/project-b", defaultModelSelection: { @@ -53,8 +53,8 @@ const readModel: OrchestrationReadModel = { ], threads: [ { - id: ThreadId.makeUnsafe("thread-1"), - projectId: ProjectId.makeUnsafe("project-a"), + id: ThreadId.make("thread-1"), + projectId: ProjectId.make("project-a"), title: "Thread A", modelSelection: { provider: "codex", @@ -76,8 +76,8 @@ const readModel: OrchestrationReadModel = { deletedAt: null, }, { - id: ThreadId.makeUnsafe("thread-2"), - projectId: ProjectId.makeUnsafe("project-b"), + id: ThreadId.make("thread-2"), + projectId: ProjectId.make("project-b"), title: "Thread B", modelSelection: { provider: "codex", @@ -103,10 +103,10 @@ const readModel: OrchestrationReadModel = { const messageSendCommand: OrchestrationCommand = { type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-1"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-1"), + threadId: ThreadId.make("thread-1"), message: { - messageId: MessageId.makeUnsafe("msg-1"), + messageId: MessageId.make("msg-1"), role: "user", text: "hello", attachments: [], @@ -118,13 +118,11 @@ const messageSendCommand: OrchestrationCommand = { describe("commandInvariants", () => { it("finds threads by id and project", () => { - expect(findThreadById(readModel, ThreadId.makeUnsafe("thread-1"))?.projectId).toBe("project-a"); - expect(findThreadById(readModel, ThreadId.makeUnsafe("missing"))).toBeUndefined(); + expect(findThreadById(readModel, ThreadId.make("thread-1"))?.projectId).toBe("project-a"); + expect(findThreadById(readModel, ThreadId.make("missing"))).toBeUndefined(); expect( - listThreadsByProjectId(readModel, ProjectId.makeUnsafe("project-b")).map( - (thread) => thread.id, - ), - ).toEqual([ThreadId.makeUnsafe("thread-2")]); + listThreadsByProjectId(readModel, ProjectId.make("project-b")).map((thread) => thread.id), + ).toEqual([ThreadId.make("thread-2")]); }); it("requires existing thread", async () => { @@ -132,17 +130,17 @@ describe("commandInvariants", () => { requireThread({ readModel, command: messageSendCommand, - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), }), ); - expect(thread.id).toBe(ThreadId.makeUnsafe("thread-1")); + expect(thread.id).toBe(ThreadId.make("thread-1")); await expect( Effect.runPromise( requireThread({ readModel, command: messageSendCommand, - threadId: ThreadId.makeUnsafe("missing"), + threadId: ThreadId.make("missing"), }), ), ).rejects.toThrow("does not exist"); @@ -154,9 +152,9 @@ describe("commandInvariants", () => { readModel, command: { type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-2"), - threadId: ThreadId.makeUnsafe("thread-3"), - projectId: ProjectId.makeUnsafe("project-a"), + commandId: CommandId.make("cmd-2"), + threadId: ThreadId.make("thread-3"), + projectId: ProjectId.make("project-a"), title: "new", modelSelection: { provider: "codex", @@ -168,7 +166,7 @@ describe("commandInvariants", () => { worktreePath: null, createdAt: now, }, - threadId: ThreadId.makeUnsafe("thread-3"), + threadId: ThreadId.make("thread-3"), }), ); @@ -178,9 +176,9 @@ describe("commandInvariants", () => { readModel, command: { type: "thread.create", - commandId: CommandId.makeUnsafe("cmd-3"), - threadId: ThreadId.makeUnsafe("thread-1"), - projectId: ProjectId.makeUnsafe("project-a"), + commandId: CommandId.make("cmd-3"), + threadId: ThreadId.make("thread-1"), + projectId: ProjectId.make("project-a"), title: "dup", modelSelection: { provider: "codex", @@ -192,7 +190,7 @@ describe("commandInvariants", () => { worktreePath: null, createdAt: now, }, - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), }), ), ).rejects.toThrow("already exists"); diff --git a/apps/server/src/orchestration/decider.projectScripts.test.ts b/apps/server/src/orchestration/decider.projectScripts.test.ts index 465865549bcef4c2360c6c9709969977b21aae78..a85e21c53f3bda4802687395c1c5318923191068 100644 --- a/apps/server/src/orchestration/decider.projectScripts.test.ts +++ b/apps/server/src/orchestration/decider.projectScripts.test.ts @@ -12,9 +12,9 @@ import { Effect } from "effect"; import { decideOrchestrationCommand } from "./decider.ts"; import { createEmptyReadModel, projectEvent } from "./projector.ts"; -const asEventId = (value: string): EventId => EventId.makeUnsafe(value); -const asProjectId = (value: string): ProjectId => ProjectId.makeUnsafe(value); -const asMessageId = (value: string): MessageId => MessageId.makeUnsafe(value); +const asEventId = (value: string): EventId => EventId.make(value); +const asProjectId = (value: string): ProjectId => ProjectId.make(value); +const asMessageId = (value: string): MessageId => MessageId.make(value); describe("decider project scripts", () => { it("emits empty scripts on project.create", async () => { @@ -25,7 +25,7 @@ describe("decider project scripts", () => { decideOrchestrationCommand({ command: { type: "project.create", - commandId: CommandId.makeUnsafe("cmd-project-create-scripts"), + commandId: CommandId.make("cmd-project-create-scripts"), projectId: asProjectId("project-scripts"), title: "Scripts", workspaceRoot: "/tmp/scripts", @@ -51,9 +51,9 @@ describe("decider project scripts", () => { aggregateId: asProjectId("project-scripts"), type: "project.created", occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-project-create-scripts"), + commandId: CommandId.make("cmd-project-create-scripts"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-project-create-scripts"), + correlationId: CommandId.make("cmd-project-create-scripts"), metadata: {}, payload: { projectId: asProjectId("project-scripts"), @@ -81,7 +81,7 @@ describe("decider project scripts", () => { decideOrchestrationCommand({ command: { type: "project.meta.update", - commandId: CommandId.makeUnsafe("cmd-project-update-scripts"), + commandId: CommandId.make("cmd-project-update-scripts"), projectId: asProjectId("project-scripts"), scripts: Array.from(scripts), }, @@ -105,9 +105,9 @@ describe("decider project scripts", () => { aggregateId: asProjectId("project-1"), type: "project.created", occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-project-create"), + commandId: CommandId.make("cmd-project-create"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-project-create"), + correlationId: CommandId.make("cmd-project-create"), metadata: {}, payload: { projectId: asProjectId("project-1"), @@ -125,15 +125,15 @@ describe("decider project scripts", () => { sequence: 2, eventId: asEventId("evt-thread-create"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-1"), + aggregateId: ThreadId.make("thread-1"), type: "thread.created", occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-thread-create"), + commandId: CommandId.make("cmd-thread-create"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-thread-create"), + correlationId: CommandId.make("cmd-thread-create"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), projectId: asProjectId("project-1"), title: "Thread", modelSelection: { @@ -154,8 +154,8 @@ describe("decider project scripts", () => { decideOrchestrationCommand({ command: { type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-turn-start"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-turn-start"), + threadId: ThreadId.make("thread-1"), message: { messageId: asMessageId("message-user-1"), role: "user", @@ -189,7 +189,7 @@ describe("decider project scripts", () => { return; } expect(turnStartEvent.payload).toMatchObject({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), messageId: asMessageId("message-user-1"), modelSelection: { provider: "codex", @@ -214,9 +214,9 @@ describe("decider project scripts", () => { aggregateId: asProjectId("project-1"), type: "project.created", occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-project-create"), + commandId: CommandId.make("cmd-project-create"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-project-create"), + correlationId: CommandId.make("cmd-project-create"), metadata: {}, payload: { projectId: asProjectId("project-1"), @@ -234,15 +234,15 @@ describe("decider project scripts", () => { sequence: 2, eventId: asEventId("evt-thread-create"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-1"), + aggregateId: ThreadId.make("thread-1"), type: "thread.created", occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-thread-create"), + commandId: CommandId.make("cmd-thread-create"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-thread-create"), + correlationId: CommandId.make("cmd-thread-create"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), projectId: asProjectId("project-1"), title: "Thread", modelSelection: { @@ -263,8 +263,8 @@ describe("decider project scripts", () => { decideOrchestrationCommand({ command: { type: "thread.runtime-mode.set", - commandId: CommandId.makeUnsafe("cmd-runtime-mode-set"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-runtime-mode-set"), + threadId: ThreadId.make("thread-1"), runtimeMode: "approval-required", createdAt: now, }, @@ -279,7 +279,7 @@ describe("decider project scripts", () => { expect(singleResult).toMatchObject({ type: "thread.runtime-mode-set", payload: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), runtimeMode: "approval-required", }, }); @@ -296,9 +296,9 @@ describe("decider project scripts", () => { aggregateId: asProjectId("project-1"), type: "project.created", occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-project-create"), + commandId: CommandId.make("cmd-project-create"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-project-create"), + correlationId: CommandId.make("cmd-project-create"), metadata: {}, payload: { projectId: asProjectId("project-1"), @@ -316,15 +316,15 @@ describe("decider project scripts", () => { sequence: 2, eventId: asEventId("evt-thread-create"), aggregateKind: "thread", - aggregateId: ThreadId.makeUnsafe("thread-1"), + aggregateId: ThreadId.make("thread-1"), type: "thread.created", occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-thread-create"), + commandId: CommandId.make("cmd-thread-create"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-thread-create"), + correlationId: CommandId.make("cmd-thread-create"), metadata: {}, payload: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), projectId: asProjectId("project-1"), title: "Thread", modelSelection: { @@ -345,8 +345,8 @@ describe("decider project scripts", () => { decideOrchestrationCommand({ command: { type: "thread.interaction-mode.set", - commandId: CommandId.makeUnsafe("cmd-interaction-mode-set"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-interaction-mode-set"), + threadId: ThreadId.make("thread-1"), interactionMode: "plan", createdAt: now, }, @@ -361,7 +361,7 @@ describe("decider project scripts", () => { expect(singleResult).toMatchObject({ type: "thread.interaction-mode-set", payload: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), interactionMode: "plan", }, }); diff --git a/apps/server/src/orchestration/projector.test.ts b/apps/server/src/orchestration/projector.test.ts index 3dcdd19250ef9abdab39594a4e736fb24cb65d90..a61153bb529e5d20999641c4a0061583ebbc0d88 100644 --- a/apps/server/src/orchestration/projector.test.ts +++ b/apps/server/src/orchestration/projector.test.ts @@ -21,15 +21,15 @@ function makeEvent(input: { }): OrchestrationEvent { return { sequence: input.sequence, - eventId: EventId.makeUnsafe(`event-${input.sequence}`), + eventId: EventId.make(`event-${input.sequence}`), type: input.type, aggregateKind: input.aggregateKind, aggregateId: input.aggregateKind === "project" - ? ProjectId.makeUnsafe(input.aggregateId) - : ThreadId.makeUnsafe(input.aggregateId), + ? ProjectId.make(input.aggregateId) + : ThreadId.make(input.aggregateId), occurredAt: input.occurredAt, - commandId: input.commandId === null ? null : CommandId.makeUnsafe(input.commandId), + commandId: input.commandId === null ? null : CommandId.make(input.commandId), causationEventId: null, correlationId: null, metadata: {}, diff --git a/apps/server/src/persistence/Layers/OrchestrationEventStore.test.ts b/apps/server/src/persistence/Layers/OrchestrationEventStore.test.ts index 249e9d1e368da68ad73bcc0784e055c6f92dc5d7..80526986a70c94fc1c866f66aafaf337ddc94418 100644 --- a/apps/server/src/persistence/Layers/OrchestrationEventStore.test.ts +++ b/apps/server/src/persistence/Layers/OrchestrationEventStore.test.ts @@ -21,18 +21,18 @@ layer("OrchestrationEventStore", (it) => { const appended = yield* eventStore.append({ type: "project.created", - eventId: EventId.makeUnsafe("evt-store-roundtrip"), + eventId: EventId.make("evt-store-roundtrip"), aggregateKind: "project", - aggregateId: ProjectId.makeUnsafe("project-roundtrip"), + aggregateId: ProjectId.make("project-roundtrip"), occurredAt: now, - commandId: CommandId.makeUnsafe("cmd-store-roundtrip"), + commandId: CommandId.make("cmd-store-roundtrip"), causationEventId: null, - correlationId: CommandId.makeUnsafe("cmd-store-roundtrip"), + correlationId: CommandId.make("cmd-store-roundtrip"), metadata: { adapterKey: "codex", }, payload: { - projectId: ProjectId.makeUnsafe("project-roundtrip"), + projectId: ProjectId.make("project-roundtrip"), title: "Roundtrip Project", workspaceRoot: "/tmp/project-roundtrip", defaultModelSelection: null, @@ -87,13 +87,13 @@ layer("OrchestrationEventStore", (it) => { metadata_json ) VALUES ( - ${EventId.makeUnsafe("evt-store-invalid-json")}, + ${EventId.make("evt-store-invalid-json")}, ${"project"}, - ${ProjectId.makeUnsafe("project-invalid-json")}, + ${ProjectId.make("project-invalid-json")}, ${0}, ${"project.created"}, ${now}, - ${CommandId.makeUnsafe("cmd-store-invalid-json")}, + ${CommandId.make("cmd-store-invalid-json")}, ${null}, ${null}, ${"server"}, diff --git a/apps/server/src/persistence/Layers/ProjectionRepositories.test.ts b/apps/server/src/persistence/Layers/ProjectionRepositories.test.ts index b0e17748377a96d83597ddbdbbabd8eef5eaebe1..08bc2481226a2c4c53d80700becfb38a46946f38 100644 --- a/apps/server/src/persistence/Layers/ProjectionRepositories.test.ts +++ b/apps/server/src/persistence/Layers/ProjectionRepositories.test.ts @@ -24,7 +24,7 @@ projectionRepositoriesLayer("Projection repositories", (it) => { const sql = yield* SqlClient.SqlClient; yield* projects.upsert({ - projectId: ProjectId.makeUnsafe("project-null-options"), + projectId: ProjectId.make("project-null-options"), title: "Null options project", workspaceRoot: "/tmp/project-null-options", defaultModelSelection: { @@ -58,7 +58,7 @@ projectionRepositoriesLayer("Projection repositories", (it) => { ); const persisted = yield* projects.getById({ - projectId: ProjectId.makeUnsafe("project-null-options"), + projectId: ProjectId.make("project-null-options"), }); assert.deepStrictEqual(Option.getOrNull(persisted)?.defaultModelSelection, { provider: "codex", @@ -73,8 +73,8 @@ projectionRepositoriesLayer("Projection repositories", (it) => { const sql = yield* SqlClient.SqlClient; yield* threads.upsert({ - threadId: ThreadId.makeUnsafe("thread-null-options"), - projectId: ProjectId.makeUnsafe("project-null-options"), + threadId: ThreadId.make("thread-null-options"), + projectId: ProjectId.make("project-null-options"), title: "Null options thread", modelSelection: { provider: "claudeAgent", @@ -112,7 +112,7 @@ projectionRepositoriesLayer("Projection repositories", (it) => { ); const persisted = yield* threads.getById({ - threadId: ThreadId.makeUnsafe("thread-null-options"), + threadId: ThreadId.make("thread-null-options"), }); assert.deepStrictEqual(Option.getOrNull(persisted)?.modelSelection, { provider: "claudeAgent", diff --git a/apps/server/src/persistence/Layers/ProjectionThreadMessages.test.ts b/apps/server/src/persistence/Layers/ProjectionThreadMessages.test.ts index 5993ad6c20030b04f402e7769b85e2ef8965b753..8bbe723bf370fbe902cbabf2e2e5eb9435e15a65 100644 --- a/apps/server/src/persistence/Layers/ProjectionThreadMessages.test.ts +++ b/apps/server/src/persistence/Layers/ProjectionThreadMessages.test.ts @@ -14,8 +14,8 @@ layer("ProjectionThreadMessageRepository", (it) => { it.effect("preserves existing attachments when upsert omits attachments", () => Effect.gen(function* () { const repository = yield* ProjectionThreadMessageRepository; - const threadId = ThreadId.makeUnsafe("thread-preserve-attachments"); - const messageId = MessageId.makeUnsafe("message-preserve-attachments"); + const threadId = ThreadId.make("thread-preserve-attachments"); + const messageId = MessageId.make("message-preserve-attachments"); const createdAt = "2026-02-28T19:00:00.000Z"; const updatedAt = "2026-02-28T19:00:01.000Z"; const persistedAttachments = [ @@ -68,8 +68,8 @@ layer("ProjectionThreadMessageRepository", (it) => { it.effect("allows explicit attachment clearing with an empty array", () => Effect.gen(function* () { const repository = yield* ProjectionThreadMessageRepository; - const threadId = ThreadId.makeUnsafe("thread-clear-attachments"); - const messageId = MessageId.makeUnsafe("message-clear-attachments"); + const threadId = ThreadId.make("thread-clear-attachments"); + const messageId = MessageId.make("message-clear-attachments"); const createdAt = "2026-02-28T19:10:00.000Z"; yield* repository.upsert({ diff --git a/apps/server/src/persistence/NodeSqliteClient.ts b/apps/server/src/persistence/NodeSqliteClient.ts index 77c316e8ca7fb057d8d6531d5c7784c56a53275d..631df9c8b92cd6f58b0718c769ed7a26c16d05e2 100644 --- a/apps/server/src/persistence/NodeSqliteClient.ts +++ b/apps/server/src/persistence/NodeSqliteClient.ts @@ -15,7 +15,7 @@ import { identity } from "effect/Function"; import * as Layer from "effect/Layer"; import * as Scope from "effect/Scope"; import * as Semaphore from "effect/Semaphore"; -import * as ServiceMap from "effect/ServiceMap"; +import * as Context from "effect/Context"; import * as Stream from "effect/Stream"; import * as Reactivity from "effect/unstable/reactivity/Reactivity"; import * as Client from "effect/unstable/sql/SqlClient"; @@ -32,7 +32,7 @@ export type TypeId = "~local/sqlite-node/SqliteClient"; /** * SqliteClient - Effect service tag for the sqlite SQL client. */ -export const SqliteClient = ServiceMap.Service("t3/persistence/NodeSqliteClient"); +export const SqliteClient = Context.Service("t3/persistence/NodeSqliteClient"); export interface SqliteClientConfig { readonly filename: string; @@ -120,7 +120,7 @@ const makeWithDatabase = Effect.fn("makeWithDatabase")(function* ( const runStatement = (statement: StatementSync, params: ReadonlyArray, raw: boolean) => Effect.withFiber, SqlError>((fiber) => { - statement.setReadBigInts(Boolean(ServiceMap.get(fiber.services, Client.SafeIntegers))); + statement.setReadBigInts(Boolean(Context.get(fiber.context, Client.SafeIntegers))); try { if (hasRows(statement)) { return Effect.succeed(statement.all(...(params as any))); @@ -200,7 +200,7 @@ const makeWithDatabase = Effect.fn("makeWithDatabase")(function* ( const acquirer = semaphore.withPermits(1)(Effect.succeed(connection)); const transactionAcquirer = Effect.uninterruptibleMask((restore) => { const fiber = Fiber.getCurrent()!; - const scope = ServiceMap.getUnsafe(fiber.services, Scope.Scope); + const scope = Context.getUnsafe(fiber.context, Scope.Scope); return Effect.as( Effect.tap(restore(semaphore.take(1)), () => Scope.addFinalizer(scope, semaphore.release(1))), connection, @@ -251,27 +251,27 @@ const makeMemory = ( export const layerConfig = ( config: Config.Wrap, ): Layer.Layer => - Layer.effectServices( + Layer.effectContext( Config.unwrap(config) .asEffect() .pipe( Effect.flatMap(make), Effect.map((client) => - ServiceMap.make(SqliteClient, client).pipe(ServiceMap.add(Client.SqlClient, client)), + Context.make(SqliteClient, client).pipe(Context.add(Client.SqlClient, client)), ), ), ).pipe(Layer.provide(Reactivity.layer)); export const layer = (config: SqliteClientConfig): Layer.Layer => - Layer.effectServices( + Layer.effectContext( Effect.map(make(config), (client) => - ServiceMap.make(SqliteClient, client).pipe(ServiceMap.add(Client.SqlClient, client)), + Context.make(SqliteClient, client).pipe(Context.add(Client.SqlClient, client)), ), ).pipe(Layer.provide(Reactivity.layer)); export const layerMemory = (config: SqliteMemoryClientConfig = {}): Layer.Layer => - Layer.effectServices( + Layer.effectContext( Effect.map(makeMemory(config), (client) => - ServiceMap.make(SqliteClient, client).pipe(ServiceMap.add(Client.SqlClient, client)), + Context.make(SqliteClient, client).pipe(Context.add(Client.SqlClient, client)), ), ).pipe(Layer.provide(Reactivity.layer)); diff --git a/apps/server/src/persistence/Services/AuthPairingLinks.ts b/apps/server/src/persistence/Services/AuthPairingLinks.ts index 76c14a6586486e1eb26b07911756dea97bf81f8a..d03e67cbb5b3db3af13a813a9b9eefe00d3e546b 100644 --- a/apps/server/src/persistence/Services/AuthPairingLinks.ts +++ b/apps/server/src/persistence/Services/AuthPairingLinks.ts @@ -1,4 +1,4 @@ -import { Option, Schema, ServiceMap } from "effect"; +import { Option, Schema, Context } from "effect"; import type { Effect } from "effect"; import type { AuthPairingLinkRepositoryError } from "../Errors.ts"; @@ -70,7 +70,7 @@ export interface AuthPairingLinkRepositoryShape { ) => Effect.Effect, AuthPairingLinkRepositoryError>; } -export class AuthPairingLinkRepository extends ServiceMap.Service< +export class AuthPairingLinkRepository extends Context.Service< AuthPairingLinkRepository, AuthPairingLinkRepositoryShape >()("t3/persistence/Services/AuthPairingLinks/AuthPairingLinkRepository") {} diff --git a/apps/server/src/persistence/Services/AuthSessions.ts b/apps/server/src/persistence/Services/AuthSessions.ts index a4410fa379ca26b7134f341d10a78abe555d9914..567d3cca5c18bc94fccbb28aa35686f40aee6a6d 100644 --- a/apps/server/src/persistence/Services/AuthSessions.ts +++ b/apps/server/src/persistence/Services/AuthSessions.ts @@ -1,5 +1,5 @@ import { AuthClientMetadataDeviceType, AuthSessionId } from "@t3tools/contracts"; -import { Option, Schema, ServiceMap } from "effect"; +import { Option, Schema, Context } from "effect"; import type { Effect } from "effect"; import type { AuthSessionRepositoryError } from "../Errors.ts"; @@ -87,7 +87,7 @@ export interface AuthSessionRepositoryShape { ) => Effect.Effect; } -export class AuthSessionRepository extends ServiceMap.Service< +export class AuthSessionRepository extends Context.Service< AuthSessionRepository, AuthSessionRepositoryShape >()("t3/persistence/Services/AuthSessions/AuthSessionRepository") {} diff --git a/apps/server/src/persistence/Services/OrchestrationCommandReceipts.ts b/apps/server/src/persistence/Services/OrchestrationCommandReceipts.ts index 0b8f8e9b5261e5f0a80a3c9a53b66ccd2225bcae..da8755ae71cf8d786ac8c4020f0bbd62ca787124 100644 --- a/apps/server/src/persistence/Services/OrchestrationCommandReceipts.ts +++ b/apps/server/src/persistence/Services/OrchestrationCommandReceipts.ts @@ -15,7 +15,7 @@ import { ProjectId, ThreadId, } from "@t3tools/contracts"; -import { Option, Schema, ServiceMap } from "effect"; +import { Option, Schema, Context } from "effect"; import type { Effect } from "effect"; import type { OrchestrationCommandReceiptRepositoryError } from "../Errors.ts"; @@ -63,7 +63,7 @@ export interface OrchestrationCommandReceiptRepositoryShape { /** * OrchestrationCommandReceiptRepository - Service tag for command receipt persistence. */ -export class OrchestrationCommandReceiptRepository extends ServiceMap.Service< +export class OrchestrationCommandReceiptRepository extends Context.Service< OrchestrationCommandReceiptRepository, OrchestrationCommandReceiptRepositoryShape >()("t3/persistence/Services/OrchestrationCommandReceipts/OrchestrationCommandReceiptRepository") {} diff --git a/apps/server/src/persistence/Services/OrchestrationEventStore.ts b/apps/server/src/persistence/Services/OrchestrationEventStore.ts index 24febd8fded8dc0360258871c02edac968529e9f..beecdcdc65668ce672eca13d37f69acc98e9005f 100644 --- a/apps/server/src/persistence/Services/OrchestrationEventStore.ts +++ b/apps/server/src/persistence/Services/OrchestrationEventStore.ts @@ -4,13 +4,13 @@ * Owns durable append/replay access to the orchestration event stream. It does * not reduce events into read models or apply command validation rules. * - * Uses Effect `ServiceMap.Service` for dependency injection and exposes typed + * Uses Effect `Context.Service` for dependency injection and exposes typed * persistence/decode errors for event append and replay operations. * * @module OrchestrationEventStore */ import { OrchestrationEvent } from "@t3tools/contracts"; -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect, Stream } from "effect"; import type { OrchestrationEventStoreError } from "../Errors.ts"; @@ -64,7 +64,7 @@ export interface OrchestrationEventStoreShape { * }) * ``` */ -export class OrchestrationEventStore extends ServiceMap.Service< +export class OrchestrationEventStore extends Context.Service< OrchestrationEventStore, OrchestrationEventStoreShape >()("t3/persistence/Services/OrchestrationEventStore") {} diff --git a/apps/server/src/persistence/Services/ProjectionCheckpoints.ts b/apps/server/src/persistence/Services/ProjectionCheckpoints.ts index 191d0af968495b2d09c16c8fe7ac80cf96d95722..617f964f333a132fd31972622d6d6fd64240a24e 100644 --- a/apps/server/src/persistence/Services/ProjectionCheckpoints.ts +++ b/apps/server/src/persistence/Services/ProjectionCheckpoints.ts @@ -16,7 +16,7 @@ import { ThreadId, TurnId, } from "@t3tools/contracts"; -import { Option, ServiceMap, Schema } from "effect"; +import { Option, Context, Schema } from "effect"; import type { Effect } from "effect"; import type { ProjectionRepositoryError } from "../Errors.ts"; @@ -87,7 +87,7 @@ export interface ProjectionCheckpointRepositoryShape { /** * ProjectionCheckpointRepository - Service tag for checkpoint projection persistence. */ -export class ProjectionCheckpointRepository extends ServiceMap.Service< +export class ProjectionCheckpointRepository extends Context.Service< ProjectionCheckpointRepository, ProjectionCheckpointRepositoryShape >()("t3/persistence/Services/ProjectionCheckpoints/ProjectionCheckpointRepository") {} diff --git a/apps/server/src/persistence/Services/ProjectionPendingApprovals.ts b/apps/server/src/persistence/Services/ProjectionPendingApprovals.ts index 8f4ec5eb4b1a44f6768a96b13a303fd1a95b717e..82c43c0bb0376bdfbb7919af558d5357553210a9 100644 --- a/apps/server/src/persistence/Services/ProjectionPendingApprovals.ts +++ b/apps/server/src/persistence/Services/ProjectionPendingApprovals.ts @@ -14,7 +14,7 @@ import { ThreadId, TurnId, } from "@t3tools/contracts"; -import { Option, Schema, ServiceMap } from "effect"; +import { Option, Schema, Context } from "effect"; import type { Effect } from "effect"; import type { ProjectionRepositoryError } from "../Errors.ts"; @@ -85,7 +85,7 @@ export interface ProjectionPendingApprovalRepositoryShape { /** * ProjectionPendingApprovalRepository - Service tag for pending approval persistence. */ -export class ProjectionPendingApprovalRepository extends ServiceMap.Service< +export class ProjectionPendingApprovalRepository extends Context.Service< ProjectionPendingApprovalRepository, ProjectionPendingApprovalRepositoryShape >()("t3/persistence/Services/ProjectionPendingApprovals/ProjectionPendingApprovalRepository") {} diff --git a/apps/server/src/persistence/Services/ProjectionProjects.ts b/apps/server/src/persistence/Services/ProjectionProjects.ts index 996ffe6e7bbc77dd6ede2765f67fc85197751911..0970bb2ead4ce2529ef3f5f3c7b02e65b7ab1a35 100644 --- a/apps/server/src/persistence/Services/ProjectionProjects.ts +++ b/apps/server/src/persistence/Services/ProjectionProjects.ts @@ -7,7 +7,7 @@ * @module ProjectionProjectRepository */ import { IsoDateTime, ModelSelection, ProjectId, ProjectScript } from "@t3tools/contracts"; -import { Option, Schema, ServiceMap } from "effect"; +import { Option, Schema, Context } from "effect"; import type { Effect } from "effect"; import type { ProjectionRepositoryError } from "../Errors.ts"; @@ -73,7 +73,7 @@ export interface ProjectionProjectRepositoryShape { /** * ProjectionProjectRepository - Service tag for project projection persistence. */ -export class ProjectionProjectRepository extends ServiceMap.Service< +export class ProjectionProjectRepository extends Context.Service< ProjectionProjectRepository, ProjectionProjectRepositoryShape >()("t3/persistence/Services/ProjectionProjects/ProjectionProjectRepository") {} diff --git a/apps/server/src/persistence/Services/ProjectionState.ts b/apps/server/src/persistence/Services/ProjectionState.ts index e8ef9ceeb0b1c0b87742468d37bb273f351052b5..0b75b817d25d93e15a7f012a9485514ec9813251 100644 --- a/apps/server/src/persistence/Services/ProjectionState.ts +++ b/apps/server/src/persistence/Services/ProjectionState.ts @@ -7,7 +7,7 @@ * @module ProjectionStateRepository */ import { IsoDateTime, NonNegativeInt } from "@t3tools/contracts"; -import { Option, Schema, ServiceMap } from "effect"; +import { Option, Schema, Context } from "effect"; import type { Effect } from "effect"; import type { ProjectionRepositoryError } from "../Errors.ts"; @@ -58,7 +58,7 @@ export interface ProjectionStateRepositoryShape { /** * ProjectionStateRepository - Service tag for projection cursor persistence. */ -export class ProjectionStateRepository extends ServiceMap.Service< +export class ProjectionStateRepository extends Context.Service< ProjectionStateRepository, ProjectionStateRepositoryShape >()("t3/persistence/Services/ProjectionState/ProjectionStateRepository") {} diff --git a/apps/server/src/persistence/Services/ProjectionThreadActivities.ts b/apps/server/src/persistence/Services/ProjectionThreadActivities.ts index 586ae3eb4a8499e81fd0458003f3392791334836..87daa3c636b514e5668d3f74205f4959054d4962 100644 --- a/apps/server/src/persistence/Services/ProjectionThreadActivities.ts +++ b/apps/server/src/persistence/Services/ProjectionThreadActivities.ts @@ -14,7 +14,7 @@ import { ThreadId, TurnId, } from "@t3tools/contracts"; -import { Schema, ServiceMap } from "effect"; +import { Schema, Context } from "effect"; import type { Effect } from "effect"; import type { ProjectionRepositoryError } from "../Errors.ts"; @@ -77,7 +77,7 @@ export interface ProjectionThreadActivityRepositoryShape { /** * ProjectionThreadActivityRepository - Service tag for thread activity persistence. */ -export class ProjectionThreadActivityRepository extends ServiceMap.Service< +export class ProjectionThreadActivityRepository extends Context.Service< ProjectionThreadActivityRepository, ProjectionThreadActivityRepositoryShape >()("t3/persistence/Services/ProjectionThreadActivities/ProjectionThreadActivityRepository") {} diff --git a/apps/server/src/persistence/Services/ProjectionThreadMessages.ts b/apps/server/src/persistence/Services/ProjectionThreadMessages.ts index b1a769cd9177ed8330b7d40586fa3e7a5cb44633..56f8f92dbfe762cb71384e86b624a54d8bdcdb25 100644 --- a/apps/server/src/persistence/Services/ProjectionThreadMessages.ts +++ b/apps/server/src/persistence/Services/ProjectionThreadMessages.ts @@ -14,7 +14,7 @@ import { TurnId, IsoDateTime, } from "@t3tools/contracts"; -import { Schema, ServiceMap } from "effect"; +import { Schema, Context } from "effect"; import type { Option } from "effect"; import type { Effect } from "effect"; @@ -88,7 +88,7 @@ export interface ProjectionThreadMessageRepositoryShape { /** * ProjectionThreadMessageRepository - Service tag for message projection persistence. */ -export class ProjectionThreadMessageRepository extends ServiceMap.Service< +export class ProjectionThreadMessageRepository extends Context.Service< ProjectionThreadMessageRepository, ProjectionThreadMessageRepositoryShape >()("t3/persistence/Services/ProjectionThreadMessages/ProjectionThreadMessageRepository") {} diff --git a/apps/server/src/persistence/Services/ProjectionThreadProposedPlans.ts b/apps/server/src/persistence/Services/ProjectionThreadProposedPlans.ts index d141a11bb9d4a22b7e1fb0e25b1c1562ec81254a..a68bedb8c37605980a82309099fff5d35d5e8ef4 100644 --- a/apps/server/src/persistence/Services/ProjectionThreadProposedPlans.ts +++ b/apps/server/src/persistence/Services/ProjectionThreadProposedPlans.ts @@ -5,7 +5,7 @@ import { TrimmedNonEmptyString, TurnId, } from "@t3tools/contracts"; -import { Schema, ServiceMap } from "effect"; +import { Schema, Context } from "effect"; import type { Effect } from "effect"; import type { ProjectionRepositoryError } from "../Errors.ts"; @@ -46,7 +46,7 @@ export interface ProjectionThreadProposedPlanRepositoryShape { ) => Effect.Effect; } -export class ProjectionThreadProposedPlanRepository extends ServiceMap.Service< +export class ProjectionThreadProposedPlanRepository extends Context.Service< ProjectionThreadProposedPlanRepository, ProjectionThreadProposedPlanRepositoryShape >()( diff --git a/apps/server/src/persistence/Services/ProjectionThreadSessions.ts b/apps/server/src/persistence/Services/ProjectionThreadSessions.ts index 537ee10beef65cc1d29088647a2ff7a437e6abf8..fcd13f068da84ac50227a9011dadae282f084c9b 100644 --- a/apps/server/src/persistence/Services/ProjectionThreadSessions.ts +++ b/apps/server/src/persistence/Services/ProjectionThreadSessions.ts @@ -13,7 +13,7 @@ import { ThreadId, TurnId, } from "@t3tools/contracts"; -import { Option, Schema, ServiceMap } from "effect"; +import { Option, Schema, Context } from "effect"; import type { Effect } from "effect"; import type { ProjectionRepositoryError } from "../Errors.ts"; @@ -68,7 +68,7 @@ export interface ProjectionThreadSessionRepositoryShape { /** * ProjectionThreadSessionRepository - Service tag for thread-session persistence. */ -export class ProjectionThreadSessionRepository extends ServiceMap.Service< +export class ProjectionThreadSessionRepository extends Context.Service< ProjectionThreadSessionRepository, ProjectionThreadSessionRepositoryShape >()("t3/persistence/Services/ProjectionThreadSessions/ProjectionThreadSessionRepository") {} diff --git a/apps/server/src/persistence/Services/ProjectionThreads.ts b/apps/server/src/persistence/Services/ProjectionThreads.ts index 59505c125368f2fdeea2cb6cc1278e8eb655cf30..31ec00a6e5e7f574ed081296dececaa7186d4d94 100644 --- a/apps/server/src/persistence/Services/ProjectionThreads.ts +++ b/apps/server/src/persistence/Services/ProjectionThreads.ts @@ -15,7 +15,7 @@ import { ThreadId, TurnId, } from "@t3tools/contracts"; -import { Option, Schema, ServiceMap } from "effect"; +import { Option, Schema, Context } from "effect"; import type { Effect } from "effect"; import type { ProjectionRepositoryError } from "../Errors.ts"; @@ -90,7 +90,7 @@ export interface ProjectionThreadRepositoryShape { /** * ProjectionThreadRepository - Service tag for thread projection persistence. */ -export class ProjectionThreadRepository extends ServiceMap.Service< +export class ProjectionThreadRepository extends Context.Service< ProjectionThreadRepository, ProjectionThreadRepositoryShape >()("t3/persistence/Services/ProjectionThreads/ProjectionThreadRepository") {} diff --git a/apps/server/src/persistence/Services/ProjectionTurns.ts b/apps/server/src/persistence/Services/ProjectionTurns.ts index 95dab450bf910f41d06888b83b93262b039fd87c..8e37ae09bd91cdffb14d5ab140d0371a445b1e58 100644 --- a/apps/server/src/persistence/Services/ProjectionTurns.ts +++ b/apps/server/src/persistence/Services/ProjectionTurns.ts @@ -17,7 +17,7 @@ import { ThreadId, TurnId, } from "@t3tools/contracts"; -import { Option, Schema, ServiceMap } from "effect"; +import { Option, Schema, Context } from "effect"; import type { Effect } from "effect"; import type { ProjectionRepositoryError } from "../Errors.ts"; @@ -162,7 +162,7 @@ export interface ProjectionTurnRepositoryShape { ) => Effect.Effect; } -export class ProjectionTurnRepository extends ServiceMap.Service< +export class ProjectionTurnRepository extends Context.Service< ProjectionTurnRepository, ProjectionTurnRepositoryShape >()("t3/persistence/Services/ProjectionTurns/ProjectionTurnRepository") {} diff --git a/apps/server/src/persistence/Services/ProviderSessionRuntime.ts b/apps/server/src/persistence/Services/ProviderSessionRuntime.ts index 885a9dd5f1b97991a0b015f68f72a3b9ea7b095a..bf8e658e8a665e9e3034337bdb84478f5a8288fd 100644 --- a/apps/server/src/persistence/Services/ProviderSessionRuntime.ts +++ b/apps/server/src/persistence/Services/ProviderSessionRuntime.ts @@ -11,7 +11,7 @@ import { RuntimeMode, ThreadId, } from "@t3tools/contracts"; -import { Option, Schema, ServiceMap } from "effect"; +import { Option, Schema, Context } from "effect"; import type { Effect } from "effect"; import type { ProviderSessionRuntimeRepositoryError } from "../Errors.ts"; @@ -75,7 +75,7 @@ export interface ProviderSessionRuntimeRepositoryShape { /** * ProviderSessionRuntimeRepository - Service tag for provider runtime persistence. */ -export class ProviderSessionRuntimeRepository extends ServiceMap.Service< +export class ProviderSessionRuntimeRepository extends Context.Service< ProviderSessionRuntimeRepository, ProviderSessionRuntimeRepositoryShape >()("t3/persistence/Services/ProviderSessionRuntime/ProviderSessionRuntimeRepository") {} diff --git a/apps/server/src/project/Layers/RepositoryIdentityResolver.ts b/apps/server/src/project/Layers/RepositoryIdentityResolver.ts index 4e33f5c16291fb3635d1078221bf50a29cb4c3de..531737ec66c40e33d960d55a7a8f12d1c9fa5653 100644 --- a/apps/server/src/project/Layers/RepositoryIdentityResolver.ts +++ b/apps/server/src/project/Layers/RepositoryIdentityResolver.ts @@ -116,17 +116,19 @@ async function resolveRepositoryIdentityFromCacheKey( export const makeRepositoryIdentityResolver = Effect.fn("makeRepositoryIdentityResolver")( function* (options: RepositoryIdentityResolverOptions = {}) { - const repositoryIdentityCache = yield* Cache.makeWith({ - capacity: options.cacheCapacity ?? DEFAULT_REPOSITORY_IDENTITY_CACHE_CAPACITY, - lookup: (cacheKey) => Effect.promise(() => resolveRepositoryIdentityFromCacheKey(cacheKey)), - timeToLive: Exit.match({ - onSuccess: (value) => - value === null - ? (options.negativeCacheTtl ?? DEFAULT_NEGATIVE_CACHE_TTL) - : (options.positiveCacheTtl ?? DEFAULT_POSITIVE_CACHE_TTL), - onFailure: () => Duration.zero, - }), - }); + const repositoryIdentityCache = yield* Cache.makeWith( + (cacheKey) => Effect.promise(() => resolveRepositoryIdentityFromCacheKey(cacheKey)), + { + capacity: options.cacheCapacity ?? DEFAULT_REPOSITORY_IDENTITY_CACHE_CAPACITY, + timeToLive: Exit.match({ + onSuccess: (value) => + value === null + ? (options.negativeCacheTtl ?? DEFAULT_NEGATIVE_CACHE_TTL) + : (options.positiveCacheTtl ?? DEFAULT_POSITIVE_CACHE_TTL), + onFailure: () => Duration.zero, + }), + }, + ); const resolve: RepositoryIdentityResolverShape["resolve"] = Effect.fn( "RepositoryIdentityResolver.resolve", diff --git a/apps/server/src/project/Services/ProjectFaviconResolver.ts b/apps/server/src/project/Services/ProjectFaviconResolver.ts index f6a8e22c0d8c0179b054c6cbae4da2605cd4f4e0..c05dfe8f1fdca41115ccda2e957d80e445c2d5d7 100644 --- a/apps/server/src/project/Services/ProjectFaviconResolver.ts +++ b/apps/server/src/project/Services/ProjectFaviconResolver.ts @@ -6,7 +6,7 @@ * * @module ProjectFaviconResolver */ -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect } from "effect"; /** @@ -24,7 +24,7 @@ export interface ProjectFaviconResolverShape { /** * ProjectFaviconResolver - Service tag for project favicon resolution. */ -export class ProjectFaviconResolver extends ServiceMap.Service< +export class ProjectFaviconResolver extends Context.Service< ProjectFaviconResolver, ProjectFaviconResolverShape >()("t3/project/Services/ProjectFaviconResolver") {} diff --git a/apps/server/src/project/Services/ProjectSetupScriptRunner.ts b/apps/server/src/project/Services/ProjectSetupScriptRunner.ts index 3828096f8519b9bb6f21e6a4bfd6710db6e96ff5..acba335a6e7d2a4a5e1289b3cbd7864c1f833f12 100644 --- a/apps/server/src/project/Services/ProjectSetupScriptRunner.ts +++ b/apps/server/src/project/Services/ProjectSetupScriptRunner.ts @@ -1,4 +1,4 @@ -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect } from "effect"; export interface ProjectSetupScriptRunnerResultNoScript { @@ -31,7 +31,7 @@ export interface ProjectSetupScriptRunnerShape { ) => Effect.Effect; } -export class ProjectSetupScriptRunner extends ServiceMap.Service< +export class ProjectSetupScriptRunner extends Context.Service< ProjectSetupScriptRunner, ProjectSetupScriptRunnerShape >()("t3/project/ProjectSetupScriptRunner") {} diff --git a/apps/server/src/project/Services/RepositoryIdentityResolver.ts b/apps/server/src/project/Services/RepositoryIdentityResolver.ts index 2847cbca1133de1701e38ca78d5b0135b0b6a617..d3eea846199931734fb8d8f096dc7dae21d13bd4 100644 --- a/apps/server/src/project/Services/RepositoryIdentityResolver.ts +++ b/apps/server/src/project/Services/RepositoryIdentityResolver.ts @@ -1,12 +1,12 @@ import type { RepositoryIdentity } from "@t3tools/contracts"; -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect } from "effect"; export interface RepositoryIdentityResolverShape { readonly resolve: (cwd: string) => Effect.Effect; } -export class RepositoryIdentityResolver extends ServiceMap.Service< +export class RepositoryIdentityResolver extends Context.Service< RepositoryIdentityResolver, RepositoryIdentityResolverShape >()("t3/project/Services/RepositoryIdentityResolver") {} diff --git a/apps/server/src/provider/Layers/ClaudeAdapter.test.ts b/apps/server/src/provider/Layers/ClaudeAdapter.test.ts index fdc6b5d789060ba4c28c6e7020b671a22f5bb61f..5c45013f8daa12651fc8c173828f0221e7f9d576 100644 --- a/apps/server/src/provider/Layers/ClaudeAdapter.test.ts +++ b/apps/server/src/provider/Layers/ClaudeAdapter.test.ts @@ -237,8 +237,8 @@ async function readFirstPromptMessage( return next.value; } -const THREAD_ID = ThreadId.makeUnsafe("thread-claude-1"); -const RESUME_THREAD_ID = ThreadId.makeUnsafe("thread-claude-resume"); +const THREAD_ID = ThreadId.make("thread-claude-1"); +const RESUME_THREAD_ID = ThreadId.make("thread-claude-resume"); describe("ClaudeAdapterLive", () => { it.effect("returns validation error for non-claude provider on startSession", () => { @@ -1104,8 +1104,8 @@ describe("ClaudeAdapterLive", () => { it.effect("closes the session when the Claude stream aborts after a turn starts", () => { const harness = makeHarness(); return Effect.gen(function* () { - const services = yield* Effect.services(); - const runFork = Effect.runForkWith(services); + const context = yield* Effect.context(); + const runFork = Effect.runForkWith(context); const adapter = yield* ClaudeAdapter; const runtimeEvents: Array = []; @@ -1204,8 +1204,8 @@ describe("ClaudeAdapterLive", () => { ); return Effect.gen(function* () { - const services = yield* Effect.services(); - const runFork = Effect.runForkWith(services); + const context = yield* Effect.context(); + const runFork = Effect.runForkWith(context); const adapter = yield* ClaudeAdapter; @@ -2108,7 +2108,7 @@ describe("ClaudeAdapterLive", () => { return; } assert.deepEqual(requested.value.providerRefs, { - providerItemId: ProviderItemId.makeUnsafe("tool-use-1"), + providerItemId: ProviderItemId.make("tool-use-1"), }); const runtimeRequestId = requested.value.requestId; assert.equal(typeof runtimeRequestId, "string"); @@ -2118,7 +2118,7 @@ describe("ClaudeAdapterLive", () => { yield* adapter.respondToRequest( session.threadId, - ApprovalRequestId.makeUnsafe(runtimeRequestId), + ApprovalRequestId.make(runtimeRequestId), "accept", ); @@ -2134,7 +2134,7 @@ describe("ClaudeAdapterLive", () => { assert.equal(resolved.value.requestId, requested.value.requestId); assert.equal(resolved.value.payload.decision, "accept"); assert.deepEqual(resolved.value.providerRefs, { - providerItemId: ProviderItemId.makeUnsafe("tool-use-1"), + providerItemId: ProviderItemId.make("tool-use-1"), }); const permissionResult = yield* Effect.promise(() => permissionPromise); @@ -2183,7 +2183,7 @@ describe("ClaudeAdapterLive", () => { yield* adapter.respondToRequest( session.threadId, - ApprovalRequestId.makeUnsafe(String(agentRequested.value.requestId)), + ApprovalRequestId.make(String(agentRequested.value.requestId)), "accept", ); yield* Stream.runHead(adapter.streamEvents); @@ -2207,7 +2207,7 @@ describe("ClaudeAdapterLive", () => { yield* adapter.respondToRequest( session.threadId, - ApprovalRequestId.makeUnsafe(String(grepRequested.value.requestId)), + ApprovalRequestId.make(String(grepRequested.value.requestId)), "accept", ); yield* Stream.runHead(adapter.streamEvents); @@ -2629,7 +2629,7 @@ describe("ClaudeAdapterLive", () => { } assert.equal(proposedEvent.value.payload.planMarkdown, "# Ship it\n\n- one\n- two"); assert.deepEqual(proposedEvent.value.providerRefs, { - providerItemId: ProviderItemId.makeUnsafe("tool-exit-1"), + providerItemId: ProviderItemId.make("tool-exit-1"), }); const permissionResult = yield* Effect.promise(() => permissionPromise); @@ -2707,7 +2707,7 @@ describe("ClaudeAdapterLive", () => { } assert.equal(proposedEvent.value.payload.planMarkdown, "# Final plan\n\n- capture it"); assert.deepEqual(proposedEvent.value.providerRefs, { - providerItemId: ProviderItemId.makeUnsafe("tool-exit-2"), + providerItemId: ProviderItemId.make("tool-exit-2"), }); }).pipe( Effect.provideService(Random.Random, makeDeterministicRandomService()), @@ -2798,15 +2798,13 @@ describe("ClaudeAdapterLive", () => { assert.equal(requestedEvent.value.payload.questions.length, 1); assert.equal(requestedEvent.value.payload.questions[0]?.question, "Which framework?"); assert.deepEqual(requestedEvent.value.providerRefs, { - providerItemId: ProviderItemId.makeUnsafe("tool-ask-1"), + providerItemId: ProviderItemId.make("tool-ask-1"), }); // Respond with the user's answers. - yield* adapter.respondToUserInput( - session.threadId, - ApprovalRequestId.makeUnsafe(requestId!), - { "Which framework?": "React" }, - ); + yield* adapter.respondToUserInput(session.threadId, ApprovalRequestId.make(requestId!), { + "Which framework?": "React", + }); // The adapter should emit a user-input.resolved event. const resolvedEvent = yield* Stream.runHead(adapter.streamEvents); @@ -2822,7 +2820,7 @@ describe("ClaudeAdapterLive", () => { "Which framework?": "React", }); assert.deepEqual(resolvedEvent.value.providerRefs, { - providerItemId: ProviderItemId.makeUnsafe("tool-ask-1"), + providerItemId: ProviderItemId.make("tool-ask-1"), }); // The canUseTool promise should resolve with the answers in SDK format. @@ -2889,11 +2887,9 @@ describe("ClaudeAdapterLive", () => { } const requestId = requestedEvent.value.requestId; - yield* adapter.respondToUserInput( - session.threadId, - ApprovalRequestId.makeUnsafe(requestId!), - { "Deploy to which env?": "Staging" }, - ); + yield* adapter.respondToUserInput(session.threadId, ApprovalRequestId.make(requestId!), { + "Deploy to which env?": "Staging", + }); // Drain the resolved event. yield* Stream.runHead(adapter.streamEvents); diff --git a/apps/server/src/provider/Layers/ClaudeAdapter.ts b/apps/server/src/provider/Layers/ClaudeAdapter.ts index 94f8ba0c907a4e5ca2eec015abc03991f86b2b87..fb32da78c5e83ef3bd6b3f1bfb38eb4b6465a03c 100644 --- a/apps/server/src/provider/Layers/ClaudeAdapter.ts +++ b/apps/server/src/provider/Layers/ClaudeAdapter.ts @@ -269,7 +269,7 @@ function isInterruptedResult(result: SDKResultMessage): boolean { } function asRuntimeItemId(value: string): RuntimeItemId { - return RuntimeItemId.makeUnsafe(value); + return RuntimeItemId.make(value); } function maxClaudeContextWindowFromModelUsage(modelUsage: unknown): number | undefined { @@ -353,7 +353,7 @@ function asCanonicalTurnId(value: TurnId): TurnId { } function asRuntimeRequestId(value: ApprovalRequestId): RuntimeRequestId { - return RuntimeRequestId.makeUnsafe(value); + return RuntimeRequestId.make(value); } function readClaudeResumeState(resumeCursor: unknown): ClaudeResumeState | undefined { @@ -371,7 +371,7 @@ function readClaudeResumeState(resumeCursor: unknown): ClaudeResumeState | undef const threadIdCandidate = typeof cursor.threadId === "string" ? cursor.threadId : undefined; const threadId = threadIdCandidate && !isSyntheticClaudeThreadId(threadIdCandidate) - ? ThreadId.makeUnsafe(threadIdCandidate) + ? ThreadId.make(threadIdCandidate) : undefined; const resumeCandidate = typeof cursor.resume === "string" @@ -641,7 +641,7 @@ function nativeProviderRefs( ): NonNullable { if (options?.providerItemId) { return { - providerItemId: ProviderItemId.makeUnsafe(options.providerItemId), + providerItemId: ProviderItemId.make(options.providerItemId), }; } return {}; @@ -934,7 +934,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( const serverSettingsService = yield* ServerSettingsService; const nowIso = Effect.map(DateTime.now, DateTime.formatIso); - const nextEventId = Effect.map(Random.nextUUIDv4, (id) => EventId.makeUnsafe(id)); + const nextEventId = Effect.map(Random.nextUUIDv4, (id) => EventId.make(id)); const makeEventStamp = () => Effect.all({ eventId: nextEventId, createdAt: nowIso }); const offerRuntimeEvent = (event: ProviderRuntimeEvent): Effect.Effect => @@ -967,7 +967,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( ? { providerThreadId: message.session_id } : {}), ...(context.turnState ? { turnId: asCanonicalTurnId(context.turnState.turnId) } : {}), - ...(itemId ? { itemId: ProviderItemId.makeUnsafe(itemId) } : {}), + ...(itemId ? { itemId: ProviderItemId.make(itemId) } : {}), payload: message, }, }, @@ -1822,7 +1822,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( // Auto-start a synthetic turn for assistant messages that arrive without // an active turn (e.g., background agent/subagent responses between user prompts). if (!context.turnState) { - const turnId = TurnId.makeUnsafe(yield* Random.nextUUIDv4); + const turnId = TurnId.make(yield* Random.nextUUIDv4); const startedAt = yield* nowIso; context.turnState = { turnId, @@ -2013,7 +2013,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( ...base, type: "task.started", payload: { - taskId: RuntimeTaskId.makeUnsafe(message.task_id), + taskId: RuntimeTaskId.make(message.task_id), description: message.description, ...(message.task_type ? { taskType: message.task_type } : {}), }, @@ -2043,7 +2043,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( ...base, type: "task.progress", payload: { - taskId: RuntimeTaskId.makeUnsafe(message.task_id), + taskId: RuntimeTaskId.make(message.task_id), description: message.description, ...(message.summary ? { summary: message.summary } : {}), ...(message.usage ? { usage: message.usage } : {}), @@ -2075,7 +2075,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( ...base, type: "task.completed", payload: { - taskId: RuntimeTaskId.makeUnsafe(message.task_id), + taskId: RuntimeTaskId.make(message.task_id), status: message.status, ...(message.summary ? { summary: message.summary } : {}), ...(message.usage ? { usage: message.usage } : {}), @@ -2380,9 +2380,9 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( existingResumeSessionId === undefined ? yield* Random.nextUUIDv4 : undefined; const sessionId = existingResumeSessionId ?? newSessionId; - const services = yield* Effect.services(); - const runFork = Effect.runForkWith(services); - const runPromise = Effect.runPromiseWith(services); + const runtimeContext = yield* Effect.context(); + const runFork = Effect.runForkWith(runtimeContext); + const runPromise = Effect.runPromiseWith(runtimeContext); const promptQueue = yield* Queue.unbounded(); const prompt = Stream.fromQueue(promptQueue).pipe( @@ -2409,7 +2409,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( toolInput: Record, callbackOptions: { readonly signal: AbortSignal; readonly toolUseID?: string }, ) { - const requestId = ApprovalRequestId.makeUnsafe(yield* Random.nextUUIDv4); + const requestId = ApprovalRequestId.make(yield* Random.nextUUIDv4); // Parse questions from the SDK's AskUserQuestion input. const rawQuestions = Array.isArray(toolInput.questions) ? toolInput.questions : []; @@ -2562,7 +2562,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( } satisfies PermissionResult; } - const requestId = ApprovalRequestId.makeUnsafe(yield* Random.nextUUIDv4); + const requestId = ApprovalRequestId.make(yield* Random.nextUUIDv4); const requestType = classifyRequestType(toolName); const detail = summarizeToolRequest(toolName, toolInput); const decisionDeferred = yield* Deferred.make(); @@ -2890,7 +2890,7 @@ const makeClaudeAdapter = Effect.fn("makeClaudeAdapter")(function* ( }); } - const turnId = TurnId.makeUnsafe(yield* Random.nextUUIDv4); + const turnId = TurnId.make(yield* Random.nextUUIDv4); const turnState: ClaudeTurnState = { turnId, startedAt: yield* nowIso, diff --git a/apps/server/src/provider/Layers/CodexAdapter.test.ts b/apps/server/src/provider/Layers/CodexAdapter.test.ts index db91e8da0ddbfcb0a4c8bb190a129daa3a7b5bf1..3278aa2105495cb00a463a24fa2cfde9142342ec 100644 --- a/apps/server/src/provider/Layers/CodexAdapter.test.ts +++ b/apps/server/src/provider/Layers/CodexAdapter.test.ts @@ -28,10 +28,10 @@ import { CodexAdapter } from "../Services/CodexAdapter.ts"; import { ProviderSessionDirectory } from "../Services/ProviderSessionDirectory.ts"; import { makeCodexAdapterLive } from "./CodexAdapter.ts"; -const asThreadId = (value: string): ThreadId => ThreadId.makeUnsafe(value); -const asTurnId = (value: string): TurnId => TurnId.makeUnsafe(value); -const asEventId = (value: string): EventId => EventId.makeUnsafe(value); -const asItemId = (value: string): ProviderItemId => ProviderItemId.makeUnsafe(value); +const asThreadId = (value: string): ThreadId => ThreadId.make(value); +const asTurnId = (value: string): TurnId => TurnId.make(value); +const asEventId = (value: string): EventId => EventId.make(value); +const asItemId = (value: string): ProviderItemId => ProviderItemId.make(value); class FakeCodexManager extends CodexAppServerManager { public startSessionImpl = vi.fn( @@ -556,7 +556,7 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { threadId: asThreadId("thread-1"), createdAt: new Date().toISOString(), method: "serverRequest/resolved", - requestId: ApprovalRequestId.makeUnsafe("req-1"), + requestId: ApprovalRequestId.make("req-1"), payload: { request: { method: "item/commandExecution/requestApproval", @@ -592,7 +592,7 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { threadId: asThreadId("thread-1"), createdAt: new Date().toISOString(), method: "serverRequest/resolved", - requestId: ApprovalRequestId.makeUnsafe("req-file-read-1"), + requestId: ApprovalRequestId.make("req-file-read-1"), payload: { request: { method: "item/fileRead/requestApproval", @@ -710,7 +710,7 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { threadId: asThreadId("thread-1"), createdAt: new Date().toISOString(), method: "item/tool/requestUserInput", - requestId: ApprovalRequestId.makeUnsafe("req-user-input-1"), + requestId: ApprovalRequestId.make("req-user-input-1"), payload: { questions: [ { @@ -735,7 +735,7 @@ lifecycleLayer("CodexAdapterLive lifecycle", (it) => { threadId: asThreadId("thread-1"), createdAt: new Date().toISOString(), method: "item/tool/requestUserInput/answered", - requestId: ApprovalRequestId.makeUnsafe("req-user-input-1"), + requestId: ApprovalRequestId.make("req-user-input-1"), payload: { answers: { sandbox_mode: { diff --git a/apps/server/src/provider/Layers/CodexAdapter.ts b/apps/server/src/provider/Layers/CodexAdapter.ts index 957ae1b2bc6661419cef56bd1280728db919c452..cae34eaaf01fa7974bea07a054d3438f6c889fae 100644 --- a/apps/server/src/provider/Layers/CodexAdapter.ts +++ b/apps/server/src/provider/Layers/CodexAdapter.ts @@ -22,7 +22,7 @@ import { TurnId, ProviderSendTurnInput, } from "@t3tools/contracts"; -import { Effect, FileSystem, Layer, Queue, Schema, ServiceMap, Stream } from "effect"; +import { Effect, FileSystem, Layer, Queue, Schema, Context, Stream } from "effect"; import { ProviderAdapterProcessError, @@ -46,7 +46,7 @@ const PROVIDER = "codex" as const; export interface CodexAdapterLiveOptions { readonly manager?: CodexAppServerManager; - readonly makeManager?: (services?: ServiceMap.ServiceMap) => CodexAppServerManager; + readonly makeManager?: (services?: Context.Context) => CodexAppServerManager; readonly nativeEventLogPath?: string; readonly nativeEventLogger?: EventNdjsonLogger; } @@ -162,11 +162,11 @@ function normalizeCodexTokenUsage(value: unknown): ThreadTokenUsageSnapshot | un } function toTurnId(value: string | undefined): TurnId | undefined { - return value?.trim() ? TurnId.makeUnsafe(value) : undefined; + return value?.trim() ? TurnId.make(value) : undefined; } function toProviderItemId(value: string | undefined): ProviderItemId | undefined { - return value?.trim() ? ProviderItemId.makeUnsafe(value) : undefined; + return value?.trim() ? ProviderItemId.make(value) : undefined; } function toTurnStatus(value: unknown): "completed" | "failed" | "cancelled" | "interrupted" { @@ -454,15 +454,15 @@ function extractProposedPlanMarkdown(text: string | undefined): string | undefin } function asRuntimeItemId(itemId: ProviderItemId): RuntimeItemId { - return RuntimeItemId.makeUnsafe(itemId); + return RuntimeItemId.make(itemId); } function asRuntimeRequestId(requestId: string): RuntimeRequestId { - return RuntimeRequestId.makeUnsafe(requestId); + return RuntimeRequestId.make(requestId); } function asRuntimeTaskId(taskId: string): RuntimeTaskId { - return RuntimeTaskId.makeUnsafe(taskId); + return RuntimeTaskId.make(taskId); } function codexEventMessage( @@ -1366,7 +1366,7 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* ( if (options?.manager) { return options.manager; } - const services = yield* Effect.services(); + const services = yield* Effect.context(); return options?.makeManager?.(services) ?? new CodexAppServerManager(services); }); @@ -1585,7 +1585,7 @@ const makeCodexAdapter = Effect.fn("makeCodexAdapter")(function* ( }); const registerListener = Effect.fn("registerListener")(function* () { - const services = yield* Effect.services(); + const services = yield* Effect.context(); const listenerEffect = Effect.fn("listener")(function* (event: ProviderEvent) { yield* writeNativeEvent(event); const runtimeEvents = mapToRuntimeEvents(event, event.threadId); diff --git a/apps/server/src/provider/Layers/EventNdjsonLogger.test.ts b/apps/server/src/provider/Layers/EventNdjsonLogger.test.ts index 9284ffac4518c4b16463c810cdd928bfd3bebaf0..aa7e5a26927fc78e2c6f417289454ede338abcdb 100644 --- a/apps/server/src/provider/Layers/EventNdjsonLogger.test.ts +++ b/apps/server/src/provider/Layers/EventNdjsonLogger.test.ts @@ -42,11 +42,11 @@ describe("EventNdjsonLogger", () => { yield* logger.write( { threadId: "provider-thread-1", id: "evt-1" }, - ThreadId.makeUnsafe("thread-1"), + ThreadId.make("thread-1"), ); yield* logger.write( { type: "turn.completed", threadId: "provider-thread-2", id: "evt-2" }, - ThreadId.makeUnsafe("thread-2"), + ThreadId.make("thread-2"), ); yield* logger.close(); @@ -178,7 +178,7 @@ describe("EventNdjsonLogger", () => { id: `evt-${index}`, payload: "x".repeat(40), }, - ThreadId.makeUnsafe("thread-rotate"), + ThreadId.make("thread-rotate"), ); } yield* logger.close(); diff --git a/apps/server/src/provider/Layers/ProviderRegistry.test.ts b/apps/server/src/provider/Layers/ProviderRegistry.test.ts index ca27371b61cd7fd7b1c254d003ea2be7fbf10340..3d6f4186037ea2f00d1e2e4b9486d3b5f39f7735 100644 --- a/apps/server/src/provider/Layers/ProviderRegistry.test.ts +++ b/apps/server/src/provider/Layers/ProviderRegistry.test.ts @@ -44,6 +44,7 @@ function mockHandle(result: { stdout: string; stderr: string; code: number }) { exitCode: Effect.succeed(ChildProcessSpawner.ExitCode(result.code)), isRunning: Effect.succeed(false), kill: () => Effect.void, + unref: Effect.succeed(Effect.void), stdin: Sink.drain, stdout: Stream.make(encoder.encode(result.stdout)), stderr: Stream.make(encoder.encode(result.stderr)), diff --git a/apps/server/src/provider/Layers/ProviderService.test.ts b/apps/server/src/provider/Layers/ProviderService.test.ts index fc3c9cf25c54d0a67afd1abb249fc1a3ac2cc922..56f9f8d65c4a45731c66c520ed706344568a7547 100644 --- a/apps/server/src/provider/Layers/ProviderService.test.ts +++ b/apps/server/src/provider/Layers/ProviderService.test.ts @@ -47,10 +47,10 @@ import { AnalyticsService } from "../../telemetry/Services/AnalyticsService.ts"; const defaultServerSettingsLayer = ServerSettingsService.layerTest(); -const asRequestId = (value: string): ApprovalRequestId => ApprovalRequestId.makeUnsafe(value); -const asEventId = (value: string): EventId => EventId.makeUnsafe(value); -const asThreadId = (value: string): ThreadId => ThreadId.makeUnsafe(value); -const asTurnId = (value: string): TurnId => TurnId.makeUnsafe(value); +const asRequestId = (value: string): ApprovalRequestId => ApprovalRequestId.make(value); +const asEventId = (value: string): EventId => EventId.make(value); +const asThreadId = (value: string): ThreadId => ThreadId.make(value); +const asTurnId = (value: string): TurnId => TurnId.make(value); type LegacyProviderRuntimeEvent = { readonly type: string; @@ -102,7 +102,7 @@ function makeFakeCodexAdapter(provider: ProviderKind = "codex") { return Effect.succeed({ threadId: input.threadId, - turnId: TurnId.makeUnsafe(`turn-${String(input.threadId)}`), + turnId: TurnId.make(`turn-${String(input.threadId)}`), }); }, ); @@ -358,7 +358,7 @@ it.effect("ProviderServiceLive keeps persisted resumable sessions on startup", ( const directory = yield* ProviderSessionDirectory; yield* directory.upsert({ provider: "codex", - threadId: ThreadId.makeUnsafe("thread-stale"), + threadId: ThreadId.make("thread-stale"), }); }).pipe(Effect.provide(directoryLayer)); diff --git a/apps/server/src/provider/Layers/ProviderSessionDirectory.test.ts b/apps/server/src/provider/Layers/ProviderSessionDirectory.test.ts index d23b247f21f1a54ab332cfa82564688e4cc0591a..3ffd6941ade749c3639edc4909596afc2f48bce8 100644 --- a/apps/server/src/provider/Layers/ProviderSessionDirectory.test.ts +++ b/apps/server/src/provider/Layers/ProviderSessionDirectory.test.ts @@ -36,7 +36,7 @@ it.layer(makeDirectoryLayer(SqlitePersistenceMemory))("ProviderSessionDirectoryL const directory = yield* ProviderSessionDirectory; const runtimeRepository = yield* ProviderSessionRuntimeRepository; - const initialThreadId = ThreadId.makeUnsafe("thread-1"); + const initialThreadId = ThreadId.make("thread-1"); yield* directory.upsert({ provider: "codex", @@ -54,7 +54,7 @@ it.layer(makeDirectoryLayer(SqlitePersistenceMemory))("ProviderSessionDirectoryL assert.equal(resolvedBinding.value.threadId, initialThreadId); } - const nextThreadId = ThreadId.makeUnsafe("thread-2"); + const nextThreadId = ThreadId.make("thread-2"); yield* directory.upsert({ provider: "codex", @@ -93,7 +93,7 @@ it.layer(makeDirectoryLayer(SqlitePersistenceMemory))("ProviderSessionDirectoryL const directory = yield* ProviderSessionDirectory; const runtimeRepository = yield* ProviderSessionRuntimeRepository; - const threadId = ThreadId.makeUnsafe("thread-runtime"); + const threadId = ThreadId.make("thread-runtime"); yield* directory.upsert({ provider: "codex", @@ -137,7 +137,7 @@ it.layer(makeDirectoryLayer(SqlitePersistenceMemory))("ProviderSessionDirectoryL Effect.gen(function* () { const directory = yield* ProviderSessionDirectory; const runtimeRepository = yield* ProviderSessionRuntimeRepository; - const threadId = ThreadId.makeUnsafe("thread-provider-change"); + const threadId = ThreadId.make("thread-provider-change"); yield* runtimeRepository.upsert({ threadId, @@ -169,7 +169,7 @@ it.layer(makeDirectoryLayer(SqlitePersistenceMemory))("ProviderSessionDirectoryL const dbPath = path.join(tempDir, "orchestration.sqlite"); const directoryLayer = makeDirectoryLayer(makeSqlitePersistenceLive(dbPath)); - const threadId = ThreadId.makeUnsafe("thread-restart"); + const threadId = ThreadId.make("thread-restart"); yield* Effect.gen(function* () { const directory = yield* ProviderSessionDirectory; diff --git a/apps/server/src/provider/Services/ClaudeAdapter.ts b/apps/server/src/provider/Services/ClaudeAdapter.ts index 3a3f616ea5f9455b7a6f65078c7421502691143f..e8c33bd8e40c98ea3c93a37577f1ea1a2116fdb6 100644 --- a/apps/server/src/provider/Services/ClaudeAdapter.ts +++ b/apps/server/src/provider/Services/ClaudeAdapter.ts @@ -5,12 +5,12 @@ * provider runtime events. It does not perform cross-provider routing, shared * event fan-out, or checkpoint orchestration. * - * Uses Effect `ServiceMap.Service` for dependency injection and returns the + * Uses Effect `Context.Service` for dependency injection and returns the * shared provider-adapter error channel with `provider: "claudeAgent"` context. * * @module ClaudeAdapter */ -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { ProviderAdapterError } from "../Errors.ts"; import type { ProviderAdapterShape } from "./ProviderAdapter.ts"; @@ -25,6 +25,6 @@ export interface ClaudeAdapterShape extends ProviderAdapterShape()( +export class ClaudeAdapter extends Context.Service()( "t3/provider/Services/ClaudeAdapter", ) {} diff --git a/apps/server/src/provider/Services/ClaudeProvider.ts b/apps/server/src/provider/Services/ClaudeProvider.ts index 18ee8a4f6d86953c139f6ea2d8681c649df793cd..7f90c549c6353f6488795add51a6261913aced8b 100644 --- a/apps/server/src/provider/Services/ClaudeProvider.ts +++ b/apps/server/src/provider/Services/ClaudeProvider.ts @@ -1,9 +1,9 @@ -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { ServerProviderShape } from "./ServerProvider"; export interface ClaudeProviderShape extends ServerProviderShape {} -export class ClaudeProvider extends ServiceMap.Service()( +export class ClaudeProvider extends Context.Service()( "t3/provider/Services/ClaudeProvider", ) {} diff --git a/apps/server/src/provider/Services/CodexAdapter.ts b/apps/server/src/provider/Services/CodexAdapter.ts index c9f944bb96ad0879af68bcbbb7d4e4ba29ef6667..e7a5508c9c7bcd21b336c7a8f36d44162579505f 100644 --- a/apps/server/src/provider/Services/CodexAdapter.ts +++ b/apps/server/src/provider/Services/CodexAdapter.ts @@ -5,12 +5,12 @@ * Codex provider events. It does not perform cross-provider routing, shared * event fan-out, or checkpoint orchestration. * - * Uses Effect `ServiceMap.Service` for dependency injection and returns the + * Uses Effect `Context.Service` for dependency injection and returns the * shared provider-adapter error channel with `provider: "codex"` context. * * @module CodexAdapter */ -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { ProviderAdapterError } from "../Errors.ts"; import type { ProviderAdapterShape } from "./ProviderAdapter.ts"; @@ -25,6 +25,6 @@ export interface CodexAdapterShape extends ProviderAdapterShape()( +export class CodexAdapter extends Context.Service()( "t3/provider/Services/CodexAdapter", ) {} diff --git a/apps/server/src/provider/Services/CodexProvider.ts b/apps/server/src/provider/Services/CodexProvider.ts index 2e9b57c89b354d9b9f981607b15b6e82580db96e..6820d4cb4f9d03dd11196e6b6aaf791e17b8d77a 100644 --- a/apps/server/src/provider/Services/CodexProvider.ts +++ b/apps/server/src/provider/Services/CodexProvider.ts @@ -1,9 +1,9 @@ -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { ServerProviderShape } from "./ServerProvider"; export interface CodexProviderShape extends ServerProviderShape {} -export class CodexProvider extends ServiceMap.Service()( +export class CodexProvider extends Context.Service()( "t3/provider/Services/CodexProvider", ) {} diff --git a/apps/server/src/provider/Services/ProviderAdapterRegistry.ts b/apps/server/src/provider/Services/ProviderAdapterRegistry.ts index 490c4d3d143e3ac17cfc252ade68d6fe7669cfa4..b8e9d4b21c31191993156ddf819f8474cf3bc7cc 100644 --- a/apps/server/src/provider/Services/ProviderAdapterRegistry.ts +++ b/apps/server/src/provider/Services/ProviderAdapterRegistry.ts @@ -8,7 +8,7 @@ * @module ProviderAdapterRegistry */ import type { ProviderKind } from "@t3tools/contracts"; -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect } from "effect"; import type { ProviderAdapterError, ProviderUnsupportedError } from "../Errors.ts"; @@ -34,7 +34,7 @@ export interface ProviderAdapterRegistryShape { /** * ProviderAdapterRegistry - Service tag for provider adapter lookup. */ -export class ProviderAdapterRegistry extends ServiceMap.Service< +export class ProviderAdapterRegistry extends Context.Service< ProviderAdapterRegistry, ProviderAdapterRegistryShape >()("t3/provider/Services/ProviderAdapterRegistry") {} diff --git a/apps/server/src/provider/Services/ProviderRegistry.ts b/apps/server/src/provider/Services/ProviderRegistry.ts index 80710691c1d2cf82eb2983723ba44a48ac72f213..2e04fa253b01aa406fbc36fe37c8df38574697fe 100644 --- a/apps/server/src/provider/Services/ProviderRegistry.ts +++ b/apps/server/src/provider/Services/ProviderRegistry.ts @@ -7,7 +7,7 @@ * @module ProviderRegistry */ import type { ProviderKind, ServerProvider } from "@t3tools/contracts"; -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect, Stream } from "effect"; export interface ProviderRegistryShape { @@ -27,6 +27,6 @@ export interface ProviderRegistryShape { readonly streamChanges: Stream.Stream>; } -export class ProviderRegistry extends ServiceMap.Service()( +export class ProviderRegistry extends Context.Service()( "t3/provider/Services/ProviderRegistry", ) {} diff --git a/apps/server/src/provider/Services/ProviderService.ts b/apps/server/src/provider/Services/ProviderService.ts index ebfe8c8ab1ac22a8ef0652a9e4770ed696c7f695..1e461fcd1c69df6198e7ecdb0db3ba49b491a316 100644 --- a/apps/server/src/provider/Services/ProviderService.ts +++ b/apps/server/src/provider/Services/ProviderService.ts @@ -6,7 +6,7 @@ * session-scoped calls via `ProviderSessionDirectory`, and exposes one unified * provider event stream to callers. * - * Uses Effect `ServiceMap.Service` for dependency injection and returns typed + * Uses Effect `Context.Service` for dependency injection and returns typed * domain errors for validation, session, codex, and checkpoint workflows. * * @module ProviderService @@ -24,7 +24,7 @@ import type { ThreadId, ProviderTurnStartResult, } from "@t3tools/contracts"; -import { ServiceMap } from "effect"; +import { Context } from "effect"; import type { Effect, Stream } from "effect"; import type { ProviderServiceError } from "../Errors.ts"; @@ -110,6 +110,6 @@ export interface ProviderServiceShape { /** * ProviderService - Service tag for provider orchestration. */ -export class ProviderService extends ServiceMap.Service()( +export class ProviderService extends Context.Service()( "t3/provider/Services/ProviderService", ) {} diff --git a/apps/server/src/provider/Services/ProviderSessionDirectory.ts b/apps/server/src/provider/Services/ProviderSessionDirectory.ts index 3a374976b0797fb8efe86ed1010278fc6ca389b6..aa0483620b400fff2d05aad0bbae28d25b962d6d 100644 --- a/apps/server/src/provider/Services/ProviderSessionDirectory.ts +++ b/apps/server/src/provider/Services/ProviderSessionDirectory.ts @@ -4,7 +4,7 @@ import type { RuntimeMode, ThreadId, } from "@t3tools/contracts"; -import { Option, ServiceMap } from "effect"; +import { Option, Context } from "effect"; import type { Effect } from "effect"; import type { @@ -51,7 +51,7 @@ export interface ProviderSessionDirectoryShape { >; } -export class ProviderSessionDirectory extends ServiceMap.Service< +export class ProviderSessionDirectory extends Context.Service< ProviderSessionDirectory, ProviderSessionDirectoryShape >()("t3/provider/Services/ProviderSessionDirectory") {} diff --git a/apps/server/src/server.test.ts b/apps/server/src/server.test.ts index 98e1395e13dbce5b30c1849bbb7a8e54de1a0aa7..8d807afba3880fb78d5bfd78df77b440197ed4d5 100644 --- a/apps/server/src/server.test.ts +++ b/apps/server/src/server.test.ts @@ -101,15 +101,15 @@ import { WorkspacePathsLive } from "./workspace/Layers/WorkspacePaths.ts"; import { ServerSecretStoreLive } from "./auth/Layers/ServerSecretStore.ts"; import { ServerAuthLive } from "./auth/Layers/ServerAuth.ts"; -const defaultProjectId = ProjectId.makeUnsafe("project-default"); -const defaultThreadId = ThreadId.makeUnsafe("thread-default"); +const defaultProjectId = ProjectId.make("project-default"); +const defaultThreadId = ThreadId.make("thread-default"); const defaultDesktopBootstrapToken = "test-desktop-bootstrap-token"; const defaultModelSelection = { provider: "codex", model: "gpt-5-codex", } as const; const testEnvironmentDescriptor = { - environmentId: EnvironmentId.makeUnsafe("environment-test"), + environmentId: EnvironmentId.make("environment-test"), label: "Test environment", platform: { os: "darwin" as const, @@ -1307,7 +1307,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { ); assert.equal(error._tag, "RpcClientError"); - assertInclude(String(error), "401"); + assertInclude(String(error), "SocketOpenError"); }).pipe(Effect.provide(NodeHttpServer.layerTest)), ); @@ -2685,7 +2685,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { updatedAt: now, projects: [ { - id: ProjectId.makeUnsafe("project-a"), + id: ProjectId.make("project-a"), title: "Project A", workspaceRoot: "/tmp/project-a", defaultModelSelection, @@ -2697,8 +2697,8 @@ it.layer(NodeServices.layer)("server router seam", (it) => { ], threads: [ { - id: ThreadId.makeUnsafe("thread-1"), - projectId: ProjectId.makeUnsafe("project-a"), + id: ThreadId.make("thread-1"), + projectId: ProjectId.make("project-a"), title: "Thread A", modelSelection: defaultModelSelection, interactionMode: "default" as const, @@ -2731,14 +2731,14 @@ it.layer(NodeServices.layer)("server router seam", (it) => { checkpointDiffQuery: { getTurnDiff: () => Effect.succeed({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), fromTurnCount: 0, toTurnCount: 1, diff: "turn-diff", }), getFullThreadDiff: () => Effect.succeed({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), fromTurnCount: 0, toTurnCount: 1, diff: "full-diff", @@ -2757,8 +2757,8 @@ it.layer(NodeServices.layer)("server router seam", (it) => { withWsRpcClient(wsUrl, (client) => client[ORCHESTRATION_WS_METHODS.dispatchCommand]({ type: "thread.session.stop", - commandId: CommandId.makeUnsafe("cmd-1"), - threadId: ThreadId.makeUnsafe("thread-1"), + commandId: CommandId.make("cmd-1"), + threadId: ThreadId.make("thread-1"), createdAt: now, }), ), @@ -2768,7 +2768,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { const turnDiffResult = yield* Effect.scoped( withWsRpcClient(wsUrl, (client) => client[ORCHESTRATION_WS_METHODS.getTurnDiff]({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), fromTurnCount: 0, toTurnCount: 1, }), @@ -2779,7 +2779,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { const fullDiffResult = yield* Effect.scoped( withWsRpcClient(wsUrl, (client) => client[ORCHESTRATION_WS_METHODS.getFullThreadDiff]({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), toTurnCount: 1, }), ), @@ -2818,7 +2818,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { readEvents: (_fromSequenceExclusive) => Stream.make({ sequence: 1, - eventId: EventId.makeUnsafe("event-1"), + eventId: EventId.make("event-1"), aggregateKind: "project", aggregateId: defaultProjectId, occurredAt: "2026-04-05T00:00:00.000Z", @@ -2866,7 +2866,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { it.effect("closes thread terminals after a successful archive command", () => Effect.gen(function* () { - const threadId = ThreadId.makeUnsafe("thread-archive"); + const threadId = ThreadId.make("thread-archive"); const closeInputs: Array[0]> = []; yield* buildAppUnderTest({ @@ -2888,7 +2888,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { withWsRpcClient(wsUrl, (client) => client[ORCHESTRATION_WS_METHODS.dispatchCommand]({ type: "thread.archive", - commandId: CommandId.makeUnsafe("cmd-thread-archive"), + commandId: CommandId.make("cmd-thread-archive"), threadId, }), ), @@ -2948,10 +2948,10 @@ it.layer(NodeServices.layer)("server router seam", (it) => { withWsRpcClient(wsUrl, (client) => client[ORCHESTRATION_WS_METHODS.dispatchCommand]({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-bootstrap-turn-start"), - threadId: ThreadId.makeUnsafe("thread-bootstrap"), + commandId: CommandId.make("cmd-bootstrap-turn-start"), + threadId: ThreadId.make("thread-bootstrap"), message: { - messageId: MessageId.makeUnsafe("msg-bootstrap"), + messageId: MessageId.make("msg-bootstrap"), role: "user", text: "hello", attachments: [], @@ -3000,7 +3000,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { path: null, }); assert.deepEqual(runForThread.mock.calls[0]?.[0], { - threadId: ThreadId.makeUnsafe("thread-bootstrap"), + threadId: ThreadId.make("thread-bootstrap"), projectId: defaultProjectId, projectCwd: "/tmp/project", worktreePath: "/tmp/bootstrap-worktree", @@ -3063,10 +3063,10 @@ it.layer(NodeServices.layer)("server router seam", (it) => { withWsRpcClient(wsUrl, (client) => client[ORCHESTRATION_WS_METHODS.dispatchCommand]({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-bootstrap-turn-start-setup-failure"), - threadId: ThreadId.makeUnsafe("thread-bootstrap-setup-failure"), + commandId: CommandId.make("cmd-bootstrap-turn-start-setup-failure"), + threadId: ThreadId.make("thread-bootstrap-setup-failure"), message: { - messageId: MessageId.makeUnsafe("msg-bootstrap-setup-failure"), + messageId: MessageId.make("msg-bootstrap-setup-failure"), role: "user", text: "hello", attachments: [], @@ -3179,10 +3179,10 @@ it.layer(NodeServices.layer)("server router seam", (it) => { withWsRpcClient(wsUrl, (client) => client[ORCHESTRATION_WS_METHODS.dispatchCommand]({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-bootstrap-turn-start-setup-activity-failure"), - threadId: ThreadId.makeUnsafe("thread-bootstrap-setup-activity-failure"), + commandId: CommandId.make("cmd-bootstrap-turn-start-setup-activity-failure"), + threadId: ThreadId.make("thread-bootstrap-setup-activity-failure"), message: { - messageId: MessageId.makeUnsafe("msg-bootstrap-setup-activity-failure"), + messageId: MessageId.make("msg-bootstrap-setup-activity-failure"), role: "user", text: "hello", attachments: [], @@ -3262,10 +3262,10 @@ it.layer(NodeServices.layer)("server router seam", (it) => { withWsRpcClient(wsUrl, (client) => client[ORCHESTRATION_WS_METHODS.dispatchCommand]({ type: "thread.turn.start", - commandId: CommandId.makeUnsafe("cmd-bootstrap-turn-start-defect"), - threadId: ThreadId.makeUnsafe("thread-bootstrap-defect"), + commandId: CommandId.make("cmd-bootstrap-turn-start-defect"), + threadId: ThreadId.make("thread-bootstrap-defect"), message: { - messageId: MessageId.makeUnsafe("msg-bootstrap-defect"), + messageId: MessageId.make("msg-bootstrap-defect"), role: "user", text: "hello", attachments: [], @@ -3311,7 +3311,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { () => Effect.gen(function* () { const now = new Date().toISOString(); - const threadId = ThreadId.makeUnsafe("thread-1"); + const threadId = ThreadId.make("thread-1"); let replayCursor: number | null = null; const makeEvent = (sequence: number): OrchestrationEvent => ({ @@ -3393,7 +3393,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { readEvents: () => Stream.make({ sequence: 1, - eventId: EventId.makeUnsafe("event-1"), + eventId: EventId.make("event-1"), aggregateKind: "project", aggregateId: defaultProjectId, occurredAt: "2026-04-06T00:00:00.000Z", @@ -3464,7 +3464,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { }), streamDomainEvents: Stream.make({ sequence: 1, - eventId: EventId.makeUnsafe("event-1"), + eventId: EventId.make("event-1"), aggregateKind: "project", aggregateId: defaultProjectId, occurredAt: "2026-04-05T00:00:00.000Z", diff --git a/apps/server/src/serverLifecycleEvents.test.ts b/apps/server/src/serverLifecycleEvents.test.ts index cfa5c553a9175039542cb805fd133fed09741042..47e24c1b87c8c59978d32d2ee914dd0e3b77d8a7 100644 --- a/apps/server/src/serverLifecycleEvents.test.ts +++ b/apps/server/src/serverLifecycleEvents.test.ts @@ -11,7 +11,7 @@ it.effect( Effect.gen(function* () { const lifecycleEvents = yield* ServerLifecycleEvents; const environment = { - environmentId: EnvironmentId.makeUnsafe("environment-test"), + environmentId: EnvironmentId.make("environment-test"), label: "Test environment", platform: { os: "darwin" as const, arch: "arm64" as const }, serverVersion: "0.0.0-test", diff --git a/apps/server/src/serverLifecycleEvents.ts b/apps/server/src/serverLifecycleEvents.ts index 4808a19d7248af284f7eee5aa606d0ad9e5ce2c0..145d1cbaa4e5f509b4bc77d47c86df256987f65c 100644 --- a/apps/server/src/serverLifecycleEvents.ts +++ b/apps/server/src/serverLifecycleEvents.ts @@ -1,5 +1,5 @@ import type { ServerLifecycleStreamEvent } from "@t3tools/contracts"; -import { Effect, Layer, PubSub, Ref, ServiceMap, Stream } from "effect"; +import { Effect, Layer, PubSub, Ref, Context, Stream } from "effect"; type LifecycleEventInput = | Omit, "sequence"> @@ -16,7 +16,7 @@ export interface ServerLifecycleEventsShape { readonly stream: Stream.Stream; } -export class ServerLifecycleEvents extends ServiceMap.Service< +export class ServerLifecycleEvents extends Context.Service< ServerLifecycleEvents, ServerLifecycleEventsShape >()("t3/serverLifecycleEvents") {} diff --git a/apps/server/src/serverRuntimeStartup.ts b/apps/server/src/serverRuntimeStartup.ts index 5d68761f0976825852c44236e5c47ed26614bdcb..441df3395d98c1e09563f3cb4c4ddee1a33f62a9 100644 --- a/apps/server/src/serverRuntimeStartup.ts +++ b/apps/server/src/serverRuntimeStartup.ts @@ -17,7 +17,7 @@ import { Queue, Ref, Scope, - ServiceMap, + Context, Console, } from "effect"; @@ -52,7 +52,7 @@ export interface ServerRuntimeStartupShape { ) => Effect.Effect; } -export class ServerRuntimeStartup extends ServiceMap.Service< +export class ServerRuntimeStartup extends Context.Service< ServerRuntimeStartup, ServerRuntimeStartupShape >()("t3/serverRuntimeStartup") {} @@ -176,12 +176,12 @@ const autoBootstrapWelcome = Effect.gen(function* () { if (Option.isNone(existingProject)) { const createdAt = new Date().toISOString(); - nextProjectId = ProjectId.makeUnsafe(crypto.randomUUID()); + nextProjectId = ProjectId.make(crypto.randomUUID()); const bootstrapProjectTitle = path.basename(serverConfig.cwd) || "project"; nextProjectDefaultModelSelection = getAutoBootstrapDefaultModelSelection(); yield* orchestrationEngine.dispatch({ type: "project.create", - commandId: CommandId.makeUnsafe(crypto.randomUUID()), + commandId: CommandId.make(crypto.randomUUID()), projectId: nextProjectId, title: bootstrapProjectTitle, workspaceRoot: serverConfig.cwd, @@ -198,10 +198,10 @@ const autoBootstrapWelcome = Effect.gen(function* () { yield* projectionReadModelQuery.getFirstActiveThreadIdByProjectId(nextProjectId); if (Option.isNone(existingThreadId)) { const createdAt = new Date().toISOString(); - const createdThreadId = ThreadId.makeUnsafe(crypto.randomUUID()); + const createdThreadId = ThreadId.make(crypto.randomUUID()); yield* orchestrationEngine.dispatch({ type: "thread.create", - commandId: CommandId.makeUnsafe(crypto.randomUUID()), + commandId: CommandId.make(crypto.randomUUID()), threadId: createdThreadId, projectId: nextProjectId, title: "New thread", diff --git a/apps/server/src/serverSettings.ts b/apps/server/src/serverSettings.ts index 79fdc29a8b06bc17cd5452d63b94be574d30b922..5a708d5c23022ff44d09662f0883d4f749ef3153 100644 --- a/apps/server/src/serverSettings.ts +++ b/apps/server/src/serverSettings.ts @@ -34,7 +34,7 @@ import { Schema, SchemaIssue, Scope, - ServiceMap, + Context, Stream, Cause, } from "effect"; @@ -62,7 +62,7 @@ export interface ServerSettingsShape { readonly streamChanges: Stream.Stream; } -export class ServerSettingsService extends ServiceMap.Service< +export class ServerSettingsService extends Context.Service< ServerSettingsService, ServerSettingsShape >()("t3/serverSettings/ServerSettingsService") { diff --git a/apps/server/src/telemetry/Services/AnalyticsService.ts b/apps/server/src/telemetry/Services/AnalyticsService.ts index 64f8c8de55271906996450246fb3e8981e6f3002..0e703573d46c713d069adc999d0f52db1db22938 100644 --- a/apps/server/src/telemetry/Services/AnalyticsService.ts +++ b/apps/server/src/telemetry/Services/AnalyticsService.ts @@ -6,7 +6,7 @@ * * @module AnalyticsService */ -import { Effect, Layer, ServiceMap } from "effect"; +import { Effect, Layer, Context } from "effect"; export interface AnalyticsServiceShape { /** @@ -23,7 +23,7 @@ export interface AnalyticsServiceShape { readonly flush: Effect.Effect; } -export class AnalyticsService extends ServiceMap.Service()( +export class AnalyticsService extends Context.Service()( "t3/telemetry/Services/AnalyticsService", ) { static readonly layerTest = Layer.succeed(AnalyticsService, { diff --git a/apps/server/src/terminal/Layers/Manager.ts b/apps/server/src/terminal/Layers/Manager.ts index 5dc216e37e86a0c48c28662997d5133cfdea9fc9..c6a16b0b496996530ee6d7eb1d90a0ef2ee4cd7f 100644 --- a/apps/server/src/terminal/Layers/Manager.ts +++ b/apps/server/src/terminal/Layers/Manager.ts @@ -664,8 +664,8 @@ const makeTerminalManager = Effect.fn("makeTerminalManager")(function* () { export const makeTerminalManagerWithOptions = Effect.fn("makeTerminalManagerWithOptions")( function* (options: TerminalManagerOptions) { const fileSystem = yield* FileSystem.FileSystem; - const services = yield* Effect.services(); - const runFork = Effect.runForkWith(services); + const context = yield* Effect.context(); + const runFork = Effect.runForkWith(context); const logsDir = options.logsDir; const historyLineLimit = options.historyLineLimit ?? DEFAULT_HISTORY_LINE_LIMIT; diff --git a/apps/server/src/terminal/Services/Manager.ts b/apps/server/src/terminal/Services/Manager.ts index ebe83e362b0c80e429d5d2104d649d4acf7dffa8..b59c4721cd3e15a2f720e420af11fc4a3afc3b6e 100644 --- a/apps/server/src/terminal/Services/Manager.ts +++ b/apps/server/src/terminal/Services/Manager.ts @@ -23,7 +23,7 @@ import { TerminalWriteInput, } from "@t3tools/contracts"; import { PtyProcess } from "./PTY"; -import { Effect, ServiceMap } from "effect"; +import { Effect, Context } from "effect"; export { TerminalCwdError, @@ -122,6 +122,6 @@ export interface TerminalManagerShape { /** * TerminalManager - Service tag for terminal session orchestration. */ -export class TerminalManager extends ServiceMap.Service()( +export class TerminalManager extends Context.Service()( "t3/terminal/Services/Manager/TerminalManager", ) {} diff --git a/apps/server/src/terminal/Services/PTY.ts b/apps/server/src/terminal/Services/PTY.ts index dc164b2621f00206a0343152f4e4381e14ae5dd4..091e527ef2bd8e6402637dc322894e3cdabe7538 100644 --- a/apps/server/src/terminal/Services/PTY.ts +++ b/apps/server/src/terminal/Services/PTY.ts @@ -6,7 +6,7 @@ * * @module PtyAdapter */ -import { Effect, Schema, ServiceMap } from "effect"; +import { Effect, Schema, Context } from "effect"; /** * PtyError - Error type for PTY adapter operations. @@ -53,6 +53,6 @@ export interface PtyAdapterShape { /** * PtyAdapter - Service tag for PTY process integration. */ -export class PtyAdapter extends ServiceMap.Service()( +export class PtyAdapter extends Context.Service()( "t3/terminal/Services/PTY/PtyAdapter", ) {} diff --git a/apps/server/src/workspace/Layers/WorkspaceEntries.ts b/apps/server/src/workspace/Layers/WorkspaceEntries.ts index 12af8601ca0118d3774caf346c0a0b807c006787..542e187457bc560a14ec772cda7ab467b504eeba 100644 --- a/apps/server/src/workspace/Layers/WorkspaceEntries.ts +++ b/apps/server/src/workspace/Layers/WorkspaceEntries.ts @@ -430,12 +430,14 @@ export const makeWorkspaceEntries = Effect.gen(function* () { return yield* buildWorkspaceIndexFromFilesystem(cwd); }); - const workspaceIndexCache = yield* Cache.makeWith({ - capacity: WORKSPACE_CACHE_MAX_KEYS, - lookup: buildWorkspaceIndex, - timeToLive: (exit) => - Exit.isSuccess(exit) ? Duration.millis(WORKSPACE_CACHE_TTL_MS) : Duration.zero, - }); + const workspaceIndexCache = yield* Cache.makeWith( + buildWorkspaceIndex, + { + capacity: WORKSPACE_CACHE_MAX_KEYS, + timeToLive: (exit) => + Exit.isSuccess(exit) ? Duration.millis(WORKSPACE_CACHE_TTL_MS) : Duration.zero, + }, + ); const normalizeWorkspaceRoot = Effect.fn("WorkspaceEntries.normalizeWorkspaceRoot")(function* ( cwd: string, diff --git a/apps/server/src/workspace/Services/WorkspaceEntries.ts b/apps/server/src/workspace/Services/WorkspaceEntries.ts index 2841b1fe2f378b27a7e24e783ffd983b150cf034..c0011a9dc9a0813514fc6bd36865158076ff8c23 100644 --- a/apps/server/src/workspace/Services/WorkspaceEntries.ts +++ b/apps/server/src/workspace/Services/WorkspaceEntries.ts @@ -6,7 +6,7 @@ * * @module WorkspaceEntries */ -import { Schema, ServiceMap } from "effect"; +import { Schema, Context } from "effect"; import type { Effect } from "effect"; import type { ProjectSearchEntriesInput, ProjectSearchEntriesResult } from "@t3tools/contracts"; @@ -43,6 +43,6 @@ export interface WorkspaceEntriesShape { /** * WorkspaceEntries - Service tag for cached workspace entry search. */ -export class WorkspaceEntries extends ServiceMap.Service()( +export class WorkspaceEntries extends Context.Service()( "t3/workspace/Services/WorkspaceEntries", ) {} diff --git a/apps/server/src/workspace/Services/WorkspaceFileSystem.ts b/apps/server/src/workspace/Services/WorkspaceFileSystem.ts index 85db1514a39058be501353e58f56a602c36a5448..dc6cc6e9d8535d6ef22f4924750a26df1cc8fd93 100644 --- a/apps/server/src/workspace/Services/WorkspaceFileSystem.ts +++ b/apps/server/src/workspace/Services/WorkspaceFileSystem.ts @@ -6,7 +6,7 @@ * * @module WorkspaceFileSystem */ -import { Schema, ServiceMap } from "effect"; +import { Schema, Context } from "effect"; import type { Effect } from "effect"; import type { ProjectWriteFileInput, ProjectWriteFileResult } from "@t3tools/contracts"; @@ -44,7 +44,7 @@ export interface WorkspaceFileSystemShape { /** * WorkspaceFileSystem - Service tag for workspace file operations. */ -export class WorkspaceFileSystem extends ServiceMap.Service< +export class WorkspaceFileSystem extends Context.Service< WorkspaceFileSystem, WorkspaceFileSystemShape >()("t3/workspace/Services/WorkspaceFileSystem") {} diff --git a/apps/server/src/workspace/Services/WorkspacePaths.ts b/apps/server/src/workspace/Services/WorkspacePaths.ts index ad6d9cd3e5a9c7edc36aa04285830493da036d50..86cef90735961b4140a3b7402f59d077c98c20e1 100644 --- a/apps/server/src/workspace/Services/WorkspacePaths.ts +++ b/apps/server/src/workspace/Services/WorkspacePaths.ts @@ -6,7 +6,7 @@ * * @module WorkspacePaths */ -import { Schema, ServiceMap } from "effect"; +import { Schema, Context } from "effect"; import type { Effect } from "effect"; export class WorkspaceRootNotExistsError extends Schema.TaggedErrorClass()( @@ -80,6 +80,6 @@ export interface WorkspacePathsShape { /** * WorkspacePaths - Service tag for workspace path normalization and resolution. */ -export class WorkspacePaths extends ServiceMap.Service()( +export class WorkspacePaths extends Context.Service()( "t3/workspace/Services/WorkspacePaths", ) {} diff --git a/apps/server/src/ws.ts b/apps/server/src/ws.ts index 8d4f94669197d200c2e167698ea72ce544b401f8..c7b1fc4804b8e58e8d26a16be3604720810ec637 100644 --- a/apps/server/src/ws.ts +++ b/apps/server/src/ws.ts @@ -128,7 +128,7 @@ const makeWsRpcLayer = (currentSessionId: AuthSessionId) => const bootstrapCredentials = yield* BootstrapCredentialService; const sessions = yield* SessionCredentialService; const serverCommandId = (tag: string) => - CommandId.makeUnsafe(`server:${tag}:${crypto.randomUUID()}`); + CommandId.make(`server:${tag}:${crypto.randomUUID()}`); const loadAuthAccessSnapshot = () => Effect.all({ @@ -149,7 +149,7 @@ const makeWsRpcLayer = (currentSessionId: AuthSessionId) => commandId: serverCommandId("setup-script-activity"), threadId: input.threadId, activity: { - id: EventId.makeUnsafe(crypto.randomUUID()), + id: EventId.make(crypto.randomUUID()), tone: input.tone, kind: input.kind, summary: input.summary, diff --git a/apps/web/src/clientPersistenceStorage.test.ts b/apps/web/src/clientPersistenceStorage.test.ts index ed88fe6f7088a8b3e2fe4136426cfdd9b77598b7..a74ce18ac30503562b4982d960154b4b6684b197 100644 --- a/apps/web/src/clientPersistenceStorage.test.ts +++ b/apps/web/src/clientPersistenceStorage.test.ts @@ -1,7 +1,7 @@ import { EnvironmentId, type PersistedSavedEnvironmentRecord } from "@t3tools/contracts"; import { afterEach, describe, expect, it, vi } from "vitest"; -const testEnvironmentId = EnvironmentId.makeUnsafe("environment-1"); +const testEnvironmentId = EnvironmentId.make("environment-1"); const savedRegistryRecord: PersistedSavedEnvironmentRecord = { environmentId: testEnvironmentId, diff --git a/apps/web/src/components/BranchToolbar.logic.test.ts b/apps/web/src/components/BranchToolbar.logic.test.ts index 6137b77c524c54f6ae44117ea89268ae0a58487c..faf21d636cf8f0f2b88f4a8dafa6fa1c02f138af 100644 --- a/apps/web/src/components/BranchToolbar.logic.test.ts +++ b/apps/web/src/components/BranchToolbar.logic.test.ts @@ -13,8 +13,8 @@ import { shouldIncludeBranchPickerItem, } from "./BranchToolbar.logic"; -const localEnvironmentId = EnvironmentId.makeUnsafe("environment-local"); -const remoteEnvironmentId = EnvironmentId.makeUnsafe("environment-remote"); +const localEnvironmentId = EnvironmentId.make("environment-local"); +const remoteEnvironmentId = EnvironmentId.make("environment-remote"); describe("resolveDraftEnvModeAfterBranchChange", () => { it("switches to local mode when returning from an existing worktree to the main worktree", () => { diff --git a/apps/web/src/components/ChatView.browser.tsx b/apps/web/src/components/ChatView.browser.tsx index de51449704540eb07b225d1eb8380023f4a1789a..2261684dd9caac6543236754dc63d10924a0cdb9 100644 --- a/apps/web/src/components/ChatView.browser.tsx +++ b/apps/web/src/components/ChatView.browser.tsx @@ -58,7 +58,7 @@ vi.mock("../lib/gitStatusState", () => ({ const THREAD_ID = "thread-browser-test" as ThreadId; const PROJECT_ID = "project-1" as ProjectId; -const LOCAL_ENVIRONMENT_ID = EnvironmentId.makeUnsafe("environment-local"); +const LOCAL_ENVIRONMENT_ID = EnvironmentId.make("environment-local"); const THREAD_REF = scopeThreadRef(LOCAL_ENVIRONMENT_ID, THREAD_ID); const THREAD_KEY = scopedThreadKey(THREAD_REF); const UUID_ROUTE_RE = /^\/draft\/[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/; @@ -143,7 +143,7 @@ function isoAt(offsetSeconds: number): string { function createBaseServerConfig(): ServerConfig { return { environment: { - environmentId: EnvironmentId.makeUnsafe("environment-local"), + environmentId: EnvironmentId.make("environment-local"), label: "Local environment", platform: { os: "darwin" as const, arch: "arm64" as const }, serverVersion: "0.0.0-test", @@ -341,7 +341,7 @@ function buildFixture(snapshot: OrchestrationReadModel): TestFixture { serverConfig: createBaseServerConfig(), welcome: { environment: { - environmentId: EnvironmentId.makeUnsafe("environment-local"), + environmentId: EnvironmentId.make("environment-local"), label: "Local environment", platform: { os: "darwin" as const, arch: "arm64" as const }, serverVersion: "0.0.0-test", @@ -402,7 +402,7 @@ function addThreadToSnapshot( function createThreadCreatedEvent(threadId: ThreadId, sequence: number): OrchestrationEvent { return { sequence, - eventId: EventId.makeUnsafe(`event-thread-created-${sequence}`), + eventId: EventId.make(`event-thread-created-${sequence}`), aggregateKind: "thread", aggregateId: threadId, occurredAt: NOW_ISO, @@ -432,7 +432,7 @@ function createThreadCreatedEvent(threadId: ThreadId, sequence: number): Orchest function createThreadSessionSetEvent(threadId: ThreadId, sequence: number): OrchestrationEvent { return { sequence, - eventId: EventId.makeUnsafe(`event-thread-session-set-${sequence}`), + eventId: EventId.make(`event-thread-session-set-${sequence}`), aggregateKind: "thread", aggregateId: threadId, occurredAt: NOW_ISO, @@ -498,7 +498,7 @@ function draftIdFromPath(pathname: string) { if (!draftId) { throw new Error(`Expected thread path, received "${pathname}".`); } - return DraftId.makeUnsafe(draftId); + return DraftId.make(draftId); } function draftThreadIdFor(draftId: ReturnType): ThreadId { @@ -666,7 +666,7 @@ function createSnapshotWithPendingUserInput(): OrchestrationReadModel { interactionMode: "plan", activities: [ { - id: EventId.makeUnsafe("activity-user-input-requested"), + id: EventId.make("activity-user-input-requested"), tone: "info", kind: "user-input.requested", summary: "User input requested", diff --git a/apps/web/src/components/ChatView.logic.test.ts b/apps/web/src/components/ChatView.logic.test.ts index ce82b3f77c547f640505117d3a02692fd91c50c6..1b96265a40e147485e39518dd9ab8aecad5ab043 100644 --- a/apps/web/src/components/ChatView.logic.test.ts +++ b/apps/web/src/components/ChatView.logic.test.ts @@ -15,7 +15,7 @@ import { waitForStartedServerThread, } from "./ChatView.logic"; -const localEnvironmentId = EnvironmentId.makeUnsafe("environment-local"); +const localEnvironmentId = EnvironmentId.make("environment-local"); describe("deriveComposerSendState", () => { it("treats expired terminal pills as non-sendable content", () => { @@ -25,7 +25,7 @@ describe("deriveComposerSendState", () => { terminalContexts: [ { id: "ctx-expired", - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), terminalId: "default", terminalLabel: "Terminal 1", lineStart: 4, @@ -49,7 +49,7 @@ describe("deriveComposerSendState", () => { terminalContexts: [ { id: "ctx-expired", - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), terminalId: "default", terminalLabel: "Terminal 1", lineStart: 4, @@ -86,23 +86,20 @@ describe("reconcileMountedTerminalThreadIds", () => { it("keeps previously mounted open threads and adds the active open thread", () => { expect( reconcileMountedTerminalThreadIds({ - currentThreadIds: [ - ThreadId.makeUnsafe("thread-hidden"), - ThreadId.makeUnsafe("thread-stale"), - ], - openThreadIds: [ThreadId.makeUnsafe("thread-hidden"), ThreadId.makeUnsafe("thread-active")], - activeThreadId: ThreadId.makeUnsafe("thread-active"), + currentThreadIds: [ThreadId.make("thread-hidden"), ThreadId.make("thread-stale")], + openThreadIds: [ThreadId.make("thread-hidden"), ThreadId.make("thread-active")], + activeThreadId: ThreadId.make("thread-active"), activeThreadTerminalOpen: true, }), - ).toEqual([ThreadId.makeUnsafe("thread-hidden"), ThreadId.makeUnsafe("thread-active")]); + ).toEqual([ThreadId.make("thread-hidden"), ThreadId.make("thread-active")]); }); it("drops mounted threads once their terminal drawer is no longer open", () => { expect( reconcileMountedTerminalThreadIds({ - currentThreadIds: [ThreadId.makeUnsafe("thread-closed")], + currentThreadIds: [ThreadId.make("thread-closed")], openThreadIds: [], - activeThreadId: ThreadId.makeUnsafe("thread-closed"), + activeThreadId: ThreadId.make("thread-closed"), activeThreadTerminalOpen: false, }), ).toEqual([]); @@ -112,55 +109,47 @@ describe("reconcileMountedTerminalThreadIds", () => { expect( reconcileMountedTerminalThreadIds({ currentThreadIds: [ - ThreadId.makeUnsafe("thread-1"), - ThreadId.makeUnsafe("thread-2"), - ThreadId.makeUnsafe("thread-3"), + ThreadId.make("thread-1"), + ThreadId.make("thread-2"), + ThreadId.make("thread-3"), ], openThreadIds: [ - ThreadId.makeUnsafe("thread-1"), - ThreadId.makeUnsafe("thread-2"), - ThreadId.makeUnsafe("thread-3"), - ThreadId.makeUnsafe("thread-4"), + ThreadId.make("thread-1"), + ThreadId.make("thread-2"), + ThreadId.make("thread-3"), + ThreadId.make("thread-4"), ], - activeThreadId: ThreadId.makeUnsafe("thread-4"), + activeThreadId: ThreadId.make("thread-4"), activeThreadTerminalOpen: true, maxHiddenThreadCount: 2, }), - ).toEqual([ - ThreadId.makeUnsafe("thread-2"), - ThreadId.makeUnsafe("thread-3"), - ThreadId.makeUnsafe("thread-4"), - ]); + ).toEqual([ThreadId.make("thread-2"), ThreadId.make("thread-3"), ThreadId.make("thread-4")]); }); it("moves the active thread to the end so it is treated as most recently used", () => { expect( reconcileMountedTerminalThreadIds({ currentThreadIds: [ - ThreadId.makeUnsafe("thread-a"), - ThreadId.makeUnsafe("thread-b"), - ThreadId.makeUnsafe("thread-c"), + ThreadId.make("thread-a"), + ThreadId.make("thread-b"), + ThreadId.make("thread-c"), ], openThreadIds: [ - ThreadId.makeUnsafe("thread-a"), - ThreadId.makeUnsafe("thread-b"), - ThreadId.makeUnsafe("thread-c"), + ThreadId.make("thread-a"), + ThreadId.make("thread-b"), + ThreadId.make("thread-c"), ], - activeThreadId: ThreadId.makeUnsafe("thread-a"), + activeThreadId: ThreadId.make("thread-a"), activeThreadTerminalOpen: true, maxHiddenThreadCount: 2, }), - ).toEqual([ - ThreadId.makeUnsafe("thread-b"), - ThreadId.makeUnsafe("thread-c"), - ThreadId.makeUnsafe("thread-a"), - ]); + ).toEqual([ThreadId.make("thread-b"), ThreadId.make("thread-c"), ThreadId.make("thread-a")]); }); it("defaults to the hidden mounted terminal cap", () => { const currentThreadIds = Array.from( { length: MAX_HIDDEN_MOUNTED_TERMINAL_THREADS + 2 }, - (_, index) => ThreadId.makeUnsafe(`thread-${index + 1}`), + (_, index) => ThreadId.make(`thread-${index + 1}`), ); expect( @@ -176,7 +165,7 @@ describe("reconcileMountedTerminalThreadIds", () => { describe("shouldWriteThreadErrorToCurrentServerThread", () => { it("routes errors to the active server thread when route and target match", () => { - const threadId = ThreadId.makeUnsafe("thread-1"); + const threadId = ThreadId.make("thread-1"); const routeThreadRef = scopeThreadRef(localEnvironmentId, threadId); expect( @@ -192,7 +181,7 @@ describe("shouldWriteThreadErrorToCurrentServerThread", () => { }); it("does not route draft-thread errors into server-backed state", () => { - const threadId = ThreadId.makeUnsafe("thread-1"); + const threadId = ThreadId.make("thread-1"); expect( shouldWriteThreadErrorToCurrentServerThread({ @@ -214,10 +203,10 @@ const makeThread = (input?: { completedAt: string | null; } | null; }): Thread => ({ - id: input?.id ?? ThreadId.makeUnsafe("thread-1"), + id: input?.id ?? ThreadId.make("thread-1"), environmentId: localEnvironmentId, codexThreadId: null, - projectId: ProjectId.makeUnsafe("project-1"), + projectId: ProjectId.make("project-1"), title: "Thread", modelSelection: { provider: "codex" as const, model: "gpt-5.4" }, runtimeMode: "full-access" as const, @@ -242,7 +231,7 @@ const makeThread = (input?: { }); function setStoreThreads(threads: ReadonlyArray>) { - const projectId = ProjectId.makeUnsafe("project-1"); + const projectId = ProjectId.make("project-1"); const environmentState: EnvironmentState = { projectIds: [projectId], projectById: { @@ -355,12 +344,12 @@ afterEach(() => { describe("waitForStartedServerThread", () => { it("resolves immediately when the thread is already started", async () => { - const threadId = ThreadId.makeUnsafe("thread-started"); + const threadId = ThreadId.make("thread-started"); setStoreThreads([ makeThread({ id: threadId, latestTurn: { - turnId: TurnId.makeUnsafe("turn-started"), + turnId: TurnId.make("turn-started"), state: "running", requestedAt: "2026-03-29T00:00:01.000Z", startedAt: "2026-03-29T00:00:01.000Z", @@ -375,7 +364,7 @@ describe("waitForStartedServerThread", () => { }); it("waits for the thread to start via subscription updates", async () => { - const threadId = ThreadId.makeUnsafe("thread-wait"); + const threadId = ThreadId.make("thread-wait"); setStoreThreads([makeThread({ id: threadId })]); const promise = waitForStartedServerThread(scopeThreadRef(localEnvironmentId, threadId), 500); @@ -384,7 +373,7 @@ describe("waitForStartedServerThread", () => { makeThread({ id: threadId, latestTurn: { - turnId: TurnId.makeUnsafe("turn-started"), + turnId: TurnId.make("turn-started"), state: "running", requestedAt: "2026-03-29T00:00:01.000Z", startedAt: "2026-03-29T00:00:01.000Z", @@ -397,7 +386,7 @@ describe("waitForStartedServerThread", () => { }); it("handles the thread starting between the initial read and subscription setup", async () => { - const threadId = ThreadId.makeUnsafe("thread-race"); + const threadId = ThreadId.make("thread-race"); setStoreThreads([makeThread({ id: threadId })]); const originalSubscribe = useStore.subscribe.bind(useStore); @@ -409,7 +398,7 @@ describe("waitForStartedServerThread", () => { makeThread({ id: threadId, latestTurn: { - turnId: TurnId.makeUnsafe("turn-race"), + turnId: TurnId.make("turn-race"), state: "running", requestedAt: "2026-03-29T00:00:01.000Z", startedAt: "2026-03-29T00:00:01.000Z", @@ -429,7 +418,7 @@ describe("waitForStartedServerThread", () => { it("returns false after the timeout when the thread never starts", async () => { vi.useFakeTimers(); - const threadId = ThreadId.makeUnsafe("thread-timeout"); + const threadId = ThreadId.make("thread-timeout"); setStoreThreads([makeThread({ id: threadId })]); const promise = waitForStartedServerThread(scopeThreadRef(localEnvironmentId, threadId), 500); @@ -440,9 +429,9 @@ describe("waitForStartedServerThread", () => { }); describe("hasServerAcknowledgedLocalDispatch", () => { - const projectId = ProjectId.makeUnsafe("project-1"); + const projectId = ProjectId.make("project-1"); const previousLatestTurn = { - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), state: "completed" as const, requestedAt: "2026-03-29T00:00:00.000Z", startedAt: "2026-03-29T00:00:01.000Z", @@ -460,7 +449,7 @@ describe("hasServerAcknowledgedLocalDispatch", () => { it("does not clear local dispatch before server state changes", () => { const localDispatch = createLocalDispatchSnapshot({ - id: ThreadId.makeUnsafe("thread-1"), + id: ThreadId.make("thread-1"), environmentId: localEnvironmentId, codexThreadId: null, projectId, @@ -497,7 +486,7 @@ describe("hasServerAcknowledgedLocalDispatch", () => { it("clears local dispatch when a new turn is already settled", () => { const localDispatch = createLocalDispatchSnapshot({ - id: ThreadId.makeUnsafe("thread-1"), + id: ThreadId.make("thread-1"), environmentId: localEnvironmentId, codexThreadId: null, projectId, @@ -525,7 +514,7 @@ describe("hasServerAcknowledgedLocalDispatch", () => { phase: "ready", latestTurn: { ...previousLatestTurn, - turnId: TurnId.makeUnsafe("turn-2"), + turnId: TurnId.make("turn-2"), requestedAt: "2026-03-29T00:01:00.000Z", startedAt: "2026-03-29T00:01:01.000Z", completedAt: "2026-03-29T00:01:30.000Z", @@ -543,7 +532,7 @@ describe("hasServerAcknowledgedLocalDispatch", () => { it("clears local dispatch when the session changes without an observed running phase", () => { const localDispatch = createLocalDispatchSnapshot({ - id: ThreadId.makeUnsafe("thread-1"), + id: ThreadId.make("thread-1"), environmentId: localEnvironmentId, codexThreadId: null, projectId, diff --git a/apps/web/src/components/GitActionsControl.browser.tsx b/apps/web/src/components/GitActionsControl.browser.tsx index 71131d6696e14e36f4ce87eaeb95470e4c2ce532..c54e63f54ffbaee1b137df853eea23ab9ffaff55 100644 --- a/apps/web/src/components/GitActionsControl.browser.tsx +++ b/apps/web/src/components/GitActionsControl.browser.tsx @@ -4,7 +4,7 @@ import { useState } from "react"; import { afterEach, describe, expect, it, vi } from "vitest"; import { render } from "vitest-browser-react"; -const SHARED_THREAD_ID = ThreadId.makeUnsafe("thread-shared"); +const SHARED_THREAD_ID = ThreadId.make("thread-shared"); const ENVIRONMENT_A = "environment-local" as never; const ENVIRONMENT_B = "environment-remote" as never; const GIT_CWD = "/repo/project"; diff --git a/apps/web/src/components/KeybindingsToast.browser.tsx b/apps/web/src/components/KeybindingsToast.browser.tsx index 68450256fe193267cf5fc4d7c286173e96accd59..32f2f68e4afa7131c254e3ded17f8fb731fbeab4 100644 --- a/apps/web/src/components/KeybindingsToast.browser.tsx +++ b/apps/web/src/components/KeybindingsToast.browser.tsx @@ -37,7 +37,7 @@ vi.mock("../lib/gitStatusState", () => ({ const THREAD_ID = "thread-kb-toast-test" as ThreadId; const PROJECT_ID = "project-1" as ProjectId; -const LOCAL_ENVIRONMENT_ID = EnvironmentId.makeUnsafe("environment-local"); +const LOCAL_ENVIRONMENT_ID = EnvironmentId.make("environment-local"); const NOW_ISO = "2026-03-04T12:00:00.000Z"; interface TestFixture { diff --git a/apps/web/src/components/Sidebar.logic.test.ts b/apps/web/src/components/Sidebar.logic.test.ts index f9e5561a50cf543ccfaca4084ce766ff9d060190..282d7f9c4dbaebb6a18e73615d95a9c3576549b0 100644 --- a/apps/web/src/components/Sidebar.logic.test.ts +++ b/apps/web/src/components/Sidebar.logic.test.ts @@ -28,7 +28,7 @@ import { type Thread, } from "../types"; -const localEnvironmentId = EnvironmentId.makeUnsafe("environment-local"); +const localEnvironmentId = EnvironmentId.make("environment-local"); function makeLatestTurn(overrides?: { completedAt?: string | null; @@ -235,42 +235,42 @@ describe("orderItemsByPreferredIds", () => { it("keeps preferred ids first, skips stale ids, and preserves the relative order of remaining items", () => { const ordered = orderItemsByPreferredIds({ items: [ - { id: ProjectId.makeUnsafe("project-1"), name: "One" }, - { id: ProjectId.makeUnsafe("project-2"), name: "Two" }, - { id: ProjectId.makeUnsafe("project-3"), name: "Three" }, + { id: ProjectId.make("project-1"), name: "One" }, + { id: ProjectId.make("project-2"), name: "Two" }, + { id: ProjectId.make("project-3"), name: "Three" }, ], preferredIds: [ - ProjectId.makeUnsafe("project-3"), - ProjectId.makeUnsafe("project-missing"), - ProjectId.makeUnsafe("project-1"), + ProjectId.make("project-3"), + ProjectId.make("project-missing"), + ProjectId.make("project-1"), ], getId: (project) => project.id, }); expect(ordered.map((project) => project.id)).toEqual([ - ProjectId.makeUnsafe("project-3"), - ProjectId.makeUnsafe("project-1"), - ProjectId.makeUnsafe("project-2"), + ProjectId.make("project-3"), + ProjectId.make("project-1"), + ProjectId.make("project-2"), ]); }); it("does not duplicate items when preferred ids repeat", () => { const ordered = orderItemsByPreferredIds({ items: [ - { id: ProjectId.makeUnsafe("project-1"), name: "One" }, - { id: ProjectId.makeUnsafe("project-2"), name: "Two" }, + { id: ProjectId.make("project-1"), name: "One" }, + { id: ProjectId.make("project-2"), name: "Two" }, ], preferredIds: [ - ProjectId.makeUnsafe("project-2"), - ProjectId.makeUnsafe("project-1"), - ProjectId.makeUnsafe("project-2"), + ProjectId.make("project-2"), + ProjectId.make("project-1"), + ProjectId.make("project-2"), ], getId: (project) => project.id, }); expect(ordered.map((project) => project.id)).toEqual([ - ProjectId.makeUnsafe("project-2"), - ProjectId.makeUnsafe("project-1"), + ProjectId.make("project-2"), + ProjectId.make("project-1"), ]); }); }); @@ -278,9 +278,9 @@ describe("orderItemsByPreferredIds", () => { describe("resolveAdjacentThreadId", () => { it("resolves adjacent thread ids in ordered sidebar traversal", () => { const threads = [ - ThreadId.makeUnsafe("thread-1"), - ThreadId.makeUnsafe("thread-2"), - ThreadId.makeUnsafe("thread-3"), + ThreadId.make("thread-1"), + ThreadId.make("thread-2"), + ThreadId.make("thread-3"), ]; expect( @@ -327,21 +327,21 @@ describe("getVisibleSidebarThreadIds", () => { getVisibleSidebarThreadIds([ { renderedThreadIds: [ - ThreadId.makeUnsafe("thread-12"), - ThreadId.makeUnsafe("thread-11"), - ThreadId.makeUnsafe("thread-10"), + ThreadId.make("thread-12"), + ThreadId.make("thread-11"), + ThreadId.make("thread-10"), ], }, { - renderedThreadIds: [ThreadId.makeUnsafe("thread-8"), ThreadId.makeUnsafe("thread-6")], + renderedThreadIds: [ThreadId.make("thread-8"), ThreadId.make("thread-6")], }, ]), ).toEqual([ - ThreadId.makeUnsafe("thread-12"), - ThreadId.makeUnsafe("thread-11"), - ThreadId.makeUnsafe("thread-10"), - ThreadId.makeUnsafe("thread-8"), - ThreadId.makeUnsafe("thread-6"), + ThreadId.make("thread-12"), + ThreadId.make("thread-11"), + ThreadId.make("thread-10"), + ThreadId.make("thread-8"), + ThreadId.make("thread-6"), ]); }); @@ -350,17 +350,14 @@ describe("getVisibleSidebarThreadIds", () => { getVisibleSidebarThreadIds([ { shouldShowThreadPanel: false, - renderedThreadIds: [ - ThreadId.makeUnsafe("thread-hidden-2"), - ThreadId.makeUnsafe("thread-hidden-1"), - ], + renderedThreadIds: [ThreadId.make("thread-hidden-2"), ThreadId.make("thread-hidden-1")], }, { shouldShowThreadPanel: true, - renderedThreadIds: [ThreadId.makeUnsafe("thread-12"), ThreadId.makeUnsafe("thread-11")], + renderedThreadIds: [ThreadId.make("thread-12"), ThreadId.make("thread-11")], }, ]), - ).toEqual([ThreadId.makeUnsafe("thread-12"), ThreadId.makeUnsafe("thread-11")]); + ).toEqual([ThreadId.make("thread-12"), ThreadId.make("thread-11")]); }); }); @@ -574,43 +571,41 @@ describe("getVisibleThreadsForProject", () => { it("includes the active thread even when it falls below the folded preview", () => { const threads = Array.from({ length: 8 }, (_, index) => makeThread({ - id: ThreadId.makeUnsafe(`thread-${index + 1}`), + id: ThreadId.make(`thread-${index + 1}`), title: `Thread ${index + 1}`, }), ); const result = getVisibleThreadsForProject({ threads, - activeThreadId: ThreadId.makeUnsafe("thread-8"), + activeThreadId: ThreadId.make("thread-8"), isThreadListExpanded: false, previewLimit: 6, }); expect(result.hasHiddenThreads).toBe(true); expect(result.visibleThreads.map((thread) => thread.id)).toEqual([ - ThreadId.makeUnsafe("thread-1"), - ThreadId.makeUnsafe("thread-2"), - ThreadId.makeUnsafe("thread-3"), - ThreadId.makeUnsafe("thread-4"), - ThreadId.makeUnsafe("thread-5"), - ThreadId.makeUnsafe("thread-6"), - ThreadId.makeUnsafe("thread-8"), - ]); - expect(result.hiddenThreads.map((thread) => thread.id)).toEqual([ - ThreadId.makeUnsafe("thread-7"), + ThreadId.make("thread-1"), + ThreadId.make("thread-2"), + ThreadId.make("thread-3"), + ThreadId.make("thread-4"), + ThreadId.make("thread-5"), + ThreadId.make("thread-6"), + ThreadId.make("thread-8"), ]); + expect(result.hiddenThreads.map((thread) => thread.id)).toEqual([ThreadId.make("thread-7")]); }); it("returns all threads when the list is expanded", () => { const threads = Array.from({ length: 8 }, (_, index) => makeThread({ - id: ThreadId.makeUnsafe(`thread-${index + 1}`), + id: ThreadId.make(`thread-${index + 1}`), }), ); const result = getVisibleThreadsForProject({ threads, - activeThreadId: ThreadId.makeUnsafe("thread-8"), + activeThreadId: ThreadId.make("thread-8"), isThreadListExpanded: true, previewLimit: 6, }); @@ -626,7 +621,7 @@ describe("getVisibleThreadsForProject", () => { function makeProject(overrides: Partial = {}): Project { const { defaultModelSelection, ...rest } = overrides; return { - id: ProjectId.makeUnsafe("project-1"), + id: ProjectId.make("project-1"), environmentId: localEnvironmentId, name: "Project", cwd: "/tmp/project", @@ -644,10 +639,10 @@ function makeProject(overrides: Partial = {}): Project { function makeThread(overrides: Partial = {}): Thread { return { - id: ThreadId.makeUnsafe("thread-1"), + id: ThreadId.make("thread-1"), environmentId: localEnvironmentId, codexThreadId: null, - projectId: ProjectId.makeUnsafe("project-1"), + projectId: ProjectId.make("project-1"), title: "Thread", modelSelection: { provider: "codex", @@ -677,7 +672,7 @@ describe("sortThreadsForSidebar", () => { const sorted = sortThreadsForSidebar( [ makeThread({ - id: ThreadId.makeUnsafe("thread-1"), + id: ThreadId.make("thread-1"), createdAt: "2026-03-09T10:00:00.000Z", updatedAt: "2026-03-09T10:10:00.000Z", messages: [ @@ -692,7 +687,7 @@ describe("sortThreadsForSidebar", () => { ], }), makeThread({ - id: ThreadId.makeUnsafe("thread-2"), + id: ThreadId.make("thread-2"), createdAt: "2026-03-09T10:05:00.000Z", updatedAt: "2026-03-09T10:05:00.000Z", messages: [ @@ -711,8 +706,8 @@ describe("sortThreadsForSidebar", () => { ); expect(sorted.map((thread) => thread.id)).toEqual([ - ThreadId.makeUnsafe("thread-2"), - ThreadId.makeUnsafe("thread-1"), + ThreadId.make("thread-2"), + ThreadId.make("thread-1"), ]); }); @@ -720,7 +715,7 @@ describe("sortThreadsForSidebar", () => { const sorted = sortThreadsForSidebar( [ makeThread({ - id: ThreadId.makeUnsafe("thread-1"), + id: ThreadId.make("thread-1"), createdAt: "2026-03-09T10:00:00.000Z", updatedAt: "2026-03-09T10:01:00.000Z", messages: [ @@ -735,7 +730,7 @@ describe("sortThreadsForSidebar", () => { ], }), makeThread({ - id: ThreadId.makeUnsafe("thread-2"), + id: ThreadId.make("thread-2"), createdAt: "2026-03-09T10:05:00.000Z", updatedAt: "2026-03-09T10:05:00.000Z", messages: [], @@ -745,8 +740,8 @@ describe("sortThreadsForSidebar", () => { ); expect(sorted.map((thread) => thread.id)).toEqual([ - ThreadId.makeUnsafe("thread-2"), - ThreadId.makeUnsafe("thread-1"), + ThreadId.make("thread-2"), + ThreadId.make("thread-1"), ]); }); @@ -754,13 +749,13 @@ describe("sortThreadsForSidebar", () => { const sorted = sortThreadsForSidebar( [ makeThread({ - id: ThreadId.makeUnsafe("thread-1"), + id: ThreadId.make("thread-1"), createdAt: "" as never, updatedAt: undefined, messages: [], }), makeThread({ - id: ThreadId.makeUnsafe("thread-2"), + id: ThreadId.make("thread-2"), createdAt: "" as never, updatedAt: undefined, messages: [], @@ -770,8 +765,8 @@ describe("sortThreadsForSidebar", () => { ); expect(sorted.map((thread) => thread.id)).toEqual([ - ThreadId.makeUnsafe("thread-2"), - ThreadId.makeUnsafe("thread-1"), + ThreadId.make("thread-2"), + ThreadId.make("thread-1"), ]); }); @@ -779,12 +774,12 @@ describe("sortThreadsForSidebar", () => { const sorted = sortThreadsForSidebar( [ makeThread({ - id: ThreadId.makeUnsafe("thread-1"), + id: ThreadId.make("thread-1"), createdAt: "2026-03-09T10:05:00.000Z", updatedAt: "2026-03-09T10:05:00.000Z", }), makeThread({ - id: ThreadId.makeUnsafe("thread-2"), + id: ThreadId.make("thread-2"), createdAt: "2026-03-09T10:00:00.000Z", updatedAt: "2026-03-09T10:10:00.000Z", }), @@ -793,8 +788,8 @@ describe("sortThreadsForSidebar", () => { ); expect(sorted.map((thread) => thread.id)).toEqual([ - ThreadId.makeUnsafe("thread-1"), - ThreadId.makeUnsafe("thread-2"), + ThreadId.make("thread-1"), + ThreadId.make("thread-2"), ]); }); }); @@ -804,80 +799,77 @@ describe("getFallbackThreadIdAfterDelete", () => { const fallbackThreadId = getFallbackThreadIdAfterDelete({ threads: [ makeThread({ - id: ThreadId.makeUnsafe("thread-oldest"), - projectId: ProjectId.makeUnsafe("project-1"), + id: ThreadId.make("thread-oldest"), + projectId: ProjectId.make("project-1"), createdAt: "2026-03-09T10:00:00.000Z", messages: [], }), makeThread({ - id: ThreadId.makeUnsafe("thread-active"), - projectId: ProjectId.makeUnsafe("project-1"), + id: ThreadId.make("thread-active"), + projectId: ProjectId.make("project-1"), createdAt: "2026-03-09T10:05:00.000Z", messages: [], }), makeThread({ - id: ThreadId.makeUnsafe("thread-newest"), - projectId: ProjectId.makeUnsafe("project-1"), + id: ThreadId.make("thread-newest"), + projectId: ProjectId.make("project-1"), createdAt: "2026-03-09T10:10:00.000Z", messages: [], }), makeThread({ - id: ThreadId.makeUnsafe("thread-other-project"), - projectId: ProjectId.makeUnsafe("project-2"), + id: ThreadId.make("thread-other-project"), + projectId: ProjectId.make("project-2"), createdAt: "2026-03-09T10:20:00.000Z", messages: [], }), ], - deletedThreadId: ThreadId.makeUnsafe("thread-active"), + deletedThreadId: ThreadId.make("thread-active"), sortOrder: "created_at", }); - expect(fallbackThreadId).toBe(ThreadId.makeUnsafe("thread-newest")); + expect(fallbackThreadId).toBe(ThreadId.make("thread-newest")); }); it("skips other threads being deleted in the same action", () => { const fallbackThreadId = getFallbackThreadIdAfterDelete({ threads: [ makeThread({ - id: ThreadId.makeUnsafe("thread-active"), - projectId: ProjectId.makeUnsafe("project-1"), + id: ThreadId.make("thread-active"), + projectId: ProjectId.make("project-1"), createdAt: "2026-03-09T10:05:00.000Z", messages: [], }), makeThread({ - id: ThreadId.makeUnsafe("thread-newest"), - projectId: ProjectId.makeUnsafe("project-1"), + id: ThreadId.make("thread-newest"), + projectId: ProjectId.make("project-1"), createdAt: "2026-03-09T10:10:00.000Z", messages: [], }), makeThread({ - id: ThreadId.makeUnsafe("thread-next"), - projectId: ProjectId.makeUnsafe("project-1"), + id: ThreadId.make("thread-next"), + projectId: ProjectId.make("project-1"), createdAt: "2026-03-09T10:07:00.000Z", messages: [], }), ], - deletedThreadId: ThreadId.makeUnsafe("thread-active"), - deletedThreadIds: new Set([ - ThreadId.makeUnsafe("thread-active"), - ThreadId.makeUnsafe("thread-newest"), - ]), + deletedThreadId: ThreadId.make("thread-active"), + deletedThreadIds: new Set([ThreadId.make("thread-active"), ThreadId.make("thread-newest")]), sortOrder: "created_at", }); - expect(fallbackThreadId).toBe(ThreadId.makeUnsafe("thread-next")); + expect(fallbackThreadId).toBe(ThreadId.make("thread-next")); }); }); describe("sortProjectsForSidebar", () => { it("sorts projects by the most recent user message across their threads", () => { const projects = [ - makeProject({ id: ProjectId.makeUnsafe("project-1"), name: "Older project" }), - makeProject({ id: ProjectId.makeUnsafe("project-2"), name: "Newer project" }), + makeProject({ id: ProjectId.make("project-1"), name: "Older project" }), + makeProject({ id: ProjectId.make("project-2"), name: "Newer project" }), ]; const threads = [ makeThread({ - projectId: ProjectId.makeUnsafe("project-1"), + projectId: ProjectId.make("project-1"), updatedAt: "2026-03-09T10:20:00.000Z", messages: [ { @@ -891,8 +883,8 @@ describe("sortProjectsForSidebar", () => { ], }), makeThread({ - id: ThreadId.makeUnsafe("thread-2"), - projectId: ProjectId.makeUnsafe("project-2"), + id: ThreadId.make("thread-2"), + projectId: ProjectId.make("project-2"), updatedAt: "2026-03-09T10:05:00.000Z", messages: [ { @@ -910,8 +902,8 @@ describe("sortProjectsForSidebar", () => { const sorted = sortProjectsForSidebar(projects, threads, "updated_at"); expect(sorted.map((project) => project.id)).toEqual([ - ProjectId.makeUnsafe("project-2"), - ProjectId.makeUnsafe("project-1"), + ProjectId.make("project-2"), + ProjectId.make("project-1"), ]); }); @@ -919,12 +911,12 @@ describe("sortProjectsForSidebar", () => { const sorted = sortProjectsForSidebar( [ makeProject({ - id: ProjectId.makeUnsafe("project-1"), + id: ProjectId.make("project-1"), name: "Older project", updatedAt: "2026-03-09T10:01:00.000Z", }), makeProject({ - id: ProjectId.makeUnsafe("project-2"), + id: ProjectId.make("project-2"), name: "Newer project", updatedAt: "2026-03-09T10:05:00.000Z", }), @@ -934,8 +926,8 @@ describe("sortProjectsForSidebar", () => { ); expect(sorted.map((project) => project.id)).toEqual([ - ProjectId.makeUnsafe("project-2"), - ProjectId.makeUnsafe("project-1"), + ProjectId.make("project-2"), + ProjectId.make("project-1"), ]); }); @@ -943,13 +935,13 @@ describe("sortProjectsForSidebar", () => { const sorted = sortProjectsForSidebar( [ makeProject({ - id: ProjectId.makeUnsafe("project-2"), + id: ProjectId.make("project-2"), name: "Beta", createdAt: undefined, updatedAt: undefined, }), makeProject({ - id: ProjectId.makeUnsafe("project-1"), + id: ProjectId.make("project-1"), name: "Alpha", createdAt: undefined, updatedAt: undefined, @@ -960,22 +952,22 @@ describe("sortProjectsForSidebar", () => { ); expect(sorted.map((project) => project.id)).toEqual([ - ProjectId.makeUnsafe("project-1"), - ProjectId.makeUnsafe("project-2"), + ProjectId.make("project-1"), + ProjectId.make("project-2"), ]); }); it("preserves manual project ordering", () => { const projects = [ - makeProject({ id: ProjectId.makeUnsafe("project-2"), name: "Second" }), - makeProject({ id: ProjectId.makeUnsafe("project-1"), name: "First" }), + makeProject({ id: ProjectId.make("project-2"), name: "Second" }), + makeProject({ id: ProjectId.make("project-1"), name: "First" }), ]; const sorted = sortProjectsForSidebar(projects, [], "manual"); expect(sorted.map((project) => project.id)).toEqual([ - ProjectId.makeUnsafe("project-2"), - ProjectId.makeUnsafe("project-1"), + ProjectId.make("project-2"), + ProjectId.make("project-1"), ]); }); @@ -983,26 +975,26 @@ describe("sortProjectsForSidebar", () => { const sorted = sortProjectsForSidebar( [ makeProject({ - id: ProjectId.makeUnsafe("project-1"), + id: ProjectId.make("project-1"), name: "Visible project", updatedAt: "2026-03-09T10:01:00.000Z", }), makeProject({ - id: ProjectId.makeUnsafe("project-2"), + id: ProjectId.make("project-2"), name: "Archived-only project", updatedAt: "2026-03-09T10:00:00.000Z", }), ], [ makeThread({ - id: ThreadId.makeUnsafe("thread-visible"), - projectId: ProjectId.makeUnsafe("project-1"), + id: ThreadId.make("thread-visible"), + projectId: ProjectId.make("project-1"), updatedAt: "2026-03-09T10:02:00.000Z", archivedAt: null, }), makeThread({ - id: ThreadId.makeUnsafe("thread-archived"), - projectId: ProjectId.makeUnsafe("project-2"), + id: ThreadId.make("thread-archived"), + projectId: ProjectId.make("project-2"), updatedAt: "2026-03-09T10:10:00.000Z", archivedAt: "2026-03-09T10:11:00.000Z", }), @@ -1011,8 +1003,8 @@ describe("sortProjectsForSidebar", () => { ); expect(sorted.map((project) => project.id)).toEqual([ - ProjectId.makeUnsafe("project-1"), - ProjectId.makeUnsafe("project-2"), + ProjectId.make("project-1"), + ProjectId.make("project-2"), ]); }); diff --git a/apps/web/src/components/ThreadTerminalDrawer.browser.tsx b/apps/web/src/components/ThreadTerminalDrawer.browser.tsx index 599f85a1c8b868d7954e8747e92323a10cd8718b..37e0df1cc4b52596af953a2cb0cc85802df90227 100644 --- a/apps/web/src/components/ThreadTerminalDrawer.browser.tsx +++ b/apps/web/src/components/ThreadTerminalDrawer.browser.tsx @@ -121,7 +121,7 @@ vi.mock("~/localApi", () => ({ import { TerminalViewport } from "./ThreadTerminalDrawer"; -const THREAD_ID = ThreadId.makeUnsafe("thread-terminal-browser"); +const THREAD_ID = ThreadId.make("thread-terminal-browser"); function createEnvironmentApi() { return { diff --git a/apps/web/src/components/chat/ChangedFilesTree.test.tsx b/apps/web/src/components/chat/ChangedFilesTree.test.tsx index 5b72fd237d30b317befc0cc441067cc8d2d2bc33..4e2a12ee12ad17580d43decfc45a625ee12dc80b 100644 --- a/apps/web/src/components/chat/ChangedFilesTree.test.tsx +++ b/apps/web/src/components/chat/ChangedFilesTree.test.tsx @@ -39,7 +39,7 @@ describe("ChangedFilesTree", () => { ({ files, visibleLabels, hiddenLabels }) => { const markup = renderToStaticMarkup( { ({ files, visibleLabels }) => { const markup = renderToStaticMarkup( { { kind: "message", createdAt: "2026-03-17T19:12:28.000Z", message: { - id: MessageId.makeUnsafe("message-2"), + id: MessageId.make("message-2"), role: "user", text: [ "yoo what's @terminal-1:1-5 mean", diff --git a/apps/web/src/components/chat/MessagesTimeline.virtualization.browser.tsx b/apps/web/src/components/chat/MessagesTimeline.virtualization.browser.tsx index 6a37c5b0991d039507efcbe98900f6df66dd9b34..9efe8ccb4f1542489f89eba787ed881ef0889810 100644 --- a/apps/web/src/components/chat/MessagesTimeline.virtualization.browser.tsx +++ b/apps/web/src/components/chat/MessagesTimeline.virtualization.browser.tsx @@ -101,7 +101,7 @@ function createMessage(input: { attachments?: ChatMessage["attachments"]; }): ChatMessage { return { - id: MessageId.makeUnsafe(input.id), + id: MessageId.make(input.id), role: input.role, text: input.text, ...(input.attachments ? { attachments: input.attachments } : {}), diff --git a/apps/web/src/components/chat/TraitsPicker.browser.tsx b/apps/web/src/components/chat/TraitsPicker.browser.tsx index 4dc7240c1302c227313ed138b1b8ce8bdf5aa33e..087d8bca516e39da603c9a62ad5a069585d2f1da 100644 --- a/apps/web/src/components/chat/TraitsPicker.browser.tsx +++ b/apps/web/src/components/chat/TraitsPicker.browser.tsx @@ -28,11 +28,11 @@ import { DEFAULT_CLIENT_SETTINGS } from "@t3tools/contracts/settings"; // ── Claude TraitsPicker tests ───────────────────────────────────────── -const LOCAL_ENVIRONMENT_ID = EnvironmentId.makeUnsafe("environment-local"); -const CLAUDE_THREAD_ID = ThreadId.makeUnsafe("thread-claude-traits"); +const LOCAL_ENVIRONMENT_ID = EnvironmentId.make("environment-local"); +const CLAUDE_THREAD_ID = ThreadId.make("thread-claude-traits"); const CLAUDE_THREAD_REF = scopeThreadRef(LOCAL_ENVIRONMENT_ID, CLAUDE_THREAD_ID); const CLAUDE_THREAD_KEY = scopedThreadKey(CLAUDE_THREAD_REF); -const CODEX_THREAD_ID = ThreadId.makeUnsafe("thread-codex-traits"); +const CODEX_THREAD_ID = ThreadId.make("thread-codex-traits"); const CODEX_THREAD_REF = scopeThreadRef(LOCAL_ENVIRONMENT_ID, CODEX_THREAD_ID); const CODEX_THREAD_KEY = scopedThreadKey(CODEX_THREAD_REF); const TEST_PROVIDERS: ReadonlyArray = [ diff --git a/apps/web/src/components/settings/SettingsPanels.browser.tsx b/apps/web/src/components/settings/SettingsPanels.browser.tsx index b48c1ef223c07750b99c7db7b1617d9f52a77c5e..0337da23a4efd5ecac03eb5d384733d0204dfabe 100644 --- a/apps/web/src/components/settings/SettingsPanels.browser.tsx +++ b/apps/web/src/components/settings/SettingsPanels.browser.tsx @@ -92,7 +92,7 @@ const authAccessHarness = vi.hoisted(() => { revision, type: "clientRemoved", payload: { - sessionId: AuthSessionId.makeUnsafe(sessionId), + sessionId: AuthSessionId.make(sessionId), }, }); revision += 1; @@ -119,13 +119,13 @@ vi.mock("../../environments/runtime", () => { id: "environment-local", label: "Local environment", source: "manual" as const, - environmentId: EnvironmentId.makeUnsafe("environment-local"), + environmentId: EnvironmentId.make("environment-local"), target: { httpBaseUrl: "http://localhost:3000", wsBaseUrl: "ws://localhost:3000", }, }, - environmentId: EnvironmentId.makeUnsafe("environment-local"), + environmentId: EnvironmentId.make("environment-local"), client: { server: { subscribeAuthAccess: (listener: Parameters[0]) => @@ -171,7 +171,7 @@ vi.mock("../../environments/runtime", () => { function createBaseServerConfig(): ServerConfig { return { environment: { - environmentId: EnvironmentId.makeUnsafe("environment-local"), + environmentId: EnvironmentId.make("environment-local"), label: "Local environment", platform: { os: "darwin" as const, arch: "arm64" as const }, serverVersion: "0.0.0-test", @@ -245,7 +245,7 @@ function makeClientSession(input: { deviceType: "unknown", ...input.client, }, - sessionId: AuthSessionId.makeUnsafe(input.sessionId), + sessionId: AuthSessionId.make(input.sessionId), issuedAt: makeUtc(input.issuedAt), expiresAt: makeUtc(input.expiresAt), lastConnectedAt: diff --git a/apps/web/src/composerDraftStore.test.ts b/apps/web/src/composerDraftStore.test.ts index fb56e691e5a0c3d9b9f5aa4fdc8bf146d0434aed..2169bbf858482148627a7c0c6e03ef0791e9d5a9 100644 --- a/apps/web/src/composerDraftStore.test.ts +++ b/apps/web/src/composerDraftStore.test.ts @@ -70,7 +70,7 @@ function makeTerminalContext(input: { }): TerminalContextDraft { return { id: input.id, - threadId: ThreadId.makeUnsafe("thread-dedupe"), + threadId: ThreadId.make("thread-dedupe"), terminalId: input.terminalId ?? "default", terminalLabel: input.terminalLabel ?? "Terminal 1", lineStart: input.lineStart ?? 4, @@ -106,9 +106,9 @@ function providerModelOptions(options: ProviderModelOptions): ProviderModelOptio return options; } -const TEST_ENVIRONMENT_ID = EnvironmentId.makeUnsafe("environment-local"); -const OTHER_TEST_ENVIRONMENT_ID = EnvironmentId.makeUnsafe("environment-remote"); -const LEGACY_TEST_ENVIRONMENT_ID = EnvironmentId.makeUnsafe("__legacy__"); +const TEST_ENVIRONMENT_ID = EnvironmentId.make("environment-local"); +const OTHER_TEST_ENVIRONMENT_ID = EnvironmentId.make("environment-remote"); +const LEGACY_TEST_ENVIRONMENT_ID = EnvironmentId.make("__legacy__"); function threadKeyFor( threadId: ThreadId, @@ -130,7 +130,7 @@ function draftByKey(key: string) { } describe("composerDraftStore addImages", () => { - const threadId = ThreadId.makeUnsafe("thread-dedupe"); + const threadId = ThreadId.make("thread-dedupe"); const threadRef = scopeThreadRef(TEST_ENVIRONMENT_ID, threadId); let originalRevokeObjectUrl: typeof URL.revokeObjectURL; let revokeSpy: ReturnType void>>; @@ -216,7 +216,7 @@ describe("composerDraftStore addImages", () => { }); describe("composerDraftStore clearComposerContent", () => { - const threadId = ThreadId.makeUnsafe("thread-clear"); + const threadId = ThreadId.make("thread-clear"); const threadRef = scopeThreadRef(TEST_ENVIRONMENT_ID, threadId); let originalRevokeObjectUrl: typeof URL.revokeObjectURL; let revokeSpy: ReturnType void>>; @@ -248,7 +248,7 @@ describe("composerDraftStore clearComposerContent", () => { }); describe("composerDraftStore syncPersistedAttachments", () => { - const threadId = ThreadId.makeUnsafe("thread-sync-persisted"); + const threadId = ThreadId.make("thread-sync-persisted"); const threadRef = scopeThreadRef(TEST_ENVIRONMENT_ID, threadId); beforeEach(() => { @@ -304,7 +304,7 @@ describe("composerDraftStore syncPersistedAttachments", () => { }); describe("composerDraftStore terminal contexts", () => { - const threadId = ThreadId.makeUnsafe("thread-dedupe"); + const threadId = ThreadId.make("thread-dedupe"); const threadRef = scopeThreadRef(TEST_ENVIRONMENT_ID, threadId); beforeEach(() => { @@ -482,18 +482,18 @@ describe("composerDraftStore terminal contexts", () => { }); describe("composerDraftStore project draft thread mapping", () => { - const projectId = ProjectId.makeUnsafe("project-a"); - const otherProjectId = ProjectId.makeUnsafe("project-b"); + const projectId = ProjectId.make("project-a"); + const otherProjectId = ProjectId.make("project-b"); const projectRef = scopeProjectRef(TEST_ENVIRONMENT_ID, projectId); const otherProjectRef = scopeProjectRef(TEST_ENVIRONMENT_ID, otherProjectId); const remoteProjectRef = scopeProjectRef(OTHER_TEST_ENVIRONMENT_ID, projectId); - const threadId = ThreadId.makeUnsafe("thread-a"); - const otherThreadId = ThreadId.makeUnsafe("thread-b"); - const draftId = DraftId.makeUnsafe("draft-a"); - const otherDraftId = DraftId.makeUnsafe("draft-b"); - const sharedDraftId = DraftId.makeUnsafe("draft-shared"); - const localDraftId = DraftId.makeUnsafe("draft-local"); - const remoteDraftId = DraftId.makeUnsafe("draft-remote"); + const threadId = ThreadId.make("thread-a"); + const otherThreadId = ThreadId.make("thread-b"); + const draftId = DraftId.make("draft-a"); + const otherDraftId = DraftId.make("draft-b"); + const sharedDraftId = DraftId.make("draft-shared"); + const localDraftId = DraftId.make("draft-local"); + const remoteDraftId = DraftId.make("draft-remote"); beforeEach(() => { resetComposerDraftStore(); @@ -847,7 +847,7 @@ describe("composerDraftStore project draft thread mapping", () => { }); describe("composerDraftStore modelSelection", () => { - const threadId = ThreadId.makeUnsafe("thread-model-options"); + const threadId = ThreadId.make("thread-model-options"); const threadRef = scopeThreadRef(TEST_ENVIRONMENT_ID, threadId); beforeEach(() => { @@ -1078,7 +1078,7 @@ describe("composerDraftStore modelSelection", () => { }); describe("composerDraftStore setModelSelection", () => { - const threadId = ThreadId.makeUnsafe("thread-model"); + const threadId = ThreadId.make("thread-model"); const threadRef = scopeThreadRef(TEST_ENVIRONMENT_ID, threadId); beforeEach(() => { @@ -1133,7 +1133,7 @@ describe("composerDraftStore sticky composer settings", () => { it("applies sticky activeProvider to new drafts", () => { const store = useComposerDraftStore.getState(); - const threadId = ThreadId.makeUnsafe("thread-sticky-active-provider"); + const threadId = ThreadId.make("thread-sticky-active-provider"); const threadRef = scopeThreadRef(TEST_ENVIRONMENT_ID, threadId); store.setStickyModelSelection(modelSelection("claudeAgent", "claude-opus-4-6")); @@ -1149,7 +1149,7 @@ describe("composerDraftStore sticky composer settings", () => { }); describe("composerDraftStore provider-scoped option updates", () => { - const threadId = ThreadId.makeUnsafe("thread-provider"); + const threadId = ThreadId.make("thread-provider"); const threadRef = scopeThreadRef(TEST_ENVIRONMENT_ID, threadId); beforeEach(() => { @@ -1175,7 +1175,7 @@ describe("composerDraftStore provider-scoped option updates", () => { }); describe("composerDraftStore runtime and interaction settings", () => { - const threadId = ThreadId.makeUnsafe("thread-settings"); + const threadId = ThreadId.make("thread-settings"); const threadRef = scopeThreadRef(TEST_ENVIRONMENT_ID, threadId); beforeEach(() => { diff --git a/apps/web/src/composerDraftStore.ts b/apps/web/src/composerDraftStore.ts index 2518ef8745c12192c488d18b6d00187af0b72c1b..231cf06566e3a9c31844ad0778bb5821e140862b 100644 --- a/apps/web/src/composerDraftStore.ts +++ b/apps/web/src/composerDraftStore.ts @@ -926,7 +926,7 @@ function normalizeComposerTarget( ): ComposerThreadTarget | null { if (typeof target === "string") { const draftId = target.trim(); - return draftId.length > 0 ? DraftId.makeUnsafe(draftId) : null; + return draftId.length > 0 ? DraftId.make(draftId) : null; } return target; } @@ -1804,7 +1804,7 @@ const composerDraftStore = create()( if (!draftThread || isDraftThreadPromoting(draftThread)) { return null; } - return toProjectDraftSession(DraftId.makeUnsafe(draftId), draftThread); + return toProjectDraftSession(DraftId.make(draftId), draftThread); }, getDraftThreadByProjectRef: (projectRef) => { return get().getDraftSessionByProjectRef(projectRef); @@ -1818,7 +1818,7 @@ const composerDraftStore = create()( draftThread.projectId === projectRef.projectId && draftThread.environmentId === projectRef.environmentId ) { - return toProjectDraftSession(DraftId.makeUnsafe(draftId), draftThread); + return toProjectDraftSession(DraftId.make(draftId), draftThread); } } return null; @@ -1837,7 +1837,7 @@ const composerDraftStore = create()( }, getDraftThread: (threadRef) => { if (typeof threadRef === "string") { - return get().getDraftSession(DraftId.makeUnsafe(threadRef)); + return get().getDraftSession(DraftId.make(threadRef)); } return get().getDraftSessionByRef(threadRef); }, @@ -1863,7 +1863,7 @@ const composerDraftStore = create()( state.logicalProjectDraftThreadKeyByLogicalProjectKey[normalizedLogicalProjectKey]; const nextDraftThread = createDraftThreadState( projectRef, - options?.threadId ?? existingThread?.threadId ?? ThreadId.makeUnsafe(draftId), + options?.threadId ?? existingThread?.threadId ?? ThreadId.make(draftId), normalizedLogicalProjectKey, existingThread, options, @@ -2438,10 +2438,9 @@ const composerDraftStore = create()( if (!threadKey || !threadId) { return; } - get().addImages( - typeof threadRef === "string" ? DraftId.makeUnsafe(threadKey) : threadRef, - [image], - ); + get().addImages(typeof threadRef === "string" ? DraftId.make(threadKey) : threadRef, [ + image, + ]); }, addImages: (threadRef, images) => { const threadKey = resolveComposerDraftKey(get(), threadRef) ?? ""; @@ -2566,7 +2565,7 @@ const composerDraftStore = create()( return; } get().addTerminalContexts( - typeof threadRef === "string" ? DraftId.makeUnsafe(threadKey) : threadRef, + typeof threadRef === "string" ? DraftId.make(threadKey) : threadRef, [context], ); }, @@ -2799,9 +2798,7 @@ export function useEffectiveComposerModelState(input: { projectModelSelection: ModelSelection | null | undefined; settings: UnifiedSettings; }): EffectiveComposerModelState { - const draft = useComposerDraftModelState( - input.threadRef ?? input.draftId ?? DraftId.makeUnsafe(""), - ); + const draft = useComposerDraftModelState(input.threadRef ?? input.draftId ?? DraftId.make("")); return useMemo( () => @@ -2836,7 +2833,7 @@ export function markPromotedDraftThread(threadId: ThreadId): void { const draftThreadTargets: ComposerThreadTarget[] = []; for (const [draftId, draftThread] of Object.entries(store.draftThreadsByThreadKey)) { if (draftThread.threadId === threadId) { - draftThreadTargets.push(DraftId.makeUnsafe(draftId)); + draftThreadTargets.push(DraftId.make(draftId)); } } if (draftThreadTargets.length === 0) { @@ -2854,7 +2851,7 @@ export function markPromotedDraftThreadByRef(threadRef: ScopedThreadRef): void { draftThread.environmentId === threadRef.environmentId && draftThread.threadId === threadRef.threadId ) { - draftStore.markDraftThreadPromoting(DraftId.makeUnsafe(draftId), threadRef); + draftStore.markDraftThreadPromoting(DraftId.make(draftId), threadRef); } } } @@ -2879,7 +2876,7 @@ export function finalizePromotedDraftThreadByRef(threadRef: ScopedThreadRef): vo draftThread.promotedTo.environmentId === threadRef.environmentId && draftThread.promotedTo.threadId === threadRef.threadId ) { - draftStore.finalizePromotedDraftThread(DraftId.makeUnsafe(draftId)); + draftStore.finalizePromotedDraftThread(DraftId.make(draftId)); } } } diff --git a/apps/web/src/diffRouteSearch.ts b/apps/web/src/diffRouteSearch.ts index d7de23e348ba95010d3a2a1bc5d5b3ef128fe6d9..d9b072f28e1559a8c4d5b0df3ebe1ff4f9c35302 100644 --- a/apps/web/src/diffRouteSearch.ts +++ b/apps/web/src/diffRouteSearch.ts @@ -28,7 +28,7 @@ export function stripDiffSearchParams>( export function parseDiffRouteSearch(search: Record): DiffRouteSearch { const diff = isDiffOpenValue(search.diff) ? "1" : undefined; const diffTurnIdRaw = diff ? normalizeSearchString(search.diffTurnId) : undefined; - const diffTurnId = diffTurnIdRaw ? TurnId.makeUnsafe(diffTurnIdRaw) : undefined; + const diffTurnId = diffTurnIdRaw ? TurnId.make(diffTurnIdRaw) : undefined; const diffFilePath = diff && diffTurnId ? normalizeSearchString(search.diffFilePath) : undefined; return { diff --git a/apps/web/src/environmentGrouping.test.ts b/apps/web/src/environmentGrouping.test.ts index 7c28f1f89fb86841d25e2a594247e2d8cee50ad3..4e8473188a16ec6e73aed68ad0ebb6aaa0ed996b 100644 --- a/apps/web/src/environmentGrouping.test.ts +++ b/apps/web/src/environmentGrouping.test.ts @@ -16,19 +16,19 @@ import { DEFAULT_INTERACTION_MODE } from "./types"; // ── Fixture Identifiers ────────────────────────────────────────────── -const primaryEnvId = EnvironmentId.makeUnsafe("env-primary"); -const remoteEnvId = EnvironmentId.makeUnsafe("env-remote"); +const primaryEnvId = EnvironmentId.make("env-primary"); +const remoteEnvId = EnvironmentId.make("env-remote"); -const sharedProjectPrimaryId = ProjectId.makeUnsafe("shared-proj-primary"); -const sharedProjectRemoteId = ProjectId.makeUnsafe("shared-proj-remote"); -const localOnlyProjectId = ProjectId.makeUnsafe("local-only-proj"); -const remoteOnlyProjectId = ProjectId.makeUnsafe("remote-only-proj"); +const sharedProjectPrimaryId = ProjectId.make("shared-proj-primary"); +const sharedProjectRemoteId = ProjectId.make("shared-proj-remote"); +const localOnlyProjectId = ProjectId.make("local-only-proj"); +const remoteOnlyProjectId = ProjectId.make("remote-only-proj"); -const threadP1 = ThreadId.makeUnsafe("thread-shared-primary-1"); -const threadP2 = ThreadId.makeUnsafe("thread-shared-primary-2"); -const threadR1 = ThreadId.makeUnsafe("thread-shared-remote-1"); -const threadL1 = ThreadId.makeUnsafe("thread-local-only-1"); -const threadRO1 = ThreadId.makeUnsafe("thread-remote-only-1"); +const threadP1 = ThreadId.make("thread-shared-primary-1"); +const threadP2 = ThreadId.make("thread-shared-primary-2"); +const threadR1 = ThreadId.make("thread-shared-remote-1"); +const threadL1 = ThreadId.make("thread-local-only-1"); +const threadRO1 = ThreadId.make("thread-remote-only-1"); const SHARED_REPO_CANONICAL_KEY = "github.com/example/shared-repo"; @@ -328,7 +328,7 @@ describe("environment grouping", () => { it("returns empty array for nonexistent environment", () => { const state = makeFixtureState(); - const ref = scopeProjectRef(EnvironmentId.makeUnsafe("nonexistent"), sharedProjectPrimaryId); + const ref = scopeProjectRef(EnvironmentId.make("nonexistent"), sharedProjectPrimaryId); expect(selectSidebarThreadsForProjectRef(state, ref)).toEqual([]); }); }); @@ -381,7 +381,7 @@ describe("environment grouping", () => { const state = makeFixtureState(); const refs = [ scopeProjectRef(primaryEnvId, sharedProjectPrimaryId), - scopeProjectRef(EnvironmentId.makeUnsafe("nonexistent"), ProjectId.makeUnsafe("nope")), + scopeProjectRef(EnvironmentId.make("nonexistent"), ProjectId.make("nope")), ]; const threads = selectSidebarThreadsForProjectRefs(state, refs); // Only returns threads from the valid ref diff --git a/apps/web/src/environments/primary/bootstrap.test.ts b/apps/web/src/environments/primary/bootstrap.test.ts index 353c151b915a3fece62c3c0ef8e52c1ff1bf04d9..6081e425e9d7a20441742ad7178b34aa2fdbda62 100644 --- a/apps/web/src/environments/primary/bootstrap.test.ts +++ b/apps/web/src/environments/primary/bootstrap.test.ts @@ -63,7 +63,7 @@ describe("environmentBootstrap", () => { desktopBridge: undefined, }); writePrimaryEnvironmentDescriptor({ - environmentId: EnvironmentId.makeUnsafe("environment-local"), + environmentId: EnvironmentId.make("environment-local"), label: "Bootstrapped environment", platform: { os: "darwin", diff --git a/apps/web/src/environments/runtime/catalog.test.ts b/apps/web/src/environments/runtime/catalog.test.ts index 4422a4f68be4adc0672979501ec0b437344418e4..f078129463a19b9ca52c5773b046548f40acd576 100644 --- a/apps/web/src/environments/runtime/catalog.test.ts +++ b/apps/web/src/environments/runtime/catalog.test.ts @@ -41,7 +41,7 @@ describe("environment runtime catalog stores", () => { }); it("resets the saved environment registry store state", () => { - const environmentId = EnvironmentId.makeUnsafe("environment-1"); + const environmentId = EnvironmentId.make("environment-1"); useSavedEnvironmentRegistryStore.getState().upsert({ environmentId, @@ -60,7 +60,7 @@ describe("environment runtime catalog stores", () => { }); it("resets the saved environment runtime store state", () => { - const environmentId = EnvironmentId.makeUnsafe("environment-1"); + const environmentId = EnvironmentId.make("environment-1"); useSavedEnvironmentRuntimeStore.getState().patch(environmentId, { connectionState: "connected", @@ -82,7 +82,7 @@ describe("environment runtime catalog stores", () => { expect(() => useSavedEnvironmentRegistryStore.getState().upsert({ - environmentId: EnvironmentId.makeUnsafe("environment-1"), + environmentId: EnvironmentId.make("environment-1"), label: "Remote environment", httpBaseUrl: "https://remote.example.com/", wsBaseUrl: "wss://remote.example.com/", @@ -121,7 +121,7 @@ describe("environment runtime catalog stores", () => { const hydrationPromise = waitForSavedEnvironmentRegistryHydration(); - const environmentId = EnvironmentId.makeUnsafe("environment-1"); + const environmentId = EnvironmentId.make("environment-1"); const record = { environmentId, label: "Remote environment", diff --git a/apps/web/src/environments/runtime/connection.test.ts b/apps/web/src/environments/runtime/connection.test.ts index 2644fb83990c11ff82be95d677e77e0c5b01bdfc..4dc65015497a6355e74cdec99c3ff7735aead2cb 100644 --- a/apps/web/src/environments/runtime/connection.test.ts +++ b/apps/web/src/environments/runtime/connection.test.ts @@ -30,7 +30,7 @@ function createTestClient(options?: { server: { getConfig: vi.fn(async () => ({ environment: { - environmentId: EnvironmentId.makeUnsafe("env-1"), + environmentId: EnvironmentId.make("env-1"), }, })), subscribeConfig: (listener: (event: any) => void) => { @@ -133,7 +133,7 @@ function createTestClient(options?: { describe("createEnvironmentConnection", () => { it("bootstraps a snapshot immediately for a new connection", async () => { - const environmentId = EnvironmentId.makeUnsafe("env-1"); + const environmentId = EnvironmentId.make("env-1"); const { client, getSnapshot } = createTestClient(); const syncSnapshot = vi.fn(); @@ -168,7 +168,7 @@ describe("createEnvironmentConnection", () => { }); it("rejects welcome/config identity drift", async () => { - const environmentId = EnvironmentId.makeUnsafe("env-1"); + const environmentId = EnvironmentId.make("env-1"); const { client, emitWelcome } = createTestClient(); const connection = createEnvironmentConnection({ @@ -189,7 +189,7 @@ describe("createEnvironmentConnection", () => { applyTerminalEvent: vi.fn(), }); - expect(() => emitWelcome(EnvironmentId.makeUnsafe("env-2"))).toThrow( + expect(() => emitWelcome(EnvironmentId.make("env-2"))).toThrow( "Environment connection env-1 changed identity to env-2 via server lifecycle welcome.", ); @@ -197,7 +197,7 @@ describe("createEnvironmentConnection", () => { }); it("rejects ensureBootstrapped when snapshot recovery fails", async () => { - const environmentId = EnvironmentId.makeUnsafe("env-1"); + const environmentId = EnvironmentId.make("env-1"); const snapshotError = new Error("snapshot failed"); const { client } = createTestClient({ getSnapshot: async () => { @@ -229,7 +229,7 @@ describe("createEnvironmentConnection", () => { }); it("retries replay recovery after transport disconnects during resubscribe", async () => { - const environmentId = EnvironmentId.makeUnsafe("env-1"); + const environmentId = EnvironmentId.make("env-1"); let replayAttempts = 0; const applyEventBatch = vi.fn(); const { client, replayEvents, triggerDomainResubscribe } = createTestClient({ @@ -287,7 +287,7 @@ describe("createEnvironmentConnection", () => { await connection.dispose(); }); it("swallows replay recovery failures triggered by resubscribe", async () => { - const environmentId = EnvironmentId.makeUnsafe("env-1"); + const environmentId = EnvironmentId.make("env-1"); const snapshotError = new Error("snapshot failed"); let snapshotCalls = 0; const { client, triggerDomainResubscribe } = createTestClient({ diff --git a/apps/web/src/environments/runtime/service.addSavedEnvironment.test.ts b/apps/web/src/environments/runtime/service.addSavedEnvironment.test.ts index 41f36f3667472a9d88aeaab843619ac37ed04545..9bcbc4f7133774b7afc15c4632dd5f4dda438839 100644 --- a/apps/web/src/environments/runtime/service.addSavedEnvironment.test.ts +++ b/apps/web/src/environments/runtime/service.addSavedEnvironment.test.ts @@ -68,7 +68,7 @@ describe("addSavedEnvironment", () => { credential: "pairing-code", }); mockFetchRemoteEnvironmentDescriptor.mockResolvedValue({ - environmentId: EnvironmentId.makeUnsafe("environment-1"), + environmentId: EnvironmentId.make("environment-1"), label: "Remote environment", }); mockBootstrapRemoteBearerSession.mockResolvedValue({ @@ -94,7 +94,7 @@ describe("addSavedEnvironment", () => { expect(mockPersistSavedEnvironmentRecord).toHaveBeenCalledTimes(1); expect(mockWriteSavedEnvironmentBearerToken).toHaveBeenCalledWith( - EnvironmentId.makeUnsafe("environment-1"), + EnvironmentId.make("environment-1"), "bearer-token", ); expect(mockSetSavedEnvironmentRegistry).toHaveBeenCalledWith([]); diff --git a/apps/web/src/environments/runtime/service.ts b/apps/web/src/environments/runtime/service.ts index 7eb8aff43bd482a81bef76723f94f926aedbe535..5c8d2dacabc685b75fa6c98dffad943cbe84d0c9 100644 --- a/apps/web/src/environments/runtime/service.ts +++ b/apps/web/src/environments/runtime/service.ts @@ -281,7 +281,7 @@ function createEnvironmentConnectionHandlers() { reconcileSnapshotDerivedState(); }, applyTerminalEvent: (event: TerminalEvent, environmentId: EnvironmentId) => { - const threadRef = scopeThreadRef(environmentId, ThreadId.makeUnsafe(event.threadId)); + const threadRef = scopeThreadRef(environmentId, ThreadId.make(event.threadId)); const serverThread = selectThreadByRef(useStore.getState(), threadRef); const hasDraftThread = useComposerDraftStore.getState().getDraftThreadByRef(threadRef) !== null; diff --git a/apps/web/src/historyBootstrap.test.ts b/apps/web/src/historyBootstrap.test.ts index eda176dab427aaa362daeb992542ccad4490e1f8..6b9e56d2db7af9b2b049f2b41d5a41ca0b0706a6 100644 --- a/apps/web/src/historyBootstrap.test.ts +++ b/apps/web/src/historyBootstrap.test.ts @@ -3,7 +3,7 @@ import { describe, expect, it } from "vitest"; import { buildBootstrapInput } from "./historyBootstrap"; -const messageId = (value: string) => MessageId.makeUnsafe(value); +const messageId = (value: string) => MessageId.make(value); describe("buildBootstrapInput", () => { it("includes full transcript when under budget", () => { diff --git a/apps/web/src/lib/contextWindow.test.ts b/apps/web/src/lib/contextWindow.test.ts index 2173c18aa7e50a35586efacd45cb6831090ca457..70479b3fa4317278dfba84bf89350349638d4101 100644 --- a/apps/web/src/lib/contextWindow.test.ts +++ b/apps/web/src/lib/contextWindow.test.ts @@ -5,12 +5,12 @@ import { deriveLatestContextWindowSnapshot, formatContextWindowTokens } from "./ function makeActivity(id: string, kind: string, payload: unknown): OrchestrationThreadActivity { return { - id: EventId.makeUnsafe(id), + id: EventId.make(id), tone: "info", kind, summary: kind, payload, - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), createdAt: "2026-03-23T00:00:00.000Z", }; } diff --git a/apps/web/src/lib/gitReactQuery.test.ts b/apps/web/src/lib/gitReactQuery.test.ts index 71788b5eac84763e8b20ccbbeb76855a75f24f2c..93ba66e4a2433e54b6223f4f53ea508cdc551000 100644 --- a/apps/web/src/lib/gitReactQuery.test.ts +++ b/apps/web/src/lib/gitReactQuery.test.ts @@ -34,8 +34,8 @@ const BRANCH_SEARCH_RESULT: InfiniteData = { pages: [BRANCH_QUERY_RESULT], pageParams: [0], }; -const ENVIRONMENT_A = EnvironmentId.makeUnsafe("environment-a"); -const ENVIRONMENT_B = EnvironmentId.makeUnsafe("environment-b"); +const ENVIRONMENT_A = EnvironmentId.make("environment-a"); +const ENVIRONMENT_B = EnvironmentId.make("environment-b"); describe("gitMutationKeys", () => { it("scopes stacked action keys by cwd", () => { diff --git a/apps/web/src/lib/gitStatusState.test.ts b/apps/web/src/lib/gitStatusState.test.ts index ef61e4e943f6d6170efde387e45e668b89625975..b5317d9ec117bd7f1a77def696901a9eddef61b2 100644 --- a/apps/web/src/lib/gitStatusState.test.ts +++ b/apps/web/src/lib/gitStatusState.test.ts @@ -34,8 +34,8 @@ function registerListener(listeners: Set<(event: T) => void>, listener: (even } const gitStatusListeners = new Set<(event: GitStatusResult) => void>(); -const ENVIRONMENT_ID = EnvironmentId.makeUnsafe("environment-local"); -const OTHER_ENVIRONMENT_ID = EnvironmentId.makeUnsafe("environment-remote"); +const ENVIRONMENT_ID = EnvironmentId.make("environment-local"); +const OTHER_ENVIRONMENT_ID = EnvironmentId.make("environment-remote"); const TARGET = { environmentId: ENVIRONMENT_ID, cwd: "/repo" } as const; const FRESH_TARGET = { environmentId: ENVIRONMENT_ID, cwd: "/fresh" } as const; diff --git a/apps/web/src/lib/providerReactQuery.test.ts b/apps/web/src/lib/providerReactQuery.test.ts index 13361fc1deec2d9a37d6740b3f6357ab06d5e675..85466326e4da5ade57227cd84e1cb1468daeb724 100644 --- a/apps/web/src/lib/providerReactQuery.test.ts +++ b/apps/web/src/lib/providerReactQuery.test.ts @@ -4,8 +4,8 @@ import { afterEach, describe, expect, it, vi } from "vitest"; import { checkpointDiffQueryOptions, providerQueryKeys } from "./providerReactQuery"; import * as environmentApi from "../environmentApi"; -const threadId = ThreadId.makeUnsafe("thread-id"); -const environmentId = EnvironmentId.makeUnsafe("environment-local"); +const threadId = ThreadId.make("thread-id"); +const environmentId = EnvironmentId.make("environment-local"); function mockNativeApi(input: { getTurnDiff: ReturnType; diff --git a/apps/web/src/lib/terminalContext.test.ts b/apps/web/src/lib/terminalContext.test.ts index 2e53c43d310c6ae837459b918541bb3d13b1fe4f..72917de7600af857715e1c5b90044eca24bc6ebb 100644 --- a/apps/web/src/lib/terminalContext.test.ts +++ b/apps/web/src/lib/terminalContext.test.ts @@ -25,7 +25,7 @@ import { function makeContext(overrides?: Partial): TerminalContextDraft { return { id: "context-1", - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), terminalId: "default", terminalLabel: "Terminal 1", lineStart: 12, diff --git a/apps/web/src/lib/terminalStateCleanup.test.ts b/apps/web/src/lib/terminalStateCleanup.test.ts index e3348d73e823b12ff62bdd367d3fdb276ecde68d..eedb33b97c041aae6de6b2effdf9690587a2a231 100644 --- a/apps/web/src/lib/terminalStateCleanup.test.ts +++ b/apps/web/src/lib/terminalStateCleanup.test.ts @@ -4,7 +4,7 @@ import { describe, expect, it } from "vitest"; import { collectActiveTerminalThreadIds } from "./terminalStateCleanup"; -const threadId = (id: string): ThreadId => ThreadId.makeUnsafe(id); +const threadId = (id: string): ThreadId => ThreadId.make(id); const threadKey = (environmentId: string, id: string): string => scopedThreadKey(scopeThreadRef(environmentId as never, threadId(id))); diff --git a/apps/web/src/lib/utils.ts b/apps/web/src/lib/utils.ts index 54169361932f49acc50bd1b74d74c87dd54ab165..b4ccb36c77c90ded25e4578e29f0ccb9d3084883 100644 --- a/apps/web/src/lib/utils.ts +++ b/apps/web/src/lib/utils.ts @@ -28,12 +28,12 @@ export function randomUUID(): string { return Effect.runSync(Random.nextUUIDv4); } -export const newCommandId = (): CommandId => CommandId.makeUnsafe(randomUUID()); +export const newCommandId = (): CommandId => CommandId.make(randomUUID()); -export const newProjectId = (): ProjectId => ProjectId.makeUnsafe(randomUUID()); +export const newProjectId = (): ProjectId => ProjectId.make(randomUUID()); -export const newThreadId = (): ThreadId => ThreadId.makeUnsafe(randomUUID()); +export const newThreadId = (): ThreadId => ThreadId.make(randomUUID()); -export const newDraftId = (): DraftId => DraftId.makeUnsafe(randomUUID()); +export const newDraftId = (): DraftId => DraftId.make(randomUUID()); -export const newMessageId = (): MessageId => MessageId.makeUnsafe(randomUUID()); +export const newMessageId = (): MessageId => MessageId.make(randomUUID()); diff --git a/apps/web/src/localApi.test.ts b/apps/web/src/localApi.test.ts index bd04cabfaa9207122af81021e3171442949e80e9..68047f4495eba08f9c2b1febf7d42e7f3cec0956 100644 --- a/apps/web/src/localApi.test.ts +++ b/apps/web/src/localApi.test.ts @@ -104,10 +104,10 @@ vi.mock("./environments/runtime", () => ({ httpBaseUrl: "http://localhost:3000", wsBaseUrl: "ws://localhost:3000", }, - environmentId: EnvironmentId.makeUnsafe("environment-local"), + environmentId: EnvironmentId.make("environment-local"), }, client: rpcClientMock, - environmentId: EnvironmentId.makeUnsafe("environment-local"), + environmentId: EnvironmentId.make("environment-local"), ensureBootstrapped: async () => undefined, reconnect: async () => undefined, dispose: async () => undefined, @@ -214,7 +214,7 @@ const defaultProviders: ReadonlyArray = [ ]; const baseEnvironment = { - environmentId: EnvironmentId.makeUnsafe("environment-local"), + environmentId: EnvironmentId.make("environment-local"), label: "Local environment", platform: { os: "darwin" as const, @@ -315,9 +315,9 @@ describe("wsApi", () => { const orchestrationEvent = { sequence: 1, - eventId: EventId.makeUnsafe("event-1"), + eventId: EventId.make("event-1"), aggregateKind: "project", - aggregateId: ProjectId.makeUnsafe("project-1"), + aggregateId: ProjectId.make("project-1"), occurredAt: "2026-02-24T00:00:00.000Z", commandId: null, causationEventId: null, @@ -325,7 +325,7 @@ describe("wsApi", () => { metadata: {}, type: "project.created", payload: { - projectId: ProjectId.makeUnsafe("project-1"), + projectId: ProjectId.make("project-1"), title: "Project", workspaceRoot: "/tmp/workspace", defaultModelSelection: { @@ -390,8 +390,8 @@ describe("wsApi", () => { const api = createEnvironmentApi(rpcClientMock as never); const command = { type: "project.create", - commandId: CommandId.makeUnsafe("cmd-1"), - projectId: ProjectId.makeUnsafe("project-1"), + commandId: CommandId.make("cmd-1"), + projectId: ProjectId.make("project-1"), title: "Project", workspaceRoot: "/tmp/project", defaultModelSelection: { @@ -429,7 +429,7 @@ describe("wsApi", () => { const api = createEnvironmentApi(rpcClientMock as never); await api.orchestration.getFullThreadDiff({ - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), toTurnCount: 1, }); @@ -535,14 +535,12 @@ describe("wsApi", () => { }); await api.persistence.getSavedEnvironmentRegistry(); await api.persistence.setSavedEnvironmentRegistry([]); - await api.persistence.getSavedEnvironmentSecret(EnvironmentId.makeUnsafe("environment-local")); + await api.persistence.getSavedEnvironmentSecret(EnvironmentId.make("environment-local")); await api.persistence.setSavedEnvironmentSecret( - EnvironmentId.makeUnsafe("environment-local"), + EnvironmentId.make("environment-local"), "bearer-token", ); - await api.persistence.removeSavedEnvironmentSecret( - EnvironmentId.makeUnsafe("environment-local"), - ); + await api.persistence.removeSavedEnvironmentSecret(EnvironmentId.make("environment-local")); expect(getClientSettings).toHaveBeenCalledWith(); expect(setClientSettings).toHaveBeenCalledWith({ @@ -574,7 +572,7 @@ describe("wsApi", () => { }); await api.persistence.setSavedEnvironmentRegistry([ { - environmentId: EnvironmentId.makeUnsafe("environment-local"), + environmentId: EnvironmentId.make("environment-local"), label: "Primary", httpBaseUrl: "http://localhost:3000", wsBaseUrl: "ws://localhost:3000", @@ -583,7 +581,7 @@ describe("wsApi", () => { }, ]); await api.persistence.setSavedEnvironmentSecret( - EnvironmentId.makeUnsafe("environment-local"), + EnvironmentId.make("environment-local"), "bearer-token", ); @@ -597,7 +595,7 @@ describe("wsApi", () => { }); await expect(api.persistence.getSavedEnvironmentRegistry()).resolves.toEqual([ { - environmentId: EnvironmentId.makeUnsafe("environment-local"), + environmentId: EnvironmentId.make("environment-local"), label: "Primary", httpBaseUrl: "http://localhost:3000", wsBaseUrl: "ws://localhost:3000", @@ -606,15 +604,13 @@ describe("wsApi", () => { }, ]); await expect( - api.persistence.getSavedEnvironmentSecret(EnvironmentId.makeUnsafe("environment-local")), + api.persistence.getSavedEnvironmentSecret(EnvironmentId.make("environment-local")), ).resolves.toBe("bearer-token"); - await api.persistence.removeSavedEnvironmentSecret( - EnvironmentId.makeUnsafe("environment-local"), - ); + await api.persistence.removeSavedEnvironmentSecret(EnvironmentId.make("environment-local")); await expect( - api.persistence.getSavedEnvironmentSecret(EnvironmentId.makeUnsafe("environment-local")), + api.persistence.getSavedEnvironmentSecret(EnvironmentId.make("environment-local")), ).resolves.toBeNull(); }); }); diff --git a/apps/web/src/orchestrationEventEffects.test.ts b/apps/web/src/orchestrationEventEffects.test.ts index 0e065288aec9c42e3db1a095b5c76bcf885eb140..d35dc9e26026f2468a8be6f4eca1c5c50f86794a 100644 --- a/apps/web/src/orchestrationEventEffects.test.ts +++ b/apps/web/src/orchestrationEventEffects.test.ts @@ -19,14 +19,14 @@ function makeEvent( const sequence = overrides.sequence ?? 1; return { sequence, - eventId: EventId.makeUnsafe(`event-${sequence}`), + eventId: EventId.make(`event-${sequence}`), aggregateKind: "thread", aggregateId: "threadId" in payload ? payload.threadId : "projectId" in payload ? payload.projectId - : ProjectId.makeUnsafe("project-1"), + : ProjectId.make("project-1"), occurredAt: "2026-02-27T00:00:00.000Z", commandId: null, causationEventId: null, @@ -40,14 +40,14 @@ function makeEvent( describe("deriveOrchestrationBatchEffects", () => { it("targets draft promotion and terminal cleanup from thread lifecycle events", () => { - const createdThreadId = ThreadId.makeUnsafe("thread-created"); - const deletedThreadId = ThreadId.makeUnsafe("thread-deleted"); - const archivedThreadId = ThreadId.makeUnsafe("thread-archived"); + const createdThreadId = ThreadId.make("thread-created"); + const deletedThreadId = ThreadId.make("thread-deleted"); + const archivedThreadId = ThreadId.make("thread-archived"); const effects = deriveOrchestrationBatchEffects([ makeEvent("thread.created", { threadId: createdThreadId, - projectId: ProjectId.makeUnsafe("project-1"), + projectId: ProjectId.make("project-1"), title: "Created thread", modelSelection: { provider: "codex", model: "gpt-5-codex" }, runtimeMode: "full-access", @@ -75,7 +75,7 @@ describe("deriveOrchestrationBatchEffects", () => { }); it("keeps only the final lifecycle outcome for a thread within one batch", () => { - const threadId = ThreadId.makeUnsafe("thread-1"); + const threadId = ThreadId.make("thread-1"); const effects = deriveOrchestrationBatchEffects([ makeEvent("thread.deleted", { @@ -84,7 +84,7 @@ describe("deriveOrchestrationBatchEffects", () => { }), makeEvent("thread.created", { threadId, - projectId: ProjectId.makeUnsafe("project-1"), + projectId: ProjectId.make("project-1"), title: "Recreated thread", modelSelection: { provider: "codex", model: "gpt-5-codex" }, runtimeMode: "full-access", @@ -96,12 +96,12 @@ describe("deriveOrchestrationBatchEffects", () => { }), makeEvent("thread.turn-diff-completed", { threadId, - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), checkpointTurnCount: 1, - checkpointRef: CheckpointRef.makeUnsafe("checkpoint-1"), + checkpointRef: CheckpointRef.make("checkpoint-1"), status: "ready", files: [], - assistantMessageId: MessageId.makeUnsafe("assistant-1"), + assistantMessageId: MessageId.make("assistant-1"), completedAt: "2026-02-27T00:00:03.000Z", }), ]); @@ -113,7 +113,7 @@ describe("deriveOrchestrationBatchEffects", () => { }); it("does not retain archive cleanup when a thread is unarchived later in the same batch", () => { - const threadId = ThreadId.makeUnsafe("thread-1"); + const threadId = ThreadId.make("thread-1"); const effects = deriveOrchestrationBatchEffects([ makeEvent("thread.archived", { diff --git a/apps/web/src/projectScripts.ts b/apps/web/src/projectScripts.ts index 03e3d291167753cc8b78a08c134cc221bfd00e40..1cb3a6c75823fcf8985015f1a43a96731f855105 100644 --- a/apps/web/src/projectScripts.ts +++ b/apps/web/src/projectScripts.ts @@ -22,7 +22,7 @@ function normalizeScriptId(value: string): string { } export const commandForProjectScript = (scriptId: string): KeybindingCommand => - SCRIPT_RUN_COMMAND_PATTERN.makeUnsafe(`script.${scriptId}.run`); + SCRIPT_RUN_COMMAND_PATTERN.make(`script.${scriptId}.run`); export function projectScriptIdFromCommand(command: string): string | null { const trimmed = command.trim(); diff --git a/apps/web/src/routes/_chat.draft.$draftId.tsx b/apps/web/src/routes/_chat.draft.$draftId.tsx index 6ddd78c6bb1a75a59895b1178a37f5b3c1741a9b..e7bb1d0912f2a6f913041d3ddb13e58947c0b2c4 100644 --- a/apps/web/src/routes/_chat.draft.$draftId.tsx +++ b/apps/web/src/routes/_chat.draft.$draftId.tsx @@ -11,7 +11,7 @@ import { buildThreadRouteParams } from "../threadRoutes"; function DraftChatThreadRouteView() { const navigate = useNavigate(); const { draftId: rawDraftId } = Route.useParams(); - const draftId = DraftId.makeUnsafe(rawDraftId); + const draftId = DraftId.make(rawDraftId); const draftSession = useComposerDraftStore((store) => store.getDraftSession(draftId)); const serverThread = useStore( useMemo( diff --git a/apps/web/src/rpc/protocol.ts b/apps/web/src/rpc/protocol.ts index 48681b4a27d5032f2ede24377a5b6b010b6b4f26..5c5c51d89903036d5d0fc2107a792b389a91c785 100644 --- a/apps/web/src/rpc/protocol.ts +++ b/apps/web/src/rpc/protocol.ts @@ -154,8 +154,8 @@ export function createWsRpcProtocolLayer( }), (protocol) => ({ ...protocol, - run: (writeResponse) => - protocol.run((response) => { + run: (clientId, writeResponse) => + protocol.run(clientId, (response) => { if (response._tag === "Chunk" || response._tag === "Exit") { acknowledgeRpcRequest(response.requestId); } else if (response._tag === "ClientProtocolError" || response._tag === "Defect") { @@ -163,11 +163,11 @@ export function createWsRpcProtocolLayer( } return writeResponse(response); }), - send: (request, transferables) => { + send: (clientId, request, transferables) => { if (request._tag === "Request") { trackRpcRequestSent(request.id, request.tag); } - return protocol.send(request, transferables); + return protocol.send(clientId, request, transferables); }, }), ), diff --git a/apps/web/src/rpc/serverState.test.ts b/apps/web/src/rpc/serverState.test.ts index 5ee6d6807f713e35193eafceb5a329582cf534ea..4df3c6927d9655060fb82ac496962a728a74b6a2 100644 --- a/apps/web/src/rpc/serverState.test.ts +++ b/apps/web/src/rpc/serverState.test.ts @@ -52,7 +52,7 @@ const defaultProviders: ReadonlyArray = [ ]; const baseEnvironment = { - environmentId: EnvironmentId.makeUnsafe("environment-local"), + environmentId: EnvironmentId.make("environment-local"), label: "Local environment", platform: { os: "darwin" as const, @@ -217,8 +217,8 @@ describe("serverState", () => { environment: baseEnvironment, cwd: "/tmp/workspace", projectName: "t3-code", - bootstrapProjectId: ProjectId.makeUnsafe("project-1"), - bootstrapThreadId: ThreadId.makeUnsafe("thread-1"), + bootstrapProjectId: ProjectId.make("project-1"), + bootstrapThreadId: ThreadId.make("thread-1"), }, }); @@ -226,8 +226,8 @@ describe("serverState", () => { environment: baseEnvironment, cwd: "/tmp/workspace", projectName: "t3-code", - bootstrapProjectId: ProjectId.makeUnsafe("project-1"), - bootstrapThreadId: ThreadId.makeUnsafe("thread-1"), + bootstrapProjectId: ProjectId.make("project-1"), + bootstrapThreadId: ThreadId.make("thread-1"), }); const lateListener = vi.fn(); @@ -236,8 +236,8 @@ describe("serverState", () => { environment: baseEnvironment, cwd: "/tmp/workspace", projectName: "t3-code", - bootstrapProjectId: ProjectId.makeUnsafe("project-1"), - bootstrapThreadId: ThreadId.makeUnsafe("thread-1"), + bootstrapProjectId: ProjectId.make("project-1"), + bootstrapThreadId: ThreadId.make("thread-1"), }); unsubscribeLate(); diff --git a/apps/web/src/session-logic.test.ts b/apps/web/src/session-logic.test.ts index a1234dff6f767798cfdb91472a28759f57aeb12c..d3fd3043499ec93e3fe8d8a39efa1b4f7167c7ee 100644 --- a/apps/web/src/session-logic.test.ts +++ b/apps/web/src/session-logic.test.ts @@ -35,13 +35,13 @@ function makeActivity(overrides: { }): OrchestrationThreadActivity { const payload = overrides.payload ?? {}; return { - id: EventId.makeUnsafe(overrides.id ?? crypto.randomUUID()), + id: EventId.make(overrides.id ?? crypto.randomUUID()), createdAt: overrides.createdAt ?? "2026-02-23T00:00:00.000Z", kind: overrides.kind ?? "tool.started", summary: overrides.summary ?? "Tool call", tone: overrides.tone ?? "tool", payload, - turnId: overrides.turnId ? TurnId.makeUnsafe(overrides.turnId) : null, + turnId: overrides.turnId ? TurnId.make(overrides.turnId) : null, ...(overrides.sequence !== undefined ? { sequence: overrides.sequence } : {}), }; } @@ -336,7 +336,7 @@ describe("deriveActivePlanState", () => { }), ]; - expect(deriveActivePlanState(activities, TurnId.makeUnsafe("turn-1"))).toEqual({ + expect(deriveActivePlanState(activities, TurnId.make("turn-1"))).toEqual({ createdAt: "2026-02-23T00:00:02.000Z", turnId: "turn-1", explanation: "Refined plan", @@ -352,7 +352,7 @@ describe("findLatestProposedPlan", () => { [ { id: "plan:thread-1:turn:turn-1", - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), planMarkdown: "# Older", implementedAt: null, implementationThreadId: null, @@ -361,7 +361,7 @@ describe("findLatestProposedPlan", () => { }, { id: "plan:thread-1:turn:turn-1", - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), planMarkdown: "# Latest", implementedAt: null, implementationThreadId: null, @@ -370,7 +370,7 @@ describe("findLatestProposedPlan", () => { }, { id: "plan:thread-1:turn:turn-2", - turnId: TurnId.makeUnsafe("turn-2"), + turnId: TurnId.make("turn-2"), planMarkdown: "# Different turn", implementedAt: null, implementationThreadId: null, @@ -378,7 +378,7 @@ describe("findLatestProposedPlan", () => { updatedAt: "2026-02-23T00:00:03.000Z", }, ], - TurnId.makeUnsafe("turn-1"), + TurnId.make("turn-1"), ), ).toEqual({ id: "plan:thread-1:turn:turn-1", @@ -396,7 +396,7 @@ describe("findLatestProposedPlan", () => { [ { id: "plan:thread-1:turn:turn-1", - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), planMarkdown: "# First", implementedAt: null, implementationThreadId: null, @@ -405,7 +405,7 @@ describe("findLatestProposedPlan", () => { }, { id: "plan:thread-1:turn:turn-2", - turnId: TurnId.makeUnsafe("turn-2"), + turnId: TurnId.make("turn-2"), planMarkdown: "# Latest", implementedAt: null, implementationThreadId: null, @@ -425,7 +425,7 @@ describe("hasActionableProposedPlan", () => { expect( hasActionableProposedPlan({ id: "plan-1", - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), planMarkdown: "# Plan", implementedAt: null, implementationThreadId: null, @@ -439,10 +439,10 @@ describe("hasActionableProposedPlan", () => { expect( hasActionableProposedPlan({ id: "plan-1", - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), planMarkdown: "# Plan", implementedAt: "2026-02-23T00:00:02.000Z", - implementationThreadId: ThreadId.makeUnsafe("thread-implement"), + implementationThreadId: ThreadId.make("thread-implement"), createdAt: "2026-02-23T00:00:00.000Z", updatedAt: "2026-02-23T00:00:02.000Z", }), @@ -456,25 +456,25 @@ describe("findSidebarProposedPlan", () => { findSidebarProposedPlan({ threads: [ { - id: ThreadId.makeUnsafe("thread-1"), + id: ThreadId.make("thread-1"), proposedPlans: [ { id: "plan-1", - turnId: TurnId.makeUnsafe("turn-plan"), + turnId: TurnId.make("turn-plan"), planMarkdown: "# Source plan", implementedAt: "2026-02-23T00:00:03.000Z", - implementationThreadId: ThreadId.makeUnsafe("thread-2"), + implementationThreadId: ThreadId.make("thread-2"), createdAt: "2026-02-23T00:00:01.000Z", updatedAt: "2026-02-23T00:00:02.000Z", }, ], }, { - id: ThreadId.makeUnsafe("thread-2"), + id: ThreadId.make("thread-2"), proposedPlans: [ { id: "plan-2", - turnId: TurnId.makeUnsafe("turn-other"), + turnId: TurnId.make("turn-other"), planMarkdown: "# Latest elsewhere", implementedAt: null, implementationThreadId: null, @@ -485,14 +485,14 @@ describe("findSidebarProposedPlan", () => { }, ], latestTurn: { - turnId: TurnId.makeUnsafe("turn-implementation"), + turnId: TurnId.make("turn-implementation"), sourceProposedPlan: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), planId: "plan-1", }, }, latestTurnSettled: false, - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), }), ).toEqual({ id: "plan-1", @@ -510,11 +510,11 @@ describe("findSidebarProposedPlan", () => { findSidebarProposedPlan({ threads: [ { - id: ThreadId.makeUnsafe("thread-1"), + id: ThreadId.make("thread-1"), proposedPlans: [ { id: "plan-1", - turnId: TurnId.makeUnsafe("turn-plan"), + turnId: TurnId.make("turn-plan"), planMarkdown: "# Older", implementedAt: null, implementationThreadId: null, @@ -523,7 +523,7 @@ describe("findSidebarProposedPlan", () => { }, { id: "plan-2", - turnId: TurnId.makeUnsafe("turn-latest"), + turnId: TurnId.make("turn-latest"), planMarkdown: "# Latest", implementedAt: null, implementationThreadId: null, @@ -534,14 +534,14 @@ describe("findSidebarProposedPlan", () => { }, ], latestTurn: { - turnId: TurnId.makeUnsafe("turn-implementation"), + turnId: TurnId.make("turn-implementation"), sourceProposedPlan: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), planId: "plan-1", }, }, latestTurnSettled: true, - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), })?.planMarkdown, ).toBe("# Latest"); }); @@ -609,7 +609,7 @@ describe("deriveWorkLogEntries", () => { makeActivity({ id: "no-turn", summary: "Checkpoint captured", tone: "info" }), ]; - const entries = deriveWorkLogEntries(activities, TurnId.makeUnsafe("turn-2")); + const entries = deriveWorkLogEntries(activities, TurnId.make("turn-2")); expect(entries.map((entry) => entry.id)).toEqual(["turn-2"]); }); @@ -1022,7 +1022,7 @@ describe("deriveTimelineEntries", () => { const entries = deriveTimelineEntries( [ { - id: MessageId.makeUnsafe("message-1"), + id: MessageId.make("message-1"), role: "assistant", text: "hello", createdAt: "2026-02-23T00:00:01.000Z", @@ -1032,7 +1032,7 @@ describe("deriveTimelineEntries", () => { [ { id: "plan:thread-1:turn:turn-1", - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), planMarkdown: "# Ship it", implementedAt: null, implementationThreadId: null, @@ -1065,14 +1065,14 @@ describe("deriveTimelineEntries", () => { const entries = deriveTimelineEntries( [ { - id: MessageId.makeUnsafe("assistant-earlier"), + id: MessageId.make("assistant-earlier"), role: "assistant", text: "progress update", createdAt: "2026-02-23T00:00:01.000Z", streaming: false, }, { - id: MessageId.makeUnsafe("assistant-final"), + id: MessageId.make("assistant-final"), role: "assistant", text: "final answer", createdAt: "2026-02-23T00:00:01.000Z", @@ -1085,7 +1085,7 @@ describe("deriveTimelineEntries", () => { expect( deriveCompletionDividerBeforeEntryId(entries, { - assistantMessageId: MessageId.makeUnsafe("assistant-final"), + assistantMessageId: MessageId.make("assistant-final"), startedAt: "2026-02-23T00:00:00.000Z", completedAt: "2026-02-23T00:00:02.000Z", }), @@ -1112,7 +1112,7 @@ describe("deriveWorkLogEntries context window handling", () => { tone: "tool", }), ], - TurnId.makeUnsafe("turn-1"), + TurnId.make("turn-1"), ); expect(entries).toHaveLength(1); @@ -1130,7 +1130,7 @@ describe("deriveWorkLogEntries context window handling", () => { tone: "info", }), ], - TurnId.makeUnsafe("turn-1"), + TurnId.make("turn-1"), ); expect(entries).toHaveLength(1); @@ -1154,14 +1154,14 @@ describe("hasToolActivityForTurn", () => { makeActivity({ id: "info-1", turnId: "turn-2", kind: "turn.completed", tone: "info" }), ]; - expect(hasToolActivityForTurn(activities, TurnId.makeUnsafe("turn-1"))).toBe(true); - expect(hasToolActivityForTurn(activities, TurnId.makeUnsafe("turn-2"))).toBe(false); + expect(hasToolActivityForTurn(activities, TurnId.make("turn-1"))).toBe(true); + expect(hasToolActivityForTurn(activities, TurnId.make("turn-2"))).toBe(false); }); }); describe("isLatestTurnSettled", () => { const latestTurn = { - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), startedAt: "2026-02-27T21:10:00.000Z", completedAt: "2026-02-27T21:10:06.000Z", } as const; @@ -1170,7 +1170,7 @@ describe("isLatestTurnSettled", () => { expect( isLatestTurnSettled(latestTurn, { orchestrationStatus: "running", - activeTurnId: TurnId.makeUnsafe("turn-1"), + activeTurnId: TurnId.make("turn-1"), }), ).toBe(false); }); @@ -1179,7 +1179,7 @@ describe("isLatestTurnSettled", () => { expect( isLatestTurnSettled(latestTurn, { orchestrationStatus: "running", - activeTurnId: TurnId.makeUnsafe("turn-2"), + activeTurnId: TurnId.make("turn-2"), }), ).toBe(false); }); @@ -1197,7 +1197,7 @@ describe("isLatestTurnSettled", () => { expect( isLatestTurnSettled( { - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), startedAt: null, completedAt: "2026-02-27T21:10:06.000Z", }, @@ -1209,7 +1209,7 @@ describe("isLatestTurnSettled", () => { describe("deriveActiveWorkStartedAt", () => { const latestTurn = { - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), startedAt: "2026-02-27T21:10:00.000Z", completedAt: "2026-02-27T21:10:06.000Z", } as const; @@ -1220,7 +1220,7 @@ describe("deriveActiveWorkStartedAt", () => { latestTurn, { orchestrationStatus: "running", - activeTurnId: TurnId.makeUnsafe("turn-1"), + activeTurnId: TurnId.make("turn-1"), }, "2026-02-27T21:11:00.000Z", ), @@ -1244,7 +1244,7 @@ describe("deriveActiveWorkStartedAt", () => { expect( deriveActiveWorkStartedAt( { - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), startedAt: "2026-02-27T21:10:00.000Z", completedAt: "2026-02-27T21:10:06.000Z", }, diff --git a/apps/web/src/session-logic.ts b/apps/web/src/session-logic.ts index 06bfee980326527c6d1444ecd03c66e52c49b3f5..54e84c883a475b6dd84cd6a8902959728f9734e6 100644 --- a/apps/web/src/session-logic.ts +++ b/apps/web/src/session-logic.ts @@ -193,7 +193,7 @@ export function derivePendingApprovals( : null; const requestId = payload && typeof payload.requestId === "string" - ? ApprovalRequestId.makeUnsafe(payload.requestId) + ? ApprovalRequestId.make(payload.requestId) : null; const requestKind = payload && @@ -299,7 +299,7 @@ export function derivePendingUserInputs( : null; const requestId = payload && typeof payload.requestId === "string" - ? ApprovalRequestId.makeUnsafe(payload.requestId) + ? ApprovalRequestId.make(payload.requestId) : null; const detail = payload && typeof payload.detail === "string" ? payload.detail : undefined; diff --git a/apps/web/src/store.test.ts b/apps/web/src/store.test.ts index 7606fad3057986284c07a98ad9865d434bc7b49f..7b7e786b67d1c96625f3c84dd719fcc68f419181 100644 --- a/apps/web/src/store.test.ts +++ b/apps/web/src/store.test.ts @@ -26,8 +26,8 @@ import { } from "./store"; import { DEFAULT_INTERACTION_MODE, DEFAULT_RUNTIME_MODE, type Thread } from "./types"; -const localEnvironmentId = EnvironmentId.makeUnsafe("environment-local"); -const remoteEnvironmentId = EnvironmentId.makeUnsafe("environment-remote"); +const localEnvironmentId = EnvironmentId.make("environment-local"); +const remoteEnvironmentId = EnvironmentId.make("environment-remote"); function withActiveEnvironmentState( environmentState: EnvironmentState, @@ -59,10 +59,10 @@ function withActiveEnvironmentState( function makeThread(overrides: Partial = {}): Thread { return { - id: ThreadId.makeUnsafe("thread-1"), + id: ThreadId.make("thread-1"), environmentId: localEnvironmentId, codexThreadId: null, - projectId: ProjectId.makeUnsafe("project-1"), + projectId: ProjectId.make("project-1"), title: "Thread", modelSelection: { provider: "codex", @@ -86,7 +86,7 @@ function makeThread(overrides: Partial = {}): Thread { } function makeState(thread: Thread): AppState { - const projectId = ProjectId.makeUnsafe("project-1"); + const projectId = ProjectId.make("project-1"); const project = { id: projectId, environmentId: thread.environmentId, @@ -226,14 +226,14 @@ function makeEvent( const sequence = overrides.sequence ?? 1; return { sequence, - eventId: EventId.makeUnsafe(`event-${sequence}`), + eventId: EventId.make(`event-${sequence}`), aggregateKind: "thread", aggregateId: "threadId" in payload ? payload.threadId : "projectId" in payload ? payload.projectId - : ProjectId.makeUnsafe("project-1"), + : ProjectId.make("project-1"), occurredAt: "2026-02-27T00:00:00.000Z", commandId: null, causationEventId: null, @@ -247,8 +247,8 @@ function makeEvent( function makeReadModelThread(overrides: Partial) { return { - id: ThreadId.makeUnsafe("thread-1"), - projectId: ProjectId.makeUnsafe("project-1"), + id: ThreadId.make("thread-1"), + projectId: ProjectId.make("project-1"), title: "Thread", modelSelection: { provider: "codex", @@ -278,7 +278,7 @@ function makeReadModel(thread: OrchestrationReadModel["threads"][number]): Orche updatedAt: "2026-02-27T00:00:00.000Z", projects: [ { - id: ProjectId.makeUnsafe("project-1"), + id: ProjectId.make("project-1"), title: "Project", workspaceRoot: "/tmp/project", defaultModelSelection: { @@ -299,7 +299,7 @@ function makeReadModelProject( overrides: Partial, ): OrchestrationReadModel["projects"][number] { return { - id: ProjectId.makeUnsafe("project-1"), + id: ProjectId.make("project-1"), title: "Project", workspaceRoot: "/tmp/project", defaultModelSelection: { @@ -316,7 +316,7 @@ function makeReadModelProject( describe("setThreadBranch", () => { it("updates only the scoped thread environment", () => { - const sharedThreadId = ThreadId.makeUnsafe("thread-shared"); + const sharedThreadId = ThreadId.make("thread-shared"); const localThread = makeThread({ id: sharedThreadId, environmentId: localEnvironmentId, @@ -397,7 +397,7 @@ describe("store read model sync", () => { model: "sonnet", }, session: { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), status: "ready", providerName: "claudeAgent", runtimeMode: "approval-required", @@ -444,9 +444,9 @@ describe("store read model sync", () => { }); it("replaces projects using snapshot order during recovery", () => { - const project1 = ProjectId.makeUnsafe("project-1"); - const project2 = ProjectId.makeUnsafe("project-2"); - const project3 = ProjectId.makeUnsafe("project-3"); + const project1 = ProjectId.make("project-1"); + const project2 = ProjectId.make("project-2"); + const project3 = ProjectId.make("project-3"); const initialState: AppState = makeEmptyState({ projectIds: [project2, project1], projectById: { @@ -516,7 +516,7 @@ describe("incremental orchestration updates", () => { const next = applyOrchestrationEvent( state, makeEvent("thread.meta-updated", { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), title: "Updated title", updatedAt: "2026-02-27T00:00:01.000Z", }), @@ -533,7 +533,7 @@ describe("incremental orchestration updates", () => { const nextAfterProjectDelete = applyOrchestrationEvent( state, makeEvent("project.deleted", { - projectId: ProjectId.makeUnsafe("project-missing"), + projectId: ProjectId.make("project-missing"), deletedAt: "2026-02-27T00:00:01.000Z", }), localEnvironmentId, @@ -541,7 +541,7 @@ describe("incremental orchestration updates", () => { const nextAfterThreadDelete = applyOrchestrationEvent( state, makeEvent("thread.deleted", { - threadId: ThreadId.makeUnsafe("thread-missing"), + threadId: ThreadId.make("thread-missing"), deletedAt: "2026-02-27T00:00:01.000Z", }), localEnvironmentId, @@ -552,8 +552,8 @@ describe("incremental orchestration updates", () => { }); it("reuses an existing project row when project.created arrives with a new id for the same cwd", () => { - const originalProjectId = ProjectId.makeUnsafe("project-1"); - const recreatedProjectId = ProjectId.makeUnsafe("project-2"); + const originalProjectId = ProjectId.make("project-1"); + const recreatedProjectId = ProjectId.make("project-2"); const state: AppState = makeEmptyState({ projectIds: [originalProjectId], projectById: { @@ -602,9 +602,9 @@ describe("incremental orchestration updates", () => { }); it("removes stale project index entries when thread.created recreates a thread under a new project", () => { - const originalProjectId = ProjectId.makeUnsafe("project-1"); - const recreatedProjectId = ProjectId.makeUnsafe("project-2"); - const threadId = ThreadId.makeUnsafe("thread-1"); + const originalProjectId = ProjectId.make("project-1"); + const recreatedProjectId = ProjectId.make("project-2"); + const threadId = ThreadId.make("thread-1"); const thread = makeThread({ id: threadId, projectId: originalProjectId, @@ -671,20 +671,20 @@ describe("incremental orchestration updates", () => { it("updates only the affected thread for message events", () => { const thread1 = makeThread({ - id: ThreadId.makeUnsafe("thread-1"), + id: ThreadId.make("thread-1"), messages: [ { - id: MessageId.makeUnsafe("message-1"), + id: MessageId.make("message-1"), role: "assistant", text: "hello", - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), createdAt: "2026-02-27T00:00:00.000Z", completedAt: "2026-02-27T00:00:00.000Z", streaming: false, }, ], }); - const thread2 = makeThread({ id: ThreadId.makeUnsafe("thread-2") }); + const thread2 = makeThread({ id: ThreadId.make("thread-2") }); const baseState = makeState(thread1); const baseEnvironmentState = localEnvironmentStateOf(baseState); const state = withActiveEnvironmentState(baseEnvironmentState, { @@ -762,10 +762,10 @@ describe("incremental orchestration updates", () => { state, makeEvent("thread.message-sent", { threadId: thread1.id, - messageId: MessageId.makeUnsafe("message-1"), + messageId: MessageId.make("message-1"), role: "assistant", text: " world", - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), streaming: true, createdAt: "2026-02-27T00:00:01.000Z", updatedAt: "2026-02-27T00:00:01.000Z", @@ -794,7 +794,7 @@ describe("incremental orchestration updates", () => { it("applies replay batches in sequence and updates session state", () => { const thread = makeThread({ latestTurn: { - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), state: "running", requestedAt: "2026-02-27T00:00:00.000Z", startedAt: "2026-02-27T00:00:00.000Z", @@ -816,7 +816,7 @@ describe("incremental orchestration updates", () => { status: "running", providerName: "codex", runtimeMode: "full-access", - activeTurnId: TurnId.makeUnsafe("turn-1"), + activeTurnId: TurnId.make("turn-1"), lastError: null, updatedAt: "2026-02-27T00:00:02.000Z", }, @@ -827,10 +827,10 @@ describe("incremental orchestration updates", () => { "thread.message-sent", { threadId: thread.id, - messageId: MessageId.makeUnsafe("assistant-1"), + messageId: MessageId.make("assistant-1"), role: "assistant", text: "done", - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), streaming: false, createdAt: "2026-02-27T00:00:03.000Z", updatedAt: "2026-02-27T00:00:03.000Z", @@ -850,7 +850,7 @@ describe("incremental orchestration updates", () => { const state = makeState( makeThread({ latestTurn: { - turnId: TurnId.makeUnsafe("turn-2"), + turnId: TurnId.make("turn-2"), state: "running", requestedAt: "2026-02-27T00:00:02.000Z", startedAt: "2026-02-27T00:00:03.000Z", @@ -863,13 +863,13 @@ describe("incremental orchestration updates", () => { const next = applyOrchestrationEvent( state, makeEvent("thread.turn-diff-completed", { - threadId: ThreadId.makeUnsafe("thread-1"), - turnId: TurnId.makeUnsafe("turn-1"), + threadId: ThreadId.make("thread-1"), + turnId: TurnId.make("turn-1"), checkpointTurnCount: 1, - checkpointRef: CheckpointRef.makeUnsafe("checkpoint-1"), + checkpointRef: CheckpointRef.make("checkpoint-1"), status: "ready", files: [], - assistantMessageId: MessageId.makeUnsafe("assistant-1"), + assistantMessageId: MessageId.make("assistant-1"), completedAt: "2026-02-27T00:00:04.000Z", }), localEnvironmentId, @@ -880,7 +880,7 @@ describe("incremental orchestration updates", () => { }); it("rebinds live turn diffs to the authoritative assistant message when it arrives later", () => { - const turnId = TurnId.makeUnsafe("turn-1"); + const turnId = TurnId.make("turn-1"); const state = makeState( makeThread({ latestTurn: { @@ -889,7 +889,7 @@ describe("incremental orchestration updates", () => { requestedAt: "2026-02-27T00:00:00.000Z", startedAt: "2026-02-27T00:00:00.000Z", completedAt: "2026-02-27T00:00:02.000Z", - assistantMessageId: MessageId.makeUnsafe("assistant:turn-1"), + assistantMessageId: MessageId.make("assistant:turn-1"), }, turnDiffSummaries: [ { @@ -897,8 +897,8 @@ describe("incremental orchestration updates", () => { completedAt: "2026-02-27T00:00:02.000Z", status: "ready", checkpointTurnCount: 1, - checkpointRef: CheckpointRef.makeUnsafe("checkpoint-1"), - assistantMessageId: MessageId.makeUnsafe("assistant:turn-1"), + checkpointRef: CheckpointRef.make("checkpoint-1"), + assistantMessageId: MessageId.make("assistant:turn-1"), files: [{ path: "src/app.ts", additions: 1, deletions: 0 }], }, ], @@ -908,8 +908,8 @@ describe("incremental orchestration updates", () => { const next = applyOrchestrationEvent( state, makeEvent("thread.message-sent", { - threadId: ThreadId.makeUnsafe("thread-1"), - messageId: MessageId.makeUnsafe("assistant-real"), + threadId: ThreadId.make("thread-1"), + messageId: MessageId.make("assistant-real"), role: "assistant", text: "final answer", turnId, @@ -921,10 +921,10 @@ describe("incremental orchestration updates", () => { ); expect(threadsOf(next)[0]?.turnDiffSummaries[0]?.assistantMessageId).toBe( - MessageId.makeUnsafe("assistant-real"), + MessageId.make("assistant-real"), ); expect(threadsOf(next)[0]?.latestTurn?.assistantMessageId).toBe( - MessageId.makeUnsafe("assistant-real"), + MessageId.make("assistant-real"), ); }); @@ -933,28 +933,28 @@ describe("incremental orchestration updates", () => { makeThread({ messages: [ { - id: MessageId.makeUnsafe("user-1"), + id: MessageId.make("user-1"), role: "user", text: "first", - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), createdAt: "2026-02-27T00:00:00.000Z", completedAt: "2026-02-27T00:00:00.000Z", streaming: false, }, { - id: MessageId.makeUnsafe("assistant-1"), + id: MessageId.make("assistant-1"), role: "assistant", text: "first reply", - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), createdAt: "2026-02-27T00:00:01.000Z", completedAt: "2026-02-27T00:00:01.000Z", streaming: false, }, { - id: MessageId.makeUnsafe("user-2"), + id: MessageId.make("user-2"), role: "user", text: "second", - turnId: TurnId.makeUnsafe("turn-2"), + turnId: TurnId.make("turn-2"), createdAt: "2026-02-27T00:00:02.000Z", completedAt: "2026-02-27T00:00:02.000Z", streaming: false, @@ -963,7 +963,7 @@ describe("incremental orchestration updates", () => { proposedPlans: [ { id: "plan-1", - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), planMarkdown: "plan 1", implementedAt: null, implementationThreadId: null, @@ -972,7 +972,7 @@ describe("incremental orchestration updates", () => { }, { id: "plan-2", - turnId: TurnId.makeUnsafe("turn-2"), + turnId: TurnId.make("turn-2"), planMarkdown: "plan 2", implementedAt: null, implementationThreadId: null, @@ -982,39 +982,39 @@ describe("incremental orchestration updates", () => { ], activities: [ { - id: EventId.makeUnsafe("activity-1"), + id: EventId.make("activity-1"), tone: "info", kind: "step", summary: "one", payload: {}, - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), createdAt: "2026-02-27T00:00:00.000Z", }, { - id: EventId.makeUnsafe("activity-2"), + id: EventId.make("activity-2"), tone: "info", kind: "step", summary: "two", payload: {}, - turnId: TurnId.makeUnsafe("turn-2"), + turnId: TurnId.make("turn-2"), createdAt: "2026-02-27T00:00:02.000Z", }, ], turnDiffSummaries: [ { - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), completedAt: "2026-02-27T00:00:01.000Z", status: "ready", checkpointTurnCount: 1, - checkpointRef: CheckpointRef.makeUnsafe("ref-1"), + checkpointRef: CheckpointRef.make("ref-1"), files: [], }, { - turnId: TurnId.makeUnsafe("turn-2"), + turnId: TurnId.make("turn-2"), completedAt: "2026-02-27T00:00:03.000Z", status: "ready", checkpointTurnCount: 2, - checkpointRef: CheckpointRef.makeUnsafe("ref-2"), + checkpointRef: CheckpointRef.make("ref-2"), files: [], }, ], @@ -1024,7 +1024,7 @@ describe("incremental orchestration updates", () => { const next = applyOrchestrationEvent( state, makeEvent("thread.reverted", { - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), turnCount: 1, }), localEnvironmentId, @@ -1036,46 +1036,46 @@ describe("incremental orchestration updates", () => { ]); expect(threadsOf(next)[0]?.proposedPlans.map((plan) => plan.id)).toEqual(["plan-1"]); expect(threadsOf(next)[0]?.activities.map((activity) => activity.id)).toEqual([ - EventId.makeUnsafe("activity-1"), + EventId.make("activity-1"), ]); expect(threadsOf(next)[0]?.turnDiffSummaries.map((summary) => summary.turnId)).toEqual([ - TurnId.makeUnsafe("turn-1"), + TurnId.make("turn-1"), ]); }); it("clears pending source proposed plans after revert before a new session-set event", () => { const thread = makeThread({ latestTurn: { - turnId: TurnId.makeUnsafe("turn-2"), + turnId: TurnId.make("turn-2"), state: "completed", requestedAt: "2026-02-27T00:00:02.000Z", startedAt: "2026-02-27T00:00:02.000Z", completedAt: "2026-02-27T00:00:03.000Z", - assistantMessageId: MessageId.makeUnsafe("assistant-2"), + assistantMessageId: MessageId.make("assistant-2"), sourceProposedPlan: { - threadId: ThreadId.makeUnsafe("thread-source"), + threadId: ThreadId.make("thread-source"), planId: "plan-2" as never, }, }, pendingSourceProposedPlan: { - threadId: ThreadId.makeUnsafe("thread-source"), + threadId: ThreadId.make("thread-source"), planId: "plan-2" as never, }, turnDiffSummaries: [ { - turnId: TurnId.makeUnsafe("turn-1"), + turnId: TurnId.make("turn-1"), completedAt: "2026-02-27T00:00:01.000Z", status: "ready", checkpointTurnCount: 1, - checkpointRef: CheckpointRef.makeUnsafe("ref-1"), + checkpointRef: CheckpointRef.make("ref-1"), files: [], }, { - turnId: TurnId.makeUnsafe("turn-2"), + turnId: TurnId.make("turn-2"), completedAt: "2026-02-27T00:00:03.000Z", status: "ready", checkpointTurnCount: 2, - checkpointRef: CheckpointRef.makeUnsafe("ref-2"), + checkpointRef: CheckpointRef.make("ref-2"), files: [], }, ], @@ -1100,7 +1100,7 @@ describe("incremental orchestration updates", () => { status: "running", providerName: "codex", runtimeMode: "full-access", - activeTurnId: TurnId.makeUnsafe("turn-3"), + activeTurnId: TurnId.make("turn-3"), lastError: null, updatedAt: "2026-02-27T00:00:04.000Z", }, @@ -1109,7 +1109,7 @@ describe("incremental orchestration updates", () => { ); expect(threadsOf(next)[0]?.latestTurn).toMatchObject({ - turnId: TurnId.makeUnsafe("turn-3"), + turnId: TurnId.make("turn-3"), state: "running", }); expect(threadsOf(next)[0]?.latestTurn?.sourceProposedPlan).toBeUndefined(); diff --git a/apps/web/src/terminalStateStore.test.ts b/apps/web/src/terminalStateStore.test.ts index 37d5ba5d0f64c569d973edf6e33af4eb7dde4262..eceb621ac7ea33618f62f7f5be0d86e6368c99dc 100644 --- a/apps/web/src/terminalStateStore.test.ts +++ b/apps/web/src/terminalStateStore.test.ts @@ -9,7 +9,7 @@ import { useTerminalStateStore, } from "./terminalStateStore"; -const THREAD_ID = ThreadId.makeUnsafe("thread-1"); +const THREAD_ID = ThreadId.make("thread-1"); const THREAD_REF = scopeThreadRef("environment-a" as never, THREAD_ID); const OTHER_THREAD_REF = scopeThreadRef("environment-b" as never, THREAD_ID); diff --git a/apps/web/src/threadRoutes.test.ts b/apps/web/src/threadRoutes.test.ts index b2010dd16d604595c47e6e56ad411485729cd775..dde5f9306f56b3f5eb365dca111a6cee24abb981 100644 --- a/apps/web/src/threadRoutes.test.ts +++ b/apps/web/src/threadRoutes.test.ts @@ -12,7 +12,7 @@ import { describe("threadRoutes", () => { it("builds canonical thread route params from a scoped ref", () => { - const ref = scopeThreadRef("env-1" as never, ThreadId.makeUnsafe("thread-1")); + const ref = scopeThreadRef("env-1" as never, ThreadId.make("thread-1")); expect(buildThreadRouteParams(ref)).toEqual({ environmentId: "env-1", @@ -36,7 +36,7 @@ describe("threadRoutes", () => { }); it("builds canonical draft route params from a draft id", () => { - expect(buildDraftThreadRouteParams(DraftId.makeUnsafe("draft-1"))).toEqual({ + expect(buildDraftThreadRouteParams(DraftId.make("draft-1"))).toEqual({ draftId: "draft-1", }); }); diff --git a/apps/web/src/threadSelectionStore.test.ts b/apps/web/src/threadSelectionStore.test.ts index 818cebc72dfb1d46246725259562913c921c8f60..7d1ecbd9a6b8c7a0e68f2e223f1486622f94e633 100644 --- a/apps/web/src/threadSelectionStore.test.ts +++ b/apps/web/src/threadSelectionStore.test.ts @@ -3,11 +3,11 @@ import { beforeEach, describe, expect, it } from "vitest"; import { useThreadSelectionStore } from "./threadSelectionStore"; -const THREAD_A = ThreadId.makeUnsafe("thread-a"); -const THREAD_B = ThreadId.makeUnsafe("thread-b"); -const THREAD_C = ThreadId.makeUnsafe("thread-c"); -const THREAD_D = ThreadId.makeUnsafe("thread-d"); -const THREAD_E = ThreadId.makeUnsafe("thread-e"); +const THREAD_A = ThreadId.make("thread-a"); +const THREAD_B = ThreadId.make("thread-b"); +const THREAD_C = ThreadId.make("thread-c"); +const THREAD_D = ThreadId.make("thread-d"); +const THREAD_E = ThreadId.make("thread-e"); const ORDERED = [THREAD_A, THREAD_B, THREAD_C, THREAD_D, THREAD_E] as const; @@ -173,7 +173,7 @@ describe("threadSelectionStore", () => { it("falls back to toggle when target is not in the ordered list", () => { const store = useThreadSelectionStore.getState(); store.toggleThread(THREAD_B); // anchor = B - const unknownThread = ThreadId.makeUnsafe("thread-unknown"); + const unknownThread = ThreadId.make("thread-unknown"); store.rangeSelectTo(unknownThread, ORDERED); const state = useThreadSelectionStore.getState(); diff --git a/apps/web/src/uiStateStore.test.ts b/apps/web/src/uiStateStore.test.ts index 950a7e11ff1dd4d8bd971c8e4ab1d60154fc6a3e..0f3b9129b3540e2a00ae2d9cbac4bbd3685089c6 100644 --- a/apps/web/src/uiStateStore.test.ts +++ b/apps/web/src/uiStateStore.test.ts @@ -22,7 +22,7 @@ function makeUiState(overrides: Partial = {}): UiState { describe("uiStateStore pure functions", () => { it("markThreadUnread moves lastVisitedAt before completion for a completed thread", () => { - const threadId = ThreadId.makeUnsafe("thread-1"); + const threadId = ThreadId.make("thread-1"); const latestTurnCompletedAt = "2026-02-25T12:30:00.000Z"; const initialState = makeUiState({ threadLastVisitedAtById: { @@ -36,7 +36,7 @@ describe("uiStateStore pure functions", () => { }); it("markThreadUnread does not change a thread without a completed turn", () => { - const threadId = ThreadId.makeUnsafe("thread-1"); + const threadId = ThreadId.make("thread-1"); const initialState = makeUiState({ threadLastVisitedAtById: { [threadId]: "2026-02-25T12:35:00.000Z", @@ -49,9 +49,9 @@ describe("uiStateStore pure functions", () => { }); it("reorderProjects moves a project to a target index", () => { - const project1 = ProjectId.makeUnsafe("project-1"); - const project2 = ProjectId.makeUnsafe("project-2"); - const project3 = ProjectId.makeUnsafe("project-3"); + const project1 = ProjectId.make("project-1"); + const project2 = ProjectId.make("project-2"); + const project3 = ProjectId.make("project-3"); const initialState = makeUiState({ projectOrder: [project1, project2, project3], }); @@ -62,9 +62,9 @@ describe("uiStateStore pure functions", () => { }); it("syncProjects preserves current project order during snapshot recovery", () => { - const project1 = ProjectId.makeUnsafe("project-1"); - const project2 = ProjectId.makeUnsafe("project-2"); - const project3 = ProjectId.makeUnsafe("project-3"); + const project1 = ProjectId.make("project-1"); + const project2 = ProjectId.make("project-2"); + const project3 = ProjectId.make("project-3"); const initialState = makeUiState({ projectExpandedById: { [project1]: true, @@ -84,9 +84,9 @@ describe("uiStateStore pure functions", () => { }); it("syncProjects preserves manual order when a project is recreated with the same cwd", () => { - const oldProject1 = ProjectId.makeUnsafe("project-1"); - const oldProject2 = ProjectId.makeUnsafe("project-2"); - const recreatedProject2 = ProjectId.makeUnsafe("project-2b"); + const oldProject1 = ProjectId.make("project-1"); + const oldProject2 = ProjectId.make("project-2"); + const recreatedProject2 = ProjectId.make("project-2b"); const initialState = syncProjects( makeUiState({ projectExpandedById: { @@ -111,7 +111,7 @@ describe("uiStateStore pure functions", () => { }); it("syncProjects returns a new state when only project cwd changes", () => { - const project1 = ProjectId.makeUnsafe("project-1"); + const project1 = ProjectId.make("project-1"); const initialState = syncProjects( makeUiState({ projectExpandedById: { @@ -130,8 +130,8 @@ describe("uiStateStore pure functions", () => { }); it("syncThreads prunes missing thread UI state", () => { - const thread1 = ThreadId.makeUnsafe("thread-1"); - const thread2 = ThreadId.makeUnsafe("thread-2"); + const thread1 = ThreadId.make("thread-1"); + const thread2 = ThreadId.make("thread-2"); const initialState = makeUiState({ threadLastVisitedAtById: { [thread1]: "2026-02-25T12:35:00.000Z", @@ -147,7 +147,7 @@ describe("uiStateStore pure functions", () => { }); it("syncThreads seeds visit state for unseen snapshot threads", () => { - const thread1 = ThreadId.makeUnsafe("thread-1"); + const thread1 = ThreadId.make("thread-1"); const initialState = makeUiState(); const next = syncThreads(initialState, [ @@ -163,7 +163,7 @@ describe("uiStateStore pure functions", () => { }); it("setProjectExpanded updates expansion without touching order", () => { - const project1 = ProjectId.makeUnsafe("project-1"); + const project1 = ProjectId.make("project-1"); const initialState = makeUiState({ projectExpandedById: { [project1]: true, @@ -178,7 +178,7 @@ describe("uiStateStore pure functions", () => { }); it("clearThreadUi removes visit state for deleted threads", () => { - const thread1 = ThreadId.makeUnsafe("thread-1"); + const thread1 = ThreadId.make("thread-1"); const initialState = makeUiState({ threadLastVisitedAtById: { [thread1]: "2026-02-25T12:35:00.000Z", diff --git a/apps/web/src/worktreeCleanup.test.ts b/apps/web/src/worktreeCleanup.test.ts index 1af904495c66287c048eaf29708dbe15b151a0a8..bdd5bb12a06f413a78aeca351c346be912bd9d91 100644 --- a/apps/web/src/worktreeCleanup.test.ts +++ b/apps/web/src/worktreeCleanup.test.ts @@ -4,14 +4,14 @@ import { describe, expect, it } from "vitest"; import { DEFAULT_INTERACTION_MODE, DEFAULT_RUNTIME_MODE, type Thread } from "./types"; import { formatWorktreePathForDisplay, getOrphanedWorktreePathForThread } from "./worktreeCleanup"; -const localEnvironmentId = EnvironmentId.makeUnsafe("environment-local"); +const localEnvironmentId = EnvironmentId.make("environment-local"); function makeThread(overrides: Partial = {}): Thread { return { - id: ThreadId.makeUnsafe("thread-1"), + id: ThreadId.make("thread-1"), environmentId: localEnvironmentId, codexThreadId: null, - projectId: ProjectId.makeUnsafe("project-1"), + projectId: ProjectId.make("project-1"), title: "Thread", modelSelection: { provider: "codex", @@ -36,49 +36,49 @@ function makeThread(overrides: Partial = {}): Thread { describe("getOrphanedWorktreePathForThread", () => { it("returns null when the target thread does not exist", () => { - const result = getOrphanedWorktreePathForThread([], ThreadId.makeUnsafe("missing-thread")); + const result = getOrphanedWorktreePathForThread([], ThreadId.make("missing-thread")); expect(result).toBeNull(); }); it("returns null when the target thread has no worktree", () => { const threads = [makeThread()]; - const result = getOrphanedWorktreePathForThread(threads, ThreadId.makeUnsafe("thread-1")); + const result = getOrphanedWorktreePathForThread(threads, ThreadId.make("thread-1")); expect(result).toBeNull(); }); it("returns the path when no other thread links to that worktree", () => { const threads = [makeThread({ worktreePath: "/tmp/repo/worktrees/feature-a" })]; - const result = getOrphanedWorktreePathForThread(threads, ThreadId.makeUnsafe("thread-1")); + const result = getOrphanedWorktreePathForThread(threads, ThreadId.make("thread-1")); expect(result).toBe("/tmp/repo/worktrees/feature-a"); }); it("returns null when another thread links to the same worktree", () => { const threads = [ makeThread({ - id: ThreadId.makeUnsafe("thread-1"), + id: ThreadId.make("thread-1"), worktreePath: "/tmp/repo/worktrees/feature-a", }), makeThread({ - id: ThreadId.makeUnsafe("thread-2"), + id: ThreadId.make("thread-2"), worktreePath: "/tmp/repo/worktrees/feature-a", }), ]; - const result = getOrphanedWorktreePathForThread(threads, ThreadId.makeUnsafe("thread-1")); + const result = getOrphanedWorktreePathForThread(threads, ThreadId.make("thread-1")); expect(result).toBeNull(); }); it("ignores threads linked to different worktrees", () => { const threads = [ makeThread({ - id: ThreadId.makeUnsafe("thread-1"), + id: ThreadId.make("thread-1"), worktreePath: "/tmp/repo/worktrees/feature-a", }), makeThread({ - id: ThreadId.makeUnsafe("thread-2"), + id: ThreadId.make("thread-2"), worktreePath: "/tmp/repo/worktrees/feature-b", }), ]; - const result = getOrphanedWorktreePathForThread(threads, ThreadId.makeUnsafe("thread-1")); + const result = getOrphanedWorktreePathForThread(threads, ThreadId.make("thread-1")); expect(result).toBe("/tmp/repo/worktrees/feature-a"); }); }); diff --git a/apps/web/test/authHttpHandlers.ts b/apps/web/test/authHttpHandlers.ts index 8b9e005166f516e4c07095313c1b67d50ca9ab2d..6ff158fc696779d883fae6f1851755f64f6ecf4e 100644 --- a/apps/web/test/authHttpHandlers.ts +++ b/apps/web/test/authHttpHandlers.ts @@ -7,7 +7,7 @@ import { HttpResponse, http } from "msw"; const TEST_SESSION_EXPIRES_AT = "2026-05-01T12:00:00.000Z"; const TEST_ENVIRONMENT_DESCRIPTOR: ExecutionEnvironmentDescriptor = { - environmentId: EnvironmentId.makeUnsafe("environment-local"), + environmentId: EnvironmentId.make("environment-local"), label: "Local environment", platform: { os: "darwin", diff --git a/bun.lock b/bun.lock index f5e71fbed35376fe75174967dd8740ee78c578f2..f54517fddbf789f5b73cce587a79aa5f34773892 100644 --- a/bun.lock +++ b/bun.lock @@ -189,16 +189,16 @@ "vite": "^8.0.0", }, "catalog": { - "@effect/atom-react": "4.0.0-beta.43", + "@effect/atom-react": "4.0.0-beta.45", "@effect/language-service": "0.84.2", - "@effect/platform-bun": "4.0.0-beta.43", - "@effect/platform-node": "4.0.0-beta.43", - "@effect/platform-node-shared": "4.0.0-beta.43", - "@effect/sql-sqlite-bun": "4.0.0-beta.43", - "@effect/vitest": "4.0.0-beta.43", + "@effect/platform-bun": "4.0.0-beta.45", + "@effect/platform-node": "4.0.0-beta.45", + "@effect/platform-node-shared": "4.0.0-beta.45", + "@effect/sql-sqlite-bun": "4.0.0-beta.45", + "@effect/vitest": "4.0.0-beta.45", "@types/bun": "^1.3.9", "@types/node": "^24.10.13", - "effect": "4.0.0-beta.43", + "effect": "4.0.0-beta.45", "tsdown": "^0.20.3", "typescript": "^5.7.3", "vitest": "^4.0.0", @@ -284,19 +284,19 @@ "@dnd-kit/utilities": ["@dnd-kit/utilities@3.2.2", "", { "dependencies": { "tslib": "^2.0.0" }, "peerDependencies": { "react": ">=16.8.0" } }, "sha512-+MKAJEOfaBe5SmV6t34p80MMKhjvUz0vRrvVJbPT0WElzaOJ/1xs+D+KDv+tD/NE5ujfrChEcshd4fLn0wpiqg=="], - "@effect/atom-react": ["@effect/atom-react@4.0.0-beta.43", "", { "peerDependencies": { "effect": "^4.0.0-beta.43", "react": "^19.2.4", "scheduler": "*" } }, "sha512-xSrRbGXuo4d0g4ph66TQST1GNSjtQZrZj8V7OiAQFuzMYcZ0kwRIPUUFwOBtbWHK43/zNENdNWOnlXh/iYM1dw=="], + "@effect/atom-react": ["@effect/atom-react@4.0.0-beta.45", "", { "peerDependencies": { "effect": "^4.0.0-beta.45", "react": "^19.2.4", "scheduler": "*" } }, "sha512-jCoiae9UNeis9Yoal1p5V/P4eJK9nX89wORom7X5LpR2Ok920SZJc8dIeYkRXRAp9BCYJ/yWcO8gGLf7do71vg=="], "@effect/language-service": ["@effect/language-service@0.84.2", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-l04qNxpiA8rY5yXWckRPJ7Mk5MNerXuNymSFf+IdflfI5i8jgL1bpBNLuP6ijg7wgjdHc/KmTnCj2kT0SCntuA=="], - "@effect/platform-bun": ["@effect/platform-bun@4.0.0-beta.43", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-beta.43" }, "peerDependencies": { "effect": "^4.0.0-beta.43" } }, "sha512-nMZ9JsD6CzJNQ+5pDUFbPw7PSZdQdTQ092MbYrocVtvlf6qEFU/hji3ITvRIOX7eabyQ8AUyp55qFPQUeq+GIA=="], + "@effect/platform-bun": ["@effect/platform-bun@4.0.0-beta.45", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-beta.45" }, "peerDependencies": { "effect": "^4.0.0-beta.45" } }, "sha512-dZsbkJ+o4JfKE1OIAlMq8YWhmEfXxtTYennYADK/M/XlOtkFLsc2jkZppDvMznVni6JpFxWc7wd5rUf8jBVP5g=="], - "@effect/platform-node": ["@effect/platform-node@4.0.0-beta.43", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-beta.43", "mime": "^4.1.0", "undici": "^7.24.0" }, "peerDependencies": { "effect": "^4.0.0-beta.43", "ioredis": "^5.7.0" } }, "sha512-Uq6E1rjaIpjHauzjwoB2HzAg3battYt2Boy8XO50GoHiWCXKE6WapYZ0/AnaBx5v5qg2sOfqpuiLsUf9ZgxOkA=="], + "@effect/platform-node": ["@effect/platform-node@4.0.0-beta.45", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-beta.45", "mime": "^4.1.0", "undici": "^7.24.0" }, "peerDependencies": { "effect": "^4.0.0-beta.45", "ioredis": "^5.7.0" } }, "sha512-P07NMG4eoy62iLX9szak0hkr7hrwgq5+XMkm7URVug/3zqfZVxEG2kxn9JzVK1lF5WbaVrEKwjt3IkEJxzSPtg=="], - "@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-beta.43", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.19.0" }, "peerDependencies": { "effect": "^4.0.0-beta.43" } }, "sha512-A9q0GEb61pYcQ06Dr6gXj1nKlDI3KHsar1sk3qb1ZY+kVSR64tBAylI8zGon23KY+NPtTUj/sEIToB7jc3Qt5w=="], + "@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-beta.45", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.19.0" }, "peerDependencies": { "effect": "^4.0.0-beta.45" } }, "sha512-0T4RG18o+aCVUSlmPxA7uAjHJkyE3MS/uRrR5kCNSZQNG3X71wdIbu82wE/MnV6+6YSSPDx/6TVdZWYkJF0JWw=="], - "@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@4.0.0-beta.43", "", { "peerDependencies": { "effect": "^4.0.0-beta.43" } }, "sha512-Ryb7x0rBjW5NHegbzvz9y2Yv4KpwZ1UiPk7/Rv+Mkux74Qkjdmotmrvy9P+M5A9TZyL2Av+GpaLTPJKsL0PG+Q=="], + "@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@4.0.0-beta.45", "", { "peerDependencies": { "effect": "^4.0.0-beta.45" } }, "sha512-sJBBztwI4YxjdjhdyjWelh3KKoZucmmZS2ONeNDIzYgqFlsrwEEUrhVkWf5ch9Io+kUUzeb6q7/SedFoLUWO7g=="], - "@effect/vitest": ["@effect/vitest@4.0.0-beta.43", "", { "peerDependencies": { "effect": "^4.0.0-beta.43", "vitest": "^3.0.0 || ^4.0.0" } }, "sha512-XN2LAwiUWPqbV2jrsYYRjrVydQ8MIgwr83MVImtUaOQco4vk43+8OHlXQMRN/u2HnGK29KT+O2yTMMBdk2Q6Sw=="], + "@effect/vitest": ["@effect/vitest@4.0.0-beta.45", "", { "peerDependencies": { "effect": "^4.0.0-beta.45", "vitest": "^3.0.0 || ^4.0.0" } }, "sha512-38JA5Z6c2FoEhpVKbl7rjTrMU8Al5T30Kwtb6N3B9kOkyr2SsmvNsP9T65bh03IBh3ak9U//acrkmjS3hLQwKA=="], "@electron/get": ["@electron/get@2.0.3", "", { "dependencies": { "debug": "^4.1.1", "env-paths": "^2.2.0", "fs-extra": "^8.1.0", "got": "^11.8.5", "progress": "^2.0.3", "semver": "^6.2.0", "sumchecker": "^3.0.1" }, "optionalDependencies": { "global-agent": "^3.0.0" } }, "sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ=="], @@ -1018,7 +1018,7 @@ "dts-resolver": ["dts-resolver@2.1.3", "", { "peerDependencies": { "oxc-resolver": ">=11.0.0" }, "optionalPeers": ["oxc-resolver"] }, "sha512-bihc7jPC90VrosXNzK0LTE2cuLP6jr0Ro8jk+kMugHReJVLIpHz/xadeq3MhuwyO4TD4OA3L1Q8pBBFRc08Tsw=="], - "effect": ["effect@4.0.0-beta.43", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.5.3", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.8", "multipasta": "^0.2.7", "toml": "^3.0.0", "uuid": "^13.0.0", "yaml": "^2.8.2" } }, "sha512-AJYyDimIwJOn87uUz/JzmgDc5GfjxJbXvEbTvNzMa+M3Uer344bLo/O5mMRkqc1vBleA+Ygs4+dbE3QsqOkKTQ=="], + "effect": ["effect@4.0.0-beta.45", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "fast-check": "^4.5.3", "find-my-way-ts": "^0.1.6", "ini": "^6.0.0", "kubernetes-types": "^1.30.0", "msgpackr": "^1.11.8", "multipasta": "^0.2.7", "toml": "^3.0.0", "uuid": "^13.0.0", "yaml": "^2.8.2" } }, "sha512-vvNrUWqnzBIW1hRMa+zw0CLRW6HLgdu7hQ6K7PT/rS+UY/73Ma11O+Oi9oc9zwL8KcN37M47UDseAdlF0bGNWw=="], "electron": ["electron@40.6.0", "", { "dependencies": { "@electron/get": "^2.0.0", "@types/node": "^24.9.0", "extract-zip": "^2.0.1" }, "bin": { "electron": "cli.js" } }, "sha512-ett8W+yOFGDuM0vhJMamYSkrbV3LoaffzJd9GfjI96zRAxyrNqUSKqBpf/WGbQCweDxX2pkUCUfrv4wwKpsFZA=="], diff --git a/package.json b/package.json index f0a158a6215e025f39a2547ebdbb5ddf274d7bce..8fe4a986724dfca17cc1657b350b657189639ee5 100644 --- a/package.json +++ b/package.json @@ -8,13 +8,13 @@ "scripts" ], "catalog": { - "effect": "4.0.0-beta.43", - "@effect/atom-react": "4.0.0-beta.43", - "@effect/platform-bun": "4.0.0-beta.43", - "@effect/platform-node": "4.0.0-beta.43", - "@effect/platform-node-shared": "4.0.0-beta.43", - "@effect/sql-sqlite-bun": "4.0.0-beta.43", - "@effect/vitest": "4.0.0-beta.43", + "effect": "4.0.0-beta.45", + "@effect/atom-react": "4.0.0-beta.45", + "@effect/platform-bun": "4.0.0-beta.45", + "@effect/platform-node": "4.0.0-beta.45", + "@effect/platform-node-shared": "4.0.0-beta.45", + "@effect/sql-sqlite-bun": "4.0.0-beta.45", + "@effect/vitest": "4.0.0-beta.45", "@effect/language-service": "0.84.2", "@types/bun": "^1.3.9", "@types/node": "^24.10.13", diff --git a/packages/client-runtime/src/knownEnvironment.test.ts b/packages/client-runtime/src/knownEnvironment.test.ts index a09954a05a22711a049d4ea98524b83c4e94ab3b..dca56c1e6da1d68e887538f03ecb357b31ded72e 100644 --- a/packages/client-runtime/src/knownEnvironment.test.ts +++ b/packages/client-runtime/src/knownEnvironment.test.ts @@ -61,9 +61,9 @@ describe("known environment bootstrap helpers", () => { }); describe("scoped refs", () => { - const environmentId = EnvironmentId.makeUnsafe("environment-test"); - const projectRef = scopeProjectRef(environmentId, ProjectId.makeUnsafe("project-1")); - const threadRef = scopeThreadRef(environmentId, ThreadId.makeUnsafe("thread-1")); + const environmentId = EnvironmentId.make("environment-test"); + const projectRef = scopeProjectRef(environmentId, ProjectId.make("project-1")); + const threadRef = scopeThreadRef(environmentId, ThreadId.make("thread-1")); it("builds stable scoped project and thread keys", () => { expect(scopedRefKey(projectRef)).toBe("environment-test:project-1"); @@ -75,11 +75,11 @@ describe("scoped refs", () => { it("returns typed scoped refs", () => { expect(projectRef).toEqual({ environmentId, - projectId: ProjectId.makeUnsafe("project-1"), + projectId: ProjectId.make("project-1"), }); expect(threadRef).toEqual({ environmentId, - threadId: ThreadId.makeUnsafe("thread-1"), + threadId: ThreadId.make("thread-1"), }); }); diff --git a/packages/contracts/src/baseSchemas.ts b/packages/contracts/src/baseSchemas.ts index 9178ef8da78c6cea0ab1f8e9dd8aaa57529b4853..10ee6851be259568eb8115f0e3d374be04b5c801 100644 --- a/packages/contracts/src/baseSchemas.ts +++ b/packages/contracts/src/baseSchemas.ts @@ -12,8 +12,9 @@ export type IsoDateTime = typeof IsoDateTime.Type; /** * Construct a branded identifier. Enforces non-empty trimmed strings */ -const makeEntityId = (brand: Brand) => - TrimmedNonEmptyString.pipe(Schema.brand(brand)); +const makeEntityId = (brand: Brand) => { + return TrimmedNonEmptyString.pipe(Schema.brand(brand)); +}; export const ThreadId = makeEntityId("ThreadId"); export type ThreadId = typeof ThreadId.Type; diff --git a/packages/contracts/src/environment.ts b/packages/contracts/src/environment.ts index 9e97be83eaf0db943464a62093a00e39f3e0c95a..bc3b5459cd9a8a056355b13756ccbaf08642ef88 100644 --- a/packages/contracts/src/environment.ts +++ b/packages/contracts/src/environment.ts @@ -1,4 +1,4 @@ -import { Schema } from "effect"; +import { Effect, Schema } from "effect"; import { EnvironmentId, ProjectId, ThreadId, TrimmedNonEmptyString } from "./baseSchemas"; @@ -20,7 +20,7 @@ export const ExecutionEnvironmentPlatform = Schema.Struct({ export type ExecutionEnvironmentPlatform = typeof ExecutionEnvironmentPlatform.Type; export const ExecutionEnvironmentCapabilities = Schema.Struct({ - repositoryIdentity: Schema.Boolean.pipe(Schema.withDecodingDefault(() => false)), + repositoryIdentity: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))), }); export type ExecutionEnvironmentCapabilities = typeof ExecutionEnvironmentCapabilities.Type; diff --git a/packages/contracts/src/orchestration.ts b/packages/contracts/src/orchestration.ts index 07e230dbf3fb56ef07e1a725bf593e14cc9a9452..c80367d1587e204e34c8c729da82d9e8f0fffddb 100644 --- a/packages/contracts/src/orchestration.ts +++ b/packages/contracts/src/orchestration.ts @@ -1,4 +1,4 @@ -import { Option, Schema, SchemaIssue, Struct } from "effect"; +import { Effect, Option, Schema, SchemaIssue, Struct } from "effect"; import { ClaudeModelOptions, CodexModelOptions } from "./model"; import { RepositoryIdentity } from "./environment"; import { @@ -177,8 +177,10 @@ export const OrchestrationProposedPlan = Schema.Struct({ id: OrchestrationProposedPlanId, turnId: Schema.NullOr(TurnId), planMarkdown: TrimmedNonEmptyString, - implementedAt: Schema.NullOr(IsoDateTime).pipe(Schema.withDecodingDefault(() => null)), - implementationThreadId: Schema.NullOr(ThreadId).pipe(Schema.withDecodingDefault(() => null)), + implementedAt: Schema.NullOr(IsoDateTime).pipe(Schema.withDecodingDefault(Effect.succeed(null))), + implementationThreadId: Schema.NullOr(ThreadId).pipe( + Schema.withDecodingDefault(Effect.succeed(null)), + ), createdAt: IsoDateTime, updatedAt: IsoDateTime, }); @@ -204,7 +206,7 @@ export const OrchestrationSession = Schema.Struct({ threadId: ThreadId, status: OrchestrationSessionStatus, providerName: Schema.NullOr(TrimmedNonEmptyString), - runtimeMode: RuntimeMode.pipe(Schema.withDecodingDefault(() => DEFAULT_RUNTIME_MODE)), + runtimeMode: RuntimeMode.pipe(Schema.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE))), activeTurnId: Schema.NullOr(TurnId), lastError: Schema.NullOr(TrimmedNonEmptyString), updatedAt: IsoDateTime, @@ -279,17 +281,19 @@ export const OrchestrationThread = Schema.Struct({ modelSelection: ModelSelection, runtimeMode: RuntimeMode, interactionMode: ProviderInteractionMode.pipe( - Schema.withDecodingDefault(() => DEFAULT_PROVIDER_INTERACTION_MODE), + Schema.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE)), ), branch: Schema.NullOr(TrimmedNonEmptyString), worktreePath: Schema.NullOr(TrimmedNonEmptyString), latestTurn: Schema.NullOr(OrchestrationLatestTurn), createdAt: IsoDateTime, updatedAt: IsoDateTime, - archivedAt: Schema.NullOr(IsoDateTime).pipe(Schema.withDecodingDefault(() => null)), + archivedAt: Schema.NullOr(IsoDateTime).pipe(Schema.withDecodingDefault(Effect.succeed(null))), deletedAt: Schema.NullOr(IsoDateTime), messages: Schema.Array(OrchestrationMessage), - proposedPlans: Schema.Array(OrchestrationProposedPlan).pipe(Schema.withDecodingDefault(() => [])), + proposedPlans: Schema.Array(OrchestrationProposedPlan).pipe( + Schema.withDecodingDefault(Effect.succeed([])), + ), activities: Schema.Array(OrchestrationThreadActivity), checkpoints: Schema.Array(OrchestrationCheckpointSummary), session: Schema.NullOr(OrchestrationSession), @@ -339,7 +343,7 @@ const ThreadCreateCommand = Schema.Struct({ modelSelection: ModelSelection, runtimeMode: RuntimeMode, interactionMode: ProviderInteractionMode.pipe( - Schema.withDecodingDefault(() => DEFAULT_PROVIDER_INTERACTION_MODE), + Schema.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE)), ), branch: Schema.NullOr(TrimmedNonEmptyString), worktreePath: Schema.NullOr(TrimmedNonEmptyString), @@ -427,9 +431,9 @@ export const ThreadTurnStartCommand = Schema.Struct({ }), modelSelection: Schema.optional(ModelSelection), titleSeed: Schema.optional(TrimmedNonEmptyString), - runtimeMode: RuntimeMode.pipe(Schema.withDecodingDefault(() => DEFAULT_RUNTIME_MODE)), + runtimeMode: RuntimeMode.pipe(Schema.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE))), interactionMode: ProviderInteractionMode.pipe( - Schema.withDecodingDefault(() => DEFAULT_PROVIDER_INTERACTION_MODE), + Schema.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE)), ), bootstrap: Schema.optional(ThreadTurnStartBootstrap), sourceProposedPlan: Schema.optional(SourceProposedPlanReference), @@ -680,9 +684,9 @@ export const ThreadCreatedPayload = Schema.Struct({ projectId: ProjectId, title: TrimmedNonEmptyString, modelSelection: ModelSelection, - runtimeMode: RuntimeMode.pipe(Schema.withDecodingDefault(() => DEFAULT_RUNTIME_MODE)), + runtimeMode: RuntimeMode.pipe(Schema.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE))), interactionMode: ProviderInteractionMode.pipe( - Schema.withDecodingDefault(() => DEFAULT_PROVIDER_INTERACTION_MODE), + Schema.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE)), ), branch: Schema.NullOr(TrimmedNonEmptyString), worktreePath: Schema.NullOr(TrimmedNonEmptyString), @@ -724,7 +728,7 @@ export const ThreadRuntimeModeSetPayload = Schema.Struct({ export const ThreadInteractionModeSetPayload = Schema.Struct({ threadId: ThreadId, interactionMode: ProviderInteractionMode.pipe( - Schema.withDecodingDefault(() => DEFAULT_PROVIDER_INTERACTION_MODE), + Schema.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE)), ), updatedAt: IsoDateTime, }); @@ -746,9 +750,9 @@ export const ThreadTurnStartRequestedPayload = Schema.Struct({ messageId: MessageId, modelSelection: Schema.optional(ModelSelection), titleSeed: Schema.optional(TrimmedNonEmptyString), - runtimeMode: RuntimeMode.pipe(Schema.withDecodingDefault(() => DEFAULT_RUNTIME_MODE)), + runtimeMode: RuntimeMode.pipe(Schema.withDecodingDefault(Effect.succeed(DEFAULT_RUNTIME_MODE))), interactionMode: ProviderInteractionMode.pipe( - Schema.withDecodingDefault(() => DEFAULT_PROVIDER_INTERACTION_MODE), + Schema.withDecodingDefault(Effect.succeed(DEFAULT_PROVIDER_INTERACTION_MODE)), ), sourceProposedPlan: Schema.optional(SourceProposedPlanReference), createdAt: IsoDateTime, diff --git a/packages/contracts/src/providerRuntime.ts b/packages/contracts/src/providerRuntime.ts index 81231d88f6816c70badcf7cf5d3f03875632e6a6..6b03d70d56c0bb624804450b337b04e26e6d4148 100644 --- a/packages/contracts/src/providerRuntime.ts +++ b/packages/contracts/src/providerRuntime.ts @@ -1,4 +1,4 @@ -import { Option, Schema } from "effect"; +import { Effect, Schema } from "effect"; import { EventId, IsoDateTime, @@ -435,7 +435,7 @@ export const UserInputQuestion = Schema.Struct({ question: TrimmedNonEmptyStringSchema, options: Schema.Array(UserInputQuestionOption), multiSelect: Schema.optional(Schema.Boolean).pipe( - Schema.withConstructorDefault(() => Option.some(false)), + Schema.withConstructorDefault(Effect.succeed(false)), ), }); export type UserInputQuestion = typeof UserInputQuestion.Type; diff --git a/packages/contracts/src/settings.ts b/packages/contracts/src/settings.ts index 6633ce42a6e5ca696b1703f429a7cfea60ea06f3..426f8bee56878348283393895746983a04fd9f83 100644 --- a/packages/contracts/src/settings.ts +++ b/packages/contracts/src/settings.ts @@ -24,16 +24,18 @@ export type SidebarThreadSortOrder = typeof SidebarThreadSortOrder.Type; export const DEFAULT_SIDEBAR_THREAD_SORT_ORDER: SidebarThreadSortOrder = "updated_at"; export const ClientSettingsSchema = Schema.Struct({ - confirmThreadArchive: Schema.Boolean.pipe(Schema.withDecodingDefault(() => false)), - confirmThreadDelete: Schema.Boolean.pipe(Schema.withDecodingDefault(() => true)), - diffWordWrap: Schema.Boolean.pipe(Schema.withDecodingDefault(() => false)), + confirmThreadArchive: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))), + confirmThreadDelete: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(true))), + diffWordWrap: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))), sidebarProjectSortOrder: SidebarProjectSortOrder.pipe( - Schema.withDecodingDefault(() => DEFAULT_SIDEBAR_PROJECT_SORT_ORDER), + Schema.withDecodingDefault(Effect.succeed(DEFAULT_SIDEBAR_PROJECT_SORT_ORDER)), ), sidebarThreadSortOrder: SidebarThreadSortOrder.pipe( - Schema.withDecodingDefault(() => DEFAULT_SIDEBAR_THREAD_SORT_ORDER), + Schema.withDecodingDefault(Effect.succeed(DEFAULT_SIDEBAR_THREAD_SORT_ORDER)), + ), + timestampFormat: TimestampFormat.pipe( + Schema.withDecodingDefault(Effect.succeed(DEFAULT_TIMESTAMP_FORMAT)), ), - timestampFormat: TimestampFormat.pipe(Schema.withDecodingDefault(() => DEFAULT_TIMESTAMP_FORMAT)), }); export type ClientSettings = typeof ClientSettingsSchema.Type; @@ -53,48 +55,50 @@ const makeBinaryPathSetting = (fallback: string) => encode: (value) => Effect.succeed(value), }), ), - Schema.withDecodingDefault(() => fallback), + Schema.withDecodingDefault(Effect.succeed(fallback)), ); export const CodexSettings = Schema.Struct({ - enabled: Schema.Boolean.pipe(Schema.withDecodingDefault(() => true)), + enabled: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(true))), binaryPath: makeBinaryPathSetting("codex"), - homePath: TrimmedString.pipe(Schema.withDecodingDefault(() => "")), - customModels: Schema.Array(Schema.String).pipe(Schema.withDecodingDefault(() => [])), + homePath: TrimmedString.pipe(Schema.withDecodingDefault(Effect.succeed(""))), + customModels: Schema.Array(Schema.String).pipe(Schema.withDecodingDefault(Effect.succeed([]))), }); export type CodexSettings = typeof CodexSettings.Type; export const ClaudeSettings = Schema.Struct({ - enabled: Schema.Boolean.pipe(Schema.withDecodingDefault(() => true)), + enabled: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(true))), binaryPath: makeBinaryPathSetting("claude"), - customModels: Schema.Array(Schema.String).pipe(Schema.withDecodingDefault(() => [])), + customModels: Schema.Array(Schema.String).pipe(Schema.withDecodingDefault(Effect.succeed([]))), }); export type ClaudeSettings = typeof ClaudeSettings.Type; export const ObservabilitySettings = Schema.Struct({ - otlpTracesUrl: TrimmedString.pipe(Schema.withDecodingDefault(() => "")), - otlpMetricsUrl: TrimmedString.pipe(Schema.withDecodingDefault(() => "")), + otlpTracesUrl: TrimmedString.pipe(Schema.withDecodingDefault(Effect.succeed(""))), + otlpMetricsUrl: TrimmedString.pipe(Schema.withDecodingDefault(Effect.succeed(""))), }); export type ObservabilitySettings = typeof ObservabilitySettings.Type; export const ServerSettings = Schema.Struct({ - enableAssistantStreaming: Schema.Boolean.pipe(Schema.withDecodingDefault(() => false)), + enableAssistantStreaming: Schema.Boolean.pipe(Schema.withDecodingDefault(Effect.succeed(false))), defaultThreadEnvMode: ThreadEnvMode.pipe( - Schema.withDecodingDefault(() => "local" as const satisfies ThreadEnvMode), + Schema.withDecodingDefault(Effect.succeed("local" as const satisfies ThreadEnvMode)), ), textGenerationModelSelection: ModelSelection.pipe( - Schema.withDecodingDefault(() => ({ - provider: "codex" as const, - model: DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER.codex, - })), + Schema.withDecodingDefault( + Effect.succeed({ + provider: "codex" as const, + model: DEFAULT_GIT_TEXT_GENERATION_MODEL_BY_PROVIDER.codex, + }), + ), ), // Provider specific settings providers: Schema.Struct({ - codex: CodexSettings.pipe(Schema.withDecodingDefault(() => ({}))), - claudeAgent: ClaudeSettings.pipe(Schema.withDecodingDefault(() => ({}))), - }).pipe(Schema.withDecodingDefault(() => ({}))), - observability: ObservabilitySettings.pipe(Schema.withDecodingDefault(() => ({}))), + codex: CodexSettings.pipe(Schema.withDecodingDefault(Effect.succeed({}))), + claudeAgent: ClaudeSettings.pipe(Schema.withDecodingDefault(Effect.succeed({}))), + }).pipe(Schema.withDecodingDefault(Effect.succeed({}))), + observability: ObservabilitySettings.pipe(Schema.withDecodingDefault(Effect.succeed({}))), }); export type ServerSettings = typeof ServerSettings.Type; diff --git a/packages/contracts/src/terminal.ts b/packages/contracts/src/terminal.ts index 8b20254def5b58691d04c92c23a24ae16e637a9f..3fe883b442047c81e7efcb043eb135ef7c158f9c 100644 --- a/packages/contracts/src/terminal.ts +++ b/packages/contracts/src/terminal.ts @@ -1,4 +1,4 @@ -import { Schema } from "effect"; +import { Effect, Schema } from "effect"; import { TrimmedNonEmptyString } from "./baseSchemas"; export const DEFAULT_TERMINAL_ID = "default"; @@ -20,7 +20,7 @@ const TerminalEnvSchema = Schema.Record(TerminalEnvKeySchema, TerminalEnvValueSc ); const TerminalIdWithDefaultSchema = TerminalIdSchema.pipe( - Schema.withDecodingDefault(() => DEFAULT_TERMINAL_ID), + Schema.withDecodingDefault(Effect.succeed(DEFAULT_TERMINAL_ID)), ); export const TerminalThreadInput = Schema.Struct({ diff --git a/packages/shared/src/Net.ts b/packages/shared/src/Net.ts index e5ac354f924754b738452767806cd0eb1de0fffb..d0a44cc5724312bcaede618b9709e39294fe9607 100644 --- a/packages/shared/src/Net.ts +++ b/packages/shared/src/Net.ts @@ -1,6 +1,6 @@ import * as Net from "node:net"; -import { Data, Effect, Layer, ServiceMap } from "effect"; +import { Data, Effect, Layer, Context } from "effect"; export class NetError extends Data.TaggedError("NetError")<{ readonly message: string; @@ -85,7 +85,7 @@ export interface NetServiceShape { /** * NetService - Service tag for startup networking helpers. */ -export class NetService extends ServiceMap.Service()( +export class NetService extends Context.Service()( "@t3tools/shared/Net/NetService", ) { static readonly layer = Layer.sync(NetService, () => { diff --git a/scripts/build-desktop-artifact.test.ts b/scripts/build-desktop-artifact.test.ts new file mode 100644 index 0000000000000000000000000000000000000000..f86beb6ff40b1ca17140b9c0e7876784f393cf65 --- /dev/null +++ b/scripts/build-desktop-artifact.test.ts @@ -0,0 +1,45 @@ +import * as NodeServices from "@effect/platform-node/NodeServices"; +import { assert, it } from "@effect/vitest"; +import { ConfigProvider, Effect, Option } from "effect"; + +import { resolveBuildOptions } from "./build-desktop-artifact.ts"; + +it.layer(NodeServices.layer)("build-desktop-artifact", (it) => { + it.effect("preserves explicit false boolean flags over true env defaults", () => + Effect.gen(function* () { + const resolved = yield* resolveBuildOptions({ + platform: Option.some("mac"), + target: Option.none(), + arch: Option.some("arm64"), + buildVersion: Option.none(), + outputDir: Option.some("release-test"), + skipBuild: Option.some(false), + keepStage: Option.some(false), + signed: Option.some(false), + verbose: Option.some(false), + mockUpdates: Option.some(false), + mockUpdateServerPort: Option.none(), + }).pipe( + Effect.provide( + ConfigProvider.layer( + ConfigProvider.fromEnv({ + env: { + T3CODE_DESKTOP_SKIP_BUILD: "true", + T3CODE_DESKTOP_KEEP_STAGE: "true", + T3CODE_DESKTOP_SIGNED: "true", + T3CODE_DESKTOP_VERBOSE: "true", + T3CODE_DESKTOP_MOCK_UPDATES: "true", + }, + }), + ), + ), + ); + + assert.equal(resolved.skipBuild, false); + assert.equal(resolved.keepStage, false); + assert.equal(resolved.signed, false); + assert.equal(resolved.verbose, false); + assert.equal(resolved.mockUpdates, false); + }), + ); +}); diff --git a/scripts/build-desktop-artifact.ts b/scripts/build-desktop-artifact.ts index feb50a666208af22c9663e6fa5cb904b20f179b2..dfeb797b339dbf146b9246900db7b4ca84b98214 100644 --- a/scripts/build-desktop-artifact.ts +++ b/scripts/build-desktop-artifact.ts @@ -214,11 +214,13 @@ const BuildEnvConfig = Config.all({ }); const resolveBooleanFlag = (flag: Option.Option, envValue: boolean) => - Option.getOrElse(Option.filter(flag, Boolean), () => envValue); + Option.getOrElse(flag, () => envValue); const mergeOptions = (a: Option.Option, b: Option.Option, defaultValue: A) => Option.getOrElse(a, () => Option.getOrElse(b, () => defaultValue)); -const resolveBuildOptions = Effect.fn("resolveBuildOptions")(function* (input: BuildCliInput) { +export const resolveBuildOptions = Effect.fn("resolveBuildOptions")(function* ( + input: BuildCliInput, +) { const path = yield* Path.Path; const repoRoot = yield* RepoRoot; const env = yield* BuildEnvConfig.asEffect(); @@ -838,8 +840,10 @@ const buildDesktopArtifactCli = Command.make("build-desktop-artifact", { const cliRuntimeLayer = Layer.mergeAll(Logger.layer([Logger.consolePretty()]), NodeServices.layer); -Command.run(buildDesktopArtifactCli, { version: "0.0.0" }).pipe( - Effect.scoped, - Effect.provide(cliRuntimeLayer), - NodeRuntime.runMain, -); +if (import.meta.main) { + Command.run(buildDesktopArtifactCli, { version: "0.0.0" }).pipe( + Effect.scoped, + Effect.provide(cliRuntimeLayer), + NodeRuntime.runMain, + ); +} diff --git a/scripts/dev-runner.test.ts b/scripts/dev-runner.test.ts index 0918e6986a77a8e24e06bd9f0cd2c8d80a08c8d6..1a15ccb8bca23c72f7857f4255e1b21fb8f66696 100644 --- a/scripts/dev-runner.test.ts +++ b/scripts/dev-runner.test.ts @@ -121,7 +121,9 @@ it.layer(NodeServices.layer)("dev-runner", (it) => { Effect.gen(function* () { const env = yield* createDevRunnerEnv({ mode: "dev", - baseEnv: {}, + baseEnv: { + T3CODE_LOG_WS_EVENTS: "1", + }, serverOffset: 0, webOffset: 0, t3Home: undefined, diff --git a/scripts/dev-runner.ts b/scripts/dev-runner.ts index 4522c21d7027c5e81b8715692d86115e6a63b01f..b0bbe51e68ff652cb59d22d9b5a08c248852092b 100644 --- a/scripts/dev-runner.ts +++ b/scripts/dev-runner.ts @@ -356,35 +356,6 @@ interface DevRunnerCliInput { readonly turboArgs: ReadonlyArray; } -const readOptionalBooleanEnv = (name: string): boolean | undefined => { - const value = process.env[name]; - if (value === undefined) { - return undefined; - } - if (value === "1" || value.toLowerCase() === "true") { - return true; - } - if (value === "0" || value.toLowerCase() === "false") { - return false; - } - return undefined; -}; - -const resolveOptionalBooleanOverride = ( - explicitValue: boolean | undefined, - envValue: boolean | undefined, -): boolean | undefined => { - if (explicitValue === true) { - return true; - } - - if (explicitValue === false) { - return envValue; - } - - return envValue; -}; - export function runDevRunnerWithInput(input: DevRunnerCliInput) { return Effect.gen(function* () { const { portOffset, devInstance } = yield* OffsetConfig.asEffect().pipe( @@ -406,12 +377,6 @@ export function runDevRunnerWithInput(input: DevRunnerCliInput) { }), }); - const envOverrides = { - noBrowser: readOptionalBooleanEnv("T3CODE_NO_BROWSER"), - autoBootstrapProjectFromCwd: readOptionalBooleanEnv("T3CODE_AUTO_BOOTSTRAP_PROJECT_FROM_CWD"), - logWebSocketEvents: readOptionalBooleanEnv("T3CODE_LOG_WS_EVENTS"), - }; - const { serverOffset, webOffset } = yield* resolveModePortOffsets({ mode: input.mode, startOffset: offset, @@ -425,15 +390,9 @@ export function runDevRunnerWithInput(input: DevRunnerCliInput) { serverOffset, webOffset, t3Home: input.t3Home, - noBrowser: resolveOptionalBooleanOverride(input.noBrowser, envOverrides.noBrowser), - autoBootstrapProjectFromCwd: resolveOptionalBooleanOverride( - input.autoBootstrapProjectFromCwd, - envOverrides.autoBootstrapProjectFromCwd, - ), - logWebSocketEvents: resolveOptionalBooleanOverride( - input.logWebSocketEvents, - envOverrides.logWebSocketEvents, - ), + noBrowser: input.noBrowser, + autoBootstrapProjectFromCwd: input.autoBootstrapProjectFromCwd, + logWebSocketEvents: input.logWebSocketEvents, host: input.host, port: input.port, devUrl: input.devUrl,