Skip to content

fix(pr-merge): resolve repo from the project checkout, not process.cwd(), in PR-mode auto-merge#2281

Merged
gsxdsm merged 6 commits into
Runfusion:mainfrom
Tchori-Labs:fix/gh-4-pr-merge-repo-resolution
Jul 18, 2026
Merged

fix(pr-merge): resolve repo from the project checkout, not process.cwd(), in PR-mode auto-merge#2281
gsxdsm merged 6 commits into
Runfusion:mainfrom
Tchori-Labs:fix/gh-4-pr-merge-repo-resolution

Conversation

@VictorCano

@VictorCano VictorCano commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Summary

In a centrally-installed, multi-project Fusion server (one process serving several repos, process.cwd() = the install dir, not any repo), every task under mergeStrategy: "pull-request" fails at the auto-merge stage with:

Could not determine repository. Specify owner/repo in params or run from a git repository with a GitHub remote.

PR creation from the dashboard and status polling work; only the engine's automatic PR path fails. This is the non-workspace sibling of #1924 (FN-7610 routed workspace-mode tasks to direct merge but does not cover regular multi-project tasks) and the completion of #1797/FN-7133 (which fixed only the getPrMergeStatus arguments).

Root cause

GitHubClient.resolveRepo() (packages/dashboard/src/github.ts) falls back to a cwd-less getCurrentRepo() — i.e. git remote get-url origin in process.cwd() — whenever a PR method is called without explicit owner/repo. The engine merge path already resolves the correct repo from the per-project cwd (prRepo = getCurrentRepo(cwd), FN-7133) but only threaded it into getPrMergeStatus. Every other GitHub call omitted it:

  • processPullRequestMergeTask: findPrForBranch / createPr / mergePr on both the per-task and shared-branch-group paths
  • createGroupPrCallback (group-PR promotion): findPrForBranch / createPr
  • createPrNodeGithubOps (pr-create/pr-merge workflow nodes): cwd-less getCurrentRepo() persisted entity.repo as "" (poisoning the downstream splitRepoSlug consumers), and the git push/createPr/mergePr ran against process.cwd()
  • the engine's review-response run (buildRespondCallback): respondOps.getCwd collapses to process.cwd() because no CLI composition site wires getTaskWorktree, so its git ops and response agent ran outside the project repo

In a central install the fallback throws; worse, if process.cwd() happens to be inside some other git repo, it silently targets the wrong repository.

What changed

  • fix(pr-merge): thread repo identity into PR auto-merge GitHub calls — widens the CLI-local GitHubOperations interface (optional owner/repo, already accepted by GitHubClient's FindPrParams/CreatePrParams/MergePrParams) and passes prRepo at all six call sites in processPullRequestMergeTask.
  • fix(pr-merge): resolve group-PR repo from project cwd in createGroupPrCallback — resolves via getCurrentRepo(cwd) from the callback input (same T4 pattern as syncGroupPrCallback) with a loud failure instead of a silent wrong-repo fallback.
  • fix(pr-merge): resolve PR-node repo from task worktree instead of process cwdresolvePrSource resolves from task.worktree, git ops run in getTaskWorktree(...) ?? task.worktree ?? process.cwd(), and createPr/mergePr pass owner/repo parsed from entity.repo.
  • fix(pr-merge): resolve review-response run cwd from the task worktree — the engine owns the store, so buildRespondCallback prefers the task's recorded worktree for the response run's git ops + agent, keeping ops.getCwd as the single-project fallback (defensive against structural PrNodeStores without getTask).
  • Changeset (@runfusion/fusion patch, structured body) included.

Deliberately not done: a constructor-scoped default repo on GitHubClient — one client instance is shared across all projects in a central install (serve.ts/daemon.ts/dashboard.ts), so per-call owner/repo is the only correct scope.

Testing

  • New regression tests simulate the central-install topology (getCurrentRepo mocked as (cwd?) => cwd ? repo : null, exactly the failing environment) and drive the merge flow end-to-end on the per-task path, the shared-branch-group path, createGroupPrCallback, and all three createPrNodeGithubOps ops, asserting every GitHub call carries explicit owner/repo (45 tests in packages/cli/src/commands/__tests__/task-lifecycle.test.ts, all green).
  • packages/engine/src/__tests__/pr-respond-cwd-resolution.test.ts covers the respond-run cwd: worktree preferred, ops.getCwd fallback when the task has no worktree, when the lookup fails, and when a structural store has no getTask.
  • Existing exact-argument assertions were extended to the new call contract (no assertions weakened or removed).
  • pnpm lint, pnpm typecheck, and pnpm build green locally; pnpm test:gate's engine-core suite green (294/294) — its PostgreSQL-backend lane needs local PG credentials this environment lacks, so that lane defers to CI. pnpm verify:fast (scoped typecheck/build + CLI build + boot smoke) also passes.

Repro

  1. Install the CLI centrally; run the server from a dir that is not a git repo, serving ≥1 project with a GitHub origin and mergeStrategy: "pull-request".
  2. Run a task to completion and let it reach the merge stage.
  3. Before this fix: the auto-merger throws Could not determine repository … (tasks with a persisted PR poll fine but never merge). Merging the same task from the Pull Requests tab succeeds, because the dashboard route resolves the repo explicitly (parseBadgeUrl(...) ?? getCurrentRepo(rootDir)).

Full analysis: Tchori-Labs#4


Developed with Claude (co-authored on all commits).

https://claude.ai/code/session_01ChEa8SHFYNAzjCdFbwFMfh

Summary by CodeRabbit

  • Bug Fixes
    • Resolved pull request auto-merge failures in centrally installed, multi-project deployments.
    • Ensured explicit repository context (owner/repo) is used for pull request lookup, creation, and merging throughout the merge workflow.
    • Improved pull request response handling to prefer the task worktree for working-directory resolution, with safe error behavior when task details are unavailable.
  • Tests
    • Expanded coverage for multi-repository merge workflows and worktree-based repository/cwd resolution in PR response handling.

VictorCano and others added 5 commits July 17, 2026 16:48
processPullRequestMergeTask already resolved prRepo from the per-project
cwd (FN-7133) but only passed it to getPrMergeStatus. findPrForBranch/
createPr/mergePr fell back to GitHubClient.resolveRepo's process.cwd()
resolution, which fails (or silently targets the wrong repo) in
centrally-installed multi-project deployments.

Co-Authored-By: Claude <noreply@anthropic.com>
…rCallback

Co-Authored-By: Claude <noreply@anthropic.com>
…cess cwd

Co-Authored-By: Claude <noreply@anthropic.com>
Co-Authored-By: Claude <noreply@anthropic.com>
The CLI-injected respondOps.getCwd defaults to process.cwd() because no
CLI composition site wires getTaskWorktree; in a centrally-installed
multi-project server the review-response run's git ops and agent would
run outside the project repo. The engine owns the store, so
buildRespondCallback now prefers the task's recorded worktree and keeps
ops.getCwd as the single-project fallback.

Co-Authored-By: Claude <noreply@anthropic.com>
@coderabbitai

coderabbitai Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 22adec4f-d610-4598-992c-57f1bf0ca61f

📥 Commits

Reviewing files that changed from the base of the PR and between 90e38c6 and 3088538.

📒 Files selected for processing (4)
  • packages/cli/src/commands/__tests__/task-lifecycle.test.ts
  • packages/cli/src/commands/task-lifecycle.ts
  • packages/engine/src/__tests__/pr-respond-cwd-resolution.test.ts
  • packages/engine/src/pr-nodes.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/cli/src/commands/tests/task-lifecycle.test.ts
  • packages/cli/src/commands/task-lifecycle.ts

📝 Walkthrough

Walkthrough

PR merge operations now receive explicit repository identity derived from task worktrees or callback cwd. PR response callbacks resolve their working directory from recorded task data with CLI fallback behavior, and tests cover group, per-task, and response flows.

Changes

PR repository resolution

Layer / File(s) Summary
Explicit repository context for GitHub operations
packages/cli/src/commands/task-lifecycle.ts, packages/cli/src/commands/__tests__/task-lifecycle.test.ts
GitHub PR lookup, creation, and merge operations accept explicit owner and repo values resolved from task worktrees or callback cwd.
Repository threading through merge workflows
packages/cli/src/commands/task-lifecycle.ts, packages/cli/src/commands/__tests__/task-lifecycle.test.ts
Shared-branch and per-task merge flows pass repository identity through all GitHub calls, with assertions covering task worktree cwd and operation payloads.
Task worktree resolution for PR responses
packages/engine/src/pr-nodes.ts, packages/engine/src/__tests__/pr-respond-cwd-resolution.test.ts
PR response callbacks use the task’s recorded worktree when available, fall back to the CLI cwd resolver when appropriate, and withhold unsupported structural stores from the agent runner.
Patch release metadata
.changeset/gh-4-pr-merge-repo-resolution.md
Adds a patch changeset describing the PR repository-resolution fix.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TaskWorktree
  participant processPullRequestMergeTask
  participant GitHubOperations
  participant buildRespondCallback
  TaskWorktree->>processPullRequestMergeTask: provide repository context
  processPullRequestMergeTask->>GitHubOperations: find, create, and merge PR with owner/repo
  buildRespondCallback->>TaskWorktree: resolve recorded worktree
  buildRespondCallback->>GitHubOperations: construct git operations with resolved cwd
Loading

Possibly related PRs

  • Runfusion/Fusion#68: Changes the same CLI PR merge path while adding merge-failure reconciliation.

Suggested reviewers: gsxdsm

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main fix: resolving the repo from the project checkout instead of process.cwd() during PR-mode auto-merge.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@greptile-apps

greptile-apps Bot commented Jul 17, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR makes pull-request workflows use each project's checkout instead of the server process directory. The main changes are:

  • Pass explicit repository identity to PR lookup, creation, and merge calls.
  • Resolve PR workflow operations from task and project worktrees.
  • Run review-response git and agent operations from the recorded task worktree.
  • Add central-install and cwd-resolution tests.
  • Add a patch changeset for the published CLI package.

Confidence Score: 5/5

The updated code looks safe to merge.

  • Repository identity is now passed explicitly through the affected PR operations.
  • Task-store read failures no longer continue in the server process directory.
  • No remaining blocking issue qualifies for this follow-up review.

Important Files Changed

Filename Overview
packages/cli/src/commands/task-lifecycle.ts Threads project repository identity through PR operations and resolves PR-node work from task checkouts.
packages/engine/src/pr-nodes.ts Uses the persisted task worktree for review-response runs and propagates task-store failures through the existing error route.
packages/cli/src/commands/tests/task-lifecycle.test.ts Adds coverage for repository threading across central-install PR workflows.
packages/engine/src/tests/pr-respond-cwd-resolution.test.ts Covers worktree preference, fallback behavior, store failures, and structural stores.
.changeset/gh-4-pr-merge-repo-resolution.md Adds the required structured patch changeset for the published package.

Reviews (2): Last reviewed commit: "fix(pr-merge): address review notes — fa..." | Re-trigger Greptile

Comment thread packages/cli/src/commands/task-lifecycle.ts Outdated
Comment thread packages/engine/src/pr-nodes.ts Outdated

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

🧹 Nitpick comments (1)
packages/cli/src/commands/task-lifecycle.ts (1)

450-451: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Apply the required FNXC format to the new requirement comments.

  • packages/cli/src/commands/task-lifecycle.ts#L450-L451: prefix the worktree rationale with FNXC:PrMergeAutoMerge yyyy-MM-dd-hh:mm:.
  • packages/cli/src/commands/__tests__/task-lifecycle.test.ts#L162-L165: encode the central-install regression requirement with the same FNXC convention.

As per coding guidelines, important implementation rationale must use dated FNXC:Area-of-product comments. Based on learnings, use the established FNXC convention without adding a literal FNXC_LOG token.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/cli/src/commands/task-lifecycle.ts` around lines 450 - 451, Update
the rationale comment near the task worktree git operations in
packages/cli/src/commands/task-lifecycle.ts:450-451 to begin with the dated
convention “FNXC:PrMergeAutoMerge yyyy-MM-dd-hh:mm:”, without adding FNXC_LOG.
Also update the central-install regression requirement comment in
packages/cli/src/commands/__tests__/task-lifecycle.test.ts:162-165 with the same
FNXC format and area prefix.

Sources: Coding guidelines, Learnings

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.changeset/gh-4-pr-merge-repo-resolution.md:
- Around line 5-7: Add a concise FNXC:Area-of-product Markdown comment near the
changeset summary, including a timestamp in yyyy-MM-dd-hh:mm format. Keep the
comment aligned with the documented multi-project deployment requirement and
preserve the existing summary and metadata.

In `@packages/cli/src/commands/__tests__/task-lifecycle.test.ts`:
- Around line 1909-1910: Update the push-call assertion in the task lifecycle
test to verify that the recorded Git push call’s cwd is
/projects/repo-a/.worktrees/fn-9601, while retaining the existing assertion that
the push call exists.

In `@packages/cli/src/commands/task-lifecycle.ts`:
- Around line 435-440: Update resolvePrSource to use the configured
options.getTaskWorktree resolver when task.worktree is absent, matching
createPr’s authoritative worktree behavior. Resolve the repository from the
resulting task worktree before falling back to process.cwd(), and preserve the
existing getCurrentRepo flow for valid worktree paths.

In `@packages/engine/src/pr-nodes.ts`:
- Around line 258-268: Update the responder setup around fullStore.getTask so it
first checks typeof fullStore.getTask === "function" before invoking it. When
the method is unavailable, use the existing cwd fallback and do not pass that
structural store to makePrResponseAgentRunner; only provide the store when
getTask exists.

---

Nitpick comments:
In `@packages/cli/src/commands/task-lifecycle.ts`:
- Around line 450-451: Update the rationale comment near the task worktree git
operations in packages/cli/src/commands/task-lifecycle.ts:450-451 to begin with
the dated convention “FNXC:PrMergeAutoMerge yyyy-MM-dd-hh:mm:”, without adding
FNXC_LOG. Also update the central-install regression requirement comment in
packages/cli/src/commands/__tests__/task-lifecycle.test.ts:162-165 with the same
FNXC format and area prefix.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: be140fa7-fa2d-410c-bbaf-5ad3f939c691

📥 Commits

Reviewing files that changed from the base of the PR and between 600e9c9 and 90e38c6.

📒 Files selected for processing (5)
  • .changeset/gh-4-pr-merge-repo-resolution.md
  • packages/cli/src/commands/__tests__/task-lifecycle.test.ts
  • packages/cli/src/commands/task-lifecycle.ts
  • packages/engine/src/__tests__/pr-respond-cwd-resolution.test.ts
  • packages/engine/src/pr-nodes.ts

Comment thread .changeset/gh-4-pr-merge-repo-resolution.md
Comment thread packages/cli/src/commands/__tests__/task-lifecycle.test.ts
Comment thread packages/cli/src/commands/task-lifecycle.ts Outdated
Comment thread packages/engine/src/pr-nodes.ts Outdated
…o/store

Review-round fixes for the gh-4 repo-resolution PR:

- resolvePrSource honors the configured getTaskWorktree resolver (same
  precedence as createPr) and throws instead of persisting entity.repo as
  "" when no repo resolves — the pr-create node maps the throw to a
  routable source-error, and "" could only ever succeed by silently
  targeting whatever repo process.cwd() sits in.
- buildRespondCallback guards getTask with a typeof check: structural
  stores without getTask degrade to the ops.getCwd fallback and are
  withheld from the agent runner (whose optional store param assumes
  getTask); a real getTask rejection now propagates to the pr-respond
  node's routable respond-error instead of silently running a mutating
  agent + git push in a possibly-wrong cwd.
- Tests: push-cwd assertion (execFile mock now records opts.cwd),
  getTaskWorktree-precedence + loud-throw coverage for resolvePrSource,
  store-withholding + rejection-propagation coverage for the respond run.
- FNXC prefixes added to the comments flagged in review.

Co-Authored-By: Claude <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01ChEa8SHFYNAzjCdFbwFMfh
@gsxdsm

gsxdsm commented Jul 18, 2026

Copy link
Copy Markdown
Collaborator

Thank you! This is a big issue appreciate the fix

@gsxdsm
gsxdsm merged commit 9cafa04 into Runfusion:main Jul 18, 2026
7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants