- Introduce a dedicated `GitVcsDriver` service and `vcsLayer` - Update server, orchestration, and workspace wiring to use the new layer - Adjust tests and mocks for the new git-specific dependency
Unified · Split
| @@ -33,7 +33,6 @@ import { ProjectionCheckpointRepositoryLive } from "../src/persistence/Layers/Pr · 32 unmodified lines | |||
| 33 | import { ProjectionPendingApprovalRepositoryLive } from "../src/persistence/Layers/ProjectionPendingApprovals.ts"; | 33 | import { ProjectionPendingApprovalRepositoryLive } from "../src/persistence/Layers/ProjectionPendingApprovals.ts"; |
| 34 | import { ProviderSessionRuntimeRepositoryLive } from "../src/persistence/Layers/ProviderSessionRuntime.ts"; | 34 | import { ProviderSessionRuntimeRepositoryLive } from "../src/persistence/Layers/ProviderSessionRuntime.ts"; |
| 35 | import { makeSqlitePersistenceLive } from "../src/persistence/Layers/Sqlite.ts"; | 35 | import { makeSqlitePersistenceLive } from "../src/persistence/Layers/Sqlite.ts"; |
| 36 | import { VcsDriver, type VcsDriverShape } from "../src/vcs/VcsDriver.ts"; | ||
| 37 | import { ProjectionCheckpointRepository } from "../src/persistence/Services/ProjectionCheckpoints.ts"; | 36 | import { ProjectionCheckpointRepository } from "../src/persistence/Services/ProjectionCheckpoints.ts"; |
| 38 | import { ProjectionPendingApprovalRepository } from "../src/persistence/Services/ProjectionPendingApprovals.ts"; | 37 | import { ProjectionPendingApprovalRepository } from "../src/persistence/Services/ProjectionPendingApprovals.ts"; |
| 39 | import { makeAdapterRegistryMock } from "../src/provider/testUtils/providerAdapterRegistryMock.ts"; | 38 | import { makeAdapterRegistryMock } from "../src/provider/testUtils/providerAdapterRegistryMock.ts"; |
| @@ -292,7 +291,7 @@ export const makeOrchestrationIntegrationHarness = ( · 252 unmodified lines | |||
| 292 | Layer.provide(providerEventLoggersLayer), | 291 | Layer.provide(providerEventLoggersLayer), |
| 293 | ); | 292 | ); |
| 294 | 293 | ||
| 295 | const checkpointStoreLayer = CheckpointStoreLive.pipe(Layer.provide(GitVcsDriver.layer)); | 294 | const checkpointStoreLayer = CheckpointStoreLive.pipe(Layer.provide(GitVcsDriver.vcsLayer)); |
| 296 | const projectionSnapshotQueryLayer = OrchestrationProjectionSnapshotQueryLive; | 295 | const projectionSnapshotQueryLayer = OrchestrationProjectionSnapshotQueryLive; |
| 297 | const runtimeServicesLayer = Layer.mergeAll( | 296 | const runtimeServicesLayer = Layer.mergeAll( |
| 298 | projectionSnapshotQueryLayer, | 297 | projectionSnapshotQueryLayer, |
| @@ -308,17 +307,17 @@ export const makeOrchestrationIntegrationHarness = ( · 9 unmodified lines | |||
| 308 | Layer.provideMerge(runtimeServicesLayer), | 307 | Layer.provideMerge(runtimeServicesLayer), |
| 309 | Layer.provideMerge(serverSettingsLayer), | 308 | Layer.provideMerge(serverSettingsLayer), |
| 310 | ); | 309 | ); |
| 311 | const vcsDriverLayer = Layer.succeed(VcsDriver, { | 310 | const gitVcsDriverLayer = Layer.succeed(GitVcsDriver.GitVcsDriver, { |
| 312 | renameBranch: (input: Parameters<VcsDriverShape["renameBranch"]>[0]) => | 311 | renameBranch: (input: Parameters<GitVcsDriver.GitVcsDriverShape["renameBranch"]>[0]) => |
| 313 | Effect.succeed({ branch: input.newBranch }), | 312 | Effect.succeed({ branch: input.newBranch }), |
| 314 | } as unknown as VcsDriverShape); | 313 | } as unknown as GitVcsDriver.GitVcsDriverShape); |
| 315 | const textGenerationLayer = Layer.succeed(TextGeneration, { | 314 | const textGenerationLayer = Layer.succeed(TextGeneration, { |
| 316 | generateBranchName: () => Effect.succeed({ branch: "update" }), | 315 | generateBranchName: () => Effect.succeed({ branch: "update" }), |
| 317 | generateThreadTitle: () => Effect.succeed({ title: "New thread" }), | 316 | generateThreadTitle: () => Effect.succeed({ title: "New thread" }), |
| 318 | } as unknown as TextGenerationShape); | 317 | } as unknown as TextGenerationShape); |
| 319 | const providerCommandReactorLayer = ProviderCommandReactorLive.pipe( | 318 | const providerCommandReactorLayer = ProviderCommandReactorLive.pipe( |
| 320 | Layer.provideMerge(runtimeServicesLayer), | 319 | Layer.provideMerge(runtimeServicesLayer), |
| 321 | Layer.provideMerge(vcsDriverLayer), | 320 | Layer.provideMerge(gitVcsDriverLayer), |
| 322 | Layer.provideMerge(textGenerationLayer), | 321 | Layer.provideMerge(textGenerationLayer), |
| 323 | Layer.provideMerge(serverSettingsLayer), | 322 | Layer.provideMerge(serverSettingsLayer), |
| 324 | ); | 323 | ); |
| @@ -343,7 +342,7 @@ export const makeOrchestrationIntegrationHarness = ( · 18 unmodified lines | |||
| 343 | Layer.provideMerge( | 342 | Layer.provideMerge( |
| 344 | WorkspaceEntriesLive.pipe( | 343 | WorkspaceEntriesLive.pipe( |
| 345 | Layer.provide(WorkspacePathsLive), | 344 | Layer.provide(WorkspacePathsLive), |
| 346 | Layer.provideMerge(GitVcsDriver.layer), | 345 | Layer.provideMerge(GitVcsDriver.vcsLayer), |
| 347 | Layer.provide(NodeServices.layer), | 346 | Layer.provide(NodeServices.layer), |
| 348 | ), | 347 | ), |
| 349 | ), | 348 | ), |
| @@ -18,7 +18,7 @@ const ServerConfigLayer = ServerConfig.layerTest(process.cwd(), { · 17 unmodified lines | |||
| 18 | prefix: "t3-checkpoint-store-test-", | 18 | prefix: "t3-checkpoint-store-test-", |
| 19 | }); | 19 | }); |
| 20 | const VcsProcessTestLayer = VcsProcess.layer.pipe(Layer.provide(NodeServices.layer)); | 20 | const VcsProcessTestLayer = VcsProcess.layer.pipe(Layer.provide(NodeServices.layer)); |
| 21 | const VcsDriverTestLayer = GitVcsDriver.layer.pipe(Layer.provide(VcsProcessTestLayer)); | 21 | const VcsDriverTestLayer = GitVcsDriver.vcsLayer.pipe(Layer.provide(VcsProcessTestLayer)); |
| 22 | const CheckpointStoreTestLayer = CheckpointStoreLive.pipe( | 22 | const CheckpointStoreTestLayer = CheckpointStoreLive.pipe( |
| 23 | Layer.provideMerge(VcsDriverTestLayer), | 23 | Layer.provideMerge(VcsDriverTestLayer), |
| 24 | Layer.provideMerge(NodeServices.layer), | 24 | Layer.provideMerge(NodeServices.layer), |
| @@ -23,7 +23,6 @@ import { · 22 unmodified lines | |||
| 23 | import { type TextGenerationShape, TextGeneration } from "../Services/TextGeneration.ts"; | 23 | import { type TextGenerationShape, TextGeneration } from "../Services/TextGeneration.ts"; |
| 24 | import * as GitVcsDriver from "../../vcs/GitVcsDriver.ts"; | 24 | import * as GitVcsDriver from "../../vcs/GitVcsDriver.ts"; |
| 25 | import * as VcsProcess from "../../vcs/VcsProcess.ts"; | 25 | import * as VcsProcess from "../../vcs/VcsProcess.ts"; |
| 26 | import { VcsDriver } from "../../vcs/VcsDriver.ts"; | ||
| 27 | import { makeGitManager } from "./GitManager.ts"; | 26 | import { makeGitManager } from "./GitManager.ts"; |
| 28 | import { ServerConfig } from "../../config.ts"; | 27 | import { ServerConfig } from "../../config.ts"; |
| 29 | import { ServerSettingsService } from "../../serverSettings.ts"; | 28 | import { ServerSettingsService } from "../../serverSettings.ts"; |
| @@ -212,30 +211,18 @@ function runGit( · 182 unmodified lines | |||
| 212 | ): Effect.Effect< | 211 | ): Effect.Effect< |
| 213 | { readonly code: number; readonly stdout: string; readonly stderr: string }, | 212 | { readonly code: number; readonly stdout: string; readonly stderr: string }, |
| 214 | GitCommandError, | 213 | GitCommandError, |
| 215 | VcsDriver | 214 | GitVcsDriver.GitVcsDriver |
| 216 | > { | 215 | > { |
| 217 | return Effect.gen(function* () { | 216 | return Effect.gen(function* () { |
| 218 | const vcs = yield* VcsDriver; | 217 | const git = yield* GitVcsDriver.GitVcsDriver; |
| 219 | const result = yield* vcs | 218 | const result = yield* git.execute({ |
| 220 | .execute({ | 219 | operation: "GitManager.test.runGit", |
| 221 | operation: "GitManager.test.runGit", | 220 | cwd, |
| 222 | cwd, | 221 | args, |
| 223 | args, | 222 | allowNonZeroExit, |
| 224 | allowNonZeroExit, | 223 | }); |
| 225 | }) | ||
| 226 | .pipe( | ||
| 227 | Effect.mapError( | ||
| 228 | (error) => | ||
| 229 | new GitCommandError({ | ||
| 230 | operation: "GitManager.test.runGit", | ||
| 231 | command: `git ${args.join(" ")}`, | ||
| 232 | cwd, | ||
| 233 | detail: error.message, | ||
| 234 | }), | ||
| 235 | ), | ||
| 236 | ); | ||
| 237 | return { | 224 | return { |
| 238 | code: result.exitCode, | 225 | code: result.code, |
| 239 | stdout: result.stdout, | 226 | stdout: result.stdout, |
| 240 | stderr: result.stderr, | 227 | stderr: result.stderr, |
| 241 | }; | 228 | }; |
| @@ -247,7 +234,7 @@ function initRepo( · 5 unmodified lines | |||
| 247 | ): Effect.Effect< | 234 | ): Effect.Effect< |
| 248 | void, | 235 | void, |
| 249 | PlatformError.PlatformError | GitCommandError, | 236 | PlatformError.PlatformError | GitCommandError, |
| 250 | FileSystem.FileSystem | Scope.Scope | VcsDriver | 237 | FileSystem.FileSystem | Scope.Scope | GitVcsDriver.GitVcsDriver |
| 251 | > { | 238 | > { |
| 252 | return Effect.gen(function* () { | 239 | return Effect.gen(function* () { |
| 253 | const fs = yield* FileSystem.FileSystem; | 240 | const fs = yield* FileSystem.FileSystem; |
| @@ -263,7 +250,7 @@ function initRepo( · 9 unmodified lines | |||
| 263 | function createBareRemote(): Effect.Effect< | 250 | function createBareRemote(): Effect.Effect< |
| 264 | string, | 251 | string, |
| 265 | PlatformError.PlatformError | GitCommandError, | 252 | PlatformError.PlatformError | GitCommandError, |
| 266 | FileSystem.FileSystem | Scope.Scope | VcsDriver | 253 | FileSystem.FileSystem | Scope.Scope | GitVcsDriver.GitVcsDriver |
| 267 | > { | 254 | > { |
| 268 | return Effect.gen(function* () { | 255 | return Effect.gen(function* () { |
| 269 | const remoteDir = yield* makeTempDir("t3code-git-remote-"); | 256 | const remoteDir = yield* makeTempDir("t3code-git-remote-"); |
| @@ -277,7 +264,7 @@ function configureRemote( · 7 unmodified lines | |||
| 277 | remoteName: string, | 264 | remoteName: string, |
| 278 | remotePath: string, | 265 | remotePath: string, |
| 279 | fetchNamespace: string, | 266 | fetchNamespace: string, |
| 280 | ): Effect.Effect<void, GitCommandError, VcsDriver> { | 267 | ): Effect.Effect<void, GitCommandError, GitVcsDriver.GitVcsDriver> { |
| 281 | return Effect.gen(function* () { | 268 | return Effect.gen(function* () { |
| 282 | yield* runGit(cwd, ["config", `remote.${remoteName}.url`, remotePath]); | 269 | yield* runGit(cwd, ["config", `remote.${remoteName}.url`, remotePath]); |
| 283 | yield* runGit(cwd, [ | 270 | yield* runGit(cwd, [ |
| @@ -49,7 +49,7 @@ import { · 48 unmodified lines | |||
| 49 | decodeGitHubPullRequestListJson, | 49 | decodeGitHubPullRequestListJson, |
| 50 | formatGitHubJsonDecodeError, | 50 | formatGitHubJsonDecodeError, |
| 51 | } from "../githubPullRequests.ts"; | 51 | } from "../githubPullRequests.ts"; |
| 52 | import { VcsDriver } from "../../vcs/VcsDriver.ts"; | 52 | import { GitVcsDriver } from "../../vcs/GitVcsDriver.ts"; |
| 53 | 53 | ||
| 54 | const COMMIT_TIMEOUT_MS = 10 * 60_000; | 54 | const COMMIT_TIMEOUT_MS = 10 * 60_000; |
| 55 | const MAX_PROGRESS_TEXT_LENGTH = 500; | 55 | const MAX_PROGRESS_TEXT_LENGTH = 500; |
| @@ -491,7 +491,7 @@ function toPullRequestHeadRemoteInfo(pr: { · 435 unmodified lines | |||
| 491 | } | 491 | } |
| 492 | 492 | ||
| 493 | export const makeGitManager = Effect.fn("makeGitManager")(function* () { | 493 | export const makeGitManager = Effect.fn("makeGitManager")(function* () { |
| 494 | const gitCore = yield* VcsDriver; | 494 | const gitCore = yield* GitVcsDriver; |
| 495 | const gitHubCli = yield* GitHubCli; | 495 | const gitHubCli = yield* GitHubCli; |
| 496 | const textGeneration = yield* TextGeneration; | 496 | const textGeneration = yield* TextGeneration; |
| 497 | const projectSetupScriptRunner = yield* ProjectSetupScriptRunner; | 497 | const projectSetupScriptRunner = yield* ProjectSetupScriptRunner; |
| @@ -307,11 +307,11 @@ describe("CheckpointReactor", () => { · 306 unmodified lines | |||
| 307 | Layer.provideMerge(RuntimeReceiptBusLive), | 307 | Layer.provideMerge(RuntimeReceiptBusLive), |
| 308 | Layer.provideMerge(Layer.succeed(ProviderService, provider.service)), | 308 | Layer.provideMerge(Layer.succeed(ProviderService, provider.service)), |
| 309 | Layer.provideMerge(gitStatusBroadcasterLayer), | 309 | Layer.provideMerge(gitStatusBroadcasterLayer), |
| 310 | Layer.provideMerge(CheckpointStoreLive.pipe(Layer.provide(GitVcsDriver.layer))), | 310 | Layer.provideMerge(CheckpointStoreLive.pipe(Layer.provide(GitVcsDriver.vcsLayer))), |
| 311 | Layer.provideMerge( | 311 | Layer.provideMerge( |
| 312 | WorkspaceEntriesLive.pipe( | 312 | WorkspaceEntriesLive.pipe( |
| 313 | Layer.provide(WorkspacePathsLive), | 313 | Layer.provide(WorkspacePathsLive), |
| 314 | Layer.provideMerge(GitVcsDriver.layer), | 314 | Layer.provideMerge(GitVcsDriver.vcsLayer), |
| 315 | ), | 315 | ), |
| 316 | ), | 316 | ), |
| 317 | Layer.provideMerge(WorkspacePathsLive), | 317 | Layer.provideMerge(WorkspacePathsLive), |
| @@ -51,7 +51,7 @@ import { OrchestrationEngineService } from "../Services/OrchestrationEngine.ts"; · 50 unmodified lines | |||
| 51 | import { ProviderCommandReactor } from "../Services/ProviderCommandReactor.ts"; | 51 | import { ProviderCommandReactor } from "../Services/ProviderCommandReactor.ts"; |
| 52 | import * as NodeServices from "@effect/platform-node/NodeServices"; | 52 | import * as NodeServices from "@effect/platform-node/NodeServices"; |
| 53 | import { ServerSettingsService } from "../../serverSettings.ts"; | 53 | import { ServerSettingsService } from "../../serverSettings.ts"; |
| 54 | import { VcsDriver, type VcsDriverShape } from "../../vcs/VcsDriver.ts"; | 54 | import * as GitVcsDriver from "../../vcs/GitVcsDriver.ts"; |
| 55 | 55 | ||
| 56 | const asProjectId = (value: string): ProjectId => ProjectId.make(value); | 56 | const asProjectId = (value: string): ProjectId => ProjectId.make(value); |
| 57 | const asApprovalRequestId = (value: string): ApprovalRequestId => ApprovalRequestId.make(value); | 57 | const asApprovalRequestId = (value: string): ApprovalRequestId => ApprovalRequestId.make(value); |
| @@ -324,7 +324,11 @@ describe("ProviderCommandReactor", () => { · 266 unmodified lines | |||
| 324 | const layer = ProviderCommandReactorLive.pipe( | 324 | const layer = ProviderCommandReactorLive.pipe( |
| 325 | Layer.provideMerge(orchestrationLayer), | 325 | Layer.provideMerge(orchestrationLayer), |
| 326 | Layer.provideMerge(Layer.succeed(ProviderService, service)), | 326 | Layer.provideMerge(Layer.succeed(ProviderService, service)), |
| 327 | Layer.provideMerge(Layer.succeed(VcsDriver, { renameBranch } as unknown as VcsDriverShape)), | 327 | Layer.provideMerge( |
| 328 | Layer.succeed(GitVcsDriver.GitVcsDriver, { | ||
| 329 | renameBranch, | ||
| 330 | } as unknown as GitVcsDriver.GitVcsDriverShape), | ||
| 331 | ), | ||
| 328 | Layer.provideMerge( | 332 | Layer.provideMerge( |
| 329 | Layer.succeed(GitStatusBroadcaster, { | 333 | Layer.succeed(GitStatusBroadcaster, { |
| 330 | getStatus: () => Effect.die("getStatus should not be called in this test"), | 334 | getStatus: () => Effect.die("getStatus should not be called in this test"), |
| @@ -28,7 +28,7 @@ import { · 27 unmodified lines | |||
| 28 | type ProviderCommandReactorShape, | 28 | type ProviderCommandReactorShape, |
| 29 | } from "../Services/ProviderCommandReactor.ts"; | 29 | } from "../Services/ProviderCommandReactor.ts"; |
| 30 | import { ServerSettingsService } from "../../serverSettings.ts"; | 30 | import { ServerSettingsService } from "../../serverSettings.ts"; |
| 31 | import { VcsDriver } from "../../vcs/VcsDriver.ts"; | 31 | import { GitVcsDriver } from "../../vcs/GitVcsDriver.ts"; |
| 32 | 32 | ||
| 33 | type ProviderIntentEvent = Extract< | 33 | type ProviderIntentEvent = Extract< |
| 34 | OrchestrationEvent, | 34 | OrchestrationEvent, |
| @@ -168,7 +168,7 @@ function buildGeneratedWorktreeBranchName(raw: string): string { · 133 unmodified lines | |||
| 168 | const make = Effect.gen(function* () { | 168 | const make = Effect.gen(function* () { |
| 169 | const orchestrationEngine = yield* OrchestrationEngineService; | 169 | const orchestrationEngine = yield* OrchestrationEngineService; |
| 170 | const providerService = yield* ProviderService; | 170 | const providerService = yield* ProviderService; |
| 171 | const git = yield* VcsDriver; | 171 | const git = yield* GitVcsDriver; |
| 172 | const gitStatusBroadcaster = yield* GitStatusBroadcaster; | 172 | const gitStatusBroadcaster = yield* GitStatusBroadcaster; |
| 173 | const textGeneration = yield* TextGeneration; | 173 | const textGeneration = yield* TextGeneration; |
| 174 | const serverSettingsService = yield* ServerSettingsService; | 174 | const serverSettingsService = yield* ServerSettingsService; |
| @@ -104,6 +104,7 @@ import { · 103 unmodified lines | |||
| 104 | import { WorkspaceEntriesLive } from "./workspace/Layers/WorkspaceEntries.ts"; | 104 | import { WorkspaceEntriesLive } from "./workspace/Layers/WorkspaceEntries.ts"; |
| 105 | import { WorkspaceFileSystemLive } from "./workspace/Layers/WorkspaceFileSystem.ts"; | 105 | import { WorkspaceFileSystemLive } from "./workspace/Layers/WorkspaceFileSystem.ts"; |
| 106 | import { WorkspacePathsLive } from "./workspace/Layers/WorkspacePaths.ts"; | 106 | import { WorkspacePathsLive } from "./workspace/Layers/WorkspacePaths.ts"; |
| 107 | import * as GitVcsDriver from "./vcs/GitVcsDriver.ts"; | ||
| 107 | import { VcsDriver, type VcsDriverShape } from "./vcs/VcsDriver.ts"; | 108 | import { VcsDriver, type VcsDriverShape } from "./vcs/VcsDriver.ts"; |
| 108 | import { ServerSecretStoreLive } from "./auth/Layers/ServerSecretStore.ts"; | 109 | import { ServerSecretStoreLive } from "./auth/Layers/ServerSecretStore.ts"; |
| 109 | import { ServerAuthLive } from "./auth/Layers/ServerAuth.ts"; | 110 | import { ServerAuthLive } from "./auth/Layers/ServerAuth.ts"; |
| @@ -315,6 +316,7 @@ const buildAppUnderTest = (options?: { · 205 unmodified lines | |||
| 315 | serverSettings?: Partial<ServerSettingsShape>; | 316 | serverSettings?: Partial<ServerSettingsShape>; |
| 316 | open?: Partial<OpenShape>; | 317 | open?: Partial<OpenShape>; |
| 317 | vcsDriver?: Partial<VcsDriverShape>; | 318 | vcsDriver?: Partial<VcsDriverShape>; |
| 319 | gitVcsDriver?: Partial<GitVcsDriver.GitVcsDriverShape>; | ||
| 318 | gitManager?: Partial<GitManagerShape>; | 320 | gitManager?: Partial<GitManagerShape>; |
| 319 | gitStatusBroadcaster?: Partial<GitStatusBroadcasterShape>; | 321 | gitStatusBroadcaster?: Partial<GitStatusBroadcasterShape>; |
| 320 | projectSetupScriptRunner?: Partial<ProjectSetupScriptRunnerShape>; | 322 | projectSetupScriptRunner?: Partial<ProjectSetupScriptRunnerShape>; |
| @@ -384,6 +386,9 @@ const buildAppUnderTest = (options?: { · 63 unmodified lines | |||
| 384 | filterIgnoredPaths: (_cwd, relativePaths) => Effect.succeed(relativePaths), | 386 | filterIgnoredPaths: (_cwd, relativePaths) => Effect.succeed(relativePaths), |
| 385 | ...options?.layers?.vcsDriver, | 387 | ...options?.layers?.vcsDriver, |
| 386 | }); | 388 | }); |
| 389 | const gitVcsDriverLayer = Layer.mock(GitVcsDriver.GitVcsDriver)({ | ||
| 390 | ...options?.layers?.gitVcsDriver, | ||
| 391 | }); | ||
| 387 | const gitManagerLayer = Layer.mock(GitManager)({ | 392 | const gitManagerLayer = Layer.mock(GitManager)({ |
| 388 | ...options?.layers?.gitManager, | 393 | ...options?.layers?.gitManager, |
| 389 | }); | 394 | }); |
| @@ -444,6 +449,7 @@ const buildAppUnderTest = (options?: { · 54 unmodified lines | |||
| 444 | }), | 449 | }), |
| 445 | ), | 450 | ), |
| 446 | Layer.provide(gitManagerLayer), | 451 | Layer.provide(gitManagerLayer), |
| 452 | Layer.provide(gitVcsDriverLayer), | ||
| 447 | Layer.provideMerge(gitStatusBroadcasterLayer), | 453 | Layer.provideMerge(gitStatusBroadcasterLayer), |
| 448 | Layer.provide( | 454 | Layer.provide( |
| 449 | Layer.mock(ProjectSetupScriptRunner)({ | 455 | Layer.mock(ProjectSetupScriptRunner)({ |
| @@ -2377,7 +2383,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 1927 unmodified lines | |||
| 2377 | worktreePath: null, | 2383 | worktreePath: null, |
| 2378 | }), | 2384 | }), |
| 2379 | }, | 2385 | }, |
| 2380 | vcsDriver: { | 2386 | gitVcsDriver: { |
| 2381 | pullCurrentBranch: () => | 2387 | pullCurrentBranch: () => |
| 2382 | Effect.succeed({ | 2388 | Effect.succeed({ |
| 2383 | status: "pulled", | 2389 | status: "pulled", |
| @@ -2531,7 +2537,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 147 unmodified lines | |||
| 2531 | let statusCalls = 0; | 2537 | let statusCalls = 0; |
| 2532 | yield* buildAppUnderTest({ | 2538 | yield* buildAppUnderTest({ |
| 2533 | layers: { | 2539 | layers: { |
| 2534 | vcsDriver: { | 2540 | gitVcsDriver: { |
| 2535 | pullCurrentBranch: () => Effect.fail(gitError), | 2541 | pullCurrentBranch: () => Effect.fail(gitError), |
| 2536 | }, | 2542 | }, |
| 2537 | gitManager: { | 2543 | gitManager: { |
| @@ -2685,7 +2691,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 147 unmodified lines | |||
| 2685 | Effect.gen(function* () { | 2691 | Effect.gen(function* () { |
| 2686 | yield* buildAppUnderTest({ | 2692 | yield* buildAppUnderTest({ |
| 2687 | layers: { | 2693 | layers: { |
| 2688 | vcsDriver: { | 2694 | gitVcsDriver: { |
| 2689 | pullCurrentBranch: () => | 2695 | pullCurrentBranch: () => |
| 2690 | Effect.succeed({ | 2696 | Effect.succeed({ |
| 2691 | status: "pulled" as const, | 2697 | status: "pulled" as const, |
| @@ -3499,13 +3505,14 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 807 unmodified lines | |||
| 3499 | pr: null, | 3505 | pr: null, |
| 3500 | }), | 3506 | }), |
| 3501 | ); | 3507 | ); |
| 3502 | const createWorktree = vi.fn((_: Parameters<VcsDriverShape["createWorktree"]>[0]) => | 3508 | const createWorktree = vi.fn( |
| 3503 | Effect.succeed({ | 3509 | (_: Parameters<GitVcsDriver.GitVcsDriverShape["createWorktree"]>[0]) => |
| 3504 | worktree: { | 3510 | Effect.succeed({ |
| 3505 | branch: "t3code/bootstrap-branch", | 3511 | worktree: { |
| 3506 | path: "/tmp/bootstrap-worktree", | 3512 | branch: "t3code/bootstrap-branch", |
| 3507 | }, | 3513 | path: "/tmp/bootstrap-worktree", |
| 3508 | }), | 3514 | }, |
| 3515 | }), | ||
| 3509 | ); | 3516 | ); |
| 3510 | const runForThread = vi.fn( | 3517 | const runForThread = vi.fn( |
| 3511 | (_: Parameters<ProjectSetupScriptRunnerShape["runForThread"]>[0]) => | 3518 | (_: Parameters<ProjectSetupScriptRunnerShape["runForThread"]>[0]) => |
| @@ -3520,7 +3527,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 8 unmodified lines | |||
| 3520 | 3527 | ||
| 3521 | yield* buildAppUnderTest({ | 3528 | yield* buildAppUnderTest({ |
| 3522 | layers: { | 3529 | layers: { |
| 3523 | vcsDriver: { | 3530 | gitVcsDriver: { |
| 3524 | createWorktree, | 3531 | createWorktree, |
| 3525 | }, | 3532 | }, |
| 3526 | gitStatusBroadcaster: { | 3533 | gitStatusBroadcaster: { |
| @@ -3624,13 +3631,14 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 97 unmodified lines | |||
| 3624 | it.effect("records setup-script failures without aborting bootstrap turn start", () => | 3631 | it.effect("records setup-script failures without aborting bootstrap turn start", () => |
| 3625 | Effect.gen(function* () { | 3632 | Effect.gen(function* () { |
| 3626 | const dispatchedCommands: Array<OrchestrationCommand> = []; | 3633 | const dispatchedCommands: Array<OrchestrationCommand> = []; |
| 3627 | const createWorktree = vi.fn((_: Parameters<VcsDriverShape["createWorktree"]>[0]) => | 3634 | const createWorktree = vi.fn( |
| 3628 | Effect.succeed({ | 3635 | (_: Parameters<GitVcsDriver.GitVcsDriverShape["createWorktree"]>[0]) => |
| 3629 | worktree: { | 3636 | Effect.succeed({ |
| 3630 | branch: "t3code/bootstrap-branch", | 3637 | worktree: { |
| 3631 | path: "/tmp/bootstrap-worktree", | 3638 | branch: "t3code/bootstrap-branch", |
| 3632 | }, | 3639 | path: "/tmp/bootstrap-worktree", |
| 3633 | }), | 3640 | }, |
| 3641 | }), | ||
| 3634 | ); | 3642 | ); |
| 3635 | const runForThread = vi.fn( | 3643 | const runForThread = vi.fn( |
| 3636 | (_: Parameters<ProjectSetupScriptRunnerShape["runForThread"]>[0]) => | 3644 | (_: Parameters<ProjectSetupScriptRunnerShape["runForThread"]>[0]) => |
| @@ -3639,7 +3647,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 2 unmodified lines | |||
| 3639 | 3647 | ||
| 3640 | yield* buildAppUnderTest({ | 3648 | yield* buildAppUnderTest({ |
| 3641 | layers: { | 3649 | layers: { |
| 3642 | vcsDriver: { | 3650 | gitVcsDriver: { |
| 3643 | createWorktree, | 3651 | createWorktree, |
| 3644 | }, | 3652 | }, |
| 3645 | orchestrationEngine: { | 3653 | orchestrationEngine: { |
| @@ -3717,13 +3725,14 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 71 unmodified lines | |||
| 3717 | it.effect("does not misattribute setup activity dispatch failures as setup launch failures", () => | 3725 | it.effect("does not misattribute setup activity dispatch failures as setup launch failures", () => |
| 3718 | Effect.gen(function* () { | 3726 | Effect.gen(function* () { |
| 3719 | const dispatchedCommands: Array<OrchestrationCommand> = []; | 3727 | const dispatchedCommands: Array<OrchestrationCommand> = []; |
| 3720 | const createWorktree = vi.fn((_: Parameters<VcsDriverShape["createWorktree"]>[0]) => | 3728 | const createWorktree = vi.fn( |
| 3721 | Effect.succeed({ | 3729 | (_: Parameters<GitVcsDriver.GitVcsDriverShape["createWorktree"]>[0]) => |
| 3722 | worktree: { | 3730 | Effect.succeed({ |
| 3723 | branch: "t3code/bootstrap-branch", | 3731 | worktree: { |
| 3724 | path: "/tmp/bootstrap-worktree", | 3732 | branch: "t3code/bootstrap-branch", |
| 3725 | }, | 3733 | path: "/tmp/bootstrap-worktree", |
| 3726 | }), | 3734 | }, |
| 3735 | }), | ||
| 3727 | ); | 3736 | ); |
| 3728 | const runForThread = vi.fn( | 3737 | const runForThread = vi.fn( |
| 3729 | (_: Parameters<ProjectSetupScriptRunnerShape["runForThread"]>[0]) => | 3738 | (_: Parameters<ProjectSetupScriptRunnerShape["runForThread"]>[0]) => |
| @@ -3739,7 +3748,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 9 unmodified lines | |||
| 3739 | 3748 | ||
| 3740 | yield* buildAppUnderTest({ | 3749 | yield* buildAppUnderTest({ |
| 3741 | layers: { | 3750 | layers: { |
| 3742 | vcsDriver: { | 3751 | gitVcsDriver: { |
| 3743 | createWorktree, | 3752 | createWorktree, |
| 3744 | }, | 3753 | }, |
| 3745 | orchestrationEngine: { | 3754 | orchestrationEngine: { |
| @@ -3835,13 +3844,14 @@ it.layer(NodeServices.layer)("server router seam", (it) => { · 89 unmodified lines | |||
| 3835 | it.effect("cleans up created bootstrap threads when worktree creation defects", () => | 3844 | it.effect("cleans up created bootstrap threads when worktree creation defects", () => |
| 3836 | Effect.gen(function* () { | 3845 | Effect.gen(function* () { |
| 3837 | const dispatchedCommands: Array<OrchestrationCommand> = []; | 3846 | const dispatchedCommands: Array<OrchestrationCommand> = []; |
| 3838 | const createWorktree = vi.fn((_: Parameters<VcsDriverShape["createWorktree"]>[0]) => | 3847 | const createWorktree = vi.fn( |
| 3839 | Effect.die(new Error("worktree exploded")), | 3848 | (_: Parameters<GitVcsDriver.GitVcsDriverShape["createWorktree"]>[0]) => |
| 3849 | Effect.die(new Error("worktree exploded")), | ||
| 3840 | ); | 3850 | ); |
| 3841 | 3851 | ||
| 3842 | yield* buildAppUnderTest({ | 3852 | yield* buildAppUnderTest({ |
| 3843 | layers: { | 3853 | layers: { |
| 3844 | vcsDriver: { | 3854 | gitVcsDriver: { |
| 3845 | createWorktree, | 3855 | createWorktree, |
| 3846 | }, | 3856 | }, |
| 3847 | orchestrationEngine: { | 3857 | orchestrationEngine: { |
| @@ -136,7 +136,7 @@ const ReactorLayerLive = Layer.empty.pipe( · 135 unmodified lines | |||
| 136 | 136 | ||
| 137 | const CheckpointingLayerLive = Layer.empty.pipe( | 137 | const CheckpointingLayerLive = Layer.empty.pipe( |
| 138 | Layer.provideMerge(CheckpointDiffQueryLive), | 138 | Layer.provideMerge(CheckpointDiffQueryLive), |
| 139 | Layer.provideMerge(CheckpointStoreLive.pipe(Layer.provide(GitVcsDriver.layer))), | 139 | Layer.provideMerge(CheckpointStoreLive.pipe(Layer.provide(GitVcsDriver.vcsLayer))), |
| 140 | ); | 140 | ); |
| 141 | 141 | ||
| 142 | const ProviderSessionDirectoryLayerLive = ProviderSessionDirectoryLive.pipe( | 142 | const ProviderSessionDirectoryLayerLive = ProviderSessionDirectoryLive.pipe( |
| @@ -173,7 +173,7 @@ const TerminalLayerLive = TerminalManagerLive.pipe(Layer.provide(PtyAdapterLive) · 30 unmodified lines | |||
| 173 | 173 | ||
| 174 | const WorkspaceEntriesLayerLive = WorkspaceEntriesLive.pipe( | 174 | const WorkspaceEntriesLayerLive = WorkspaceEntriesLive.pipe( |
| 175 | Layer.provide(WorkspacePathsLive), | 175 | Layer.provide(WorkspacePathsLive), |
| 176 | Layer.provideMerge(GitVcsDriver.layer), | 176 | Layer.provideMerge(GitVcsDriver.vcsLayer), |
| 177 | ); | 177 | ); |
| 178 | 178 | ||
| 179 | const WorkspaceFileSystemLayerLive = WorkspaceFileSystemLive.pipe( | 179 | const WorkspaceFileSystemLayerLive = WorkspaceFileSystemLive.pipe( |
| @@ -18,7 +18,7 @@ const GitVcsDriverTestDependencies = ServerConfig.layerTest(process.cwd(), { · 17 unmodified lines | |||
| 18 | prefix: "t3-git-vcs-driver-test-", | 18 | prefix: "t3-git-vcs-driver-test-", |
| 19 | }).pipe(Layer.provide(NodeServices.layer)); | 19 | }).pipe(Layer.provide(NodeServices.layer)); |
| 20 | 20 | ||
| 21 | it.layer(Layer.empty)("GitVcsDriver.layer", (it) => { | 21 | it.layer(Layer.empty)("GitVcsDriver.vcsLayer", (it) => { |
| 22 | describe("workspace helpers", () => { | 22 | describe("workspace helpers", () => { |
| 23 | it.effect("filterIgnoredPaths chunks large path lists and preserves kept paths", () => | 23 | it.effect("filterIgnoredPaths chunks large path lists and preserves kept paths", () => |
| 24 | Effect.gen(function* () { | 24 | Effect.gen(function* () { |
| @@ -32,7 +32,7 @@ it.layer(Layer.empty)("GitVcsDriver.layer", (it) => { · 7 unmodified lines | |||
| 32 | ); | 32 | ); |
| 33 | 33 | ||
| 34 | const seenChunks: string[][] = []; | 34 | const seenChunks: string[][] = []; |
| 35 | const layer = GitVcsDriver.layer.pipe( | 35 | const layer = GitVcsDriver.vcsLayer.pipe( |
| 36 | Layer.provideMerge(GitVcsDriverTestDependencies), | 36 | Layer.provideMerge(GitVcsDriverTestDependencies), |
| 37 | Layer.provideMerge(NodeServices.layer), | 37 | Layer.provideMerge(NodeServices.layer), |
| 38 | Layer.provide( | 38 | Layer.provide( |
| @@ -81,7 +81,7 @@ it.layer(Layer.empty)("GitVcsDriver.layer", (it) => { · 42 unmodified lines | |||
| 81 | 81 | ||
| 82 | it.effect("listWorkspaceFiles disables fsmonitor and untracked cache helpers", () => | 82 | it.effect("listWorkspaceFiles disables fsmonitor and untracked cache helpers", () => |
| 83 | Effect.gen(function* () { | 83 | Effect.gen(function* () { |
| 84 | const layer = GitVcsDriver.layer.pipe( | 84 | const layer = GitVcsDriver.vcsLayer.pipe( |
| 85 | Layer.provideMerge(GitVcsDriverTestDependencies), | 85 | Layer.provideMerge(GitVcsDriverTestDependencies), |
| 86 | Layer.provideMerge(NodeServices.layer), | 86 | Layer.provideMerge(NodeServices.layer), |
| 87 | Layer.provide( | 87 | Layer.provide( |
| @@ -1,10 +1,17 @@ | |||
| 1 | import { DateTime, Effect, Layer } from "effect"; | 1 | import { Context, DateTime, Effect, Layer } from "effect"; |
| 2 | 2 | ||
| 3 | import { VcsProcessExitError } from "@t3tools/contracts"; | 3 | import { VcsProcessExitError } from "@t3tools/contracts"; |
| 4 | import { makeGitCore } from "../git/Layers/GitCore.ts"; | 4 | import { makeGitCore } from "../git/Layers/GitCore.ts"; |
| 5 | import type { GitCoreShape } from "../git/Services/GitCore.ts"; | ||
| 5 | import { VcsDriver, type VcsDriverShape } from "./VcsDriver.ts"; | 6 | import { VcsDriver, type VcsDriverShape } from "./VcsDriver.ts"; |
| 6 | import { VcsProcess, type VcsProcessShape } from "./VcsProcess.ts"; | 7 | import { VcsProcess, type VcsProcessShape } from "./VcsProcess.ts"; |
| 7 | 8 | ||
| 9 | export interface GitVcsDriverShape extends GitCoreShape {} | ||
| 10 | |||
| 11 | export class GitVcsDriver extends Context.Service<GitVcsDriver, GitVcsDriverShape>()( | ||
| 12 | "t3/vcs/GitVcsDriver", | ||
| 13 | ) {} | ||
| 14 | |||
| 8 | const WORKSPACE_FILES_MAX_OUTPUT_BYTES = 16 * 1024 * 1024; | 15 | const WORKSPACE_FILES_MAX_OUTPUT_BYTES = 16 * 1024 * 1024; |
| 9 | const GIT_CHECK_IGNORE_MAX_STDIN_BYTES = 256 * 1024; | 16 | const GIT_CHECK_IGNORE_MAX_STDIN_BYTES = 256 * 1024; |
| 10 | const WORKSPACE_GIT_HARDENED_CONFIG_ARGS = [ | 17 | const WORKSPACE_GIT_HARDENED_CONFIG_ARGS = [ |
| @@ -92,9 +99,8 @@ const gitCommand = ( · 81 unmodified lines | |||
| 92 | : {}), | 99 | : {}), |
| 93 | }); | 100 | }); |
| 94 | 101 | ||
| 95 | export const make = Effect.fn("makeGitVcsDriver")(function* () { | 102 | export const makeVcsDriver = Effect.fn("makeGitVcsDriver")(function* () { |
| 96 | const process = yield* VcsProcess; | 103 | const process = yield* VcsProcess; |
| 97 | const legacyGit = yield* makeGitCore(); | ||
| 98 | const capabilities = { | 104 | const capabilities = { |
| 99 | kind: "git" as const, | 105 | kind: "git" as const, |
| 100 | supportsWorktrees: true, | 106 | supportsWorktrees: true, |
| @@ -243,7 +249,6 @@ export const make = Effect.fn("makeGitVcsDriver")(function* () { · 142 unmodified lines | |||
| 243 | ); | 249 | ); |
| 244 | 250 | ||
| 245 | return VcsDriver.of({ | 251 | return VcsDriver.of({ |
| 246 | ...legacyGit, | ||
| 247 | capabilities, | 252 | capabilities, |
| 248 | execute, | 253 | execute, |
| 249 | detectRepository, | 254 | detectRepository, |
| @@ -253,4 +258,10 @@ export const make = Effect.fn("makeGitVcsDriver")(function* () { · 3 unmodified lines | |||
| 253 | }); | 258 | }); |
| 254 | }); | 259 | }); |
| 255 | 260 | ||
| 256 | export const layer = Layer.effect(VcsDriver, make()); | 261 | export const make = Effect.fn("makeGitVcsDriverService")(function* () { |
| 262 | const legacyGit = yield* makeGitCore(); | ||
| 263 | return GitVcsDriver.of(legacyGit); | ||
| 264 | }); | ||
| 265 | |||
| 266 | export const vcsLayer = Layer.effect(VcsDriver, makeVcsDriver()); | ||
| 267 | export const layer = Layer.effect(GitVcsDriver, make()); | ||
| @@ -6,10 +6,9 @@ import type { · 5 unmodified lines | |||
| 6 | VcsListWorkspaceFilesResult, | 6 | VcsListWorkspaceFilesResult, |
| 7 | VcsRepositoryIdentity, | 7 | VcsRepositoryIdentity, |
| 8 | } from "@t3tools/contracts"; | 8 | } from "@t3tools/contracts"; |
| 9 | import type { GitCoreShape } from "../git/Services/GitCore.ts"; | ||
| 10 | import type { VcsProcessInput, VcsProcessOutput } from "./VcsProcess.ts"; | 9 | import type { VcsProcessInput, VcsProcessOutput } from "./VcsProcess.ts"; |
| 11 | 10 | ||
| 12 | export interface VcsDriverShape extends Omit<GitCoreShape, "execute"> { | 11 | export interface VcsDriverShape { |
| 13 | readonly capabilities: VcsDriverCapabilities; | 12 | readonly capabilities: VcsDriverCapabilities; |
| 14 | readonly execute: ( | 13 | readonly execute: ( |
| 15 | input: Omit<VcsProcessInput, "command">, | 14 | input: Omit<VcsProcessInput, "command">, |
| @@ -15,7 +15,7 @@ const TestLayer = Layer.empty.pipe( · 14 unmodified lines | |||
| 15 | Layer.provideMerge(WorkspaceEntriesLive.pipe(Layer.provide(WorkspacePathsLive))), | 15 | Layer.provideMerge(WorkspaceEntriesLive.pipe(Layer.provide(WorkspacePathsLive))), |
| 16 | Layer.provideMerge(WorkspacePathsLive), | 16 | Layer.provideMerge(WorkspacePathsLive), |
| 17 | Layer.provideMerge(VcsProcess.layer), | 17 | Layer.provideMerge(VcsProcess.layer), |
| 18 | Layer.provideMerge(GitVcsDriver.layer.pipe(Layer.provide(VcsProcess.layer))), | 18 | Layer.provideMerge(GitVcsDriver.vcsLayer.pipe(Layer.provide(VcsProcess.layer))), |
| 19 | Layer.provide( | 19 | Layer.provide( |
| 20 | ServerConfig.layerTest(process.cwd(), { | 20 | ServerConfig.layerTest(process.cwd(), { |
| 21 | prefix: "t3-workspace-entries-test-", | 21 | prefix: "t3-workspace-entries-test-", |
| @@ -20,7 +20,7 @@ const TestLayer = Layer.empty.pipe( · 19 unmodified lines | |||
| 20 | Layer.provideMerge(ProjectLayer), | 20 | Layer.provideMerge(ProjectLayer), |
| 21 | Layer.provideMerge(WorkspaceEntriesLive.pipe(Layer.provide(WorkspacePathsLive))), | 21 | Layer.provideMerge(WorkspaceEntriesLive.pipe(Layer.provide(WorkspacePathsLive))), |
| 22 | Layer.provideMerge(WorkspacePathsLive), | 22 | Layer.provideMerge(WorkspacePathsLive), |
| 23 | Layer.provideMerge(GitVcsDriver.layer.pipe(Layer.provide(VcsProcess.layer))), | 23 | Layer.provideMerge(GitVcsDriver.vcsLayer.pipe(Layer.provide(VcsProcess.layer))), |
| 24 | Layer.provide( | 24 | Layer.provide( |
| 25 | ServerConfig.layerTest(process.cwd(), { | 25 | ServerConfig.layerTest(process.cwd(), { |
| 26 | prefix: "t3-workspace-files-test-", | 26 | prefix: "t3-workspace-files-test-", |
| @@ -49,7 +49,7 @@ import { TerminalManager } from "./terminal/Services/Manager.ts"; · 48 unmodified lines | |||
| 49 | import { WorkspaceEntries } from "./workspace/Services/WorkspaceEntries.ts"; | 49 | import { WorkspaceEntries } from "./workspace/Services/WorkspaceEntries.ts"; |
| 50 | import { WorkspaceFileSystem } from "./workspace/Services/WorkspaceFileSystem.ts"; | 50 | import { WorkspaceFileSystem } from "./workspace/Services/WorkspaceFileSystem.ts"; |
| 51 | import { WorkspacePathOutsideRootError } from "./workspace/Services/WorkspacePaths.ts"; | 51 | import { WorkspacePathOutsideRootError } from "./workspace/Services/WorkspacePaths.ts"; |
| 52 | import { VcsDriver } from "./vcs/VcsDriver.ts"; | 52 | import { GitVcsDriver } from "./vcs/GitVcsDriver.ts"; |
| 53 | import { ProjectSetupScriptRunner } from "./project/Services/ProjectSetupScriptRunner.ts"; | 53 | import { ProjectSetupScriptRunner } from "./project/Services/ProjectSetupScriptRunner.ts"; |
| 54 | import { RepositoryIdentityResolver } from "./project/Services/RepositoryIdentityResolver.ts"; | 54 | import { RepositoryIdentityResolver } from "./project/Services/RepositoryIdentityResolver.ts"; |
| 55 | import { ServerEnvironment } from "./environment/Services/ServerEnvironment.ts"; | 55 | import { ServerEnvironment } from "./environment/Services/ServerEnvironment.ts"; |
| @@ -137,7 +137,7 @@ const makeWsRpcLayer = (currentSessionId: AuthSessionId) => · 81 unmodified lines | |||
| 137 | const keybindings = yield* Keybindings; | 137 | const keybindings = yield* Keybindings; |
| 138 | const open = yield* Open; | 138 | const open = yield* Open; |
| 139 | const gitManager = yield* GitManager; | 139 | const gitManager = yield* GitManager; |
| 140 | const git = yield* VcsDriver; | 140 | const git = yield* GitVcsDriver; |
| 141 | const gitStatusBroadcaster = yield* GitStatusBroadcaster; | 141 | const gitStatusBroadcaster = yield* GitStatusBroadcaster; |
| 142 | const terminalManager = yield* TerminalManager; | 142 | const terminalManager = yield* TerminalManager; |
| 143 | const providerRegistry = yield* ProviderRegistry; | 143 | const providerRegistry = yield* ProviderRegistry; |