| ... | @@ -534,3 +534,93 @@ it.effect("settles only the stopped run's background work, once", () => | ... | @@ -534,3 +534,93 @@ it.effect("settles only the stopped run's background work, once", () => |
| 534 | ]); | 534 | ]); |
| 535 | }).pipe(Effect.provide(testLayer)), | 535 | }).pipe(Effect.provide(testLayer)), |
| 536 | ); | 536 | ); |
| | 537 | |
| | 538 | it.effect("keeps delegated child pull-request links independent of the parent", () => |
| | 539 | Effect.gen(function* () { |
| | 540 | const orchestrator = yield* Orchestrator.OrchestratorV2; |
| | 541 | const projections = yield* ProjectionStore.ProjectionStoreV2; |
| | 542 | const parentThreadId = ThreadId.make("thread:parent-pr"); |
| | 543 | const projectId = ProjectId.make("project:parent-pr"); |
| | 544 | const parentPullRequest = { |
| | 545 | projectId, |
| | 546 | repository: "pingdotgg/t3code", |
| | 547 | number: 123, |
| | 548 | url: "https://github.com/pingdotgg/t3code/pull/123", |
| | 549 | }; |
| | 550 | yield* orchestrator.dispatch({ |
| | 551 | type: "thread.create", |
| | 552 | commandId: CommandId.make("create-parent-pr"), |
| | 553 | threadId: parentThreadId, |
| | 554 | projectId, |
| | 555 | title: "Parent with a linked PR", |
| | 556 | modelSelection, |
| | 557 | runtimeMode: "full-access", |
| | 558 | interactionMode: "default", |
| | 559 | branch: "feature/parent-pr", |
| | 560 | worktreePath: "/repo-worktree", |
| | 561 | createdBy: "user", |
| | 562 | creationSource: "web", |
| | 563 | }); |
| | 564 | yield* orchestrator.dispatch({ |
| | 565 | type: "thread.metadata.update", |
| | 566 | commandId: CommandId.make("link-parent-pr"), |
| | 567 | threadId: parentThreadId, |
| | 568 | linkedPullRequest: parentPullRequest, |
| | 569 | }); |
| | 570 | yield* orchestrator.dispatch({ |
| | 571 | type: "message.dispatch", |
| | 572 | commandId: CommandId.make("start-parent-pr"), |
| | 573 | threadId: parentThreadId, |
| | 574 | messageId: MessageId.make("message:parent-pr"), |
| | 575 | text: "Delegate a review", |
| | 576 | attachments: [], |
| | 577 | dispatchMode: { type: "start_immediately" }, |
| | 578 | createdBy: "user", |
| | 579 | creationSource: "web", |
| | 580 | }); |
| | 581 | const parent = yield* projections.getThreadProjection(parentThreadId); |
| | 582 | const parentRun = parent.runs[0]!; |
| | 583 | yield* orchestrator.dispatch({ |
| | 584 | type: "delegated_task.request", |
| | 585 | commandId: CommandId.make("delegate-parent-pr"), |
| | 586 | parentThreadId, |
| | 587 | parentRunId: parentRun.id, |
| | 588 | parentNodeId: parentRun.rootNodeId!, |
| | 589 | task: "Review the changes", |
| | 590 | modelSelection, |
| | 591 | runtimeMode: "full-access", |
| | 592 | interactionMode: "default", |
| | 593 | createdBy: "agent", |
| | 594 | creationSource: "mcp", |
| | 595 | }); |
| | 596 | const updatedParent = yield* projections.getThreadProjection(parentThreadId); |
| | 597 | const childThreadId = updatedParent.subagents[0]!.childThreadId!; |
| | 598 | const child = yield* projections.getThreadProjection(childThreadId); |
| | 599 | assert.isNull(child.thread.linkedPullRequest); |
| | 600 | assert.deepEqual(child.thread.pullRequests, []); |
| | 601 | assert.equal(child.thread.branch, parent.thread.branch); |
| | 602 | assert.equal(child.thread.worktreePath, parent.thread.worktreePath); |
| | 603 | assert.equal(child.thread.lineage.parentThreadId, parentThreadId); |
| | 604 | |
| | 605 | const childPullRequest = { |
| | 606 | ...parentPullRequest, |
| | 607 | number: 456, |
| | 608 | url: "https://github.com/pingdotgg/t3code/pull/456", |
| | 609 | }; |
| | 610 | yield* orchestrator.dispatch({ |
| | 611 | type: "thread.metadata.update", |
| | 612 | commandId: CommandId.make("link-child-pr"), |
| | 613 | threadId: childThreadId, |
| | 614 | linkedPullRequest: childPullRequest, |
| | 615 | }); |
| | 616 | const linkedChild = yield* projections.getThreadProjection(childThreadId); |
| | 617 | assert.deepEqual(linkedChild.thread.linkedPullRequest, childPullRequest); |
| | 618 | assert.deepEqual( |
| | 619 | linkedChild.thread.pullRequests?.map((link) => link.number), |
| | 620 | [456], |
| | 621 | ); |
| | 622 | const parentAfterChildLink = yield* projections.getThreadProjection(parentThreadId); |
| | 623 | assert.deepEqual(parentAfterChildLink.thread.linkedPullRequest, parentPullRequest); |
| | 624 | assert.deepEqual(parentAfterChildLink.thread.pullRequests, parent.thread.pullRequests); |
| | 625 | }).pipe(Effect.provide(testLayer)), |
| | 626 | ); |