From fe4f66b371012310ca388e705ed3c60e568c7172 Mon Sep 17 00:00:00 2001 From: Markus Hartung Date: Sun, 13 Sep 2026 22:07:57 +0200 Subject: [PATCH 1/2] fix(build): keep node:fs out of the client chunk graph for /dashboard/logs Same root cause as #13436/#13509/#13568: open-sse/utils/cursorAgentCliVersion.ts imports node:fs/node:os/node:path (local Cursor CLI install detection), and those PRs already cut several edges reaching it. This is a further, previously-undiscovered edge: src/lib/oauth/constants/oauth.ts imports CURSOR_AGENT_CLI_VERSION from the full resolver, and oauth.ts turns out to be reachable from a very large share of the dashboard's client bundles (250+ pages/components in this repo, confirmed by the existing client-bundle guard test) via open-sse/config/providerModels.ts and open-sse/services/usage/supportedProviders.ts among others. Reproduced live: /dashboard/logs panicked with "the chunking context (unknown) does not support external modules (request: node:fs)" the first time Turbopack dev-mode compiled that page's client bundle. Same fix as the sibling PRs: the pin string moves to a new import-free cursorAgentCliVersionPin.ts (single source of truth); cursorAgentCliVersion.ts and oauth.ts both import it from there instead of duplicating it inline. cursorAgentCliVersion.ts itself is otherwise unchanged -- it still owns the full env -> local-install -> disk-cache -> pin resolution used by real Cursor CLI impersonation call sites. Also registers open-sse/utils/cursorAgentCliVersion.ts in the existing client-bundle-no-server-only-10692.test.ts guard's hardcoded SERVER_ONLY list, so this reproduces as a real test failure (250+ offending entry points) rather than only a live Turbopack panic, and any future edge reaching it fails CI immediately. --- open-sse/utils/cursorAgentCliVersion.ts | 7 ++----- open-sse/utils/cursorAgentCliVersionPin.ts | 14 ++++++++++++++ src/lib/oauth/constants/oauth.ts | 4 ++-- .../client-bundle-no-server-only-10692.test.ts | 7 +++++++ 4 files changed, 25 insertions(+), 7 deletions(-) create mode 100644 open-sse/utils/cursorAgentCliVersionPin.ts diff --git a/open-sse/utils/cursorAgentCliVersion.ts b/open-sse/utils/cursorAgentCliVersion.ts index 91bedd220631..ba0dda576a28 100644 --- a/open-sse/utils/cursorAgentCliVersion.ts +++ b/open-sse/utils/cursorAgentCliVersion.ts @@ -19,12 +19,9 @@ import { } from "node:fs"; import { homedir } from "node:os"; import { join } from "node:path"; +import { CURSOR_AGENT_CLI_VERSION } from "./cursorAgentCliVersionPin.ts"; -/** - * Pinned Agent CLI build id used when no local install is found (typical - * headless OmniRoute). Bump when refreshing Cursor CLI impersonation. - */ -export const CURSOR_AGENT_CLI_VERSION = "2026.07.08-0c04a8a"; +export { CURSOR_AGENT_CLI_VERSION }; const VERSION_ID_RE = /^\d{4}\.\d{2}\.\d{2}-[0-9a-f]+$/; const CACHE_TTL_MS = 60 * 60 * 1000; diff --git a/open-sse/utils/cursorAgentCliVersionPin.ts b/open-sse/utils/cursorAgentCliVersionPin.ts new file mode 100644 index 000000000000..77830e3ede78 --- /dev/null +++ b/open-sse/utils/cursorAgentCliVersionPin.ts @@ -0,0 +1,14 @@ +/** + * Pinned Agent CLI build id used when no local install is found (typical + * headless OmniRoute). Bump when refreshing Cursor CLI impersonation. + * + * Deliberately import-free: cursorAgentCliVersion.ts (the full resolver: + * env → local install detect → disk-cached installer scrape → this pin) + * pulls in `node:fs`/`node:os`/`node:path`. Any client-reachable file that + * only needs the pin string -- not the full resolver -- must import it from + * here instead, or Turbopack/webpack chokes trying to bundle those Node + * builtins into the browser build ("the chunking context does not support + * external modules"). See #13436/#13509/#13568 for the same cut applied to + * other edges reaching this same resolver. + */ +export const CURSOR_AGENT_CLI_VERSION = "2026.07.08-0c04a8a"; diff --git a/src/lib/oauth/constants/oauth.ts b/src/lib/oauth/constants/oauth.ts index 8094bb58cd04..1a108f8144c1 100644 --- a/src/lib/oauth/constants/oauth.ts +++ b/src/lib/oauth/constants/oauth.ts @@ -19,7 +19,7 @@ import { GROK_BUILD_TOKEN_URL, } from "@omniroute/open-sse/config/grokBuild.ts"; import { resolvePublicCred } from "@omniroute/open-sse/utils/publicCreds.ts"; -import { CURSOR_AGENT_CLI_VERSION } from "@omniroute/open-sse/utils/cursorAgentCliVersion.ts"; +import { CURSOR_AGENT_CLI_VERSION } from "@omniroute/open-sse/utils/cursorAgentCliVersionPin.ts"; import { buildGitLabOAuthEndpoints, GITLAB_DUO_DEFAULT_BASE_URL } from "../gitlab"; /** @@ -381,7 +381,7 @@ export const KIRO_CONFIG = { // Cursor stores credentials in SQLite database: state.vscdb // Keys: cursorAuth/accessToken, cursorAuth/refreshToken, storage.serviceMachineId // Deep-control PKCE + refresh aligned with OpenCodex (lidge-jun/opencodex src/oauth/cursor.ts). -// clientVersion pin lives in open-sse/utils/cursorAgentCliVersion.ts — single source of truth. +// clientVersion pin lives in open-sse/utils/cursorAgentCliVersionPin.ts — single source of truth. export const CURSOR_CONFIG = { // API endpoints apiEndpoint: "https://api2.cursor.sh", diff --git a/tests/unit/client-bundle-no-server-only-10692.test.ts b/tests/unit/client-bundle-no-server-only-10692.test.ts index e29ae9d2fafb..da2d7589f239 100644 --- a/tests/unit/client-bundle-no-server-only-10692.test.ts +++ b/tests/unit/client-bundle-no-server-only-10692.test.ts @@ -37,6 +37,13 @@ const SERVER_ONLY = new Set([ "src/lib/db/migrationRunner.ts", "open-sse/utils/proxyFetch.ts", "open-sse/utils/tlsClient.ts", + // fs/os/path resolver behind CURSOR_AGENT_CLI_VERSION; the pin string alone + // lives in the import-free cursorAgentCliVersionPin.ts (single source of + // truth) precisely so client-reachable code can depend on the value + // without dragging this file in. Turbopack panic reproduced live via + // `open-sse/config/providerModels.ts` -> ... -> `src/lib/oauth/constants/oauth.ts` + // -> here, reached from /dashboard/logs. + "open-sse/utils/cursorAgentCliVersion.ts", ]); /** From 4fa5af87a19a5a483b054592190fd4d70ea32851 Mon Sep 17 00:00:00 2001 From: Markus Hartung Date: Tue, 15 Sep 2026 15:26:49 +0200 Subject: [PATCH 2/2] docs(changelog): add fragment for #13604 --- .../fixes/13604-dashboard-logs-cursor-cli-version-client-leak.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog.d/fixes/13604-dashboard-logs-cursor-cli-version-client-leak.md diff --git a/changelog.d/fixes/13604-dashboard-logs-cursor-cli-version-client-leak.md b/changelog.d/fixes/13604-dashboard-logs-cursor-cli-version-client-leak.md new file mode 100644 index 000000000000..59489157346b --- /dev/null +++ b/changelog.d/fixes/13604-dashboard-logs-cursor-cli-version-client-leak.md @@ -0,0 +1 @@ +- **fix(build):** keep `node:fs`/`node:os`/`node:path` out of the client chunk graph for `/dashboard/logs` — a further, previously-undiscovered edge (`src/lib/oauth/constants/oauth.ts` importing `cursorAgentCliVersion.ts`, reachable from 250+ dashboard pages) of the same root cause already fixed in #13436/#13509/#13568. Moves the pinned CLI version string into a new import-free leaf module and extends the `client-bundle-no-server-only-10692` guard test to cover it ([#13604](https://github.com/diegosouzapw/OmniRoute/pull/13604)).