| author | |
| committer | |
| log | 8f6b21a12e8c6509649883da8e36d375e5aa1fdf |
| tree | cb25078bb068c6f579039c82c7fdabf6ef180c0b |
| parent | dc530f7a7e21dac998126024b2b112fc893df404 |
71 files changed, 353 insertions(+), 148 deletions(-)
apps/server/integration/OrchestrationEngineHarness.integration.ts+1-1| ... | @@ -3,7 +3,7 @@ import os from "node:os"; | ... | @@ -3,7 +3,7 @@ import os from "node:os"; |
| 3 | import path from "node:path"; | 3 | import path from "node:path"; |
| 4 | import { execFileSync } from "node:child_process"; | 4 | import { execFileSync } from "node:child_process"; |
| 5 | 5 | ||
| 6 | import { NodeServices } from "@effect/platform-node"; | 6 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 7 | import { | 7 | import { |
| 8 | ApprovalRequestId, | 8 | ApprovalRequestId, |
| 9 | type OrchestrationEvent, | 9 | type OrchestrationEvent, |
apps/server/integration/providerService.integration.test.ts+1-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | import type { ProviderRuntimeEvent, ProviderSessionId } from "@t3tools/contracts"; | 1 | import type { ProviderRuntimeEvent, ProviderSessionId } from "@t3tools/contracts"; |
| 2 | import { ThreadId } from "@t3tools/contracts"; | 2 | import { ThreadId } from "@t3tools/contracts"; |
| 3 | import { NodeServices } from "@effect/platform-node"; | 3 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 4 | import { it, assert } from "@effect/vitest"; | 4 | import { it, assert } from "@effect/vitest"; |
| 5 | import { Effect, FileSystem, Layer, Path, Queue, Stream } from "effect"; | 5 | import { Effect, FileSystem, Layer, Path, Queue, Stream } from "effect"; |
| 6 | 6 |
apps/server/package.json+4-4| ... | @@ -18,17 +18,17 @@ | ... | @@ -18,17 +18,17 @@ |
| 18 | "test": "vitest run" | 18 | "test": "vitest run" |
| 19 | }, | 19 | }, |
| 20 | "dependencies": { | 20 | "dependencies": { |
| 21 | "@effect/platform-node": "4.0.0-beta.10", | 21 | "@effect/platform-node": "catalog:", |
| 22 | "@effect/sql-sqlite-bun": "4.0.0-beta.10", | 22 | "@effect/sql-sqlite-bun": "catalog:", |
| 23 | "@pierre/diffs": "^1.1.0-beta.16", | 23 | "@pierre/diffs": "^1.1.0-beta.16", |
| 24 | "effect": "4.0.0-beta.10", | 24 | "effect": "catalog:", |
| 25 | "node-pty": "^1.1.0", | 25 | "node-pty": "^1.1.0", |
| 26 | "open": "^10.1.0", | 26 | "open": "^10.1.0", |
| 27 | "ws": "^8.18.0" | 27 | "ws": "^8.18.0" |
| 28 | }, | 28 | }, |
| 29 | "devDependencies": { | 29 | "devDependencies": { |
| 30 | "@effect/language-service": "0.75.1", | 30 | "@effect/language-service": "0.75.1", |
| 31 | "@effect/vitest": "4.0.0-beta.10", | 31 | "@effect/vitest": "catalog:", |
| 32 | "@t3tools/contracts": "workspace:*", | 32 | "@t3tools/contracts": "workspace:*", |
| 33 | "@t3tools/web": "workspace:*", | 33 | "@t3tools/web": "workspace:*", |
| 34 | "@types/bun": "^1.3.9", | 34 | "@types/bun": "^1.3.9", |
apps/server/src/checkpointing/Services/CheckpointDiffQuery.ts+1-1| ... | @@ -46,4 +46,4 @@ export interface CheckpointDiffQueryShape { | ... | @@ -46,4 +46,4 @@ export interface CheckpointDiffQueryShape { |
| 46 | export class CheckpointDiffQuery extends ServiceMap.Service< | 46 | export class CheckpointDiffQuery extends ServiceMap.Service< |
| 47 | CheckpointDiffQuery, | 47 | CheckpointDiffQuery, |
| 48 | CheckpointDiffQueryShape | 48 | CheckpointDiffQueryShape |
| 49 | >()("checkpointing/CheckpointDiffQuery") {} | 49 | >()("t3/checkpointing/Services/CheckpointDiffQuery") {} |
apps/server/src/checkpointing/Services/CheckpointStore.ts+1-1| ... | @@ -96,5 +96,5 @@ export interface CheckpointStoreShape { | ... | @@ -96,5 +96,5 @@ export interface CheckpointStoreShape { |
| 96 | * CheckpointStore - Service tag for checkpoint persistence and restore operations. | 96 | * CheckpointStore - Service tag for checkpoint persistence and restore operations. |
| 97 | */ | 97 | */ |
| 98 | export class CheckpointStore extends ServiceMap.Service<CheckpointStore, CheckpointStoreShape>()( | 98 | export class CheckpointStore extends ServiceMap.Service<CheckpointStore, CheckpointStoreShape>()( |
| 99 | "checkpointing/CheckpointStore", | 99 | "t3/checkpointing/Services/CheckpointStore", |
| 100 | ) {} | 100 | ) {} |
apps/server/src/config.ts+7-7| ... | @@ -35,7 +35,7 @@ export interface ServerConfigShape { | ... | @@ -35,7 +35,7 @@ export interface ServerConfigShape { |
| 35 | * ServerConfig - Service tag for server runtime configuration. | 35 | * ServerConfig - Service tag for server runtime configuration. |
| 36 | */ | 36 | */ |
| 37 | export class ServerConfig extends ServiceMap.Service<ServerConfig, ServerConfigShape>()( | 37 | export class ServerConfig extends ServiceMap.Service<ServerConfig, ServerConfigShape>()( |
| 38 | "server/ServerConfig", | 38 | "t3/config/ServerConfig", |
| 39 | ) {} | 39 | ) {} |
| 40 | 40 | ||
| 41 | // Helpers | 41 | // Helpers |
| ... | @@ -61,7 +61,7 @@ export interface NetServiceShape { | ... | @@ -61,7 +61,7 @@ export interface NetServiceShape { |
| 61 | * NetService - Service tag for startup networking helpers. | 61 | * NetService - Service tag for startup networking helpers. |
| 62 | */ | 62 | */ |
| 63 | export class NetService extends ServiceMap.Service<NetService, NetServiceShape>()( | 63 | export class NetService extends ServiceMap.Service<NetService, NetServiceShape>()( |
| 64 | "server/NetService", | 64 | "t3/config/NetService", |
| 65 | ) { | 65 | ) { |
| 66 | static readonly layer = Layer.succeed(NetService, { | 66 | static readonly layer = Layer.succeed(NetService, { |
| 67 | findAvailablePort: (preferred) => | 67 | findAvailablePort: (preferred) => |
| ... | @@ -102,18 +102,18 @@ export class NetService extends ServiceMap.Service<NetService, NetServiceShape>( | ... | @@ -102,18 +102,18 @@ export class NetService extends ServiceMap.Service<NetService, NetServiceShape>( |
| 102 | 102 | ||
| 103 | export const resolveStaticDir = Effect.fn(function* () { | 103 | export const resolveStaticDir = Effect.fn(function* () { |
| 104 | const { join, resolve } = yield* Path.Path; | 104 | const { join, resolve } = yield* Path.Path; |
| 105 | const { stat } = yield* FileSystem.FileSystem; | 105 | const { exists } = yield* FileSystem.FileSystem; |
| 106 | const bundledClient = resolve(join(import.meta.dirname, "client")); | 106 | const bundledClient = resolve(join(import.meta.dirname, "client")); |
| 107 | const bundledStat = yield* stat(join(bundledClient, "index.html")).pipe( | 107 | const bundledStat = yield* exists(join(bundledClient, "index.html")).pipe( |
| 108 | Effect.orElseSucceed(() => undefined), | 108 | Effect.orElseSucceed(() => false), |
| 109 | ); | 109 | ); |
| 110 | if (bundledStat) { | 110 | if (bundledStat) { |
| 111 | return bundledClient; | 111 | return bundledClient; |
| 112 | } | 112 | } |
| 113 | 113 | ||
| 114 | const monorepoClient = resolve(join(import.meta.dirname, "../../web/dist")); | 114 | const monorepoClient = resolve(join(import.meta.dirname, "../../web/dist")); |
| 115 | const monorepoStat = yield* stat(join(monorepoClient, "index.html")).pipe( | 115 | const monorepoStat = yield* exists(join(monorepoClient, "index.html")).pipe( |
| 116 | Effect.orElseSucceed(() => undefined), | 116 | Effect.orElseSucceed(() => false), |
| 117 | ); | 117 | ); |
| 118 | if (monorepoStat) { | 118 | if (monorepoStat) { |
| 119 | return monorepoClient; | 119 | return monorepoClient; |
apps/server/src/git/Layers/CodexTextGeneration.test.ts+1-1| ... | @@ -1,4 +1,4 @@ | ... | @@ -1,4 +1,4 @@ |
| 1 | import { NodeServices } from "@effect/platform-node"; | 1 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 2 | import { it } from "@effect/vitest"; | 2 | import { it } from "@effect/vitest"; |
| 3 | import { Effect, FileSystem, Layer, Path } from "effect"; | 3 | import { Effect, FileSystem, Layer, Path } from "effect"; |
| 4 | import { expect } from "vitest"; | 4 | import { expect } from "vitest"; |
apps/server/src/git/Layers/GitCore.test.ts+1-1| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | import { existsSync } from "node:fs"; | 1 | import { existsSync } from "node:fs"; |
| 2 | import path from "node:path"; | 2 | import path from "node:path"; |
| 3 | 3 | ||
| 4 | import { NodeServices } from "@effect/platform-node"; | 4 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 5 | import { it } from "@effect/vitest"; | 5 | import { it } from "@effect/vitest"; |
| 6 | import { Effect, FileSystem, Layer, PlatformError, Scope } from "effect"; | 6 | import { Effect, FileSystem, Layer, PlatformError, Scope } from "effect"; |
| 7 | import { describe, expect, vi } from "vitest"; | 7 | import { describe, expect, vi } from "vitest"; |
apps/server/src/git/Layers/GitManager.test.ts+1-1| ... | @@ -1,7 +1,7 @@ | ... | @@ -1,7 +1,7 @@ |
| 1 | import fs from "node:fs"; | 1 | import fs from "node:fs"; |
| 2 | import path from "node:path"; | 2 | import path from "node:path"; |
| 3 | 3 | ||
| 4 | import { NodeServices } from "@effect/platform-node"; | 4 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 5 | import { it } from "@effect/vitest"; | 5 | import { it } from "@effect/vitest"; |
| 6 | import { Effect, FileSystem, Layer, PlatformError, Scope } from "effect"; | 6 | import { Effect, FileSystem, Layer, PlatformError, Scope } from "effect"; |
| 7 | import { expect } from "vitest"; | 7 | import { expect } from "vitest"; |
apps/server/src/git/Layers/GitService.test.ts+1-1| ... | @@ -1,4 +1,4 @@ | ... | @@ -1,4 +1,4 @@ |
| 1 | import { NodeServices } from "@effect/platform-node"; | 1 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 2 | import { it, assert } from "@effect/vitest"; | 2 | import { it, assert } from "@effect/vitest"; |
| 3 | import { Effect, Layer } from "effect"; | 3 | import { Effect, Layer } from "effect"; |
| 4 | 4 |
apps/server/src/git/Services/GitCore.ts+3-1| ... | @@ -143,4 +143,6 @@ export interface GitCoreShape { | ... | @@ -143,4 +143,6 @@ export interface GitCoreShape { |
| 143 | /** | 143 | /** |
| 144 | * GitCore - Service tag for low-level Git repository operations. | 144 | * GitCore - Service tag for low-level Git repository operations. |
| 145 | */ | 145 | */ |
| 146 | export class GitCore extends ServiceMap.Service<GitCore, GitCoreShape>()("git/GitCore") {} | 146 | export class GitCore extends ServiceMap.Service<GitCore, GitCoreShape>()( |
| 147 | "t3/git/Services/GitCore", | ||
| 148 | ) {} |
apps/server/src/git/Services/GitHubCli.ts+3-1| ... | @@ -63,4 +63,6 @@ export interface GitHubCliShape { | ... | @@ -63,4 +63,6 @@ export interface GitHubCliShape { |
| 63 | /** | 63 | /** |
| 64 | * GitHubCli - Service tag for GitHub CLI process execution. | 64 | * GitHubCli - Service tag for GitHub CLI process execution. |
| 65 | */ | 65 | */ |
| 66 | export class GitHubCli extends ServiceMap.Service<GitHubCli, GitHubCliShape>()("git/GitHubCli") {} | 66 | export class GitHubCli extends ServiceMap.Service<GitHubCli, GitHubCliShape>()( |
| 67 | "t3/git/Services/GitHubCli", | ||
| 68 | ) {} |
apps/server/src/git/Services/GitManager.ts+4-2| ... | @@ -23,7 +23,9 @@ export interface GitManagerShape { | ... | @@ -23,7 +23,9 @@ export interface GitManagerShape { |
| 23 | /** | 23 | /** |
| 24 | * Read current repository Git status plus open PR metadata when available. | 24 | * Read current repository Git status plus open PR metadata when available. |
| 25 | */ | 25 | */ |
| 26 | readonly status: (input: GitStatusInput) => Effect.Effect<GitStatusResult, GitManagerServiceError>; | 26 | readonly status: ( |
| 27 | input: GitStatusInput, | ||
| 28 | ) => Effect.Effect<GitStatusResult, GitManagerServiceError>; | ||
| 27 | 29 | ||
| 28 | /** | 30 | /** |
| 29 | * Run a stacked Git action (`commit`, `commit_push`, `commit_push_pr`). | 31 | * Run a stacked Git action (`commit`, `commit_push`, `commit_push_pr`). |
| ... | @@ -37,5 +39,5 @@ export interface GitManagerShape { | ... | @@ -37,5 +39,5 @@ export interface GitManagerShape { |
| 37 | * GitManager - Service tag for stacked Git workflow orchestration. | 39 | * GitManager - Service tag for stacked Git workflow orchestration. |
| 38 | */ | 40 | */ |
| 39 | export class GitManager extends ServiceMap.Service<GitManager, GitManagerShape>()( | 41 | export class GitManager extends ServiceMap.Service<GitManager, GitManagerShape>()( |
| 40 | "git/GitManager", | 42 | "t3/git/Services/GitManager", |
| 41 | ) {} | 43 | ) {} |
apps/server/src/git/Services/GitService.ts+1-1| ... | @@ -41,5 +41,5 @@ export interface GitServiceShape { | ... | @@ -41,5 +41,5 @@ export interface GitServiceShape { |
| 41 | * GitService - Service for Git command execution. | 41 | * GitService - Service for Git command execution. |
| 42 | */ | 42 | */ |
| 43 | export class GitService extends ServiceMap.Service<GitService, GitServiceShape>()( | 43 | export class GitService extends ServiceMap.Service<GitService, GitServiceShape>()( |
| 44 | "git/GitService", | 44 | "t3/git/Services/GitService", |
| 45 | ) {} | 45 | ) {} |
apps/server/src/git/Services/TextGeneration.ts+1-1| ... | @@ -67,5 +67,5 @@ export interface TextGenerationShape { | ... | @@ -67,5 +67,5 @@ export interface TextGenerationShape { |
| 67 | * TextGeneration - Service tag for commit and PR text generation. | 67 | * TextGeneration - Service tag for commit and PR text generation. |
| 68 | */ | 68 | */ |
| 69 | export class TextGeneration extends ServiceMap.Service<TextGeneration, TextGenerationShape>()( | 69 | export class TextGeneration extends ServiceMap.Service<TextGeneration, TextGenerationShape>()( |
| 70 | "git/TextGeneration", | 70 | "t3/git/Services/TextGeneration", |
| 71 | ) {} | 71 | ) {} |
apps/server/src/keybindings.test.ts+22-5| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | import { KeybindingCommand, KeybindingRule, KeybindingsConfig } from "@t3tools/contracts"; | 1 | import { KeybindingCommand, KeybindingRule, KeybindingsConfig } from "@t3tools/contracts"; |
| 2 | import { NodeServices } from "@effect/platform-node"; | 2 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 3 | import { assert, it } from "@effect/vitest"; | 3 | import { assert, it } from "@effect/vitest"; |
| 4 | import { assertFailure } from "@effect/vitest/utils"; | 4 | import { assertFailure } from "@effect/vitest/utils"; |
| 5 | import { Effect, FileSystem, Layer, Logger, Path, Schema } from "effect"; | 5 | import { Effect, FileSystem, Layer, Logger, Path, Schema } from "effect"; |
| ... | @@ -178,7 +178,10 @@ it.layer(NodeServices.layer)("keybindings", (it) => { | ... | @@ -178,7 +178,10 @@ it.layer(NodeServices.layer)("keybindings", (it) => { |
| 178 | return yield* keybindings.loadConfigState; | 178 | return yield* keybindings.loadConfigState; |
| 179 | }); | 179 | }); |
| 180 | 180 | ||
| 181 | assert.deepEqual(configState.keybindings, compileResolvedKeybindingsConfig(DEFAULT_KEYBINDINGS)); | 181 | assert.deepEqual( |
| 182 | configState.keybindings, | ||
| 183 | compileResolvedKeybindingsConfig(DEFAULT_KEYBINDINGS), | ||
| 184 | ); | ||
| 182 | assert.deepEqual(configState.issues, [ | 185 | assert.deepEqual(configState.issues, [ |
| 183 | { | 186 | { |
| 184 | kind: "keybindings.malformed-config", | 187 | kind: "keybindings.malformed-config", |
| ... | @@ -208,10 +211,24 @@ it.layer(NodeServices.layer)("keybindings", (it) => { | ... | @@ -208,10 +211,24 @@ it.layer(NodeServices.layer)("keybindings", (it) => { |
| 208 | }); | 211 | }); |
| 209 | 212 | ||
| 210 | assert.isTrue(configState.keybindings.some((entry) => entry.command === "terminal.toggle")); | 213 | assert.isTrue(configState.keybindings.some((entry) => entry.command === "terminal.toggle")); |
| 211 | assert.isFalse(configState.keybindings.some((entry) => entry.command === "invalid.command")); | 214 | assert.isFalse( |
| 215 | configState.keybindings.some( | ||
| 216 | (entry) => | ||
| 217 | // @ts-expect-error - invalid command | ||
| 218 | entry.command === "invalid.command", | ||
| 219 | ), | ||
| 220 | ); | ||
| 212 | assert.deepEqual(configState.issues, [ | 221 | assert.deepEqual(configState.issues, [ |
| 213 | { kind: "keybindings.invalid-entry", index: 1, message: configState.issues[0]?.message ?? "" }, | 222 | { |
| 214 | { kind: "keybindings.invalid-entry", index: 2, message: configState.issues[1]?.message ?? "" }, | 223 | kind: "keybindings.invalid-entry", |
| 224 | index: 1, | ||
| 225 | message: configState.issues[0]?.message ?? "", | ||
| 226 | }, | ||
| 227 | { | ||
| 228 | kind: "keybindings.invalid-entry", | ||
| 229 | index: 2, | ||
| 230 | message: configState.issues[1]?.message ?? "", | ||
| 231 | }, | ||
| 215 | ]); | 232 | ]); |
| 216 | }).pipe(Effect.provide(makeKeybindingsLayer())), | 233 | }).pipe(Effect.provide(makeKeybindingsLayer())), |
| 217 | ); | 234 | ); |
apps/server/src/keybindings.ts+1-1| ... | @@ -498,7 +498,7 @@ export interface KeybindingsShape { | ... | @@ -498,7 +498,7 @@ export interface KeybindingsShape { |
| 498 | * Keybindings - Service tag for keybinding configuration operations. | 498 | * Keybindings - Service tag for keybinding configuration operations. |
| 499 | */ | 499 | */ |
| 500 | export class Keybindings extends ServiceMap.Service<Keybindings, KeybindingsShape>()( | 500 | export class Keybindings extends ServiceMap.Service<Keybindings, KeybindingsShape>()( |
| 501 | "server/Keybindings", | 501 | "t3/keybindings", |
| 502 | ) {} | 502 | ) {} |
| 503 | 503 | ||
| 504 | const makeKeybindings = Effect.gen(function* () { | 504 | const makeKeybindings = Effect.gen(function* () { |
apps/server/src/main.test.ts+1-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | import * as Http from "node:http"; | 1 | import * as Http from "node:http"; |
| 2 | import { NodeServices } from "@effect/platform-node"; | 2 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 3 | import { assert, it, vi } from "@effect/vitest"; | 3 | import { assert, it, vi } from "@effect/vitest"; |
| 4 | import * as ConfigProvider from "effect/ConfigProvider"; | 4 | import * as ConfigProvider from "effect/ConfigProvider"; |
| 5 | import * as Effect from "effect/Effect"; | 5 | import * as Effect from "effect/Effect"; |
apps/server/src/main.ts+3-1| ... | @@ -63,7 +63,9 @@ export interface CliConfigShape { | ... | @@ -63,7 +63,9 @@ export interface CliConfigShape { |
| 63 | /** | 63 | /** |
| 64 | * CliConfig - Service tag for startup CLI/runtime helpers. | 64 | * CliConfig - Service tag for startup CLI/runtime helpers. |
| 65 | */ | 65 | */ |
| 66 | export class CliConfig extends ServiceMap.Service<CliConfig, CliConfigShape>()("server/CliConfig") { | 66 | export class CliConfig extends ServiceMap.Service<CliConfig, CliConfigShape>()( |
| 67 | "t3/main/CliConfig", | ||
| 68 | ) { | ||
| 67 | static readonly layer = Layer.effect( | 69 | static readonly layer = Layer.effect( |
| 68 | CliConfig, | 70 | CliConfig, |
| 69 | Effect.gen(function* () { | 71 | Effect.gen(function* () { |
apps/server/src/open.ts+1-1| ... | @@ -50,7 +50,7 @@ export interface OpenShape { | ... | @@ -50,7 +50,7 @@ export interface OpenShape { |
| 50 | /** | 50 | /** |
| 51 | * Open - Service tag for browser/editor launch operations. | 51 | * Open - Service tag for browser/editor launch operations. |
| 52 | */ | 52 | */ |
| 53 | export class Open extends ServiceMap.Service<Open, OpenShape>()("server/Open") {} | 53 | export class Open extends ServiceMap.Service<Open, OpenShape>()("t3/open") {} |
| 54 | 54 | ||
| 55 | // ============================== | 55 | // ============================== |
| 56 | // Implementations | 56 | // Implementations |
apps/server/src/orchestration/Layers/CheckpointReactor.test.ts+1-1| ... | @@ -14,7 +14,7 @@ import { | ... | @@ -14,7 +14,7 @@ import { |
| 14 | ThreadId, | 14 | ThreadId, |
| 15 | TurnId, | 15 | TurnId, |
| 16 | } from "@t3tools/contracts"; | 16 | } from "@t3tools/contracts"; |
| 17 | import { NodeServices } from "@effect/platform-node"; | 17 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 18 | import { Effect, Exit, Layer, ManagedRuntime, PubSub, Scope, Stream } from "effect"; | 18 | import { Effect, Exit, Layer, ManagedRuntime, PubSub, Scope, Stream } from "effect"; |
| 19 | import { afterEach, describe, expect, it, vi } from "vitest"; | 19 | import { afterEach, describe, expect, it, vi } from "vitest"; |
| 20 | 20 |
apps/server/src/orchestration/Layers/OrchestrationEngine.ts+2-2| ... | @@ -5,7 +5,7 @@ import type { | ... | @@ -5,7 +5,7 @@ import type { |
| 5 | ThreadId, | 5 | ThreadId, |
| 6 | } from "@t3tools/contracts"; | 6 | } from "@t3tools/contracts"; |
| 7 | import { OrchestrationCommand } from "@t3tools/contracts"; | 7 | import { OrchestrationCommand } from "@t3tools/contracts"; |
| 8 | import { Deferred, Effect, Layer, Option, PubSub, Queue, Stream } from "effect"; | 8 | import { Deferred, Effect, Layer, Option, PubSub, Queue, Schema, Stream } from "effect"; |
| 9 | import * as SqlClient from "effect/unstable/sql/SqlClient"; | 9 | import * as SqlClient from "effect/unstable/sql/SqlClient"; |
| 10 | 10 | ||
| 11 | import { toPersistenceSqlError } from "../../persistence/Errors.ts"; | 11 | import { toPersistenceSqlError } from "../../persistence/Errors.ts"; |
| ... | @@ -181,7 +181,7 @@ const makeOrchestrationEngine = Effect.gen(function* () { | ... | @@ -181,7 +181,7 @@ const makeOrchestrationEngine = Effect.gen(function* () { |
| 181 | ), | 181 | ), |
| 182 | ); | 182 | ); |
| 183 | 183 | ||
| 184 | if (error instanceof OrchestrationCommandInvariantError) { | 184 | if (Schema.is(OrchestrationCommandInvariantError)(error)) { |
| 185 | const aggregateRef = commandToAggregateRef(envelope.command); | 185 | const aggregateRef = commandToAggregateRef(envelope.command); |
| 186 | yield* commandReceiptRepository | 186 | yield* commandReceiptRepository |
| 187 | .upsert({ | 187 | .upsert({ |
apps/server/src/orchestration/Layers/ProjectionPipeline.test.ts+1-1| ... | @@ -10,7 +10,7 @@ import { | ... | @@ -10,7 +10,7 @@ import { |
| 10 | ThreadId, | 10 | ThreadId, |
| 11 | TurnId, | 11 | TurnId, |
| 12 | } from "@t3tools/contracts"; | 12 | } from "@t3tools/contracts"; |
| 13 | import { NodeServices } from "@effect/platform-node"; | 13 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 14 | import { assert, it } from "@effect/vitest"; | 14 | import { assert, it } from "@effect/vitest"; |
| 15 | import { Effect, Layer } from "effect"; | 15 | import { Effect, Layer } from "effect"; |
| 16 | import fs from "node:fs"; | 16 | import fs from "node:fs"; |
apps/server/src/orchestration/Services/CheckpointReactor.ts+1-1| ... | @@ -31,4 +31,4 @@ export interface CheckpointReactorShape { | ... | @@ -31,4 +31,4 @@ export interface CheckpointReactorShape { |
| 31 | export class CheckpointReactor extends ServiceMap.Service< | 31 | export class CheckpointReactor extends ServiceMap.Service< |
| 32 | CheckpointReactor, | 32 | CheckpointReactor, |
| 33 | CheckpointReactorShape | 33 | CheckpointReactorShape |
| 34 | >()("orchestration/CheckpointReactor") {} | 34 | >()("t3/orchestration/Services/CheckpointReactor") {} |
apps/server/src/orchestration/Services/OrchestrationEngine.ts+1-1| ... | @@ -77,4 +77,4 @@ export interface OrchestrationEngineShape { | ... | @@ -77,4 +77,4 @@ export interface OrchestrationEngineShape { |
| 77 | export class OrchestrationEngineService extends ServiceMap.Service< | 77 | export class OrchestrationEngineService extends ServiceMap.Service< |
| 78 | OrchestrationEngineService, | 78 | OrchestrationEngineService, |
| 79 | OrchestrationEngineShape | 79 | OrchestrationEngineShape |
| 80 | >()("orchestration/Engine") {} | 80 | >()("t3/orchestration/Services/OrchestrationEngine/OrchestrationEngineService") {} |
apps/server/src/orchestration/Services/OrchestrationReactor.ts+1-1| ... | @@ -28,4 +28,4 @@ export interface OrchestrationReactorShape { | ... | @@ -28,4 +28,4 @@ export interface OrchestrationReactorShape { |
| 28 | export class OrchestrationReactor extends ServiceMap.Service< | 28 | export class OrchestrationReactor extends ServiceMap.Service< |
| 29 | OrchestrationReactor, | 29 | OrchestrationReactor, |
| 30 | OrchestrationReactorShape | 30 | OrchestrationReactorShape |
| 31 | >()("orchestration/OrchestrationReactor") {} | 31 | >()("t3/orchestration/Services/OrchestrationReactor") {} |
apps/server/src/orchestration/Services/ProjectionPipeline.ts+1-1| ... | @@ -39,4 +39,4 @@ export interface OrchestrationProjectionPipelineShape { | ... | @@ -39,4 +39,4 @@ export interface OrchestrationProjectionPipelineShape { |
| 39 | export class OrchestrationProjectionPipeline extends ServiceMap.Service< | 39 | export class OrchestrationProjectionPipeline extends ServiceMap.Service< |
| 40 | OrchestrationProjectionPipeline, | 40 | OrchestrationProjectionPipeline, |
| 41 | OrchestrationProjectionPipelineShape | 41 | OrchestrationProjectionPipelineShape |
| 42 | >()("orchestration/ProjectionPipeline") {} | 42 | >()("t3/orchestration/Services/ProjectionPipeline/OrchestrationProjectionPipeline") {} |
apps/server/src/orchestration/Services/ProjectionSnapshotQuery.ts+1-1| ... | @@ -31,4 +31,4 @@ export interface ProjectionSnapshotQueryShape { | ... | @@ -31,4 +31,4 @@ export interface ProjectionSnapshotQueryShape { |
| 31 | export class ProjectionSnapshotQuery extends ServiceMap.Service< | 31 | export class ProjectionSnapshotQuery extends ServiceMap.Service< |
| 32 | ProjectionSnapshotQuery, | 32 | ProjectionSnapshotQuery, |
| 33 | ProjectionSnapshotQueryShape | 33 | ProjectionSnapshotQueryShape |
| 34 | >()("orchestration/ProjectionSnapshotQuery") {} | 34 | >()("t3/orchestration/Services/ProjectionSnapshotQuery") {} |
apps/server/src/orchestration/Services/ProviderCommandReactor.ts+1-1| ... | @@ -31,4 +31,4 @@ export interface ProviderCommandReactorShape { | ... | @@ -31,4 +31,4 @@ export interface ProviderCommandReactorShape { |
| 31 | export class ProviderCommandReactor extends ServiceMap.Service< | 31 | export class ProviderCommandReactor extends ServiceMap.Service< |
| 32 | ProviderCommandReactor, | 32 | ProviderCommandReactor, |
| 33 | ProviderCommandReactorShape | 33 | ProviderCommandReactorShape |
| 34 | >()("orchestration/ProviderCommandReactor") {} | 34 | >()("t3/orchestration/Services/ProviderCommandReactor") {} |
apps/server/src/orchestration/Services/ProviderRuntimeIngestion.ts+1-1| ... | @@ -31,4 +31,4 @@ export interface ProviderRuntimeIngestionShape { | ... | @@ -31,4 +31,4 @@ export interface ProviderRuntimeIngestionShape { |
| 31 | export class ProviderRuntimeIngestionService extends ServiceMap.Service< | 31 | export class ProviderRuntimeIngestionService extends ServiceMap.Service< |
| 32 | ProviderRuntimeIngestionService, | 32 | ProviderRuntimeIngestionService, |
| 33 | ProviderRuntimeIngestionShape | 33 | ProviderRuntimeIngestionShape |
| 34 | >()("orchestration/ProviderRuntimeIngestion") {} | 34 | >()("t3/orchestration/Services/ProviderRuntimeIngestion/ProviderRuntimeIngestionService") {} |
apps/server/src/persistence/Layers/OrchestrationEventStore.test.ts+2-2| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | import { CommandId, EventId, ProjectId } from "@t3tools/contracts"; | 1 | import { CommandId, EventId, ProjectId } from "@t3tools/contracts"; |
| 2 | import { assert, it } from "@effect/vitest"; | 2 | import { assert, it } from "@effect/vitest"; |
| 3 | import { Effect, Layer, Stream } from "effect"; | 3 | import { Effect, Layer, Schema, Stream } from "effect"; |
| 4 | import * as SqlClient from "effect/unstable/sql/SqlClient"; | 4 | import * as SqlClient from "effect/unstable/sql/SqlClient"; |
| 5 | 5 | ||
| 6 | import { PersistenceDecodeError } from "../Errors.ts"; | 6 | import { PersistenceDecodeError } from "../Errors.ts"; |
| ... | @@ -107,7 +107,7 @@ layer("OrchestrationEventStore", (it) => { | ... | @@ -107,7 +107,7 @@ layer("OrchestrationEventStore", (it) => { |
| 107 | ); | 107 | ); |
| 108 | assert.equal(replayResult._tag, "Failure"); | 108 | assert.equal(replayResult._tag, "Failure"); |
| 109 | if (replayResult._tag === "Failure") { | 109 | if (replayResult._tag === "Failure") { |
| 110 | assert.ok(replayResult.failure instanceof PersistenceDecodeError); | 110 | assert.ok(Schema.is(PersistenceDecodeError)(replayResult.failure)); |
| 111 | assert.ok( | 111 | assert.ok( |
| 112 | replayResult.failure.operation.includes( | 112 | replayResult.failure.operation.includes( |
| 113 | "OrchestrationEventStore.readFromSequence:decodeRows", | 113 | "OrchestrationEventStore.readFromSequence:decodeRows", |
apps/server/src/persistence/Layers/ProviderSessions.ts+2-6| ... | @@ -51,14 +51,10 @@ function toValidationError( | ... | @@ -51,14 +51,10 @@ function toValidationError( |
| 51 | }); | 51 | }); |
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | function decodeInput<A>( | 54 | function decodeInput<S extends Schema.Top>(schema: S, input: unknown, operation: string) { |
| 55 | schema: Schema.Schema<A>, | ||
| 56 | input: unknown, | ||
| 57 | operation: string, | ||
| 58 | ): Effect.Effect<A, ProviderSessionRepositoryValidationError> { | ||
| 59 | return Schema.decodeUnknownEffect(schema)(input).pipe( | 55 | return Schema.decodeUnknownEffect(schema)(input).pipe( |
| 60 | Effect.mapError((cause) => toValidationError(operation, cause)), | 56 | Effect.mapError((cause) => toValidationError(operation, cause)), |
| 61 | ) as Effect.Effect<A, ProviderSessionRepositoryValidationError>; | 57 | ); |
| 62 | } | 58 | } |
| 63 | 59 | ||
| 64 | function toPersistenceError( | 60 | function toPersistenceError( |
apps/server/src/persistence/NodeSqliteClient.ts+1-1| ... | @@ -32,7 +32,7 @@ export type TypeId = "~local/sqlite-node/SqliteClient"; | ... | @@ -32,7 +32,7 @@ export type TypeId = "~local/sqlite-node/SqliteClient"; |
| 32 | /** | 32 | /** |
| 33 | * SqliteClient - Effect service tag for the sqlite SQL client. | 33 | * SqliteClient - Effect service tag for the sqlite SQL client. |
| 34 | */ | 34 | */ |
| 35 | export const SqliteClient = ServiceMap.Service<Client.SqlClient>("@local/sqlite-node/SqliteClient"); | 35 | export const SqliteClient = ServiceMap.Service<Client.SqlClient>("t3/persistence/NodeSqliteClient"); |
| 36 | 36 | ||
| 37 | export interface SqliteClientConfig { | 37 | export interface SqliteClientConfig { |
| 38 | readonly filename: string; | 38 | readonly filename: string; |
apps/server/src/persistence/Services/OrchestrationCommandReceipts.ts+1-1| ... | @@ -66,4 +66,4 @@ export interface OrchestrationCommandReceiptRepositoryShape { | ... | @@ -66,4 +66,4 @@ export interface OrchestrationCommandReceiptRepositoryShape { |
| 66 | export class OrchestrationCommandReceiptRepository extends ServiceMap.Service< | 66 | export class OrchestrationCommandReceiptRepository extends ServiceMap.Service< |
| 67 | OrchestrationCommandReceiptRepository, | 67 | OrchestrationCommandReceiptRepository, |
| 68 | OrchestrationCommandReceiptRepositoryShape | 68 | OrchestrationCommandReceiptRepositoryShape |
| 69 | >()("persistence/OrchestrationCommandReceiptRepository") {} | 69 | >()("t3/persistence/Services/OrchestrationCommandReceipts/OrchestrationCommandReceiptRepository") {} |
apps/server/src/persistence/Services/OrchestrationEventStore.ts+1-1| ... | @@ -67,4 +67,4 @@ export interface OrchestrationEventStoreShape { | ... | @@ -67,4 +67,4 @@ export interface OrchestrationEventStoreShape { |
| 67 | export class OrchestrationEventStore extends ServiceMap.Service< | 67 | export class OrchestrationEventStore extends ServiceMap.Service< |
| 68 | OrchestrationEventStore, | 68 | OrchestrationEventStore, |
| 69 | OrchestrationEventStoreShape | 69 | OrchestrationEventStoreShape |
| 70 | >()("orchestration/EventStore") {} | 70 | >()("t3/persistence/Services/OrchestrationEventStore") {} |
apps/server/src/persistence/Services/ProjectionCheckpoints.ts+1-1| ... | @@ -90,4 +90,4 @@ export interface ProjectionCheckpointRepositoryShape { | ... | @@ -90,4 +90,4 @@ export interface ProjectionCheckpointRepositoryShape { |
| 90 | export class ProjectionCheckpointRepository extends ServiceMap.Service< | 90 | export class ProjectionCheckpointRepository extends ServiceMap.Service< |
| 91 | ProjectionCheckpointRepository, | 91 | ProjectionCheckpointRepository, |
| 92 | ProjectionCheckpointRepositoryShape | 92 | ProjectionCheckpointRepositoryShape |
| 93 | >()("persistence/ProjectionCheckpointRepository") {} | 93 | >()("t3/persistence/Services/ProjectionCheckpoints/ProjectionCheckpointRepository") {} |
apps/server/src/persistence/Services/ProjectionPendingApprovals.ts+1-1| ... | @@ -88,4 +88,4 @@ export interface ProjectionPendingApprovalRepositoryShape { | ... | @@ -88,4 +88,4 @@ export interface ProjectionPendingApprovalRepositoryShape { |
| 88 | export class ProjectionPendingApprovalRepository extends ServiceMap.Service< | 88 | export class ProjectionPendingApprovalRepository extends ServiceMap.Service< |
| 89 | ProjectionPendingApprovalRepository, | 89 | ProjectionPendingApprovalRepository, |
| 90 | ProjectionPendingApprovalRepositoryShape | 90 | ProjectionPendingApprovalRepositoryShape |
| 91 | >()("persistence/ProjectionPendingApprovalRepository") {} | 91 | >()("t3/persistence/Services/ProjectionPendingApprovals/ProjectionPendingApprovalRepository") {} |
apps/server/src/persistence/Services/ProjectionProjects.ts+1-1| ... | @@ -76,4 +76,4 @@ export interface ProjectionProjectRepositoryShape { | ... | @@ -76,4 +76,4 @@ export interface ProjectionProjectRepositoryShape { |
| 76 | export class ProjectionProjectRepository extends ServiceMap.Service< | 76 | export class ProjectionProjectRepository extends ServiceMap.Service< |
| 77 | ProjectionProjectRepository, | 77 | ProjectionProjectRepository, |
| 78 | ProjectionProjectRepositoryShape | 78 | ProjectionProjectRepositoryShape |
| 79 | >()("persistence/ProjectionProjectRepository") {} | 79 | >()("t3/persistence/Services/ProjectionProjects/ProjectionProjectRepository") {} |
apps/server/src/persistence/Services/ProjectionState.ts+1-1| ... | @@ -61,4 +61,4 @@ export interface ProjectionStateRepositoryShape { | ... | @@ -61,4 +61,4 @@ export interface ProjectionStateRepositoryShape { |
| 61 | export class ProjectionStateRepository extends ServiceMap.Service< | 61 | export class ProjectionStateRepository extends ServiceMap.Service< |
| 62 | ProjectionStateRepository, | 62 | ProjectionStateRepository, |
| 63 | ProjectionStateRepositoryShape | 63 | ProjectionStateRepositoryShape |
| 64 | >()("persistence/ProjectionStateRepository") {} | 64 | >()("t3/persistence/Services/ProjectionState/ProjectionStateRepository") {} |
apps/server/src/persistence/Services/ProjectionThreadActivities.ts+1-1| ... | @@ -77,4 +77,4 @@ export interface ProjectionThreadActivityRepositoryShape { | ... | @@ -77,4 +77,4 @@ export interface ProjectionThreadActivityRepositoryShape { |
| 77 | export class ProjectionThreadActivityRepository extends ServiceMap.Service< | 77 | export class ProjectionThreadActivityRepository extends ServiceMap.Service< |
| 78 | ProjectionThreadActivityRepository, | 78 | ProjectionThreadActivityRepository, |
| 79 | ProjectionThreadActivityRepositoryShape | 79 | ProjectionThreadActivityRepositoryShape |
| 80 | >()("persistence/ProjectionThreadActivityRepository") {} | 80 | >()("t3/persistence/Services/ProjectionThreadActivities/ProjectionThreadActivityRepository") {} |
apps/server/src/persistence/Services/ProjectionThreadMessages.ts+1-1| ... | @@ -76,4 +76,4 @@ export interface ProjectionThreadMessageRepositoryShape { | ... | @@ -76,4 +76,4 @@ export interface ProjectionThreadMessageRepositoryShape { |
| 76 | export class ProjectionThreadMessageRepository extends ServiceMap.Service< | 76 | export class ProjectionThreadMessageRepository extends ServiceMap.Service< |
| 77 | ProjectionThreadMessageRepository, | 77 | ProjectionThreadMessageRepository, |
| 78 | ProjectionThreadMessageRepositoryShape | 78 | ProjectionThreadMessageRepositoryShape |
| 79 | >()("persistence/ProjectionThreadMessageRepository") {} | 79 | >()("t3/persistence/Services/ProjectionThreadMessages/ProjectionThreadMessageRepository") {} |
apps/server/src/persistence/Services/ProjectionThreadSessions.ts+1-1| ... | @@ -73,4 +73,4 @@ export interface ProjectionThreadSessionRepositoryShape { | ... | @@ -73,4 +73,4 @@ export interface ProjectionThreadSessionRepositoryShape { |
| 73 | export class ProjectionThreadSessionRepository extends ServiceMap.Service< | 73 | export class ProjectionThreadSessionRepository extends ServiceMap.Service< |
| 74 | ProjectionThreadSessionRepository, | 74 | ProjectionThreadSessionRepository, |
| 75 | ProjectionThreadSessionRepositoryShape | 75 | ProjectionThreadSessionRepositoryShape |
| 76 | >()("persistence/ProjectionThreadSessionRepository") {} | 76 | >()("t3/persistence/Services/ProjectionThreadSessions/ProjectionThreadSessionRepository") {} |
apps/server/src/persistence/Services/ProjectionThreads.ts+1-1| ... | @@ -82,4 +82,4 @@ export interface ProjectionThreadRepositoryShape { | ... | @@ -82,4 +82,4 @@ export interface ProjectionThreadRepositoryShape { |
| 82 | export class ProjectionThreadRepository extends ServiceMap.Service< | 82 | export class ProjectionThreadRepository extends ServiceMap.Service< |
| 83 | ProjectionThreadRepository, | 83 | ProjectionThreadRepository, |
| 84 | ProjectionThreadRepositoryShape | 84 | ProjectionThreadRepositoryShape |
| 85 | >()("persistence/ProjectionThreadRepository") {} | 85 | >()("t3/persistence/Services/ProjectionThreads/ProjectionThreadRepository") {} |
apps/server/src/persistence/Services/ProjectionTurns.ts+1-1| ... | @@ -158,4 +158,4 @@ export interface ProjectionTurnRepositoryShape { | ... | @@ -158,4 +158,4 @@ export interface ProjectionTurnRepositoryShape { |
| 158 | export class ProjectionTurnRepository extends ServiceMap.Service< | 158 | export class ProjectionTurnRepository extends ServiceMap.Service< |
| 159 | ProjectionTurnRepository, | 159 | ProjectionTurnRepository, |
| 160 | ProjectionTurnRepositoryShape | 160 | ProjectionTurnRepositoryShape |
| 161 | >()("persistence/ProjectionTurnRepository") {} | 161 | >()("t3/persistence/Services/ProjectionTurns/ProjectionTurnRepository") {} |
apps/server/src/persistence/Services/ProviderSessionRuntime.ts+1-1| ... | @@ -84,4 +84,4 @@ export interface ProviderSessionRuntimeRepositoryShape { | ... | @@ -84,4 +84,4 @@ export interface ProviderSessionRuntimeRepositoryShape { |
| 84 | export class ProviderSessionRuntimeRepository extends ServiceMap.Service< | 84 | export class ProviderSessionRuntimeRepository extends ServiceMap.Service< |
| 85 | ProviderSessionRuntimeRepository, | 85 | ProviderSessionRuntimeRepository, |
| 86 | ProviderSessionRuntimeRepositoryShape | 86 | ProviderSessionRuntimeRepositoryShape |
| 87 | >()("persistence/ProviderSessionRuntimeRepository") {} | 87 | >()("t3/persistence/Services/ProviderSessionRuntime/ProviderSessionRuntimeRepository") {} |
apps/server/src/persistence/Services/ProviderSessions.ts+1-1| ... | @@ -78,4 +78,4 @@ export interface ProviderSessionRepositoryShape { | ... | @@ -78,4 +78,4 @@ export interface ProviderSessionRepositoryShape { |
| 78 | export class ProviderSessionRepository extends ServiceMap.Service< | 78 | export class ProviderSessionRepository extends ServiceMap.Service< |
| 79 | ProviderSessionRepository, | 79 | ProviderSessionRepository, |
| 80 | ProviderSessionRepositoryShape | 80 | ProviderSessionRepositoryShape |
| 81 | >()("persistence/ProviderSessionRepository") {} | 81 | >()("t3/persistence/Services/ProviderSessions/ProviderSessionRepository") {} |
apps/server/src/provider/Layers/ProviderAdapterRegistry.test.ts+1-1| ... | @@ -8,7 +8,7 @@ import { CodexAdapter, CodexAdapterShape } from "../Services/CodexAdapter.ts"; | ... | @@ -8,7 +8,7 @@ import { CodexAdapter, CodexAdapterShape } from "../Services/CodexAdapter.ts"; |
| 8 | import { ProviderAdapterRegistry } from "../Services/ProviderAdapterRegistry.ts"; | 8 | import { ProviderAdapterRegistry } from "../Services/ProviderAdapterRegistry.ts"; |
| 9 | import { ProviderAdapterRegistryLive } from "./ProviderAdapterRegistry.ts"; | 9 | import { ProviderAdapterRegistryLive } from "./ProviderAdapterRegistry.ts"; |
| 10 | import { ProviderUnsupportedError } from "../Errors.ts"; | 10 | import { ProviderUnsupportedError } from "../Errors.ts"; |
| 11 | import { NodeServices } from "@effect/platform-node"; | 11 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 12 | 12 | ||
| 13 | const fakeCodexAdapter: CodexAdapterShape = { | 13 | const fakeCodexAdapter: CodexAdapterShape = { |
| 14 | provider: "codex", | 14 | provider: "codex", |
apps/server/src/provider/Layers/ProviderService.test.ts+1-1| ... | @@ -37,7 +37,7 @@ import { ProviderService } from "../Services/ProviderService.ts"; | ... | @@ -37,7 +37,7 @@ import { ProviderService } from "../Services/ProviderService.ts"; |
| 37 | import { ProviderSessionDirectory } from "../Services/ProviderSessionDirectory.ts"; | 37 | import { ProviderSessionDirectory } from "../Services/ProviderSessionDirectory.ts"; |
| 38 | import { makeProviderServiceLive } from "./ProviderService.ts"; | 38 | import { makeProviderServiceLive } from "./ProviderService.ts"; |
| 39 | import { ProviderSessionDirectoryLive } from "./ProviderSessionDirectory.ts"; | 39 | import { ProviderSessionDirectoryLive } from "./ProviderSessionDirectory.ts"; |
| 40 | import { NodeServices } from "@effect/platform-node"; | 40 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 41 | import { ProviderSessionRuntimeRepositoryLive } from "../../persistence/Layers/ProviderSessionRuntime.ts"; | 41 | import { ProviderSessionRuntimeRepositoryLive } from "../../persistence/Layers/ProviderSessionRuntime.ts"; |
| 42 | import { ProviderSessionRuntimeRepository } from "../../persistence/Services/ProviderSessionRuntime.ts"; | 42 | import { ProviderSessionRuntimeRepository } from "../../persistence/Services/ProviderSessionRuntime.ts"; |
| 43 | import { | 43 | import { |
apps/server/src/provider/Layers/ProviderSessionDirectory.test.ts+1-1| ... | @@ -2,7 +2,7 @@ import fs from "node:fs"; | ... | @@ -2,7 +2,7 @@ import fs from "node:fs"; |
| 2 | import os from "node:os"; | 2 | import os from "node:os"; |
| 3 | import path from "node:path"; | 3 | import path from "node:path"; |
| 4 | 4 | ||
| 5 | import { NodeServices } from "@effect/platform-node"; | 5 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 6 | import { ProviderSessionId, ProviderThreadId, ThreadId } from "@t3tools/contracts"; | 6 | import { ProviderSessionId, ProviderThreadId, ThreadId } from "@t3tools/contracts"; |
| 7 | import { it, assert } from "@effect/vitest"; | 7 | import { it, assert } from "@effect/vitest"; |
| 8 | import { assertFailure, assertSome } from "@effect/vitest/utils"; | 8 | import { assertFailure, assertSome } from "@effect/vitest/utils"; |
apps/server/src/provider/Services/CodexAdapter.ts+1-1| ... | @@ -26,5 +26,5 @@ export interface CodexAdapterShape extends ProviderAdapterShape<ProviderAdapterE | ... | @@ -26,5 +26,5 @@ export interface CodexAdapterShape extends ProviderAdapterShape<ProviderAdapterE |
| 26 | * CodexAdapter - Service tag for Codex provider adapter operations. | 26 | * CodexAdapter - Service tag for Codex provider adapter operations. |
| 27 | */ | 27 | */ |
| 28 | export class CodexAdapter extends ServiceMap.Service<CodexAdapter, CodexAdapterShape>()( | 28 | export class CodexAdapter extends ServiceMap.Service<CodexAdapter, CodexAdapterShape>()( |
| 29 | "provider/CodexAdapter", | 29 | "t3/provider/Services/CodexAdapter", |
| 30 | ) {} | 30 | ) {} |
apps/server/src/provider/Services/ProviderAdapterRegistry.ts+1-1| ... | @@ -37,6 +37,6 @@ export interface ProviderAdapterRegistryShape { | ... | @@ -37,6 +37,6 @@ export interface ProviderAdapterRegistryShape { |
| 37 | export class ProviderAdapterRegistry extends ServiceMap.Service< | 37 | export class ProviderAdapterRegistry extends ServiceMap.Service< |
| 38 | ProviderAdapterRegistry, | 38 | ProviderAdapterRegistry, |
| 39 | ProviderAdapterRegistryShape | 39 | ProviderAdapterRegistryShape |
| 40 | >()("provider/ProviderAdapterRegistry") {} | 40 | >()("t3/provider/Services/ProviderAdapterRegistry") {} |
| 41 | 41 | ||
| 42 | // Dummy comment for workflow testing. | 42 | // Dummy comment for workflow testing. |
apps/server/src/provider/Services/ProviderService.ts+1-1| ... | @@ -105,5 +105,5 @@ export interface ProviderServiceShape { | ... | @@ -105,5 +105,5 @@ export interface ProviderServiceShape { |
| 105 | * ProviderService - Service tag for provider orchestration. | 105 | * ProviderService - Service tag for provider orchestration. |
| 106 | */ | 106 | */ |
| 107 | export class ProviderService extends ServiceMap.Service<ProviderService, ProviderServiceShape>()( | 107 | export class ProviderService extends ServiceMap.Service<ProviderService, ProviderServiceShape>()( |
| 108 | "provider/ProviderService", | 108 | "t3/provider/Services/ProviderService", |
| 109 | ) {} | 109 | ) {} |
apps/server/src/provider/Services/ProviderSessionDirectory.ts+1-1| ... | @@ -99,4 +99,4 @@ export interface ProviderSessionDirectoryShape { | ... | @@ -99,4 +99,4 @@ export interface ProviderSessionDirectoryShape { |
| 99 | export class ProviderSessionDirectory extends ServiceMap.Service< | 99 | export class ProviderSessionDirectory extends ServiceMap.Service< |
| 100 | ProviderSessionDirectory, | 100 | ProviderSessionDirectory, |
| 101 | ProviderSessionDirectoryShape | 101 | ProviderSessionDirectoryShape |
| 102 | >()("provider/ProviderSessionDirectory") {} | 102 | >()("t3/provider/Services/ProviderSessionDirectory") {} |
apps/server/src/serverLayers.ts+1-1| ... | @@ -1,6 +1,6 @@ | ... | @@ -1,6 +1,6 @@ |
| 1 | import path from "node:path"; | 1 | import path from "node:path"; |
| 2 | 2 | ||
| 3 | import { NodeServices } from "@effect/platform-node"; | 3 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 4 | import { Effect, Layer } from "effect"; | 4 | import { Effect, Layer } from "effect"; |
| 5 | import * as SqlClient from "effect/unstable/sql/SqlClient"; | 5 | import * as SqlClient from "effect/unstable/sql/SqlClient"; |
| 6 | 6 |
apps/server/src/terminal/Layers/Manager.test.ts+42-4| ... | @@ -9,7 +9,13 @@ import { | ... | @@ -9,7 +9,13 @@ import { |
| 9 | } from "@t3tools/contracts"; | 9 | } from "@t3tools/contracts"; |
| 10 | import { afterEach, describe, expect, it } from "vitest"; | 10 | import { afterEach, describe, expect, it } from "vitest"; |
| 11 | 11 | ||
| 12 | import type { PtyAdapterShape, PtyExitEvent, PtyProcess, PtySpawnInput } from "../Services/PTY"; | 12 | import { |
| 13 | PtySpawnError, | ||
| 14 | type PtyAdapterShape, | ||
| 15 | type PtyExitEvent, | ||
| 16 | type PtyProcess, | ||
| 17 | type PtySpawnInput, | ||
| 18 | } from "../Services/PTY"; | ||
| 13 | import { TerminalManagerRuntime } from "./Manager"; | 19 | import { TerminalManagerRuntime } from "./Manager"; |
| 14 | import { Effect, Encoding } from "effect"; | 20 | import { Effect, Encoding } from "effect"; |
| 15 | 21 | ||
| ... | @@ -69,14 +75,33 @@ class FakePtyAdapter implements PtyAdapterShape { | ... | @@ -69,14 +75,33 @@ class FakePtyAdapter implements PtyAdapterShape { |
| 69 | readonly spawnFailures: Error[] = []; | 75 | readonly spawnFailures: Error[] = []; |
| 70 | private nextPid = 9000; | 76 | private nextPid = 9000; |
| 71 | 77 | ||
| 72 | spawn(input: PtySpawnInput): Effect.Effect<PtyProcess> { | 78 | constructor(private readonly mode: "sync" | "async" = "sync") {} |
| 79 | |||
| 80 | spawn(input: PtySpawnInput): Effect.Effect<PtyProcess, PtySpawnError> { | ||
| 73 | this.spawnInputs.push(input); | 81 | this.spawnInputs.push(input); |
| 74 | const failure = this.spawnFailures.shift(); | 82 | const failure = this.spawnFailures.shift(); |
| 75 | if (failure) { | 83 | if (failure) { |
| 76 | throw failure; | 84 | return Effect.fail( |
| 85 | new PtySpawnError({ | ||
| 86 | adapter: "fake", | ||
| 87 | message: "Failed to spawn PTY process", | ||
| 88 | cause: failure, | ||
| 89 | }), | ||
| 90 | ); | ||
| 77 | } | 91 | } |
| 78 | const process = new FakePtyProcess(this.nextPid++); | 92 | const process = new FakePtyProcess(this.nextPid++); |
| 79 | this.processes.push(process); | 93 | this.processes.push(process); |
| 94 | if (this.mode === "async") { | ||
| 95 | return Effect.tryPromise({ | ||
| 96 | try: async () => process, | ||
| 97 | catch: (cause) => | ||
| 98 | new PtySpawnError({ | ||
| 99 | adapter: "fake", | ||
| 100 | message: "Failed to spawn PTY process", | ||
| 101 | cause, | ||
| 102 | }), | ||
| 103 | }); | ||
| 104 | } | ||
| 80 | return Effect.succeed(process); | 105 | return Effect.succeed(process); |
| 81 | } | 106 | } |
| 82 | } | 107 | } |
| ... | @@ -150,11 +175,12 @@ describe("TerminalManager", () => { | ... | @@ -150,11 +175,12 @@ describe("TerminalManager", () => { |
| 150 | subprocessPollIntervalMs?: number; | 175 | subprocessPollIntervalMs?: number; |
| 151 | processKillGraceMs?: number; | 176 | processKillGraceMs?: number; |
| 152 | maxRetainedInactiveSessions?: number; | 177 | maxRetainedInactiveSessions?: number; |
| 178 | ptyAdapter?: FakePtyAdapter; | ||
| 153 | } = {}, | 179 | } = {}, |
| 154 | ) { | 180 | ) { |
| 155 | const logsDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3code-terminal-")); | 181 | const logsDir = fs.mkdtempSync(path.join(os.tmpdir(), "t3code-terminal-")); |
| 156 | tempDirs.push(logsDir); | 182 | tempDirs.push(logsDir); |
| 157 | const ptyAdapter = new FakePtyAdapter(); | 183 | const ptyAdapter = options.ptyAdapter ?? new FakePtyAdapter(); |
| 158 | const manager = new TerminalManagerRuntime({ | 184 | const manager = new TerminalManagerRuntime({ |
| 159 | logsDir, | 185 | logsDir, |
| 160 | ptyAdapter, | 186 | ptyAdapter, |
| ... | @@ -189,6 +215,18 @@ describe("TerminalManager", () => { | ... | @@ -189,6 +215,18 @@ describe("TerminalManager", () => { |
| 189 | manager.dispose(); | 215 | manager.dispose(); |
| 190 | }); | 216 | }); |
| 191 | 217 | ||
| 218 | it("supports asynchronous PTY spawn effects", async () => { | ||
| 219 | const { manager, ptyAdapter } = makeManager(5, { ptyAdapter: new FakePtyAdapter("async") }); | ||
| 220 | |||
| 221 | const snapshot = await manager.open(openInput()); | ||
| 222 | |||
| 223 | expect(snapshot.status).toBe("running"); | ||
| 224 | expect(ptyAdapter.spawnInputs).toHaveLength(1); | ||
| 225 | expect(ptyAdapter.processes).toHaveLength(1); | ||
| 226 | |||
| 227 | manager.dispose(); | ||
| 228 | }); | ||
| 229 | |||
| 192 | it("forwards write and resize to active pty process", async () => { | 230 | it("forwards write and resize to active pty process", async () => { |
| 193 | const { manager, ptyAdapter } = makeManager(); | 231 | const { manager, ptyAdapter } = makeManager(); |
| 194 | await manager.open(openInput()); | 232 | await manager.open(openInput()); |
apps/server/src/terminal/Layers/Manager.ts+75-20| ... | @@ -117,8 +117,43 @@ function resolveShellCandidates(shellResolver: () => string): ShellCandidate[] { | ... | @@ -117,8 +117,43 @@ function resolveShellCandidates(shellResolver: () => string): ShellCandidate[] { |
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | function isRetryableShellSpawnError(error: unknown): boolean { | 119 | function isRetryableShellSpawnError(error: unknown): boolean { |
| 120 | if (!(error instanceof Error)) return false; | 120 | const queue: unknown[] = [error]; |
| 121 | const message = error.message.toLowerCase(); | 121 | const seen = new Set<unknown>(); |
| 122 | const messages: string[] = []; | ||
| 123 | |||
| 124 | while (queue.length > 0) { | ||
| 125 | const current = queue.shift(); | ||
| 126 | if (!current || seen.has(current)) { | ||
| 127 | continue; | ||
| 128 | } | ||
| 129 | seen.add(current); | ||
| 130 | |||
| 131 | if (typeof current === "string") { | ||
| 132 | messages.push(current); | ||
| 133 | continue; | ||
| 134 | } | ||
| 135 | |||
| 136 | if (current instanceof Error) { | ||
| 137 | messages.push(current.message); | ||
| 138 | const cause = (current as { cause?: unknown }).cause; | ||
| 139 | if (cause) { | ||
| 140 | queue.push(cause); | ||
| 141 | } | ||
| 142 | continue; | ||
| 143 | } | ||
| 144 | |||
| 145 | if (typeof current === "object") { | ||
| 146 | const value = current as { message?: unknown; cause?: unknown }; | ||
| 147 | if (typeof value.message === "string") { | ||
| 148 | messages.push(value.message); | ||
| 149 | } | ||
| 150 | if (value.cause) { | ||
| 151 | queue.push(value.cause); | ||
| 152 | } | ||
| 153 | } | ||
| 154 | } | ||
| 155 | |||
| 156 | const message = messages.join(" ").toLowerCase(); | ||
| 122 | return ( | 157 | return ( |
| 123 | message.includes("posix_spawnp failed") || | 158 | message.includes("posix_spawnp failed") || |
| 124 | message.includes("enoent") || | 159 | message.includes("enoent") || |
| ... | @@ -354,7 +389,7 @@ export class TerminalManagerRuntime extends EventEmitter<TerminalManagerEvents> | ... | @@ -354,7 +389,7 @@ export class TerminalManagerRuntime extends EventEmitter<TerminalManagerEvents> |
| 354 | }; | 389 | }; |
| 355 | this.sessions.set(sessionKey, session); | 390 | this.sessions.set(sessionKey, session); |
| 356 | this.evictInactiveSessionsIfNeeded(); | 391 | this.evictInactiveSessionsIfNeeded(); |
| 357 | this.startSession(session, { ...input, cols, rows }, "started"); | 392 | await this.startSession(session, { ...input, cols, rows }, "started"); |
| 358 | return this.snapshot(session); | 393 | return this.snapshot(session); |
| 359 | } | 394 | } |
| 360 | 395 | ||
| ... | @@ -380,7 +415,7 @@ export class TerminalManagerRuntime extends EventEmitter<TerminalManagerEvents> | ... | @@ -380,7 +415,7 @@ export class TerminalManagerRuntime extends EventEmitter<TerminalManagerEvents> |
| 380 | } | 415 | } |
| 381 | 416 | ||
| 382 | if (!existing.process) { | 417 | if (!existing.process) { |
| 383 | this.startSession(existing, { ...input, cols: targetCols, rows: targetRows }, "started"); | 418 | await this.startSession(existing, { ...input, cols: targetCols, rows: targetRows }, "started"); |
| 384 | return this.snapshot(existing); | 419 | return this.snapshot(existing); |
| 385 | } | 420 | } |
| 386 | 421 | ||
| ... | @@ -477,7 +512,7 @@ export class TerminalManagerRuntime extends EventEmitter<TerminalManagerEvents> | ... | @@ -477,7 +512,7 @@ export class TerminalManagerRuntime extends EventEmitter<TerminalManagerEvents> |
| 477 | 512 | ||
| 478 | session.history = ""; | 513 | session.history = ""; |
| 479 | await this.persistHistory(input.threadId, input.terminalId, session.history); | 514 | await this.persistHistory(input.threadId, input.terminalId, session.history); |
| 480 | this.startSession(session, { ...input, cols, rows }, "restarted"); | 515 | await this.startSession(session, { ...input, cols, rows }, "restarted"); |
| 481 | return this.snapshot(session); | 516 | return this.snapshot(session); |
| 482 | }); | 517 | }); |
| 483 | } | 518 | } |
| ... | @@ -528,11 +563,11 @@ export class TerminalManagerRuntime extends EventEmitter<TerminalManagerEvents> | ... | @@ -528,11 +563,11 @@ export class TerminalManagerRuntime extends EventEmitter<TerminalManagerEvents> |
| 528 | this.persistQueues.clear(); | 563 | this.persistQueues.clear(); |
| 529 | } | 564 | } |
| 530 | 565 | ||
| 531 | private startSession( | 566 | private async startSession( |
| 532 | session: TerminalSessionState, | 567 | session: TerminalSessionState, |
| 533 | input: TerminalStartInput, | 568 | input: TerminalStartInput, |
| 534 | eventType: "started" | "restarted", | 569 | eventType: "started" | "restarted", |
| 535 | ): void { | 570 | ): Promise<void> { |
| 536 | this.stopProcess(session); | 571 | this.stopProcess(session); |
| 537 | 572 | ||
| 538 | session.status = "starting"; | 573 | session.status = "starting"; |
| ... | @@ -551,26 +586,46 @@ export class TerminalManagerRuntime extends EventEmitter<TerminalManagerEvents> | ... | @@ -551,26 +586,46 @@ export class TerminalManagerRuntime extends EventEmitter<TerminalManagerEvents> |
| 551 | const terminalEnv = createTerminalSpawnEnv(process.env, session.runtimeEnv); | 586 | const terminalEnv = createTerminalSpawnEnv(process.env, session.runtimeEnv); |
| 552 | let lastSpawnError: unknown = null; | 587 | let lastSpawnError: unknown = null; |
| 553 | 588 | ||
| 554 | for (const candidate of shellCandidates) { | 589 | const spawnWithCandidate = (candidate: ShellCandidate) => |
| 590 | Effect.runPromise( | ||
| 591 | this.ptyAdapter.spawn({ | ||
| 592 | shell: candidate.shell, | ||
| 593 | ...(candidate.args ? { args: candidate.args } : {}), | ||
| 594 | cwd: session.cwd, | ||
| 595 | cols: session.cols, | ||
| 596 | rows: session.rows, | ||
| 597 | env: terminalEnv, | ||
| 598 | }), | ||
| 599 | ); | ||
| 600 | |||
| 601 | const trySpawn = async ( | ||
| 602 | candidates: ShellCandidate[], | ||
| 603 | index = 0, | ||
| 604 | ): Promise<{ process: PtyProcess; shellLabel: string } | null> => { | ||
| 605 | if (index >= candidates.length) { | ||
| 606 | return null; | ||
| 607 | } | ||
| 608 | const candidate = candidates[index]; | ||
| 609 | if (!candidate) { | ||
| 610 | return null; | ||
| 611 | } | ||
| 612 | |||
| 555 | try { | 613 | try { |
| 556 | ptyProcess = Effect.runSync( | 614 | const process = await spawnWithCandidate(candidate); |
| 557 | this.ptyAdapter.spawn({ | 615 | return { process, shellLabel: formatShellCandidate(candidate) }; |
| 558 | shell: candidate.shell, | ||
| 559 | ...(candidate.args ? { args: candidate.args } : {}), | ||
| 560 | cwd: session.cwd, | ||
| 561 | cols: session.cols, | ||
| 562 | rows: session.rows, | ||
| 563 | env: terminalEnv, | ||
| 564 | }), | ||
| 565 | ); | ||
| 566 | startedShell = formatShellCandidate(candidate); | ||
| 567 | break; | ||
| 568 | } catch (error) { | 616 | } catch (error) { |
| 569 | lastSpawnError = error; | 617 | lastSpawnError = error; |
| 570 | if (!isRetryableShellSpawnError(error)) { | 618 | if (!isRetryableShellSpawnError(error)) { |
| 571 | throw error; | 619 | throw error; |
| 572 | } | 620 | } |
| 621 | return trySpawn(candidates, index + 1); | ||
| 573 | } | 622 | } |
| 623 | }; | ||
| 624 | |||
| 625 | const spawnResult = await trySpawn(shellCandidates); | ||
| 626 | if (spawnResult) { | ||
| 627 | ptyProcess = spawnResult.process; | ||
| 628 | startedShell = spawnResult.shellLabel; | ||
| 574 | } | 629 | } |
| 575 | 630 | ||
| 576 | if (!ptyProcess) { | 631 | if (!ptyProcess) { |
apps/server/src/terminal/Layers/NodePTY.test.ts+1-1| ... | @@ -2,7 +2,7 @@ import { FileSystem, Path, Effect } from "effect"; | ... | @@ -2,7 +2,7 @@ import { FileSystem, Path, Effect } from "effect"; |
| 2 | import { assert, it } from "@effect/vitest"; | 2 | import { assert, it } from "@effect/vitest"; |
| 3 | 3 | ||
| 4 | import { ensureNodePtySpawnHelperExecutable } from "./NodePTY"; | 4 | import { ensureNodePtySpawnHelperExecutable } from "./NodePTY"; |
| 5 | import { NodeServices } from "@effect/platform-node"; | 5 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 6 | 6 | ||
| 7 | it.layer(NodeServices.layer)("ensureNodePtySpawnHelperExecutable", (it) => { | 7 | it.layer(NodeServices.layer)("ensureNodePtySpawnHelperExecutable", (it) => { |
| 8 | it.effect("adds executable bits when helper exists but is not executable", () => | 8 | it.effect("adds executable bits when helper exists but is not executable", () => |
apps/server/src/terminal/Layers/NodePTY.ts+5-4| ... | @@ -37,11 +37,12 @@ export const ensureNodePtySpawnHelperExecutable = Effect.fn(function* (explicitP | ... | @@ -37,11 +37,12 @@ export const ensureNodePtySpawnHelperExecutable = Effect.fn(function* (explicitP |
| 37 | didEnsureSpawnHelperExecutable = true; | 37 | didEnsureSpawnHelperExecutable = true; |
| 38 | } | 38 | } |
| 39 | 39 | ||
| 40 | const stat = yield* fs.stat(helperPath); | 40 | if (!(yield* fs.exists(helperPath))) { |
| 41 | const mode = stat.mode & 0o777; | 41 | return; |
| 42 | if ((mode & 0o111) === 0) { | ||
| 43 | yield* fs.chmod(helperPath, mode | 0o111); | ||
| 44 | } | 42 | } |
| 43 | |||
| 44 | // Best-effort: avoid FileSystem.stat in packaged mode where some fs metadata can be missing. | ||
| 45 | yield* fs.chmod(helperPath, 0o755).pipe(Effect.orElseSucceed(() => undefined)); | ||
| 45 | }); | 46 | }); |
| 46 | 47 | ||
| 47 | class NodePtyProcess implements PtyProcess { | 48 | class NodePtyProcess implements PtyProcess { |
apps/server/src/terminal/Services/Manager.ts+1-1| ... | @@ -113,5 +113,5 @@ export interface TerminalManagerShape { | ... | @@ -113,5 +113,5 @@ export interface TerminalManagerShape { |
| 113 | * TerminalManager - Service tag for terminal session orchestration. | 113 | * TerminalManager - Service tag for terminal session orchestration. |
| 114 | */ | 114 | */ |
| 115 | export class TerminalManager extends ServiceMap.Service<TerminalManager, TerminalManagerShape>()( | 115 | export class TerminalManager extends ServiceMap.Service<TerminalManager, TerminalManagerShape>()( |
| 116 | "terminal/TerminalManager", | 116 | "t3/terminal/Services/Manager/TerminalManager", |
| 117 | ) {} | 117 | ) {} |
apps/server/src/terminal/Services/PTY.ts+12-3| ... | @@ -6,7 +6,16 @@ | ... | @@ -6,7 +6,16 @@ |
| 6 | * | 6 | * |
| 7 | * @module PtyAdapter | 7 | * @module PtyAdapter |
| 8 | */ | 8 | */ |
| 9 | import { Effect, ServiceMap } from "effect"; | 9 | import { Effect, Schema, ServiceMap } from "effect"; |
| 10 | |||
| 11 | /** | ||
| 12 | * PtyError - Error type for PTY adapter operations. | ||
| 13 | */ | ||
| 14 | export class PtySpawnError extends Schema.TaggedErrorClass<PtySpawnError>()("PtySpawnError", { | ||
| 15 | adapter: Schema.String, | ||
| 16 | message: Schema.String, | ||
| 17 | cause: Schema.optional(Schema.Defect), | ||
| 18 | }) {} | ||
| 10 | 19 | ||
| 11 | export interface PtyExitEvent { | 20 | export interface PtyExitEvent { |
| 12 | exitCode: number; | 21 | exitCode: number; |
| ... | @@ -38,12 +47,12 @@ export interface PtyAdapterShape { | ... | @@ -38,12 +47,12 @@ export interface PtyAdapterShape { |
| 38 | /** | 47 | /** |
| 39 | * Spawn a PTY process for a terminal session. | 48 | * Spawn a PTY process for a terminal session. |
| 40 | */ | 49 | */ |
| 41 | spawn(input: PtySpawnInput): Effect.Effect<PtyProcess>; | 50 | spawn(input: PtySpawnInput): Effect.Effect<PtyProcess, PtySpawnError>; |
| 42 | } | 51 | } |
| 43 | 52 | ||
| 44 | /** | 53 | /** |
| 45 | * PtyAdapter - Service tag for PTY process integration. | 54 | * PtyAdapter - Service tag for PTY process integration. |
| 46 | */ | 55 | */ |
| 47 | export class PtyAdapter extends ServiceMap.Service<PtyAdapter, PtyAdapterShape>()( | 56 | export class PtyAdapter extends ServiceMap.Service<PtyAdapter, PtyAdapterShape>()( |
| 48 | "terminal/PtyAdapter", | 57 | "t3/terminal/Services/PTY/PtyAdapter", |
| 49 | ) {} | 58 | ) {} |
apps/server/src/wsServer.ts+10-14| ... | @@ -23,7 +23,7 @@ import { | ... | @@ -23,7 +23,7 @@ import { |
| 23 | WsPush, | 23 | WsPush, |
| 24 | WsResponse, | 24 | WsResponse, |
| 25 | } from "@t3tools/contracts"; | 25 | } from "@t3tools/contracts"; |
| 26 | import { NodeHttpServer } from "@effect/platform-node"; | 26 | import * as NodeHttpServer from "@effect/platform-node/NodeHttpServer"; |
| 27 | import { Cause, Effect, Exit, Layer, Ref, Schema, Scope, ServiceMap, Stream, Struct } from "effect"; | 27 | import { Cause, Effect, Exit, Layer, Ref, Schema, Scope, ServiceMap, Stream, Struct } from "effect"; |
| 28 | import { WebSocketServer, type WebSocket } from "ws"; | 28 | import { WebSocketServer, type WebSocket } from "ws"; |
| 29 | 29 | ||
| ... | @@ -79,7 +79,7 @@ export interface ServerShape { | ... | @@ -79,7 +79,7 @@ export interface ServerShape { |
| 79 | /** | 79 | /** |
| 80 | * Server - Service tag for HTTP/WebSocket lifecycle management. | 80 | * Server - Service tag for HTTP/WebSocket lifecycle management. |
| 81 | */ | 81 | */ |
| 82 | export class Server extends ServiceMap.Service<Server, ServerShape>()("server/Server") {} | 82 | export class Server extends ServiceMap.Service<Server, ServerShape>()("t3/wsServer/Server") {} |
| 83 | 83 | ||
| 84 | const isServerNotRunningError = (error: unknown): boolean => { | 84 | const isServerNotRunningError = (error: unknown): boolean => { |
| 85 | if (!(error instanceof Error)) return false; | 85 | if (!(error instanceof Error)) return false; |
| ... | @@ -320,22 +320,18 @@ export const createServer = Effect.fn(function* (): Effect.fn.Return< | ... | @@ -320,22 +320,18 @@ export const createServer = Effect.fn(function* (): Effect.fn.Return< |
| 320 | yield* Effect.addFinalizer(() => Scope.close(subscriptionsScope, Exit.void)); | 320 | yield* Effect.addFinalizer(() => Scope.close(subscriptionsScope, Exit.void)); |
| 321 | 321 | ||
| 322 | yield* Stream.runForEach(orchestrationEngine.streamDomainEvents, (event) => | 322 | yield* Stream.runForEach(orchestrationEngine.streamDomainEvents, (event) => |
| 323 | Effect.gen(function* () { | 323 | broadcastPush({ |
| 324 | yield* broadcastPush({ | 324 | type: "push", |
| 325 | type: "push", | 325 | channel: ORCHESTRATION_WS_CHANNELS.domainEvent, |
| 326 | channel: ORCHESTRATION_WS_CHANNELS.domainEvent, | 326 | data: event, |
| 327 | data: event, | ||
| 328 | }); | ||
| 329 | }), | 327 | }), |
| 330 | ).pipe(Effect.forkIn(subscriptionsScope)); | 328 | ).pipe(Effect.forkIn(subscriptionsScope)); |
| 331 | 329 | ||
| 332 | yield* Stream.runForEach(keybindingsManager.changes, (event) => | 330 | yield* Stream.runForEach(keybindingsManager.changes, (event) => |
| 333 | Effect.gen(function* () { | 331 | broadcastPush({ |
| 334 | yield* broadcastPush({ | 332 | type: "push", |
| 335 | type: "push", | 333 | channel: WS_CHANNELS.serverConfigUpdated, |
| 336 | channel: WS_CHANNELS.serverConfigUpdated, | 334 | data: event, |
| 337 | data: event, | ||
| 338 | }); | ||
| 339 | }), | 335 | }), |
| 340 | ).pipe(Effect.forkIn(subscriptionsScope)); | 336 | ).pipe(Effect.forkIn(subscriptionsScope)); |
| 341 | 337 |
apps/server/tsconfig.json+8-1| ... | @@ -8,7 +8,14 @@ | ... | @@ -8,7 +8,14 @@ |
| 8 | "allowImportingTsExtensions": true, | 8 | "allowImportingTsExtensions": true, |
| 9 | "plugins": [ | 9 | "plugins": [ |
| 10 | { | 10 | { |
| 11 | "name": "@effect/language-service" | 11 | "name": "@effect/language-service", |
| 12 | "namespaceImportPackages": ["@effect/platform-node"], | ||
| 13 | "diagnosticSeverity": { | ||
| 14 | "importFromBarrel": "error", | ||
| 15 | "anyUnknownInErrorContext": "warning", | ||
| 16 | "instanceOfSchema": "warning", | ||
| 17 | "deterministicKeys": "warning" | ||
| 18 | } | ||
| 12 | } | 19 | } |
| 13 | ] | 20 | ] |
| 14 | }, | 21 | }, |
apps/web/package.json+2-1| ... | @@ -21,7 +21,7 @@ | ... | @@ -21,7 +21,7 @@ |
| 21 | "@xterm/addon-fit": "^0.11.0", | 21 | "@xterm/addon-fit": "^0.11.0", |
| 22 | "@xterm/xterm": "^6.0.0", | 22 | "@xterm/xterm": "^6.0.0", |
| 23 | "class-variance-authority": "^0.7.1", | 23 | "class-variance-authority": "^0.7.1", |
| 24 | "effect": "4.0.0-beta.10", | 24 | "effect": "catalog:", |
| 25 | "highlight.js": "^11.11.1", | 25 | "highlight.js": "^11.11.1", |
| 26 | "lucide-react": "^0.564.0", | 26 | "lucide-react": "^0.564.0", |
| 27 | "react": "^19.0.0", | 27 | "react": "^19.0.0", |
| ... | @@ -32,6 +32,7 @@ | ... | @@ -32,6 +32,7 @@ |
| 32 | "tailwind-merge": "^3.4.0" | 32 | "tailwind-merge": "^3.4.0" |
| 33 | }, | 33 | }, |
| 34 | "devDependencies": { | 34 | "devDependencies": { |
| 35 | "@effect/language-service": "catalog:", | ||
| 35 | "@tailwindcss/vite": "^4.0.0", | 36 | "@tailwindcss/vite": "^4.0.0", |
| 36 | "@tanstack/router-plugin": "^1.161.0", | 37 | "@tanstack/router-plugin": "^1.161.0", |
| 37 | "@types/react": "^19.0.0", | 38 | "@types/react": "^19.0.0", |
apps/web/src/components/DiffWorkerPoolProvider.tsx+2-2| ... | @@ -1,4 +1,5 @@ | ... | @@ -1,4 +1,5 @@ |
| 1 | import { WorkerPoolContextProvider } from "@pierre/diffs/react"; | 1 | import { WorkerPoolContextProvider } from "@pierre/diffs/react"; |
| 2 | import DiffsWorker from "@pierre/diffs/worker/worker.js?worker"; | ||
| 2 | import { useMemo, type ReactNode } from "react"; | 3 | import { useMemo, type ReactNode } from "react"; |
| 3 | 4 | ||
| 4 | export function DiffWorkerPoolProvider({ children }: { children?: ReactNode }) { | 5 | export function DiffWorkerPoolProvider({ children }: { children?: ReactNode }) { |
| ... | @@ -11,8 +12,7 @@ export function DiffWorkerPoolProvider({ children }: { children?: ReactNode }) { | ... | @@ -11,8 +12,7 @@ export function DiffWorkerPoolProvider({ children }: { children?: ReactNode }) { |
| 11 | return ( | 12 | return ( |
| 12 | <WorkerPoolContextProvider | 13 | <WorkerPoolContextProvider |
| 13 | poolOptions={{ | 14 | poolOptions={{ |
| 14 | workerFactory: () => | 15 | workerFactory: () => new DiffsWorker(), |
| 15 | new Worker(new URL("../workers/diffs.worker.ts", import.meta.url), { type: "module" }), | ||
| 16 | poolSize: workerPoolSize, | 16 | poolSize: workerPoolSize, |
| 17 | totalASTLRUCacheSize: 240, | 17 | totalASTLRUCacheSize: 240, |
| 18 | }} | 18 | }} |
apps/web/src/workers/diffs.worker.ts deleted-1| ... | @@ -1 +0,0 @@ | ||
| 1 | import "@pierre/diffs/worker/worker.js"; | ||
apps/web/tsconfig.json+13-1| ... | @@ -7,7 +7,19 @@ | ... | @@ -7,7 +7,19 @@ |
| 7 | "types": ["vite/client"], | 7 | "types": ["vite/client"], |
| 8 | "paths": { | 8 | "paths": { |
| 9 | "~/*": ["./src/*"] | 9 | "~/*": ["./src/*"] |
| 10 | } | 10 | }, |
| 11 | "plugins": [ | ||
| 12 | { | ||
| 13 | "name": "@effect/language-service", | ||
| 14 | "namespaceImportPackages": ["@effect/platform-node"], | ||
| 15 | "diagnosticSeverity": { | ||
| 16 | "importFromBarrel": "error", | ||
| 17 | "anyUnknownInErrorContext": "warning", | ||
| 18 | "instanceOfSchema": "warning", | ||
| 19 | "deterministicKeys": "warning" | ||
| 20 | } | ||
| 21 | } | ||
| 22 | ] | ||
| 11 | }, | 23 | }, |
| 12 | "include": ["src", "vite.config.ts"] | 24 | "include": ["src", "vite.config.ts"] |
| 13 | } | 25 | } |
bun.lock+20-12| ... | @@ -35,17 +35,17 @@ | ... | @@ -35,17 +35,17 @@ |
| 35 | "t3": "./dist/index.mjs", | 35 | "t3": "./dist/index.mjs", |
| 36 | }, | 36 | }, |
| 37 | "dependencies": { | 37 | "dependencies": { |
| 38 | "@effect/platform-node": "4.0.0-beta.10", | 38 | "@effect/platform-node": "catalog:", |
| 39 | "@effect/sql-sqlite-bun": "4.0.0-beta.10", | 39 | "@effect/sql-sqlite-bun": "catalog:", |
| 40 | "@pierre/diffs": "^1.1.0-beta.16", | 40 | "@pierre/diffs": "^1.1.0-beta.16", |
| 41 | "effect": "4.0.0-beta.10", | 41 | "effect": "catalog:", |
| 42 | "node-pty": "^1.1.0", | 42 | "node-pty": "^1.1.0", |
| 43 | "open": "^10.1.0", | 43 | "open": "^10.1.0", |
| 44 | "ws": "^8.18.0", | 44 | "ws": "^8.18.0", |
| 45 | }, | 45 | }, |
| 46 | "devDependencies": { | 46 | "devDependencies": { |
| 47 | "@effect/language-service": "0.75.1", | 47 | "@effect/language-service": "0.75.1", |
| 48 | "@effect/vitest": "4.0.0-beta.10", | 48 | "@effect/vitest": "catalog:", |
| 49 | "@t3tools/contracts": "workspace:*", | 49 | "@t3tools/contracts": "workspace:*", |
| 50 | "@t3tools/web": "workspace:*", | 50 | "@t3tools/web": "workspace:*", |
| 51 | "@types/bun": "^1.3.9", | 51 | "@types/bun": "^1.3.9", |
| ... | @@ -70,7 +70,7 @@ | ... | @@ -70,7 +70,7 @@ |
| 70 | "@xterm/addon-fit": "^0.11.0", | 70 | "@xterm/addon-fit": "^0.11.0", |
| 71 | "@xterm/xterm": "^6.0.0", | 71 | "@xterm/xterm": "^6.0.0", |
| 72 | "class-variance-authority": "^0.7.1", | 72 | "class-variance-authority": "^0.7.1", |
| 73 | "effect": "4.0.0-beta.10", | 73 | "effect": "catalog:", |
| 74 | "highlight.js": "^11.11.1", | 74 | "highlight.js": "^11.11.1", |
| 75 | "lucide-react": "^0.564.0", | 75 | "lucide-react": "^0.564.0", |
| 76 | "react": "^19.0.0", | 76 | "react": "^19.0.0", |
| ... | @@ -81,6 +81,7 @@ | ... | @@ -81,6 +81,7 @@ |
| 81 | "tailwind-merge": "^3.4.0", | 81 | "tailwind-merge": "^3.4.0", |
| 82 | }, | 82 | }, |
| 83 | "devDependencies": { | 83 | "devDependencies": { |
| 84 | "@effect/language-service": "catalog:", | ||
| 84 | "@tailwindcss/vite": "^4.0.0", | 85 | "@tailwindcss/vite": "^4.0.0", |
| 85 | "@tanstack/router-plugin": "^1.161.0", | 86 | "@tanstack/router-plugin": "^1.161.0", |
| 86 | "@types/react": "^19.0.0", | 87 | "@types/react": "^19.0.0", |
| ... | @@ -96,16 +97,23 @@ | ... | @@ -96,16 +97,23 @@ |
| 96 | "name": "@t3tools/contracts", | 97 | "name": "@t3tools/contracts", |
| 97 | "version": "0.0.0", | 98 | "version": "0.0.0", |
| 98 | "dependencies": { | 99 | "dependencies": { |
| 99 | "effect": "4.0.0-beta.10", | 100 | "effect": "catalog:", |
| 100 | }, | 101 | }, |
| 101 | "devDependencies": { | 102 | "devDependencies": { |
| 102 | "@effect/language-service": "0.75.1", | 103 | "@effect/language-service": "0.75.1", |
| 103 | "@effect/vitest": "4.0.0-beta.10", | 104 | "@effect/vitest": "catalog:", |
| 104 | "tsdown": "^0.20.3", | 105 | "tsdown": "^0.20.3", |
| 105 | "typescript": "^5.7.3", | 106 | "typescript": "^5.7.3", |
| 106 | }, | 107 | }, |
| 107 | }, | 108 | }, |
| 108 | }, | 109 | }, |
| 110 | "catalog": { | ||
| 111 | "@effect/language-service": "0.75.1", | ||
| 112 | "@effect/platform-node": "https://pkg.pr.new/Effect-TS/effect-smol/@effect/platform-node@f591738", | ||
| 113 | "@effect/sql-sqlite-bun": "https://pkg.pr.new/Effect-TS/effect-smol/@effect/sql-sqlite-bun@f591738", | ||
| 114 | "@effect/vitest": "https://pkg.pr.new/Effect-TS/effect-smol/@effect/vitest@f591738", | ||
| 115 | "effect": "https://pkg.pr.new/Effect-TS/effect-smol/effect@f591738", | ||
| 116 | }, | ||
| 109 | "packages": { | 117 | "packages": { |
| 110 | "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], | 118 | "@babel/code-frame": ["@babel/code-frame@7.29.0", "", { "dependencies": { "@babel/helper-validator-identifier": "^7.28.5", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" } }, "sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw=="], |
| 111 | 119 | ||
| ... | @@ -157,13 +165,13 @@ | ... | @@ -157,13 +165,13 @@ |
| 157 | 165 | ||
| 158 | "@effect/language-service": ["@effect/language-service@0.75.1", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-g9xD2tAQgRFpYC2YgpZq02VeSL5fBbFJ0B/g1o+14NuNmwtaYJc7SjiLWAA9eyhJHosNrn6h1Ye+Kx6j5mN0AA=="], | 166 | "@effect/language-service": ["@effect/language-service@0.75.1", "", { "bin": { "effect-language-service": "cli.js" } }, "sha512-g9xD2tAQgRFpYC2YgpZq02VeSL5fBbFJ0B/g1o+14NuNmwtaYJc7SjiLWAA9eyhJHosNrn6h1Ye+Kx6j5mN0AA=="], |
| 159 | 167 | ||
| 160 | "@effect/platform-node": ["@effect/platform-node@4.0.0-beta.10", "", { "dependencies": { "@effect/platform-node-shared": "^4.0.0-beta.10", "mime": "^4.1.0", "undici": "^7.20.0" }, "peerDependencies": { "effect": "^4.0.0-beta.10", "ioredis": "^5.7.0" } }, "sha512-ikZ/uyos5okYAHE+wWOwZkHgriFUTY3aY8Kdqbj/ro8xw0z9YXWN4fbyQAZUWkBcieDKS36N+QfHRMPG4fEWRA=="], | 168 | "@effect/platform-node": ["@effect/platform-node@https://pkg.pr.new/Effect-TS/effect-smol/@effect/platform-node@f591738", { "dependencies": { "@effect/platform-node-shared": "https://pkg.pr.new/Effect-TS/effect-smol/@effect/platform-node-shared@f59173885df0eb490dc2e6619ae89467feac0413", "mime": "^4.1.0", "undici": "^7.20.0" }, "peerDependencies": { "effect": "^4.0.0-beta.19", "ioredis": "^5.7.0" } }], |
| 161 | 169 | ||
| 162 | "@effect/platform-node-shared": ["@effect/platform-node-shared@4.0.0-beta.10", "", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.19.0" }, "peerDependencies": { "effect": "^4.0.0-beta.10" } }, "sha512-gBSeOG2bfchXFdgdi5oipHKynOzSd7BlzTy5QcjFOoCUTtLP9igqohPB9hTkV3a6seWE2JJqsgsQ79VuLb7fAg=="], | 170 | "@effect/platform-node-shared": ["@effect/platform-node-shared@https://pkg.pr.new/Effect-TS/effect-smol/@effect/platform-node-shared@f59173885df0eb490dc2e6619ae89467feac0413", { "dependencies": { "@types/ws": "^8.18.1", "ws": "^8.19.0" }, "peerDependencies": { "effect": "^4.0.0-beta.19" } }], |
| 163 | 171 | ||
| 164 | "@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@4.0.0-beta.10", "", { "peerDependencies": { "effect": "^4.0.0-beta.10" } }, "sha512-LY1jNu2uqGYsJCVjVU73nzcZ+kAYBDsG7O8x5ddmkIXj10RmnIhjYMStWBa0NZOFg4Hsl+CadxtsDy3edaOVeA=="], | 172 | "@effect/sql-sqlite-bun": ["@effect/sql-sqlite-bun@https://pkg.pr.new/Effect-TS/effect-smol/@effect/sql-sqlite-bun@f591738", { "peerDependencies": { "effect": "^4.0.0-beta.19" } }], |
| 165 | 173 | ||
| 166 | "@effect/vitest": ["@effect/vitest@4.0.0-beta.10", "", { "peerDependencies": { "effect": "^4.0.0-beta.10", "vitest": "^3.0.0" } }, "sha512-WmE8vCNw+eDoAq9CwwymrAdIBw1f+8hDP3AUF7jyC7/Cj/kyAYOFwkbtKmDXIFaTlf7G/2fmulEXeCO5W8j0kQ=="], | 174 | "@effect/vitest": ["@effect/vitest@https://pkg.pr.new/Effect-TS/effect-smol/@effect/vitest@f591738", { "peerDependencies": { "effect": "^4.0.0-beta.19", "vitest": "^3.0.0" } }], |
| 167 | 175 | ||
| 168 | "@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=="], | 176 | "@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=="], |
| 169 | 177 | ||
| ... | @@ -729,7 +737,7 @@ | ... | @@ -729,7 +737,7 @@ |
| 729 | 737 | ||
| 730 | "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], | 738 | "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], |
| 731 | 739 | ||
| 732 | "effect": ["effect@4.0.0-beta.10", "", { "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-UvxWmT0uzWZqNmQODfW7y1zb0LMlH3xtSn/UESpck2Wvv6SogxibYPWKKNcUsRMm5wwprOoW2IwItYLQyZpe8Q=="], | 740 | "effect": ["effect@https://pkg.pr.new/Effect-TS/effect-smol/effect@f591738", { "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" } }], |
| 733 | 741 | ||
| 734 | "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=="], | 742 | "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=="], |
| 735 | 743 |
package.json+13-4| ... | @@ -1,10 +1,19 @@ | ... | @@ -1,10 +1,19 @@ |
| 1 | { | 1 | { |
| 2 | "name": "@t3tools/monorepo", | 2 | "name": "@t3tools/monorepo", |
| 3 | "private": true, | 3 | "private": true, |
| 4 | "workspaces": [ | 4 | "workspaces": { |
| 5 | "apps/*", | 5 | "packages": [ |
| 6 | "packages/*" | 6 | "apps/*", |
| 7 | ], | 7 | "packages/*" |
| 8 | ], | ||
| 9 | "catalog": { | ||
| 10 | "effect": "https://pkg.pr.new/Effect-TS/effect-smol/effect@f591738", | ||
| 11 | "@effect/platform-node": "https://pkg.pr.new/Effect-TS/effect-smol/@effect/platform-node@f591738", | ||
| 12 | "@effect/sql-sqlite-bun": "https://pkg.pr.new/Effect-TS/effect-smol/@effect/sql-sqlite-bun@f591738", | ||
| 13 | "@effect/vitest": "https://pkg.pr.new/Effect-TS/effect-smol/@effect/vitest@f591738", | ||
| 14 | "@effect/language-service": "0.75.1" | ||
| 15 | } | ||
| 16 | }, | ||
| 8 | "scripts": { | 17 | "scripts": { |
| 9 | "dev": "bun run scripts/dev-runner.mjs dev", | 18 | "dev": "bun run scripts/dev-runner.mjs dev", |
| 10 | "dev:server": "bun run scripts/dev-runner.mjs dev:server", | 19 | "dev:server": "bun run scripts/dev-runner.mjs dev:server", |
packages/contracts/package.json+2-2| ... | @@ -24,11 +24,11 @@ | ... | @@ -24,11 +24,11 @@ |
| 24 | "test": "vitest run" | 24 | "test": "vitest run" |
| 25 | }, | 25 | }, |
| 26 | "dependencies": { | 26 | "dependencies": { |
| 27 | "effect": "4.0.0-beta.10" | 27 | "effect": "catalog:" |
| 28 | }, | 28 | }, |
| 29 | "devDependencies": { | 29 | "devDependencies": { |
| 30 | "@effect/language-service": "0.75.1", | 30 | "@effect/language-service": "0.75.1", |
| 31 | "@effect/vitest": "4.0.0-beta.10", | 31 | "@effect/vitest": "catalog:", |
| 32 | "tsdown": "^0.20.3", | 32 | "tsdown": "^0.20.3", |
| 33 | "typescript": "^5.7.3" | 33 | "typescript": "^5.7.3" |
| 34 | } | 34 | } |
packages/contracts/tsconfig.json+8-1| ... | @@ -3,7 +3,14 @@ | ... | @@ -3,7 +3,14 @@ |
| 3 | "compilerOptions": { | 3 | "compilerOptions": { |
| 4 | "plugins": [ | 4 | "plugins": [ |
| 5 | { | 5 | { |
| 6 | "name": "@effect/language-service" | 6 | "name": "@effect/language-service", |
| 7 | "namespaceImportPackages": ["@effect/platform-node"], | ||
| 8 | "diagnosticSeverity": { | ||
| 9 | "importFromBarrel": "error", | ||
| 10 | "anyUnknownInErrorContext": "warning", | ||
| 11 | "instanceOfSchema": "warning", | ||
| 12 | "deterministicKeys": "warning" | ||
| 13 | } | ||
| 7 | } | 14 | } |
| 8 | ] | 15 | ] |
| 9 | }, | 16 | }, |
scripts/build-desktop-dmg.mjs+43-1| ... | @@ -206,6 +206,42 @@ async function validateBundledClientAssets(clientDir) { | ... | @@ -206,6 +206,42 @@ async function validateBundledClientAssets(clientDir) { |
| 206 | } | 206 | } |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | function readWorkspaceCatalog(rootPackageJson) { | ||
| 210 | const workspaces = rootPackageJson?.workspaces; | ||
| 211 | if (!workspaces || typeof workspaces !== "object" || Array.isArray(workspaces)) { | ||
| 212 | return {}; | ||
| 213 | } | ||
| 214 | |||
| 215 | const catalog = workspaces.catalog; | ||
| 216 | if (!catalog || typeof catalog !== "object" || Array.isArray(catalog)) { | ||
| 217 | return {}; | ||
| 218 | } | ||
| 219 | |||
| 220 | return catalog; | ||
| 221 | } | ||
| 222 | |||
| 223 | function resolveCatalogDependencies(dependencies, catalog, dependencySourceLabel) { | ||
| 224 | return Object.fromEntries( | ||
| 225 | Object.entries(dependencies).map(([dependencyName, spec]) => { | ||
| 226 | if (typeof spec !== "string" || !spec.startsWith("catalog:")) { | ||
| 227 | return [dependencyName, spec]; | ||
| 228 | } | ||
| 229 | |||
| 230 | const catalogKey = spec.slice("catalog:".length).trim(); | ||
| 231 | const lookupKey = catalogKey.length > 0 ? catalogKey : dependencyName; | ||
| 232 | const resolvedSpec = catalog[lookupKey]; | ||
| 233 | if (typeof resolvedSpec !== "string" || resolvedSpec.length === 0) { | ||
| 234 | fail( | ||
| 235 | `Unable to resolve '${spec}' for ${dependencySourceLabel} dependency '${dependencyName}'. ` + | ||
| 236 | `Expected key '${lookupKey}' in root workspace catalog.`, | ||
| 237 | ); | ||
| 238 | } | ||
| 239 | |||
| 240 | return [dependencyName, resolvedSpec]; | ||
| 241 | }), | ||
| 242 | ); | ||
| 243 | } | ||
| 244 | |||
| 209 | async function main() { | 245 | async function main() { |
| 210 | const options = parseArgs(process.argv.slice(2)); | 246 | const options = parseArgs(process.argv.slice(2)); |
| 211 | if (options.help) { | 247 | if (options.help) { |
| ... | @@ -217,6 +253,7 @@ async function main() { | ... | @@ -217,6 +253,7 @@ async function main() { |
| 217 | fail("This script only builds macOS .dmg artifacts and must run on macOS."); | 253 | fail("This script only builds macOS .dmg artifacts and must run on macOS."); |
| 218 | } | 254 | } |
| 219 | 255 | ||
| 256 | const rootPkg = await readJson(path.join(repoRoot, "package.json")); | ||
| 220 | const desktopPkg = await readJson(path.join(repoRoot, "apps/desktop/package.json")); | 257 | const desktopPkg = await readJson(path.join(repoRoot, "apps/desktop/package.json")); |
| 221 | const serverPkg = await readJson(path.join(repoRoot, "apps/server/package.json")); | 258 | const serverPkg = await readJson(path.join(repoRoot, "apps/server/package.json")); |
| 222 | 259 | ||
| ... | @@ -229,6 +266,11 @@ async function main() { | ... | @@ -229,6 +266,11 @@ async function main() { |
| 229 | if (!dependencies || Object.keys(dependencies).length === 0) { | 266 | if (!dependencies || Object.keys(dependencies).length === 0) { |
| 230 | fail("Could not resolve production dependencies from apps/server/package.json."); | 267 | fail("Could not resolve production dependencies from apps/server/package.json."); |
| 231 | } | 268 | } |
| 269 | const resolvedDependencies = resolveCatalogDependencies( | ||
| 270 | dependencies, | ||
| 271 | readWorkspaceCatalog(rootPkg), | ||
| 272 | "apps/server", | ||
| 273 | ); | ||
| 232 | 274 | ||
| 233 | const appVersion = options.version ?? serverPkg.version ?? "0.1.0"; | 275 | const appVersion = options.version ?? serverPkg.version ?? "0.1.0"; |
| 234 | const stageRoot = path.join(os.tmpdir(), "t3code-desktop-dmg-stage"); | 276 | const stageRoot = path.join(os.tmpdir(), "t3code-desktop-dmg-stage"); |
| ... | @@ -291,7 +333,7 @@ async function main() { | ... | @@ -291,7 +333,7 @@ async function main() { |
| 291 | category: "public.app-category.developer-tools", | 333 | category: "public.app-category.developer-tools", |
| 292 | }, | 334 | }, |
| 293 | }, | 335 | }, |
| 294 | dependencies, | 336 | dependencies: resolvedDependencies, |
| 295 | devDependencies: { | 337 | devDependencies: { |
| 296 | electron: electronVersion, | 338 | electron: electronVersion, |
| 297 | }, | 339 | }, |