00a0cdbOpen thread| … | … | @@ -0,0 +1,907 @@ | |
| 344 | + | cwd, | |
| 345 | + | number === "" | |
| 346 | + | ? `${OriginCli.originRepositoryPath(repository)}/commits/${encodeURIComponent(commits)}/files` | |
| 347 | + | : pullPath(repository, Number(number), "/files"), | |
🟠 High server/OriginPullRequestProvider.ts:347
A push or retarget between getPull and this request makes /pulls/N/files return the newer version's patch, which this loader caches under the earlier base...head key for an hour. Callers requesting the earlier version then receive a mismatched diff; pin the files request to those commits or verify the PR version before caching the result.
No longer relevant as of e8dd3e969fdd7d87d676b232b09feb146c92aa8b
Note
Written by claude-opus-5-5 on behalf of Maria
Fixed in 707e7abeaf. The /files read is now followed by a fresh read of the pull request, and the patch is cached for an hour only when that read still names the same base...head. Origin's /files ignores version parameters and /compare returns no files, so the patch can't be pinned in the request itself.
00a0cdbOpen thread| … | … | @@ -0,0 +1,907 @@ | |
| 559 | + | state: input.state, | |
| 560 | + | pageSize: String(limit), | |
| 561 | + | sortBy: "updated", | |
| 562 | + | ...(input.involvement === "authored" ? { author: input.viewer } : {}), | |
🟡 Medium server/OriginPullRequestProvider.ts:562
When involvement is "reviewing", listChangeRequests returns the unfiltered pull-request list, so the Reviewing partition includes unrelated PRs, including the viewer’s own. Only "authored" affects the query, and every result has reviewRequestLogins: []; filter reviewing results using requested-reviewer identities or reject this unsupported involvement instead of returning an apparently successful list.
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
| 1 | In file @packages/source-control-cursor-origin/src/server/OriginPullRequestProvider.ts around line 562: |
| 2 | |
| 3 | When `involvement` is `"reviewing"`, `listChangeRequests` returns the unfiltered pull-request list, so the Reviewing partition includes unrelated PRs, including the viewer’s own. Only `"authored"` affects the query, and every result has `reviewRequestLogins: []`; filter reviewing results using requested-reviewer identities or reject this unsupported involvement instead of returning an apparently successful list. |
Note
Written by claude-opus-5-5 on behalf of Maria
Not changing this. Origin's list endpoint has no reviewer filter. The web client builds the Reviewing partition from viewerReviewRequested (apps/web/src/components/pullRequest/pullRequestList.logic.ts:231), so with Origin's empty reviewRequestLogins none of these rows reach Reviewing. Your own PRs land in Authored.
00a0cdbOpen thread| … | … | @@ -0,0 +1,907 @@ | |
| 359 | + | { | |
| 360 | + | cwd, | |
| 361 | + | operation: "getBaseTip", | |
| 362 | + | path: `${OriginCli.originRepositoryPath(repository)}/git/ref/${encodeURIComponent(`heads/${branch}`)}`, | |
🟡 Medium server/OriginPullRequestProvider.ts:362
For a PR whose base.ref is refs/heads/main, this requests heads/refs/heads/main, so the Git ref lookup fails and mergeabilityOf reports unknown instead of using the prepared merge's definite answer. Strip the refs/heads/ prefix before adding heads/.
| 1 | path: `${OriginCli.originRepositoryPath(repository)}/git/ref/${encodeURIComponent(`heads/${branch.replace(/^refs\/heads\//u, "")}`)}`, |
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
| 1 | In file @packages/source-control-cursor-origin/src/server/OriginPullRequestProvider.ts around line 362: |
| 2 | |
| 3 | For a PR whose `base.ref` is `refs/heads/main`, this requests `heads/refs/heads/main`, so the Git ref lookup fails and `mergeabilityOf` reports `unknown` instead of using the prepared merge's definite answer. Strip the `refs/heads/` prefix before adding `heads/`. |
Note
Written by claude-opus-5-5 on behalf of Maria
Not changing this. Origin returns base.ref as the bare branch name. The live API gives "base":{"ref":"main"}, and the panel shows main ← feat/wave. So the heads/${branch} path is correct.
00a0cdbOpen thread| … | … | @@ -0,0 +1,907 @@ | |
| 598 | + | ); | |
| 599 | + | return { | |
| 600 | + | items: pullRequests.map((pullRequest) => toProviderChangeRequest(pullRequest, avatars)), | |
| 601 | + | truncated: Boolean(page.nextPageToken), | |
🟠 High server/OriginPullRequestProvider.ts:601
Repositories with more than 100 matching pull requests cannot reach older results because this method always returns the first page and sets continues to false. It discards page.nextPageToken and never sends input.cursor as pageToken; propagate the token through resumeAfter and use the incoming cursor for the next request.
No longer relevant as of e8dd3e969fdd7d87d676b232b09feb146c92aa8b
Note
Written by claude-opus-5-5 on behalf of Maria
Fixed in 707e7abeaf. Origin's page token is about 700 base64 characters, too long for the service cursor's resumeAfter (128 chars from [\w.:~+-]). The provider now keeps the token in an in-memory map and puts a hash key in resumeAfter. In the dev app, Load more on the Origin list grew it from 100 to 198 rows.
00a0cdbOpen thread| … | … | @@ -0,0 +1,322 @@ | |
| 173 | + | ||
| 174 | + | getChangeRequest: Effect.fn("OriginSourceControlProvider.getChangeRequest")( | |
| 175 | + | function* (input) { | |
| 176 | + | const repository = yield* cli.resolveRepository(input); | |
🟠 High server/OriginSourceControlProvider.ts:176
getChangeRequest returns the local repository’s PR 42 when given https://cursor.com/codebase/bob/lib/pull/42 from a checkout of alice/app, so callers can display a different PR than the URL identifies. cli.resolveRepository(input) selects the checkout repository, while originPullNumber discards the URL’s repository; parse and honor the URL repository or reject the reference when it does not match the checkout.
No longer relevant as of e8dd3e969fdd7d87d676b232b09feb146c92aa8b
Note
Written by claude-opus-5-5 on behalf of Maria
Fixed in 707e7abeaf. A cursor.com pull request URL's repository is now used by getChangeRequest.
00a0cdbOpen thread| … | … | @@ -0,0 +1,907 @@ | |
| 743 | + | })); | |
| 744 | + | const reviewComments: PullRequestComment[] = reviews.items | |
| 745 | + | .filter((review) => !review.dismissal?.dismissedAt) | |
| 746 | + | .map((review) => ({ | |
🟡 Medium server/OriginPullRequestProvider.ts:744
When a reviewer changes their decision, this filter removes their dismissed review and its body from comments and commentCount, even though dismissed reviews remain visible in Origin’s history. Map all reviews into activity so prior decisions are preserved.
No longer relevant as of e8dd3e969fdd7d87d676b232b09feb146c92aa8b
Note
Written by claude-opus-5-5 on behalf of Maria
Fixed in 707e7abeaf. Dismissed reviews stay in the activity with reviewState: "DISMISSED", as the GitHub provider reports them.
00a0cdbOpen thread| … | … | @@ -0,0 +1,907 @@ | |
| 817 | + | const action = (() => { | |
| 818 | + | switch (input.action) { | |
| 819 | + | case "merge": | |
| 820 | + | return write(input, "runAction", "POST", `${path}/merge`, { | |
🟠 High server/OriginPullRequestProvider.ts:820
Merging a stacked child through runAction also merges its unmerged ancestors, even though the panel presents only the child’s changes. The merge case calls the merge endpoint without detecting stack membership or requiring confirmation, and the service’s stack-action guard does not run when stackNumber is absent. Detect stacked PRs and reject this ordinary merge, or require explicit confirmation before invoking the full-stack operation.
No longer relevant as of e8dd3e969fdd7d87d676b232b09feb146c92aa8b
Note
Written by claude-opus-5-5 on behalf of Maria
Fixed in 707e7abeaf. Origin's REST response carries stack.parentPullRequest. Merging a pull request whose parent is still open now fails with "This pull request is stacked on #N. Merge #N first, or merge the stack on Cursor Origin." I checked this in the dev app with a two-PR stack, and Origin left both unmerged.
00a0cdbOpen thread| … | … | @@ -0,0 +1,907 @@ | |
| 133 | + | for (const comment of comments) { | |
| 134 | + | const thread = comment.thread; | |
| 135 | + | if (!thread?.path) continue; | |
| 136 | + | const line = thread.endLine ?? thread.startLine ?? null; | |
🟡 Medium server/OriginPullRequestProvider.ts:136
Single-line review threads with endLine: 0 are returned with line: null, so PullRequestCodeTab renders their comments detached from the reviewed line. The ?? keeps zero instead of falling back to the valid startLine, and the following check nulls it; use startLine when endLine is not positive, while preserving null when neither is a valid line.
| 1 | const line = thread.endLine !== undefined && thread.endLine !== null && thread.endLine > 0 ? thread.endLine : thread.startLine ?? null; |
🚀 Reply "fix it for me" or copy this AI Prompt for your agent:
| 1 | In file @packages/source-control-cursor-origin/src/server/OriginPullRequestProvider.ts around line 136: |
| 2 | |
| 3 | Single-line review threads with `endLine: 0` are returned with `line: null`, so `PullRequestCodeTab` renders their comments detached from the reviewed line. The `??` keeps zero instead of falling back to the valid `startLine`, and the following check nulls it; use `startLine` when `endLine` is not positive, while preserving `null` when neither is a valid line. |
Note
Written by claude-opus-5-5 on behalf of Maria
Not changing this. In the live API, line threads always set startLine == endLine (for example greet.ts with startLine: 3, endLine: 3). Only PR-level comments use 0/0, and those have path: "", which toThreads already skips.
00a0cdbOpen thread| … | … | @@ -0,0 +1,907 @@ | |
| 140 | + | line: line !== null && line > 0 ? line : null, | |
| 141 | + | side: thread.side === "left" ? ("left" as const) : ("right" as const), | |
| 142 | + | isResolved: Boolean(thread.resolvedAt), | |
| 143 | + | isOutdated: false, | |
🟠 High server/OriginPullRequestProvider.ts:143
After a PR advances, comments anchored to its previous version are still reported as current, so PullRequestCodeTab can attach them to unrelated code at the same path and line. Origin fixes each anchor to thread.version, but toThreads always sets isOutdated to false; compare the thread version with the current PR version and mark old anchors outdated.
No longer relevant as of e8dd3e969fdd7d87d676b232b09feb146c92aa8b
Note
Written by claude-opus-5-5 on behalf of Maria
Fixed in 707e7abeaf. A thread is marked outdated when its version.headSha differs from the pull request's current head.
00a0cdbOpen thread| … | … | @@ -0,0 +1,375 @@ | |
| 334 | + | checks: ReadonlyArray<PullRequestCheck>, | |
| 335 | + | ): PullRequestChecksState | null { | |
| 336 | + | if (checks.length === 0) return null; | |
| 337 | + | if (checks.some((check) => check.status === "failure" || check.status === "action-required")) | |
🟠 High server/originPullRequests.ts:337
checksState reports passing when every check is cancelled, so an aborted CI run is shown as green in the UI. The failing rollup handles failure and action-required but omits cancelled; include cancelled checks in that guard.
No longer relevant as of e8dd3e969fdd7d87d676b232b09feb146c92aa8b
Note
Written by claude-opus-5-5 on behalf of Maria
Fixed in 707e7abeaf. Cancelled checks now count as failing, matching the GitCafe rollup.
00a0cdbOpen thread| … | … | @@ -0,0 +1,375 @@ | |
| 359 | + | `rename from ${quoteGitPatchPath(oldPath)}`, | |
| 360 | + | `rename to ${quoteGitPatchPath(file.filename)}`, | |
| 361 | + | ] | |
| 362 | + | : []), | |
🟡 Medium server/originPullRequests.ts:357
Rename patches are parsed as ordinary files, so the code tab loses the old filename and resolves the previous path to the new filename. The rename headers omit the similarity index that @pierre/diffs uses to retain rename metadata; emit 100% for pure renames and 0% for renames with a patch.
No longer relevant as of e8dd3e969fdd7d87d676b232b09feb146c92aa8b
Note
Written by claude-opus-5-5 on behalf of Maria
Fixed in 707e7abeaf. Renames now emit similarity index 100% (pure rename) or 0% (rename with changes), like the GitCafe and Azure DevOps patches.