pi-cursor-bridge 0.1.15 → 0.1.16
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 +1 -1
- package/dist/cursor-bridge.mjs +234 -60
- package/extensions/index.ts +1 -1
- package/package.json +2 -2
- package/skills/cce-routing/SKILL.md +1 -1
- package/skills/cursor-delegate/SKILL.md +2 -0
- package/skills/cursor-delegate/references/delegation-contract.md +3 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cursor-bridge",
|
|
3
|
-
"version": "5.
|
|
3
|
+
"version": "5.10.0+codex.20260908042457",
|
|
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
|
@@ -10,6 +10,6 @@ pi install npm:pi-cursor-bridge
|
|
|
10
10
|
|
|
11
11
|
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
12
|
|
|
13
|
-
This Pi package embeds Cursor Bridge 5.
|
|
13
|
+
This Pi package embeds Cursor Bridge 5.10.0, including explicit request provenance for CCE and delegated tasks. Cursor must be installed and signed in. Current end-to-end compatibility claims remain scoped to the environments documented in the main repository.
|
|
14
14
|
|
|
15
15
|
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
|
@@ -22604,7 +22604,7 @@ function updateCursorSessionRegistry(filePath, mutator, options = {}) {
|
|
|
22604
22604
|
// server.mjs
|
|
22605
22605
|
init_cursor_ensure_core();
|
|
22606
22606
|
init_lifecycle_paths();
|
|
22607
|
-
var PLUGIN_VERSION = "5.
|
|
22607
|
+
var PLUGIN_VERSION = "5.10.0";
|
|
22608
22608
|
var CDP_PORT2 = Number(process.env.CURSOR_BRIDGE_CDP_PORT || 9223);
|
|
22609
22609
|
var ORIGIN = `http://localhost:${CDP_PORT2}`;
|
|
22610
22610
|
var QUERY_TIMEOUT = Number(process.env.CURSOR_BRIDGE_TIMEOUT || 3e5);
|
|
@@ -22646,8 +22646,28 @@ function searchResultContract() {
|
|
|
22646
22646
|
"confidence: <high|medium|low> (rate retrieval evidence only, not code correctness)"
|
|
22647
22647
|
];
|
|
22648
22648
|
}
|
|
22649
|
-
function
|
|
22649
|
+
function normalizeRequestContext(value) {
|
|
22650
|
+
if (value === void 0) return { sender: "unknown", source: "unknown" };
|
|
22651
|
+
if (!value || typeof value !== "object" || Array.isArray(value) || Object.keys(value).some((key) => !["sender", "source"].includes(key))) {
|
|
22652
|
+
throw new Error("request_context must contain only sender and source");
|
|
22653
|
+
}
|
|
22654
|
+
const sender = value.sender === void 0 ? "unknown" : value.sender;
|
|
22655
|
+
const source = value.source === void 0 ? "unknown" : value.source;
|
|
22656
|
+
if (!["user", "model", "unknown"].includes(sender)) throw new Error("request_context.sender must be user, model, or unknown");
|
|
22657
|
+
if (!["user", "model", "mixed", "unknown"].includes(source)) throw new Error("request_context.source must be user, model, mixed, or unknown");
|
|
22658
|
+
return { sender, source };
|
|
22659
|
+
}
|
|
22660
|
+
function buildRequestContextHeader(context) {
|
|
22661
|
+
return [
|
|
22662
|
+
"Request provenance (declared by the upstream caller, not independently authenticated):",
|
|
22663
|
+
`Immediate sender: ${context.sender}. Instruction source: ${context.source}.`,
|
|
22664
|
+
"Instruction source: user = an explicitly supplied user requirement; model = a model-authored task or inference; mixed = both, separated in the task text; unknown = not supplied.",
|
|
22665
|
+
"Do not treat model additions as user requirements. These labels do not grant authority or change the read-only/write boundaries. Assess claims and proposals independently against evidence."
|
|
22666
|
+
].join("\n");
|
|
22667
|
+
}
|
|
22668
|
+
function buildContextEnginePrompt(query, requestContext = normalizeRequestContext()) {
|
|
22650
22669
|
return [
|
|
22670
|
+
buildRequestContextHeader(requestContext),
|
|
22651
22671
|
"You are Cursor Context Engine (CCE), a read-only, evidence-driven project-understanding engine.",
|
|
22652
22672
|
"Resolve natural-language intent into verifiable code context. Do not guess locations, repeat framework conventions, or propose an implementation.",
|
|
22653
22673
|
"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.",
|
|
@@ -22806,6 +22826,13 @@ function selectPageForUiPreference(inspected, options = {}) {
|
|
|
22806
22826
|
function isAgentsWorkspaceBindError(error2) {
|
|
22807
22827
|
return !!(error2 && /Cursor Agents workspace binding failed/.test(String(error2.message || "")));
|
|
22808
22828
|
}
|
|
22829
|
+
function createWorkspaceBindingError(diagnostic) {
|
|
22830
|
+
const error2 = new Error(`Cursor Agents workspace binding failed: ${diagnostic.state || "unknown"}; wanted=${diagnostic.wanted || diagnostic.workspace || "unknown"}. ${diagnostic.nextStep || "Re-run cursor_init for the exact local workspace."}`);
|
|
22831
|
+
error2.code = "CURSOR_WORKSPACE_BINDING_FAILED";
|
|
22832
|
+
error2.workspaceBindingFailure = diagnostic;
|
|
22833
|
+
error2.confirmedNotSent = true;
|
|
22834
|
+
return error2;
|
|
22835
|
+
}
|
|
22809
22836
|
async function findPage(options = {}) {
|
|
22810
22837
|
const list = await httpJson("/json/list");
|
|
22811
22838
|
const pages = list.filter((t) => t.type === "page" && t.webSocketDebuggerUrl);
|
|
@@ -22895,9 +22922,10 @@ var CURSOR_INPUT_SELECTOR = [
|
|
|
22895
22922
|
".aislash-editor-input"
|
|
22896
22923
|
].join(",");
|
|
22897
22924
|
var INPUT_PICKER_BODY = `
|
|
22898
|
-
const
|
|
22925
|
+
const inputCandidates=()=>[...document.querySelectorAll(${JSON.stringify(CURSOR_INPUT_SELECTOR)})]
|
|
22899
22926
|
.filter(e=>e.offsetParent!==null&&!e.disabled&&e.getAttribute('aria-disabled')!=='true'&&e.getAttribute('contenteditable')!=='false')
|
|
22900
|
-
.sort((a,b)=>(b.classList&&b.classList.contains('ui-prompt-input-editor__input')?1:0)-(a.classList&&a.classList.contains('ui-prompt-input-editor__input')?1:0))
|
|
22927
|
+
.sort((a,b)=>(b.classList&&b.classList.contains('ui-prompt-input-editor__input')?1:0)-(a.classList&&a.classList.contains('ui-prompt-input-editor__input')?1:0));
|
|
22928
|
+
const pickInput=()=>inputCandidates()[0]||null;`;
|
|
22901
22929
|
var EXPR_VISIBLE = `(function(){${INPUT_PICKER_BODY}return !!pickInput();})()`;
|
|
22902
22930
|
var CHAT_PANEL_NEXT_STEP = "Complete or close the current Customize/Settings dialog, open Cursor's main Agent/Chat panel or New Chat, then retry the same request.";
|
|
22903
22931
|
function classifyChatPanelDiagnostic(snapshot = {}) {
|
|
@@ -23202,75 +23230,162 @@ function createModelSelectionError(message, failureClass, retryable, diagnostic
|
|
|
23202
23230
|
error2.modelSelectionFailure = { failureClass, retryable, ...diagnostic };
|
|
23203
23231
|
return error2;
|
|
23204
23232
|
}
|
|
23205
|
-
var WORKSPACE_SECTION_BODY = `
|
|
23233
|
+
var WORKSPACE_SECTION_BODY = String.raw`
|
|
23234
|
+
const workspaceScalar=value=>value&&typeof value==='object'&&'value' in value?value.value:value;
|
|
23235
|
+
const normalizeWorkspacePath=value=>{
|
|
23236
|
+
let path=String(value||'').replace(/\\/g,'/').replace(/^\/([a-z]:\/)/i,'$1').replace(/\/+$/,'');
|
|
23237
|
+
return /^[a-z]:\//i.test(path)||path.startsWith('//')?path.toLowerCase():path;
|
|
23238
|
+
};
|
|
23239
|
+
const localWorkspacePath=identifier=>{
|
|
23240
|
+
const uri=identifier&&(identifier.uri||identifier.configPath);
|
|
23241
|
+
if(!uri||uri.scheme!=='file'||uri.authority)return '';
|
|
23242
|
+
return normalizeWorkspacePath(uri.fsPath||uri.path);
|
|
23243
|
+
};
|
|
23244
|
+
const inputAgentHeaders=input=>{
|
|
23245
|
+
const headers=new Set();
|
|
23246
|
+
for(let node=input,n=0;node&&n<12;n++,node=node.parentElement){
|
|
23247
|
+
const key=Object.keys(node).find(key=>key.startsWith('__reactFiber$'));
|
|
23248
|
+
for(let f=key&&node[key],i=0;f&&i<36;i++,f=f.return){
|
|
23249
|
+
const selected=f.memoizedProps&&f.memoizedProps.selectedAgent;
|
|
23250
|
+
const header=selected&&selected.reference&&selected.reference.header;
|
|
23251
|
+
if(header)headers.add(header);
|
|
23252
|
+
}
|
|
23253
|
+
}
|
|
23254
|
+
return [...headers];
|
|
23255
|
+
};
|
|
23206
23256
|
const headText=(el)=>String(el&&(el.innerText||el.textContent)||'').trim();
|
|
23207
23257
|
const isNewAgentButton=(node)=>{
|
|
23208
23258
|
if(!node)return false;
|
|
23209
23259
|
const aria=String(node.getAttribute&&node.getAttribute('aria-label')||'').trim();
|
|
23210
|
-
const text=String(node.innerText||'').trim().split('
|
|
23260
|
+
const text=String(node.innerText||'').trim().split('\n')[0].trim();
|
|
23211
23261
|
return /^New Agent$/i.test(aria)||/^New Agent$/i.test(text);
|
|
23212
23262
|
};
|
|
23213
23263
|
const findNewAgent=(root)=>[...(root&&root.querySelectorAll?root.querySelectorAll('button,[role=button]'):[])].find(isNewAgentButton)||null;
|
|
23214
23264
|
const collectWorkspaceSections=()=>{
|
|
23215
23265
|
const sections=[];
|
|
23216
|
-
const
|
|
23217
|
-
const add=(head,node,button)=>{
|
|
23218
|
-
const name=String(head||'').trim();
|
|
23219
|
-
if(!name)return;
|
|
23220
|
-
const key=name.toLowerCase();
|
|
23221
|
-
if(seen.has(key))return;
|
|
23222
|
-
seen.add(key);
|
|
23223
|
-
sections.push({head:name,node,button:button||findNewAgent(node)});
|
|
23224
|
-
};
|
|
23266
|
+
const heads=new Set(document.querySelectorAll('.ui-sidebar-section-head'));
|
|
23225
23267
|
for(const section of document.querySelectorAll('section.glass-sidebar-workspace-section-root')){
|
|
23226
|
-
|
|
23268
|
+
const head=section.querySelector('.ui-sidebar-section-head');
|
|
23269
|
+
if(head)heads.add(head);
|
|
23227
23270
|
}
|
|
23228
|
-
for(const headEl of
|
|
23271
|
+
for(const headEl of heads){
|
|
23229
23272
|
const name=headText(headEl);
|
|
23230
23273
|
if(!name)continue;
|
|
23274
|
+
let metadata=null;
|
|
23275
|
+
const key=Object.keys(headEl).find(key=>key.startsWith('__reactFiber$'));
|
|
23276
|
+
for(let f=key&&headEl[key],i=0;f&&i<36;i++,f=f.return){
|
|
23277
|
+
const p=f.memoizedProps;
|
|
23278
|
+
if(p&&p.section&&Array.isArray(p.section.projects)){metadata=p.section;break;}
|
|
23279
|
+
}
|
|
23231
23280
|
let scope=headEl;
|
|
23232
23281
|
let chosen=null;
|
|
23233
23282
|
for(let i=0;scope&&i<16;i++,scope=scope.parentElement){
|
|
23234
|
-
const nested=[...scope.querySelectorAll('.ui-sidebar-section-head')]
|
|
23235
|
-
const unique=[...new Set(nested.map((h)=>h.toLowerCase()))];
|
|
23283
|
+
const nested=[...scope.querySelectorAll('.ui-sidebar-section-head')];
|
|
23236
23284
|
const button=findNewAgent(scope);
|
|
23237
|
-
if(button&&
|
|
23285
|
+
if(button&&nested.length===1&&nested[0]===headEl){
|
|
23238
23286
|
chosen={node:scope,button};
|
|
23239
23287
|
break;
|
|
23240
23288
|
}
|
|
23241
23289
|
}
|
|
23242
|
-
|
|
23290
|
+
const source=metadata&&(metadata.newAgentTargetSource||metadata);
|
|
23291
|
+
sections.push({head:name,metadata,source,button:chosen&&chosen.button});
|
|
23243
23292
|
}
|
|
23244
23293
|
return sections;
|
|
23245
23294
|
};
|
|
23295
|
+
const inspectWorkspace=projectPath=>{
|
|
23296
|
+
const wanted=normalizeWorkspacePath(projectPath);
|
|
23297
|
+
const sections=collectWorkspaceSections();
|
|
23298
|
+
const available=sections.map(s=>({
|
|
23299
|
+
title:s.head,sectionId:s.metadata&&s.metadata.id||null,
|
|
23300
|
+
projects:(s.source&&s.source.projects||[]).map(p=>({
|
|
23301
|
+
type:p.type,workspaceId:p.workspaceIdentifier&&p.workspaceIdentifier.id||null,
|
|
23302
|
+
path:localWorkspacePath(p.workspaceIdentifier)||null,remoteAuthority:p.remoteAuthority||null,
|
|
23303
|
+
repoUrls:Array.isArray(p.repoUrls)?p.repoUrls:[]
|
|
23304
|
+
}))
|
|
23305
|
+
}));
|
|
23306
|
+
const matches=[];
|
|
23307
|
+
for(const section of sections){
|
|
23308
|
+
for(const project of section.source&§ion.source.projects||[]){
|
|
23309
|
+
if(project.type==='workspace'&&localWorkspacePath(project.workspaceIdentifier)===wanted){
|
|
23310
|
+
matches.push({section,project});
|
|
23311
|
+
}
|
|
23312
|
+
}
|
|
23313
|
+
}
|
|
23314
|
+
const fail=state=>({ok:false,state,wanted,available,
|
|
23315
|
+
nextStep:'In Cursor Agents Window, add or open the exact local folder (or .code-workspace file) '+projectPath+'. Ensure it has one registered local workspace creation target, then run cursor_init with that same path. Repository titles and historical Agents cannot establish the target.'});
|
|
23316
|
+
if(!matches.length)return {diagnostic:fail(sections.some(s=>s.metadata)?'workspace_registration_required':'workspace_identity_unavailable')};
|
|
23317
|
+
if(matches.length!==1)return {diagnostic:fail('workspace_ambiguous')};
|
|
23318
|
+
const {section,project}=matches[0];
|
|
23319
|
+
if(project.remoteAuthority||!project.workspaceIdentifier.id)return {diagnostic:fail('workspace_environment_unverified')};
|
|
23320
|
+
// Cursor's section-level New Agent action chooses among registered targets.
|
|
23321
|
+
// Do not click it when a second workspace could win that choice.
|
|
23322
|
+
if(section.source.projects.length!==1)return {diagnostic:fail('workspace_creation_target_ambiguous')};
|
|
23323
|
+
if(!section.button)return {diagnostic:fail('workspace_new_agent_unavailable')};
|
|
23324
|
+
return {section,diagnostic:{ok:true,state:'workspace_ready',workspace:wanted,
|
|
23325
|
+
workspaceId:project.workspaceIdentifier.id,sectionId:section.metadata.id,
|
|
23326
|
+
environment:'local',identitySource:'registered_workspace_file_uri',repoUrls:Array.isArray(project.repoUrls)?project.repoUrls:[]}};
|
|
23327
|
+
};
|
|
23246
23328
|
`;
|
|
23247
23329
|
function exprCreateAgentForWorkspace(projectPath) {
|
|
23248
|
-
const workspaceLabel = JSON.stringify(basename6(String(projectPath || "")).trim().toLowerCase());
|
|
23249
23330
|
return `(function(){
|
|
23250
23331
|
${WORKSPACE_SECTION_BODY}
|
|
23251
|
-
|
|
23252
|
-
const
|
|
23253
|
-
|
|
23254
|
-
const
|
|
23255
|
-
|
|
23256
|
-
|
|
23257
|
-
|
|
23258
|
-
if(!button)return JSON.stringify({ok:false,state:'repository_new_agent_unavailable',wanted});
|
|
23259
|
-
button.click();
|
|
23260
|
-
return JSON.stringify({ok:true,state:'repository_agent_created',workspace:wanted});
|
|
23332
|
+
${INPUT_PICKER_BODY}
|
|
23333
|
+
const result=inspectWorkspace(${JSON.stringify(String(projectPath || ""))});
|
|
23334
|
+
if(!result.diagnostic.ok)return JSON.stringify(result.diagnostic);
|
|
23335
|
+
const previousAgentIds=[...new Set(inputCandidates().flatMap(inputAgentHeaders)
|
|
23336
|
+
.map(header=>String(workspaceScalar(header.id)||'')).filter(Boolean))];
|
|
23337
|
+
result.section.button.click();
|
|
23338
|
+
return JSON.stringify({...result.diagnostic,state:'workspace_agent_creation_requested',previousAgentIds});
|
|
23261
23339
|
})()`;
|
|
23262
23340
|
}
|
|
23263
23341
|
function exprInspectWorkspaceRepository(projectPath) {
|
|
23264
|
-
const workspaceLabel = JSON.stringify(basename6(String(projectPath || "")).trim().toLowerCase());
|
|
23265
23342
|
return `(function(){
|
|
23266
23343
|
${WORKSPACE_SECTION_BODY}
|
|
23267
|
-
|
|
23268
|
-
|
|
23269
|
-
|
|
23270
|
-
|
|
23271
|
-
|
|
23272
|
-
|
|
23273
|
-
|
|
23344
|
+
return JSON.stringify(inspectWorkspace(${JSON.stringify(String(projectPath || ""))}).diagnostic);
|
|
23345
|
+
})()`;
|
|
23346
|
+
}
|
|
23347
|
+
function exprInspectAgentWorkspace(projectPath, options = {}) {
|
|
23348
|
+
return `(function(){
|
|
23349
|
+
${WORKSPACE_SECTION_BODY}
|
|
23350
|
+
${INPUT_PICKER_BODY}
|
|
23351
|
+
const wanted=normalizeWorkspacePath(${JSON.stringify(String(projectPath || ""))});
|
|
23352
|
+
const options=${JSON.stringify(options)};
|
|
23353
|
+
const rawId=id=>String(id||'').replace(/^local:/,'');
|
|
23354
|
+
const excluded=new Set((options.excludedAgentIds||[]).map(rawId));
|
|
23355
|
+
const fail=(state,observed=null)=>({ok:false,state,wanted,observed,
|
|
23356
|
+
nextStep:'Inspect task sendState before retrying. Select the exact local workspace '+${JSON.stringify(String(projectPath || ""))}+' in Cursor and retry cursor_init when no task may still be running. The Agent must expose an existing local environment for that same path; do not substitute a repository alias, cloud target, or another worktree.'});
|
|
23357
|
+
const inputs=inputCandidates();
|
|
23358
|
+
if(inputs.length!==1)return JSON.stringify(fail('agent_workspace_identity_unavailable',{inputCount:inputs.length}));
|
|
23359
|
+
const headers=inputAgentHeaders(inputs[0]);
|
|
23360
|
+
const ids=[...new Set(headers.map(header=>rawId(workspaceScalar(header.id))).filter(Boolean))];
|
|
23361
|
+
if(ids.length!==1||excluded.has(ids[0])||options.agentId&&ids[0]!==rawId(options.agentId)){
|
|
23362
|
+
return JSON.stringify(fail('agent_workspace_identity_unavailable',{
|
|
23363
|
+
inputCount:inputs.length,headerCount:headers.length,candidateAgentIds:ids,
|
|
23364
|
+
identitySource:'writable_input_react_ancestors',expectedAgentId:options.agentId||null,
|
|
23365
|
+
excludedAgentIdsMatched:ids.filter(id=>excluded.has(id))
|
|
23366
|
+
}));
|
|
23367
|
+
}
|
|
23368
|
+
const id=ids[0];
|
|
23369
|
+
if(options.requireInputFocus&&document.activeElement!==inputs[0])return JSON.stringify(fail('agent_input_focus_mismatch'));
|
|
23370
|
+
let observed;
|
|
23371
|
+
for(const header of headers){
|
|
23372
|
+
const target=workspaceScalar(header.targetEnvironment);
|
|
23373
|
+
const environment=workspaceScalar(header.environment);
|
|
23374
|
+
const location=workspaceScalar(header.location);
|
|
23375
|
+
observed={agentId:'local:'+id,targetType:target&&target.type||null,
|
|
23376
|
+
workspaceId:environment&&environment.id||null,path:localWorkspacePath(environment)||null,
|
|
23377
|
+
targetPath:localWorkspacePath(target&&target.environment)||null,locationType:location&&location.type||null};
|
|
23378
|
+
if(!wanted||!environment||!environment.id||!target||target.type!=='existing'
|
|
23379
|
+
||environment.remoteAuthority||target.remoteAuthority||target.environment&&target.environment.remoteAuthority
|
|
23380
|
+
||observed.path!==wanted||observed.targetPath!==wanted||target.environment.id!==environment.id
|
|
23381
|
+
||location&&(location.type!=='local'&&location.type!=='worktree'
|
|
23382
|
+
||localWorkspacePath(location.environment)!==wanted
|
|
23383
|
+
||location.type==='worktree'&&normalizeWorkspacePath(location.worktreePath)!==wanted)){
|
|
23384
|
+
return JSON.stringify(fail('agent_workspace_mismatch',observed));
|
|
23385
|
+
}
|
|
23386
|
+
}
|
|
23387
|
+
return JSON.stringify({ok:true,state:'agent_workspace_verified',workspace:wanted,
|
|
23388
|
+
environment:'local',identitySource:'selected_agent_existing_file_uri',...observed});
|
|
23274
23389
|
})()`;
|
|
23275
23390
|
}
|
|
23276
23391
|
var EXPR_HISTORY_OPEN = `(function(){return !![...document.querySelectorAll('.compact-agent-history-react-menu-label')].find(e=>e.offsetParent!==null);})()`;
|
|
@@ -23749,7 +23864,8 @@ var CursorBridge = class {
|
|
|
23749
23864
|
initialized: !!this.projectPath,
|
|
23750
23865
|
reinitializable: true,
|
|
23751
23866
|
interactionPreference: "agents_v2_when_open_else_legacy",
|
|
23752
|
-
cursorUiPreferencePreserved: true
|
|
23867
|
+
cursorUiPreferencePreserved: true,
|
|
23868
|
+
workspaceBinding: this._lastWorkspaceBinding || null
|
|
23753
23869
|
};
|
|
23754
23870
|
}
|
|
23755
23871
|
sessionRegistryView() {
|
|
@@ -24185,6 +24301,7 @@ var CursorBridge = class {
|
|
|
24185
24301
|
this.workspaceSource = "persistent_init";
|
|
24186
24302
|
this.workspaceUpdatedAt = saved.updatedAt;
|
|
24187
24303
|
this._lastLifecycle = null;
|
|
24304
|
+
this._lastWorkspaceBinding = null;
|
|
24188
24305
|
try {
|
|
24189
24306
|
await this._ensureCursor();
|
|
24190
24307
|
} catch (error2) {
|
|
@@ -24224,6 +24341,7 @@ var CursorBridge = class {
|
|
|
24224
24341
|
}
|
|
24225
24342
|
async _findAgentsWorkspace(projectPath) {
|
|
24226
24343
|
if (!projectPath) return null;
|
|
24344
|
+
this._lastWorkspaceBinding = null;
|
|
24227
24345
|
let page;
|
|
24228
24346
|
try {
|
|
24229
24347
|
page = await findPage({ purpose: "fifo", preferAgentsV2: true });
|
|
@@ -24235,13 +24353,15 @@ var CursorBridge = class {
|
|
|
24235
24353
|
try {
|
|
24236
24354
|
await c.ready;
|
|
24237
24355
|
const repository = JSON.parse(await evalJS(c, exprInspectWorkspaceRepository(projectPath)) || "{}");
|
|
24356
|
+
this._lastWorkspaceBinding = { ...repository, checkedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
24238
24357
|
if (!repository.ok) return null;
|
|
24239
24358
|
return {
|
|
24240
24359
|
targetId: page.id,
|
|
24241
24360
|
targetUiFlavor: "agents_v2",
|
|
24242
24361
|
workspace: repository.workspace
|
|
24243
24362
|
};
|
|
24244
|
-
} catch {
|
|
24363
|
+
} catch (error2) {
|
|
24364
|
+
this._lastWorkspaceBinding = { ok: false, state: "workspace_probe_failed", wanted: projectPath, error: String(error2.message || error2) };
|
|
24245
24365
|
return null;
|
|
24246
24366
|
} finally {
|
|
24247
24367
|
c.close();
|
|
@@ -24371,16 +24491,18 @@ var CursorBridge = class {
|
|
|
24371
24491
|
recovery: normalized === "minimal" ? "Switch CCE to normal mode before opening Cursor manually." : null
|
|
24372
24492
|
};
|
|
24373
24493
|
}
|
|
24374
|
-
async contextEngine(query) {
|
|
24494
|
+
async contextEngine(query, options = {}) {
|
|
24375
24495
|
const text = String(query || "").trim();
|
|
24376
24496
|
if (!text) throw new Error("query must not be empty");
|
|
24377
24497
|
if (text.length > 2e4) throw new Error("query exceeds the 20,000-character limit");
|
|
24498
|
+
const requestContext = normalizeRequestContext(options.requestContext);
|
|
24378
24499
|
this._assertWorkspaceConfirmed();
|
|
24379
24500
|
if (this._hasGlobalReservation()) {
|
|
24380
24501
|
throw new Error("A global Cursor reservation has an unconfirmed Stop state; resolve blockingTaskIds from cursor_status first");
|
|
24381
24502
|
}
|
|
24382
24503
|
await this._ensureCursor();
|
|
24383
|
-
const job = this._enqueue("context_engine", buildContextEnginePrompt(text), {
|
|
24504
|
+
const job = this._enqueue("context_engine", buildContextEnginePrompt(text, requestContext), {
|
|
24505
|
+
requestContext,
|
|
24384
24506
|
timeoutMs: QUERY_TIMEOUT,
|
|
24385
24507
|
newChat: true,
|
|
24386
24508
|
execution: "fifo",
|
|
@@ -24406,6 +24528,7 @@ var CursorBridge = class {
|
|
|
24406
24528
|
const text = String(prompt || "").trim();
|
|
24407
24529
|
if (!text) throw new Error("prompt must not be empty");
|
|
24408
24530
|
if (text.length > 1e5) throw new Error("prompt exceeds the 100,000-character limit");
|
|
24531
|
+
const requestContext = normalizeRequestContext(options.requestContext);
|
|
24409
24532
|
this._assertWorkspaceConfirmed();
|
|
24410
24533
|
if (this._hasGlobalReservation()) {
|
|
24411
24534
|
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");
|
|
@@ -24454,7 +24577,7 @@ var CursorBridge = class {
|
|
|
24454
24577
|
throw cursorSessionError("SESSION_WORKSPACE_REQUIRED", "initialize one workspace before creating or continuing a session");
|
|
24455
24578
|
}
|
|
24456
24579
|
const contract = String(options.completionContract || "").trim();
|
|
24457
|
-
let fullPrompt = text + DO_LANGUAGE_CONTRACT;
|
|
24580
|
+
let fullPrompt = buildRequestContextHeader(requestContext) + "\n\nTask:\n" + text + DO_LANGUAGE_CONTRACT;
|
|
24458
24581
|
if (readOnly) fullPrompt += "\n\nRead-only boundary: Do not modify, create, or delete files, and do not run commands that change workspace state.";
|
|
24459
24582
|
if (allowedPaths.length > 0) {
|
|
24460
24583
|
fullPrompt += "\n\nAllowed modification scope (do not cross this boundary):\n" + allowedPaths.map((x) => "- " + x).join("\n");
|
|
@@ -24493,6 +24616,7 @@ var CursorBridge = class {
|
|
|
24493
24616
|
}
|
|
24494
24617
|
}
|
|
24495
24618
|
const job = this._enqueue("do", fullPrompt, {
|
|
24619
|
+
requestContext,
|
|
24496
24620
|
taskId,
|
|
24497
24621
|
timeoutMs,
|
|
24498
24622
|
newChat: sessionMode !== "continue",
|
|
@@ -24556,6 +24680,7 @@ var CursorBridge = class {
|
|
|
24556
24680
|
id,
|
|
24557
24681
|
kind,
|
|
24558
24682
|
prompt,
|
|
24683
|
+
requestContext: options.requestContext || normalizeRequestContext(),
|
|
24559
24684
|
timeoutMs: options.timeoutMs,
|
|
24560
24685
|
newChat: options.newChat,
|
|
24561
24686
|
preferLegacyUi: options.preferLegacyUi === true,
|
|
@@ -24635,6 +24760,7 @@ var CursorBridge = class {
|
|
|
24635
24760
|
if (isTerminalTask(job)) return;
|
|
24636
24761
|
const e = error2 instanceof Error ? error2 : new Error(String(error2));
|
|
24637
24762
|
job.error = e.message;
|
|
24763
|
+
if (e.workspaceBindingFailure) job.workspaceBinding = e.workspaceBindingFailure;
|
|
24638
24764
|
if (e.providerError) job.providerError = e.providerError;
|
|
24639
24765
|
if (e.uiDiagnostic) job.uiDiagnostic = e.uiDiagnostic;
|
|
24640
24766
|
if (e.terminalEvidence) job.terminalEvidence = e.terminalEvidence;
|
|
@@ -24740,7 +24866,7 @@ var CursorBridge = class {
|
|
|
24740
24866
|
this._lastLifecycle = promoteAgentsWorkspaceLifecycle(this._lastLifecycle, agentsWorkspace);
|
|
24741
24867
|
}
|
|
24742
24868
|
}
|
|
24743
|
-
if (rr.ok && rr.
|
|
24869
|
+
if (rr.ok && rr.workspaceAction === "reused-agents-window" && rr.projectPath) {
|
|
24744
24870
|
const agentsWorkspace = await this._findAgentsWorkspace(rr.projectPath);
|
|
24745
24871
|
if (agentsWorkspace) {
|
|
24746
24872
|
this._lastLifecycle = promoteAgentsWorkspaceLifecycle(this._lastLifecycle, agentsWorkspace);
|
|
@@ -24748,9 +24874,9 @@ var CursorBridge = class {
|
|
|
24748
24874
|
this._lastLifecycle = {
|
|
24749
24875
|
...this._lastLifecycle,
|
|
24750
24876
|
status: "workspace-not-ready",
|
|
24751
|
-
message: `Cursor is reachable, but Cursor Bridge could not verify workspace ${rr.projectPath} in the
|
|
24877
|
+
message: `Cursor is reachable, but Cursor Bridge could not verify workspace ${rr.projectPath} in the Agents Window (${this._lastWorkspaceBinding?.state || "workspace_probe_unavailable"}).`,
|
|
24752
24878
|
needsAction: "open_workspace_in_cursor",
|
|
24753
|
-
nextStep: `Open workspace ${rr.projectPath} in Cursor, then retry the same operation.`,
|
|
24879
|
+
nextStep: this._lastWorkspaceBinding?.nextStep || `Open workspace ${rr.projectPath} in Cursor, then retry the same operation.`,
|
|
24754
24880
|
retryable: true
|
|
24755
24881
|
};
|
|
24756
24882
|
}
|
|
@@ -24927,10 +25053,11 @@ var CursorBridge = class {
|
|
|
24927
25053
|
try {
|
|
24928
25054
|
await this._newChat(c, {
|
|
24929
25055
|
uiFlavor: options.targetUiFlavor,
|
|
24930
|
-
projectPath: options.projectPath || this._lastLifecycle && this._lastLifecycle.projectPath || this.projectPath
|
|
25056
|
+
projectPath: options.projectPath || this._lastLifecycle && this._lastLifecycle.projectPath || this.projectPath,
|
|
25057
|
+
job: options
|
|
24931
25058
|
});
|
|
24932
25059
|
} catch (error2) {
|
|
24933
|
-
if (attempt === 0 && options.targetUiFlavor === "agents_v2" && isAgentsWorkspaceBindError(error2)) {
|
|
25060
|
+
if (attempt === 0 && options.targetUiFlavor === "agents_v2" && isAgentsWorkspaceBindError(error2) && !error2.workspaceBindingFailure) {
|
|
24934
25061
|
const fallback = await findPage({ purpose: "fifo", preferLegacy: true });
|
|
24935
25062
|
if (fallback && fallback.id !== page.id) {
|
|
24936
25063
|
options.fallbackReason = "agents_window_unbound_use_workbench";
|
|
@@ -24957,10 +25084,11 @@ var CursorBridge = class {
|
|
|
24957
25084
|
} catch {
|
|
24958
25085
|
}
|
|
24959
25086
|
const providerErrorBaseline = providerErrorSignature(await this._readProviderError(c));
|
|
25087
|
+
await this._verifyAgentsWorkspace(c, options, "before_send");
|
|
24960
25088
|
options.sendState = "dispatching";
|
|
24961
25089
|
try {
|
|
24962
25090
|
await chord(c, 0, "Enter", "Enter", 13);
|
|
24963
|
-
await this._confirmSubmission(c, baseline.messageCount || 0, providerErrorBaseline);
|
|
25091
|
+
await this._confirmSubmission(c, baseline.messageCount || 0, providerErrorBaseline, options);
|
|
24964
25092
|
options.sendState = "sent";
|
|
24965
25093
|
options.sentAt = options.sentAt || (/* @__PURE__ */ new Date()).toISOString();
|
|
24966
25094
|
await this._bindFifoAgentAfterSend(c, options, historyBefore, providerErrorBaseline);
|
|
@@ -25350,11 +25478,19 @@ var CursorBridge = class {
|
|
|
25350
25478
|
async _newChat(c, options = {}) {
|
|
25351
25479
|
if (options.uiFlavor === "agents_v2" && options.projectPath) {
|
|
25352
25480
|
const created = JSON.parse(await evalJS(c, exprCreateAgentForWorkspace(options.projectPath)) || "{}");
|
|
25481
|
+
if (options.job) {
|
|
25482
|
+
options.job.workspaceBindingChecks = { before_create: { ...created, checkedAt: (/* @__PURE__ */ new Date()).toISOString() } };
|
|
25483
|
+
}
|
|
25353
25484
|
if (!created.ok) {
|
|
25354
|
-
|
|
25355
|
-
throw new Error(`Cursor Agents workspace binding failed: ${created.state || "unknown"}; wanted=${created.wanted || basename6(options.projectPath)}${available}`);
|
|
25485
|
+
throw createWorkspaceBindingError(created);
|
|
25356
25486
|
}
|
|
25357
25487
|
await sleep2(1100);
|
|
25488
|
+
const actual = JSON.parse(await evalJS(c, exprInspectAgentWorkspace(options.projectPath, { excludedAgentIds: created.previousAgentIds })) || "{}");
|
|
25489
|
+
if (options.job) options.job.workspaceBindingChecks.after_create = { ...actual, checkedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
25490
|
+
if (!actual.ok) throw createWorkspaceBindingError(actual);
|
|
25491
|
+
if (actual.workspaceId !== created.workspaceId) {
|
|
25492
|
+
throw createWorkspaceBindingError({ ...actual, ok: false, state: "created_workspace_id_mismatch" });
|
|
25493
|
+
}
|
|
25358
25494
|
return true;
|
|
25359
25495
|
}
|
|
25360
25496
|
return this._clickNewAgent(c, true);
|
|
@@ -25491,6 +25627,7 @@ var CursorBridge = class {
|
|
|
25491
25627
|
}
|
|
25492
25628
|
}
|
|
25493
25629
|
async _fillPrompt(c, text, job, timeoutMs = 2500) {
|
|
25630
|
+
await this._verifyAgentsWorkspace(c, job);
|
|
25494
25631
|
const prepared = await evalJS(c, EXPR_PREPARE_INPUT);
|
|
25495
25632
|
if (prepared !== "READY") return prepared;
|
|
25496
25633
|
try {
|
|
@@ -25522,7 +25659,18 @@ var CursorBridge = class {
|
|
|
25522
25659
|
};
|
|
25523
25660
|
throw error2;
|
|
25524
25661
|
}
|
|
25525
|
-
async
|
|
25662
|
+
async _verifyAgentsWorkspace(c, job, stage = "before_fill") {
|
|
25663
|
+
if (!job || job.targetUiFlavor !== "agents_v2") return;
|
|
25664
|
+
const projectPath = job.projectPath || this.projectPath;
|
|
25665
|
+
const diagnostic = JSON.parse(await evalJS(c, exprInspectAgentWorkspace(projectPath, {
|
|
25666
|
+
agentId: job.agentId || job.provisionalAgentId || job.workspaceBinding?.agentId,
|
|
25667
|
+
requireInputFocus: stage === "before_send"
|
|
25668
|
+
})) || "{}");
|
|
25669
|
+
job.workspaceBinding = { ...diagnostic, checkedAt: (/* @__PURE__ */ new Date()).toISOString() };
|
|
25670
|
+
job.workspaceBindingChecks = { ...job.workspaceBindingChecks, [stage]: job.workspaceBinding };
|
|
25671
|
+
if (!diagnostic.ok) throw createWorkspaceBindingError(diagnostic);
|
|
25672
|
+
}
|
|
25673
|
+
async _confirmSubmission(c, baselineCount = 0, providerErrorBaseline = "", job = null) {
|
|
25526
25674
|
const accepted = async () => {
|
|
25527
25675
|
await this._throwIfNewProviderError(c, providerErrorBaseline);
|
|
25528
25676
|
let snap = {};
|
|
@@ -25537,6 +25685,13 @@ var CursorBridge = class {
|
|
|
25537
25685
|
await sleep2(250);
|
|
25538
25686
|
if (await accepted()) return "enter";
|
|
25539
25687
|
}
|
|
25688
|
+
try {
|
|
25689
|
+
await this._verifyAgentsWorkspace(c, job, "before_send_fallback");
|
|
25690
|
+
} catch (error3) {
|
|
25691
|
+
error3.confirmedNotSent = false;
|
|
25692
|
+
error3.sent = true;
|
|
25693
|
+
throw error3;
|
|
25694
|
+
}
|
|
25540
25695
|
const clicked = await evalJS(c, EXPR_CLICK_SEND);
|
|
25541
25696
|
if (clicked === "CLICKED") {
|
|
25542
25697
|
for (let i = 0; i < 20; i++) {
|
|
@@ -25587,9 +25742,9 @@ var CursorBridge = class {
|
|
|
25587
25742
|
this._throwIfCancelledBeforeSend(job);
|
|
25588
25743
|
let createdForWorkspace = false;
|
|
25589
25744
|
try {
|
|
25590
|
-
createdForWorkspace = job.targetUiFlavor === "agents_v2" && job.projectPath ? await this._newChat(c, { uiFlavor: job.targetUiFlavor, projectPath: job.projectPath }) : await this._clickNewAgent(c, false);
|
|
25745
|
+
createdForWorkspace = job.targetUiFlavor === "agents_v2" && job.projectPath ? await this._newChat(c, { uiFlavor: job.targetUiFlavor, projectPath: job.projectPath, job }) : await this._clickNewAgent(c, false);
|
|
25591
25746
|
} catch (error2) {
|
|
25592
|
-
if (isAgentsWorkspaceBindError(error2)) {
|
|
25747
|
+
if (isAgentsWorkspaceBindError(error2) && !error2.workspaceBindingFailure) {
|
|
25593
25748
|
return { fallbackReason: "Agents Window could not bind the current repository; downgraded to FIFO/workbench before submission" };
|
|
25594
25749
|
}
|
|
25595
25750
|
throw error2;
|
|
@@ -25622,9 +25777,10 @@ var CursorBridge = class {
|
|
|
25622
25777
|
baseline = JSON.parse(await evalJS(c, EXPR_SNAP));
|
|
25623
25778
|
} catch {
|
|
25624
25779
|
}
|
|
25780
|
+
await this._verifyAgentsWorkspace(c, job, "before_send");
|
|
25625
25781
|
job.sendState = "dispatching";
|
|
25626
25782
|
await chord(c, 0, "Enter", "Enter", 13);
|
|
25627
|
-
await this._confirmSubmission(c, baseline.messageCount || 0, providerErrorBaseline);
|
|
25783
|
+
await this._confirmSubmission(c, baseline.messageCount || 0, providerErrorBaseline, job);
|
|
25628
25784
|
sent = true;
|
|
25629
25785
|
job.sendState = "sent";
|
|
25630
25786
|
job.sentAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -25739,9 +25895,10 @@ var CursorBridge = class {
|
|
|
25739
25895
|
}
|
|
25740
25896
|
await sleep2(350);
|
|
25741
25897
|
this._throwIfCancelledBeforeSend(job);
|
|
25898
|
+
await this._verifyAgentsWorkspace(c, job, "before_send");
|
|
25742
25899
|
job.sendState = "dispatching";
|
|
25743
25900
|
await chord(c, 0, "Enter", "Enter", 13);
|
|
25744
|
-
await this._confirmSubmission(c, job.responseBaseline.messageCount, providerErrorBaseline);
|
|
25901
|
+
await this._confirmSubmission(c, job.responseBaseline.messageCount, providerErrorBaseline, job);
|
|
25745
25902
|
sent = true;
|
|
25746
25903
|
job.sendState = "sent";
|
|
25747
25904
|
job.sentAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
@@ -26569,6 +26726,9 @@ var CursorBridge = class {
|
|
|
26569
26726
|
allowedPaths: job.allowedPaths,
|
|
26570
26727
|
modelPreference: job.modelPreference,
|
|
26571
26728
|
modelSelection: job.modelSelection,
|
|
26729
|
+
requestContext: job.requestContext || normalizeRequestContext(),
|
|
26730
|
+
workspaceBinding: job.workspaceBinding || null,
|
|
26731
|
+
workspaceBindingChecks: job.workspaceBindingChecks || null,
|
|
26572
26732
|
projectPath: job.projectPath,
|
|
26573
26733
|
sessionMode: job.sessionMode || "isolated",
|
|
26574
26734
|
sessionId: job.sessionId || null,
|
|
@@ -26696,11 +26856,21 @@ function buildSearchInputSchema() {
|
|
|
26696
26856
|
return {
|
|
26697
26857
|
type: "object",
|
|
26698
26858
|
properties: {
|
|
26699
|
-
query: { type: "string", description: "Describe the behavior, concept, symbol relationship, or ownership boundary to locate. State intent instead of guessing a directory." }
|
|
26859
|
+
query: { type: "string", description: "Describe the behavior, concept, symbol relationship, or ownership boundary to locate. State intent instead of guessing a directory." },
|
|
26860
|
+
request_context: REQUEST_CONTEXT_SCHEMA
|
|
26700
26861
|
},
|
|
26701
26862
|
required: ["query"]
|
|
26702
26863
|
};
|
|
26703
26864
|
}
|
|
26865
|
+
var REQUEST_CONTEXT_SCHEMA = {
|
|
26866
|
+
type: "object",
|
|
26867
|
+
additionalProperties: false,
|
|
26868
|
+
description: "Caller-declared provenance for this request only, not authentication or authorization. Missing values remain unknown; never infer them from the chosen model. Separate user requirements and model additions in mixed task text.",
|
|
26869
|
+
properties: {
|
|
26870
|
+
sender: { type: "string", enum: ["user", "model", "unknown"], description: "Who directly sends this Bridge request. AI callers should declare model, even when acting on a user request." },
|
|
26871
|
+
source: { type: "string", enum: ["user", "model", "mixed", "unknown"], description: "user for explicitly supplied user requirements, model for model-authored tasks/inferences, mixed when the prompt clearly separates both; unknown when not established." }
|
|
26872
|
+
}
|
|
26873
|
+
};
|
|
26704
26874
|
function buildToolDefinitions(bridgeInstance) {
|
|
26705
26875
|
return [
|
|
26706
26876
|
{
|
|
@@ -26726,6 +26896,7 @@ function buildToolDefinitions(bridgeInstance) {
|
|
|
26726
26896
|
type: "object",
|
|
26727
26897
|
properties: {
|
|
26728
26898
|
prompt: { type: "string", description: "The task Cursor should receive. State the goal, boundaries, and what a complete result looks like." },
|
|
26899
|
+
request_context: REQUEST_CONTEXT_SCHEMA,
|
|
26729
26900
|
background: { type: "boolean", default: true, description: "When true, return the task ID immediately. When false, wait for the task to finish or need attention." },
|
|
26730
26901
|
execution: { type: "string", enum: ["fifo", "parallel_agent"], default: "fifo", description: "fifo is the first-in, first-out serial queue and runs one task at a time in a clean chat. parallel_agent creates a separate top-level Cursor Agent." },
|
|
26731
26902
|
read_only: { type: "boolean", default: false, description: "Set true when Cursor must not change the workspace." },
|
|
@@ -26855,11 +27026,12 @@ server.setRequestHandler(CallToolRequestSchema, async (request2) => {
|
|
|
26855
27026
|
return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }] };
|
|
26856
27027
|
}
|
|
26857
27028
|
if (name === "cursor_context_engine" || name === "cursor_search" || name === "cursor_search_deep") {
|
|
26858
|
-
const result = await bridge.contextEngine(String(args && args.query || ""));
|
|
27029
|
+
const result = await bridge.contextEngine(String(args && args.query || ""), { requestContext: args && args.request_context });
|
|
26859
27030
|
return { content: [{ type: "text", text: String(result) }] };
|
|
26860
27031
|
}
|
|
26861
27032
|
if (name === "cursor_do") {
|
|
26862
27033
|
const result = await bridge.doTask(String(args && args.prompt || ""), {
|
|
27034
|
+
requestContext: args && args.request_context,
|
|
26863
27035
|
background: !args || args.background !== false,
|
|
26864
27036
|
execution: args && args.execution,
|
|
26865
27037
|
readOnly: !!(args && args.read_only),
|
|
@@ -27002,6 +27174,7 @@ export {
|
|
|
27002
27174
|
exprClickBoundComposerStop,
|
|
27003
27175
|
exprClickSelectedAgentStop,
|
|
27004
27176
|
exprCreateAgentForWorkspace,
|
|
27177
|
+
exprInspectAgentWorkspace,
|
|
27005
27178
|
exprInspectWorkspaceRepository,
|
|
27006
27179
|
exprOpenAgent,
|
|
27007
27180
|
isConfirmedCompletedReply,
|
|
@@ -27017,6 +27190,7 @@ export {
|
|
|
27017
27190
|
normalizeCursorRuntimeMode,
|
|
27018
27191
|
normalizeDelegationMode,
|
|
27019
27192
|
normalizeModelPickerText,
|
|
27193
|
+
normalizeRequestContext,
|
|
27020
27194
|
pathsOverlap,
|
|
27021
27195
|
promoteAgentsWorkspaceLifecycle,
|
|
27022
27196
|
providerErrorSignature,
|
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.1.
|
|
13
|
+
packageVersion: "0.1.16",
|
|
14
14
|
serverName: "cursor-bridge",
|
|
15
15
|
serverScript: join(packageRoot, "dist", "cursor-bridge.mjs"),
|
|
16
16
|
cwd: hostCwd,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-cursor-bridge",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.16",
|
|
4
4
|
"description": "Use Cursor Context Engine and bounded, explicitly continuous Cursor Agent execution from the Pi coding agent.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -47,6 +47,6 @@
|
|
|
47
47
|
},
|
|
48
48
|
"piPackage": {
|
|
49
49
|
"embeddedProduct": "Cursor Bridge",
|
|
50
|
-
"embeddedProductVersion": "5.
|
|
50
|
+
"embeddedProductVersion": "5.10.0"
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -41,7 +41,7 @@ Call `cursor_context_engine` once with the question's real intent. Include a kno
|
|
|
41
41
|
- Describe the relationship or behavior to establish and the evidence needed.
|
|
42
42
|
- Preserve the language of the user's current substantive request unless the user explicitly asks for another language. Do not infer or persist a different language from the operating system when the conversation already provides a clear signal.
|
|
43
43
|
- Do not prescribe Cursor's internal search sequence, harness, Explore usage, or number of files.
|
|
44
|
-
-
|
|
44
|
+
- Keep investigation intent in `query`. Use the optional `request_context` only to declare provenance: AI callers use `sender="model"`; `source` is `user`, `model`, `mixed`, or `unknown`. A retrieval question you inferred is model-authored even when it serves a user goal. Separate user requirements and your additions when using `mixed`; never guess missing provenance.
|
|
45
45
|
- Allow a cold or large workspace enough time to complete its serialized Cursor UI turn.
|
|
46
46
|
|
|
47
47
|
## Verify and continue
|
|
@@ -7,6 +7,8 @@ description: "Delegate bounded light-to-medium implementation, investigation, do
|
|
|
7
7
|
|
|
8
8
|
Use Cursor as an execution partner. Keep direction, scope decisions, risk ownership, result review, and final verification with the primary agent.
|
|
9
9
|
|
|
10
|
+
Declare `request_context` for each call: an AI caller uses `sender="model"`; set `source="user"` for explicitly supplied user requirements, `"model"` for your own task/inference, or `"mixed"` when both appear. In mixed prompts, label user-confirmed requirements separately from your additions. Use `"unknown"` where provenance is unavailable; a user asking you to use Cursor does not make your authored message user-authored. These labels are declarations, not authentication or extra permission, and do not carry over to later session turns.
|
|
11
|
+
|
|
10
12
|
## Respect execution controls
|
|
11
13
|
|
|
12
14
|
- Do not call `cursor_do` when the user explicitly says not to use Cursor or not to delegate. A direct user opt-out always wins.
|
|
@@ -16,6 +16,7 @@ Provide every task independently:
|
|
|
16
16
|
| Field | Requirement |
|
|
17
17
|
|---|---|
|
|
18
18
|
| `prompt` | State one objective, the necessary context, prohibited actions, and the expected report. Use the current user-task language unless the user explicitly requests another language. Do not ask Cursor to repeat the primary agent's scope decision. |
|
|
19
|
+
| `request_context` | Declare `sender` (`user/model/unknown`) and instruction `source` (`user/model/mixed/unknown`) for this turn. AI callers use sender=model. Label user-confirmed requirements and model additions separately for mixed prompts. Omitted fields remain unknown; these declarations never authorize work. |
|
|
19
20
|
| `execution` | Use only `fifo` or `parallel_agent`. Use `fifo` when safe parallelism cannot be demonstrated. |
|
|
20
21
|
| `read_only` | Use `true` for lookup and analysis; use `false` for any file modification. |
|
|
21
22
|
| `allowed_paths` | Required when `read_only=false`. Provide the smallest workspace-relative path set, with no glob, absolute path, or workspace-escaping `..`. Omit it when `read_only=true`. This is not a filesystem sandbox. |
|
|
@@ -40,6 +41,7 @@ Parallel read-only task:
|
|
|
40
41
|
```json
|
|
41
42
|
{
|
|
42
43
|
"prompt": "Read the specified files and return conclusions without modifying any file.",
|
|
44
|
+
"request_context": { "sender": "model", "source": "model" },
|
|
43
45
|
"execution": "parallel_agent",
|
|
44
46
|
"read_only": true,
|
|
45
47
|
"background": true,
|
|
@@ -52,6 +54,7 @@ Bounded write task:
|
|
|
52
54
|
```json
|
|
53
55
|
{
|
|
54
56
|
"prompt": "Implement the specified tool script under the fixed design without expanding scope.",
|
|
57
|
+
"request_context": { "sender": "model", "source": "model" },
|
|
55
58
|
"execution": "parallel_agent",
|
|
56
59
|
"read_only": false,
|
|
57
60
|
"background": true,
|