import * as Cause from "effect/Cause";import * as Crypto from "effect/Crypto";import * as DateTime from "effect/DateTime";import * as Duration from "effect/Duration";import * as Effect from "effect/Effect";import * as Layer from "effect/Layer";import * as Option from "effect/Option";import * as Queue from "effect/Queue";import * as Ref from "effect/Ref";import * as Schema from "effect/Schema";import * as Stream from "effect/Stream";import { DEFAULT_AUTOMATIC_GIT_FETCH_INTERVAL, AuthAccessStreamError, type AuthAccessStreamEvent, type AuthEnvironmentScope, AuthSessionId, CommandId, type DiscoveredLocalServerList, EventId, type OrchestrationCommand, type GitActionProgressEvent, type GitManagerServiceError, OrchestrationDispatchCommandError, type OrchestrationEvent, type OrchestrationShellStreamEvent, type OrchestrationShellStreamItem, type OrchestrationThreadStreamItem, OrchestrationGetFullThreadDiffError, OrchestrationGetSnapshotError, OrchestrationSearchThreadsError, OrchestrationGetTurnDiffError, ORCHESTRATION_WS_METHODS, type ProjectId, type ProjectEntriesFailure, type ProjectFileFailure, type ProjectFileOperation, ProjectListEntriesError, ProjectReadFileError, ProjectSearchContentsError, ProjectSearchEntriesError, ProjectWriteFileError, RelayClientInstallFailedError, type RelayClientInstallProgressEvent, type ServerSelfUpdateError, type ServerSelfUpdateProgressEvent, type FilesystemBrowseFailure, FilesystemBrowseError, AssetWorkspaceContextNotFoundError, AssetWorkspaceContextResolutionError, RpcClientId, EnvironmentAuthorizationError, ThreadId, type TerminalAttachStreamEvent, type TerminalError, type TerminalEvent, type TerminalMetadataStreamEvent, WS_METHODS, WsRpcGroup,} from "@t3tools/contracts";import { resolveServerBackgroundActivitySettings } from "@t3tools/shared/backgroundActivitySettings";import { HttpRouter, HttpServerRequest, HttpServerRespondable } from "effect/unstable/http";import { RpcSerialization, RpcServer } from "effect/unstable/rpc"; import * as CheckpointDiffQuery from "./checkpointing/CheckpointDiffQuery.ts";import * as ServerConfig from "./config.ts";import * as Keybindings from "./keybindings.ts";import * as ExternalLauncher from "./process/externalLauncher.ts";import { projectActivityEvent, projectThreadDetailSnapshot,} from "./orchestration/ActivityPayloadProjection.ts";import { normalizeDispatchCommand } from "./orchestration/Normalizer.ts";import * as OrchestrationEngine from "./orchestration/Services/OrchestrationEngine.ts";import * as ProjectionSnapshotQuery from "./orchestration/Services/ProjectionSnapshotQuery.ts";import { observeRpcEffect as instrumentRpcEffect, observeRpcStream as instrumentRpcStream, observeRpcStreamEffect as instrumentRpcStreamEffect,} from "./observability/RpcInstrumentation.ts";import * as ProviderRegistry from "./provider/Services/ProviderRegistry.ts";import * as ProviderMaintenanceRunner from "./provider/providerMaintenanceRunner.ts";import * as ServerSelfUpdate from "./cloud/selfUpdate.ts";import * as ServerLifecycleEvents from "./serverLifecycleEvents.ts";import * as ServerRuntimeStartup from "./serverRuntimeStartup.ts";import * as ServerSettings from "./serverSettings.ts";import * as TerminalManager from "./terminal/Manager.ts";import * as PreviewAutomationBroker from "./mcp/PreviewAutomationBroker.ts";import * as PreviewManager from "./preview/Manager.ts";import { issueAssetUrl } from "./assets/AssetAccess.ts";import * as PortScanner from "./preview/PortScanner.ts";import * as WorkspaceEntries from "./workspace/WorkspaceEntries.ts";import * as WorkspaceFileSystem from "./workspace/WorkspaceFileSystem.ts";import { readWorkflowScript } from "./orchestration/workflowScriptQuery.ts";import * as WorkspacePaths from "./workspace/WorkspacePaths.ts";import * as VcsStatusBroadcaster from "./vcs/VcsStatusBroadcaster.ts";import * as VcsProvisioningService from "./vcs/VcsProvisioningService.ts";import * as GitWorkflowService from "./git/GitWorkflowService.ts";import * as ReviewService from "./review/ReviewService.ts";import * as ProjectSetupScriptRunner from "./project/ProjectSetupScriptRunner.ts";import * as ServerEnvironment from "./environment/ServerEnvironment.ts";import * as RemoteOpenTargets from "./environment/RemoteOpenTargets.ts";import * as BackgroundPolicy from "./background/BackgroundPolicy.ts";import * as EnvironmentAuth from "./auth/EnvironmentAuth.ts";import { requiredScopeForRpcMethod } from "./auth/RpcAuthorization.ts";import * as ProcessDiagnostics from "./diagnostics/ProcessDiagnostics.ts";import * as ProcessResourceMonitor from "./diagnostics/ProcessResourceMonitor.ts";import * as ResourceTelemetry from "./resourceTelemetry/ResourceTelemetry.ts";import * as UsageService from "./usage/UsageService.ts";import * as TraceDiagnostics from "./diagnostics/TraceDiagnostics.ts";import * as PullRequestService from "./pullRequest/PullRequestService.ts";import * as SourceControlDiscovery from "./sourceControl/SourceControlDiscovery.ts";import * as SourceControlRepositoryService from "./sourceControl/SourceControlRepositoryService.ts";import * as AzureDevOpsCli from "./sourceControl/AzureDevOpsCli.ts";import * as BitbucketApi from "./sourceControl/BitbucketApi.ts";import * as GitHubCli from "./sourceControl/GitHubCli.ts";import * as GitLabCli from "./sourceControl/GitLabCli.ts";import * as SourceControlProviderRegistry from "./sourceControl/SourceControlProviderRegistry.ts";import * as GitVcsDriver from "./vcs/GitVcsDriver.ts";import * as VcsDriverRegistry from "./vcs/VcsDriverRegistry.ts";import * as VcsProjectConfig from "./vcs/VcsProjectConfig.ts";import * as VcsProcess from "./vcs/VcsProcess.ts";import * as PairingGrantStore from "./auth/PairingGrantStore.ts";import * as SessionStore from "./auth/SessionStore.ts";import { failEnvironmentAuthInvalid, failEnvironmentInternal } from "./auth/http.ts";import * as RelayClient from "@t3tools/shared/relayClient";const isOrchestrationDispatchCommandError = Schema.is(OrchestrationDispatchCommandError); const nowIso = Effect.map(DateTime.now, DateTime.formatIso);const EDITOR_DISCOVERY_TIMEOUT = Duration.seconds(5); export const resolveAvailableEditorsForConfig = <A, E, R>( discovery: Effect.Effect<ReadonlyArray<A>, E, R>,) => discovery.pipe( Effect.timeoutOption(EDITOR_DISCOVERY_TIMEOUT), Effect.map(Option.getOrElse(() => [])), ); function unexpectedCompatibilityError(error: never): never { throw new Error(`Unhandled compatibility error: ${String(error)}`);} /** Preserve the setup runner's broader pre-refactor message normalization. */function legacySetupFailureDescription(cause: unknown): string { if ( typeof cause === "object" && cause !== null && "message" in cause && typeof cause.message === "string" ) { return cause.message; } return String(cause);} function projectEntriesFailureContext(error: WorkspaceEntries.WorkspaceEntriesError): { readonly failure: ProjectEntriesFailure; readonly normalizedCwd?: string; readonly timeout?: string; readonly detail?: string;} { switch (error._tag) { case "WorkspaceRootNotExistsError": return { failure: "workspace_root_not_found", normalizedCwd: error.normalizedWorkspaceRoot, }; case "WorkspaceRootCreateFailedError": return { failure: "workspace_root_create_failed", normalizedCwd: error.normalizedWorkspaceRoot, }; case "WorkspaceRootStatFailedError": return { failure: "workspace_root_stat_failed", normalizedCwd: error.normalizedWorkspaceRoot, detail: error.phase, }; case "WorkspaceRootNotDirectoryError": return { failure: "workspace_root_not_directory", normalizedCwd: error.normalizedWorkspaceRoot, }; case "WorkspaceSearchIndexCreateFailed": return { failure: "search_index_create_failed", normalizedCwd: error.cwd, detail: error.reason, }; case "WorkspaceSearchIndexScanTimedOut": return { failure: "search_index_scan_timed_out", normalizedCwd: error.cwd, timeout: error.timeout, }; case "WorkspaceSearchIndexSearchFailed": return { failure: "search_index_search_failed", normalizedCwd: error.cwd, detail: error.reason, }; default: return unexpectedCompatibilityError(error); }} function filesystemBrowseFailureContext(error: WorkspaceEntries.WorkspaceEntriesBrowseError): { readonly failure: FilesystemBrowseFailure; readonly parentPath?: string; readonly platform?: string;} { switch (error._tag) { case "WorkspaceEntriesWindowsPathUnsupportedError": return { failure: "windows_path_unsupported", platform: error.platform }; case "WorkspaceEntriesCurrentProjectRequiredError": return { failure: "current_project_required" }; case "WorkspaceEntriesReadDirectoryError": return { failure: "read_directory_failed", parentPath: error.parentPath }; default: return unexpectedCompatibilityError(error); }} function projectFileFailureContext( error: | WorkspaceFileSystem.WorkspaceFileSystemError | WorkspacePaths.WorkspacePathOutsideRootError,): { readonly failure: ProjectFileFailure; readonly resolvedPath?: string; readonly resolvedWorkspaceRoot?: string; readonly operation?: ProjectFileOperation; readonly operationPath?: string;} { switch (error._tag) { case "WorkspacePathOutsideRootError": return { failure: "workspace_path_outside_root" }; case "WorkspaceFileSystemOperationError": return { failure: "operation_failed", resolvedPath: error.resolvedPath, operation: error.operation, operationPath: error.operationPath, }; case "WorkspaceFilePathEscapeError": return { failure: "resolved_path_outside_root", resolvedPath: error.resolvedPath, resolvedWorkspaceRoot: error.resolvedWorkspaceRoot, }; case "WorkspacePathNotFileError": return { failure: "path_not_file", resolvedPath: error.resolvedPath }; case "WorkspaceBinaryFileError": return { failure: "binary_file", resolvedPath: error.resolvedPath }; default: return unexpectedCompatibilityError(error); }} function projectSetupScriptCompatibilityDetail( error: ProjectSetupScriptRunner.ProjectSetupScriptRunnerError,): string { switch (error._tag) { case "ProjectSetupScriptOperationError": return legacySetupFailureDescription(error.cause); case "ProjectSetupScriptProjectNotFoundError": return "Project was not found for setup script execution."; default: return unexpectedCompatibilityError(error); }} export function isThreadDetailEvent(event: OrchestrationEvent): event is Extract< OrchestrationEvent, { type: | "thread.message-sent" | "thread.proposed-plan-upserted" | "thread.activity-appended" | "thread.turn-diff-completed" | "thread.reverted" | "thread.session-set"; }> { return ( event.type === "thread.message-sent" || event.type === "thread.proposed-plan-upserted" || event.type === "thread.activity-appended" || event.type === "thread.turn-diff-completed" || event.type === "thread.reverted" || event.type === "thread.session-set" );} const PROVIDER_STATUS_DEBOUNCE_MS = 200; // When a resuming client's cursor is more than this many events behind the// current head, skip the per-event catch-up replay and send a fresh shell// snapshot instead. Replaying each intervening event costs a shell refetch;// past this gap a single O(active-threads) snapshot is cheaper and bounded.// Matches the event store's default page size (DEFAULT_READ_FROM_SEQUENCE_LIMIT).const SHELL_RESUME_MAX_GAP = 1_000; // Same bound for thread resume. The replay reads the *global* event range and// filters per-thread afterwards, so a stale cursor far behind the head would// otherwise decode every intervening event's payload — reconnects with cursors// hundreds of thousands of events behind have OOM-killed servers on large// databases. Past this gap the client is reset with a fresh thread snapshot.const THREAD_RESUME_MAX_GAP = 1_000; function toAuthAccessStreamEvent( change: PairingGrantStore.BootstrapCredentialChange | SessionStore.SessionCredentialChange, revision: number, currentSessionId: AuthSessionId,): AuthAccessStreamEvent { switch (change.type) { case "pairingLinkUpserted": return { version: 1, revision, type: "pairingLinkUpserted", payload: change.pairingLink, }; case "pairingLinkRemoved": return { version: 1, revision, type: "pairingLinkRemoved", payload: { id: change.id }, }; case "clientUpserted": return { version: 1, revision, type: "clientUpserted", payload: { ...change.clientSession, current: change.clientSession.sessionId === currentSessionId, }, }; case "clientRemoved": return { version: 1, revision, type: "clientRemoved", payload: { sessionId: change.sessionId }, }; }} const makeWsRpcLayer = ( currentSession: EnvironmentAuth.AuthenticatedSession, previewAutomationBroker: PreviewAutomationBroker.PreviewAutomationBroker["Service"],) => WsRpcGroup.toLayer( Effect.gen(function* () { const currentSessionId = currentSession.sessionId; const crypto = yield* Crypto.Crypto; const projectionSnapshotQuery = yield* ProjectionSnapshotQuery.ProjectionSnapshotQuery; const orchestrationEngine = yield* OrchestrationEngine.OrchestrationEngineService; const checkpointDiffQuery = yield* CheckpointDiffQuery.CheckpointDiffQuery; const keybindings = yield* Keybindings.Keybindings; const externalLauncher = yield* ExternalLauncher.ExternalLauncher; const remoteOpenTargets = yield* RemoteOpenTargets.RemoteOpenTargets; const gitWorkflow = yield* GitWorkflowService.GitWorkflowService; const review = yield* ReviewService.ReviewService; const vcsProvisioning = yield* VcsProvisioningService.VcsProvisioningService; const vcsStatusBroadcaster = yield* VcsStatusBroadcaster.VcsStatusBroadcaster; const terminalManager = yield* TerminalManager.TerminalManager; const previewManager = yield* PreviewManager.PreviewManager; const portDiscovery = yield* PortScanner.PortDiscovery; const providerRegistry = yield* ProviderRegistry.ProviderRegistry; const providerMaintenanceRunner = yield* ProviderMaintenanceRunner.ProviderMaintenanceRunner; const serverSelfUpdate = yield* ServerSelfUpdate.ServerSelfUpdate; const config = yield* ServerConfig.ServerConfig; const lifecycleEvents = yield* ServerLifecycleEvents.ServerLifecycleEvents; const serverSettings = yield* ServerSettings.ServerSettingsService; const startup = yield* ServerRuntimeStartup.ServerRuntimeStartup; const workspaceEntries = yield* WorkspaceEntries.WorkspaceEntries; const workspaceFileSystem = yield* WorkspaceFileSystem.WorkspaceFileSystem; const projectSetupScriptRunner = yield* ProjectSetupScriptRunner.ProjectSetupScriptRunner; const serverEnvironment = yield* ServerEnvironment.ServerEnvironment; const backgroundPolicy = yield* BackgroundPolicy.BackgroundPolicy; const rpcClientIds = yield* Ref.make(new Set<RpcClientId>()); yield* Effect.addFinalizer(() => Ref.get(rpcClientIds).pipe( Effect.flatMap((clientIds) => Effect.forEach( clientIds, (clientId) => backgroundPolicy.removeRpcClient(currentSessionId, clientId), { discard: true, }, ), ), Effect.ignore, ), ); const serverAuth = yield* EnvironmentAuth.EnvironmentAuth; const sourceControlDiscovery = yield* SourceControlDiscovery.SourceControlDiscovery; const automaticGitFetchInterval = serverSettings.getSettings.pipe( Effect.map( (settings) => resolveServerBackgroundActivitySettings(settings).automaticGitFetchInterval, ), Effect.catch((cause) => Effect.logWarning("Failed to read automatic Git fetch interval setting", { detail: cause.message, }).pipe(Effect.as(DEFAULT_AUTOMATIC_GIT_FETCH_INTERVAL)), ), ); const sourceControlRepositories = yield* SourceControlRepositoryService.SourceControlRepositoryService; const pullRequests = yield* PullRequestService.PullRequestService; const bootstrapCredentials = yield* PairingGrantStore.PairingGrantStore; const sessions = yield* SessionStore.SessionStore; const processDiagnostics = yield* ProcessDiagnostics.ProcessDiagnostics; const processResourceMonitor = yield* ProcessResourceMonitor.ProcessResourceMonitor; const resourceTelemetry = yield* ResourceTelemetry.ResourceTelemetry; const usage = yield* UsageService.UsageService; const relayClient = yield* RelayClient.RelayClient; const authorizationError = (requiredScope: AuthEnvironmentScope) => new EnvironmentAuthorizationError({ message: `The authenticated token is missing required scope: ${requiredScope}.`, requiredScope, }); const authorizeEffect = <A, E, R>( requiredScope: AuthEnvironmentScope, effect: Effect.Effect<A, E, R>, ): Effect.Effect<A, E | EnvironmentAuthorizationError, R> => currentSession.scopes.includes(requiredScope) ? effect : Effect.fail(authorizationError(requiredScope)); const authorizeStream = <A, E, R>( requiredScope: AuthEnvironmentScope, stream: Stream.Stream<A, E, R>, ): Stream.Stream<A, E | EnvironmentAuthorizationError, R> => currentSession.scopes.includes(requiredScope) ? stream : Stream.fail(authorizationError(requiredScope)); const observeRpcEffect = <A, E, R>( method: string, effect: Effect.Effect<A, E, R>, traceAttributes?: Readonly<Record<string, unknown>>, ) => instrumentRpcEffect( method, authorizeEffect(requiredScopeForRpcMethod(method), effect), traceAttributes, ); const observeRpcStream = <A, E, R>( method: string, stream: Stream.Stream<A, E, R>, traceAttributes?: Readonly<Record<string, unknown>>, ) => instrumentRpcStream( method, authorizeStream(requiredScopeForRpcMethod(method), stream), traceAttributes, ); const observeRpcStreamEffect = <A, StreamError, StreamContext, EffectError, EffectContext>( method: string, effect: Effect.Effect< Stream.Stream<A, StreamError, StreamContext>, EffectError, EffectContext >, traceAttributes?: Readonly<Record<string, unknown>>, ) => instrumentRpcStreamEffect( method, authorizeEffect(requiredScopeForRpcMethod(method), effect), traceAttributes, ); const toDispatchCommandError = (cause: unknown, fallbackMessage: string) => isOrchestrationDispatchCommandError(cause) ? cause : new OrchestrationDispatchCommandError({ message: cause instanceof Error ? cause.message : fallbackMessage, cause, }); const randomUUID = crypto.randomUUIDv4.pipe( Effect.mapError((cause) => toDispatchCommandError(cause, "Failed to generate orchestration command identifier."), ), ); const serverEventId = randomUUID.pipe(Effect.map(EventId.make)); const serverCommandId = (tag: string) => randomUUID.pipe(Effect.map((uuid) => CommandId.make(`server:${tag}:${uuid}`))); const loadAuthAccessSnapshot = () => Effect.all({ pairingLinks: serverAuth.listPairingLinks(), clientSessions: serverAuth.listClientSessions(currentSessionId), }).pipe( Effect.mapError( (error) => new AuthAccessStreamError({ message: error.message, }),Lines 1–500 of 2369. Load more
import * as Cause from "effect/Cause"; import * as Crypto from "effect/Crypto"; import * as DateTime from "effect/DateTime"; import * as Duration from "effect/Duration"; import * as Effect from "effect/Effect"; import * as Layer from "effect/Layer"; import * as Option from "effect/Option"; import * as Queue from "effect/Queue"; import * as Ref from "effect/Ref"; import * as Schema from "effect/Schema"; import * as Stream from "effect/Stream"; import { DEFAULT_AUTOMATIC_GIT_FETCH_INTERVAL, AuthAccessStreamError, type AuthAccessStreamEvent, type AuthEnvironmentScope, AuthSessionId, CommandId, type DiscoveredLocalServerList, EventId, type OrchestrationCommand, type GitActionProgressEvent, type GitManagerServiceError, OrchestrationDispatchCommandError, type OrchestrationEvent, type OrchestrationShellStreamEvent, type OrchestrationShellStreamItem, type OrchestrationThreadStreamItem, OrchestrationGetFullThreadDiffError, OrchestrationGetSnapshotError, OrchestrationSearchThreadsError, OrchestrationGetTurnDiffError, ORCHESTRATION_WS_METHODS, type ProjectId, type ProjectEntriesFailure, type ProjectFileFailure, type ProjectFileOperation, ProjectListEntriesError, ProjectReadFileError, ProjectSearchContentsError, ProjectSearchEntriesError, ProjectWriteFileError, RelayClientInstallFailedError, type RelayClientInstallProgressEvent, type ServerSelfUpdateError, type ServerSelfUpdateProgressEvent, type FilesystemBrowseFailure, FilesystemBrowseError, AssetWorkspaceContextNotFoundError, AssetWorkspaceContextResolutionError, RpcClientId, EnvironmentAuthorizationError, ThreadId, type TerminalAttachStreamEvent, type TerminalError, type TerminalEvent, type TerminalMetadataStreamEvent, WS_METHODS, WsRpcGroup, } from "@t3tools/contracts"; import { resolveServerBackgroundActivitySettings } from "@t3tools/shared/backgroundActivitySettings"; import { HttpRouter, HttpServerRequest, HttpServerRespondable } from "effect/unstable/http"; import { RpcSerialization, RpcServer } from "effect/unstable/rpc"; import * as CheckpointDiffQuery from "./checkpointing/CheckpointDiffQuery.ts"; import * as ServerConfig from "./config.ts"; import * as Keybindings from "./keybindings.ts"; import * as ExternalLauncher from "./process/externalLauncher.ts"; import { projectActivityEvent, projectThreadDetailSnapshot, } from "./orchestration/ActivityPayloadProjection.ts"; import { normalizeDispatchCommand } from "./orchestration/Normalizer.ts"; import * as OrchestrationEngine from "./orchestration/Services/OrchestrationEngine.ts"; import * as ProjectionSnapshotQuery from "./orchestration/Services/ProjectionSnapshotQuery.ts"; import { observeRpcEffect as instrumentRpcEffect, observeRpcStream as instrumentRpcStream, observeRpcStreamEffect as instrumentRpcStreamEffect, } from "./observability/RpcInstrumentation.ts"; import * as ProviderRegistry from "./provider/Services/ProviderRegistry.ts"; import * as ProviderMaintenanceRunner from "./provider/providerMaintenanceRunner.ts"; import * as ServerSelfUpdate from "./cloud/selfUpdate.ts"; import * as ServerLifecycleEvents from "./serverLifecycleEvents.ts"; import * as ServerRuntimeStartup from "./serverRuntimeStartup.ts"; import * as ServerSettings from "./serverSettings.ts"; import * as TerminalManager from "./terminal/Manager.ts"; import * as PreviewAutomationBroker from "./mcp/PreviewAutomationBroker.ts"; import * as PreviewManager from "./preview/Manager.ts"; import { issueAssetUrl } from "./assets/AssetAccess.ts"; import * as PortScanner from "./preview/PortScanner.ts"; import * as WorkspaceEntries from "./workspace/WorkspaceEntries.ts"; import * as WorkspaceFileSystem from "./workspace/WorkspaceFileSystem.ts"; import { readWorkflowScript } from "./orchestration/workflowScriptQuery.ts"; import * as WorkspacePaths from "./workspace/WorkspacePaths.ts"; import * as VcsStatusBroadcaster from "./vcs/VcsStatusBroadcaster.ts"; import * as VcsProvisioningService from "./vcs/VcsProvisioningService.ts"; import * as GitWorkflowService from "./git/GitWorkflowService.ts"; import * as ReviewService from "./review/ReviewService.ts"; import * as ProjectSetupScriptRunner from "./project/ProjectSetupScriptRunner.ts"; import * as ServerEnvironment from "./environment/ServerEnvironment.ts"; import * as RemoteOpenTargets from "./environment/RemoteOpenTargets.ts"; import * as BackgroundPolicy from "./background/BackgroundPolicy.ts"; import * as EnvironmentAuth from "./auth/EnvironmentAuth.ts"; import { requiredScopeForRpcMethod } from "./auth/RpcAuthorization.ts"; import * as ProcessDiagnostics from "./diagnostics/ProcessDiagnostics.ts"; import * as ProcessResourceMonitor from "./diagnostics/ProcessResourceMonitor.ts"; import * as ResourceTelemetry from "./resourceTelemetry/ResourceTelemetry.ts"; import * as UsageService from "./usage/UsageService.ts"; import * as TraceDiagnostics from "./diagnostics/TraceDiagnostics.ts"; import * as PullRequestService from "./pullRequest/PullRequestService.ts"; import * as SourceControlDiscovery from "./sourceControl/SourceControlDiscovery.ts"; import * as SourceControlRepositoryService from "./sourceControl/SourceControlRepositoryService.ts"; import * as AzureDevOpsCli from "./sourceControl/AzureDevOpsCli.ts"; import * as BitbucketApi from "./sourceControl/BitbucketApi.ts"; import * as GitHubCli from "./sourceControl/GitHubCli.ts"; import * as GitLabCli from "./sourceControl/GitLabCli.ts"; import * as SourceControlProviderRegistry from "./sourceControl/SourceControlProviderRegistry.ts"; import * as GitVcsDriver from "./vcs/GitVcsDriver.ts"; import * as VcsDriverRegistry from "./vcs/VcsDriverRegistry.ts"; import * as VcsProjectConfig from "./vcs/VcsProjectConfig.ts"; import * as VcsProcess from "./vcs/VcsProcess.ts"; import * as PairingGrantStore from "./auth/PairingGrantStore.ts"; import * as SessionStore from "./auth/SessionStore.ts"; import { failEnvironmentAuthInvalid, failEnvironmentInternal } from "./auth/http.ts"; import * as RelayClient from "@t3tools/shared/relayClient"; const isOrchestrationDispatchCommandError = Schema.is(OrchestrationDispatchCommandError); const nowIso = Effect.map(DateTime.now, DateTime.formatIso); const EDITOR_DISCOVERY_TIMEOUT = Duration.seconds(5); export const resolveAvailableEditorsForConfig = <A, E, R>( discovery: Effect.Effect<ReadonlyArray<A>, E, R>, ) => discovery.pipe( Effect.timeoutOption(EDITOR_DISCOVERY_TIMEOUT), Effect.map(Option.getOrElse(() => [])), ); function unexpectedCompatibilityError(error: never): never { throw new Error(`Unhandled compatibility error: ${String(error)}`); } /** Preserve the setup runner's broader pre-refactor message normalization. */ function legacySetupFailureDescription(cause: unknown): string { if ( typeof cause === "object" && cause !== null && "message" in cause && typeof cause.message === "string" ) { return cause.message; } return String(cause); } function projectEntriesFailureContext(error: WorkspaceEntries.WorkspaceEntriesError): { readonly failure: ProjectEntriesFailure; readonly normalizedCwd?: string; readonly timeout?: string; readonly detail?: string; } { switch (error._tag) { case "WorkspaceRootNotExistsError": return { failure: "workspace_root_not_found", normalizedCwd: error.normalizedWorkspaceRoot, }; case "WorkspaceRootCreateFailedError": return { failure: "workspace_root_create_failed", normalizedCwd: error.normalizedWorkspaceRoot, }; case "WorkspaceRootStatFailedError": return { failure: "workspace_root_stat_failed", normalizedCwd: error.normalizedWorkspaceRoot, detail: error.phase, }; case "WorkspaceRootNotDirectoryError": return { failure: "workspace_root_not_directory", normalizedCwd: error.normalizedWorkspaceRoot, }; case "WorkspaceSearchIndexCreateFailed": return { failure: "search_index_create_failed", normalizedCwd: error.cwd, detail: error.reason, }; case "WorkspaceSearchIndexScanTimedOut": return { failure: "search_index_scan_timed_out", normalizedCwd: error.cwd, timeout: error.timeout, }; case "WorkspaceSearchIndexSearchFailed": return { failure: "search_index_search_failed", normalizedCwd: error.cwd, detail: error.reason, }; default: return unexpectedCompatibilityError(error); } } function filesystemBrowseFailureContext(error: WorkspaceEntries.WorkspaceEntriesBrowseError): { readonly failure: FilesystemBrowseFailure; readonly parentPath?: string; readonly platform?: string; } { switch (error._tag) { case "WorkspaceEntriesWindowsPathUnsupportedError": return { failure: "windows_path_unsupported", platform: error.platform }; case "WorkspaceEntriesCurrentProjectRequiredError": return { failure: "current_project_required" }; case "WorkspaceEntriesReadDirectoryError": return { failure: "read_directory_failed", parentPath: error.parentPath }; default: return unexpectedCompatibilityError(error); } } function projectFileFailureContext( error: | WorkspaceFileSystem.WorkspaceFileSystemError | WorkspacePaths.WorkspacePathOutsideRootError, ): { readonly failure: ProjectFileFailure; readonly resolvedPath?: string; readonly resolvedWorkspaceRoot?: string; readonly operation?: ProjectFileOperation; readonly operationPath?: string; } { switch (error._tag) { case "WorkspacePathOutsideRootError": return { failure: "workspace_path_outside_root" }; case "WorkspaceFileSystemOperationError": return { failure: "operation_failed", resolvedPath: error.resolvedPath, operation: error.operation, operationPath: error.operationPath, }; case "WorkspaceFilePathEscapeError": return { failure: "resolved_path_outside_root", resolvedPath: error.resolvedPath, resolvedWorkspaceRoot: error.resolvedWorkspaceRoot, }; case "WorkspacePathNotFileError": return { failure: "path_not_file", resolvedPath: error.resolvedPath }; case "WorkspaceBinaryFileError": return { failure: "binary_file", resolvedPath: error.resolvedPath }; default: return unexpectedCompatibilityError(error); } } function projectSetupScriptCompatibilityDetail( error: ProjectSetupScriptRunner.ProjectSetupScriptRunnerError, ): string { switch (error._tag) { case "ProjectSetupScriptOperationError": return legacySetupFailureDescription(error.cause); case "ProjectSetupScriptProjectNotFoundError": return "Project was not found for setup script execution."; default: return unexpectedCompatibilityError(error); } } export function isThreadDetailEvent(event: OrchestrationEvent): event is Extract< OrchestrationEvent, { type: | "thread.message-sent" | "thread.proposed-plan-upserted" | "thread.activity-appended" | "thread.turn-diff-completed" | "thread.reverted" | "thread.session-set"; } > { return ( event.type === "thread.message-sent" || event.type === "thread.proposed-plan-upserted" || event.type === "thread.activity-appended" || event.type === "thread.turn-diff-completed" || event.type === "thread.reverted" || event.type === "thread.session-set" ); } const PROVIDER_STATUS_DEBOUNCE_MS = 200; // When a resuming client's cursor is more than this many events behind the // current head, skip the per-event catch-up replay and send a fresh shell // snapshot instead. Replaying each intervening event costs a shell refetch; // past this gap a single O(active-threads) snapshot is cheaper and bounded. // Matches the event store's default page size (DEFAULT_READ_FROM_SEQUENCE_LIMIT). const SHELL_RESUME_MAX_GAP = 1_000; // Same bound for thread resume. The replay reads the *global* event range and // filters per-thread afterwards, so a stale cursor far behind the head would // otherwise decode every intervening event's payload — reconnects with cursors // hundreds of thousands of events behind have OOM-killed servers on large // databases. Past this gap the client is reset with a fresh thread snapshot. const THREAD_RESUME_MAX_GAP = 1_000; function toAuthAccessStreamEvent( change: PairingGrantStore.BootstrapCredentialChange | SessionStore.SessionCredentialChange, revision: number, currentSessionId: AuthSessionId, ): AuthAccessStreamEvent { switch (change.type) { case "pairingLinkUpserted": return { version: 1, revision, type: "pairingLinkUpserted", payload: change.pairingLink, }; case "pairingLinkRemoved": return { version: 1, revision, type: "pairingLinkRemoved", payload: { id: change.id }, }; case "clientUpserted": return { version: 1, revision, type: "clientUpserted", payload: { ...change.clientSession, current: change.clientSession.sessionId === currentSessionId, }, }; case "clientRemoved": return { version: 1, revision, type: "clientRemoved", payload: { sessionId: change.sessionId }, }; } } const makeWsRpcLayer = ( currentSession: EnvironmentAuth.AuthenticatedSession, previewAutomationBroker: PreviewAutomationBroker.PreviewAutomationBroker["Service"], ) => WsRpcGroup.toLayer( Effect.gen(function* () { const currentSessionId = currentSession.sessionId; const crypto = yield* Crypto.Crypto; const projectionSnapshotQuery = yield* ProjectionSnapshotQuery.ProjectionSnapshotQuery; const orchestrationEngine = yield* OrchestrationEngine.OrchestrationEngineService; const checkpointDiffQuery = yield* CheckpointDiffQuery.CheckpointDiffQuery; const keybindings = yield* Keybindings.Keybindings; const externalLauncher = yield* ExternalLauncher.ExternalLauncher; const remoteOpenTargets = yield* RemoteOpenTargets.RemoteOpenTargets; const gitWorkflow = yield* GitWorkflowService.GitWorkflowService; const review = yield* ReviewService.ReviewService; const vcsProvisioning = yield* VcsProvisioningService.VcsProvisioningService; const vcsStatusBroadcaster = yield* VcsStatusBroadcaster.VcsStatusBroadcaster; const terminalManager = yield* TerminalManager.TerminalManager; const previewManager = yield* PreviewManager.PreviewManager; const portDiscovery = yield* PortScanner.PortDiscovery; const providerRegistry = yield* ProviderRegistry.ProviderRegistry; const providerMaintenanceRunner = yield* ProviderMaintenanceRunner.ProviderMaintenanceRunner; const serverSelfUpdate = yield* ServerSelfUpdate.ServerSelfUpdate; const config = yield* ServerConfig.ServerConfig; const lifecycleEvents = yield* ServerLifecycleEvents.ServerLifecycleEvents; const serverSettings = yield* ServerSettings.ServerSettingsService; const startup = yield* ServerRuntimeStartup.ServerRuntimeStartup; const workspaceEntries = yield* WorkspaceEntries.WorkspaceEntries; const workspaceFileSystem = yield* WorkspaceFileSystem.WorkspaceFileSystem; const projectSetupScriptRunner = yield* ProjectSetupScriptRunner.ProjectSetupScriptRunner; const serverEnvironment = yield* ServerEnvironment.ServerEnvironment; const backgroundPolicy = yield* BackgroundPolicy.BackgroundPolicy; const rpcClientIds = yield* Ref.make(new Set<RpcClientId>()); yield* Effect.addFinalizer(() => Ref.get(rpcClientIds).pipe( Effect.flatMap((clientIds) => Effect.forEach( clientIds, (clientId) => backgroundPolicy.removeRpcClient(currentSessionId, clientId), { discard: true, }, ), ), Effect.ignore, ), ); const serverAuth = yield* EnvironmentAuth.EnvironmentAuth; const sourceControlDiscovery = yield* SourceControlDiscovery.SourceControlDiscovery; const automaticGitFetchInterval = serverSettings.getSettings.pipe( Effect.map( (settings) => resolveServerBackgroundActivitySettings(settings).automaticGitFetchInterval, ), Effect.catch((cause) => Effect.logWarning("Failed to read automatic Git fetch interval setting", { detail: cause.message, }).pipe(Effect.as(DEFAULT_AUTOMATIC_GIT_FETCH_INTERVAL)), ), ); const sourceControlRepositories = yield* SourceControlRepositoryService.SourceControlRepositoryService; const pullRequests = yield* PullRequestService.PullRequestService; const bootstrapCredentials = yield* PairingGrantStore.PairingGrantStore; const sessions = yield* SessionStore.SessionStore; const processDiagnostics = yield* ProcessDiagnostics.ProcessDiagnostics; const processResourceMonitor = yield* ProcessResourceMonitor.ProcessResourceMonitor; const resourceTelemetry = yield* ResourceTelemetry.ResourceTelemetry; const usage = yield* UsageService.UsageService; const relayClient = yield* RelayClient.RelayClient; const authorizationError = (requiredScope: AuthEnvironmentScope) => new EnvironmentAuthorizationError({ message: `The authenticated token is missing required scope: ${requiredScope}.`, requiredScope, }); const authorizeEffect = <A, E, R>( requiredScope: AuthEnvironmentScope, effect: Effect.Effect<A, E, R>, ): Effect.Effect<A, E | EnvironmentAuthorizationError, R> => currentSession.scopes.includes(requiredScope) ? effect : Effect.fail(authorizationError(requiredScope)); const authorizeStream = <A, E, R>( requiredScope: AuthEnvironmentScope, stream: Stream.Stream<A, E, R>, ): Stream.Stream<A, E | EnvironmentAuthorizationError, R> => currentSession.scopes.includes(requiredScope) ? stream : Stream.fail(authorizationError(requiredScope)); const observeRpcEffect = <A, E, R>( method: string, effect: Effect.Effect<A, E, R>, traceAttributes?: Readonly<Record<string, unknown>>, ) => instrumentRpcEffect( method, authorizeEffect(requiredScopeForRpcMethod(method), effect), traceAttributes, ); const observeRpcStream = <A, E, R>( method: string, stream: Stream.Stream<A, E, R>, traceAttributes?: Readonly<Record<string, unknown>>, ) => instrumentRpcStream( method, authorizeStream(requiredScopeForRpcMethod(method), stream), traceAttributes, ); const observeRpcStreamEffect = <A, StreamError, StreamContext, EffectError, EffectContext>( method: string, effect: Effect.Effect< Stream.Stream<A, StreamError, StreamContext>, EffectError, EffectContext >, traceAttributes?: Readonly<Record<string, unknown>>, ) => instrumentRpcStreamEffect( method, authorizeEffect(requiredScopeForRpcMethod(method), effect), traceAttributes, ); const toDispatchCommandError = (cause: unknown, fallbackMessage: string) => isOrchestrationDispatchCommandError(cause) ? cause : new OrchestrationDispatchCommandError({ message: cause instanceof Error ? cause.message : fallbackMessage, cause, }); const randomUUID = crypto.randomUUIDv4.pipe( Effect.mapError((cause) => toDispatchCommandError(cause, "Failed to generate orchestration command identifier."), ), ); const serverEventId = randomUUID.pipe(Effect.map(EventId.make)); const serverCommandId = (tag: string) => randomUUID.pipe(Effect.map((uuid) => CommandId.make(`server:${tag}:${uuid}`))); const loadAuthAccessSnapshot = () => Effect.all({ pairingLinks: serverAuth.listPairingLinks(), clientSessions: serverAuth.listClientSessions(currentSessionId), }).pipe( Effect.mapError( (error) => new AuthAccessStreamError({ message: error.message, }),