pi-cursor-bridge 0.2.3 → 0.2.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 +1 -1
- package/README.md +4 -2
- package/dist/cursor-bridge.mjs +167 -22
- package/dist/cursor-lifecycle-supervisor.mjs +10 -3
- package/extensions/index.ts +1 -1
- package/package.json +3 -3
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cursor-bridge",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.4+codex.20260921093343",
|
|
4
4
|
"description": "Evidence-backed Cursor Context Engine search and bounded Cursor Agent execution, including a UI-suppressed minimal runtime.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Vanyangyang"
|
package/README.md
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
# Cursor Bridge for Pi
|
|
2
2
|
|
|
3
|
+
> **Windows only:** Cursor Bridge currently supports Windows only. macOS and Linux are not supported or covered by end-to-end acceptance.
|
|
4
|
+
|
|
3
5
|
Use Cursor's project index and Agent search from Pi, with compact `path:line` evidence and optional bounded Cursor task execution.
|
|
4
6
|
|
|
5
|
-
⭐ If Cursor Bridge helps you, please consider giving it a
|
|
7
|
+
⭐ If Cursor Bridge helps you, please consider giving it a Star on GitHub—it helps others discover the project.
|
|
6
8
|
|
|
7
9
|
```powershell
|
|
8
10
|
pi install npm:pi-cursor-bridge
|
|
@@ -10,6 +12,6 @@ pi install npm:pi-cursor-bridge
|
|
|
10
12
|
|
|
11
13
|
Restart Pi after installation. Initialize the current project by asking Pi to initialize Cursor Bridge for the absolute project path, then use it normally. The package includes the `cce-routing` and `cursor-delegate` Skills and registers the native Cursor Bridge MCP tools directly in Pi.
|
|
12
14
|
|
|
13
|
-
Pi wrapper 0.2.
|
|
15
|
+
Pi wrapper 0.2.4 embeds Cursor Bridge 6.0.4, including explicit request provenance for CCE and delegated tasks. Its result contract returns a compact receipt for background `cursor_do` work: poll `cursor_status(task_id)` normally, retrieve the terminal raw reply with `cursor_status(task_id, detail="result")`, check `isError` before using its content, and use `detail="full"` only when diagnostics are needed. Cursor must be installed and signed in. Current end-to-end compatibility claims remain scoped to the environments documented in the main repository.
|
|
14
16
|
|
|
15
17
|
Full documentation: [English](https://github.com/Vanyangyang/cursor-bridge#readme) · [简体中文](https://github.com/Vanyangyang/cursor-bridge/blob/main/README.zh-CN.md)
|
package/dist/cursor-bridge.mjs
CHANGED
|
@@ -3115,6 +3115,7 @@ var require_utils = __commonJS({
|
|
|
3115
3115
|
"use strict";
|
|
3116
3116
|
var isUUID = RegExp.prototype.test.bind(/^[\da-f]{8}-[\da-f]{4}-[\da-f]{4}-[\da-f]{4}-[\da-f]{12}$/iu);
|
|
3117
3117
|
var isIPv4 = RegExp.prototype.test.bind(/^(?:(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)\.){3}(?:25[0-5]|2[0-4]\d|1\d{2}|[1-9]\d|\d)$/u);
|
|
3118
|
+
var isPort = RegExp.prototype.test.bind(/^\d*$/u);
|
|
3118
3119
|
var isHexPair = RegExp.prototype.test.bind(/^[\da-f]{2}$/iu);
|
|
3119
3120
|
var isUnreserved = RegExp.prototype.test.bind(/^[\da-z\-._~]$/iu);
|
|
3120
3121
|
var isPathCharacter = RegExp.prototype.test.bind(/^[A-Za-z0-9\-._~!$&'()*+,;=:@/]$/u);
|
|
@@ -3580,8 +3581,12 @@ var require_utils = __commonJS({
|
|
|
3580
3581
|
uriTokens.push(host);
|
|
3581
3582
|
}
|
|
3582
3583
|
if (typeof component.port === "number" || typeof component.port === "string") {
|
|
3584
|
+
const port = String(component.port);
|
|
3585
|
+
if (!isPort(port)) {
|
|
3586
|
+
throw new TypeError("URI port is malformed.");
|
|
3587
|
+
}
|
|
3583
3588
|
uriTokens.push(":");
|
|
3584
|
-
uriTokens.push(
|
|
3589
|
+
uriTokens.push(port);
|
|
3585
3590
|
}
|
|
3586
3591
|
return uriTokens.length ? uriTokens.join("") : void 0;
|
|
3587
3592
|
}
|
|
@@ -4024,12 +4029,15 @@ var require_fast_uri = __commonJS({
|
|
|
4024
4029
|
}
|
|
4025
4030
|
return false;
|
|
4026
4031
|
}
|
|
4032
|
+
function isIPLiteral(host) {
|
|
4033
|
+
return host[0] === "[" && host[host.length - 1] === "]";
|
|
4034
|
+
}
|
|
4027
4035
|
function hasMalformedComponentPercentEncoding(matches) {
|
|
4028
4036
|
const host = matches[4];
|
|
4029
|
-
return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !(host
|
|
4037
|
+
return hasMalformedPercentEncoding(matches[3]) || host !== void 0 && !isIPLiteral(host) && hasMalformedPercentEncoding(host) || hasMalformedPercentEncoding(matches[6]) || hasMalformedPercentEncoding(matches[7]) || hasMalformedPercentEncoding(matches[8]);
|
|
4030
4038
|
}
|
|
4031
4039
|
function canonicalizeHost(parsed, options, schemeHandler, isIP) {
|
|
4032
|
-
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && parsed.host
|
|
4040
|
+
if (!options.unicodeSupport && (!schemeHandler || !schemeHandler.unicodeSupport) && parsed.host && !isIPLiteral(parsed.host) && (options.domainHost || schemeHandler && schemeHandler.domainHost) && isIP === false && nonSimpleDomain(parsed.host)) {
|
|
4033
4041
|
try {
|
|
4034
4042
|
parsed.host = new URL("http://" + parsed.host).hostname;
|
|
4035
4043
|
} catch (e) {
|
|
@@ -4116,10 +4124,11 @@ var require_fast_uri = __commonJS({
|
|
|
4116
4124
|
if (parsed.host) {
|
|
4117
4125
|
const ipv4result = isIPv4(parsed.host);
|
|
4118
4126
|
if (ipv4result === false) {
|
|
4119
|
-
const bracketedIPLiteral = parsed.host
|
|
4127
|
+
const bracketedIPLiteral = isIPLiteral(parsed.host);
|
|
4128
|
+
const hasIPLiteralBracket = parsed.host.indexOf("[") !== -1 || parsed.host.indexOf("]") !== -1;
|
|
4120
4129
|
const ipv6result = normalizeIPv6(parsed.host);
|
|
4121
4130
|
isIP = ipv6result.isIPV6 || ipv6result.isIPVFuture === true;
|
|
4122
|
-
malformedIPLiteral =
|
|
4131
|
+
malformedIPLiteral = hasIPLiteralBracket && (!bracketedIPLiteral || ipv6result.error === true);
|
|
4123
4132
|
parsed.host = isIP ? ipv6result.host : ipv6result.host.toLowerCase();
|
|
4124
4133
|
if (malformedIPLiteral) {
|
|
4125
4134
|
parsed.error = parsed.error || "URI host is malformed.";
|
|
@@ -4142,14 +4151,17 @@ var require_fast_uri = __commonJS({
|
|
|
4142
4151
|
parsed.error = parsed.error || "URI is not a " + options.reference + " reference.";
|
|
4143
4152
|
}
|
|
4144
4153
|
const schemeHandler = getSchemeHandler(options.scheme || parsed.scheme);
|
|
4145
|
-
|
|
4146
|
-
|
|
4147
|
-
|
|
4148
|
-
|
|
4149
|
-
|
|
4150
|
-
|
|
4151
|
-
|
|
4154
|
+
if (!malformedIPLiteral) {
|
|
4155
|
+
malformedHost = canonicalizeHost(parsed, options, schemeHandler, isIP);
|
|
4156
|
+
}
|
|
4157
|
+
if (uri.indexOf("%") !== -1 && parsed.host !== void 0 && !malformedIPLiteral) {
|
|
4158
|
+
let host = isIP ? parsed.host : normalizePercentEncoding(parsed.host, true);
|
|
4159
|
+
if (!isIP) {
|
|
4160
|
+
host = normalizePercentEncoding(host.toLowerCase());
|
|
4152
4161
|
}
|
|
4162
|
+
parsed.host = reescapeHostDelimiters(host, isIP);
|
|
4163
|
+
}
|
|
4164
|
+
if (!schemeHandler || schemeHandler && !schemeHandler.skipNormalize) {
|
|
4153
4165
|
if (parsed.path) {
|
|
4154
4166
|
parsed.path = normalizePathEncoding(parsed.path);
|
|
4155
4167
|
}
|
|
@@ -11618,6 +11630,11 @@ function cdpUp(timeoutMs = 1500) {
|
|
|
11618
11630
|
});
|
|
11619
11631
|
});
|
|
11620
11632
|
}
|
|
11633
|
+
function cdpListIsCursor(payload) {
|
|
11634
|
+
const d = typeof payload === "string" ? payload : payload == null ? "" : JSON.stringify(payload);
|
|
11635
|
+
if (WINDSURF_CDP_PATH.test(d)) return false;
|
|
11636
|
+
return CURSOR_CDP_PATH.test(d);
|
|
11637
|
+
}
|
|
11621
11638
|
function cdpIsCursor(timeoutMs = 1500) {
|
|
11622
11639
|
return new Promise((resolve9) => {
|
|
11623
11640
|
const req = http.get({ host: CDP_HOST, port: CDP_PORT, path: "/json/list" }, (res) => {
|
|
@@ -11625,8 +11642,7 @@ function cdpIsCursor(timeoutMs = 1500) {
|
|
|
11625
11642
|
res.on("data", (c) => d += c);
|
|
11626
11643
|
res.on("end", () => {
|
|
11627
11644
|
try {
|
|
11628
|
-
|
|
11629
|
-
resolve9(/[\/\\]cursor[\/\\](resources|app)|cursor\.exe|vscode-app[^"]*[\/\\]cursor[\/\\]/i.test(d));
|
|
11645
|
+
resolve9(cdpListIsCursor(d));
|
|
11630
11646
|
} catch {
|
|
11631
11647
|
resolve9(false);
|
|
11632
11648
|
}
|
|
@@ -12115,7 +12131,7 @@ async function waitForProjectCdpTarget(maxMs, projectPath, listImpl = listCdpPag
|
|
|
12115
12131
|
}
|
|
12116
12132
|
return null;
|
|
12117
12133
|
}
|
|
12118
|
-
var CDP_PORT, CDP_ORIGIN, CDP_HOST, PROJECT_TARGETS, CODEX_THREAD_PROJECTS, loadModule;
|
|
12134
|
+
var CDP_PORT, CDP_ORIGIN, CDP_HOST, PROJECT_TARGETS, CODEX_THREAD_PROJECTS, loadModule, WINDSURF_CDP_PATH, CURSOR_CDP_PATH;
|
|
12119
12135
|
var init_cursor_ensure_core = __esm({
|
|
12120
12136
|
"cursor-ensure-core.mjs"() {
|
|
12121
12137
|
init_cursor_startup_window();
|
|
@@ -12126,6 +12142,8 @@ var init_cursor_ensure_core = __esm({
|
|
|
12126
12142
|
PROJECT_TARGETS = /* @__PURE__ */ new Map();
|
|
12127
12143
|
CODEX_THREAD_PROJECTS = /* @__PURE__ */ new Map();
|
|
12128
12144
|
loadModule = createNodeRequire(import.meta.url);
|
|
12145
|
+
WINDSURF_CDP_PATH = /[\/\\](windsurf)[\/\\]/i;
|
|
12146
|
+
CURSOR_CDP_PATH = /[\/\\]cursor[\/\\](resources|app)|cursor\.exe|vscode-app[^"]*[\/\\]cursor[\/\\]|[\/\\]cursor\.app[\/\\]contents[\/\\]resources[\/\\]app[\/\\]/i;
|
|
12129
12147
|
}
|
|
12130
12148
|
});
|
|
12131
12149
|
|
|
@@ -22967,7 +22985,7 @@ function updateCursorSessionRegistry(filePath, mutator, options = {}) {
|
|
|
22967
22985
|
// server.mjs
|
|
22968
22986
|
init_cursor_ensure_core();
|
|
22969
22987
|
init_lifecycle_paths();
|
|
22970
|
-
var PLUGIN_VERSION = "6.0.
|
|
22988
|
+
var PLUGIN_VERSION = "6.0.4";
|
|
22971
22989
|
var CDP_PORT2 = Number(process.env.CURSOR_BRIDGE_CDP_PORT || 9223);
|
|
22972
22990
|
var ORIGIN = `http://localhost:${CDP_PORT2}`;
|
|
22973
22991
|
var QUERY_TIMEOUT = Number(process.env.CURSOR_BRIDGE_TIMEOUT || 3e5);
|
|
@@ -23508,6 +23526,27 @@ var EXPR_MODEL_PICKER_ROWS = `(function(){
|
|
|
23508
23526
|
}
|
|
23509
23527
|
return JSON.stringify({open:menus.length>0,rows});
|
|
23510
23528
|
})()`;
|
|
23529
|
+
var EXPR_SELECTED_AGENT_MODEL_CONFIG = `(function(){
|
|
23530
|
+
${INPUT_PICKER_BODY}
|
|
23531
|
+
const inputs=inputCandidates();
|
|
23532
|
+
if(inputs.length!==1)return JSON.stringify({found:false,state:'input_ambiguous',inputCount:inputs.length});
|
|
23533
|
+
const configs=[];
|
|
23534
|
+
for(let node=inputs[0],n=0;node&&n<12;n++,node=node.parentElement){
|
|
23535
|
+
const key=Object.keys(node).find(key=>key.startsWith('__reactFiber$'));
|
|
23536
|
+
for(let f=key&&node[key],i=0;f&&i<48;i++,f=f.return){
|
|
23537
|
+
const reference=f.memoizedProps&&f.memoizedProps.selectedAgent&&f.memoizedProps.selectedAgent.reference;
|
|
23538
|
+
const handle=reference&&(reference._composerDataHandle||reference.composerDataHandle);
|
|
23539
|
+
const data=handle&&(handle._cachedData||handle.data);
|
|
23540
|
+
if(data&&data.modelConfig&&!configs.includes(data.modelConfig))configs.push(data.modelConfig);
|
|
23541
|
+
}
|
|
23542
|
+
}
|
|
23543
|
+
if(configs.length!==1)return JSON.stringify({found:false,state:'model_config_ambiguous',configCount:configs.length});
|
|
23544
|
+
const config=configs[0];
|
|
23545
|
+
return JSON.stringify({found:true,modelName:String(config.modelName||''),selectedModels:(config.selectedModels||[]).map(model=>({
|
|
23546
|
+
modelId:String(model&&model.modelId||''),
|
|
23547
|
+
parameters:Object.fromEntries((model&&model.parameters||[]).map(parameter=>[String(parameter&¶meter.id||''),String(parameter&¶meter.value||'')]))
|
|
23548
|
+
}))});
|
|
23549
|
+
})()`;
|
|
23511
23550
|
function normalizeModelPickerText(value) {
|
|
23512
23551
|
return String(value || "").trim().toLowerCase().replace(/extra[\s_-]*high/g, "xhigh").replace(/[^a-z0-9]+/g, "");
|
|
23513
23552
|
}
|
|
@@ -23629,13 +23668,12 @@ var WORKSPACE_SECTION_BODY = String.raw`
|
|
|
23629
23668
|
if(matches.length!==1)return {diagnostic:fail('workspace_ambiguous')};
|
|
23630
23669
|
const {section,project}=matches[0];
|
|
23631
23670
|
if(project.remoteAuthority||!project.workspaceIdentifier.id)return {diagnostic:fail('workspace_environment_unverified')};
|
|
23632
|
-
// Cursor's section-level New Agent action chooses among registered targets.
|
|
23633
|
-
// Do not click it when a second workspace could win that choice.
|
|
23634
|
-
if(section.source.projects.length!==1)return {diagnostic:fail('workspace_creation_target_ambiguous')};
|
|
23635
23671
|
if(!section.button)return {diagnostic:fail('workspace_new_agent_unavailable')};
|
|
23636
23672
|
return {section,diagnostic:{ok:true,state:'workspace_ready',workspace:wanted,
|
|
23637
23673
|
workspaceId:project.workspaceIdentifier.id,sectionId:section.metadata.id,
|
|
23638
|
-
environment:'local',identitySource:'registered_workspace_file_uri',
|
|
23674
|
+
environment:'local',identitySource:'registered_workspace_file_uri',
|
|
23675
|
+
workspaceSelectionRequired:section.source.projects.length!==1,
|
|
23676
|
+
repoUrls:Array.isArray(project.repoUrls)?project.repoUrls:[]}};
|
|
23639
23677
|
};
|
|
23640
23678
|
`;
|
|
23641
23679
|
function exprCreateAgentForWorkspace(projectPath) {
|
|
@@ -23650,6 +23688,49 @@ function exprCreateAgentForWorkspace(projectPath) {
|
|
|
23650
23688
|
return JSON.stringify({...result.diagnostic,state:'workspace_agent_creation_requested',previousAgentIds});
|
|
23651
23689
|
})()`;
|
|
23652
23690
|
}
|
|
23691
|
+
function matchSelectedAgentModelConfig(snapshot, requestedModel, requestedEffort) {
|
|
23692
|
+
if (!snapshot || snapshot.found !== true) return null;
|
|
23693
|
+
const requested = normalizeModelPickerText(requestedModel);
|
|
23694
|
+
const entries = Array.isArray(snapshot.selectedModels) && snapshot.selectedModels.length ? snapshot.selectedModels : [{ modelId: snapshot.modelName, parameters: {} }];
|
|
23695
|
+
const matches = entries.filter((entry) => {
|
|
23696
|
+
const candidate = normalizeModelPickerText(entry && entry.modelId);
|
|
23697
|
+
return candidate && (candidate === requested || requested === `cursor${candidate}`);
|
|
23698
|
+
});
|
|
23699
|
+
if (matches.length !== 1) return null;
|
|
23700
|
+
const match = matches[0];
|
|
23701
|
+
const effort = normalizeCursorModelEffort(match.parameters && match.parameters.effort, "");
|
|
23702
|
+
if (requestedEffort && effort !== requestedEffort) return null;
|
|
23703
|
+
return { modelId: match.modelId, effort: effort || null };
|
|
23704
|
+
}
|
|
23705
|
+
function exprSelectAgentWorkspace(projectPath) {
|
|
23706
|
+
return `(async function(){
|
|
23707
|
+
const wanted=String(${JSON.stringify(String(projectPath || ""))}).replace(/\\\\/g,'/').replace(/^\\/([a-z]:\\/)/i,'$1').replace(/\\/+$/,'').toLowerCase();
|
|
23708
|
+
const normalize=value=>String(value||'').replace(/\\\\/g,'/').replace(/^\\/([a-z]:\\/)/i,'$1').replace(/\\/+$/,'').toLowerCase();
|
|
23709
|
+
const visible=node=>!!(node&&(node.offsetParent!==null||(node.getClientRects&&node.getClientRects().length>0)));
|
|
23710
|
+
const pathTriggers=()=>[...document.querySelectorAll('button.ui-select-trigger,button[aria-haspopup="menu"]')]
|
|
23711
|
+
.filter(visible).filter(node=>/^[a-z]:\\//i.test(normalize(node.innerText||node.textContent)));
|
|
23712
|
+
const triggers=pathTriggers();
|
|
23713
|
+
const fail=(state,extra={})=>JSON.stringify({ok:false,state,wanted,...extra,
|
|
23714
|
+
nextStep:'Select the exact local workspace '+${JSON.stringify(String(projectPath || ""))}+' in the new Agent project picker before retrying.'});
|
|
23715
|
+
if(triggers.length!==1)return fail(triggers.length?'workspace_project_selector_ambiguous':'workspace_project_selector_unavailable',{triggerCount:triggers.length});
|
|
23716
|
+
triggers[0].click();
|
|
23717
|
+
await new Promise(resolve=>setTimeout(resolve,350));
|
|
23718
|
+
const menus=[...document.querySelectorAll('[data-component="menu-popup"],[role="menu"]')].filter(visible)
|
|
23719
|
+
.filter(menu=>String(menu.getAttribute('aria-label')||'')==='Select a project'||menu.querySelector('[aria-label="Select a project"]'));
|
|
23720
|
+
const rows=[];const seen=new Set();
|
|
23721
|
+
for(const menu of menus){
|
|
23722
|
+
for(const row of menu.querySelectorAll('[data-component="menu-row"][role="menuitem"],[role="option"]')){
|
|
23723
|
+
if(!visible(row)||seen.has(row))continue;seen.add(row);rows.push(row);
|
|
23724
|
+
}
|
|
23725
|
+
}
|
|
23726
|
+
const available=rows.map(row=>String(row.innerText||row.textContent||'').replace(/\\s+/g,' ').trim());
|
|
23727
|
+
const matches=rows.filter(row=>normalize(row.innerText||row.textContent)===wanted);
|
|
23728
|
+
if(matches.length!==1)return fail(matches.length?'workspace_project_option_ambiguous':'workspace_project_option_unavailable',{available});
|
|
23729
|
+
matches[0].click();
|
|
23730
|
+
await new Promise(resolve=>setTimeout(resolve,350));
|
|
23731
|
+
return JSON.stringify({ok:true,state:'workspace_project_selection_requested',workspace:wanted,available});
|
|
23732
|
+
})()`;
|
|
23733
|
+
}
|
|
23653
23734
|
function exprInspectWorkspaceRepository(projectPath) {
|
|
23654
23735
|
return `(function(){
|
|
23655
23736
|
${WORKSPACE_SECTION_BODY}
|
|
@@ -23945,7 +24026,8 @@ var EXPR_PAGE_CAPABILITIES = `(function(){${INPUT_PICKER_BODY}
|
|
|
23945
24026
|
const hasLegacyInput=!!document.querySelector('.aislash-editor-input');
|
|
23946
24027
|
const hasLegacyHistory=!!document.querySelector('.compact-agent-history-react-menu-label')||
|
|
23947
24028
|
[...document.querySelectorAll('button,[role=button],a.action-label,.codicon')].some(e=>/Show Chat History|Chat History|Agent History/i.test((e.getAttribute('aria-label')||'')+' '+(e.getAttribute('title')||'')));
|
|
23948
|
-
const dialogs=[...document.querySelectorAll('[role="dialog"],dialog[open],.monaco-dialog-box,.quick-input-widget')]
|
|
24029
|
+
const dialogs=[...document.querySelectorAll('[role="dialog"],dialog[open],.monaco-dialog-box,.quick-input-widget')]
|
|
24030
|
+
.filter(visible).filter(node=>node.getAttribute('data-component')!=='preview-card-layer-popup');
|
|
23949
24031
|
const dialog=dialogs[dialogs.length-1]||null;
|
|
23950
24032
|
const dialogHeading=dialog&&dialog.querySelector('h1,h2,h3,[role="heading"]');
|
|
23951
24033
|
const dialogLabel=dialog?String(dialog.getAttribute('aria-label')||dialog.getAttribute('title')||label(dialogHeading)||'').slice(0,120):null;
|
|
@@ -25532,6 +25614,9 @@ var CursorBridge = class {
|
|
|
25532
25614
|
const snapshot = await this._readModelPickerValue(c, EXPR_MODEL_PICKER_ROWS, "rows", options);
|
|
25533
25615
|
return { open: snapshot.open === true, rows: Array.isArray(snapshot.rows) ? snapshot.rows : [] };
|
|
25534
25616
|
}
|
|
25617
|
+
async _readSelectedAgentModelConfig(c, options) {
|
|
25618
|
+
return this._readModelPickerValue(c, EXPR_SELECTED_AGENT_MODEL_CONFIG, "selected_agent_model_config", options);
|
|
25619
|
+
}
|
|
25535
25620
|
async _clickModelPickerPoint(c, point) {
|
|
25536
25621
|
if (!point || !Number.isFinite(Number(point.x)) || !Number.isFinite(Number(point.y))) {
|
|
25537
25622
|
throw new Error("Cursor model picker returned an invalid target");
|
|
@@ -25705,6 +25790,32 @@ var CursorBridge = class {
|
|
|
25705
25790
|
const selectionStartedAt = Date.now();
|
|
25706
25791
|
let stage = "open_picker";
|
|
25707
25792
|
try {
|
|
25793
|
+
if (this.runtimeMode === "minimal") {
|
|
25794
|
+
stage = "verify_hidden_model_config";
|
|
25795
|
+
const snapshot = await this._readSelectedAgentModelConfig(c);
|
|
25796
|
+
const verified = matchSelectedAgentModelConfig(snapshot, requestedModel, requestedEffort);
|
|
25797
|
+
if (!verified) {
|
|
25798
|
+
throw createModelSelectionError(
|
|
25799
|
+
`Cursor minimal runtime could not confirm ${requestedModel}${requestedEffort ? ` / ${requestedEffort}` : ""}; switch Cursor runtime to normal and retry`,
|
|
25800
|
+
"hidden_model_not_confirmed",
|
|
25801
|
+
true,
|
|
25802
|
+
{ available: (snapshot.selectedModels || []).map((entry) => entry.modelId).filter(Boolean) }
|
|
25803
|
+
);
|
|
25804
|
+
}
|
|
25805
|
+
const result2 = {
|
|
25806
|
+
configured: true,
|
|
25807
|
+
applied: true,
|
|
25808
|
+
requestedModel,
|
|
25809
|
+
requestedEffort,
|
|
25810
|
+
effectiveModel: verified.modelId,
|
|
25811
|
+
effectiveEffort: verified.effort,
|
|
25812
|
+
pickerDetail: null,
|
|
25813
|
+
verificationSource: "selected_agent_model_config",
|
|
25814
|
+
verifiedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
25815
|
+
};
|
|
25816
|
+
if (job) job.modelSelection = result2;
|
|
25817
|
+
return result2;
|
|
25818
|
+
}
|
|
25708
25819
|
const opened = await this._openModelPicker(c);
|
|
25709
25820
|
stage = "locate_model";
|
|
25710
25821
|
let located = await this._findModelPickerModel(c, opened, requestedModel);
|
|
@@ -25761,6 +25872,31 @@ var CursorBridge = class {
|
|
|
25761
25872
|
await this._clickModelPickerPoint(c, selectedEffort.row);
|
|
25762
25873
|
await sleep2(550);
|
|
25763
25874
|
}
|
|
25875
|
+
} else if (requestedEffort) {
|
|
25876
|
+
if (!modelRow.selected) {
|
|
25877
|
+
stage = "select_model";
|
|
25878
|
+
this._throwIfCancelledBeforeSend(job);
|
|
25879
|
+
await this._clickModelPickerPoint(c, modelRow);
|
|
25880
|
+
await sleep2(550);
|
|
25881
|
+
const reopened = await this._openModelPicker(c);
|
|
25882
|
+
located = await this._findModelPickerModel(c, reopened, requestedModel);
|
|
25883
|
+
modelRow = located.modelRow;
|
|
25884
|
+
if (!modelRow) {
|
|
25885
|
+
throw createModelSelectionError(
|
|
25886
|
+
`Cursor model row disappeared while applying effort: ${requestedModel}`,
|
|
25887
|
+
"model_unavailable",
|
|
25888
|
+
true
|
|
25889
|
+
);
|
|
25890
|
+
}
|
|
25891
|
+
}
|
|
25892
|
+
stage = "select_effort";
|
|
25893
|
+
const selectedEffort = await resolveEffort();
|
|
25894
|
+
if (!selectedEffort.row) throwEffortFailure(selectedEffort);
|
|
25895
|
+
if (!selectedEffort.row.selected) {
|
|
25896
|
+
this._throwIfCancelledBeforeSend(job);
|
|
25897
|
+
await this._clickModelPickerPoint(c, selectedEffort.row);
|
|
25898
|
+
await sleep2(550);
|
|
25899
|
+
}
|
|
25764
25900
|
} else if (!modelRow.selected) {
|
|
25765
25901
|
stage = "select_model";
|
|
25766
25902
|
this._throwIfCancelledBeforeSend(job);
|
|
@@ -25944,7 +26080,13 @@ var CursorBridge = class {
|
|
|
25944
26080
|
if (!created.ok) {
|
|
25945
26081
|
throw createWorkspaceBindingError(created);
|
|
25946
26082
|
}
|
|
25947
|
-
|
|
26083
|
+
if (created.workspaceSelectionRequired) {
|
|
26084
|
+
await sleep2(250);
|
|
26085
|
+
const selected = JSON.parse(await evalJS(c, exprSelectAgentWorkspace(options.projectPath)) || "{}");
|
|
26086
|
+
if (options.job) options.job.workspaceBindingChecks.project_selection = { ...selected, checkedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
26087
|
+
if (!selected.ok) throw createWorkspaceBindingError(selected);
|
|
26088
|
+
}
|
|
26089
|
+
await sleep2(created.workspaceSelectionRequired ? 750 : 1100);
|
|
25948
26090
|
const actual = JSON.parse(await evalJS(c, exprInspectAgentWorkspace(options.projectPath, { excludedAgentIds: created.previousAgentIds })) || "{}");
|
|
25949
26091
|
if (options.job) options.job.workspaceBindingChecks.after_create = { ...actual, checkedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
25950
26092
|
if (!actual.ok) throw createWorkspaceBindingError(actual);
|
|
@@ -27856,6 +27998,7 @@ export {
|
|
|
27856
27998
|
EXPR_PAGE_CAPABILITIES,
|
|
27857
27999
|
EXPR_PREPARE_INPUT,
|
|
27858
28000
|
EXPR_PROVIDER_ERROR,
|
|
28001
|
+
EXPR_SELECTED_AGENT_MODEL_CONFIG,
|
|
27859
28002
|
EXPR_SNAP,
|
|
27860
28003
|
EXPR_VISIBLE,
|
|
27861
28004
|
EXPR_VISIBLE_COMPOSER,
|
|
@@ -27876,12 +28019,14 @@ export {
|
|
|
27876
28019
|
exprInspectWorkspaceRepository,
|
|
27877
28020
|
exprOpenAgent,
|
|
27878
28021
|
exprRegisterAgentsWorkspace,
|
|
28022
|
+
exprSelectAgentWorkspace,
|
|
27879
28023
|
isConfirmedCompletedReply,
|
|
27880
28024
|
isCursorEffortOptionText,
|
|
27881
28025
|
isDurablyRegisteredParallelEntry,
|
|
27882
28026
|
isSessionTurnReplyReady,
|
|
27883
28027
|
isTargetedStopConfirmed,
|
|
27884
28028
|
lifecycleFailureSummary,
|
|
28029
|
+
matchSelectedAgentModelConfig,
|
|
27885
28030
|
modelPickerAvailableIsDecisive,
|
|
27886
28031
|
normalizeAllowedPath,
|
|
27887
28032
|
normalizeCceSearchResult,
|
|
@@ -4104,6 +4104,7 @@ __export(cursor_ensure_core_exports, {
|
|
|
4104
4104
|
CDP_ORIGIN: () => CDP_ORIGIN,
|
|
4105
4105
|
CDP_PORT: () => CDP_PORT,
|
|
4106
4106
|
cdpIsCursor: () => cdpIsCursor,
|
|
4107
|
+
cdpListIsCursor: () => cdpListIsCursor,
|
|
4107
4108
|
cdpUp: () => cdpUp,
|
|
4108
4109
|
cursorRunning: () => cursorRunning,
|
|
4109
4110
|
ensureCursorRunningLocal: () => ensureCursorRunningLocal,
|
|
@@ -4298,6 +4299,11 @@ function cdpUp(timeoutMs = 1500) {
|
|
|
4298
4299
|
});
|
|
4299
4300
|
});
|
|
4300
4301
|
}
|
|
4302
|
+
function cdpListIsCursor(payload) {
|
|
4303
|
+
const d = typeof payload === "string" ? payload : payload == null ? "" : JSON.stringify(payload);
|
|
4304
|
+
if (WINDSURF_CDP_PATH.test(d)) return false;
|
|
4305
|
+
return CURSOR_CDP_PATH.test(d);
|
|
4306
|
+
}
|
|
4301
4307
|
function cdpIsCursor(timeoutMs = 1500) {
|
|
4302
4308
|
return new Promise((resolve4) => {
|
|
4303
4309
|
const req = http.get({ host: CDP_HOST, port: CDP_PORT, path: "/json/list" }, (res) => {
|
|
@@ -4305,8 +4311,7 @@ function cdpIsCursor(timeoutMs = 1500) {
|
|
|
4305
4311
|
res.on("data", (c) => d += c);
|
|
4306
4312
|
res.on("end", () => {
|
|
4307
4313
|
try {
|
|
4308
|
-
|
|
4309
|
-
resolve4(/[\/\\]cursor[\/\\](resources|app)|cursor\.exe|vscode-app[^"]*[\/\\]cursor[\/\\]/i.test(d));
|
|
4314
|
+
resolve4(cdpListIsCursor(d));
|
|
4310
4315
|
} catch {
|
|
4311
4316
|
resolve4(false);
|
|
4312
4317
|
}
|
|
@@ -4795,7 +4800,7 @@ async function waitForProjectCdpTarget(maxMs, projectPath, listImpl = listCdpPag
|
|
|
4795
4800
|
}
|
|
4796
4801
|
return null;
|
|
4797
4802
|
}
|
|
4798
|
-
var CDP_PORT, CDP_ORIGIN, CDP_HOST, PROJECT_TARGETS, CODEX_THREAD_PROJECTS, loadModule;
|
|
4803
|
+
var CDP_PORT, CDP_ORIGIN, CDP_HOST, PROJECT_TARGETS, CODEX_THREAD_PROJECTS, loadModule, WINDSURF_CDP_PATH, CURSOR_CDP_PATH;
|
|
4799
4804
|
var init_cursor_ensure_core = __esm({
|
|
4800
4805
|
"cursor-ensure-core.mjs"() {
|
|
4801
4806
|
init_cursor_startup_window();
|
|
@@ -4806,6 +4811,8 @@ var init_cursor_ensure_core = __esm({
|
|
|
4806
4811
|
PROJECT_TARGETS = /* @__PURE__ */ new Map();
|
|
4807
4812
|
CODEX_THREAD_PROJECTS = /* @__PURE__ */ new Map();
|
|
4808
4813
|
loadModule = createNodeRequire(import.meta.url);
|
|
4814
|
+
WINDSURF_CDP_PATH = /[\/\\](windsurf)[\/\\]/i;
|
|
4815
|
+
CURSOR_CDP_PATH = /[\/\\]cursor[\/\\](resources|app)|cursor\.exe|vscode-app[^"]*[\/\\]cursor[\/\\]|[\/\\]cursor\.app[\/\\]contents[\/\\]resources[\/\\]app[\/\\]/i;
|
|
4809
4816
|
}
|
|
4810
4817
|
});
|
|
4811
4818
|
|
package/extensions/index.ts
CHANGED
|
@@ -10,7 +10,7 @@ const hostWorkspaceId = hostCwd.replace(/\\/g, "/").toLowerCase();
|
|
|
10
10
|
export default createStdioMcpExtension({
|
|
11
11
|
label: "Cursor Bridge",
|
|
12
12
|
clientName: "pi-cursor-bridge",
|
|
13
|
-
packageVersion: "0.2.
|
|
13
|
+
packageVersion: "0.2.4",
|
|
14
14
|
serverName: "cursor-bridge",
|
|
15
15
|
serverScript: join(packageRoot, "dist", "cursor-bridge.mjs"),
|
|
16
16
|
cwd: hostCwd,
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-cursor-bridge",
|
|
3
|
-
"version": "0.2.
|
|
4
|
-
"description": "Use Cursor Context Engine and bounded, explicitly continuous Cursor Agent execution from the Pi coding agent.",
|
|
3
|
+
"version": "0.2.4",
|
|
4
|
+
"description": "Windows only. Use Cursor Context Engine and bounded, explicitly continuous Cursor Agent execution from the Pi coding agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"author": "Vanyangyang",
|
|
@@ -47,6 +47,6 @@
|
|
|
47
47
|
},
|
|
48
48
|
"piPackage": {
|
|
49
49
|
"embeddedProduct": "Cursor Bridge",
|
|
50
|
-
"embeddedProductVersion": "6.0.
|
|
50
|
+
"embeddedProductVersion": "6.0.4"
|
|
51
51
|
}
|
|
52
52
|
}
|