pi-cursor-bridge 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codex-plugin/plugin.json +9 -9
- package/README.md +13 -13
- package/dist/cursor-bridge.mjs +171 -149
- package/dist/cursor-lifecycle-supervisor.mjs +17 -17
- package/extensions/index.ts +28 -28
- package/extensions/mcp-stdio.ts +92 -92
- package/package.json +2 -2
- package/skills/cce-routing/SKILL.md +3 -0
- package/skills/cursor-delegate/SKILL.md +10 -8
- package/skills/cursor-delegate/references/delegation-contract.md +2 -2
package/dist/cursor-bridge.mjs
CHANGED
|
@@ -11025,15 +11025,15 @@ function writeWorkspaceBinding(filePath, bindingKey, projectPath, options = {})
|
|
|
11025
11025
|
const key = String(bindingKey || "").trim();
|
|
11026
11026
|
if (!key) throw new Error("cursor_init could not identify the current Codex or Claude Code workspace session");
|
|
11027
11027
|
if (!isAbsoluteWorkspacePath(projectPath)) {
|
|
11028
|
-
throw new Error("
|
|
11028
|
+
throw new Error("Provide an absolute project path, for example C:\\Projects\\my-app or /Users/me/Projects/my-app");
|
|
11029
11029
|
}
|
|
11030
11030
|
const normalized = normalizeWorkspacePath(projectPath);
|
|
11031
11031
|
const existsImpl = options.existsImpl || existsSync;
|
|
11032
11032
|
if (!normalized || !existsImpl(normalized)) {
|
|
11033
|
-
throw new Error(
|
|
11033
|
+
throw new Error(`Workspace not found: ${normalized || projectPath}`);
|
|
11034
11034
|
}
|
|
11035
11035
|
if (!isWorkspaceTarget(normalized, options)) {
|
|
11036
|
-
throw new Error("
|
|
11036
|
+
throw new Error("The workspace must be a project directory or a .code-workspace file");
|
|
11037
11037
|
}
|
|
11038
11038
|
const state = readWorkspaceBindings(filePath);
|
|
11039
11039
|
const updatedAt = options.updatedAt || (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -11351,8 +11351,8 @@ async function ensureCursorRunningLocal(options = {}) {
|
|
|
11351
11351
|
windowGuard: windowGuard2,
|
|
11352
11352
|
needsAction: "install_or_locate_cursor",
|
|
11353
11353
|
retryable: true,
|
|
11354
|
-
nextStep: "
|
|
11355
|
-
message: `CCE
|
|
11354
|
+
nextStep: "Confirm that Cursor is installed and signed in. For a portable or custom installation, set CURSOR_EXE and run the same initialization command again.",
|
|
11355
|
+
message: `CCE connected to Cursor but cannot open workspace ${projectPath} because the Cursor executable was not found.`
|
|
11356
11356
|
};
|
|
11357
11357
|
}
|
|
11358
11358
|
const beforeTargetIds = new Set(currentTargets.map((target2) => target2.id));
|
|
@@ -11379,8 +11379,8 @@ async function ensureCursorRunningLocal(options = {}) {
|
|
|
11379
11379
|
cursorExecutableSource: cursorExecutable2.source,
|
|
11380
11380
|
needsAction: "retry_initialization",
|
|
11381
11381
|
retryable: true,
|
|
11382
|
-
nextStep: "
|
|
11383
|
-
message: `Cursor
|
|
11382
|
+
nextStep: "Wait for Cursor to finish opening the project, then run the same initialization command again.",
|
|
11383
|
+
message: `Cursor opened the project, but CCE has not confirmed that workspace ${projectPath} is ready. Initialization stopped safely to avoid searching the wrong project.`
|
|
11384
11384
|
};
|
|
11385
11385
|
}
|
|
11386
11386
|
targetId2 = openedTarget2.id;
|
|
@@ -11397,7 +11397,7 @@ async function ensureCursorRunningLocal(options = {}) {
|
|
|
11397
11397
|
windowGuard: windowGuard2,
|
|
11398
11398
|
targetId: targetId2,
|
|
11399
11399
|
workspaceAction,
|
|
11400
|
-
message: workspaceAction === "reused-agents-window" ? `CDP ${CDP_PORT}
|
|
11400
|
+
message: workspaceAction === "reused-agents-window" ? `CDP ${CDP_PORT} responded as Cursor; Agents Window ${targetId2} was reused without opening another IDE window.` : `CDP ${CDP_PORT} responded as Cursor; the target workspace is bound to CDP target ${targetId2 || "default"}.`
|
|
11401
11401
|
};
|
|
11402
11402
|
}
|
|
11403
11403
|
return {
|
|
@@ -11406,8 +11406,8 @@ async function ensureCursorRunningLocal(options = {}) {
|
|
|
11406
11406
|
port: CDP_PORT,
|
|
11407
11407
|
needsAction: "free_cce_port",
|
|
11408
11408
|
retryable: true,
|
|
11409
|
-
nextStep:
|
|
11410
|
-
message: `CCE
|
|
11409
|
+
nextStep: `Local port ${CDP_PORT} is in use by another program. Close that program, then run the same initialization command again.`,
|
|
11410
|
+
message: `CCE cannot connect to Cursor because required local port ${CDP_PORT} is occupied by another program.`
|
|
11411
11411
|
};
|
|
11412
11412
|
}
|
|
11413
11413
|
if (cursorRunningImpl()) {
|
|
@@ -11420,8 +11420,8 @@ async function ensureCursorRunningLocal(options = {}) {
|
|
|
11420
11420
|
cursorExecutableSource: cursorExecutable2 && cursorExecutable2.source || null,
|
|
11421
11421
|
needsAction: "close_cursor_and_retry",
|
|
11422
11422
|
retryable: true,
|
|
11423
|
-
nextStep: projectPath ?
|
|
11424
|
-
message: "Cursor
|
|
11423
|
+
nextStep: projectPath ? `Save your work, exit Cursor normally once, then initialize CCE for workspace ${projectPath} again.` : "Save your work, exit Cursor normally once, then retry the previous CCE operation.",
|
|
11424
|
+
message: "Cursor was already running, so CCE cannot add the required connection capability in place. Cursor Bridge will not force-close it, protecting unsaved work."
|
|
11425
11425
|
};
|
|
11426
11426
|
}
|
|
11427
11427
|
const cursorExecutable = findCursorExeDetailsImpl();
|
|
@@ -11433,8 +11433,8 @@ async function ensureCursorRunningLocal(options = {}) {
|
|
|
11433
11433
|
port: CDP_PORT,
|
|
11434
11434
|
needsAction: "install_or_locate_cursor",
|
|
11435
11435
|
retryable: true,
|
|
11436
|
-
nextStep: "
|
|
11437
|
-
message: "
|
|
11436
|
+
nextStep: "Install and sign in to Cursor first. For a portable or custom installation, set CURSOR_EXE and run the same initialization command again.",
|
|
11437
|
+
message: "Cursor was not found. Standard Windows and macOS installations are detected automatically and normally do not require an explicit executable path."
|
|
11438
11438
|
};
|
|
11439
11439
|
}
|
|
11440
11440
|
const launchPort = resolveCursorLaunchCdpPort(CDP_PORT);
|
|
@@ -11469,8 +11469,8 @@ async function ensureCursorRunningLocal(options = {}) {
|
|
|
11469
11469
|
cursorExecutableSource: cursorExecutable.source,
|
|
11470
11470
|
needsAction: "retry_initialization",
|
|
11471
11471
|
retryable: true,
|
|
11472
|
-
nextStep: "
|
|
11473
|
-
message: "Cursor
|
|
11472
|
+
nextStep: "Wait a moment, then run the same initialization command again.",
|
|
11473
|
+
message: "Cursor started, but CCE is not ready yet. No port setting needs to be changed."
|
|
11474
11474
|
};
|
|
11475
11475
|
}
|
|
11476
11476
|
const cursorPid = findCursorPidByPort(CDP_PORT) || child.pid || null;
|
|
@@ -11490,13 +11490,13 @@ async function ensureCursorRunningLocal(options = {}) {
|
|
|
11490
11490
|
cursorExecutableSource: cursorExecutable.source,
|
|
11491
11491
|
needsAction: "retry_initialization",
|
|
11492
11492
|
retryable: true,
|
|
11493
|
-
nextStep: "
|
|
11494
|
-
message: `Cursor
|
|
11493
|
+
nextStep: "Wait for Cursor to finish opening the project, then run the same initialization command again.",
|
|
11494
|
+
message: `Cursor started, but CCE has not confirmed that workspace ${projectPath} is ready. Initialization stopped safely to avoid searching the wrong project.`
|
|
11495
11495
|
};
|
|
11496
11496
|
}
|
|
11497
11497
|
if (projectPath && targetId) PROJECT_TARGETS.set(normalizeProjectKey(projectPath), targetId);
|
|
11498
11498
|
const windowGuard = effectiveRuntimeMode === "minimal" && cursorPid ? startMinimalWindowGuard(cursorPid) : null;
|
|
11499
|
-
const target = projectPath ?
|
|
11499
|
+
const target = projectPath ? `opening ${projectPath}` : "restoring the previous workspace";
|
|
11500
11500
|
const presentation = effectiveRuntimeMode === "minimal" ? setCursorWindowPresentation({ action: "hide", port: CDP_PORT, pid: cursorPid }) : null;
|
|
11501
11501
|
return {
|
|
11502
11502
|
ok: true,
|
|
@@ -11513,7 +11513,7 @@ async function ensureCursorRunningLocal(options = {}) {
|
|
|
11513
11513
|
cursorExecutableSource: cursorExecutable.source,
|
|
11514
11514
|
targetId,
|
|
11515
11515
|
workspaceAction: projectPath ? "launched-project" : "launched-last-workspace",
|
|
11516
|
-
message:
|
|
11516
|
+
message: `Cursor started (${exe}, ${target}); CDP ${CDP_PORT} is ready.`
|
|
11517
11517
|
};
|
|
11518
11518
|
}
|
|
11519
11519
|
function normalizeProjectKey(projectPath) {
|
|
@@ -20740,7 +20740,7 @@ init_cursor_ensure_core();
|
|
|
20740
20740
|
init_lifecycle_paths();
|
|
20741
20741
|
import http2 from "http";
|
|
20742
20742
|
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
20743
|
-
var PLUGIN_VERSION = "5.
|
|
20743
|
+
var PLUGIN_VERSION = "5.5.0";
|
|
20744
20744
|
var CDP_PORT2 = Number(process.env.CURSOR_BRIDGE_CDP_PORT || 9223);
|
|
20745
20745
|
var ORIGIN = `http://localhost:${CDP_PORT2}`;
|
|
20746
20746
|
var QUERY_TIMEOUT = Number(process.env.CURSOR_BRIDGE_TIMEOUT || 3e5);
|
|
@@ -20750,38 +20750,39 @@ function normalizeDelegationMode(value = process.env.CURSOR_BRIDGE_DELEGATION) {
|
|
|
20750
20750
|
var DELEGATION_MODE = normalizeDelegationMode();
|
|
20751
20751
|
function searchResultContract() {
|
|
20752
20752
|
return [
|
|
20753
|
-
"
|
|
20753
|
+
"Return only the minimum sufficient evidence set, ordered by evidence strength. Do not pad the result with similar matches.",
|
|
20754
20754
|
"",
|
|
20755
|
-
"
|
|
20755
|
+
"Output format (keep it compact; write narrative fields in the language of the user query and do not append a long explanation):",
|
|
20756
20756
|
"CCE_SEARCH_RESULT",
|
|
20757
|
-
"intent:
|
|
20758
|
-
"coverage: <focused|extended> |
|
|
20757
|
+
"intent: <one-sentence restatement of the retrieval intent>",
|
|
20758
|
+
"coverage: <focused|extended> | <why this search depth was sufficient; whether the preferred scope was expanded>",
|
|
20759
20759
|
"evidence:",
|
|
20760
|
-
"- <workspace-relative-path>:<start>-<end> | <symbol
|
|
20761
|
-
"gaps:
|
|
20762
|
-
"confidence: <high|medium|low
|
|
20760
|
+
"- <workspace-relative-path>:<start>-<end> | <symbol or anchor> | <relevance or verified relationship> | <semantic|exact|reference|source-read>",
|
|
20761
|
+
"gaps: <anything not confirmed; write none when empty>",
|
|
20762
|
+
"confidence: <high|medium|low> (rate retrieval evidence only, not code correctness)"
|
|
20763
20763
|
];
|
|
20764
20764
|
}
|
|
20765
20765
|
function buildContextEnginePrompt(query) {
|
|
20766
20766
|
return [
|
|
20767
|
-
"
|
|
20768
|
-
"
|
|
20769
|
-
"
|
|
20770
|
-
"
|
|
20771
|
-
"
|
|
20772
|
-
"
|
|
20773
|
-
"
|
|
20774
|
-
"
|
|
20767
|
+
"You are Cursor Context Engine (CCE), a read-only, evidence-driven project-understanding engine.",
|
|
20768
|
+
"Resolve natural-language intent into verifiable code context. Do not guess locations, repeat framework conventions, or propose an implementation.",
|
|
20769
|
+
"Search before answering. Choose the search depth from the question shape and discovered relationships: converge quickly for a simple location; trace call chains, data flow, registrations, or cross-module relationships until the minimum sufficient evidence is reached.",
|
|
20770
|
+
"Choose the best Cursor capabilities available, including indexed semantic retrieval, exact text search, symbol/reference tracing, targeted source reading, and Explore or subagents when they materially help. The caller defines the read-only, evidence, and stopping boundaries; it does not prescribe Cursor's internal harness.",
|
|
20771
|
+
"Support every claimed relationship with actual search, references, or source reading. Semantic similarity is not a proven call edge. Stop at minimum sufficient context and avoid unrelated repository-wide exploration.",
|
|
20772
|
+
"Do not modify, create, or delete files, and do not run commands that change workspace state. Read only the context needed to verify the location.",
|
|
20773
|
+
"When evidence is missing, write NOT_FOUND and list the terms, symbols, references, or scopes actually searched under gaps. Never answer without searching.",
|
|
20774
|
+
"The search scope is the complete workspace currently open and indexed by Cursor. Treat any module or path named in the intent as a clue, not a hard boundary.",
|
|
20775
|
+
"Write narrative output in the language of the user query unless the query explicitly requests another language. Never translate paths, symbols, identifiers, keys, enum values, or evidence-source markers.",
|
|
20775
20776
|
...searchResultContract(),
|
|
20776
20777
|
"",
|
|
20777
|
-
|
|
20778
|
+
`Retrieval intent: ${String(query || "").trim()}`
|
|
20778
20779
|
].join("\n");
|
|
20779
20780
|
}
|
|
20780
20781
|
function normalizeCceSearchResult(value) {
|
|
20781
20782
|
const text = String(value || "").trim();
|
|
20782
20783
|
const marker = text.indexOf("CCE_SEARCH_RESULT");
|
|
20783
20784
|
if (marker < 0) return text;
|
|
20784
|
-
return text.slice(marker).replace(/^CCE_SEARCH_RESULT\s+(?=intent:)/, "CCE_SEARCH_RESULT\n").replace(/[^\S\r\n]+(?=(?:coverage|evidence|gaps|confidence):)/g, "\n");
|
|
20785
|
+
return text.slice(marker).replace(/^CCE_SEARCH_RESULT\s+(?=intent:)/, "CCE_SEARCH_RESULT\n").replace(/[^\S\r\n]+(?=(?:coverage|evidence|gaps|confidence):)/g, "\n").replace(/^(?!- )([^:\r\n]+:\d+(?:-\d+)?\s+\|)/gm, "- $1");
|
|
20785
20786
|
}
|
|
20786
20787
|
function isConfirmedCompletedReply({ answer, snapshot = {}, sawStop = false, baselineCount = 0 } = {}) {
|
|
20787
20788
|
if (!String(answer || "").trim()) return false;
|
|
@@ -20792,7 +20793,8 @@ function isConfirmedCompletedReply({ answer, snapshot = {}, sawStop = false, bas
|
|
|
20792
20793
|
const hasCompletionEvidence = sawStop || Number(snapshot.messageCount || 0) >= Number(baselineCount || 0) + 2;
|
|
20793
20794
|
return hasAssistantEvidence && hasCompletionEvidence;
|
|
20794
20795
|
}
|
|
20795
|
-
var DO_DEFAULT_CONTRACT = "\n\
|
|
20796
|
+
var DO_DEFAULT_CONTRACT = "\n\nCompletion requirements: Work directly in the workspace currently open in Cursor; do not push to a remote. Before finishing, inspect the actual changes and run verification proportional to risk. The final reply must list completed work, changed files, verification results, and remaining risks or blockers.";
|
|
20797
|
+
var DO_LANGUAGE_CONTRACT = "\n\nResponse language: Reply in the language of the user task unless it explicitly requests another language. Never translate paths, commands, identifiers, keys, enum values, exact options, or error/status codes.";
|
|
20796
20798
|
var CDP_HOST2 = "127.0.0.1";
|
|
20797
20799
|
function httpJson(path) {
|
|
20798
20800
|
return new Promise((resolve6, reject) => {
|
|
@@ -20803,12 +20805,12 @@ function httpJson(path) {
|
|
|
20803
20805
|
try {
|
|
20804
20806
|
resolve6(JSON.parse(d));
|
|
20805
20807
|
} catch {
|
|
20806
|
-
reject(new Error("CDP
|
|
20808
|
+
reject(new Error("CDP returned a non-JSON response"));
|
|
20807
20809
|
}
|
|
20808
20810
|
});
|
|
20809
20811
|
});
|
|
20810
20812
|
req.on("error", reject);
|
|
20811
|
-
req.setTimeout(4e3, () => req.destroy(new Error(`Cursor
|
|
20813
|
+
req.setTimeout(4e3, () => req.destroy(new Error(`Cursor debug port ${CDP_PORT2} did not respond. Was Cursor started with --remote-debugging-port=${CDP_PORT2}?`)));
|
|
20812
20814
|
});
|
|
20813
20815
|
}
|
|
20814
20816
|
function scoreCursorPageCandidate(candidate, purpose = "fifo") {
|
|
@@ -20832,7 +20834,7 @@ function selectCursorPageCandidate(candidates, options = {}) {
|
|
|
20832
20834
|
const pages = Array.isArray(candidates) ? candidates.filter(Boolean) : [];
|
|
20833
20835
|
if (options.targetId) {
|
|
20834
20836
|
const exact = pages.find((page) => page.id === options.targetId);
|
|
20835
|
-
if (!exact) throw new Error(`Cursor CDP target
|
|
20837
|
+
if (!exact) throw new Error(`Cursor CDP target disappeared: ${options.targetId}`);
|
|
20836
20838
|
return exact;
|
|
20837
20839
|
}
|
|
20838
20840
|
const purpose = options.purpose || "fifo";
|
|
@@ -20880,11 +20882,11 @@ async function reloadPageTarget(page, timeoutMs = 5e3) {
|
|
|
20880
20882
|
try {
|
|
20881
20883
|
await Promise.race([
|
|
20882
20884
|
c.ready,
|
|
20883
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error("CDP target
|
|
20885
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("Timed out connecting to the CDP target")), timeoutMs))
|
|
20884
20886
|
]);
|
|
20885
20887
|
await Promise.race([
|
|
20886
20888
|
c.send("Page.reload", { ignoreCache: true }),
|
|
20887
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error("CDP
|
|
20889
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("Timed out reloading the CDP target")), timeoutMs))
|
|
20888
20890
|
]);
|
|
20889
20891
|
return true;
|
|
20890
20892
|
} catch {
|
|
@@ -20899,11 +20901,11 @@ async function inspectPageTarget(page) {
|
|
|
20899
20901
|
try {
|
|
20900
20902
|
await Promise.race([
|
|
20901
20903
|
c.ready,
|
|
20902
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error("CDP target
|
|
20904
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("Timed out connecting to the CDP target")), probeMs))
|
|
20903
20905
|
]);
|
|
20904
20906
|
const raw = await Promise.race([
|
|
20905
20907
|
evalJS(c, EXPR_PAGE_CAPABILITIES),
|
|
20906
|
-
new Promise((_, reject) => setTimeout(() => reject(new Error("CDP target
|
|
20908
|
+
new Promise((_, reject) => setTimeout(() => reject(new Error("Timed out probing the CDP target")), probeMs))
|
|
20907
20909
|
]);
|
|
20908
20910
|
return { ...page, capabilities: JSON.parse(raw || "{}") };
|
|
20909
20911
|
} catch (error2) {
|
|
@@ -20956,7 +20958,7 @@ function isAgentsWorkspaceBindError(error2) {
|
|
|
20956
20958
|
async function findPage(options = {}) {
|
|
20957
20959
|
const list = await httpJson("/json/list");
|
|
20958
20960
|
const pages = list.filter((t) => t.type === "page" && t.webSocketDebuggerUrl);
|
|
20959
|
-
if (!pages.length) throw new Error("
|
|
20961
|
+
if (!pages.length) throw new Error("No Cursor workbench page target was found");
|
|
20960
20962
|
if (options.targetId && options.preferAgentsV2 !== true && options.preferLegacy !== true) {
|
|
20961
20963
|
return selectCursorPageCandidate(pages, options);
|
|
20962
20964
|
}
|
|
@@ -20994,14 +20996,14 @@ function makeClient(wsUrl) {
|
|
|
20994
20996
|
else res(m.result);
|
|
20995
20997
|
}
|
|
20996
20998
|
});
|
|
20997
|
-
ws.on("close", () => failAll("CDP
|
|
20998
|
-
ws.on("error", (e) => failAll("CDP
|
|
20999
|
+
ws.on("close", () => failAll("CDP WebSocket closed because the page or renderer disappeared"));
|
|
21000
|
+
ws.on("error", (e) => failAll("CDP WebSocket error: " + (e && e.message)));
|
|
20999
21001
|
const CMD_TIMEOUT = Number(process.env.CURSOR_BRIDGE_CMD_TIMEOUT || 3e4);
|
|
21000
21002
|
const send = (method, params = {}) => {
|
|
21001
21003
|
const myId = ++id;
|
|
21002
21004
|
return new Promise((res, rej) => {
|
|
21003
21005
|
const t = setTimeout(() => {
|
|
21004
|
-
if (pending.delete(myId)) rej(new Error(`CDP
|
|
21006
|
+
if (pending.delete(myId)) rej(new Error(`CDP command timed out: ${method} (${CMD_TIMEOUT}ms)`));
|
|
21005
21007
|
}, CMD_TIMEOUT);
|
|
21006
21008
|
pending.set(myId, { res: (v) => {
|
|
21007
21009
|
clearTimeout(t);
|
|
@@ -21029,7 +21031,7 @@ function makeClient(wsUrl) {
|
|
|
21029
21031
|
var sleep2 = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
21030
21032
|
async function evalJS(c, expr) {
|
|
21031
21033
|
const r = await c.send("Runtime.evaluate", { expression: expr, returnByValue: true, includeCommandLineAPI: true });
|
|
21032
|
-
if (r.exceptionDetails) throw new Error("
|
|
21034
|
+
if (r.exceptionDetails) throw new Error("Page exception: " + (r.exceptionDetails.exception && r.exceptionDetails.exception.description || r.exceptionDetails.text));
|
|
21033
21035
|
return r.result && r.result.value;
|
|
21034
21036
|
}
|
|
21035
21037
|
async function chord(c, modifiers, key, code, vk) {
|
|
@@ -21268,7 +21270,8 @@ var REACT_ADAPTER_BODY = `
|
|
|
21268
21270
|
id:String(e&&e.id||''),label:String(e&&e.label||''),searchText:String(e&&e.searchText||''),
|
|
21269
21271
|
timestamp:normalizeTimestamp(e&&e.timestamp,index),isSelected:!!(e&&e.isSelected),
|
|
21270
21272
|
showSpinner:!!(e&&e.showSpinner),
|
|
21271
|
-
icon:String(typeof (e&&e.icon)==='string'?e.icon:(e&&e.icon&&((e.icon.id)||(e.icon.props&&e.icon.props.id)||(e.icon.type&&e.icon.type.id)))||'')
|
|
21273
|
+
icon:String(typeof (e&&e.icon)==='string'?e.icon:(e&&e.icon&&((e.icon.id)||(e.icon.props&&e.icon.props.id)||(e.icon.type&&e.icon.type.id)))||''),
|
|
21274
|
+
durable:true
|
|
21272
21275
|
});
|
|
21273
21276
|
const normalizeV2=(header,selectedId,index,section)=>{
|
|
21274
21277
|
const rawId=String(readScalar(header&&header.id)||'').replace(/^local:/,'');
|
|
@@ -21286,7 +21289,8 @@ var REACT_ADAPTER_BODY = `
|
|
|
21286
21289
|
timestamp:normalizeTimestamp(readScalar(header&&header.lastUpdatedAt)||readScalar(header&&header.createdAt),index),
|
|
21287
21290
|
isSelected:!!rawId&&(String(selectedId||'')===rawId||String(selectedId||'')==='local:'+rawId),
|
|
21288
21291
|
showSpinner:/in_progress|running|generating/.test(status),icon:icon||'draft',
|
|
21289
|
-
workspaceId:String(readScalar(section&§ion.id)||''),workspaceLabel:String(readScalar(section&§ion.displayName)||'')
|
|
21292
|
+
workspaceId:String(readScalar(section&§ion.id)||''),workspaceLabel:String(readScalar(section&§ion.displayName)||''),
|
|
21293
|
+
durable:true
|
|
21290
21294
|
};
|
|
21291
21295
|
};
|
|
21292
21296
|
const findLegacyAdapter=()=>{
|
|
@@ -21367,7 +21371,7 @@ var REACT_ADAPTER_BODY = `
|
|
|
21367
21371
|
entries.push({
|
|
21368
21372
|
id:selectedId,label:'',searchText:'',timestamp:0,isSelected:true,
|
|
21369
21373
|
showSpinner:/in_progress|running|generating/.test(status),icon,
|
|
21370
|
-
workspaceId:'',workspaceLabel:''
|
|
21374
|
+
workspaceId:'',workspaceLabel:'',durable:false
|
|
21371
21375
|
});
|
|
21372
21376
|
}
|
|
21373
21377
|
}
|
|
@@ -21474,6 +21478,13 @@ function classifyParallelTerminalIcon(icon) {
|
|
|
21474
21478
|
if (/check-circled|check/i.test(value)) return "completed";
|
|
21475
21479
|
return "unknown";
|
|
21476
21480
|
}
|
|
21481
|
+
function isDurablyRegisteredParallelEntry(entry) {
|
|
21482
|
+
return !!entry && entry.durable !== false && (entry.showSpinner || classifyParallelTerminalIcon(entry.icon) !== "unknown");
|
|
21483
|
+
}
|
|
21484
|
+
function uncertainSubmissionReservationScope(job, error2) {
|
|
21485
|
+
if (error2 && error2.requiresGlobalReservation) return "global";
|
|
21486
|
+
return job && job.readOnly ? "agent" : "paths";
|
|
21487
|
+
}
|
|
21477
21488
|
function providerErrorSignature(info) {
|
|
21478
21489
|
if (!info || info.found !== true) return "";
|
|
21479
21490
|
return String(info.signature || [info.title, info.message, info.requestId].filter(Boolean).join("|"));
|
|
@@ -21503,7 +21514,7 @@ function promoteAgentsWorkspaceLifecycle(lifecycle, agentsWorkspace) {
|
|
|
21503
21514
|
targetId: agentsWorkspace.targetId,
|
|
21504
21515
|
targetUiFlavor: agentsWorkspace.targetUiFlavor,
|
|
21505
21516
|
workspaceAction: "reused-agents-repository",
|
|
21506
|
-
message: `CCE
|
|
21517
|
+
message: `CCE confirmed that workspace ${lifecycle.projectPath || agentsWorkspace.workspace || ""} is available in Cursor Agents.`,
|
|
21507
21518
|
needsAction: null,
|
|
21508
21519
|
nextStep: null,
|
|
21509
21520
|
retryable: false
|
|
@@ -21590,8 +21601,8 @@ var CursorBridge = class {
|
|
|
21590
21601
|
bindingPersisted: true,
|
|
21591
21602
|
ready: false,
|
|
21592
21603
|
status: lifecycle.status,
|
|
21593
|
-
message: lifecycle.message || "CCE
|
|
21594
|
-
nextStep: lifecycle.nextStep || "
|
|
21604
|
+
message: lifecycle.message || "CCE initialization is not complete, but the workspace binding was saved.",
|
|
21605
|
+
nextStep: lifecycle.nextStep || "Resolve the reported condition, then run the same initialization command again.",
|
|
21595
21606
|
retryable: lifecycle.retryable !== false,
|
|
21596
21607
|
lifecycle
|
|
21597
21608
|
};
|
|
@@ -21602,8 +21613,8 @@ var CursorBridge = class {
|
|
|
21602
21613
|
bindingPersisted: true,
|
|
21603
21614
|
ready: true,
|
|
21604
21615
|
status: "ready",
|
|
21605
|
-
message: `CCE
|
|
21606
|
-
nextStep: "
|
|
21616
|
+
message: `CCE is ready to use workspace ${saved.projectPath}.`,
|
|
21617
|
+
nextStep: "You can now use cursor_context_engine or cursor_do directly.",
|
|
21607
21618
|
lifecycle: this._lastLifecycle
|
|
21608
21619
|
};
|
|
21609
21620
|
}
|
|
@@ -21728,10 +21739,10 @@ var CursorBridge = class {
|
|
|
21728
21739
|
}
|
|
21729
21740
|
async contextEngine(query) {
|
|
21730
21741
|
const text = String(query || "").trim();
|
|
21731
|
-
if (!text) throw new Error("query
|
|
21732
|
-
if (text.length > 2e4) throw new Error("query
|
|
21742
|
+
if (!text) throw new Error("query must not be empty");
|
|
21743
|
+
if (text.length > 2e4) throw new Error("query exceeds the 20,000-character limit");
|
|
21733
21744
|
if (this._hasGlobalReservation()) {
|
|
21734
|
-
throw new Error("
|
|
21745
|
+
throw new Error("A global Cursor reservation has an unconfirmed Stop state; resolve blockingTaskIds from cursor_status first");
|
|
21735
21746
|
}
|
|
21736
21747
|
await this._ensureCursor();
|
|
21737
21748
|
const job = this._enqueue("context_engine", buildContextEnginePrompt(text), {
|
|
@@ -21755,36 +21766,36 @@ var CursorBridge = class {
|
|
|
21755
21766
|
throw new Error("cursor_do is disabled by CURSOR_BRIDGE_DELEGATION=off; restart the MCP server without that setting to enable delegation");
|
|
21756
21767
|
}
|
|
21757
21768
|
const text = String(prompt || "").trim();
|
|
21758
|
-
if (!text) throw new Error("prompt
|
|
21759
|
-
if (text.length > 1e5) throw new Error("prompt
|
|
21769
|
+
if (!text) throw new Error("prompt must not be empty");
|
|
21770
|
+
if (text.length > 1e5) throw new Error("prompt exceeds the 100,000-character limit");
|
|
21760
21771
|
if (this._hasGlobalReservation()) {
|
|
21761
|
-
throw new Error("
|
|
21772
|
+
throw new Error("A global Cursor reservation has an unconfirmed Stop state; no new task may be submitted until it is explicitly recovered or released");
|
|
21762
21773
|
}
|
|
21763
21774
|
await this._ensureCursor();
|
|
21764
21775
|
const execution = String(options.execution || "fifo");
|
|
21765
21776
|
if (execution !== "fifo" && execution !== "parallel_agent") {
|
|
21766
|
-
throw new Error(`execution
|
|
21777
|
+
throw new Error(`Unsupported execution value ${execution}; expected fifo or parallel_agent`);
|
|
21767
21778
|
}
|
|
21768
21779
|
const readOnly = options.readOnly === true;
|
|
21769
21780
|
const timeoutMs = Math.max(3e4, Math.min(9e5, Number(options.timeoutMs || 6e5)));
|
|
21770
21781
|
const allowedPaths = Array.isArray(options.allowedPaths) ? options.allowedPaths.map((x) => String(x).trim()).filter(Boolean) : [];
|
|
21771
21782
|
if (readOnly && allowedPaths.length > 0) {
|
|
21772
|
-
throw new Error("read_only=true
|
|
21783
|
+
throw new Error("read_only=true cannot be combined with allowed_paths because a read-only task cannot declare a write scope");
|
|
21773
21784
|
}
|
|
21774
21785
|
if (execution === "parallel_agent" && !readOnly && allowedPaths.length === 0) {
|
|
21775
|
-
throw new Error("parallel_agent
|
|
21786
|
+
throw new Error("A parallel_agent write task must provide allowed_paths; set read_only=true explicitly for a read-only task");
|
|
21776
21787
|
}
|
|
21777
21788
|
if (execution === "parallel_agent" && !readOnly) {
|
|
21778
21789
|
this._validateParallelAllowedPaths(allowedPaths);
|
|
21779
21790
|
this._assertNoParallelPathConflict(allowedPaths);
|
|
21780
21791
|
}
|
|
21781
21792
|
const contract = String(options.completionContract || "").trim();
|
|
21782
|
-
let fullPrompt = text;
|
|
21783
|
-
if (readOnly) fullPrompt += "\n\
|
|
21793
|
+
let fullPrompt = text + DO_LANGUAGE_CONTRACT;
|
|
21794
|
+
if (readOnly) fullPrompt += "\n\nRead-only boundary: Do not modify, create, or delete files, and do not run commands that change workspace state.";
|
|
21784
21795
|
if (allowedPaths.length > 0) {
|
|
21785
|
-
fullPrompt += "\n\n
|
|
21796
|
+
fullPrompt += "\n\nAllowed modification scope (do not cross this boundary):\n" + allowedPaths.map((x) => "- " + x).join("\n");
|
|
21786
21797
|
}
|
|
21787
|
-
fullPrompt += contract ? "\n\n
|
|
21798
|
+
fullPrompt += contract ? "\n\nAcceptance and reporting contract:\n" + contract : DO_DEFAULT_CONTRACT;
|
|
21788
21799
|
const job = this._enqueue("do", fullPrompt, {
|
|
21789
21800
|
timeoutMs,
|
|
21790
21801
|
newChat: true,
|
|
@@ -21799,24 +21810,24 @@ var CursorBridge = class {
|
|
|
21799
21810
|
}
|
|
21800
21811
|
_assertNoParallelPathConflict(allowedPaths) {
|
|
21801
21812
|
if (this._hasGlobalReservation()) {
|
|
21802
|
-
throw new Error("
|
|
21813
|
+
throw new Error("A global Cursor reservation has an unconfirmed Stop state; no new parallel_agent write task may be submitted");
|
|
21803
21814
|
}
|
|
21804
21815
|
const live = [...this.tasks.values()].filter((job) => job.execution === "parallel_agent" && !job.readOnly && !isTerminalTask(job));
|
|
21805
21816
|
for (const job of live) {
|
|
21806
21817
|
const overlap = allowedPaths.some((a) => job.allowedPaths.some((b) => pathsOverlap(a, b)));
|
|
21807
|
-
if (overlap) throw new Error(`parallel_agent allowed_paths
|
|
21818
|
+
if (overlap) throw new Error(`parallel_agent allowed_paths overlap task ${job.id}; use fifo or split the work into non-overlapping paths`);
|
|
21808
21819
|
}
|
|
21809
21820
|
}
|
|
21810
21821
|
_validateParallelAllowedPaths(allowedPaths) {
|
|
21811
21822
|
for (const raw of allowedPaths) {
|
|
21812
21823
|
const slash = String(raw).replace(/\\/g, "/");
|
|
21813
|
-
if (/[*?\[\]{}!]/.test(slash)) throw new Error(`parallel_agent allowed_paths
|
|
21824
|
+
if (/[*?\[\]{}!]/.test(slash)) throw new Error(`parallel_agent allowed_paths do not accept globs: ${raw}`);
|
|
21814
21825
|
if (/^[a-zA-Z]:\//.test(slash) || slash.startsWith("/")) {
|
|
21815
|
-
throw new Error(`parallel_agent allowed_paths
|
|
21826
|
+
throw new Error(`parallel_agent allowed_paths must use workspace-relative paths: ${raw}`);
|
|
21816
21827
|
}
|
|
21817
21828
|
const normalized = normalizeAllowedPath(slash);
|
|
21818
21829
|
if (normalized === "." || normalized === ".." || normalized.startsWith("../")) {
|
|
21819
|
-
throw new Error(`parallel_agent allowed_paths
|
|
21830
|
+
throw new Error(`parallel_agent allowed_paths must not be empty or escape the workspace: ${raw}`);
|
|
21820
21831
|
}
|
|
21821
21832
|
}
|
|
21822
21833
|
}
|
|
@@ -21914,7 +21925,7 @@ var CursorBridge = class {
|
|
|
21914
21925
|
}
|
|
21915
21926
|
_cancelJob(job, reason, options = {}) {
|
|
21916
21927
|
if (isTerminalTask(job)) return this._taskView(job, true);
|
|
21917
|
-
const message = String(reason || "
|
|
21928
|
+
const message = String(reason || "Task cancelled").trim() || "Task cancelled";
|
|
21918
21929
|
this.queue = this.queue.filter((candidate) => candidate.id !== job.id);
|
|
21919
21930
|
this.activeParallel.delete(job.id);
|
|
21920
21931
|
this._invalidateParallelMonitor(job);
|
|
@@ -22040,9 +22051,9 @@ var CursorBridge = class {
|
|
|
22040
22051
|
console.error("\u26A0\uFE0F " + rr.message + " | " + life);
|
|
22041
22052
|
return;
|
|
22042
22053
|
}
|
|
22043
|
-
console.error("\u{1FA9F}
|
|
22054
|
+
console.error("\u{1FA9F} Cursor self-healing launch: " + (rr.message || rr.status) + " | " + life);
|
|
22044
22055
|
} catch (e) {
|
|
22045
|
-
console.error("\u26A0\uFE0F
|
|
22056
|
+
console.error("\u26A0\uFE0F Cursor self-healing failed; CCE or delegation was stopped to avoid driving the wrong workspace:", e.message);
|
|
22046
22057
|
throw e;
|
|
22047
22058
|
} finally {
|
|
22048
22059
|
this._healing = null;
|
|
@@ -22105,7 +22116,7 @@ var CursorBridge = class {
|
|
|
22105
22116
|
this._cancelJob(job, job.cancelReason, { underlyingStopConfirmed: true });
|
|
22106
22117
|
} else {
|
|
22107
22118
|
job.cancelRequested = false;
|
|
22108
|
-
this._orphanParallelJob(job, new Error(
|
|
22119
|
+
this._orphanParallelJob(job, new Error(`Unable to confirm that the Cursor Agent stopped: ${stopped.error || stopped.state}`));
|
|
22109
22120
|
job.recoveryState = "cancel_unconfirmed";
|
|
22110
22121
|
}
|
|
22111
22122
|
} else {
|
|
@@ -22120,19 +22131,19 @@ var CursorBridge = class {
|
|
|
22120
22131
|
} catch (error2) {
|
|
22121
22132
|
if (error2 && error2.cancelled || job.cancelRequested) {
|
|
22122
22133
|
if (error2 && error2.stopConfirmed) {
|
|
22123
|
-
this._cancelJob(job, job.cancelReason || error2.message || "
|
|
22134
|
+
this._cancelJob(job, job.cancelReason || error2.message || "Task cancelled", {
|
|
22124
22135
|
underlyingStopConfirmed: true
|
|
22125
22136
|
});
|
|
22126
22137
|
} else {
|
|
22127
22138
|
job.cancelRequested = false;
|
|
22128
|
-
this._orphanParallelJob(job, new Error("
|
|
22139
|
+
this._orphanParallelJob(job, new Error("Cancellation was requested, but Cursor could not be confirmed stopped; the reservation remains held"));
|
|
22129
22140
|
job.recoveryState = "cancel_unconfirmed";
|
|
22130
22141
|
}
|
|
22131
22142
|
} else if (error2 && error2.confirmedTerminal) {
|
|
22132
22143
|
this.activeParallel.delete(job.id);
|
|
22133
22144
|
this._failJob(job, error2);
|
|
22134
22145
|
} else if (error2 && error2.sent) {
|
|
22135
|
-
job.error =
|
|
22146
|
+
job.error = `Submission state is uncertain; monitoring continues by agentId: ${error2.message}`;
|
|
22136
22147
|
if (job.agentId) {
|
|
22137
22148
|
job.phase = "running";
|
|
22138
22149
|
job.reservationScope = job.readOnly ? "agent" : "paths";
|
|
@@ -22192,7 +22203,7 @@ var CursorBridge = class {
|
|
|
22192
22203
|
await this._bindFifoComposerIdentity(c, options);
|
|
22193
22204
|
this._throwIfCancelledBeforeSend(options);
|
|
22194
22205
|
const filled = await evalJS(c, exprFill(prompt));
|
|
22195
|
-
if (filled === "NO_INPUT" || filled === "EXEC_FAIL") throw new Error("
|
|
22206
|
+
if (filled === "NO_INPUT" || filled === "EXEC_FAIL") throw new Error("Failed to enter the query because the input state was invalid");
|
|
22196
22207
|
await sleep2(450);
|
|
22197
22208
|
this._throwIfCancelledBeforeSend(options);
|
|
22198
22209
|
let baseline = { messageCount: 0 };
|
|
@@ -22233,7 +22244,7 @@ var CursorBridge = class {
|
|
|
22233
22244
|
}
|
|
22234
22245
|
_throwIfCancelledBeforeSend(job) {
|
|
22235
22246
|
if (!job || !job.cancelRequested || job.sendState === "dispatching" || job.sendState === "sent") return;
|
|
22236
|
-
const error2 = new Error(job.cancelReason || "
|
|
22247
|
+
const error2 = new Error(job.cancelReason || "Task cancelled");
|
|
22237
22248
|
error2.cancelled = true;
|
|
22238
22249
|
error2.stopConfirmed = true;
|
|
22239
22250
|
error2.preSend = true;
|
|
@@ -22251,7 +22262,7 @@ var CursorBridge = class {
|
|
|
22251
22262
|
await sleep2(1300);
|
|
22252
22263
|
vis = await evalJS(c, EXPR_VISIBLE);
|
|
22253
22264
|
}
|
|
22254
|
-
if (!vis) throw new Error("
|
|
22265
|
+
if (!vis) throw new Error("Unable to open the Cursor chat or agent input panel. Confirm that Cursor is signed in and its window is available.");
|
|
22255
22266
|
}
|
|
22256
22267
|
// 清空对话上下文:定位 "New Agent" 钮后【Alt+click】——Alt 修饰使其执行 Replace Agent(清空旧对话),
|
|
22257
22268
|
// 而非新建(aria 标注 "New Agent (Ctrl+N) / [Alt] Replace Agent")。2026-06-08 实测回复区 markdown DOM 清空
|
|
@@ -22303,10 +22314,10 @@ var CursorBridge = class {
|
|
|
22303
22314
|
}
|
|
22304
22315
|
}
|
|
22305
22316
|
async _readAgentEntries(c, keepOpen = false) {
|
|
22306
|
-
if (!await this._ensureHistoryOpen(c)) throw new Error("Cursor Agent
|
|
22317
|
+
if (!await this._ensureHistoryOpen(c)) throw new Error("Cursor Agent list adapter is unavailable");
|
|
22307
22318
|
try {
|
|
22308
22319
|
const snapshot = JSON.parse(await evalJS(c, EXPR_HISTORY_ENTRIES));
|
|
22309
|
-
if (!snapshot.ok) throw new Error(snapshot.error || "Agent History React adapter
|
|
22320
|
+
if (!snapshot.ok) throw new Error(snapshot.error || "Agent History React adapter is unavailable");
|
|
22310
22321
|
return snapshot.entries || [];
|
|
22311
22322
|
} finally {
|
|
22312
22323
|
if (!keepOpen) await this._closeHistory(c);
|
|
@@ -22402,7 +22413,7 @@ var CursorBridge = class {
|
|
|
22402
22413
|
if (await accepted()) return "button";
|
|
22403
22414
|
}
|
|
22404
22415
|
}
|
|
22405
|
-
const error2 = new Error(`Cursor
|
|
22416
|
+
const error2 = new Error(`Cursor did not accept the submission (submit_not_accepted: ${clicked || "unknown"}); the prompt remains in the input and no orphan task was created`);
|
|
22406
22417
|
error2.confirmedNotSent = true;
|
|
22407
22418
|
throw error2;
|
|
22408
22419
|
}
|
|
@@ -22439,7 +22450,7 @@ var CursorBridge = class {
|
|
|
22439
22450
|
try {
|
|
22440
22451
|
before = await this._readAgentEntries(c);
|
|
22441
22452
|
} catch (e) {
|
|
22442
|
-
return { fallbackReason: `parallel_agent
|
|
22453
|
+
return { fallbackReason: `parallel_agent prerequisite is unavailable: ${e.message}` };
|
|
22443
22454
|
}
|
|
22444
22455
|
const previousSelectedId = (before.find((e) => e.isSelected) || {}).id || null;
|
|
22445
22456
|
this._throwIfCancelledBeforeSend(job);
|
|
@@ -22448,12 +22459,12 @@ var CursorBridge = class {
|
|
|
22448
22459
|
createdForWorkspace = job.targetUiFlavor === "agents_v2" && job.projectPath ? await this._newChat(c, { uiFlavor: job.targetUiFlavor, projectPath: job.projectPath }) : await this._clickNewAgent(c, false);
|
|
22449
22460
|
} catch (error2) {
|
|
22450
22461
|
if (isAgentsWorkspaceBindError(error2)) {
|
|
22451
|
-
return { fallbackReason: "Agents Window
|
|
22462
|
+
return { fallbackReason: "Agents Window could not bind the current repository; downgraded to FIFO/workbench before submission" };
|
|
22452
22463
|
}
|
|
22453
22464
|
throw error2;
|
|
22454
22465
|
}
|
|
22455
22466
|
if (!createdForWorkspace) {
|
|
22456
|
-
return { fallbackReason: "
|
|
22467
|
+
return { fallbackReason: "Cursor New Agent button was not found; downgraded to FIFO before submission" };
|
|
22457
22468
|
}
|
|
22458
22469
|
let agent = null;
|
|
22459
22470
|
for (let i = 0; i < 5 && !agent; i++) {
|
|
@@ -22471,7 +22482,7 @@ var CursorBridge = class {
|
|
|
22471
22482
|
await this._ensureChatPanel(c);
|
|
22472
22483
|
this._throwIfCancelledBeforeSend(job);
|
|
22473
22484
|
const filled = await evalJS(c, exprFill(job.prompt));
|
|
22474
|
-
if (filled === "NO_INPUT" || filled === "EXEC_FAIL") throw new Error("parallel_agent
|
|
22485
|
+
if (filled === "NO_INPUT" || filled === "EXEC_FAIL") throw new Error("Failed to enter the parallel_agent task");
|
|
22475
22486
|
await sleep2(350);
|
|
22476
22487
|
this._throwIfCancelledBeforeSend(job);
|
|
22477
22488
|
const providerErrorBaseline = providerErrorSignature(await this._readProviderError(c));
|
|
@@ -22487,18 +22498,26 @@ var CursorBridge = class {
|
|
|
22487
22498
|
job.sendState = "sent";
|
|
22488
22499
|
job.sentAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
22489
22500
|
agent = null;
|
|
22490
|
-
|
|
22501
|
+
let provisionalAgent = job.agentId ? { id: job.agentId, label: job.agentLabel } : null;
|
|
22502
|
+
for (let i = 0; i < 40 && !agent; i++) {
|
|
22491
22503
|
await sleep2(350);
|
|
22492
22504
|
await this._throwIfNewProviderError(c, providerErrorBaseline);
|
|
22493
22505
|
try {
|
|
22494
22506
|
const candidate = selectNewAgentEntry(before, await this._readAgentEntries(c));
|
|
22495
|
-
if (candidate &&
|
|
22507
|
+
if (candidate && !provisionalAgent) {
|
|
22508
|
+
provisionalAgent = candidate;
|
|
22509
|
+
job.agentId = candidate.id;
|
|
22510
|
+
job.agentLabel = candidate.label || null;
|
|
22511
|
+
}
|
|
22512
|
+
if (isDurablyRegisteredParallelEntry(candidate)) agent = candidate;
|
|
22496
22513
|
} catch {
|
|
22497
22514
|
}
|
|
22498
22515
|
}
|
|
22499
22516
|
if (!agent) {
|
|
22500
|
-
const e = new Error("
|
|
22517
|
+
const e = new Error(provisionalAgent ? `Cursor Agent ${provisionalAgent.id} was submitted but did not become a durable Agent History row; the reservation remains held and automatic resubmission is forbidden` : "The task may have been submitted, but a unique agentId could not be captured from Agent History; the reservation remains held and automatic resubmission is forbidden");
|
|
22501
22518
|
e.sent = true;
|
|
22519
|
+
e.requiresGlobalReservation = !!provisionalAgent;
|
|
22520
|
+
e.recoveryState = provisionalAgent ? "awaiting_durable_history" : "unbound_agent";
|
|
22502
22521
|
throw e;
|
|
22503
22522
|
}
|
|
22504
22523
|
job.agentId = agent.id;
|
|
@@ -22564,12 +22583,12 @@ var CursorBridge = class {
|
|
|
22564
22583
|
transientErrors = 0;
|
|
22565
22584
|
} catch (e) {
|
|
22566
22585
|
transientErrors++;
|
|
22567
|
-
if (transientErrors >= 45) throw new Error(
|
|
22586
|
+
if (transientErrors >= 45) throw new Error(`Agent History remained unreadable: ${e.message}`);
|
|
22568
22587
|
continue;
|
|
22569
22588
|
}
|
|
22570
22589
|
if (!entry) {
|
|
22571
22590
|
missingPolls++;
|
|
22572
|
-
if (missingPolls >= 45) throw new Error(`Agent History
|
|
22591
|
+
if (missingPolls >= 45) throw new Error(`Agent History continued to omit ${job.agentId}`);
|
|
22573
22592
|
continue;
|
|
22574
22593
|
}
|
|
22575
22594
|
missingPolls = 0;
|
|
@@ -22588,19 +22607,19 @@ var CursorBridge = class {
|
|
|
22588
22607
|
completedStable = 0;
|
|
22589
22608
|
if (terminalErrorStable >= 2) {
|
|
22590
22609
|
if (terminalClass === "needs_attention") {
|
|
22591
|
-
throw new Error(`Cursor Agent ${job.agentId}
|
|
22610
|
+
throw new Error(`Cursor Agent ${job.agentId} is waiting for user action`);
|
|
22592
22611
|
}
|
|
22593
22612
|
if (terminalClass === "cancelled") {
|
|
22594
22613
|
await this._withJobLock(job, async () => {
|
|
22595
22614
|
if (!this._monitorOwns(job, generation)) return;
|
|
22596
22615
|
job.terminalEvidence = `stable_history_icon:${entry.icon}`;
|
|
22597
|
-
this._cancelJob(job, `Cursor Agent ${job.agentId}
|
|
22616
|
+
this._cancelJob(job, `Cursor Agent ${job.agentId} reached a stable cancelled terminal state`, {
|
|
22598
22617
|
underlyingStopConfirmed: true
|
|
22599
22618
|
});
|
|
22600
22619
|
});
|
|
22601
22620
|
return;
|
|
22602
22621
|
}
|
|
22603
|
-
const error2 = new Error(`Cursor Agent ${job.agentId}
|
|
22622
|
+
const error2 = new Error(`Cursor Agent ${job.agentId} reached stable failure state ${entry.icon}`);
|
|
22604
22623
|
error2.confirmedTerminal = true;
|
|
22605
22624
|
throw error2;
|
|
22606
22625
|
}
|
|
@@ -22629,7 +22648,7 @@ var CursorBridge = class {
|
|
|
22629
22648
|
if (!this._monitorOwns(job, generation)) return "stale";
|
|
22630
22649
|
collectionAttempts++;
|
|
22631
22650
|
lastCollectionError = error2.message;
|
|
22632
|
-
job.error =
|
|
22651
|
+
job.error = `Result collection attempt ${collectionAttempts} did not complete; retrying: ${error2.message}`;
|
|
22633
22652
|
job.phase = "running";
|
|
22634
22653
|
return "retry";
|
|
22635
22654
|
}
|
|
@@ -22644,8 +22663,8 @@ var CursorBridge = class {
|
|
|
22644
22663
|
}
|
|
22645
22664
|
}
|
|
22646
22665
|
if (!this._monitorOwns(job, generation)) return;
|
|
22647
|
-
const detail = lastCollectionError ?
|
|
22648
|
-
throw new Error(`Cursor parallel_agent
|
|
22666
|
+
const detail = lastCollectionError ? `; last collection error: ${lastCollectionError}` : "";
|
|
22667
|
+
throw new Error(`Cursor parallel_agent task timed out (${job.timeoutMs}ms)${detail}`);
|
|
22649
22668
|
}
|
|
22650
22669
|
async _waitForSelectedAgent(c, agentId, timeoutMs = 15e3) {
|
|
22651
22670
|
const deadline = Date.now() + timeoutMs;
|
|
@@ -22655,7 +22674,7 @@ var CursorBridge = class {
|
|
|
22655
22674
|
if (target && target.isSelected) return true;
|
|
22656
22675
|
await sleep2(250);
|
|
22657
22676
|
}
|
|
22658
|
-
throw new Error(
|
|
22677
|
+
throw new Error(`After opening ${agentId}, it could not be confirmed as the selected Agent`);
|
|
22659
22678
|
}
|
|
22660
22679
|
async _collectParallelAgent(job) {
|
|
22661
22680
|
const page = await findPage({ targetId: job.targetId, purpose: "parallel_agent" });
|
|
@@ -22666,7 +22685,7 @@ var CursorBridge = class {
|
|
|
22666
22685
|
const entries = await this._readAgentEntries(c, true);
|
|
22667
22686
|
previousSelectedId = (entries.find((e) => e.isSelected) || {}).id || null;
|
|
22668
22687
|
const opened = await evalJS(c, exprOpenAgent(job.agentId));
|
|
22669
|
-
if (opened !== "OPENED") throw new Error(
|
|
22688
|
+
if (opened !== "OPENED") throw new Error(`Unable to open ${job.agentId}: ${opened}`);
|
|
22670
22689
|
await this._closeHistory(c);
|
|
22671
22690
|
await this._waitForSelectedAgent(c, job.agentId);
|
|
22672
22691
|
let answer = "";
|
|
@@ -22693,7 +22712,7 @@ var CursorBridge = class {
|
|
|
22693
22712
|
}
|
|
22694
22713
|
await sleep2(300);
|
|
22695
22714
|
}
|
|
22696
|
-
if (!answer) throw new Error(
|
|
22715
|
+
if (!answer) throw new Error(`${job.agentId} was opened, but no final assistant reply was found`);
|
|
22697
22716
|
if (previousSelectedId && previousSelectedId !== job.agentId) {
|
|
22698
22717
|
if (await this._ensureHistoryOpen(c)) {
|
|
22699
22718
|
await evalJS(c, exprOpenAgent(previousSelectedId));
|
|
@@ -22709,7 +22728,7 @@ var CursorBridge = class {
|
|
|
22709
22728
|
}
|
|
22710
22729
|
_reapWithoutResult(job, error2, evidence) {
|
|
22711
22730
|
if (isTerminalTask(job)) return;
|
|
22712
|
-
const message = error2 instanceof Error ? error2.message : String(error2 || "Cursor Agent
|
|
22731
|
+
const message = error2 instanceof Error ? error2.message : String(error2 || "The Cursor Agent terminated, but its final reply could not be collected");
|
|
22713
22732
|
job.status = "needs_attention";
|
|
22714
22733
|
job.phase = "orphaned";
|
|
22715
22734
|
job.finishedAt = null;
|
|
@@ -22718,7 +22737,8 @@ var CursorBridge = class {
|
|
|
22718
22737
|
job.resultUnavailable = true;
|
|
22719
22738
|
job.terminalEvidence = evidence || "stable_completed_history_icon";
|
|
22720
22739
|
job.recoveryState = "terminal_result_uncollected";
|
|
22721
|
-
job.reservationScope = job
|
|
22740
|
+
job.reservationScope = uncertainSubmissionReservationScope(job, error2);
|
|
22741
|
+
job.recoveryState = error2.recoveryState || "monitoring_uncertain_submission";
|
|
22722
22742
|
}
|
|
22723
22743
|
_abandonJob(job, reason) {
|
|
22724
22744
|
if (isTerminalTask(job)) return this._taskView(job, true);
|
|
@@ -22753,16 +22773,16 @@ var CursorBridge = class {
|
|
|
22753
22773
|
} catch (error2) {
|
|
22754
22774
|
job.lastRecoveryAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
22755
22775
|
job.recoveryState = "history_unavailable";
|
|
22756
|
-
job.error =
|
|
22776
|
+
job.error = `Failed to recheck Agent History: ${error2.message}`;
|
|
22757
22777
|
return { stable: false, error: error2.message, entry: null };
|
|
22758
22778
|
}
|
|
22759
22779
|
job.lastRecoveryAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
22760
22780
|
if (!first || !second) {
|
|
22761
22781
|
job.recoveryState = "agent_missing";
|
|
22762
|
-
return { stable: false, error: "Agent History
|
|
22782
|
+
return { stable: false, error: "The bound agentId was not found in Agent History", entry: second || first || null };
|
|
22763
22783
|
}
|
|
22764
22784
|
const stable = first.id === second.id && first.showSpinner === second.showSpinner && String(first.icon || "") === String(second.icon || "");
|
|
22765
|
-
return { stable, entry: second, error: stable ? null : "Agent History
|
|
22785
|
+
return { stable, entry: second, error: stable ? null : "Agent History state is not yet stable" };
|
|
22766
22786
|
}
|
|
22767
22787
|
async _reapParallelJob(job, options = {}) {
|
|
22768
22788
|
if (!job) return { changed: false, state: "missing", task: null };
|
|
@@ -22796,11 +22816,11 @@ var CursorBridge = class {
|
|
|
22796
22816
|
const terminalClass = classifyParallelTerminalIcon(icon);
|
|
22797
22817
|
if (terminalClass === "cancelled") {
|
|
22798
22818
|
job.terminalEvidence = `stable_history_icon:${icon || "cancelled"}`;
|
|
22799
|
-
const task = this._cancelJob(job, `Cursor Agent ${job.agentId}
|
|
22819
|
+
const task = this._cancelJob(job, `Cursor Agent ${job.agentId} reached a cancelled terminal state`, { underlyingStopConfirmed: true });
|
|
22800
22820
|
return { changed: true, state: "cancelled", task };
|
|
22801
22821
|
}
|
|
22802
22822
|
if (terminalClass === "failed") {
|
|
22803
|
-
const error2 = new Error(`Cursor Agent ${job.agentId}
|
|
22823
|
+
const error2 = new Error(`Cursor Agent ${job.agentId} reached stable failure state ${icon}`);
|
|
22804
22824
|
job.terminalEvidence = `stable_history_icon:${icon}`;
|
|
22805
22825
|
this.activeParallel.delete(job.id);
|
|
22806
22826
|
this._failJob(job, error2);
|
|
@@ -22825,7 +22845,7 @@ var CursorBridge = class {
|
|
|
22825
22845
|
changed: false,
|
|
22826
22846
|
state: "terminal_uncollected",
|
|
22827
22847
|
error: error2.message,
|
|
22828
|
-
next: "
|
|
22848
|
+
next: "The underlying Agent is stably complete, but its final reply has not been collected. Retry with reap, or explicitly abandon only if a missing reply is acceptable.",
|
|
22829
22849
|
task: this._taskView(job, true)
|
|
22830
22850
|
};
|
|
22831
22851
|
}
|
|
@@ -22996,23 +23016,23 @@ var CursorBridge = class {
|
|
|
22996
23016
|
}
|
|
22997
23017
|
async taskControl(taskId, options = {}) {
|
|
22998
23018
|
const id = String(taskId || "").trim();
|
|
22999
|
-
if (!id) throw new Error("task_id
|
|
23019
|
+
if (!id) throw new Error("task_id must not be empty");
|
|
23000
23020
|
const job = this.tasks.get(id);
|
|
23001
23021
|
if (!job) return { found: false, taskId: id };
|
|
23002
23022
|
const action = String(options.action || "reap").trim().toLowerCase();
|
|
23003
23023
|
if (!["reap", "cancel", "abandon"].includes(action)) {
|
|
23004
|
-
throw new Error(
|
|
23024
|
+
throw new Error(`Unsupported action=${action}; expected reap, cancel, or abandon`);
|
|
23005
23025
|
}
|
|
23006
23026
|
const reason = String(options.reason || "").trim();
|
|
23007
23027
|
const expectedAgentId = String(options.expectedAgentId || "").trim();
|
|
23008
|
-
if (action !== "reap" && options.confirm !== true) throw new Error(`${action}
|
|
23028
|
+
if (action !== "reap" && options.confirm !== true) throw new Error(`${action} requires confirm=true`);
|
|
23009
23029
|
const submittingCancelWithoutPublishedId = action === "cancel" && job.phase === "submitting" && !expectedAgentId;
|
|
23010
23030
|
if (job.agentId && action !== "reap" && !submittingCancelWithoutPublishedId && expectedAgentId !== job.agentId) {
|
|
23011
|
-
throw new Error(`expected_agent_id
|
|
23031
|
+
throw new Error(`expected_agent_id does not match; the task is bound to ${job.agentId}`);
|
|
23012
23032
|
}
|
|
23013
23033
|
if (action === "cancel" && !isTerminalTask(job)) {
|
|
23014
23034
|
job.cancelRequested = true;
|
|
23015
|
-
job.cancelReason = reason || (job.execution === "parallel_agent" ? "
|
|
23035
|
+
job.cancelReason = reason || (job.execution === "parallel_agent" ? "User requested Cursor Agent cancellation" : "User requested FIFO task cancellation");
|
|
23016
23036
|
job.cancelRequestSeq = Number(job.cancelRequestSeq || 0) + 1;
|
|
23017
23037
|
}
|
|
23018
23038
|
return this._withJobLock(job, () => this._taskControlLocked(job, action, {
|
|
@@ -23025,7 +23045,7 @@ var CursorBridge = class {
|
|
|
23025
23045
|
if (action === "reap") {
|
|
23026
23046
|
const result = await this._reapParallelJobLocked(job, { reattach: true });
|
|
23027
23047
|
if (result.state === "not_parallel_reservation" && job.phase === "orphaned") {
|
|
23028
|
-
result.next = job.agentId ? "FIFO
|
|
23048
|
+
result.next = job.agentId ? "FIFO is bound to an agentId, but reap applies only to parallel_agent. Use cancel for a targeted stop, or abandon after confirmation." : "The FIFO orphan has no agentId that can be safely rebound. Confirm that it stopped in the Cursor UI before explicitly abandoning it.";
|
|
23029
23049
|
}
|
|
23030
23050
|
return { found: true, action, ...result };
|
|
23031
23051
|
}
|
|
@@ -23034,18 +23054,18 @@ var CursorBridge = class {
|
|
|
23034
23054
|
}
|
|
23035
23055
|
if (action === "abandon") {
|
|
23036
23056
|
if (options.acknowledgeMayStillWrite !== true) {
|
|
23037
|
-
throw new Error("abandon
|
|
23057
|
+
throw new Error("abandon requires acknowledge_may_still_write=true");
|
|
23038
23058
|
}
|
|
23039
|
-
if (!options.reason) throw new Error("abandon
|
|
23059
|
+
if (!options.reason) throw new Error("abandon requires a non-empty reason");
|
|
23040
23060
|
if (job.phase !== "orphaned" && job.phase !== "cancelling" && job.status !== "needs_attention") {
|
|
23041
|
-
throw new Error("abandon
|
|
23061
|
+
throw new Error("abandon is allowed only for tasks in needs_attention, orphaned, or cancelling state");
|
|
23042
23062
|
}
|
|
23043
23063
|
return {
|
|
23044
23064
|
found: true,
|
|
23045
23065
|
action,
|
|
23046
23066
|
changed: true,
|
|
23047
23067
|
state: "abandoned",
|
|
23048
|
-
warning: "Bridge
|
|
23068
|
+
warning: "The Bridge released its reservation, but cannot prove that the underlying Cursor Agent stopped; it may still write files.",
|
|
23049
23069
|
task: this._abandonJob(job, options.reason)
|
|
23050
23070
|
};
|
|
23051
23071
|
}
|
|
@@ -23055,7 +23075,7 @@ var CursorBridge = class {
|
|
|
23055
23075
|
action,
|
|
23056
23076
|
changed: true,
|
|
23057
23077
|
state: "cancelled",
|
|
23058
|
-
task: this._cancelJob(job, options.reason || "
|
|
23078
|
+
task: this._cancelJob(job, options.reason || "Queued task cancelled", { underlyingStopConfirmed: true })
|
|
23059
23079
|
};
|
|
23060
23080
|
}
|
|
23061
23081
|
if (job.phase === "orphaned" && !job.agentId) {
|
|
@@ -23065,7 +23085,7 @@ var CursorBridge = class {
|
|
|
23065
23085
|
action,
|
|
23066
23086
|
changed: false,
|
|
23067
23087
|
state: "cancel_unconfirmed",
|
|
23068
|
-
next: "
|
|
23088
|
+
next: "The task is orphaned without a safely targetable identity and still holds the global reservation. Confirm that it stopped in the Cursor UI before explicitly abandoning it.",
|
|
23069
23089
|
task: this._taskView(job, true)
|
|
23070
23090
|
};
|
|
23071
23091
|
}
|
|
@@ -23077,7 +23097,7 @@ var CursorBridge = class {
|
|
|
23077
23097
|
action,
|
|
23078
23098
|
changed: true,
|
|
23079
23099
|
state: job.recoveryState,
|
|
23080
|
-
next: "Bridge
|
|
23100
|
+
next: "The Bridge latched the cancellation request. It will stop before submission, or bind the agentId and issue a targeted stop if the message was already sent.",
|
|
23081
23101
|
task: this._taskView(job, true)
|
|
23082
23102
|
};
|
|
23083
23103
|
}
|
|
@@ -23121,14 +23141,14 @@ var CursorBridge = class {
|
|
|
23121
23141
|
job.phase = "orphaned";
|
|
23122
23142
|
job.cancelRequested = false;
|
|
23123
23143
|
job.recoveryState = "cancel_unconfirmed";
|
|
23124
|
-
job.error =
|
|
23144
|
+
job.error = `Unable to confirm that the Cursor Agent stopped: ${stopped.error || stopped.state}`;
|
|
23125
23145
|
return {
|
|
23126
23146
|
found: true,
|
|
23127
23147
|
action,
|
|
23128
23148
|
changed: false,
|
|
23129
23149
|
state: "cancel_unconfirmed",
|
|
23130
23150
|
stop: stopped,
|
|
23131
|
-
next: "
|
|
23151
|
+
next: "After confirming that the Cursor UI has stopped, retry cancel. Use abandon only when explicitly accepting the risk.",
|
|
23132
23152
|
task: this._taskView(job, true)
|
|
23133
23153
|
};
|
|
23134
23154
|
}
|
|
@@ -23140,7 +23160,7 @@ var CursorBridge = class {
|
|
|
23140
23160
|
action,
|
|
23141
23161
|
changed: true,
|
|
23142
23162
|
state: "cancel_pending_stop",
|
|
23143
|
-
next: "Bridge
|
|
23163
|
+
next: "The Bridge latched the cancellation request. The running FIFO task will be stopped through its bound agentId without clicking an ambiguous Stop control.",
|
|
23144
23164
|
task: this._taskView(job, true)
|
|
23145
23165
|
};
|
|
23146
23166
|
}
|
|
@@ -23151,7 +23171,7 @@ var CursorBridge = class {
|
|
|
23151
23171
|
action,
|
|
23152
23172
|
changed: true,
|
|
23153
23173
|
state: "cancel_pending_fifo",
|
|
23154
|
-
next: "FIFO
|
|
23174
|
+
next: "FIFO has no safely targetable agentId, so the Bridge will not click an ambiguous Stop control. The task becomes a global orphan reservation; confirm that it stopped manually before abandoning it.",
|
|
23155
23175
|
task: this._taskView(job, true)
|
|
23156
23176
|
};
|
|
23157
23177
|
}
|
|
@@ -23185,7 +23205,7 @@ var CursorBridge = class {
|
|
|
23185
23205
|
await this._closeHistory(c);
|
|
23186
23206
|
c.close();
|
|
23187
23207
|
}
|
|
23188
|
-
}).catch((e) => console.error("\u26A0\uFE0F
|
|
23208
|
+
}).catch((e) => console.error("\u26A0\uFE0F Failed to restore the original Cursor Agent: " + e.message));
|
|
23189
23209
|
}
|
|
23190
23210
|
async _waitComplete(c, timeoutMs = QUERY_TIMEOUT, baselineCount = 0, job = null, providerErrorBaseline = "") {
|
|
23191
23211
|
const start = Date.now();
|
|
@@ -23203,14 +23223,14 @@ var CursorBridge = class {
|
|
|
23203
23223
|
} catch (error2) {
|
|
23204
23224
|
stopped = { confirmed: false, state: "stop_error", error: error2.message };
|
|
23205
23225
|
}
|
|
23206
|
-
const e2 = new Error(job.cancelReason || "
|
|
23226
|
+
const e2 = new Error(job.cancelReason || "Task cancelled");
|
|
23207
23227
|
e2.cancelled = true;
|
|
23208
23228
|
e2.stopConfirmed = stopped.confirmed === true;
|
|
23209
23229
|
e2.stop = stopped;
|
|
23210
23230
|
if (stopped.confirmed) job.terminalEvidence = `targeted_stop:${job.agentId}`;
|
|
23211
23231
|
throw e2;
|
|
23212
23232
|
}
|
|
23213
|
-
const e = new Error(job.cancelReason || "
|
|
23233
|
+
const e = new Error(job.cancelReason || "Task cancelled");
|
|
23214
23234
|
e.cancelled = true;
|
|
23215
23235
|
e.stopConfirmed = false;
|
|
23216
23236
|
throw e;
|
|
@@ -23254,8 +23274,8 @@ var CursorBridge = class {
|
|
|
23254
23274
|
sawStop,
|
|
23255
23275
|
baselineCount
|
|
23256
23276
|
})) return ans;
|
|
23257
|
-
const taskHint = job && job.id ?
|
|
23258
|
-
throw new Error(`Cursor
|
|
23277
|
+
const taskHint = job && job.id ? `; task_id=${job.id}. Inspect it with cursor_status(task_id) and follow the recovery flow` : "";
|
|
23278
|
+
throw new Error(`Cursor task timed out (${timeoutMs}ms) before generation was confirmed stopped with a complete assistant reply${taskHint}`);
|
|
23259
23279
|
}
|
|
23260
23280
|
_taskView(job, includeResult = false) {
|
|
23261
23281
|
const view = {
|
|
@@ -23298,9 +23318,9 @@ var CursorBridge = class {
|
|
|
23298
23318
|
if (includeResult || isTerminalTask(job)) view.result = job.result;
|
|
23299
23319
|
if (job.phase === "orphaned") {
|
|
23300
23320
|
if (job.recoveryState === "terminal_result_uncollected") {
|
|
23301
|
-
view.attention = "Agent History
|
|
23321
|
+
view.attention = "Agent History proves that the underlying task ended, but its final reply has not been collected. Retry with reap, or explicitly abandon only if a missing reply is acceptable.";
|
|
23302
23322
|
} else {
|
|
23303
|
-
view.attention = job.agentId ? job.execution === "parallel_agent" ? "
|
|
23323
|
+
view.attention = job.agentId ? job.execution === "parallel_agent" ? "Use cursor_task_control(action=reap) to recheck the original agentId. Use cancel when a stop is needed, and abandon only after manual confirmation while accepting residual write risk." : "FIFO is bound to an agentId. Use cursor_task_control(action=cancel) with the exact expected_agent_id for a targeted stop." : "This orphan has no agentId that can be safely rebound and globally blocks new delegation. Confirm that it stopped in the Cursor UI, then explicitly release it with cursor_task_control(action=abandon).";
|
|
23304
23324
|
}
|
|
23305
23325
|
}
|
|
23306
23326
|
return view;
|
|
@@ -23441,7 +23461,7 @@ function buildToolDefinitions(bridgeInstance) {
|
|
|
23441
23461
|
var ADAPTER_START_CWD = process.cwd();
|
|
23442
23462
|
var bridge = new CursorBridge({ adapterStartCwd: ADAPTER_START_CWD });
|
|
23443
23463
|
var server = new Server(
|
|
23444
|
-
{ name: "cursor-bridge", version: "5.
|
|
23464
|
+
{ name: "cursor-bridge", version: "5.5.0" },
|
|
23445
23465
|
{ capabilities: { tools: { listChanged: true } } }
|
|
23446
23466
|
);
|
|
23447
23467
|
async function ensureBridgeCursor(targetBridge, reason) {
|
|
@@ -23555,26 +23575,26 @@ server.setRequestHandler(CallToolRequestSchema, async (request2) => {
|
|
|
23555
23575
|
const r = await ensureBridgeCursor(bridge, "cursor_launch");
|
|
23556
23576
|
return { content: [{ type: "text", text: JSON.stringify(r, null, 2) }], isError: !r.ok };
|
|
23557
23577
|
}
|
|
23558
|
-
throw new Error(
|
|
23578
|
+
throw new Error(`Unknown tool: ${name}`);
|
|
23559
23579
|
} catch (error2) {
|
|
23560
|
-
return { content: [{ type: "text", text:
|
|
23580
|
+
return { content: [{ type: "text", text: `Error: ${error2 instanceof Error ? error2.message : String(error2)}` }], isError: true };
|
|
23561
23581
|
}
|
|
23562
23582
|
});
|
|
23563
23583
|
async function main() {
|
|
23564
|
-
console.error("\u{1F680}
|
|
23584
|
+
console.error("\u{1F680} Starting cursor-bridge (direct CDP on port " + CDP_PORT2 + ")...");
|
|
23565
23585
|
const releasedCwd = releaseAdapterWorkingDirectory();
|
|
23566
|
-
console.error(`\u{1F513} MCP
|
|
23586
|
+
console.error(`\u{1F513} MCP working directory released from the plugin cache: ${releasedCwd}`);
|
|
23567
23587
|
const startupEnsure = shouldAutoLaunchCursor() ? ensureBridgeCursor(bridge, "adapter-startup").then((r) => {
|
|
23568
23588
|
console.error(
|
|
23569
|
-
"\u{1FA9F}
|
|
23589
|
+
"\u{1FA9F} Startup Cursor check: " + (r.message || r.status) + " | adapterPid=" + bridge._lastLifecycle.adapterPid + " supervisorPid=" + bridge._lastLifecycle.supervisorPid + " reused=" + bridge._lastLifecycle.reusedSupervisor + " reason=" + bridge._lastLifecycle.launchReason
|
|
23570
23590
|
);
|
|
23571
23591
|
return r;
|
|
23572
23592
|
}).catch((error2) => {
|
|
23573
|
-
console.error("\u26A0\uFE0F
|
|
23593
|
+
console.error("\u26A0\uFE0F Startup Cursor launch failed; continuing and retrying on demand:", error2.message);
|
|
23574
23594
|
return null;
|
|
23575
23595
|
}) : Promise.resolve(null);
|
|
23576
23596
|
await server.connect(new StdioServerTransport());
|
|
23577
|
-
console.error("\u2705 MCP
|
|
23597
|
+
console.error("\u2705 MCP connected.");
|
|
23578
23598
|
void startupEnsure;
|
|
23579
23599
|
}
|
|
23580
23600
|
var isMain2 = import.meta.url === pathToFileURL2(process.argv[1] || "").href;
|
|
@@ -23582,7 +23602,7 @@ if (isMain2) {
|
|
|
23582
23602
|
process.on("unhandledRejection", (r) => console.error("unhandledRejection:", r));
|
|
23583
23603
|
process.on("SIGINT", () => process.exit(0));
|
|
23584
23604
|
main().catch((e) => {
|
|
23585
|
-
console.error("\u274C
|
|
23605
|
+
console.error("\u274C Fatal error:", e);
|
|
23586
23606
|
process.exit(1);
|
|
23587
23607
|
});
|
|
23588
23608
|
}
|
|
@@ -23611,6 +23631,7 @@ export {
|
|
|
23611
23631
|
exprOpenAgent,
|
|
23612
23632
|
isBlankAgentsWindow,
|
|
23613
23633
|
isConfirmedCompletedReply,
|
|
23634
|
+
isDurablyRegisteredParallelEntry,
|
|
23614
23635
|
isTargetedStopConfirmed,
|
|
23615
23636
|
normalizeAllowedPath,
|
|
23616
23637
|
normalizeCceSearchResult,
|
|
@@ -23627,5 +23648,6 @@ export {
|
|
|
23627
23648
|
shouldAutoLaunchCursor,
|
|
23628
23649
|
shouldRecoverNormalAgentsPresentation,
|
|
23629
23650
|
summarizeCdpPages,
|
|
23651
|
+
uncertainSubmissionReservationScope,
|
|
23630
23652
|
updateStableEntryObservation
|
|
23631
23653
|
};
|