Skip to content

fix(cursor): grep content results keep their matched lines - #25037

Open
juliusmarminge wants to merge 7 commits into
mainfrom
fix/issue-24919
Open

juliusmarminge wants to merge 7 commits into
mainfrom
fix/issue-24919

Conversation

@juliusmarminge

@juliusmarminge juliusmarminge commented Oct 25, 2026 •

Copy link
Copy Markdown
Member

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 #24919

Triaged via the automated issue flow; GitCafe issue https://git.cafe/pingdotgg/t3code/issues/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 with line: undefined, no lineNumber/context, and totalMatches: 0 instead of 7.
  • 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, model default, 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 97e35bc, unpatched SDK
sdk: node_modules/.pnpm/@cursor+sdk@1.0.38_zod@4.6.5/node_modules/@cursor/sdk/dist/cjs/index.js
grep tool-call-completed updates: 1
{
 "status": "success",
 "value": {
  "workspaceResults": {
   "/tmp/issue-lead-24919-r2/runtime/fixture": {
    "type": "content",
    "output": {
     "matches": [
      {
       "file": "./src/one.ts"
      },
      {
       "file": "./src/two.ts"
      }
     ],
     "totalMatches": 0
    }
   }
  }
 }
}
After: fix/issue-24919 cc081f9, patched SDK
sdk: node_modules/.pnpm/@cursor+sdk@1.0.38_patch_hash=c50f9c6f1eea79f6e41ca9c80dfd8db777206627f77adc8c9607160410f44c56_zod@4.6.5/node_modules/@cursor/sdk/dist/cjs/index.js
grep tool-call-completed updates: 1
{
 "status": "success",
 "value": {
  "workspaceResults": {
   "/tmp/issue-lead-24919-r2/runtime/fixture": {
    "type": "content",
    "output": {
     "matches": [
      {
       "file": "./src/one.ts",
       "lineNumber": 3,
       "line": "export const marker = \"zebra-needle one\";",
       "beforeContext": [
        "// before one"
       ],
       "afterContext": [
        "// after one"
       ]
      },
      {
       "file": "./src/two.ts",
       "lineNumber": 2,
       "line": "export const second = \"zebra-needle two\";",
       "beforeContext": [
        "export const first = \"x\";"
       ]
      }
     ],
     "totalMatches": 2
    }
   }
  }
 }
}
Driver script (scratch, not committed)
// Usage: node driver.mjs <provider-cursor dir> <fixture cwd> <out dir>
import { createRequire } from "node:module";
import { writeFileSync, mkdirSync } from "node:fs";
const [pkgDir, cwd, out] = process.argv.slice(2);
mkdirSync(out, { recursive: true });
const require = createRequire(pkgDir + "/package.json");
const sdkPath = require.resolve("@cursor/sdk");
const mod = await import(sdkPath);
const { Agent, Cursor } = mod.Agent ? mod : mod.default;
const apiKey = process.env.CURSOR_API_KEY;
if (process.argv.includes("--models")) { const m = await Cursor.models.list({ apiKey }); console.log(JSON.stringify(m).slice(0, 2000)); process.exit(0); }
const model = process.env.MODEL ?? "composer-2";
const agent = await Agent.create({ apiKey, model: { id: model }, local: { cwd } });
const updates = [];
const run = await agent.send(
  "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.",
  { onDelta: async ({ update }) => { updates.push(update); } },
);
const result = await run.wait?.();
writeFileSync(out + "/updates.json", JSON.stringify(updates, null, 2));
const grep = updates.filter((u) => JSON.stringify(u).includes('"grep"') && u.type?.includes("completed"));
console.log("sdk:", sdkPath);
console.log("grep tool-call-completed updates:", grep.length);
for (const u of grep) console.log(JSON.stringify(u.toolCall?.result ?? u, null, 1).slice(0, 2500));
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

juliusmarminge and others added 3 commits October 25, 2026 21:38
Red test for #24919: @cursor/sdk 1.0.35 converts grouped GrepContentResult
protos as if they were flat, dropping match text, line numbers, context
lines, and totalMatchedLines.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cursor/sdk 1.0.35 converts GrepContentResult protos as if each entry were a
flat match, but the proto groups lines per file (GrepFileMatch{file, matches:
[{lineNumber, content, isContextLine}]}). Every match lost its text and line
number and totalMatches fell to 0.

Patch the SDK converter (esm, cjs, bundled) to flatten grouped results, attach
adjacent context lines as beforeContext/afterContext, read totalMatchedLines,
skip malformed lines, and keep flat legacy results unchanged.

Fixes #24919

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@macroscopeapp

macroscopeapp Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Macroscope skipped reviewing this pull request. Per-review cost limit exceeded (workspace setting).

This review would cost an estimated $192.00, which exceeds your per-review limit of $15.00.

The top 2 files driving up this estimate:

File Diff Size Estimate
patches/@cursor__sdk@1.0.38.patch 4.97MB $191.98
pnpm-workspace.yaml 406B $0.02

Tip

To get this pull request reviewed, you can:

  1. Comment @macroscope-app on this PR to request a manual review (monthly spend limits still apply).
  2. Exclude the file(s) above from review by adding a pattern to your .macroscope/ignore.md — note that creating this file replaces Macroscope's built-in default ignores rather than extending them.
  3. Raise your cost limit in your workspace billing settings.

Turn off this reminder going forward

@github-actions github-actions Bot added vouch:trusted PR author is trusted by repo permissions or the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Oct 25, 2026
@macroscopeapp

macroscopeapp Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — The change patches Cursor SDK grep conversion to retain matched lines and adds regression coverage. It also introduces a file-level nodeBuiltinImport diagnostic suppression in the adapter tests, which requires human review.

Needs human approval because:

  • Per-review cost limit exceeded (workspace setting). Approvability relies on correctness review in order to determine eligibility

Review your spending limits in Billing settings, or comment @macroscope-app review this PR to bypass the limit and review now. You can add or adjust custom eligibility rules. Learn more.

@github-actions

github-actions Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

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.3 KiB 1.3 KiB 0 B (0.0%) 2.0 KiB ✅
Codex Live turn WebSocket decoded 21.6 KiB 21.6 KiB 0 B (0.0%) 24.4 KiB ✅
Codex Live turn messages 2 2 0 (0.0%) 8 ✅
Claude Total thread wire 5.0 KiB 5.0 KiB −29 B (−0.6%) 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.3 KiB 1.2 KiB −29 B (−2.3%) 2.0 KiB ✅
Claude Live turn WebSocket decoded 21.9 KiB 21.9 KiB −41 B (−0.2%) 24.4 KiB ✅
Claude Live turn messages 2 1 −1 (−50.0%) 8 ✅

Baseline: 5ef5685 · PR result: 3e5f87b · 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.

@coderabbitai

coderabbitai Bot commented Oct 25, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

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.

Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 2ed9261 and c3ab326.

Files ignored due to path filters: 1
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
Files selected for processing: 3
  • packages/provider-cursor/src/server/adapter.test.ts
  • patches/@cursor__sdk@1.0.35.patch
  • pnpm-workspace.yaml

Limit details: You’ve used all 10 included reviews currently available.

Walkthrough

The workspace pins @cursor/sdk to 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.yaml
Pins @cursor/sdk to version 1.0.35 and registers its patch.
Installed converter regression tests
packages/provider-cursor/src/server/adapter.test.ts
Adds 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.

Priority: Normal

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: 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 #24919 is 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 #24919 is 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: 💡 1
🛠️ 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

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

juliusmarminge and others added 4 commits October 30, 2026 07:49
…rter (#24919)

These tests reproduce #24919: @cursor/sdk's grep result converter reads
grouped content results as flat matches, so match text, line numbers,
context and the reported total are dropped in both the esm and cjs builds.
The loader now finds the converter chunk by scanning the build directory
instead of a hardcoded chunk number.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@cursor/sdk 1.0.38 converts native grep content results as flat matches, but the
wire shape groups lines per file (GrepFileMatch{file, matches: [{lineNumber,
content, isContextLine}]}). Every match lost its text, line number and context,
totalMatches fell to 0, and Cursor file-search previews rendered empty.

Patch the SDK converter in the esm, cjs and bundled builds to flatten grouped
results into one match per non-context line, attach contiguous context lines as
beforeContext/afterContext, and report totalMatchedLines. Entries that already
carry `line` keep the SDK's flat handling.

Fixes #24919

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@juliusmarminge juliusmarminge changed the title fix(cursor): preserve grouped grep match text fix(cursor): grep content results keep their matched lines Oct 30, 2026
@github-actions github-actions Bot added size:XXL 1,000+ changed lines (additions + deletions). size:M 30-99 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). size:XXL 1,000+ changed lines (additions + deletions). labels Oct 30, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:M 30-99 changed lines (additions + deletions). vouch:trusted PR author is trusted by repo permissions or the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Cursor SDK drops match text from grouped grep output

1 participant