Macroscope has since reviewed this pull request. An earlier review was skipped by a cost limit; a review has now completed, so that notice no longer applies.
fix(cursor): grep content results keep their matched lines#25037
Problem
@cursor/sdk 1.0.38 (and 1.0.35 through 1.2.0) converts native grep content results as if they were flat matches. The wire shape is grouped (file + matches[{lineNumber, content, isContextLine}]), so every match loses its text, line number and context, and totalMatches becomes 0. T3's Cursor adapter uses that text as the file-search preview, so a content-mode grep shows bare file names. Reproduced on main 97e35bcf23 with a real Cursor agent grep (transcript below).
Change
A pnpm patch of @cursor/sdk@1.0.38 rewrites only the converter's content case, in the cjs, esm and bundled builds. Grouped results become one match per non-context line, with adjacent context lines attached as beforeContext/afterContext. totalMatches takes totalMatchedLines, then totalMatches, then the match count. Entries that are already flat pass through unchanged. The patch file is large because the SDK ships single-line minified chunks; the logical change is one expression per file. The test reads the installed converter, finds the chunk that holds it instead of hardcoding a chunk number, and fails loudly if a future SDK rewrites it.
Scope and approval
Fixes pingdotgg/t3code#24919
Triaged via the automated issue flow; GitCafe issue #24919. No settings, contracts or client changes.
Verification
- Red first:
keeps grouped grep content match text, lines, and totals in the %s Cursor SDK build(esm and cjs) fails on unpatched 1.0.38 withline: undefined, nolineNumber/context, andtotalMatches: 0instead of7. vp test run packages/provider-cursor/src/server/adapter.test.ts: 23 passed.vp run check:changed: all checks passed (unused patches, format, lint, knip, typecheck of 39 packages, tests).- Bundled build checked by hand with the same input: output identical to cjs and esm.
- Runtime: a real Cursor agent (
Agent.create, modeldefault, local cwd = a synthetic two-file fixture) asked for one content-mode grep with one line of context. Same driver, same prompt, before and after:
Before: main 97e35bcf23, unpatched SDK
| 1 | sdk: node_modules/.pnpm/@cursor+sdk@1.0.38_zod@4.6.5/node_modules/@cursor/sdk/dist/cjs/index.js |
| 2 | grep tool-call-completed updates: 1 |
| 3 | { |
| 4 | "status": "success", |
| 5 | "value": { |
| 6 | "workspaceResults": { |
| 7 | "/tmp/issue-lead-24919-r2/runtime/fixture": { |
| 8 | "type": "content", |
| 9 | "output": { |
| 10 | "matches": [ |
| 11 | { |
| 12 | "file": "./src/one.ts" |
| 13 | }, |
| 14 | { |
| 15 | "file": "./src/two.ts" |
| 16 | } |
| 17 | ], |
| 18 | "totalMatches": 0 |
| 19 | } |
| 20 | } |
| 21 | } |
| 22 | } |
| 23 | } |
After: fix/issue-24919 cc081f946f, patched SDK
| 1 | sdk: node_modules/.pnpm/@cursor+sdk@1.0.38_patch_hash=c50f9c6f1eea79f6e41ca9c80dfd8db777206627f77adc8c9607160410f44c56_zod@4.6.5/node_modules/@cursor/sdk/dist/cjs/index.js |
| 2 | grep tool-call-completed updates: 1 |
| 3 | { |
| 4 | "status": "success", |
| 5 | "value": { |
| 6 | "workspaceResults": { |
| 7 | "/tmp/issue-lead-24919-r2/runtime/fixture": { |
| 8 | "type": "content", |
| 9 | "output": { |
| 10 | "matches": [ |
| 11 | { |
| 12 | "file": "./src/one.ts", |
| 13 | "lineNumber": 3, |
| 14 | "line": "export const marker = \"zebra-needle one\";", |
| 15 | "beforeContext": [ |
| 16 | "// before one" |
| 17 | ], |
| 18 | "afterContext": [ |
| 19 | "// after one" |
| 20 | ] |
| 21 | }, |
| 22 | { |
| 23 | "file": "./src/two.ts", |
| 24 | "lineNumber": 2, |
| 25 | "line": "export const second = \"zebra-needle two\";", |
| 26 | "beforeContext": [ |
| 27 | "export const first = \"x\";" |
| 28 | ] |
| 29 | } |
| 30 | ], |
| 31 | "totalMatches": 2 |
| 32 | } |
| 33 | } |
| 34 | } |
| 35 | } |
| 36 | } |
Driver script (scratch, not committed)
| 1 | // Usage: node driver.mjs <provider-cursor dir> <fixture cwd> <out dir> |
| 2 | import { createRequire } from "node:module"; |
| 3 | import { writeFileSync, mkdirSync } from "node:fs"; |
| 4 | const [pkgDir, cwd, out] = process.argv.slice(2); |
| 5 | mkdirSync(out, { recursive: true }); |
| 6 | const require = createRequire(pkgDir + "/package.json"); |
| 7 | const sdkPath = require.resolve("@cursor/sdk"); |
| 8 | const mod = await import(sdkPath); |
| 9 | const { Agent, Cursor } = mod.Agent ? mod : mod.default; |
| 10 | const apiKey = process.env.CURSOR_API_KEY; |
| 11 | if (process.argv.includes("--models")) { const m = await Cursor.models.list({ apiKey }); console.log(JSON.stringify(m).slice(0, 2000)); process.exit(0); } |
| 12 | const model = process.env.MODEL ?? "composer-2"; |
| 13 | const agent = await Agent.create({ apiKey, model: { id: model }, local: { cwd } }); |
| 14 | const updates = []; |
| 15 | const run = await agent.send( |
| 16 | "Use your grep tool exactly once, in content output mode, with 1 line of context before and after, to search for the regex 'zebra-needle' in this directory. Do not use any other tool. Then reply with just the word done.", |
| 17 | { onDelta: async ({ update }) => { updates.push(update); } }, |
| 18 | ); |
| 19 | const result = await run.wait?.(); |
| 20 | writeFileSync(out + "/updates.json", JSON.stringify(updates, null, 2)); |
| 21 | const grep = updates.filter((u) => JSON.stringify(u).includes('"grep"') && u.type?.includes("completed")); |
| 22 | console.log("sdk:", sdkPath); |
| 23 | console.log("grep tool-call-completed updates:", grep.length); |
| 24 | for (const u of grep) console.log(JSON.stringify(u.toolCall?.result ?? u, null, 1).slice(0, 2500)); |
| 25 | process.exit(0); |
Not checked: no before/after UI capture at this head. The renderer is unchanged and the adapter maps line straight to the search preview (adapter.ts:486); captures from the earlier 1.0.35 revision were dropped as stale. The bundled build was not run under Bun. Electron and mobile were not run; both consume the same server-side search result.
Implemented with Claude Opus 5.5 in Claude Code; reviewed with GPT-6.1-Sol in Codex and Claude Opus 5.5 in Claude Code.
🤖 Generated with Claude Code
Checks
Added 3 commits
Approvability
Verdict: Needs Human Approval
Macroscope's review found this PR requires human approval — The change patches Cursor grep-result conversion and adds regression coverage. The new test file disables the nodeBuiltinImport diagnostic at file scope, requiring human review of that suppression.
You can add or adjust custom eligibility rules. Learn more.
Thread transfer impact
✅ Thread transfer remains within every enforced ceiling.
| Provider | Metric | Main baseline | This PR | Impact | PR ceiling | |
|---|---|---|---|---|---|---|
| Codex | Total thread wire | 5.0 KiB | 5.0 KiB | 0 B (0.0%) | 6.8 KiB | ✅ |
| Codex | Thread snapshot wire | 3.8 KiB | 3.8 KiB | 0 B (0.0%) | 4.9 KiB | ✅ |
| Codex | Live turn WebSocket wire | 1.2 KiB | 1.2 KiB | 0 B (0.0%) | 2.0 KiB | ✅ |
| Codex | Live turn WebSocket decoded | 21.5 KiB | 21.5 KiB | 0 B (0.0%) | 24.4 KiB | ✅ |
| Codex | Live turn messages | 1 | 1 | 0 (0.0%) | 8 | ✅ |
| Claude | Total thread wire | 5.0 KiB | 5.0 KiB | 0 B (0.0%) | 6.8 KiB | ✅ |
| Claude | Thread snapshot wire | 3.8 KiB | 3.8 KiB | 0 B (0.0%) | 4.9 KiB | ✅ |
| Claude | Live turn WebSocket wire | 1.2 KiB | 1.2 KiB | 0 B (0.0%) | 2.0 KiB | ✅ |
| Claude | Live turn WebSocket decoded | 21.9 KiB | 21.9 KiB | 0 B (0.0%) | 24.4 KiB | ✅ |
| Claude | Live turn messages | 1 | 1 | 0 (0.0%) | 8 | ✅ |
Baseline: 3a8c250 · PR result: b071e61 · Source CI: success
Scenario and decoded snapshot size
10 historical turns, 5 command tools per turn, 878.9 KiB retained MCP result per historical turn, and a 1.05 MiB retained result in the measured turn.
- Codex decoded thread snapshot: 108.5 KiB
- Claude decoded thread snapshot: 108.8 KiB
Updated in place by a trusted workflow. PR artifacts are strictly validated and never executed.
Important
Review skipped
We couldn't safely recover the incremental review. No full review was started, and the last reviewed checkpoint was preserved. Retry later, or explicitly request a full review by commenting @coderabbitai full review.
You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.
Use the checkbox below for a quick retry:
- Trigger review
No actionable comments were generated in the recent review.
Walkthrough
-
The workspace pins
@cursor/sdkto version 1.0.35 and registers a patch. Adapter tests load the installed ESM or CJS grep converter and check its output for grouped and legacy results, malformed entries, and context lines around gapped matches.Changes: Cursor grep conversion
Layer / File(s) Summary SDK version and patch registration
pnpm-workspace.yamlPins @cursor/sdkto version 1.0.35 and registers its patch.Installed converter regression tests
packages/provider-cursor/src/server/adapter.test.tsAdds a helper that extracts the installed converter from the ESM or CJS chunk. Tests check grouped matches, context lines, reported totals, legacy-shaped results, malformed entries, and context around gapped matches. Estimated code review effort: 2 (Simple) | ~15 minutes
Change: Bug fix · Severity of issue fixed: Medium
Possibly related PRs
- pingdotgg/t3code#24920: Changes the same Cursor SDK grep conversion behavior and supports grouped and legacy results.
Suggested reviewers:
t3dotgg,macroscopeapp
Merge Risk: External image Minimal · previous review c3ab3
-
No actionable merge-blocking issue remains in the reviewed grep change. The converter preserves the reported totals and marked context under the established contract.
Pre-merge checks: Passed 4
-
Check name Status Explanation Linked Issues check Passed Issue #24919is the active direct linked issue. The PR patches the Cursor grep converter in the CJS, ESM, and bundled builds. The converter flattens grouped content matches and preserves file, line nu…Out of Scope Changes check Passed The changes stay within the grep-output scope of issue #24919. The SDK patch changes the grep conversion expression. The workspace override pins that patch. The adapter test loader and regression test…Title check Passed The title is concise, uses the required conventional format, and clearly identifies the main change: preserving matched lines in Cursor grep content results. Description check Passed The description includes the required Problem, Change, Scope and approval, and Verification sections. It explains the bug, implementation, linked issue, test results, runtime validation, and untested … Full details: Linked Issues check
-
Explanation
Issue
#24919is the active direct linked issue. The PR patches the Cursor grep converter in the CJS, ESM, and bundled builds. The converter flattens grouped content matches and preserves file, line number, match text, context, and the reported total. The PR retains flat-result handling and rejects malformed entries. The adapter tests cover grouped matches, context, totals, flat compatibility, malformed entries, and both module builds. The SDK override pins the patched dependency.
Full details: Out of Scope Changes check
-
Explanation
The changes stay within the grep-output scope of issue
#24919. The SDK patch changes the grep conversion expression. The workspace override pins that patch. The adapter test loader and regression tests verify the conversion boundary. No client, renderer, settings, or unrelated product behavior changes are reported.
Full details: Description check
-
Explanation
The description includes the required Problem, Change, Scope and approval, and Verification sections. It explains the bug, implementation, linked issue, test results, runtime validation, and untested environments.
-
Finishing Touches
-
Fix failing CI checks
-
- Commit to this branch
- Create a new PR
Generate docstrings
-
- Commit to this branch
- Create a new PR
🧪 Generate unit tests (beta)
-
- Commit to this branch
- Create a new PR
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
External image Recent review info
-
External image Run configuration
-
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: fix/issue-24919
- File: .coderabbit.config.ts
- Commit: c3ab326
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Team
- Run ID:
a2b01a1c-a2ce-444f-a9e8-858ae4fe3749
External image Commits
-
Reviewing files that changed from the base of the PR and between 2ed92618e60f5ee6ecc694eb834c28105a502d09 and c3ab326d51d25702ed9d7291249f71560c361521.
External image Files ignored due to path filters: 1
-
pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
External image Files selected for processing: 3
-
packages/provider-cursor/src/server/adapter.test.tspatches/@cursor__sdk@1.0.35.patchpnpm-workspace.yaml
Limit details: You’ve used all 10 included reviews currently available.
External image Recent review info
-
External image Run configuration
-
- Source mode: Auto
- Repository: pingdotgg/t3code
- Branch: fix/issue-24919
- File: .coderabbit.config.ts
- Commit: c3ab326
- Layers: Repository TS config
- Review profile: CHILL
- Plan: Team
- Run ID:
a2b01a1c-a2ce-444f-a9e8-858ae4fe3749
External image Commits
-
Reviewing files that changed from the base of the PR and between 2ed92618e60f5ee6ecc694eb834c28105a502d09 and c3ab326d51d25702ed9d7291249f71560c361521.
External image Files ignored due to path filters: 1
-
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
External image Files selected for processing: 3
-
packages/provider-cursor/src/server/adapter.test.tspatches/@cursor__sdk@1.0.35.patchpnpm-workspace.yaml
Limit details: You’ve used all 10 included reviews currently available.
-
Added 6 commits
- Merge remote-tracking branch 'origin/main' into fix/issue-249193c2c60a
- test(cursor): reproduce lost grouped grep match text in the SDK converter (#24919)cf6bfbc
- fix(cursor): grep content results keep their matched linescc081f9
- Merge remote-tracking branch 'origin/main' into fix/issue-249193e5f87b
- Merge remote-tracking branch 'origin/main' into fix/issue-249195bb0534
- test(cursor): keep the SDK grep converter check out of the adapter testsb071e61
The automated pipeline stopped on this pull request and will not merge it:
someone else pushed to fix/issue-24919 (head is now 3e5f87b7cf); the pipeline does not build on commits it did not review
It stays open for a person to finish or close.