Skip to content
  •  
  •  
  •  
2 changes: 1 addition & 1 deletion apps/desktop/src/backend/DesktopBackendManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import * as Schema from "effect/Schema";
import * as Sink from "effect/Sink";
import * as Scope from "effect/Scope";
import * as Stream from "effect/Stream";
import { TestClock } from "effect/testing";
import * as TestClock from "effect/testing/TestClock";
import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http";
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";

Expand Down
6 changes: 3 additions & 3 deletions apps/desktop/src/ssh/DesktopSshEnvironment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import type {
DesktopSshEnvironmentBootstrap,
DesktopSshEnvironmentTarget,
} from "@t3tools/contracts";
import { type NetError, NetService } from "@t3tools/shared/Net";
import * as NetService from "@t3tools/shared/Net";
import {
SshPasswordPrompt,
type SshPasswordPromptShape,
Expand Down Expand Up @@ -35,7 +35,7 @@ export type DesktopSshEnvironmentRuntimeServices =
| FileSystem.FileSystem
| Path.Path
| HttpClient.HttpClient
| NetService;
| NetService.NetService;

export type DesktopSshEnvironmentOperationError =
| SshCommandError
Expand All @@ -44,7 +44,7 @@ export type DesktopSshEnvironmentOperationError =
| SshPairingError
| SshReadinessError
| SshPasswordPromptError
| NetError;
| NetService.NetError;

export type DesktopSshEnvironmentDiscoverError = SshHostDiscoveryError;

Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/ssh/DesktopSshPasswordPrompts.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as Effect from "effect/Effect";
import * as Fiber from "effect/Fiber";
import * as Layer from "effect/Layer";
import * as Option from "effect/Option";
import { TestClock } from "effect/testing";
import * as TestClock from "effect/testing/TestClock";
import type * as Electron from "electron";

import * as ElectronWindow from "../electron/ElectronWindow.ts";
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/updates/DesktopUpdates.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import * as Effect from "effect/Effect";
import * as Fiber from "effect/Fiber";
import * as Layer from "effect/Layer";
import * as Option from "effect/Option";
import { TestClock } from "effect/testing";
import * as TestClock from "effect/testing/TestClock";

import * as DesktopBackendManager from "../backend/DesktopBackendManager.ts";
import * as DesktopConfig from "../app/DesktopConfig.ts";
Expand Down
14 changes: 1 addition & 13 deletions apps/desktop/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,7 @@
"compilerOptions": {
"composite": true,
"types": ["node", "electron"],
"lib": ["ESNext", "DOM", "esnext.disposable"],
"plugins": [
{
"name": "@effect/language-service",
"namespaceImportPackages": ["@effect/platform-node", "effect"],
"diagnosticSeverity": {
"importFromBarrel": "error",
"anyUnknownInErrorContext": "error",
"instanceOfSchema": "warning",
"deterministicKeys": "warning"
}
}
]
"lib": ["ESNext", "DOM", "esnext.disposable"]
},
"include": ["src", "tsdown.config.ts"]
}
27 changes: 13 additions & 14 deletions apps/server/integration/OrchestrationEngineHarness.integration.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @effect-diagnostics nodeBuiltinImport:off
import { execFileSync } from "node:child_process";

import * as NodeServices from "@effect/platform-node/NodeServices";
Expand All @@ -8,20 +9,18 @@ import {
type OrchestrationEvent,
type OrchestrationThread,
} from "@t3tools/contracts";
import {
Effect,
Exit,
FileSystem,
Layer,
ManagedRuntime,
Option,
Path,
Ref,
Schedule,
Schema,
Scope,
Stream,
} from "effect";
import * as Effect from "effect/Effect";
import * as Exit from "effect/Exit";
import * as FileSystem from "effect/FileSystem";
import * as Layer from "effect/Layer";
import * as ManagedRuntime from "effect/ManagedRuntime";
import * as Option from "effect/Option";
import * as Path from "effect/Path";
import * as Ref from "effect/Ref";
import * as Schedule from "effect/Schedule";
import * as Schema from "effect/Schema";
import * as Scope from "effect/Scope";
import * as Stream from "effect/Stream";

import { CheckpointStoreLive } from "../src/checkpointing/Layers/CheckpointStore.ts";
import { CheckpointStore } from "../src/checkpointing/Services/CheckpointStore.ts";
Expand Down
14 changes: 7 additions & 7 deletions apps/server/integration/TestProviderAdapter.integration.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
import { randomUUID } from "node:crypto";

import {
ApprovalRequestId,
EventId,
Expand All @@ -12,7 +10,10 @@ import {
TurnId,
ProviderDriverKind,
} from "@t3tools/contracts";
import { Effect, Queue, Stream } from "effect";
import * as Effect from "effect/Effect";
import * as Queue from "effect/Queue";
import * as Random from "effect/Random";
import * as Stream from "effect/Stream";

import {
ProviderAdapterSessionNotFoundError,
Expand Down Expand Up @@ -202,7 +203,7 @@ interface MakeTestProviderAdapterHarnessOptions {
}

function nowIso(): string {
return new Date().toISOString();
return "2026-01-01T00:00:00.000Z";
}

function sessionNotFound(
Expand Down Expand Up @@ -308,10 +309,9 @@ export const makeTestProviderAdapterHarness = (options?: MakeTestProviderAdapter
for (const fixtureEvent of response.events) {
const rawEvent: Record<string, unknown> = {
...(fixtureEvent as Record<string, unknown>),
eventId: randomUUID(),
eventId: yield* Random.nextUUIDv4,
provider,
sessionId: RuntimeSessionId.make(String(input.threadId)),
createdAt: nowIso(),
Comment thread
juliusmarminge marked this conversation as resolved.
};
rawEvent.threadId = state.snapshot.threadId;
if (Object.hasOwn(rawEvent, "turnId")) {
Expand Down Expand Up @@ -366,7 +366,7 @@ export const makeTestProviderAdapterHarness = (options?: MakeTestProviderAdapter
if (deferredTurnCompletedEvents.length === 0) {
yield* emit({
type: "turn.completed",
eventId: EventId.make(randomUUID()),
eventId: EventId.make(yield* Random.nextUUIDv4),
provider,
createdAt: nowIso(),
threadId: state.snapshot.threadId,
Expand Down
17 changes: 12 additions & 5 deletions apps/server/integration/orchestrationEngine.integration.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @effect-diagnostics nodeBuiltinImport:off
import fs from "node:fs";
import path from "node:path";

Expand All @@ -17,7 +18,10 @@ import {
ProviderInstanceId,
} from "@t3tools/contracts";
import { assert, it } from "@effect/vitest";
import { Effect, Option, Schema } from "effect";
import * as Clock from "effect/Clock";
import * as Effect from "effect/Effect";
import * as Option from "effect/Option";
import * as Schema from "effect/Schema";

import type { TestTurnResponse } from "./TestProviderAdapter.integration.ts";
import {
Expand Down Expand Up @@ -47,7 +51,7 @@ const CODEX_PROVIDER = ProviderDriverKind.make("codex");
const CLAUDE_AGENT_PROVIDER = ProviderDriverKind.make("claudeAgent");

function nowIso() {
return new Date().toISOString();
return "2026-05-01T00:00:00.000Z";
}

class IntegrationWaitTimeoutError extends Schema.TaggedErrorClass<IntegrationWaitTimeoutError>()(
Expand All @@ -64,14 +68,14 @@ function waitForSync<A>(
timeoutMs = 10_000,
): Effect.Effect<A, never> {
return Effect.gen(function* () {
const deadline = Date.now() + timeoutMs;
const deadline = (yield* Clock.currentTimeMillis) + timeoutMs;

while (true) {
const value = read();
if (predicate(value)) {
return value;
}
if (Date.now() >= deadline) {
if ((yield* Clock.currentTimeMillis) >= deadline) {
return yield* Effect.die(new IntegrationWaitTimeoutError({ description }));
}
yield* Effect.sleep(10);
Expand Down Expand Up @@ -156,6 +160,7 @@ const startTurn = (input: {
readonly messageId: string;
readonly text: string;
readonly modelSelection?: ModelSelection;
readonly createdAt?: string;
}) =>
input.harness.engine.dispatch({
type: "thread.turn.start",
Expand All @@ -174,7 +179,7 @@ const startTurn = (input: {
: {}),
interactionMode: DEFAULT_PROVIDER_INTERACTION_MODE,
runtimeMode: "approval-required",
createdAt: nowIso(),
createdAt: input.createdAt ?? nowIso(),
});

it.live("runs a single turn end-to-end and persists checkpoint state in sqlite + git", () =>
Expand Down Expand Up @@ -755,6 +760,7 @@ it.live("reverts to an earlier checkpoint and trims checkpoint projections + git
commandId: "cmd-turn-start-revert-1",
messageId: "msg-user-revert-1",
text: "First edit",
createdAt: "2026-02-24T10:04:59.900Z",
});

yield* harness.waitForThread(
Expand Down Expand Up @@ -813,6 +819,7 @@ it.live("reverts to an earlier checkpoint and trims checkpoint projections + git
commandId: "cmd-turn-start-revert-2",
messageId: "msg-user-revert-2",
text: "Second edit",
createdAt: "2026-02-24T10:05:00.900Z",
});

yield* harness.waitForThread(
Expand Down
7 changes: 6 additions & 1 deletion apps/server/integration/providerService.integration.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,12 @@ import { ProviderDriverKind, ProviderInstanceId, ThreadId } from "@t3tools/contr
import { DEFAULT_SERVER_SETTINGS } from "@t3tools/contracts/settings";
import * as NodeServices from "@effect/platform-node/NodeServices";
import { it, assert } from "@effect/vitest";
import { Effect, FileSystem, Layer, Path, Queue, Stream } from "effect";
import * as Effect from "effect/Effect";
import * as FileSystem from "effect/FileSystem";
import * as Layer from "effect/Layer";
import * as Path from "effect/Path";
import * as Queue from "effect/Queue";
import * as Stream from "effect/Stream";

import { ProviderAdapterRegistry } from "../src/provider/Services/ProviderAdapterRegistry.ts";
import { makeAdapterRegistryMock } from "../src/provider/testUtils/providerAdapterRegistryMock.ts";
Expand Down
1 change: 1 addition & 0 deletions apps/server/scripts/acp-mock-agent.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#!/usr/bin/env bun
// @effect-diagnostics nodeBuiltinImport:off
import { appendFileSync } from "node:fs";

import * as Effect from "effect/Effect";
Expand Down
16 changes: 13 additions & 3 deletions apps/server/scripts/cli.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
#!/usr/bin/env node

import * as NodeRuntime from "@effect/platform-node/NodeRuntime";
import * as NodeServices from "@effect/platform-node/NodeServices";
import { Data, Effect, FileSystem, Logger, Option, Path } from "effect";
import * as Data from "effect/Data";
import * as Effect from "effect/Effect";
import * as FileSystem from "effect/FileSystem";
import * as Logger from "effect/Logger";
import * as Option from "effect/Option";
import * as Path from "effect/Path";
import * as Schema from "effect/Schema";
import { Command, Flag } from "effect/unstable/cli";
import { ChildProcess, ChildProcessSpawner } from "effect/unstable/process";

Expand All @@ -11,6 +16,7 @@ import {
PUBLISH_ICON_OVERRIDES,
} from "../../../scripts/lib/brand-assets.ts";
import { resolveCatalogDependencies } from "../../../scripts/lib/resolve-catalog.ts";
import { fromJsonStringPretty } from "@t3tools/shared/schemaJson";
import rootPackageJson from "../../../package.json" with { type: "json" };
import serverPackageJson from "../package.json" with { type: "json" };

Expand All @@ -30,6 +36,9 @@ interface PackageJson {
overrides: Record<string, string>;
}

const PackageJsonPrettyJson = fromJsonStringPretty(Schema.Unknown);
const encodePackageJson = Schema.encodeEffect(PackageJsonPrettyJson);

class CliError extends Data.TaggedError("CliError")<{
readonly message: string;
readonly cause?: unknown;
Expand Down Expand Up @@ -227,8 +236,9 @@ const publishCmd = Command.make(
};

const original = yield* fs.readFileString(packageJsonPath);
const packageJsonString = yield* encodePackageJson(pkg);
yield* fs.writeFileString(backupPath, original);
yield* fs.writeFileString(packageJsonPath, `${JSON.stringify(pkg, null, 2)}\n`);
yield* fs.writeFileString(packageJsonPath, `${packageJsonString}\n`);
yield* Effect.log("[cli] Prepared package.json for publish");

const iconBackups = yield* applyPublishIconOverrides(repoRoot, serverDir);
Expand Down
12 changes: 8 additions & 4 deletions apps/server/scripts/cursor-acp-model-mismatch-probe.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// @effect-diagnostics nodeBuiltinImport:off
import { spawn, type ChildProcessWithoutNullStreams } from "node:child_process";
import process from "node:process";
import readline from "node:readline";
import * as NodeTimers from "node:timers";

type JsonPrimitive = null | boolean | number | string;
type JsonValue = JsonPrimitive | JsonValue[] | { [key: string]: JsonValue };
Expand Down Expand Up @@ -114,7 +116,8 @@ function matchesKeyword(option: SessionConfigOption, keyword: string): boolean {

function sleep(ms: number) {
return new Promise<void>((resolve) => {
setTimeout(resolve, ms);
// @effect-diagnostics-next-line globalTimers:off - Standalone Node probe script, not an Effect runtime test.
NodeTimers.setTimeout(resolve, ms);
});
}

Expand Down Expand Up @@ -177,19 +180,20 @@ class JsonRpcChild {
const id = this.nextId++;

const responsePromise = new Promise<JsonValue | undefined>((resolve, reject) => {
const timeout = setTimeout(() => {
// @effect-diagnostics-next-line globalTimers:off - Standalone Node probe script request timeout.
const timeout = NodeTimers.setTimeout(() => {
this.pending.delete(id);
reject(new Error(`Timed out waiting for ${method} response after ${timeoutMs}ms.`));
}, timeoutMs);

this.pending.set(id, {
method,
resolve: (value) => {
clearTimeout(timeout);
NodeTimers.clearTimeout(timeout);
resolve(value);
},
reject: (error) => {
clearTimeout(timeout);
NodeTimers.clearTimeout(timeout);
reject(error);
},
});
Expand Down
4 changes: 3 additions & 1 deletion apps/server/src/atomicWrite.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import { Effect, FileSystem, Path } from "effect";
import * as Effect from "effect/Effect";
import * as FileSystem from "effect/FileSystem";
import * as Path from "effect/Path";
import * as Random from "effect/Random";

export const writeFileStringAtomically = (input: {
Expand Down
11 changes: 6 additions & 5 deletions apps/server/src/attachmentPaths.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import path from "node:path";
// @effect-diagnostics nodeBuiltinImport:off
import NodePath from "node:path";

export const ATTACHMENTS_ROUTE_PREFIX = "/attachments";

export function normalizeAttachmentRelativePath(rawRelativePath: string): string | null {
const normalized = path.normalize(rawRelativePath).replace(/^[/\\]+/, "");
const normalized = NodePath.normalize(rawRelativePath).replace(/^[/\\]+/, "");
if (normalized.length === 0 || normalized.startsWith("..") || normalized.includes("\0")) {
return null;
}
Expand All @@ -19,9 +20,9 @@ export function resolveAttachmentRelativePath(input: {
return null;
}

const attachmentsRoot = path.resolve(input.attachmentsDir);
const filePath = path.resolve(path.join(attachmentsRoot, normalizedRelativePath));
if (!filePath.startsWith(`${attachmentsRoot}${path.sep}`)) {
const attachmentsRoot = NodePath.resolve(input.attachmentsDir);
const filePath = NodePath.resolve(NodePath.join(attachmentsRoot, normalizedRelativePath));
if (!filePath.startsWith(`${attachmentsRoot}${NodePath.sep}`)) {
return null;
}
return filePath;
Expand Down
1 change: 1 addition & 0 deletions apps/server/src/attachmentStore.test.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @effect-diagnostics nodeBuiltinImport:off
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
Expand Down
1 change: 1 addition & 0 deletions apps/server/src/attachmentStore.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
// @effect-diagnostics nodeBuiltinImport:off
import { randomUUID } from "node:crypto";
import { existsSync } from "node:fs";

Expand Down
3 changes: 2 additions & 1 deletion apps/server/src/auth/Layers/AuthControlPlane.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as NodeServices from "@effect/platform-node/NodeServices";
import { expect, it } from "@effect/vitest";
import { Effect, Layer } from "effect";
import * as Effect from "effect/Effect";
import * as Layer from "effect/Layer";

import type { ServerConfigShape } from "../../config.ts";
import { ServerConfig } from "../../config.ts";
Expand Down
Loading
Loading