| ... | ... | @@ -8378,6 +8378,13 @@ it.layer(NodeServices.layer)("server router seam", (it) => { |
| 8378 | 8378 | bootstrapGitOperations.push("fetch"); |
| 8379 | 8379 | }), |
| 8380 | 8380 | ); |
| 8381 | const remoteBranchExists = vi.fn( |
| 8382 | (_: Parameters<GitVcsDriver.GitVcsDriver["Service"]["remoteBranchExists"]>[0]) => |
| 8383 | Effect.sync(() => { |
| 8384 | bootstrapGitOperations.push("remote-branch-exists"); |
| 8385 | return true; |
| 8386 | }), |
| 8387 | ); |
| 8381 | 8388 | const fetchedOriginCommit = "0123456789abcdef0123456789abcdef01234567"; |
| 8382 | 8389 | const resolveRemoteTrackingCommit = vi.fn( |
| 8383 | 8390 | (_: Parameters<GitVcsDriver.GitVcsDriver["Service"]["resolveRemoteTrackingCommit"]>[0]) => |
| ... | ... | @@ -8421,6 +8428,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { |
| 8421 | 8428 | gitVcsDriver: { |
| 8422 | 8429 | remoteExists, |
| 8423 | 8430 | fetchRemote, |
| 8431 | remoteBranchExists, |
| 8424 | 8432 | resolveRemoteTrackingCommit, |
| 8425 | 8433 | createWorktree, |
| 8426 | 8434 | }, |
| ... | ... | @@ -8504,6 +8512,11 @@ it.layer(NodeServices.layer)("server router seam", (it) => { |
| 8504 | 8512 | cwd: "/tmp/project", |
| 8505 | 8513 | remoteName: "origin", |
| 8506 | 8514 | }); |
| 8515 | assert.deepEqual(remoteBranchExists.mock.calls[0]?.[0], { |
| 8516 | cwd: "/tmp/project", |
| 8517 | remoteName: "origin", |
| 8518 | refName: "main", |
| 8519 | }); |
| 8507 | 8520 | assert.deepEqual(resolveRemoteTrackingCommit.mock.calls[0]?.[0], { |
| 8508 | 8521 | cwd: "/tmp/project", |
| 8509 | 8522 | refName: "main", |
| ... | ... | @@ -8512,6 +8525,7 @@ it.layer(NodeServices.layer)("server router seam", (it) => { |
| 8512 | 8525 | assert.deepEqual(bootstrapGitOperations, [ |
| 8513 | 8526 | "remote-exists", |
| 8514 | 8527 | "fetch", |
| 8528 | "remote-branch-exists", |
| 8515 | 8529 | "resolve-remote-commit", |
| 8516 | 8530 | "create-worktree", |
| 8517 | 8531 | ]); |
| ... | ... | @@ -8539,108 +8553,122 @@ it.layer(NodeServices.layer)("server router seam", (it) => { |
| 8539 | 8553 | }).pipe(Effect.provide(NodeHttpServer.layerTest)), |
| 8540 | 8554 | ); |
| 8541 | 8555 | |
| 8542 | | it.effect( |
| 8543 | | "falls back to the local base branch when startFromOrigin is set but no origin remote exists", |
| 8544 | | () => |
| 8545 | | Effect.gen(function* () { |
| 8546 | | const dispatchedCommands: Array<OrchestrationCommand> = []; |
| 8547 | | const remoteExists = vi.fn( |
| 8548 | | (_: Parameters<GitVcsDriver.GitVcsDriver["Service"]["remoteExists"]>[0]) => |
| 8549 | | Effect.succeed(false), |
| 8550 | | ); |
| 8551 | | const fetchRemote = vi.fn( |
| 8552 | | (_: Parameters<GitVcsDriver.GitVcsDriver["Service"]["fetchRemote"]>[0]) => Effect.void, |
| 8553 | | ); |
| 8554 | | const resolveRemoteTrackingCommit = vi.fn( |
| 8555 | | (_: Parameters<GitVcsDriver.GitVcsDriver["Service"]["resolveRemoteTrackingCommit"]>[0]) => |
| 8556 | | Effect.succeed({ |
| 8557 | | commitSha: "0123456789abcdef0123456789abcdef01234567", |
| 8558 | | remoteRefName: "origin/main", |
| 8559 | | }), |
| 8560 | | ); |
| 8561 | | const createWorktree = vi.fn( |
| 8562 | | (_: Parameters<GitVcsDriver.GitVcsDriver["Service"]["createWorktree"]>[0]) => |
| 8563 | | Effect.succeed({ |
| 8564 | | worktree: { |
| 8565 | | refName: "t3code/bootstrap-refName", |
| 8566 | | path: "/tmp/bootstrap-worktree", |
| 8567 | | }, |
| 8568 | | }), |
| 8569 | | ); |
| 8570 | | |
| 8571 | | yield* buildAppUnderTest({ |
| 8572 | | layers: { |
| 8573 | | gitVcsDriver: { |
| 8574 | | remoteExists, |
| 8575 | | fetchRemote, |
| 8576 | | resolveRemoteTrackingCommit, |
| 8577 | | createWorktree, |
| 8578 | | }, |
| 8579 | | orchestrationEngine: { |
| 8580 | | dispatch: (command) => |
| 8581 | | Effect.sync(() => { |
| 8582 | | dispatchedCommands.push(command); |
| 8583 | | return { sequence: dispatchedCommands.length }; |
| 8584 | | }), |
| 8585 | | readEvents: () => Stream.empty, |
| 8556 | it.effect.each([ |
| 8557 | { caseName: "the origin remote is missing", hasOrigin: false }, |
| 8558 | { caseName: "the base branch exists only locally", hasOrigin: true }, |
| 8559 | ])("falls back to the local base branch when $caseName", ({ hasOrigin }) => |
| 8560 | Effect.gen(function* () { |
| 8561 | const dispatchedCommands: Array<OrchestrationCommand> = []; |
| 8562 | const remoteExists = vi.fn( |
| 8563 | (_: Parameters<GitVcsDriver.GitVcsDriver["Service"]["remoteExists"]>[0]) => |
| 8564 | Effect.succeed(hasOrigin), |
| 8565 | ); |
| 8566 | const fetchRemote = vi.fn( |
| 8567 | (_: Parameters<GitVcsDriver.GitVcsDriver["Service"]["fetchRemote"]>[0]) => Effect.void, |
| 8568 | ); |
| 8569 | const resolveRemoteTrackingCommit = vi.fn( |
| 8570 | (_: Parameters<GitVcsDriver.GitVcsDriver["Service"]["resolveRemoteTrackingCommit"]>[0]) => |
| 8571 | Effect.succeed({ |
| 8572 | commitSha: "0123456789abcdef0123456789abcdef01234567", |
| 8573 | remoteRefName: "origin/main", |
| 8574 | }), |
| 8575 | ); |
| 8576 | const remoteBranchExists = vi.fn( |
| 8577 | (_: Parameters<GitVcsDriver.GitVcsDriver["Service"]["remoteBranchExists"]>[0]) => |
| 8578 | Effect.succeed(false), |
| 8579 | ); |
| 8580 | const createWorktree = vi.fn( |
| 8581 | (_: Parameters<GitVcsDriver.GitVcsDriver["Service"]["createWorktree"]>[0]) => |
| 8582 | Effect.succeed({ |
| 8583 | worktree: { |
| 8584 | refName: "t3code/bootstrap-refName", |
| 8585 | path: "/tmp/bootstrap-worktree", |
| 8586 | 8586 | }, |
| 8587 | }), |
| 8588 | ); |
| 8589 | |
| 8590 | yield* buildAppUnderTest({ |
| 8591 | layers: { |
| 8592 | gitVcsDriver: { |
| 8593 | remoteExists, |
| 8594 | fetchRemote, |
| 8595 | remoteBranchExists, |
| 8596 | resolveRemoteTrackingCommit, |
| 8597 | createWorktree, |
| 8587 | 8598 | }, |
| 8588 | | }); |
| 8599 | orchestrationEngine: { |
| 8600 | dispatch: (command) => |
| 8601 | Effect.sync(() => { |
| 8602 | dispatchedCommands.push(command); |
| 8603 | return { sequence: dispatchedCommands.length }; |
| 8604 | }), |
| 8605 | readEvents: () => Stream.empty, |
| 8606 | }, |
| 8607 | }, |
| 8608 | }); |
| 8589 | 8609 | |
| 8590 | | const createdAt = "2026-01-01T00:00:00.000Z"; |
| 8591 | | const wsUrl = yield* getWsServerUrl("/ws"); |
| 8592 | | yield* Effect.scoped( |
| 8593 | | withWsRpcClient(wsUrl, (client) => |
| 8594 | | client[ORCHESTRATION_WS_METHODS.dispatchCommand]({ |
| 8595 | | type: "thread.turn.start", |
| 8596 | | commandId: CommandId.make("cmd-bootstrap-turn-start-no-origin"), |
| 8597 | | threadId: ThreadId.make("thread-bootstrap-no-origin"), |
| 8598 | | message: { |
| 8599 | | messageId: MessageId.make("msg-bootstrap-no-origin"), |
| 8600 | | role: "user", |
| 8601 | | text: "hello", |
| 8602 | | attachments: [], |
| 8610 | const createdAt = "2026-01-01T00:00:00.000Z"; |
| 8611 | const wsUrl = yield* getWsServerUrl("/ws"); |
| 8612 | yield* Effect.scoped( |
| 8613 | withWsRpcClient(wsUrl, (client) => |
| 8614 | client[ORCHESTRATION_WS_METHODS.dispatchCommand]({ |
| 8615 | type: "thread.turn.start", |
| 8616 | commandId: CommandId.make("cmd-bootstrap-turn-start-no-origin"), |
| 8617 | threadId: ThreadId.make("thread-bootstrap-no-origin"), |
| 8618 | message: { |
| 8619 | messageId: MessageId.make("msg-bootstrap-no-origin"), |
| 8620 | role: "user", |
| 8621 | text: "hello", |
| 8622 | attachments: [], |
| 8623 | }, |
| 8624 | modelSelection: defaultModelSelection, |
| 8625 | runtimeMode: "full-access", |
| 8626 | interactionMode: "default", |
| 8627 | bootstrap: { |
| 8628 | createThread: { |
| 8629 | projectId: defaultProjectId, |
| 8630 | title: "Bootstrap Thread", |
| 8631 | modelSelection: defaultModelSelection, |
| 8632 | runtimeMode: "full-access", |
| 8633 | interactionMode: "default", |
| 8634 | branch: "main", |
| 8635 | worktreePath: null, |
| 8636 | createdAt, |
| 8603 | 8637 | }, |
| 8604 | | modelSelection: defaultModelSelection, |
| 8605 | | runtimeMode: "full-access", |
| 8606 | | interactionMode: "default", |
| 8607 | | bootstrap: { |
| 8608 | | createThread: { |
| 8609 | | projectId: defaultProjectId, |
| 8610 | | title: "Bootstrap Thread", |
| 8611 | | modelSelection: defaultModelSelection, |
| 8612 | | runtimeMode: "full-access", |
| 8613 | | interactionMode: "default", |
| 8614 | | branch: "main", |
| 8615 | | worktreePath: null, |
| 8616 | | createdAt, |
| 8617 | | }, |
| 8618 | | prepareWorktree: { |
| 8619 | | projectCwd: "/tmp/project", |
| 8620 | | baseBranch: "main", |
| 8621 | | branch: "t3code/bootstrap-refName", |
| 8622 | | startFromOrigin: true, |
| 8623 | | }, |
| 8638 | prepareWorktree: { |
| 8639 | projectCwd: "/tmp/project", |
| 8640 | baseBranch: "main", |
| 8641 | branch: "t3code/bootstrap-refName", |
| 8642 | startFromOrigin: true, |
| 8624 | 8643 | }, |
| 8625 | | createdAt, |
| 8626 | | }), |
| 8627 | | ), |
| 8628 | | ); |
| 8644 | }, |
| 8645 | createdAt, |
| 8646 | }), |
| 8647 | ), |
| 8648 | ); |
| 8629 | 8649 | |
| 8630 | | assert.deepEqual(remoteExists.mock.calls[0]?.[0], { |
| 8650 | assert.deepEqual(remoteExists.mock.calls[0]?.[0], { |
| 8651 | cwd: "/tmp/project", |
| 8652 | remoteName: "origin", |
| 8653 | }); |
| 8654 | assert.equal(fetchRemote.mock.calls.length, hasOrigin ? 1 : 0); |
| 8655 | assert.equal(remoteBranchExists.mock.calls.length, hasOrigin ? 1 : 0); |
| 8656 | if (hasOrigin) { |
| 8657 | assert.deepEqual(remoteBranchExists.mock.calls[0]?.[0], { |
| 8631 | 8658 | cwd: "/tmp/project", |
| 8632 | 8659 | remoteName: "origin", |
| 8633 | | }); |
| 8634 | | assert.equal(fetchRemote.mock.calls.length, 0); |
| 8635 | | assert.equal(resolveRemoteTrackingCommit.mock.calls.length, 0); |
| 8636 | | assert.deepEqual(createWorktree.mock.calls[0]?.[0], { |
| 8637 | | cwd: "/tmp/project", |
| 8638 | 8660 | refName: "main", |
| 8639 | | newRefName: "t3code/bootstrap-refName", |
| 8640 | | baseRefName: "main", |
| 8641 | | path: null, |
| 8642 | 8661 | }); |
| 8643 | | }).pipe(Effect.provide(NodeHttpServer.layerTest)), |
| 8662 | } |
| 8663 | assert.equal(resolveRemoteTrackingCommit.mock.calls.length, 0); |
| 8664 | assert.deepEqual(createWorktree.mock.calls[0]?.[0], { |
| 8665 | cwd: "/tmp/project", |
| 8666 | refName: "main", |
| 8667 | newRefName: "t3code/bootstrap-refName", |
| 8668 | baseRefName: "main", |
| 8669 | path: null, |
| 8670 | }); |
| 8671 | }).pipe(Effect.provide(NodeHttpServer.layerTest)), |
| 8644 | 8672 | ); |
| 8645 | 8673 | |
| 8646 | 8674 | it.effect("records setup-script failures without aborting bootstrap turn start", () => |