Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 50 additions & 13 deletions src/integrations/cursor-effort-table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
* instead of a hand-copied mirror. Read-only, size-bounded, cached by (path, mtime, size);
* any parse failure yields null so the caller falls back to the static mirror.
*/
import { readFileSync, statSync } from "node:fs";
import { closeSync, constants, fstatSync, openSync, readSync } from "node:fs";
import { join } from "node:path";
import type { CursorInstall } from "./cursor-detect";

Expand Down Expand Up @@ -111,32 +111,69 @@ function splitStrings(list: string): string[] {

export interface CursorEffortTableDeps {
platform: string;
stat(path: string): { mtimeMs: number; size: number } | null;
readText(path: string): string | null;
readBundle(path: string, cached?: { mtimeMs: number; size: number }): { mtimeMs: number; size: number; text: string | null } | null;
}

export function realCursorEffortTableDeps(): CursorEffortTableDeps {
return {
platform: process.platform,
stat: path => { try { const s = statSync(path); return { mtimeMs: s.mtimeMs, size: s.size }; } catch { return null; } },
readText: path => { try { return readFileSync(path, "utf8"); } catch { return null; } },
readBundle: readCursorBundle,
};
}

let cache: { key: string; table: CursorEffortTable | null } | null = null;
function readCursorBundle(path: string, cached?: { mtimeMs: number; size: number }): { mtimeMs: number; size: number; text: string | null } | null {
let fd: number | null = null;
try {
// O_NOFOLLOW binds the validation and read to the same regular file. O_NONBLOCK
// keeps opening a substituted special file from stalling before fstat rejects it.
fd = openSync(path, constants.O_RDONLY | constants.O_NOFOLLOW | constants.O_NONBLOCK);
const stat = fstatSync(fd);
if (!stat.isFile() || stat.size > BUNDLE_MAX_BYTES) return null;
if (cached?.mtimeMs === stat.mtimeMs && cached.size === stat.size) {
return { mtimeMs: stat.mtimeMs, size: stat.size, text: null };
}

const chunks: Buffer[] = [];
let size = 0;
while (size <= BUNDLE_MAX_BYTES) {
const chunk = Buffer.allocUnsafe(Math.min(64 * 1024, BUNDLE_MAX_BYTES + 1 - size));
const bytesRead = readSync(fd, chunk, 0, chunk.length, null);
if (bytesRead === 0) break;
chunks.push(chunk.subarray(0, bytesRead));
size += bytesRead;
}
if (size > BUNDLE_MAX_BYTES) return null;
return { mtimeMs: stat.mtimeMs, size, text: Buffer.concat(chunks, size).toString("utf8") };
} catch {
return null;
} finally {
if (fd !== null) closeSync(fd);
}
}

let cache: { key: string; path: string; mtimeMs: number; size: number; table: CursorEffortTable | null } | null = null;

/** Table from the Private Inference install, else null (caller falls back to the static mirror). */
export function loadCursorEffortTable(install: CursorInstall | undefined, deps: CursorEffortTableDeps = realCursorEffortTableDeps()): CursorEffortTable | null {
if (!install) return null;
const bundlePath = cursorAgentBundlePath(install, deps.platform);
const st = deps.stat(bundlePath);
if (!st || st.size > BUNDLE_MAX_BYTES) return null;
const key = `${bundlePath}|${st.mtimeMs}|${st.size}`;
if (cache?.key === key) return cache.table;
const text = deps.readText(bundlePath);
const parsed = text ? parseCursorEffortTable(text) : null;
const cachedMetadata = cache?.path === bundlePath
? { mtimeMs: cache.mtimeMs, size: cache.size }
: undefined;
const bundle = deps.readBundle(bundlePath, cachedMetadata);
if (!bundle) return null;
const key = `${bundlePath}|${bundle.mtimeMs}|${bundle.size}`;
if (cache?.key === key) {
// The cache key covers bundle identity only; install.version comes from
// product.json and can change or resolve without touching the bundle.
const cached = cache.table;
return cached && cached.version !== install.version
? { ...cached, version: install.version }
: cached;
}
const parsed = bundle.text ? parseCursorEffortTable(bundle.text) : null;
const table = parsed ? { ...parsed, version: install.version, bundlePath } : null;
cache = { key, table };
cache = { key, path: bundlePath, mtimeMs: bundle.mtimeMs, size: bundle.size, table };
return table;
}

Expand Down
48 changes: 40 additions & 8 deletions tests/providers/cursor/cursor-effort-table.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { beforeEach, describe, expect, test } from "bun:test";
import { readFileSync } from "node:fs";
import { execFileSync } from "node:child_process";
import { mkdirSync, readFileSync, rmSync, symlinkSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import {
cursorAgentBundlePath,
loadCursorEffortTable,
parseCursorEffortTable,
resetCursorEffortTableCacheForTests,
Expand Down Expand Up @@ -65,15 +68,13 @@ describe("Cursor installed-bundle effort table", () => {
test("activates the static fallback for missing installs, missing literals, and malformed regexes", () => {
const missingStat: CursorEffortTableDeps = {
platform: "darwin",
stat: () => null,
readText: () => { throw new Error("readText must not run without a stat"); },
readBundle: () => null,
};
expect(loadCursorEffortTable(INSTALL, missingStat)).toBeNull();

const loadSource = (source: string, mtimeMs: number) => loadCursorEffortTable(INSTALL, {
platform: "darwin",
stat: () => ({ mtimeMs, size: source.length }),
readText: () => source,
readBundle: () => ({ mtimeMs, size: source.length, text: source }),
});
expect(loadSource("function unrelated(){}", 1)).toBeNull();
expect(loadSource(FIXTURE.replace("/^claude-opus-5$/u", "/[/u"), 2)).toBeNull();
Expand Down Expand Up @@ -102,10 +103,12 @@ describe("Cursor installed-bundle effort table", () => {
let reads = 0;
const deps: CursorEffortTableDeps = {
platform: "darwin",
stat: () => ({ mtimeMs, size: FIXTURE.length }),
readText: () => {
readBundle: (_path, cached) => {
if (cached?.mtimeMs === mtimeMs && cached.size === FIXTURE.length) {
return { ...cached, text: null };
}
reads += 1;
return FIXTURE;
return { mtimeMs, size: FIXTURE.length, text: FIXTURE };
},
};
expect(loadCursorEffortTable(INSTALL, deps)?.families).toHaveLength(16);
Expand All @@ -115,4 +118,33 @@ describe("Cursor installed-bundle effort table", () => {
expect(loadCursorEffortTable(INSTALL, deps)?.families).toHaveLength(16);
expect(reads).toBe(2);
});

test("refreshes the reported version on a bundle cache hit", () => {
const deps: CursorEffortTableDeps = {
platform: "darwin",
readBundle: () => ({ mtimeMs: 1, size: FIXTURE.length, text: FIXTURE }),
};
expect(loadCursorEffortTable(INSTALL, deps)?.version).toBe("3.18.25");
const upgraded = { ...INSTALL, version: "3.19.0" };
expect(loadCursorEffortTable(upgraded, deps)?.version).toBe("3.19.0");
});

test("rejects symlinks and special files without blocking", () => {
if (process.platform === "win32") return;
const root = `${tmpdir()}/ocx-cursor-bundle-${process.pid}-${Date.now()}`;
const install = { ...INSTALL, path: root };
const bundlePath = cursorAgentBundlePath(install, process.platform);
const target = `${root}/target.js`;
mkdirSync(bundlePath.slice(0, bundlePath.lastIndexOf("/")), { recursive: true });
writeFileSync(target, FIXTURE);
try {
symlinkSync(target, bundlePath);
expect(loadCursorEffortTable(install)).toBeNull();
rmSync(bundlePath);
execFileSync("mkfifo", [bundlePath]);
expect(loadCursorEffortTable(install)).toBeNull();
} finally {
rmSync(root, { recursive: true, force: true });
}
});
});
Loading