Skip to content

Review PR diffs in the app, with viewed marks and stacked-PR actions (#1527) - #1602

Merged
currentbits merged 2 commits into
mainfrom
coder/pr-code-tab-per-commit-diffs-viewed-mark-f635f7
Oct 11, 2026
Merged

currentbits merged 2 commits into
mainfrom
coder/pr-code-tab-per-commit-diffs-viewed-mark-f635f7

Conversation

@currentbits

Copy link
Copy Markdown
Owner

You can review a PR's files inside Solenta instead of leaving for GitHub. The workspace now has a Code tab (lazy per-file diffs + all-commits / single-commit picker), viewed marks that flip to Changed after a later push, several linked PRs per thread (including other repos), and rebase/merge for a stacked chain. Closes #1527.

Changes

  • Code tab reuses the 0.24 lazy FileHunks renderer; git.prDiff budgets large patches the same way local diffs do.
  • Viewed marks live in the store keyed repo#number + head SHA (blob SHA when GitHub sends one). Same blob stays Viewed; a changed file becomes Changed.
  • prLinks[] is additive; prNumber stays primary. Agents attach a PR with the always-on link_pull_request MCP tool.
  • Stack detect walks base→head. Merge is bottom-up and retargets the next PR onto the bottom PR's base (usually main) before GitHub deletes the old head. Rebase uses a temp worktree + --force-with-lease.
  • A thread auto-settles only when every linked PR is merged or closed.

Verification

  • node --test electron/test/pr-workspace.test.js electron/test/pr-links.test.js — including secret-block (after unsetting inherited CODER_GUARDRAILS_PATH) and merge-stack retarget onto main.
  • Renderer: test/prLinks.test.ts, test/prViewed.test.ts, test/prStack.test.ts, test/threadSettle.test.ts, test/prCodeTab.test.tsx.
  • scripts/sync-ipc-preload.js --check clean.
  • Not tested: live Electron click-through of Rebase stack / Merge stack against a real GitHub stack.

Notes for reviewers

  • Read electron/prWorkspace.js stack defaultBase first: it must be stack[0].baseRefName, not the PR the user has open.
  • Do not require services-projects from prWorkspace.js (pulls terminal.js / cross-spawn and breaks bare node --test).
  • Viewed marks are local; they do not sync to GitHub's viewed files. Inline review comments are a follow-up.

cursor-grok-4.6 via Cursor

Made with Cursor

Solenta-Message-Id: c9595604-04a9-4ada-8f93-f86c0dc45180
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 11, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-11T19:23:10.659339Z f30a434 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

Keep both link_pull_request and automation_create imports in orchServer.

Co-authored-by: Cursor <cursoragent@cursor.com>
@currentbits
currentbits merged commit 79ae564 into main Oct 11, 2026
3 of 6 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f30a434c3e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread electron/prWorkspace.js
Comment on lines +782 to +784
const diffArgs = ["pr", "diff", String(number)];
if (only) diffArgs.push("--", only);
const diffed = await ghApiTryAsync(repo.cwd, diffArgs, ghOpts(other));

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Fetch lazy files without an extra positional argument

When a file is omitted as lazy or large, the Code tab calls this path-specific branch, but gh pr diff does not accept a path after --. Its documented usage is gh pr diff [<number> | <url> | <branch>] [flags], and this invocation returns accepts at most 1 arg(s), received 2. Consequently, the files most likely to require lazy loading or “Show anyway” always fail to render; fetch the PR patch and extract the requested file, or use a supported API endpoint.

Useful? React with 👍 / 👎.

Comment thread electron/prWorkspace.js
Comment on lines +833 to +840
const key = viewedKey(parseRepoSlug(input && input.repo), number);
const viewed = input && input.viewed === false
? null
: {
headSha,
...(input && input.blobSha ? { blobSha: String(input.blobSha) } : {}),
};
store.setPrViewedMark(key, filePath, viewed);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Use the origin slug when storing viewed marks

For the primary PR, PrCodeTab omits repo, so this stores the mark under #<number>. A subsequent prDiff resolves the checkout's origin slug and reads from <owner>/<repo>#<number> instead. Thus clicking “Mark viewed” on the normal same-repository PR succeeds but immediately reloads as unseen; derive the repository key from projectPath here just as prDiff does.

Useful? React with 👍 / 👎.

Comment thread electron/prWorkspace.js
Comment on lines +929 to +932
const merged = await mergePrAt(
projectPath,
{ prNumber: current.number, method: input && input.method },
opts,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Pass the selected repository into each stack merge

When a linked PR belongs to another repository, prStack correctly discovers the chain using input.repo, but each mergePrAt call drops that repository. The merge therefore targets the checkout's origin and may either fail or merge an unrelated local PR with the same number, while the later retarget operation still targets the external repository. Include repo: other in every stack merge input.

Useful? React with 👍 / 👎.

Comment thread electron/prWorkspace.js
Comment on lines +962 to +964
const repo = await requireGitHubRepo(projectPath);
if (!repo.ok) return repo;
const fetched = await gitTryAsync(repo.cwd, ["fetch", "origin"]);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Rebase cross-repository stacks against their actual remote

For a stack selected from a linked repo, discovery is performed in that repository, but the rebase implementation fetches PR refs and force-pushes branches through the local project's origin. In the common case this fails because those refs or branches are absent; if matching names exist, it can rewrite the wrong repository. The rebase action must resolve and consistently use a remote for input.repo, or reject cross-repository stacks.

Useful? React with 👍 / 👎.

Comment thread electron/prWorkspace.js
Comment on lines +934 to +938
if (!merged.ok) return merged;
const next = open[i + 1];
if (next) {
const retarget = await retargetPrBase(repo.cwd, next.number, base, other);
if (!retarget.ok) return retarget;

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Retarget the next PR before merging its base branch

In repositories configured to delete merged head branches, mergePrAt can delete current.headRefName before this code retargets the next PR whose base is that branch. GitHub may then close or otherwise invalidate the next PR before pr edit --base runs, leaving a partially merged stack. Retarget the next PR to the landing base before issuing the merge that can delete its current base.

Useful? React with 👍 / 👎.

Comment thread electron/prLinks.js
Comment on lines +158 to +166
const links = upsertPrLink(normalizePrLinks(thread), link);
const primary = thread.prNumber == null ? link : null;
const patch = {
prLinks: links,
...(primary
? {
prNumber: primary.number,
prUrl: primary.url || thread.prUrl || null,
prState: primary.state || thread.prState || null,

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Refresh linked PR states before evaluating settlement

The link_pull_request schema supplies no state, so newly persisted links normally have state unset, and the existing background refresher updates only the legacy prState fields rather than prLinks. Because effectiveSettled treats a nonempty prLinks list as authoritative, even a single linked PR that later becomes merged or closed will not settle from its terminal state and instead falls through to inactivity. Persist refreshed states into the matching link or merge the primary legacy state into normalized links.

Useful? React with 👍 / 👎.

Comment thread src/threadSettle.ts
Comment on lines +81 to +84
if (links.length > 0) {
if (allLinkedPrsSettled(links, settleOnMerge)) return true;
if (anyLinkedPrOpen(links)) return false;
} else if (changeRequestAutoSettles(thread.prState, settleOnMerge)) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Enforce linked-PR settlement rules in background cleanup

This all-linked terminal check only changes renderer-side folding. The background path in electron/worktrees-pr.js still calls prFlipSettles solely from the primary prState, then runs onSettle and may delete the merged worktree. Consequently, merging the bottom PR of a stack can execute settlement hooks and reclaim the checkout while another linked PR remains open. Apply the same all-linked predicate before background settlement and cleanup.

Useful? React with 👍 / 👎.

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.

PR Code tab: per-commit diffs, viewed marks that reset on push, stacked-PR actions, several PRs per thread

1 participant