fix(cursor): activated modern exec frames

This commit is contained in:
can1357
2026-07-30 01:46:13 +02:00
parent 34d7f2fb38
commit 1efa4e42ac
3 changed files with 9 additions and 1 deletions
+1
View File
@@ -36,6 +36,7 @@
- Fixed the `pi_read` range translation padding the slice it asks for. `piReadPath` composed a plain `:N+K` selector, which the local `read` tool expands by one leading and three trailing context line — so a frame naming offset 5/limit 20 received lines 4-27. Ranged Pi reads now compose `:raw:N+K`; the wire result is an opaque output string, so the line-number gutter `raw` also drops carries nothing the contract needs.
- Fixed ranged legacy Cursor reads reporting the returned window byte length as the full file size.
- Updated the Cursor client build advertisement to activate the modern exec-frame protocol handled by this provider.
- Fixed four Cursor exec frames answering with a result whose oneof was never set. In proto3 that is not an empty result — the server reads it as "the tool ran and produced nothing", indistinguishable from real success. `listMcpResourcesExecResult`, `readMcpResourceExecResult`, `recordScreenResult` and `computerUseResult` now send `ListMcpResourcesSuccess{resources: []}`, `ReadMcpResourceNotFound{uri}`, `RecordScreenFailure` and `ComputerUseError` respectively.
- The MCP resource frames now answer from the host instead of a fixed verdict. `CursorExecHandlers` gained `listMcpResources`/`readMcpResource`, so a host holding live MCP connections advertises them; the empty catalog and `not_found` above remain the answer when no handler is supplied. A handler that throws surfaces as `ListMcpResourcesError`/`ReadMcpResourceError` rather than collapsing into "none exist", which the model cannot retry. A read carrying `download_path` forwards it and answers with `ReadMcpResourceSuccess.download_path` and no content, which is what that mode means.
- Fixed Cursor `connect_scm` calls losing their repository and settling on a fabricated verdict. The target rides in the `ConnectScmArgs.target` oneof, so reading a flat `github` property always saw `undefined`; and the authoritative `success`/`error`/`rejected` result only arrives on the completion frame, so answering at the announcement persisted a fixed failure for every call — including the ones the server went on to accept. The block now opens on the start frame and settles from the completion's decoded result.
+1 -1
View File
@@ -212,7 +212,7 @@ import {
} from "./cursor/exec-modern";
export const CURSOR_API_URL = "https://api2.cursor.sh";
export const CURSOR_CLIENT_VERSION = "cli-2026.01.09-231024f";
export const CURSOR_CLIENT_VERSION = "cli-2026.07.23-e383d2b";
const CURSOR_PROXY_TUNNEL_TIMEOUT_MS = 30_000;
@@ -2,6 +2,7 @@ import { describe, expect, it } from "bun:test";
import { create, fromBinary, toBinary } from "@bufbuild/protobuf";
import {
type BlockState,
CURSOR_CLIENT_VERSION,
flushOpenToolCalls,
handleServerMessage,
processInteractionUpdate,
@@ -192,6 +193,12 @@ function soleResult(frames: AgentClientMessage[]) {
return frame.value.message;
}
describe("Cursor modern exec protocol activation", () => {
it("advertises the client build whose schema includes modern exec frames", () => {
expect(CURSOR_CLIENT_VERSION).toBe("cli-2026.07.23-e383d2b");
});
});
describe("Cursor stream teardown", () => {
it("keeps whole arguments on a block still open when the transport ends", async () => {
// A connect-SCM block arrives with complete `arguments` and never feeds