From 9fae3ee0e95b036388b597558ee58617b0035494 Mon Sep 17 00:00:00 2001 From: Julius Marminge Date: Thu, 26 Feb 2026 00:18:11 -0800 Subject: [PATCH] look over effect services --- .plans/16c-pr89-remediation-checklist.md | 12 +- apps/server/src/checkpointing/Errors.ts | 40 +----- .../Layers/CheckpointDiffQuery.ts | 1 - .../Services/CheckpointDiffQuery.ts | 25 ++++ .../checkpointing/Services/CheckpointStore.ts | 11 ++ apps/server/src/config.ts | 25 ++++ apps/server/src/git/Errors.ts | 21 +-- apps/server/src/git/Services/GitService.ts | 3 + apps/server/src/keybindings.ts | 26 ++++ apps/server/src/main.ts | 25 ++++ apps/server/src/open.ts | 23 ++++ apps/server/src/orchestration/Errors.ts | 4 - .../Layers/ProjectionSnapshotQuery.ts | 24 +--- .../Services/CheckpointReactor.ts | 17 +++ .../Services/OrchestrationEngine.ts | 8 ++ .../Services/OrchestrationReactor.ts | 14 ++ .../Services/ProjectionPipeline.ts | 35 +++-- .../Services/ProjectionSnapshotQuery.ts | 20 +++ .../Services/ProviderCommandReactor.ts | 17 +++ .../Services/ProviderRuntimeIngestion.ts | 17 +++ apps/server/src/persistence/Errors.ts | 121 +----------------- .../src/persistence/NodeSqliteClient.ts | 5 + .../Services/OrchestrationCommandReceipts.ts | 22 ++++ .../Services/OrchestrationEventStore.ts | 7 + .../Services/ProjectionCheckpoints.ts | 30 +++++ .../Services/ProjectionPendingApprovals.ts | 30 +++++ .../Services/ProjectionPendingTurnStarts.ts | 25 ++++ .../Services/ProjectionProjects.ts | 30 +++++ .../persistence/Services/ProjectionState.ts | 30 +++++ .../Services/ProjectionThreadActivities.ts | 27 ++++ .../Services/ProjectionThreadMessages.ts | 27 ++++ .../Services/ProjectionThreadSessions.ts | 25 ++++ .../Services/ProjectionThreadTurns.ts | 29 +++++ .../persistence/Services/ProjectionThreads.ts | 30 +++++ .../Services/ProviderSessionRuntime.ts | 29 +++++ .../persistence/Services/ProviderSessions.ts | 30 +++++ apps/server/src/provider/Errors.ts | 71 ---------- .../src/provider/Services/CodexAdapter.ts | 3 + .../Services/ProviderAdapterRegistry.ts | 3 + .../src/provider/Services/ProviderService.ts | 7 + .../Services/ProviderSessionDirectory.ts | 6 + apps/server/src/terminal/Services/Manager.ts | 52 ++++++++ apps/server/src/terminal/Services/PTY.ts | 17 +++ apps/server/src/wsServer.ts | 21 +++ 44 files changed, 765 insertions(+), 280 deletions(-) diff --git a/.plans/16c-pr89-remediation-checklist.md b/.plans/16c-pr89-remediation-checklist.md index eded5e72215f03306956a6b7948248c5378a1cce..c7273eb075896e90a0f3f90182d97d25a8d38e01 100644 --- a/.plans/16c-pr89-remediation-checklist.md +++ b/.plans/16c-pr89-remediation-checklist.md @@ -210,8 +210,8 @@ Counts: active `51` (`valid=33`, `partially-valid=18`), closed-invalid `6` - Threads: PRRT_kwDORLtfbc5wiLhQ - Audit note: Snapshot sequence can under-report due to extra projectors, but replay impact is lower now. -- [ ] `C033` Three error classes defined but never instantiated anywhere - - Status: `TODO` +- [x] `C033` Three error classes defined but never instantiated anywhere + - Status: `DONE` - Verdict: `partially-valid` - Severity: `Low` - Area: `Checkpointing correctness` @@ -219,8 +219,8 @@ Counts: active `51` (`valid=33`, `partially-valid=18`), closed-invalid `6` - Threads: PRRT_kwDORLtfbc5wlYgo - Audit note: Original claim overstated; some errors used, others appear unused. -- [ ] `C034` Redundant `CheckpointInvariantError` in `CheckpointServiceError` union type - - Status: `TODO` +- [x] `C034` Redundant `CheckpointInvariantError` in `CheckpointServiceError` union type + - Status: `DONE` - Verdict: `valid` - Severity: `Low` - Area: `Checkpointing correctness` @@ -228,8 +228,8 @@ Counts: active `51` (`valid=33`, `partially-valid=18`), closed-invalid `6` - Threads: PRRT_kwDORLtfbc5wj5fn - Audit note: CheckpointInvariantError remains redundantly included in service union. -- [ ] `C035` Redundant error type in CheckpointServiceError union definition - - Status: `TODO` +- [x] `C035` Redundant error type in CheckpointServiceError union definition + - Status: `DONE` - Verdict: `valid` - Severity: `Low` - Area: `Checkpointing correctness` diff --git a/apps/server/src/checkpointing/Errors.ts b/apps/server/src/checkpointing/Errors.ts index 0e0ecf1d0757fb63a867719f3ec2d4db2d73c443..782d0918e628dc5ccbfb59f7ab58fc0024419166 100644 --- a/apps/server/src/checkpointing/Errors.ts +++ b/apps/server/src/checkpointing/Errors.ts @@ -19,37 +19,6 @@ export class CheckpointUnavailableError extends Schema.TaggedErrorClass()( - "CheckpointRepositoryError", - { - cwd: Schema.String, - detail: Schema.String, - cause: Schema.optional(Schema.Defect), - }, -) { - override get message(): string { - return `Checkpoint repository error for ${this.cwd}: ${this.detail}`; - } -} - -/** - * CheckpointSessionNotFoundError - Session is missing in checkpoint workflow. - */ -export class CheckpointSessionNotFoundError extends Schema.TaggedErrorClass()( - "CheckpointSessionNotFoundError", - { - sessionId: Schema.String, - cause: Schema.optional(Schema.Defect), - }, -) { - override get message(): string { - return `Checkpoint session not found: ${this.sessionId}`; - } -} - /** * CheckpointInvariantError - Inconsistent provider/filesystem/catalog state. */ @@ -69,11 +38,6 @@ export class CheckpointInvariantError extends Schema.TaggedErrorClass Effect.Effect; + + /** + * Read the full patch diff across a thread range of checkpoints. + * + * Delegates to turn diff with `fromTurnCount = 0`. + */ readonly getFullThreadDiff: ( input: OrchestrationGetFullThreadDiffInput, ) => Effect.Effect; } +/** + * CheckpointDiffQuery - Service tag for checkpoint diff queries. + */ export class CheckpointDiffQuery extends ServiceMap.Service< CheckpointDiffQuery, CheckpointDiffQueryShape diff --git a/apps/server/src/checkpointing/Services/CheckpointStore.ts b/apps/server/src/checkpointing/Services/CheckpointStore.ts index c6f7c7c6c758aacfe32ea67115e9bbbdbc083a39..b004c87fda6552ac400650e67be789a84e9903c4 100644 --- a/apps/server/src/checkpointing/Services/CheckpointStore.ts +++ b/apps/server/src/checkpointing/Services/CheckpointStore.ts @@ -39,6 +39,9 @@ export interface DeleteCheckpointRefsInput { readonly checkpointRefs: ReadonlyArray; } +/** + * CheckpointStoreShape - Service API for checkpoint capture/restore and diff access. + */ export interface CheckpointStoreShape { /** * Check whether cwd is inside a Git worktree. @@ -47,6 +50,8 @@ export interface CheckpointStoreShape { /** * Capture a checkpoint commit and store it at the provided checkpoint ref. + * + * Uses an isolated temporary Git index and writes a hidden ref. */ readonly captureCheckpoint: ( input: CaptureCheckpointInput, @@ -61,6 +66,8 @@ export interface CheckpointStoreShape { /** * Restore workspace/staging state to a checkpoint. + * + * Optionally falls back to current `HEAD` when the checkpoint ref is missing. */ readonly restoreCheckpoint: ( input: RestoreCheckpointInput, @@ -68,6 +75,8 @@ export interface CheckpointStoreShape { /** * Compute patch diff between two checkpoint refs. + * + * Can optionally treat missing "from" ref as `HEAD`. */ readonly diffCheckpoints: ( input: DiffCheckpointsInput, @@ -75,6 +84,8 @@ export interface CheckpointStoreShape { /** * Delete the provided checkpoint refs. + * + * Best-effort delete: missing refs are tolerated. */ readonly deleteCheckpointRefs: ( input: DeleteCheckpointRefsInput, diff --git a/apps/server/src/config.ts b/apps/server/src/config.ts index ba523e3b52d141e090a1aca3c4dec70e3a2f9e65..1dc0573a62c5cb96fc5e056dabd660dceeb79069 100644 --- a/apps/server/src/config.ts +++ b/apps/server/src/config.ts @@ -1,3 +1,11 @@ +/** + * ServerConfig and NetService - Runtime configuration services. + * + * Defines process-level server configuration and networking helpers used by + * startup and runtime layers. + * + * @module ServerConfig + */ import * as Net from "node:net"; import { Data, Effect, FileSystem, Layer, Path, ServiceMap } from "effect"; @@ -5,6 +13,9 @@ export const DEFAULT_PORT = 3773; export type RuntimeMode = "web" | "desktop"; +/** + * ServerConfigShape - Process/runtime configuration required by the server. + */ export interface ServerConfigShape { readonly mode: RuntimeMode; readonly port: number; @@ -20,6 +31,9 @@ export interface ServerConfigShape { readonly logWebSocketEvents: boolean; } +/** + * ServerConfig - Service tag for server runtime configuration. + */ export class ServerConfig extends ServiceMap.Service()( "server/ServerConfig", ) {} @@ -31,10 +45,21 @@ export class NetError extends Data.TaggedError("NetError")<{ readonly cause?: unknown; }> {} +/** + * NetServiceShape - Networking helper operations used during startup. + */ export interface NetServiceShape { + /** + * Resolve an available listening port, preferring the provided port first. + * + * Falls back to an ephemeral OS-assigned port when the preferred port is in use. + */ readonly findAvailablePort: (preferred: number) => Effect.Effect; } +/** + * NetService - Service tag for startup networking helpers. + */ export class NetService extends ServiceMap.Service()( "server/NetService", ) { diff --git a/apps/server/src/git/Errors.ts b/apps/server/src/git/Errors.ts index 106c0ab45383e555bd35e1d2d3e0fa6854993d6a..15bf482f7bfe073b9037e8eed68fe7ec2c33ef60 100644 --- a/apps/server/src/git/Errors.ts +++ b/apps/server/src/git/Errors.ts @@ -57,26 +57,11 @@ export class GitManagerError extends Schema.TaggedErrorClass()( } } -/** - * GitCoreError - Errors emitted by low-level Git repository operations. - */ -export type GitCoreError = GitCommandError; - -/** - * GitHubCliServiceError - Errors emitted by GitHub CLI service helpers. - */ -export type GitHubCliServiceError = GitHubCliError; - -/** - * TextGenerationServiceError - Errors emitted by commit/PR text generation. - */ -export type TextGenerationServiceError = TextGenerationError; - /** * GitManagerServiceError - Errors emitted by stacked Git workflow orchestration. */ export type GitManagerServiceError = | GitManagerError - | GitCoreError - | GitHubCliServiceError - | TextGenerationServiceError; + | GitCommandError + | GitHubCliError + | TextGenerationError; diff --git a/apps/server/src/git/Services/GitService.ts b/apps/server/src/git/Services/GitService.ts index 185ec1d14552289daa2c812f1ba12289d564392b..9bd43f3cc86093c75dd57f37f5aacb89ec053f0d 100644 --- a/apps/server/src/git/Services/GitService.ts +++ b/apps/server/src/git/Services/GitService.ts @@ -27,6 +27,9 @@ export interface ExecuteGitResult { readonly stderr: string; } +/** + * GitServiceShape - Service API for Git command execution. + */ export interface GitServiceShape { /** * Execute a Git command. diff --git a/apps/server/src/keybindings.ts b/apps/server/src/keybindings.ts index b727017f1e638cc1cf79669cfbff56bdb93d110c..b433b05fd3fad19210ccdddc91832a804b94dc59 100644 --- a/apps/server/src/keybindings.ts +++ b/apps/server/src/keybindings.ts @@ -1,3 +1,11 @@ +/** + * Keybindings - Keybinding configuration service definitions. + * + * Owns parsing, validation, merge, and persistence of user keybinding + * configuration consumed by the server runtime. + * + * @module Keybindings + */ import { KeybindingRule, KeybindingsConfig, @@ -388,16 +396,34 @@ function mergeWithDefaultKeybindings(custom: ResolvedKeybindingsConfig): Resolve return merged.slice(-MAX_KEYBINDINGS_COUNT); } +/** + * KeybindingsShape - Service API for keybinding configuration operations. + */ export interface KeybindingsShape { + /** + * Load and resolve keybindings from disk merged with defaults. + * + * Returns an in-memory cached result after the first successful load. + */ readonly loadResolvedKeybindingsConfig: Effect.Effect< readonly ResolvedKeybindingRule[], KeybindingsConfigError >; + + /** + * Upsert a keybinding rule and persist the resulting configuration. + * + * Writes config atomically and enforces the max rule count by truncating + * oldest entries when needed. + */ readonly upsertKeybindingRule: ( rule: KeybindingRule, ) => Effect.Effect; } +/** + * Keybindings - Service tag for keybinding configuration operations. + */ export class Keybindings extends ServiceMap.Service()( "server/Keybindings", ) {} diff --git a/apps/server/src/main.ts b/apps/server/src/main.ts index 0358959352b70c6055b90f14ffc69282dfeb06a2..97d237d51dcd8b2b868ee5379e5b0f7e93976e45 100644 --- a/apps/server/src/main.ts +++ b/apps/server/src/main.ts @@ -1,3 +1,11 @@ +/** + * CliConfig - CLI/runtime bootstrap service definitions. + * + * Defines startup-only service contracts used while resolving process config + * and constructing server runtime layers. + * + * @module CliConfig + */ import { Config, Data, Effect, FileSystem, Layer, Option, Path, Schema, ServiceMap } from "effect"; import { Command, Flag } from "effect/unstable/cli"; @@ -32,12 +40,29 @@ interface CliInput { readonly logWebSocketEvents: Option.Option; } +/** + * CliConfigShape - Startup helpers required while building server layers. + */ export interface CliConfigShape { + /** + * Current process working directory. + */ readonly cwd: string; + + /** + * Apply OS-specific PATH normalization. + */ readonly fixPath: Effect.Effect; + + /** + * Resolve static web asset directory for server mode. + */ readonly resolveStaticDir: Effect.Effect; } +/** + * CliConfig - Service tag for startup CLI/runtime helpers. + */ export class CliConfig extends ServiceMap.Service()("server/CliConfig") { static readonly layer = Layer.effect( CliConfig, diff --git a/apps/server/src/open.ts b/apps/server/src/open.ts index d88f519f8fcf6f289b30ec921506a5ae7dc81576..dbfadbfce9ad78014eb566aa36a004b47eb1bfe8 100644 --- a/apps/server/src/open.ts +++ b/apps/server/src/open.ts @@ -1,3 +1,11 @@ +/** + * Open - Browser/editor launch service interface. + * + * Owns process launch helpers for opening URLs in a browser and workspace + * paths in a configured editor. + * + * @module Open + */ import { spawn } from "node:child_process"; import { EDITORS, type EditorId } from "@t3tools/contracts"; @@ -22,11 +30,26 @@ interface EditorLaunch { readonly args: ReadonlyArray; } +/** + * OpenShape - Service API for browser and editor launch actions. + */ export interface OpenShape { + /** + * Open a URL target in the default browser. + */ readonly openBrowser: (target: string) => Effect.Effect; + + /** + * Open a workspace path in a selected editor integration. + * + * Launches the editor as a detached process so server startup is not blocked. + */ readonly openInEditor: (input: OpenInEditorInput) => Effect.Effect; } +/** + * Open - Service tag for browser/editor launch operations. + */ export class Open extends ServiceMap.Service()("server/Open") {} // ============================== diff --git a/apps/server/src/orchestration/Errors.ts b/apps/server/src/orchestration/Errors.ts index 81e83751be59fb1d1b8a9488bf514021cf070e23..5882ead3e8e069b9bf953881f4026cedf9834677 100644 --- a/apps/server/src/orchestration/Errors.ts +++ b/apps/server/src/orchestration/Errors.ts @@ -1,8 +1,6 @@ import { SchemaIssue, Schema } from "effect"; import type { - OrchestrationCommandReceiptRepositoryError, - OrchestrationEventStoreError, ProjectionRepositoryError, } from "../persistence/Errors.ts"; @@ -83,8 +81,6 @@ export class OrchestrationListenerCallbackError extends Schema.TaggedErrorClass< } export type OrchestrationDispatchError = - | OrchestrationEventStoreError - | OrchestrationCommandReceiptRepositoryError | ProjectionRepositoryError | OrchestrationCommandInvariantError | OrchestrationCommandPreviouslyRejectedError diff --git a/apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts b/apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts index dfaa8c008e37b2e2a8904d2381dc31d976981bda..2c2b77001bb490fb067dd5d11018ffd9701dd199 100644 --- a/apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts +++ b/apps/server/src/orchestration/Layers/ProjectionSnapshotQuery.ts @@ -14,9 +14,7 @@ import * as SqlClient from "effect/unstable/sql/SqlClient"; import * as SqlSchema from "effect/unstable/sql/SqlSchema"; import { - PersistenceDecodeError, - PersistenceSerializationError, - PersistenceSqlError, + isPersistenceError, toPersistenceDecodeError, toPersistenceSqlError, type ProjectionRepositoryError, @@ -106,19 +104,6 @@ function toPersistenceSqlOrDecodeError(sqlOperation: string, decodeOperation: st : toPersistenceSqlError(sqlOperation)(cause); } -function toProjectionRepositoryError(operation: string) { - return (cause: unknown): ProjectionRepositoryError => { - if ( - cause instanceof PersistenceSqlError || - cause instanceof PersistenceDecodeError || - cause instanceof PersistenceSerializationError - ) { - return cause; - } - return toPersistenceSqlError(operation)(cause); - }; -} - const makeProjectionSnapshotQuery = Effect.gen(function* () { const sql = yield* SqlClient.SqlClient; @@ -441,7 +426,12 @@ const makeProjectionSnapshotQuery = Effect.gen(function* () { }), ) .pipe( - Effect.mapError(toProjectionRepositoryError("ProjectionSnapshotQuery.getSnapshot:query")), + Effect.mapError((error) => { + if (isPersistenceError(error)) { + return error; + } + return toPersistenceSqlError("ProjectionSnapshotQuery.getSnapshot:query")(error); + }), ); return { diff --git a/apps/server/src/orchestration/Services/CheckpointReactor.ts b/apps/server/src/orchestration/Services/CheckpointReactor.ts index 330b800b13aaf1f389bfab6d9d2097b3c59dc204..3e4688b89909e66d82337f024cd4e46cc5dee455 100644 --- a/apps/server/src/orchestration/Services/CheckpointReactor.ts +++ b/apps/server/src/orchestration/Services/CheckpointReactor.ts @@ -1,16 +1,33 @@ +/** + * CheckpointReactor - Checkpoint reaction service interface. + * + * Owns background workers that react to orchestration checkpoint lifecycle + * events and apply checkpoint side effects. + * + * @module CheckpointReactor + */ import { ServiceMap } from "effect"; import type { Effect, Scope } from "effect"; +/** + * CheckpointReactorShape - Service API for checkpoint reactor lifecycle. + */ export interface CheckpointReactorShape { /** * Start the checkpoint reactor. * * The returned effect must be run in a scope so all worker fibers can be * finalized on shutdown. + * + * Consumes both orchestration-domain and provider-runtime events via an + * internal queue. */ readonly start: Effect.Effect; } +/** + * CheckpointReactor - Service tag for checkpoint reactor workers. + */ export class CheckpointReactor extends ServiceMap.Service< CheckpointReactor, CheckpointReactorShape diff --git a/apps/server/src/orchestration/Services/OrchestrationEngine.ts b/apps/server/src/orchestration/Services/OrchestrationEngine.ts index ed2bf6a35fe20ceafcdeef50a54f2a877beb9f19..4907860cb670d8fb06df0ef2ead2ac2812955c2c 100644 --- a/apps/server/src/orchestration/Services/OrchestrationEngine.ts +++ b/apps/server/src/orchestration/Services/OrchestrationEngine.ts @@ -21,6 +21,9 @@ import type { Effect, Stream } from "effect"; import type { OrchestrationDispatchError } from "../Errors.ts"; import type { OrchestrationEventStoreError } from "../../persistence/Errors.ts"; +/** + * OrchestrationEngineShape - Service API for orchestration command and event flow. + */ export interface OrchestrationEngineShape { /** * Read the current in-memory orchestration read model. @@ -44,6 +47,9 @@ export interface OrchestrationEngineShape { * * @param command - Valid orchestration command. * @returns Effect containing the sequence of the persisted event. + * + * Dispatch is serialized through an internal queue and deduplicated via + * command receipts. */ readonly dispatch: ( command: OrchestrationCommand, @@ -51,6 +57,8 @@ export interface OrchestrationEngineShape { /** * Stream persisted domain events in dispatch order. + * + * This is a hot runtime stream (new events only), not a historical replay. */ readonly streamDomainEvents: Stream.Stream; } diff --git a/apps/server/src/orchestration/Services/OrchestrationReactor.ts b/apps/server/src/orchestration/Services/OrchestrationReactor.ts index 185750fb25beb53d608375fdeb39775fc71b8253..384da07b2018769f3050ef250dd049c250ea4698 100644 --- a/apps/server/src/orchestration/Services/OrchestrationReactor.ts +++ b/apps/server/src/orchestration/Services/OrchestrationReactor.ts @@ -1,6 +1,17 @@ +/** + * OrchestrationReactor - Composite orchestration reactor service interface. + * + * Coordinates startup of orchestration runtime reactors that translate domain + * events into downstream side effects. + * + * @module OrchestrationReactor + */ import { ServiceMap } from "effect"; import type { Effect, Scope } from "effect"; +/** + * OrchestrationReactorShape - Service API for orchestration reactor lifecycle. + */ export interface OrchestrationReactorShape { /** * Start orchestration-side reactors for provider/runtime/checkpoint flows. @@ -11,6 +22,9 @@ export interface OrchestrationReactorShape { readonly start: Effect.Effect; } +/** + * OrchestrationReactor - Service tag for orchestration reactor coordination. + */ export class OrchestrationReactor extends ServiceMap.Service< OrchestrationReactor, OrchestrationReactorShape diff --git a/apps/server/src/orchestration/Services/ProjectionPipeline.ts b/apps/server/src/orchestration/Services/ProjectionPipeline.ts index 9457aaf8d9b3cf684a76da26e8dd43cb70f97ad1..370409a9d42e68e0d505f2b560c52c9f0b994ca5 100644 --- a/apps/server/src/orchestration/Services/ProjectionPipeline.ts +++ b/apps/server/src/orchestration/Services/ProjectionPipeline.ts @@ -1,24 +1,41 @@ +/** + * OrchestrationProjectionPipeline - Event projection pipeline service interface. + * + * Coordinates projection bootstrap/replay and per-event projection updates for + * orchestration read models. + * + * @module OrchestrationProjectionPipeline + */ import type { OrchestrationEvent } from "@t3tools/contracts"; import { ServiceMap } from "effect"; import type { Effect } from "effect"; -import type { - OrchestrationEventStoreError, - ProjectionRepositoryError, -} from "../../persistence/Errors.ts"; - -export type OrchestrationProjectionPipelineError = - | OrchestrationEventStoreError - | ProjectionRepositoryError; +import type { ProjectionRepositoryError } from "../../persistence/Errors.ts"; +/** + * OrchestrationProjectionPipelineShape - Service API for projection execution. + */ export interface OrchestrationProjectionPipelineShape { - readonly bootstrap: Effect.Effect; + /** + * Bootstrap projections by replaying persisted events. + * + * Resumes each projector from its stored projection-state cursor. + */ + readonly bootstrap: Effect.Effect; + /** + * Project a single orchestration event into projection repositories. + * + * Projectors are executed sequentially to preserve deterministic ordering. + */ readonly projectEvent: ( event: OrchestrationEvent, ) => Effect.Effect; } +/** + * OrchestrationProjectionPipeline - Service tag for orchestration projections. + */ export class OrchestrationProjectionPipeline extends ServiceMap.Service< OrchestrationProjectionPipeline, OrchestrationProjectionPipelineShape diff --git a/apps/server/src/orchestration/Services/ProjectionSnapshotQuery.ts b/apps/server/src/orchestration/Services/ProjectionSnapshotQuery.ts index 66e27a3fe426a3d2a78cb959816664818d2042a8..bd8d57cf548204cb2425a3bcef356116a0849bc3 100644 --- a/apps/server/src/orchestration/Services/ProjectionSnapshotQuery.ts +++ b/apps/server/src/orchestration/Services/ProjectionSnapshotQuery.ts @@ -1,13 +1,33 @@ +/** + * ProjectionSnapshotQuery - Read-model snapshot query service interface. + * + * Exposes the current orchestration projection snapshot for read-only API + * access. + * + * @module ProjectionSnapshotQuery + */ import type { OrchestrationReadModel } from "@t3tools/contracts"; import { ServiceMap } from "effect"; import type { Effect } from "effect"; import type { ProjectionRepositoryError } from "../../persistence/Errors.ts"; +/** + * ProjectionSnapshotQueryShape - Service API for read-model snapshots. + */ export interface ProjectionSnapshotQueryShape { + /** + * Read the latest orchestration projection snapshot. + * + * Rehydrates from projection tables and derives snapshot sequence from + * projector cursor state. + */ readonly getSnapshot: () => Effect.Effect; } +/** + * ProjectionSnapshotQuery - Service tag for projection snapshot queries. + */ export class ProjectionSnapshotQuery extends ServiceMap.Service< ProjectionSnapshotQuery, ProjectionSnapshotQueryShape diff --git a/apps/server/src/orchestration/Services/ProviderCommandReactor.ts b/apps/server/src/orchestration/Services/ProviderCommandReactor.ts index 1069137abc654dca5df1334ea2aa7dbbe84da9c2..7007e8e0fa9cd89eb6f395f20186453c2a52c150 100644 --- a/apps/server/src/orchestration/Services/ProviderCommandReactor.ts +++ b/apps/server/src/orchestration/Services/ProviderCommandReactor.ts @@ -1,16 +1,33 @@ +/** + * ProviderCommandReactor - Provider command reaction service interface. + * + * Owns background workers that react to orchestration intent events and + * dispatch provider-side command execution. + * + * @module ProviderCommandReactor + */ import { ServiceMap } from "effect"; import type { Effect, Scope } from "effect"; +/** + * ProviderCommandReactorShape - Service API for provider command reactors. + */ export interface ProviderCommandReactorShape { /** * Start reacting to provider-intent orchestration domain events. * * The returned effect must be run in a scope so all worker fibers can be * finalized on shutdown. + * + * Filters orchestration domain events to provider-intent types before + * processing. */ readonly start: Effect.Effect; } +/** + * ProviderCommandReactor - Service tag for provider command reaction workers. + */ export class ProviderCommandReactor extends ServiceMap.Service< ProviderCommandReactor, ProviderCommandReactorShape diff --git a/apps/server/src/orchestration/Services/ProviderRuntimeIngestion.ts b/apps/server/src/orchestration/Services/ProviderRuntimeIngestion.ts index ba45bac8578ab272051ca87501633037ef707544..13574acf90712ddcba3f06172e3d54a4d7e07b2e 100644 --- a/apps/server/src/orchestration/Services/ProviderRuntimeIngestion.ts +++ b/apps/server/src/orchestration/Services/ProviderRuntimeIngestion.ts @@ -1,16 +1,33 @@ +/** + * ProviderRuntimeIngestionService - Provider runtime ingestion service interface. + * + * Owns background workers that consume provider runtime streams and emit + * orchestration commands/events. + * + * @module ProviderRuntimeIngestionService + */ import { ServiceMap } from "effect"; import type { Effect, Scope } from "effect"; +/** + * ProviderRuntimeIngestionShape - Service API for runtime ingestion lifecycle. + */ export interface ProviderRuntimeIngestionShape { /** * Start ingesting provider runtime events into orchestration commands. * * The returned effect must be run in a scope so all worker fibers can be * finalized on shutdown. + * + * Uses an internal queue and continues after non-interrupt failures by + * logging warnings. */ readonly start: Effect.Effect; } +/** + * ProviderRuntimeIngestionService - Service tag for runtime ingestion workers. + */ export class ProviderRuntimeIngestionService extends ServiceMap.Service< ProviderRuntimeIngestionService, ProviderRuntimeIngestionShape diff --git a/apps/server/src/persistence/Errors.ts b/apps/server/src/persistence/Errors.ts index a2b3b57c2ac6184900b7a6066488fe4211e00d57..cb1cb2f3f87d711111d80c83371aa4e8790b5bd6 100644 --- a/apps/server/src/persistence/Errors.ts +++ b/apps/server/src/persistence/Errors.ts @@ -30,19 +30,6 @@ export class PersistenceDecodeError extends Schema.TaggedErrorClass()( - "PersistenceSerializationError", - { - operation: Schema.String, - detail: Schema.String, - cause: Schema.optional(Schema.Defect), - }, -) { - override get message(): string { - return `Serialization error in ${this.operation}: ${this.detail}`; - } -} - export function toPersistenceSqlError(operation: string) { return (cause: unknown): PersistenceSqlError => new PersistenceSqlError({ @@ -70,85 +57,8 @@ export function toPersistenceDecodeCauseError(operation: string) { }); } -export function toPersistenceSerializationError(operation: string) { - return (cause: unknown): PersistenceSerializationError => - new PersistenceSerializationError({ - operation, - detail: `Failed to execute ${operation}`, - cause, - }); -} - -// =============================== -// Project Repository Errors -// =============================== - -export class ProjectValidationError extends Schema.TaggedErrorClass()( - "ProjectValidationError", - { - operation: Schema.String, - issue: Schema.String, - cause: Schema.optional(Schema.Defect), - }, -) { - override get message(): string { - return `Project validation failed in ${this.operation}: ${this.issue}`; - } -} - -export class ProjectPathMissingError extends Schema.TaggedErrorClass()( - "ProjectPathMissingError", - { - cwd: Schema.String, - cause: Schema.optional(Schema.Defect), - }, -) { - override get message(): string { - return `Project path does not exist: ${this.cwd}`; - } -} - -export class ProjectNotFoundError extends Schema.TaggedErrorClass()( - "ProjectNotFoundError", - { - projectId: Schema.String, - cause: Schema.optional(Schema.Defect), - }, -) { - override get message(): string { - return `Project not found: ${this.projectId}`; - } -} - -// =============================== -// Checkpoint Repository Errors -// =============================== - -export class CheckpointRepositoryValidationError extends Schema.TaggedErrorClass()( - "CheckpointRepositoryValidationError", - { - operation: Schema.String, - issue: Schema.String, - cause: Schema.optional(Schema.Defect), - }, -) { - override get message(): string { - return `Checkpoint repository validation failed in ${this.operation}: ${this.issue}`; - } -} - -export class CheckpointRepositoryPersistenceError extends Schema.TaggedErrorClass()( - "CheckpointRepositoryPersistenceError", - { - operation: Schema.String, - detail: Schema.String, - cause: Schema.optional(Schema.Defect), - }, -) { - override get message(): string { - return `Checkpoint repository persistence error in ${this.operation}: ${this.detail}`; - } -} +export const isPersistenceError = (u: unknown) => + Schema.is(PersistenceSqlError)(u) || Schema.is(PersistenceDecodeError)(u); // =============================== // Provider Session Repository Errors @@ -180,22 +90,7 @@ export class ProviderSessionRepositoryPersistenceError extends Schema.TaggedErro } } -export type ProjectRepositoryError = - | PersistenceSqlError - | PersistenceDecodeError - | PersistenceSerializationError - | ProjectValidationError - | ProjectPathMissingError - | ProjectNotFoundError; - -export type OrchestrationEventStoreError = - | PersistenceSqlError - | PersistenceDecodeError - | PersistenceSerializationError; - -export type CheckpointRepositoryError = - | CheckpointRepositoryValidationError - | CheckpointRepositoryPersistenceError; +export type OrchestrationEventStoreError = PersistenceSqlError | PersistenceDecodeError; export type ProviderSessionRepositoryError = | ProviderSessionRepositoryValidationError @@ -205,12 +100,6 @@ export type OrchestrationCommandReceiptRepositoryError = | PersistenceSqlError | PersistenceDecodeError; -export type ProviderSessionRuntimeRepositoryError = - | PersistenceSqlError - | PersistenceDecodeError - | PersistenceSerializationError; +export type ProviderSessionRuntimeRepositoryError = PersistenceSqlError | PersistenceDecodeError; -export type ProjectionRepositoryError = - | PersistenceSqlError - | PersistenceDecodeError - | PersistenceSerializationError; +export type ProjectionRepositoryError = PersistenceSqlError | PersistenceDecodeError; diff --git a/apps/server/src/persistence/NodeSqliteClient.ts b/apps/server/src/persistence/NodeSqliteClient.ts index cdfcee4e986329b31c2aa8e06b4b42e94f8b2da6..cfbcb8b9c50071278989636b1120a538144a1dcb 100644 --- a/apps/server/src/persistence/NodeSqliteClient.ts +++ b/apps/server/src/persistence/NodeSqliteClient.ts @@ -1,6 +1,8 @@ /** * Port of `@effect/sql-sqlite-node` that uses the native `node:sqlite` * bindings instead of `better-sqlite3`. + * + * @module SqliteClient */ import { DatabaseSync, type StatementSync } from "node:sqlite"; @@ -27,6 +29,9 @@ export const TypeId: TypeId = "~local/sqlite-node/SqliteClient"; export type TypeId = "~local/sqlite-node/SqliteClient"; +/** + * SqliteClient - Effect service tag for the sqlite SQL client. + */ export const SqliteClient = ServiceMap.Service("@local/sqlite-node/SqliteClient"); export interface SqliteClientConfig { diff --git a/apps/server/src/persistence/Services/OrchestrationCommandReceipts.ts b/apps/server/src/persistence/Services/OrchestrationCommandReceipts.ts index 95fbbf493495646b32e2342c4e59c4e612ca145f..c1ec79c9fb760a49948db303c1438ee95767f157 100644 --- a/apps/server/src/persistence/Services/OrchestrationCommandReceipts.ts +++ b/apps/server/src/persistence/Services/OrchestrationCommandReceipts.ts @@ -1,3 +1,11 @@ +/** + * OrchestrationCommandReceiptRepository - Repository interface for command receipts. + * + * Owns persistence operations for deduplication and status tracking of + * orchestration command handling. + * + * @module OrchestrationCommandReceiptRepository + */ import { CommandId, IsoDateTime, @@ -28,11 +36,22 @@ export const GetByCommandIdInput = Schema.Struct({ }); export type GetByCommandIdInput = typeof GetByCommandIdInput.Type; +/** + * OrchestrationCommandReceiptRepositoryShape - Service API for command receipts. + */ export interface OrchestrationCommandReceiptRepositoryShape { + /** + * Insert or replace a command receipt row. + * + * Upserts by `commandId` for idempotent command-result tracking. + */ readonly upsert: ( receipt: OrchestrationCommandReceipt, ) => Effect.Effect; + /** + * Read a command receipt by command id. + */ readonly getByCommandId: ( input: GetByCommandIdInput, ) => Effect.Effect< @@ -41,6 +60,9 @@ export interface OrchestrationCommandReceiptRepositoryShape { >; } +/** + * OrchestrationCommandReceiptRepository - Service tag for command receipt persistence. + */ export class OrchestrationCommandReceiptRepository extends ServiceMap.Service< OrchestrationCommandReceiptRepository, OrchestrationCommandReceiptRepositoryShape diff --git a/apps/server/src/persistence/Services/OrchestrationEventStore.ts b/apps/server/src/persistence/Services/OrchestrationEventStore.ts index 2ee8e8486ab6602338e188d0f1f3cb029bb4a1ef..6a557c03790328174f9f04f3478ae31a5bb2da98 100644 --- a/apps/server/src/persistence/Services/OrchestrationEventStore.ts +++ b/apps/server/src/persistence/Services/OrchestrationEventStore.ts @@ -15,12 +15,17 @@ import type { Effect, Stream } from "effect"; import type { OrchestrationEventStoreError } from "../Errors.ts"; +/** + * OrchestrationEventStoreShape - Service API for orchestration event persistence. + */ export interface OrchestrationEventStoreShape { /** * Persist a new orchestration event. * * @param event - Event payload without sequence (assigned by storage). * @returns Effect containing the stored event with assigned sequence. + * + * Actor kind is inferred from command/metadata before persistence. */ readonly append: ( event: Omit, @@ -32,6 +37,8 @@ export interface OrchestrationEventStoreShape { * @param sequenceExclusive - Sequence cursor (exclusive). * @param limit - Maximum number of events to emit. * @returns Stream containing ordered events. + * + * Reads in fixed-size pages and normalizes non-integer/negative limits. */ readonly readFromSequence: ( sequenceExclusive: number, diff --git a/apps/server/src/persistence/Services/ProjectionCheckpoints.ts b/apps/server/src/persistence/Services/ProjectionCheckpoints.ts index cc5a93eb847b7f53a8848c14a418fdf52fe5d3d8..d10c86d816d50f3069b7262944f8b417b8853186 100644 --- a/apps/server/src/persistence/Services/ProjectionCheckpoints.ts +++ b/apps/server/src/persistence/Services/ProjectionCheckpoints.ts @@ -1,3 +1,11 @@ +/** + * ProjectionCheckpointRepository - Projection repository interface for checkpoints. + * + * Owns persistence operations for projected checkpoint summaries in thread + * timelines. + * + * @module ProjectionCheckpointRepository + */ import { CheckpointRef, IsoDateTime, @@ -41,22 +49,44 @@ export const DeleteByThreadIdInput = Schema.Struct({ }); export type DeleteByThreadIdInput = typeof DeleteByThreadIdInput.Type; +/** + * ProjectionCheckpointRepositoryShape - Service API for projected checkpoints. + */ export interface ProjectionCheckpointRepositoryShape { + /** + * Insert or replace a projected checkpoint row. + * + * Upserts by composite key `(threadId, checkpointTurnCount)`. + */ readonly upsert: (row: ProjectionCheckpoint) => Effect.Effect; + /** + * List projected checkpoints for a thread. + * + * Returned in ascending checkpoint turn-count order. + */ readonly listByThreadId: ( input: ListByThreadIdInput, ) => Effect.Effect, ProjectionRepositoryError>; + /** + * Read a projected checkpoint by thread and turn-count key. + */ readonly getByThreadAndTurnCount: ( input: GetByThreadAndTurnCountInput, ) => Effect.Effect, ProjectionRepositoryError>; + /** + * Delete projected checkpoint rows by thread. + */ readonly deleteByThreadId: ( input: DeleteByThreadIdInput, ) => Effect.Effect; } +/** + * ProjectionCheckpointRepository - Service tag for checkpoint projection persistence. + */ export class ProjectionCheckpointRepository extends ServiceMap.Service< ProjectionCheckpointRepository, ProjectionCheckpointRepositoryShape diff --git a/apps/server/src/persistence/Services/ProjectionPendingApprovals.ts b/apps/server/src/persistence/Services/ProjectionPendingApprovals.ts index 1d4083625d9177727734ff8e87f206b26ecb513e..8e0d3736be910aa87ad182dff231df56e2a4de2e 100644 --- a/apps/server/src/persistence/Services/ProjectionPendingApprovals.ts +++ b/apps/server/src/persistence/Services/ProjectionPendingApprovals.ts @@ -1,3 +1,11 @@ +/** + * ProjectionPendingApprovalRepository - Repository interface for pending approvals. + * + * Owns persistence operations for projected approval requests awaiting user + * decisions. + * + * @module ProjectionPendingApprovalRepository + */ import { ApprovalRequestId, IsoDateTime, @@ -37,24 +45,46 @@ export const DeleteProjectionPendingApprovalInput = Schema.Struct({ }); export type DeleteProjectionPendingApprovalInput = typeof DeleteProjectionPendingApprovalInput.Type; +/** + * ProjectionPendingApprovalRepositoryShape - Service API for pending approvals. + */ export interface ProjectionPendingApprovalRepositoryShape { + /** + * Insert or replace a projected pending approval row. + * + * Upserts by `requestId`. + */ readonly upsert: ( row: ProjectionPendingApproval, ) => Effect.Effect; + /** + * List pending approvals for a thread. + * + * Returned in ascending creation order. + */ readonly listByThreadId: ( input: ListProjectionPendingApprovalsInput, ) => Effect.Effect, ProjectionRepositoryError>; + /** + * Read a pending approval row by request id. + */ readonly getByRequestId: ( input: GetProjectionPendingApprovalInput, ) => Effect.Effect, ProjectionRepositoryError>; + /** + * Delete a pending approval row by request id. + */ readonly deleteByRequestId: ( input: DeleteProjectionPendingApprovalInput, ) => Effect.Effect; } +/** + * ProjectionPendingApprovalRepository - Service tag for pending approval persistence. + */ export class ProjectionPendingApprovalRepository extends ServiceMap.Service< ProjectionPendingApprovalRepository, ProjectionPendingApprovalRepositoryShape diff --git a/apps/server/src/persistence/Services/ProjectionPendingTurnStarts.ts b/apps/server/src/persistence/Services/ProjectionPendingTurnStarts.ts index 58c2572fe2cb0c37af10590938fe53b1ab06f1b7..6b6f9a065897aed76239ee8feee7e835701d4ccc 100644 --- a/apps/server/src/persistence/Services/ProjectionPendingTurnStarts.ts +++ b/apps/server/src/persistence/Services/ProjectionPendingTurnStarts.ts @@ -1,3 +1,11 @@ +/** + * ProjectionPendingTurnStartRepository - Repository interface for pending turn starts. + * + * Owns persistence operations for projected "pending turn start" markers used + * while creating new turns from queued messages. + * + * @module ProjectionPendingTurnStartRepository + */ import { IsoDateTime, MessageId, ThreadId } from "@t3tools/contracts"; import { Option, Schema, ServiceMap } from "effect"; import type { Effect } from "effect"; @@ -21,20 +29,37 @@ export const DeleteProjectionPendingTurnStartInput = Schema.Struct({ }); export type DeleteProjectionPendingTurnStartInput = typeof DeleteProjectionPendingTurnStartInput.Type; +/** + * ProjectionPendingTurnStartRepositoryShape - Service API for pending turn-start markers. + */ export interface ProjectionPendingTurnStartRepositoryShape { + /** + * Insert or replace a pending turn-start row. + * + * Maintains at most one pending marker per thread. + */ readonly upsert: ( row: ProjectionPendingTurnStart, ) => Effect.Effect; + /** + * Read a pending turn-start marker by thread id. + */ readonly getByThreadId: ( input: GetProjectionPendingTurnStartInput, ) => Effect.Effect, ProjectionRepositoryError>; + /** + * Delete a pending turn-start marker by thread id. + */ readonly deleteByThreadId: ( input: DeleteProjectionPendingTurnStartInput, ) => Effect.Effect; } +/** + * ProjectionPendingTurnStartRepository - Service tag for pending turn-start persistence. + */ export class ProjectionPendingTurnStartRepository extends ServiceMap.Service< ProjectionPendingTurnStartRepository, ProjectionPendingTurnStartRepositoryShape diff --git a/apps/server/src/persistence/Services/ProjectionProjects.ts b/apps/server/src/persistence/Services/ProjectionProjects.ts index bb51dc1c034b8a635ef4e3733525554b9b4e6d4e..c3fcea002be1e4938715b1f724e9dc8511922abe 100644 --- a/apps/server/src/persistence/Services/ProjectionProjects.ts +++ b/apps/server/src/persistence/Services/ProjectionProjects.ts @@ -1,3 +1,11 @@ +/** + * ProjectionProjectRepository - Projection repository interface for projects. + * + * Owns persistence operations for project rows in the orchestration projection + * read model. + * + * @module ProjectionProjectRepository + */ import { IsoDateTime, ProjectId, ProjectScript } from "@t3tools/contracts"; import { Option, Schema, ServiceMap } from "effect"; import type { Effect } from "effect"; @@ -26,23 +34,45 @@ export const DeleteProjectionProjectInput = Schema.Struct({ }); export type DeleteProjectionProjectInput = typeof DeleteProjectionProjectInput.Type; +/** + * ProjectionProjectRepositoryShape - Service API for projected project records. + */ export interface ProjectionProjectRepositoryShape { + /** + * Insert or replace a projected project row. + * + * Upserts by `projectId` and persists scripts through JSON encoding. + */ readonly upsert: (row: ProjectionProject) => Effect.Effect; + /** + * Read a projected project row by id. + */ readonly getById: ( input: GetProjectionProjectInput, ) => Effect.Effect, ProjectionRepositoryError>; + /** + * List all projected project rows. + * + * Returned in deterministic creation order. + */ readonly listAll: () => Effect.Effect< ReadonlyArray, ProjectionRepositoryError >; + /** + * Soft-delete a projected project row by id. + */ readonly deleteById: ( input: DeleteProjectionProjectInput, ) => Effect.Effect; } +/** + * ProjectionProjectRepository - Service tag for project projection persistence. + */ export class ProjectionProjectRepository extends ServiceMap.Service< ProjectionProjectRepository, ProjectionProjectRepositoryShape diff --git a/apps/server/src/persistence/Services/ProjectionState.ts b/apps/server/src/persistence/Services/ProjectionState.ts index c079f941b525e3408c9ee0f1f4a171b248a73948..7e3a2f6b9220581369f726aef2a07f19cad2c424 100644 --- a/apps/server/src/persistence/Services/ProjectionState.ts +++ b/apps/server/src/persistence/Services/ProjectionState.ts @@ -1,3 +1,11 @@ +/** + * ProjectionStateRepository - Projection repository interface for projector cursors. + * + * Owns persistence operations for projection cursor state used to resume + * incremental event projection. + * + * @module ProjectionStateRepository + */ import { IsoDateTime, NonNegativeInt } from "@t3tools/contracts"; import { Option, Schema, ServiceMap } from "effect"; import type { Effect } from "effect"; @@ -16,18 +24,40 @@ export const GetProjectionStateInput = Schema.Struct({ }); export type GetProjectionStateInput = typeof GetProjectionStateInput.Type; +/** + * ProjectionStateRepositoryShape - Service API for projector state records. + */ export interface ProjectionStateRepositoryShape { + /** + * Insert or replace a projection cursor row. + * + * Upserts by projector name. + */ readonly upsert: (row: ProjectionState) => Effect.Effect; + /** + * Read projection cursor state for a projector key. + */ readonly getByProjector: ( input: GetProjectionStateInput, ) => Effect.Effect, ProjectionRepositoryError>; + /** + * List all projector cursor rows. + */ readonly listAll: () => Effect.Effect, ProjectionRepositoryError>; + /** + * Read the minimum applied sequence across all projectors. + * + * Returns `null` when no projector state rows exist. + */ readonly minLastAppliedSequence: () => Effect.Effect; } +/** + * ProjectionStateRepository - Service tag for projection cursor persistence. + */ export class ProjectionStateRepository extends ServiceMap.Service< ProjectionStateRepository, ProjectionStateRepositoryShape diff --git a/apps/server/src/persistence/Services/ProjectionThreadActivities.ts b/apps/server/src/persistence/Services/ProjectionThreadActivities.ts index 3284805c92082142f914ec740986fe1814c97481..2e5d67909c51181060b6815ff40009f7be359be8 100644 --- a/apps/server/src/persistence/Services/ProjectionThreadActivities.ts +++ b/apps/server/src/persistence/Services/ProjectionThreadActivities.ts @@ -1,3 +1,11 @@ +/** + * ProjectionThreadActivityRepository - Projection repository interface for thread activity. + * + * Owns persistence operations for activity timeline entries projected from + * orchestration events. + * + * @module ProjectionThreadActivityRepository + */ import { EventId, IsoDateTime, @@ -33,20 +41,39 @@ export const DeleteProjectionThreadActivitiesInput = Schema.Struct({ export type DeleteProjectionThreadActivitiesInput = typeof DeleteProjectionThreadActivitiesInput.Type; +/** + * ProjectionThreadActivityRepositoryShape - Service API for projected thread activity. + */ export interface ProjectionThreadActivityRepositoryShape { + /** + * Insert or replace a projected thread activity row. + * + * Upserts by `activityId` and JSON-encodes payload. + */ readonly upsert: ( row: ProjectionThreadActivity, ) => Effect.Effect; + /** + * List projected thread activity rows for a thread. + * + * Returned in ascending creation order. + */ readonly listByThreadId: ( input: ListProjectionThreadActivitiesInput, ) => Effect.Effect, ProjectionRepositoryError>; + /** + * Delete projected thread activity rows by thread. + */ readonly deleteByThreadId: ( input: DeleteProjectionThreadActivitiesInput, ) => Effect.Effect; } +/** + * ProjectionThreadActivityRepository - Service tag for thread activity persistence. + */ export class ProjectionThreadActivityRepository extends ServiceMap.Service< ProjectionThreadActivityRepository, ProjectionThreadActivityRepositoryShape diff --git a/apps/server/src/persistence/Services/ProjectionThreadMessages.ts b/apps/server/src/persistence/Services/ProjectionThreadMessages.ts index 79bdb6237e51a8feb7746aa0282e5be1dd6f032c..6f59b6a8e4663025d6e8664bff1fa69e8353264d 100644 --- a/apps/server/src/persistence/Services/ProjectionThreadMessages.ts +++ b/apps/server/src/persistence/Services/ProjectionThreadMessages.ts @@ -1,3 +1,11 @@ +/** + * ProjectionThreadMessageRepository - Projection repository interface for messages. + * + * Owns persistence operations for projected thread messages rendered in the + * orchestration read model. + * + * @module ProjectionThreadMessageRepository + */ import { OrchestrationMessageRole, MessageId, @@ -32,20 +40,39 @@ export const DeleteProjectionThreadMessagesInput = Schema.Struct({ }); export type DeleteProjectionThreadMessagesInput = typeof DeleteProjectionThreadMessagesInput.Type; +/** + * ProjectionThreadMessageRepositoryShape - Service API for projected thread messages. + */ export interface ProjectionThreadMessageRepositoryShape { + /** + * Insert or replace a projected thread message row. + * + * Upserts by `messageId`. + */ readonly upsert: ( message: ProjectionThreadMessage, ) => Effect.Effect; + /** + * List projected thread messages for a thread. + * + * Returned in ascending creation order. + */ readonly listByThreadId: ( input: ListProjectionThreadMessagesInput, ) => Effect.Effect, ProjectionRepositoryError>; + /** + * Delete projected thread messages by thread. + */ readonly deleteByThreadId: ( input: DeleteProjectionThreadMessagesInput, ) => Effect.Effect; } +/** + * ProjectionThreadMessageRepository - Service tag for message projection persistence. + */ export class ProjectionThreadMessageRepository extends ServiceMap.Service< ProjectionThreadMessageRepository, ProjectionThreadMessageRepositoryShape diff --git a/apps/server/src/persistence/Services/ProjectionThreadSessions.ts b/apps/server/src/persistence/Services/ProjectionThreadSessions.ts index a6b20a777f4fe8e9bf6b24e9cbd890a3712b004e..57f460b76503e4545343c65b4fd44cf5ae37b82e 100644 --- a/apps/server/src/persistence/Services/ProjectionThreadSessions.ts +++ b/apps/server/src/persistence/Services/ProjectionThreadSessions.ts @@ -1,3 +1,11 @@ +/** + * ProjectionThreadSessionRepository - Repository interface for thread sessions. + * + * Owns persistence operations for projected provider-session linkage and + * runtime status for each thread. + * + * @module ProjectionThreadSessionRepository + */ import { IsoDateTime, OrchestrationSessionStatus, @@ -33,18 +41,35 @@ export const DeleteProjectionThreadSessionInput = Schema.Struct({ }); export type DeleteProjectionThreadSessionInput = typeof DeleteProjectionThreadSessionInput.Type; +/** + * ProjectionThreadSessionRepositoryShape - Service API for projected thread sessions. + */ export interface ProjectionThreadSessionRepositoryShape { + /** + * Insert or replace a projected thread-session row. + * + * Upserts by `threadId`. + */ readonly upsert: (row: ProjectionThreadSession) => Effect.Effect; + /** + * Read projected thread-session state by thread id. + */ readonly getByThreadId: ( input: GetProjectionThreadSessionInput, ) => Effect.Effect, ProjectionRepositoryError>; + /** + * Delete projected thread-session state by thread id. + */ readonly deleteByThreadId: ( input: DeleteProjectionThreadSessionInput, ) => Effect.Effect; } +/** + * ProjectionThreadSessionRepository - Service tag for thread-session persistence. + */ export class ProjectionThreadSessionRepository extends ServiceMap.Service< ProjectionThreadSessionRepository, ProjectionThreadSessionRepositoryShape diff --git a/apps/server/src/persistence/Services/ProjectionThreadTurns.ts b/apps/server/src/persistence/Services/ProjectionThreadTurns.ts index 7aad85ddffa34095f43069f9624fcb16e90a8bcd..d332717931707eb4cafaf5d543564c6630c70795 100644 --- a/apps/server/src/persistence/Services/ProjectionThreadTurns.ts +++ b/apps/server/src/persistence/Services/ProjectionThreadTurns.ts @@ -1,3 +1,10 @@ +/** + * ProjectionThreadTurnRepository - Projection repository interface for turns. + * + * Owns persistence operations for projected turn records in thread timelines. + * + * @module ProjectionThreadTurnRepository + */ import { IsoDateTime, MessageId, @@ -38,22 +45,44 @@ export const DeleteProjectionThreadTurnsInput = Schema.Struct({ }); export type DeleteProjectionThreadTurnsInput = typeof DeleteProjectionThreadTurnsInput.Type; +/** + * ProjectionThreadTurnRepositoryShape - Service API for projected thread turns. + */ export interface ProjectionThreadTurnRepositoryShape { + /** + * Insert or replace a projected turn row. + * + * Upserts by `turnId`. + */ readonly upsert: (turn: ProjectionThreadTurn) => Effect.Effect; + /** + * List projected turns for a thread. + * + * Returned in ascending `turnCount` order. + */ readonly listByThreadId: ( input: ListProjectionThreadTurnsInput, ) => Effect.Effect, ProjectionRepositoryError>; + /** + * Read a projected turn row by turn id. + */ readonly getByTurnId: ( input: GetProjectionThreadTurnInput, ) => Effect.Effect, ProjectionRepositoryError>; + /** + * Delete projected turn rows by thread. + */ readonly deleteByThreadId: ( input: DeleteProjectionThreadTurnsInput, ) => Effect.Effect; } +/** + * ProjectionThreadTurnRepository - Service tag for turn projection persistence. + */ export class ProjectionThreadTurnRepository extends ServiceMap.Service< ProjectionThreadTurnRepository, ProjectionThreadTurnRepositoryShape diff --git a/apps/server/src/persistence/Services/ProjectionThreads.ts b/apps/server/src/persistence/Services/ProjectionThreads.ts index 88f91bf749a87e4c0290f334ac568185bb84c1b5..94099128558a12c44845ffa8a3967cb8da1bb83e 100644 --- a/apps/server/src/persistence/Services/ProjectionThreads.ts +++ b/apps/server/src/persistence/Services/ProjectionThreads.ts @@ -1,3 +1,11 @@ +/** + * ProjectionThreadRepository - Projection repository interface for threads. + * + * Owns persistence operations for projected thread records in the + * orchestration read model. + * + * @module ProjectionThreadRepository + */ import { IsoDateTime, ProjectId, ThreadId, TurnId } from "@t3tools/contracts"; import { Option, Schema, ServiceMap } from "effect"; import type { Effect } from "effect"; @@ -33,22 +41,44 @@ export const ListProjectionThreadsByProjectInput = Schema.Struct({ }); export type ListProjectionThreadsByProjectInput = typeof ListProjectionThreadsByProjectInput.Type; +/** + * ProjectionThreadRepositoryShape - Service API for projected thread records. + */ export interface ProjectionThreadRepositoryShape { + /** + * Insert or replace a projected thread row. + * + * Upserts by `threadId`. + */ readonly upsert: (thread: ProjectionThread) => Effect.Effect; + /** + * Read a projected thread row by id. + */ readonly getById: ( input: GetProjectionThreadInput, ) => Effect.Effect, ProjectionRepositoryError>; + /** + * List projected threads for a project. + * + * Returned in deterministic creation order. + */ readonly listByProjectId: ( input: ListProjectionThreadsByProjectInput, ) => Effect.Effect, ProjectionRepositoryError>; + /** + * Soft-delete a projected thread row by id. + */ readonly deleteById: ( input: DeleteProjectionThreadInput, ) => Effect.Effect; } +/** + * ProjectionThreadRepository - Service tag for thread projection persistence. + */ export class ProjectionThreadRepository extends ServiceMap.Service< ProjectionThreadRepository, ProjectionThreadRepositoryShape diff --git a/apps/server/src/persistence/Services/ProviderSessionRuntime.ts b/apps/server/src/persistence/Services/ProviderSessionRuntime.ts index 8cf2bc465ac850da2a37ff00cc702f2b30bba815..77ad0ff698ca4deef168acd2e324fd8cf112b726 100644 --- a/apps/server/src/persistence/Services/ProviderSessionRuntime.ts +++ b/apps/server/src/persistence/Services/ProviderSessionRuntime.ts @@ -1,3 +1,10 @@ +/** + * ProviderSessionRuntimeRepository - Repository interface for provider runtime sessions. + * + * Owns persistence operations for provider runtime metadata and resume cursors. + * + * @module ProviderSessionRuntimeRepository + */ import { IsoDateTime, ProviderSessionId, @@ -33,25 +40,47 @@ export const DeleteProviderSessionRuntimeInput = Schema.Struct({ }); export type DeleteProviderSessionRuntimeInput = typeof DeleteProviderSessionRuntimeInput.Type; +/** + * ProviderSessionRuntimeRepositoryShape - Service API for provider runtime records. + */ export interface ProviderSessionRuntimeRepositoryShape { + /** + * Insert or replace a provider runtime row. + * + * Upserts by `providerSessionId`, including JSON payload/cursor fields. + */ readonly upsert: ( runtime: ProviderSessionRuntime, ) => Effect.Effect; + /** + * Read provider runtime state by provider session id. + */ readonly getBySessionId: ( input: GetProviderSessionRuntimeInput, ) => Effect.Effect, ProviderSessionRuntimeRepositoryError>; + /** + * List all provider runtime rows. + * + * Returned in ascending last-seen order. + */ readonly list: () => Effect.Effect< ReadonlyArray, ProviderSessionRuntimeRepositoryError >; + /** + * Delete provider runtime state by provider session id. + */ readonly deleteBySessionId: ( input: DeleteProviderSessionRuntimeInput, ) => Effect.Effect; } +/** + * ProviderSessionRuntimeRepository - Service tag for provider runtime persistence. + */ export class ProviderSessionRuntimeRepository extends ServiceMap.Service< ProviderSessionRuntimeRepository, ProviderSessionRuntimeRepositoryShape diff --git a/apps/server/src/persistence/Services/ProviderSessions.ts b/apps/server/src/persistence/Services/ProviderSessions.ts index 445c63bc0ab2a7ce3a5fdeb953c508f9b33aa92f..54c34e434802bc03966db8bdb7b20661d8a2c1aa 100644 --- a/apps/server/src/persistence/Services/ProviderSessions.ts +++ b/apps/server/src/persistence/Services/ProviderSessions.ts @@ -1,3 +1,11 @@ +/** + * ProviderSessionRepository - Repository interface for provider session lookup. + * + * Owns persistence operations that map internal sessions to provider kinds and + * optional thread ownership. + * + * @module ProviderSessionRepository + */ import type { ProviderKind, ProviderSessionId, ThreadId } from "@t3tools/contracts"; import { Option, ServiceMap } from "effect"; import type { Effect } from "effect"; @@ -26,25 +34,47 @@ export interface GetProviderSessionInput { readonly sessionId: ProviderSessionId; } +/** + * ProviderSessionRepositoryShape - Service API for provider-session records. + */ export interface ProviderSessionRepositoryShape { + /** + * Insert or replace a provider-session row. + * + * Upserts by `sessionId`. + */ readonly upsertSession: ( input: UpsertProviderSessionInput, ) => Effect.Effect; + /** + * Read a provider-session row by session id. + */ readonly getSession: ( input: GetProviderSessionInput, ) => Effect.Effect, ProviderSessionRepositoryError>; + /** + * List all provider-session rows. + * + * Returned in deterministic creation order. + */ readonly listSessions: () => Effect.Effect< ReadonlyArray, ProviderSessionRepositoryError >; + /** + * Delete a provider-session row by session id. + */ readonly deleteSession: ( input: DeleteProviderSessionInput, ) => Effect.Effect; } +/** + * ProviderSessionRepository - Service tag for provider-session persistence. + */ export class ProviderSessionRepository extends ServiceMap.Service< ProviderSessionRepository, ProviderSessionRepositoryShape diff --git a/apps/server/src/provider/Errors.ts b/apps/server/src/provider/Errors.ts index 3ba38d995d0e1bf9fd807dee5dd515269ce4a6cd..a3d29f77cc9d5f52482f37f59aca5f870b2e779e 100644 --- a/apps/server/src/provider/Errors.ts +++ b/apps/server/src/provider/Errors.ts @@ -51,23 +51,6 @@ export class ProviderAdapterSessionClosedError extends Schema.TaggedErrorClass

()( - "ProviderAdapterProtocolError", - { - provider: Schema.String, - operation: Schema.String, - detail: Schema.String, - cause: Schema.optional(Schema.Defect), - }, -) { - override get message(): string { - return `Provider adapter protocol error (${this.provider}) in ${this.operation}: ${this.detail}`; - } -} - /** * ProviderAdapterRequestError - Provider protocol request failed or timed out. */ @@ -164,61 +147,10 @@ export class ProviderSessionDirectoryPersistenceError extends Schema.TaggedError } } -/** - * ProviderCheckpointUnavailableError - Checkpointing unavailable for this session. - */ -export class ProviderCheckpointUnavailableError extends Schema.TaggedErrorClass()( - "ProviderCheckpointUnavailableError", - { - sessionId: Schema.String, - detail: Schema.String, - cause: Schema.optional(Schema.Defect), - }, -) { - override get message(): string { - return `Provider checkpoint unavailable for session ${this.sessionId}: ${this.detail}`; - } -} - -/** - * ProviderCheckpointRangeError - Requested checkpoint range is invalid. - */ -export class ProviderCheckpointRangeError extends Schema.TaggedErrorClass()( - "ProviderCheckpointRangeError", - { - sessionId: Schema.String, - fromTurnCount: Schema.Number, - toTurnCount: Schema.Number, - detail: Schema.String, - cause: Schema.optional(Schema.Defect), - }, -) { - override get message(): string { - return `Provider checkpoint range error for session ${this.sessionId}: ${this.fromTurnCount}..${this.toTurnCount} (${this.detail})`; - } -} - -/** - * ProviderFilesystemError - Filesystem checkpoint capture/restore failure. - */ -export class ProviderFilesystemError extends Schema.TaggedErrorClass()( - "ProviderFilesystemError", - { - sessionId: Schema.String, - detail: Schema.String, - cause: Schema.optional(Schema.Defect), - }, -) { - override get message(): string { - return `Provider filesystem checkpoint error for session ${this.sessionId}: ${this.detail}`; - } -} - export type ProviderAdapterError = | ProviderAdapterValidationError | ProviderAdapterSessionNotFoundError | ProviderAdapterSessionClosedError - | ProviderAdapterProtocolError | ProviderAdapterRequestError | ProviderAdapterProcessError; @@ -227,8 +159,5 @@ export type ProviderServiceError = | ProviderUnsupportedError | ProviderSessionNotFoundError | ProviderSessionDirectoryPersistenceError - | ProviderCheckpointUnavailableError - | ProviderCheckpointRangeError - | ProviderFilesystemError | ProviderAdapterError | CheckpointServiceError; diff --git a/apps/server/src/provider/Services/CodexAdapter.ts b/apps/server/src/provider/Services/CodexAdapter.ts index 2c33eabb7794411dd66e5756c7f35d3b13480da2..9eac2c994d0220601468660458747afa2ebc7a90 100644 --- a/apps/server/src/provider/Services/CodexAdapter.ts +++ b/apps/server/src/provider/Services/CodexAdapter.ts @@ -15,6 +15,9 @@ import { ServiceMap } from "effect"; import type { ProviderAdapterError } from "../Errors.ts"; import type { ProviderAdapterShape } from "./ProviderAdapter.ts"; +/** + * CodexAdapterShape - Service API for the Codex provider adapter. + */ export interface CodexAdapterShape extends ProviderAdapterShape { readonly provider: "codex"; } diff --git a/apps/server/src/provider/Services/ProviderAdapterRegistry.ts b/apps/server/src/provider/Services/ProviderAdapterRegistry.ts index 420086a7c15b129c05315a5e29cdf3e32aa4b79a..5591742aee3f02f7ed3e7c7022c882da03867ca3 100644 --- a/apps/server/src/provider/Services/ProviderAdapterRegistry.ts +++ b/apps/server/src/provider/Services/ProviderAdapterRegistry.ts @@ -14,6 +14,9 @@ import type { Effect } from "effect"; import type { ProviderAdapterError, ProviderUnsupportedError } from "../Errors.ts"; import type { ProviderAdapterShape } from "./ProviderAdapter.ts"; +/** + * ProviderAdapterRegistryShape - Service API for adapter lookup by provider kind. + */ export interface ProviderAdapterRegistryShape { /** * Resolve the adapter for a provider kind. diff --git a/apps/server/src/provider/Services/ProviderService.ts b/apps/server/src/provider/Services/ProviderService.ts index d704b7be1e2e230393bedd500e3cb357b52397b3..cbe45fe6affc7affc6a162c46bea3e71d082dfde 100644 --- a/apps/server/src/provider/Services/ProviderService.ts +++ b/apps/server/src/provider/Services/ProviderService.ts @@ -28,6 +28,9 @@ import type { Effect, Stream } from "effect"; import type { ProviderServiceError } from "../Errors.ts"; +/** + * ProviderServiceShape - Service API for provider session and turn orchestration. + */ export interface ProviderServiceShape { /** * Start a provider session. @@ -67,6 +70,8 @@ export interface ProviderServiceShape { /** * List active provider sessions. + * + * Aggregates runtime session lists from all registered adapters. */ readonly listSessions: () => Effect.Effect>; @@ -83,6 +88,8 @@ export interface ProviderServiceShape { * * Persisted session bindings remain so stale sessions can be resumed after * process restart. + * + * Runtime alias mappings are cleared as part of shutdown. */ readonly stopAll: () => Effect.Effect; diff --git a/apps/server/src/provider/Services/ProviderSessionDirectory.ts b/apps/server/src/provider/Services/ProviderSessionDirectory.ts index af04a38aa17f8f38c9de7a8136650da61580f1e6..2d3c2397627eca8bd4cba7bd4407b96233650521 100644 --- a/apps/server/src/provider/Services/ProviderSessionDirectory.ts +++ b/apps/server/src/provider/Services/ProviderSessionDirectory.ts @@ -42,9 +42,15 @@ export type ProviderSessionDirectoryWriteError = | ProviderValidationError | ProviderSessionDirectoryPersistenceError; +/** + * ProviderSessionDirectoryShape - Service API for provider session ownership metadata. + */ export interface ProviderSessionDirectoryShape { /** * Record or update ownership for one provider session. + * + * Preserves existing persisted fields when omitted and shallow-merges + * runtime payload objects. */ readonly upsert: ( binding: ProviderSessionBinding, diff --git a/apps/server/src/terminal/Services/Manager.ts b/apps/server/src/terminal/Services/Manager.ts index 94c757d5afd9a46b3d926ca0fefc39baf31edfda..22cbd4ecc164b368d4695629de20c69f0ad88605 100644 --- a/apps/server/src/terminal/Services/Manager.ts +++ b/apps/server/src/terminal/Services/Manager.ts @@ -1,3 +1,11 @@ +/** + * TerminalManager - Terminal session orchestration service interface. + * + * Owns terminal lifecycle operations, output fanout, and session state + * transitions for thread-scoped terminals. + * + * @module TerminalManager + */ import { TerminalClearInput, TerminalCloseInput, @@ -40,17 +48,61 @@ export interface TerminalStartInput extends TerminalOpenInput { rows: number; } +/** + * TerminalManagerShape - Service API for terminal session lifecycle operations. + */ export interface TerminalManagerShape { + /** + * Open or attach to a terminal session. + * + * Reuses an existing session for the same thread/terminal id and restores + * persisted history on first open. + */ readonly open: (input: TerminalOpenInput) => Effect.Effect; + + /** + * Write input bytes to a terminal session. + */ readonly write: (input: TerminalWriteInput) => Effect.Effect; + + /** + * Resize the PTY backing a terminal session. + */ readonly resize: (input: TerminalResizeInput) => Effect.Effect; + + /** + * Clear terminal output history. + */ readonly clear: (input: TerminalClearInput) => Effect.Effect; + + /** + * Restart a terminal session in place. + * + * Always resets history before spawning the new process. + */ readonly restart: (input: TerminalOpenInput) => Effect.Effect; + + /** + * Close an active terminal session. + * + * When `terminalId` is omitted, closes all sessions for the thread. + */ readonly close: (input: TerminalCloseInput) => Effect.Effect; + + /** + * Subscribe to terminal runtime events. + */ readonly subscribe: (listener: (event: TerminalEvent) => void) => Effect.Effect<() => void>; + + /** + * Dispose all managed terminal resources. + */ readonly dispose: () => Effect.Effect; } +/** + * TerminalManager - Service tag for terminal session orchestration. + */ export class TerminalManager extends ServiceMap.Service()( "terminal/TerminalManager", ) {} diff --git a/apps/server/src/terminal/Services/PTY.ts b/apps/server/src/terminal/Services/PTY.ts index 1ab7fc55c52cae600f97e8d93c568926c24a2684..ca9e51ea0bf6102f0d19268390994227bf853014 100644 --- a/apps/server/src/terminal/Services/PTY.ts +++ b/apps/server/src/terminal/Services/PTY.ts @@ -1,3 +1,11 @@ +/** + * PtyAdapter - Terminal PTY adapter service contract. + * + * Defines the process primitives required by terminal session management + * without binding to a specific PTY implementation. + * + * @module PtyAdapter + */ import { ServiceMap } from "effect"; export interface PtyExitEvent { @@ -23,10 +31,19 @@ export interface PtySpawnInput { env: NodeJS.ProcessEnv; } +/** + * PtyAdapterShape - Service API for spawning and controlling PTY processes. + */ export interface PtyAdapterShape { + /** + * Spawn a PTY process for a terminal session. + */ spawn(input: PtySpawnInput): PtyProcess; } +/** + * PtyAdapter - Service tag for PTY process integration. + */ export class PtyAdapter extends ServiceMap.Service()( "terminal/PtyAdapter", ) {} diff --git a/apps/server/src/wsServer.ts b/apps/server/src/wsServer.ts index ed61fe39e81af94ad57b569dcdb6abb640284554..eb825f020547b067c4872a0de20940a5c159c095 100644 --- a/apps/server/src/wsServer.ts +++ b/apps/server/src/wsServer.ts @@ -1,3 +1,11 @@ +/** + * Server - HTTP/WebSocket server service interface. + * + * Owns startup and shutdown lifecycle of the HTTP server, static asset serving, + * and WebSocket request routing. + * + * @module Server + */ import fs from "node:fs"; import http from "node:http"; import path from "node:path"; @@ -49,15 +57,28 @@ const MIME_TYPES: Record = { ".map": "application/json", }; +/** + * ServerShape - Service API for server lifecycle control. + */ export interface ServerShape { + /** + * Start HTTP and WebSocket listeners. + */ readonly start: Effect.Effect< http.Server, unknown, Scope.Scope | ServerRuntimeServices | ServerConfig >; + + /** + * Wait for process shutdown signals. + */ readonly stopSignal: Effect.Effect; } +/** + * Server - Service tag for HTTP/WebSocket lifecycle management. + */ export class Server extends ServiceMap.Service()("server/Server") {} const isServerNotRunningError = (error: unknown): boolean => { -- 2.54.0