| author | |
| committer | |
| log | 9dcea68bce25e1c30be7a6439bfe607b236740a0 |
| tree | 1538eda948b6476fcd5952b6e8022e4588e4990c |
| parent | 5f7ec73a22b28e2775987b03a744f75e5e151152 |
| signature | Signed by PGP key B5690EEEBB952194 |
4 files changed, 70 insertions(+), 1 deletions(-)
apps/server/src/orchestration/Layers/ProviderCommandReactor.test.ts+34| ... | @@ -27,6 +27,10 @@ import { | ... | @@ -27,6 +27,10 @@ import { |
| 27 | type ProviderServiceShape, | 27 | type ProviderServiceShape, |
| 28 | } from "../../provider/Services/ProviderService.ts"; | 28 | } from "../../provider/Services/ProviderService.ts"; |
| 29 | import { GitCore, type GitCoreShape } from "../../git/Services/GitCore.ts"; | 29 | import { GitCore, type GitCoreShape } from "../../git/Services/GitCore.ts"; |
| 30 | import { | ||
| 31 | GitStatusBroadcaster, | ||
| 32 | type GitStatusBroadcasterShape, | ||
| 33 | } from "../../git/Services/GitStatusBroadcaster.ts"; | ||
| 30 | import { TextGeneration, type TextGenerationShape } from "../../git/Services/TextGeneration.ts"; | 34 | import { TextGeneration, type TextGenerationShape } from "../../git/Services/TextGeneration.ts"; |
| 31 | import { RepositoryIdentityResolverLive } from "../../project/Layers/RepositoryIdentityResolver.ts"; | 35 | import { RepositoryIdentityResolverLive } from "../../project/Layers/RepositoryIdentityResolver.ts"; |
| 32 | import { OrchestrationEngineLive } from "./OrchestrationEngine.ts"; | 36 | import { OrchestrationEngineLive } from "./OrchestrationEngine.ts"; |
| ... | @@ -177,6 +181,24 @@ describe("ProviderCommandReactor", () => { | ... | @@ -177,6 +181,24 @@ describe("ProviderCommandReactor", () => { |
| 177 | : "renamed-branch", | 181 | : "renamed-branch", |
| 178 | }), | 182 | }), |
| 179 | ); | 183 | ); |
| 184 | const refreshStatus = vi.fn((_: string) => | ||
| 185 | Effect.succeed({ | ||
| 186 | isRepo: true, | ||
| 187 | hasOriginRemote: true, | ||
| 188 | isDefaultBranch: false, | ||
| 189 | branch: "renamed-branch", | ||
| 190 | hasWorkingTreeChanges: false, | ||
| 191 | workingTree: { | ||
| 192 | files: [], | ||
| 193 | insertions: 0, | ||
| 194 | deletions: 0, | ||
| 195 | }, | ||
| 196 | hasUpstream: true, | ||
| 197 | aheadCount: 0, | ||
| 198 | behindCount: 0, | ||
| 199 | pr: null, | ||
| 200 | }), | ||
| 201 | ); | ||
| 180 | const generateBranchName = vi.fn<TextGenerationShape["generateBranchName"]>((_) => | 202 | const generateBranchName = vi.fn<TextGenerationShape["generateBranchName"]>((_) => |
| 181 | Effect.fail( | 203 | Effect.fail( |
| 182 | new TextGenerationError({ | 204 | new TextGenerationError({ |
| ... | @@ -225,6 +247,15 @@ describe("ProviderCommandReactor", () => { | ... | @@ -225,6 +247,15 @@ describe("ProviderCommandReactor", () => { |
| 225 | Layer.provideMerge(orchestrationLayer), | 247 | Layer.provideMerge(orchestrationLayer), |
| 226 | Layer.provideMerge(Layer.succeed(ProviderService, service)), | 248 | Layer.provideMerge(Layer.succeed(ProviderService, service)), |
| 227 | Layer.provideMerge(Layer.succeed(GitCore, { renameBranch } as unknown as GitCoreShape)), | 249 | Layer.provideMerge(Layer.succeed(GitCore, { renameBranch } as unknown as GitCoreShape)), |
| 250 | Layer.provideMerge( | ||
| 251 | Layer.succeed(GitStatusBroadcaster, { | ||
| 252 | getStatus: () => Effect.die("getStatus should not be called in this test"), | ||
| 253 | refreshLocalStatus: () => | ||
| 254 | Effect.die("refreshLocalStatus should not be called in this test"), | ||
| 255 | refreshStatus, | ||
| 256 | streamStatus: () => Stream.die("streamStatus should not be called in this test"), | ||
| 257 | } satisfies GitStatusBroadcasterShape), | ||
| 258 | ), | ||
| 228 | Layer.provideMerge( | 259 | Layer.provideMerge( |
| 229 | Layer.mock(TextGeneration, { | 260 | Layer.mock(TextGeneration, { |
| 230 | generateBranchName, | 261 | generateBranchName, |
| ... | @@ -279,6 +310,7 @@ describe("ProviderCommandReactor", () => { | ... | @@ -279,6 +310,7 @@ describe("ProviderCommandReactor", () => { |
| 279 | respondToUserInput, | 310 | respondToUserInput, |
| 280 | stopSession, | 311 | stopSession, |
| 281 | renameBranch, | 312 | renameBranch, |
| 313 | refreshStatus, | ||
| 282 | generateBranchName, | 314 | generateBranchName, |
| 283 | generateThreadTitle, | 315 | generateThreadTitle, |
| 284 | stateDir, | 316 | stateDir, |
| ... | @@ -513,9 +545,11 @@ describe("ProviderCommandReactor", () => { | ... | @@ -513,9 +545,11 @@ describe("ProviderCommandReactor", () => { |
| 513 | ); | 545 | ); |
| 514 | 546 | ||
| 515 | await waitFor(() => harness.generateBranchName.mock.calls.length === 1); | 547 | await waitFor(() => harness.generateBranchName.mock.calls.length === 1); |
| 548 | await waitFor(() => harness.refreshStatus.mock.calls.length === 1); | ||
| 516 | expect(harness.generateBranchName.mock.calls[0]?.[0]).toMatchObject({ | 549 | expect(harness.generateBranchName.mock.calls[0]?.[0]).toMatchObject({ |
| 517 | message: "Add a safer reconnect backoff.", | 550 | message: "Add a safer reconnect backoff.", |
| 518 | }); | 551 | }); |
| 552 | expect(harness.refreshStatus.mock.calls[0]?.[0]).toBe("/tmp/provider-project-worktree"); | ||
| 519 | }); | 553 | }); |
| 520 | 554 | ||
| 521 | it("forwards codex model options through session start and turn send", async () => { | 555 | it("forwards codex model options through session start and turn send", async () => { |
apps/server/src/orchestration/Layers/ProviderCommandReactor.ts+3| ... | @@ -17,6 +17,7 @@ import { makeDrainableWorker } from "@t3tools/shared/DrainableWorker"; | ... | @@ -17,6 +17,7 @@ import { makeDrainableWorker } from "@t3tools/shared/DrainableWorker"; |
| 17 | 17 | ||
| 18 | import { resolveThreadWorkspaceCwd } from "../../checkpointing/Utils.ts"; | 18 | import { resolveThreadWorkspaceCwd } from "../../checkpointing/Utils.ts"; |
| 19 | import { GitCore } from "../../git/Services/GitCore.ts"; | 19 | import { GitCore } from "../../git/Services/GitCore.ts"; |
| 20 | import { GitStatusBroadcaster } from "../../git/Services/GitStatusBroadcaster.ts"; | ||
| 20 | import { increment, orchestrationEventsProcessedTotal } from "../../observability/Metrics.ts"; | 21 | import { increment, orchestrationEventsProcessedTotal } from "../../observability/Metrics.ts"; |
| 21 | import { ProviderAdapterRequestError, ProviderServiceError } from "../../provider/Errors.ts"; | 22 | import { ProviderAdapterRequestError, ProviderServiceError } from "../../provider/Errors.ts"; |
| 22 | import { TextGeneration } from "../../git/Services/TextGeneration.ts"; | 23 | import { TextGeneration } from "../../git/Services/TextGeneration.ts"; |
| ... | @@ -145,6 +146,7 @@ const make = Effect.gen(function* () { | ... | @@ -145,6 +146,7 @@ const make = Effect.gen(function* () { |
| 145 | const orchestrationEngine = yield* OrchestrationEngineService; | 146 | const orchestrationEngine = yield* OrchestrationEngineService; |
| 146 | const providerService = yield* ProviderService; | 147 | const providerService = yield* ProviderService; |
| 147 | const git = yield* GitCore; | 148 | const git = yield* GitCore; |
| 149 | const gitStatusBroadcaster = yield* GitStatusBroadcaster; | ||
| 148 | const textGeneration = yield* TextGeneration; | 150 | const textGeneration = yield* TextGeneration; |
| 149 | const serverSettingsService = yield* ServerSettingsService; | 151 | const serverSettingsService = yield* ServerSettingsService; |
| 150 | const handledTurnStartKeys = yield* Cache.make<string, true>({ | 152 | const handledTurnStartKeys = yield* Cache.make<string, true>({ |
| ... | @@ -447,6 +449,7 @@ const make = Effect.gen(function* () { | ... | @@ -447,6 +449,7 @@ const make = Effect.gen(function* () { |
| 447 | branch: renamed.branch, | 449 | branch: renamed.branch, |
| 448 | worktreePath: cwd, | 450 | worktreePath: cwd, |
| 449 | }); | 451 | }); |
| 452 | yield* gitStatusBroadcaster.refreshStatus(cwd).pipe(Effect.ignoreCause({ log: true })); | ||
| 450 | }).pipe( | 453 | }).pipe( |
| 451 | Effect.catchCause((cause) => | 454 | Effect.catchCause((cause) => |
| 452 | Effect.logWarning("provider command reactor failed to generate or rename worktree branch", { | 455 | Effect.logWarning("provider command reactor failed to generate or rename worktree branch", { |
apps/server/src/server.test.ts+32-1| ... | @@ -58,6 +58,10 @@ import { | ... | @@ -58,6 +58,10 @@ import { |
| 58 | import { GitCore, type GitCoreShape } from "./git/Services/GitCore.ts"; | 58 | import { GitCore, type GitCoreShape } from "./git/Services/GitCore.ts"; |
| 59 | import { GitManager, type GitManagerShape } from "./git/Services/GitManager.ts"; | 59 | import { GitManager, type GitManagerShape } from "./git/Services/GitManager.ts"; |
| 60 | import { GitStatusBroadcasterLive } from "./git/Layers/GitStatusBroadcaster.ts"; | 60 | import { GitStatusBroadcasterLive } from "./git/Layers/GitStatusBroadcaster.ts"; |
| 61 | import { | ||
| 62 | GitStatusBroadcaster, | ||
| 63 | type GitStatusBroadcasterShape, | ||
| 64 | } from "./git/Services/GitStatusBroadcaster.ts"; | ||
| 61 | import { Keybindings, type KeybindingsShape } from "./keybindings.ts"; | 65 | import { Keybindings, type KeybindingsShape } from "./keybindings.ts"; |
| 62 | import { Open, type OpenShape } from "./open.ts"; | 66 | import { Open, type OpenShape } from "./open.ts"; |
| 63 | import { | 67 | import { |
| ... | @@ -293,6 +297,7 @@ const buildAppUnderTest = (options?: { | ... | @@ -293,6 +297,7 @@ const buildAppUnderTest = (options?: { |
| 293 | open?: Partial<OpenShape>; | 297 | open?: Partial<OpenShape>; |
| 294 | gitCore?: Partial<GitCoreShape>; | 298 | gitCore?: Partial<GitCoreShape>; |
| 295 | gitManager?: Partial<GitManagerShape>; | 299 | gitManager?: Partial<GitManagerShape>; |
| 300 | gitStatusBroadcaster?: Partial<GitStatusBroadcasterShape>; | ||
| 296 | projectSetupScriptRunner?: Partial<ProjectSetupScriptRunnerShape>; | 301 | projectSetupScriptRunner?: Partial<ProjectSetupScriptRunnerShape>; |
| 297 | terminalManager?: Partial<TerminalManagerShape>; | 302 | terminalManager?: Partial<TerminalManagerShape>; |
| 298 | orchestrationEngine?: Partial<OrchestrationEngineShape>; | 303 | orchestrationEngine?: Partial<OrchestrationEngineShape>; |
| ... | @@ -341,7 +346,11 @@ const buildAppUnderTest = (options?: { | ... | @@ -341,7 +346,11 @@ const buildAppUnderTest = (options?: { |
| 341 | const gitManagerLayer = Layer.mock(GitManager)({ | 346 | const gitManagerLayer = Layer.mock(GitManager)({ |
| 342 | ...options?.layers?.gitManager, | 347 | ...options?.layers?.gitManager, |
| 343 | }); | 348 | }); |
| 344 | const gitStatusBroadcasterLayer = GitStatusBroadcasterLive.pipe(Layer.provide(gitManagerLayer)); | 349 | const gitStatusBroadcasterLayer = options?.layers?.gitStatusBroadcaster |
| 350 | ? Layer.mock(GitStatusBroadcaster)({ | ||
| 351 | ...options.layers.gitStatusBroadcaster, | ||
| 352 | }) | ||
| 353 | : GitStatusBroadcasterLive.pipe(Layer.provide(gitManagerLayer)); | ||
| 345 | 354 | ||
| 346 | const servedRoutesLayer = HttpRouter.serve(makeRoutesLayer, { | 355 | const servedRoutesLayer = HttpRouter.serve(makeRoutesLayer, { |
| 347 | disableListenLog: true, | 356 | disableListenLog: true, |
| ... | @@ -2913,6 +2922,24 @@ it.layer(NodeServices.layer)("server router seam", (it) => { | ... | @@ -2913,6 +2922,24 @@ it.layer(NodeServices.layer)("server router seam", (it) => { |
| 2913 | () => | 2922 | () => |
| 2914 | Effect.gen(function* () { | 2923 | Effect.gen(function* () { |
| 2915 | const dispatchedCommands: Array<OrchestrationCommand> = []; | 2924 | const dispatchedCommands: Array<OrchestrationCommand> = []; |
| 2925 | const refreshStatus = vi.fn((_: string) => | ||
| 2926 | Effect.succeed({ | ||
| 2927 | isRepo: true, | ||
| 2928 | hasOriginRemote: true, | ||
| 2929 | isDefaultBranch: false, | ||
| 2930 | branch: "t3code/bootstrap-branch", | ||
| 2931 | hasWorkingTreeChanges: false, | ||
| 2932 | workingTree: { | ||
| 2933 | files: [], | ||
| 2934 | insertions: 0, | ||
| 2935 | deletions: 0, | ||
| 2936 | }, | ||
| 2937 | hasUpstream: true, | ||
| 2938 | aheadCount: 0, | ||
| 2939 | behindCount: 0, | ||
| 2940 | pr: null, | ||
| 2941 | }), | ||
| 2942 | ); | ||
| 2916 | const createWorktree = vi.fn((_: Parameters<GitCoreShape["createWorktree"]>[0]) => | 2943 | const createWorktree = vi.fn((_: Parameters<GitCoreShape["createWorktree"]>[0]) => |
| 2917 | Effect.succeed({ | 2944 | Effect.succeed({ |
| 2918 | worktree: { | 2945 | worktree: { |
| ... | @@ -2937,6 +2964,9 @@ it.layer(NodeServices.layer)("server router seam", (it) => { | ... | @@ -2937,6 +2964,9 @@ it.layer(NodeServices.layer)("server router seam", (it) => { |
| 2937 | gitCore: { | 2964 | gitCore: { |
| 2938 | createWorktree, | 2965 | createWorktree, |
| 2939 | }, | 2966 | }, |
| 2967 | gitStatusBroadcaster: { | ||
| 2968 | refreshStatus, | ||
| 2969 | }, | ||
| 2940 | orchestrationEngine: { | 2970 | orchestrationEngine: { |
| 2941 | dispatch: (command) => | 2971 | dispatch: (command) => |
| 2942 | Effect.sync(() => { | 2972 | Effect.sync(() => { |
| ... | @@ -3014,6 +3044,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { | ... | @@ -3014,6 +3044,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { |
| 3014 | projectCwd: "/tmp/project", | 3044 | projectCwd: "/tmp/project", |
| 3015 | worktreePath: "/tmp/bootstrap-worktree", | 3045 | worktreePath: "/tmp/bootstrap-worktree", |
| 3016 | }); | 3046 | }); |
| 3047 | assert.deepEqual(refreshStatus.mock.calls[0]?.[0], "/tmp/bootstrap-worktree"); | ||
| 3017 | 3048 | ||
| 3018 | const setupActivities = dispatchedCommands.filter( | 3049 | const setupActivities = dispatchedCommands.filter( |
| 3019 | (command): command is Extract<OrchestrationCommand, { type: "thread.activity.append" }> => | 3050 | (command): command is Extract<OrchestrationCommand, { type: "thread.activity.append" }> => |
apps/server/src/ws.ts+1| ... | @@ -464,6 +464,7 @@ const makeWsRpcLayer = (currentSessionId: AuthSessionId) => | ... | @@ -464,6 +464,7 @@ const makeWsRpcLayer = (currentSessionId: AuthSessionId) => |
| 464 | branch: worktree.worktree.branch, | 464 | branch: worktree.worktree.branch, |
| 465 | worktreePath: targetWorktreePath, | 465 | worktreePath: targetWorktreePath, |
| 466 | }); | 466 | }); |
| 467 | yield* refreshGitStatus(targetWorktreePath); | ||
| 467 | } | 468 | } |
| 468 | 469 | ||
| 469 | yield* runSetupProgram(); | 470 | yield* runSetupProgram(); |