pi-cursor-bridge 0.1.10 → 0.1.12

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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cursor-bridge",
3
- "version": "5.8.0+codex.20260901100252",
3
+ "version": "5.8.2+codex.20260904092304",
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
@@ -2,12 +2,14 @@
2
2
 
3
3
  Use Cursor's project index and Agent search from Pi, with compact `path:line` evidence and optional bounded Cursor task execution.
4
4
 
5
+ ⭐ If Cursor Bridge helps you, please consider giving it a [Star on GitHub](https://github.com/Vanyangyang/cursor-bridge)—it helps others discover the project.
6
+
5
7
  ```powershell
6
8
  pi install npm:pi-cursor-bridge
7
9
  ```
8
10
 
9
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.
10
12
 
11
- This Pi package embeds Cursor Bridge 5.8.0. Cursor must be installed and signed in. Current end-to-end compatibility claims remain scoped to the environments documented in the main repository.
13
+ This Pi package embeds Cursor Bridge 5.8.2. Cursor must be installed and signed in. Current end-to-end compatibility claims remain scoped to the environments documented in the main repository.
12
14
 
13
- Full documentation: [English](https://github.com/Vanyangyang/cursor-bridge#readme) · [简体中文](https://github.com/Vanyangyang/cursor-bridge/blob/master/README.zh-CN.md)
15
+ Full documentation: [English](https://github.com/Vanyangyang/cursor-bridge#readme) · [简体中文](https://github.com/Vanyangyang/cursor-bridge/blob/main/README.zh-CN.md)
@@ -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.8.0";
22607
+ var PLUGIN_VERSION = "5.8.2";
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);
@@ -22744,11 +22744,6 @@ function summarizeCdpPages(list) {
22744
22744
  page: first && first.url ? String(first.url).slice(0, 60) : ""
22745
22745
  };
22746
22746
  }
22747
- function isBlankAgentsWindow(page) {
22748
- if (!page || !isAgentsWindowTitle(page.title)) return false;
22749
- if (page.probeError || !page.capabilities) return true;
22750
- return page.capabilities.uiFlavor !== "agents_v2" && !page.capabilities.hasWritableInput;
22751
- }
22752
22747
  var NORMAL_AGENTS_PRESENTATION_REFRESH_MS = 5 * 60 * 1e3;
22753
22748
  function shouldRecoverNormalAgentsPresentation({
22754
22749
  runtimeMode,
@@ -22769,25 +22764,6 @@ function shouldRecoverNormalAgentsPresentation({
22769
22764
  if (!Number.isFinite(previousAt)) return true;
22770
22765
  return Number(now) - previousAt >= Math.max(0, Number(refreshMs) || 0);
22771
22766
  }
22772
- async function reloadPageTarget(page, timeoutMs = 5e3) {
22773
- if (!page || !page.webSocketDebuggerUrl) return false;
22774
- const c = makeClient(page.webSocketDebuggerUrl);
22775
- try {
22776
- await Promise.race([
22777
- c.ready,
22778
- new Promise((_, reject) => setTimeout(() => reject(new Error("Timed out connecting to the CDP target")), timeoutMs))
22779
- ]);
22780
- await Promise.race([
22781
- c.send("Page.reload", { ignoreCache: true }),
22782
- new Promise((_, reject) => setTimeout(() => reject(new Error("Timed out reloading the CDP target")), timeoutMs))
22783
- ]);
22784
- return true;
22785
- } catch {
22786
- return false;
22787
- } finally {
22788
- c.close();
22789
- }
22790
- }
22791
22767
  async function inspectPageTarget(page) {
22792
22768
  const c = makeClient(page.webSocketDebuggerUrl);
22793
22769
  const probeMs = Number(process.env.CURSOR_BRIDGE_PAGE_PROBE_TIMEOUT || 5e3);
@@ -22807,24 +22783,6 @@ async function inspectPageTarget(page) {
22807
22783
  c.close();
22808
22784
  }
22809
22785
  }
22810
- async function recoverBlankAgentsWindows(inspected) {
22811
- const pages = Array.isArray(inspected) ? inspected : [];
22812
- const recovered = [];
22813
- for (const page of pages) {
22814
- if (!isBlankAgentsWindow(page)) {
22815
- recovered.push(page);
22816
- continue;
22817
- }
22818
- const reloaded = await reloadPageTarget(page);
22819
- if (!reloaded) {
22820
- recovered.push(page);
22821
- continue;
22822
- }
22823
- await sleep2(800);
22824
- recovered.push(await inspectPageTarget(page));
22825
- }
22826
- return recovered;
22827
- }
22828
22786
  function pagesWithFlavor(pages, flavor) {
22829
22787
  return (Array.isArray(pages) ? pages : []).filter((page) => page && page.capabilities && page.capabilities.uiFlavor === flavor);
22830
22788
  }
@@ -22855,7 +22813,7 @@ async function findPage(options = {}) {
22855
22813
  if (options.targetId && options.preferAgentsV2 !== true && options.preferLegacy !== true) {
22856
22814
  return selectCursorPageCandidate(pages, options);
22857
22815
  }
22858
- const inspected = await recoverBlankAgentsWindows(await Promise.all(pages.map(inspectPageTarget)));
22816
+ const inspected = await Promise.all(pages.map(inspectPageTarget));
22859
22817
  return selectPageForUiPreference(inspected, options) || pages[0];
22860
22818
  }
22861
22819
  function makeClient(wsUrl) {
@@ -22941,10 +22899,71 @@ var INPUT_PICKER_BODY = `
22941
22899
  .filter(e=>e.offsetParent!==null&&!e.disabled&&e.getAttribute('aria-disabled')!=='true'&&e.getAttribute('contenteditable')!=='false')
22942
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))[0]||null;`;
22943
22901
  var EXPR_VISIBLE = `(function(){${INPUT_PICKER_BODY}return !!pickInput();})()`;
22944
- function exprFill(text) {
22945
- const js = JSON.stringify(text);
22946
- return `(function(){${INPUT_PICKER_BODY}const inp=pickInput();if(!inp)return 'NO_INPUT';inp.focus();try{const s=getSelection();const r=document.createRange();r.selectNodeContents(inp);s.removeAllRanges();s.addRange(r);}catch(e){}const ok=document.execCommand('insertText',false,${js});try{inp.dispatchEvent(new InputEvent('input',{bubbles:true,inputType:'insertText',data:${js}}));}catch(e){inp.dispatchEvent(new Event('input',{bubbles:true}));}return ok?(inp.innerText||'').slice(0,30):'EXEC_FAIL';})()`;
22902
+ 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
+ function classifyChatPanelDiagnostic(snapshot = {}) {
22904
+ const evidence = {
22905
+ writableInputVisible: snapshot.writableInputVisible === true || snapshot.hasWritableInput === true,
22906
+ inputCandidateCount: Number.isFinite(Number(snapshot.inputCandidateCount)) ? Number(snapshot.inputCandidateCount) : 0,
22907
+ settingsOrCustomizeVisible: snapshot.settingsOrCustomizeVisible === true,
22908
+ modalVisible: snapshot.modalVisible === true,
22909
+ modalLabel: snapshot.modalLabel ? String(snapshot.modalLabel) : null,
22910
+ signInControlVisible: snapshot.signInControlVisible === true,
22911
+ signInVisible: snapshot.signInVisible === true,
22912
+ agentSurfaceVisible: snapshot.agentSurfaceVisible === true,
22913
+ composerCount: Number.isFinite(Number(snapshot.composerCount)) ? Number(snapshot.composerCount) : 0,
22914
+ visibilityState: String(snapshot.visibilityState || "unknown"),
22915
+ focused: typeof snapshot.focused === "boolean" ? snapshot.focused : null,
22916
+ pageTitle: snapshot.pageTitle ? String(snapshot.pageTitle) : null,
22917
+ probeError: snapshot.probeError ? String(snapshot.probeError) : null,
22918
+ inputStateChanged: snapshot.inputStateChanged === true
22919
+ };
22920
+ let state = "composer_input_unavailable";
22921
+ let needsAction = "open_new_chat";
22922
+ let message = "Cursor shows an Agent/Chat surface, but no writable input was detected.";
22923
+ if (evidence.signInVisible) {
22924
+ state = "sign_in_required";
22925
+ needsAction = "sign_in_to_cursor";
22926
+ message = "Cursor is showing a sign-in surface instead of a writable Agent/Chat input.";
22927
+ } else if (evidence.settingsOrCustomizeVisible) {
22928
+ state = "settings_or_customize_open";
22929
+ needsAction = "complete_or_close_configuration";
22930
+ message = "Cursor is showing Customize/Settings instead of a writable Agent/Chat input.";
22931
+ } else if (evidence.modalVisible) {
22932
+ state = "modal_dialog_open";
22933
+ needsAction = "complete_or_close_dialog";
22934
+ message = "A visible Cursor dialog is blocking access to the Agent/Chat input.";
22935
+ } else if (evidence.probeError || ["hidden", "prerender", "unloaded"].includes(evidence.visibilityState)) {
22936
+ state = "cursor_window_unavailable";
22937
+ needsAction = "make_cursor_window_available";
22938
+ message = "The selected Cursor page is unavailable or not visible.";
22939
+ } else if (evidence.inputStateChanged) {
22940
+ state = "input_state_changed";
22941
+ needsAction = "open_new_chat";
22942
+ message = "Cursor's Agent/Chat input changed while the request was being prepared.";
22943
+ } else if (!evidence.agentSurfaceVisible && evidence.composerCount === 0) {
22944
+ state = "agent_chat_panel_not_open";
22945
+ needsAction = "open_agent_chat_panel";
22946
+ message = "Cursor's main Agent/Chat panel is not open.";
22947
+ }
22948
+ return {
22949
+ schemaVersion: 1,
22950
+ code: "CURSOR_CHAT_PANEL_UNAVAILABLE",
22951
+ state,
22952
+ message,
22953
+ needsAction,
22954
+ nextStep: CHAT_PANEL_NEXT_STEP,
22955
+ retryable: true,
22956
+ evidence
22957
+ };
22958
+ }
22959
+ function createChatPanelUnavailableError(snapshot) {
22960
+ const uiDiagnostic = classifyChatPanelDiagnostic(snapshot);
22961
+ const error2 = new Error(`${uiDiagnostic.code}: ${uiDiagnostic.message} ${uiDiagnostic.nextStep}`);
22962
+ error2.code = uiDiagnostic.code;
22963
+ error2.uiDiagnostic = uiDiagnostic;
22964
+ return error2;
22947
22965
  }
22966
+ var EXPR_PREPARE_INPUT = `(function(){${INPUT_PICKER_BODY}const inp=pickInput();if(!inp)return 'NO_INPUT';inp.focus();try{const s=getSelection();const r=document.createRange();r.selectNodeContents(inp);s.removeAllRanges();s.addRange(r);}catch(e){}return 'READY';})()`;
22948
22967
  var EXPR_SNAP = `(function(){
22949
22968
  const md=[...document.querySelectorAll('.markdown-root,.aichat-container [class*=markdown]')]
22950
22969
  .filter(e=>e.offsetParent!==null&&!e.closest('.ui-model-picker__trigger,[class*=model-picker]'));
@@ -22955,14 +22974,17 @@ var EXPR_SNAP = `(function(){
22955
22974
  ${INPUT_PICKER_BODY}
22956
22975
  const input=pickInput();
22957
22976
  const inputText=String(input&&(input.innerText||input.textContent)||'').trim();
22958
- return JSON.stringify({messageCount:texts.length,replyLength:last.length,replyHash:hash,stop,inputTextLength:inputText.length});
22977
+ const composer=input&&(input.closest('.composer-bar,.ui-prompt-input,.agent-prompt-input-root')||input.parentElement);
22978
+ const sendButtons=composer?[...composer.querySelectorAll('button.ui-prompt-input-submit-button[data-state="send"],button.ui-prompt-input-submit-button[aria-label="Send message"],button[aria-label="Send"]')]
22979
+ .filter(button=>button.offsetParent!==null&&!button.disabled&&button.closest('.composer-bar,.ui-prompt-input,.agent-prompt-input-root')===composer):[];
22980
+ return JSON.stringify({messageCount:texts.length,replyLength:last.length,replyHash:hash,stop,inputTextLength:inputText.length,sendReady:sendButtons.length===1});
22959
22981
  })()`;
22960
22982
  var EXPR_CLICK_SEND = `(function(){${INPUT_PICKER_BODY}
22961
22983
  const input=pickInput();if(!input)return 'NO_INPUT';
22962
- const composer=input.closest('.composer-bar')||input.parentElement;
22984
+ const composer=input.closest('.composer-bar,.ui-prompt-input,.agent-prompt-input-root')||input.parentElement;
22963
22985
  if(!composer)return 'NO_COMPOSER';
22964
- const buttons=[...composer.querySelectorAll('button.ui-prompt-input-submit-button[data-state="send"],button[aria-label="Send"]')]
22965
- .filter(button=>button.offsetParent!==null&&!button.disabled&&button.closest('.composer-bar')===input.closest('.composer-bar'));
22986
+ const buttons=[...composer.querySelectorAll('button.ui-prompt-input-submit-button[data-state="send"],button.ui-prompt-input-submit-button[aria-label="Send message"],button[aria-label="Send"]')]
22987
+ .filter(button=>button.offsetParent!==null&&!button.disabled&&button.closest('.composer-bar,.ui-prompt-input,.agent-prompt-input-root')===composer);
22966
22988
  if(buttons.length!==1)return buttons.length?'AMBIGUOUS_SEND':'NO_SEND';
22967
22989
  buttons[0].click();return 'CLICKED';
22968
22990
  })()`;
@@ -23080,7 +23102,7 @@ function exprClickBoundComposerStop(agentId) {
23080
23102
  var EXPR_FIND_NEWAGENT = `(function(){const b=[...document.querySelectorAll('button,[role=button],a.action-label,.codicon')].find(e=>{if(e.offsetParent===null||e.closest('.glass-sidebar-agent-menu-btn'))return false;const s=(e.getAttribute('aria-label')||'')+' '+(e.getAttribute('title')||'')+' '+(e.innerText||'');return /(?:^|\\s)New (?:Agent|Chat)(?:\\s|$)/i.test(s);});if(!b)return '';const r=b.getBoundingClientRect();return JSON.stringify({x:Math.round(r.x+r.width/2),y:Math.round(r.y+r.height/2)});})()`;
23081
23103
  var MODEL_PICKER_VISIBLE_BODY = `
23082
23104
  const visible=(node)=>!!(node&&(node.offsetParent!==null||(node.getClientRects&&node.getClientRects().length>0)));
23083
- const composers=[...document.querySelectorAll('.composer-bar[data-composer-id],.composer-bar,.ui-prompt-input-root')].filter(visible);
23105
+ const composers=[...document.querySelectorAll('.composer-bar[data-composer-id],.composer-bar,.ui-prompt-input-root,.agent-prompt-input-root,.ui-prompt-input')].filter(visible);
23084
23106
  const composer=composers[composers.length-1]||document;
23085
23107
  `;
23086
23108
  var EXPR_MODEL_PICKER_TRIGGER = `(function(){
@@ -23136,15 +23158,23 @@ function selectModelPickerRow(rows, requested, kind = "model") {
23136
23158
  const candidates = (Array.isArray(rows) ? rows : []).filter((row) => row && row.disabled !== true && (kind === "any" || row.kind === kind)).map((row) => {
23137
23159
  const normalized = normalizeModelPickerText(row.text);
23138
23160
  let score = normalized === wanted ? 1e3 : 0;
23139
- if (!score && normalized.startsWith(wanted)) score = 800;
23140
- if (!score && wanted.startsWith(normalized)) score = 700;
23141
- if (!score && normalized.includes(wanted)) score = 600;
23161
+ if (kind !== "parameter") {
23162
+ if (!score && normalized.startsWith(wanted)) score = 800;
23163
+ if (!score && wanted.startsWith(normalized)) score = 700;
23164
+ if (!score && normalized.includes(wanted)) score = 600;
23165
+ }
23142
23166
  return { row, score, distance: Math.abs(normalized.length - wanted.length) };
23143
23167
  }).filter((entry) => entry.score > 0).sort((a, b) => b.score - a.score || a.distance - b.distance);
23144
23168
  if (candidates.length === 0) return null;
23145
23169
  if (candidates.length > 1 && candidates[0].score === candidates[1].score && candidates[0].distance === candidates[1].distance) return null;
23146
23170
  return candidates[0].row;
23147
23171
  }
23172
+ function createModelSelectionError(message, failureClass, retryable, diagnostic = {}) {
23173
+ const error2 = new Error(message);
23174
+ error2.code = `CURSOR_MODEL_${String(failureClass || "PROBE_ERROR").toUpperCase()}`;
23175
+ error2.modelSelectionFailure = { failureClass, retryable, ...diagnostic };
23176
+ return error2;
23177
+ }
23148
23178
  var WORKSPACE_SECTION_BODY = `
23149
23179
  const headText=(el)=>String(el&&(el.innerText||el.textContent)||'').trim();
23150
23180
  const isNewAgentButton=(node)=>{
@@ -23398,17 +23428,44 @@ var REACT_ADAPTER_BODY = `
23398
23428
  const a=findAdapter();`;
23399
23429
  var EXPR_AGENT_ADAPTER_READY = `(function(){${REACT_ADAPTER_BODY}return !!a;})()`;
23400
23430
  var EXPR_PAGE_CAPABILITIES = `(function(){${INPUT_PICKER_BODY}
23431
+ const visible=node=>!!(node&&(node.offsetParent!==null||(typeof node.getClientRects==='function'&&node.getClientRects().length>0)));
23432
+ const label=node=>String(node&&(node.getAttribute&&(
23433
+ node.getAttribute('aria-label')||node.getAttribute('title'))||node.innerText||node.textContent)||'').replace(/\\s+/g,' ').trim();
23401
23434
  const input=pickInput();
23435
+ const inputCandidateCount=[...document.querySelectorAll(${JSON.stringify(CURSOR_INPUT_SELECTOR)})].filter(visible).length;
23402
23436
  const hasV2Sidebar=!!document.querySelector('.glass-sidebar-agent-list-container');
23403
23437
  const hasLegacyInput=!!document.querySelector('.aislash-editor-input');
23404
23438
  const hasLegacyHistory=!!document.querySelector('.compact-agent-history-react-menu-label')||
23405
23439
  [...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')||'')));
23440
+ const dialogs=[...document.querySelectorAll('[role="dialog"],dialog[open],.monaco-dialog-box,.quick-input-widget')].filter(visible);
23441
+ const dialog=dialogs[dialogs.length-1]||null;
23442
+ const dialogHeading=dialog&&dialog.querySelector('h1,h2,h3,[role="heading"]');
23443
+ const dialogLabel=dialog?String(dialog.getAttribute('aria-label')||dialog.getAttribute('title')||label(dialogHeading)||'').slice(0,120):null;
23444
+ const pageTitle=String(document.title||'').replace(/\\s+/g,' ').trim();
23445
+ const pagePath=String(globalThis.location&&globalThis.location.pathname||'');
23446
+ const headings=[...document.querySelectorAll('h1,h2,h3,[role="heading"]')]
23447
+ .filter(node=>visible(node)&&!node.closest('.markdown-root,.composer-messages-container,.composer-react-transcript-root,.aichat-container'))
23448
+ .map(label).filter(Boolean).slice(0,40);
23449
+ const configurationText=[pageTitle,pagePath,...headings,label(dialogHeading)].join(' ');
23450
+ const configurationSelector='.ui-customize-view,.settings-editor,.settings-body,.preferences-editor,[class*="settings-editor"],[class*="preferences-editor"],[data-testid*="customize"]';
23451
+ const settingsOrCustomizeVisible=[...document.querySelectorAll(configurationSelector)].some(visible)||/(?:settings?|customize|preferences|\u8BBE\u7F6E|\u8A2D\u5B9A|\u81EA\u5B9A\u4E49|\u81EA\u8A02)/i.test(configurationText);
23452
+ const authControls=[...document.querySelectorAll('button,a,[role="button"],[role="link"]')]
23453
+ .filter(node=>visible(node)&&!node.closest('.markdown-root,.composer-messages-container,.composer-react-transcript-root'));
23454
+ const signInPattern=/(?:sign|log)\\s*in(?:\\s+to\\s+cursor)?|authenticate(?:\\s+cursor)?|continue with (?:google|github|email|sso)|\u767B\u5F55|\u767B\u5165/i;
23455
+ const signInControlVisible=authControls.some(node=>signInPattern.test(label(node)));
23456
+ const signInVisible=authControls.some(node=>signInPattern.test(label(node))&&!node.closest(configurationSelector));
23457
+ const composerCount=[...document.querySelectorAll('.composer-bar[data-composer-id],.composer-bar,.ui-prompt-input-root')].filter(visible).length;
23458
+ const agentSurfaceVisible=composerCount>0||[...document.querySelectorAll('.glass-sidebar-agent-list-container,.compact-agent-history-react-menu-label,.aichat-container')].some(visible)||authControls.some(node=>/(?:New (?:Agent|Chat)|(?:Chat|Agent) History)/i.test(label(node)));
23406
23459
  const uiFlavor=hasV2Sidebar||(input&&input.classList&&input.classList.contains('ui-prompt-input-editor__input'))?'agents_v2':hasLegacyInput?'legacy':'unknown';
23407
23460
  return JSON.stringify({
23408
- hasWritableInput:!!input,uiFlavor,
23461
+ hasWritableInput:!!input,inputCandidateCount,uiFlavor,
23409
23462
  agentAdapterKind:hasV2Sidebar?'agents_v2':hasLegacyHistory?'legacy':'none',
23410
23463
  hasComposer:!!document.querySelector('.composer-bar[data-composer-id]'),
23411
- visible:document.visibilityState==='visible',focused:typeof document.hasFocus==='function'&&document.hasFocus(),documentTitle:String(document.title||'')
23464
+ modalVisible:!!dialog,modalLabel:dialogLabel,
23465
+ settingsOrCustomizeVisible,signInControlVisible,signInVisible,agentSurfaceVisible,composerCount,
23466
+ visibilityState:String(document.visibilityState||'unknown'),
23467
+ visible:document.visibilityState==='visible',focused:typeof document.hasFocus==='function'&&document.hasFocus(),
23468
+ documentTitle:pageTitle,pageTitle:pageTitle.slice(0,160)
23412
23469
  });
23413
23470
  })()`;
23414
23471
  var EXPR_HISTORY_ENTRIES = `(function(){${REACT_ADAPTER_BODY}
@@ -23826,6 +23883,7 @@ var CursorBridge = class {
23826
23883
  status: outcome,
23827
23884
  finishedAt: job.finishedAt || now,
23828
23885
  error: job.error || null,
23886
+ uiDiagnostic: job.uiDiagnostic || null,
23829
23887
  terminalEvidence: job.terminalEvidence || null,
23830
23888
  resultUnavailable: job.resultUnavailable === true
23831
23889
  };
@@ -24426,6 +24484,7 @@ var CursorBridge = class {
24426
24484
  resultUnavailable: false,
24427
24485
  terminalEvidence: null,
24428
24486
  providerError: null,
24487
+ uiDiagnostic: null,
24429
24488
  sendState: "not_sent",
24430
24489
  reservationScope: null,
24431
24490
  controlTail: Promise.resolve(),
@@ -24460,6 +24519,7 @@ var CursorBridge = class {
24460
24519
  const e = error2 instanceof Error ? error2 : new Error(String(error2));
24461
24520
  job.error = e.message;
24462
24521
  if (e.providerError) job.providerError = e.providerError;
24522
+ if (e.uiDiagnostic) job.uiDiagnostic = e.uiDiagnostic;
24463
24523
  if (e.terminalEvidence) job.terminalEvidence = e.terminalEvidence;
24464
24524
  job.status = "failed";
24465
24525
  job.phase = "failed";
@@ -24769,7 +24829,8 @@ var CursorBridge = class {
24769
24829
  this._throwIfCancelledBeforeSend(options);
24770
24830
  await this._applyModelPreference(c, options.modelPreference, options);
24771
24831
  this._throwIfCancelledBeforeSend(options);
24772
- const filled = await evalJS(c, exprFill(prompt));
24832
+ const filled = await this._fillPrompt(c, prompt, options);
24833
+ if (filled === "NO_INPUT") await this._throwChatPanelUnavailableAfterNoInput(c);
24773
24834
  if (filled === "NO_INPUT" || filled === "EXEC_FAIL") throw new Error("Failed to enter the query because the input state was invalid");
24774
24835
  await sleep2(450);
24775
24836
  this._throwIfCancelledBeforeSend(options);
@@ -24888,25 +24949,83 @@ var CursorBridge = class {
24888
24949
  modelRow = selectModelPickerRow(expanded && expanded.rows, requestedModel, "model");
24889
24950
  return { snapshot: expanded, modelRow };
24890
24951
  }
24891
- async _selectedEffortRow(c, modelRow, effort) {
24892
- let snapshot = await this._readModelPickerRows(c);
24893
- let effortRow = selectModelPickerRow(snapshot.rows, cursorEffortUiValue(effort), "parameter");
24894
- if (!effortRow) {
24895
- snapshot = await this._openModelPickerControl(c, snapshot, "effort_control");
24896
- effortRow = selectModelPickerRow(snapshot.rows, cursorEffortUiValue(effort), "parameter");
24952
+ _inspectModelPickerRows(snapshot, requested, kind) {
24953
+ const rows = (snapshot && Array.isArray(snapshot.rows) ? snapshot.rows : []).filter((row) => row && row.disabled !== true && row.kind === kind);
24954
+ const wanted = normalizeModelPickerText(requested);
24955
+ const exact = rows.filter((row) => normalizeModelPickerText(row.text) === wanted);
24956
+ return {
24957
+ snapshot,
24958
+ row: exact.length === 1 ? exact[0] : null,
24959
+ ambiguous: exact.length > 1,
24960
+ available: rows.map((row) => row.text)
24961
+ };
24962
+ }
24963
+ async _waitForModelPickerMatch(c, requested, kind, job, options = {}) {
24964
+ const timeoutMs = Math.max(0, Number(options.timeoutMs ?? 700));
24965
+ const pollMs = Math.max(10, Number(options.pollMs ?? 100));
24966
+ const stableMs = Math.max(0, Number(options.stableMs ?? 250));
24967
+ const deadline = Date.now() + timeoutMs;
24968
+ let stableSignature = null;
24969
+ let stableSince = 0;
24970
+ let last = this._inspectModelPickerRows({ open: false, rows: [] }, requested, kind);
24971
+ do {
24972
+ this._throwIfCancelledBeforeSend(job);
24973
+ last = this._inspectModelPickerRows(await this._readModelPickerRows(c), requested, kind);
24974
+ if (last.row) return { ...last, state: "matched" };
24975
+ const signature = JSON.stringify(last.available);
24976
+ if (last.available.length > 0) {
24977
+ if (signature !== stableSignature) {
24978
+ stableSignature = signature;
24979
+ stableSince = Date.now();
24980
+ } else if (Date.now() - stableSince >= stableMs) {
24981
+ return { ...last, state: last.ambiguous ? "ambiguous" : "unsupported" };
24982
+ }
24983
+ } else {
24984
+ stableSignature = null;
24985
+ stableSince = 0;
24986
+ }
24987
+ if (Date.now() >= deadline) break;
24988
+ await sleep2(Math.min(pollMs, Math.max(0, deadline - Date.now())));
24989
+ } while (Date.now() <= deadline);
24990
+ return { ...last, state: last.ambiguous ? "ambiguous" : "not_rendered" };
24991
+ }
24992
+ async _selectedEffortRow(c, modelRow, effort, job) {
24993
+ const requested = cursorEffortUiValue(effort);
24994
+ const snapshot = await this._readModelPickerRows(c);
24995
+ const immediate = this._inspectModelPickerRows(snapshot, requested, "parameter");
24996
+ if (immediate.row) return { ...immediate, state: "matched", attempts: ["visible"] };
24997
+ const attempts = [];
24998
+ const effortControl = (snapshot.rows || []).find((row) => row.kind === "effort_control" && row.disabled !== true);
24999
+ if (effortControl) {
25000
+ this._throwIfCancelledBeforeSend(job);
25001
+ attempts.push("effort_control");
25002
+ await this._clickModelPickerPoint(c, effortControl);
25003
+ const result2 = await this._waitForModelPickerMatch(c, requested, "parameter", job, { timeoutMs: 700 });
25004
+ if (result2.state !== "not_rendered") return { ...result2, attempts };
24897
25005
  }
24898
- if (effortRow) return effortRow;
25006
+ this._throwIfCancelledBeforeSend(job);
25007
+ attempts.push("model_hover");
24899
25008
  await this._hoverModelPickerPoint(c, modelRow);
24900
- await sleep2(400);
24901
- snapshot = await this._readModelPickerRows(c);
24902
- effortRow = selectModelPickerRow(snapshot.rows, cursorEffortUiValue(effort), "parameter");
24903
- if (!effortRow && modelRow && modelRow.hasSubmenu) {
25009
+ let result = await this._waitForModelPickerMatch(c, requested, "parameter", job, { timeoutMs: 700 });
25010
+ if (result.state !== "not_rendered") return { ...result, attempts };
25011
+ if (modelRow && modelRow.hasSubmenu) {
25012
+ this._throwIfCancelledBeforeSend(job);
25013
+ attempts.push("model_click");
24904
25014
  await this._clickModelPickerPoint(c, modelRow);
24905
- await sleep2(350);
24906
- snapshot = await this._readModelPickerRows(c);
24907
- effortRow = selectModelPickerRow(snapshot.rows, cursorEffortUiValue(effort), "parameter");
25015
+ result = await this._waitForModelPickerMatch(c, requested, "parameter", job, { timeoutMs: 1100 });
24908
25016
  }
24909
- return effortRow;
25017
+ return { ...result, attempts };
25018
+ }
25019
+ async _waitForSelectedModelPickerRow(c, requested, kind, job, timeoutMs = 1500) {
25020
+ const deadline = Date.now() + timeoutMs;
25021
+ do {
25022
+ this._throwIfCancelledBeforeSend(job);
25023
+ const inspected = this._inspectModelPickerRows(await this._readModelPickerRows(c), requested, kind);
25024
+ if (inspected.row && inspected.row.selected) return inspected.row;
25025
+ if (Date.now() >= deadline) break;
25026
+ await sleep2(Math.min(100, Math.max(0, deadline - Date.now())));
25027
+ } while (Date.now() <= deadline);
25028
+ return null;
24910
25029
  }
24911
25030
  async _applyModelPreference(c, preference, job) {
24912
25031
  if (!preference) {
@@ -24915,63 +25034,167 @@ var CursorBridge = class {
24915
25034
  }
24916
25035
  const requestedModel = String(preference.model || "").trim();
24917
25036
  const requestedEffort = preference.effort ? normalizeCursorModelEffort(preference.effort, "") : null;
24918
- const opened = await this._openModelPicker(c);
24919
- let located = await this._findModelPickerModel(c, opened, requestedModel);
24920
- let modelRow = located.modelRow;
24921
- if (!modelRow) {
24922
- throw new Error(`Configured Cursor model is unavailable or ambiguous: ${requestedModel}`);
24923
- }
24924
- let selectedEffortRow = null;
24925
- if (requestedEffort && modelRow.hasSubmenu) {
24926
- selectedEffortRow = await this._selectedEffortRow(c, modelRow, requestedEffort);
24927
- if (!selectedEffortRow) {
24928
- throw new Error(`Cursor model ${requestedModel} does not expose effort ${requestedEffort}`);
24929
- }
24930
- if (!selectedEffortRow.selected || !modelRow.selected) {
24931
- await this._clickModelPickerPoint(c, selectedEffortRow);
24932
- await sleep2(550);
24933
- }
24934
- } else if (!modelRow.selected) {
24935
- await this._clickModelPickerPoint(c, modelRow);
24936
- await sleep2(550);
24937
- }
24938
- let trigger = await this._readModelPickerTrigger(c);
24939
- if (!trigger.found || !normalizeModelPickerText(trigger.text).includes(normalizeModelPickerText(requestedModel))) {
24940
- const reopened = await this._openModelPicker(c);
24941
- located = await this._findModelPickerModel(c, reopened, requestedModel);
24942
- const selected = selectModelPickerRow(located.snapshot.rows.filter((row) => row.selected), requestedModel, "model");
24943
- if (!selected) throw new Error(`Cursor did not confirm configured model ${requestedModel}`);
24944
- modelRow = selected;
24945
- }
25037
+ let modelRow = null;
24946
25038
  let effectiveEffort = null;
24947
- if (requestedEffort) {
24948
- const reopened = await this._openModelPicker(c);
24949
- located = await this._findModelPickerModel(c, reopened, requestedModel);
25039
+ let primaryError = null;
25040
+ try {
25041
+ const opened = await this._openModelPicker(c);
25042
+ let located = await this._findModelPickerModel(c, opened, requestedModel);
24950
25043
  modelRow = located.modelRow;
24951
- if (!modelRow) throw new Error(`Cursor model row disappeared while applying effort: ${requestedModel}`);
24952
- let effortRow = await this._selectedEffortRow(c, modelRow, requestedEffort);
24953
- if (!effortRow) {
24954
- throw new Error(`Cursor model ${requestedModel} does not expose effort ${requestedEffort}`);
25044
+ if (!modelRow) {
25045
+ throw createModelSelectionError(
25046
+ `Configured Cursor model is unavailable or ambiguous: ${requestedModel}`,
25047
+ "model_unavailable",
25048
+ false,
25049
+ { available: (located.snapshot.rows || []).filter((row) => row.kind === "model").map((row) => row.text) }
25050
+ );
24955
25051
  }
24956
- if (!effortRow.selected) {
24957
- await this._clickModelPickerPoint(c, effortRow);
24958
- await sleep2(450);
25052
+ let effortPickerReopened = false;
25053
+ const resolveEffort = async () => {
25054
+ let outcome = await this._selectedEffortRow(c, modelRow, requestedEffort, job);
25055
+ if (!outcome.row && outcome.state === "not_rendered" && !effortPickerReopened) {
25056
+ effortPickerReopened = true;
25057
+ await this._closeModelPicker(c);
25058
+ const reopened = await this._openModelPicker(c);
25059
+ located = await this._findModelPickerModel(c, reopened, requestedModel);
25060
+ modelRow = located.modelRow;
25061
+ if (!modelRow) {
25062
+ throw createModelSelectionError(
25063
+ `Cursor model row disappeared while applying effort: ${requestedModel}`,
25064
+ "model_unavailable",
25065
+ true
25066
+ );
25067
+ }
25068
+ outcome = await this._selectedEffortRow(c, modelRow, requestedEffort, job);
25069
+ outcome.attempts = ["picker_reopen", ...outcome.attempts || []];
25070
+ }
25071
+ return outcome;
25072
+ };
25073
+ const throwEffortFailure = (outcome) => {
25074
+ const failureClass = outcome.state === "ambiguous" ? "effort_ambiguous" : outcome.state === "unsupported" ? "effort_unsupported" : "effort_menu_not_rendered";
25075
+ const message = failureClass === "effort_menu_not_rendered" ? `Cursor effort menu did not render for model ${requestedModel}` : failureClass === "effort_ambiguous" ? `Cursor model ${requestedModel} exposes ambiguous effort ${requestedEffort}` : `Cursor model ${requestedModel} does not expose effort ${requestedEffort}`;
25076
+ throw createModelSelectionError(
25077
+ message,
25078
+ failureClass,
25079
+ failureClass === "effort_menu_not_rendered",
25080
+ { available: outcome.available || [], attempts: outcome.attempts || [] }
25081
+ );
25082
+ };
25083
+ if (requestedEffort && modelRow.hasSubmenu) {
25084
+ const selectedEffort = await resolveEffort();
25085
+ if (!selectedEffort.row) throwEffortFailure(selectedEffort);
25086
+ if (!selectedEffort.row.selected || !modelRow.selected) {
25087
+ this._throwIfCancelledBeforeSend(job);
25088
+ await this._clickModelPickerPoint(c, selectedEffort.row);
25089
+ await sleep2(550);
25090
+ }
25091
+ } else if (!modelRow.selected) {
25092
+ this._throwIfCancelledBeforeSend(job);
25093
+ await this._clickModelPickerPoint(c, modelRow);
25094
+ await sleep2(550);
24959
25095
  }
24960
- trigger = await this._readModelPickerTrigger(c);
24961
- const detailMatches = normalizeModelPickerText(`${trigger.detail || ""} ${trigger.text || ""}`).includes(normalizeModelPickerText(requestedEffort));
24962
- if (!detailMatches) {
24963
- const verify = await this._openModelPicker(c);
24964
- const verifiedModel = await this._findModelPickerModel(c, verify, requestedModel);
24965
- const selectedModel = verifiedModel.modelRow;
24966
- effortRow = await this._selectedEffortRow(c, selectedModel, requestedEffort);
25096
+ let trigger2 = await this._readModelPickerTrigger(c);
25097
+ if (!trigger2.found || !normalizeModelPickerText(trigger2.text).includes(normalizeModelPickerText(requestedModel))) {
25098
+ const reopened = await this._openModelPicker(c);
25099
+ located = await this._findModelPickerModel(c, reopened, requestedModel);
25100
+ const selected = selectModelPickerRow(located.snapshot.rows.filter((row) => row.selected), requestedModel, "model");
25101
+ if (!selected) {
25102
+ throw createModelSelectionError(
25103
+ `Cursor did not confirm configured model ${requestedModel}`,
25104
+ "model_not_confirmed",
25105
+ true
25106
+ );
25107
+ }
25108
+ modelRow = selected;
25109
+ }
25110
+ if (requestedEffort) {
25111
+ const reopened = await this._openModelPicker(c);
25112
+ located = await this._findModelPickerModel(c, reopened, requestedModel);
25113
+ modelRow = located.modelRow;
25114
+ if (!modelRow) {
25115
+ throw createModelSelectionError(
25116
+ `Cursor model row disappeared while applying effort: ${requestedModel}`,
25117
+ "model_unavailable",
25118
+ true
25119
+ );
25120
+ }
25121
+ const effortOutcome = await resolveEffort();
25122
+ if (!effortOutcome.row) throwEffortFailure(effortOutcome);
25123
+ let effortRow = effortOutcome.row;
25124
+ if (!effortRow.selected) {
25125
+ effortRow = await this._waitForSelectedModelPickerRow(
25126
+ c,
25127
+ cursorEffortUiValue(requestedEffort),
25128
+ "parameter",
25129
+ job
25130
+ );
25131
+ }
24967
25132
  if (!effortRow || !effortRow.selected) {
24968
- throw new Error(`Cursor did not confirm effort ${requestedEffort} for model ${requestedModel}`);
25133
+ throw createModelSelectionError(
25134
+ `Cursor did not confirm effort ${requestedEffort} for model ${requestedModel}`,
25135
+ "effort_not_confirmed",
25136
+ true
25137
+ );
25138
+ }
25139
+ effectiveEffort = requestedEffort;
25140
+ }
25141
+ } catch (error2) {
25142
+ primaryError = error2 instanceof Error ? error2 : new Error(String(error2));
25143
+ let failure = primaryError.modelSelectionFailure;
25144
+ if (!failure) {
25145
+ const pickerUnavailable = /model picker (?:is unavailable|did not open)/i.test(primaryError.message);
25146
+ failure = {
25147
+ failureClass: pickerUnavailable ? "picker_did_not_open" : "probe_error",
25148
+ retryable: true
25149
+ };
25150
+ }
25151
+ const diagnostic = {
25152
+ configured: true,
25153
+ applied: false,
25154
+ requestedModel,
25155
+ requestedEffort,
25156
+ failureClass: failure.failureClass,
25157
+ retryable: failure.retryable === true,
25158
+ errorCode: primaryError.code || `CURSOR_MODEL_${String(failure.failureClass).toUpperCase()}`,
25159
+ available: failure.available || [],
25160
+ attempts: failure.attempts || [],
25161
+ runtimeMode: this.runtimeMode,
25162
+ lastError: primaryError.message,
25163
+ failedAt: (/* @__PURE__ */ new Date()).toISOString()
25164
+ };
25165
+ primaryError.modelSelection = diagnostic;
25166
+ if (job) job.modelSelection = diagnostic;
25167
+ throw primaryError;
25168
+ } finally {
25169
+ try {
25170
+ await this._closeModelPicker(c);
25171
+ } catch (cleanupError) {
25172
+ const message = cleanupError instanceof Error ? cleanupError.message : String(cleanupError);
25173
+ if (!primaryError) {
25174
+ const error2 = createModelSelectionError(message, "picker_cleanup_failed", true);
25175
+ const diagnostic = {
25176
+ configured: true,
25177
+ applied: false,
25178
+ requestedModel,
25179
+ requestedEffort,
25180
+ failureClass: "picker_cleanup_failed",
25181
+ retryable: true,
25182
+ errorCode: error2.code,
25183
+ available: [],
25184
+ attempts: [],
25185
+ runtimeMode: this.runtimeMode,
25186
+ lastError: message,
25187
+ failedAt: (/* @__PURE__ */ new Date()).toISOString()
25188
+ };
25189
+ error2.modelSelection = diagnostic;
25190
+ if (job) job.modelSelection = diagnostic;
25191
+ throw error2;
24969
25192
  }
25193
+ if (primaryError.modelSelection) primaryError.modelSelection.cleanupError = message;
25194
+ if (job && job.modelSelection) job.modelSelection.cleanupError = message;
24970
25195
  }
24971
- effectiveEffort = requestedEffort;
24972
25196
  }
24973
- await this._closeModelPicker(c);
24974
- trigger = await this._readModelPickerTrigger(c);
25197
+ const trigger = await this._readModelPickerTrigger(c);
24975
25198
  const result = {
24976
25199
  configured: true,
24977
25200
  applied: true,
@@ -24985,19 +25208,24 @@ var CursorBridge = class {
24985
25208
  if (job) job.modelSelection = result;
24986
25209
  return result;
24987
25210
  }
24988
- async _ensureChatPanel(c) {
24989
- let vis = await evalJS(c, EXPR_VISIBLE);
24990
- if (!vis) {
24991
- await chord(c, 2, "L", "KeyL", 76);
24992
- await sleep2(1300);
24993
- vis = await evalJS(c, EXPR_VISIBLE);
24994
- }
24995
- if (!vis) {
24996
- await chord(c, 2, "I", "KeyI", 73);
24997
- await sleep2(1300);
24998
- vis = await evalJS(c, EXPR_VISIBLE);
25211
+ async _readChatPanelDiagnostic(c) {
25212
+ try {
25213
+ return JSON.parse(await evalJS(c, EXPR_PAGE_CAPABILITIES) || "{}");
25214
+ } catch (error2) {
25215
+ return { probeError: error2 instanceof Error ? error2.message : String(error2) };
24999
25216
  }
25000
- 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.");
25217
+ }
25218
+ async _ensureChatPanel(c) {
25219
+ const snapshot = await this._readChatPanelDiagnostic(c);
25220
+ if (snapshot.modalVisible !== true && snapshot.hasWritableInput === true) return snapshot;
25221
+ throw createChatPanelUnavailableError(snapshot);
25222
+ }
25223
+ async _throwChatPanelUnavailableAfterNoInput(c) {
25224
+ const snapshot = await this._readChatPanelDiagnostic(c);
25225
+ throw createChatPanelUnavailableError({
25226
+ ...snapshot,
25227
+ inputStateChanged: snapshot.hasWritableInput === true
25228
+ });
25001
25229
  }
25002
25230
  // 清空对话上下文:定位 "New Agent" 钮后【Alt+click】——Alt 修饰使其执行 Replace Agent(清空旧对话),
25003
25231
  // 而非新建(aria 标注 "New Agent (Ctrl+N) / [Alt] Replace Agent")。2026-06-08 实测回复区 markdown DOM 清空
@@ -25145,6 +25373,38 @@ var CursorBridge = class {
25145
25373
  }
25146
25374
  }
25147
25375
  }
25376
+ async _fillPrompt(c, text, job, timeoutMs = 2500) {
25377
+ const prepared = await evalJS(c, EXPR_PREPARE_INPUT);
25378
+ if (prepared !== "READY") return prepared;
25379
+ try {
25380
+ await c.send("Input.insertText", { text: String(text) });
25381
+ } catch {
25382
+ return "EXEC_FAIL";
25383
+ }
25384
+ const deadline = Date.now() + timeoutMs;
25385
+ let snapshot = {};
25386
+ do {
25387
+ this._throwIfCancelledBeforeSend(job);
25388
+ try {
25389
+ snapshot = JSON.parse(await evalJS(c, EXPR_SNAP));
25390
+ } catch {
25391
+ }
25392
+ if (Number(snapshot.inputTextLength || 0) > 0 && snapshot.sendReady === true) {
25393
+ return String(text).slice(0, 30);
25394
+ }
25395
+ if (Date.now() >= deadline) break;
25396
+ await sleep2(Math.min(100, Math.max(0, deadline - Date.now())));
25397
+ } while (Date.now() <= deadline);
25398
+ const error2 = new Error("Cursor composer did not become send-ready after trusted input");
25399
+ error2.code = "CURSOR_COMPOSER_NOT_SEND_READY";
25400
+ error2.confirmedNotSent = true;
25401
+ error2.composerDiagnostic = {
25402
+ inputTextLength: Number(snapshot.inputTextLength || 0),
25403
+ sendReady: snapshot.sendReady === true,
25404
+ runtimeMode: this.runtimeMode
25405
+ };
25406
+ throw error2;
25407
+ }
25148
25408
  async _confirmSubmission(c, baselineCount = 0, providerErrorBaseline = "") {
25149
25409
  const accepted = async () => {
25150
25410
  await this._throwIfNewProviderError(c, providerErrorBaseline);
@@ -25234,7 +25494,8 @@ var CursorBridge = class {
25234
25494
  this._throwIfCancelledBeforeSend(job);
25235
25495
  await this._applyModelPreference(c, job.modelPreference, job);
25236
25496
  this._throwIfCancelledBeforeSend(job);
25237
- const filled = await evalJS(c, exprFill(job.prompt));
25497
+ const filled = await this._fillPrompt(c, job.prompt, job);
25498
+ if (filled === "NO_INPUT") await this._throwChatPanelUnavailableAfterNoInput(c);
25238
25499
  if (filled === "NO_INPUT" || filled === "EXEC_FAIL") throw new Error("Failed to enter the parallel_agent task");
25239
25500
  await sleep2(350);
25240
25501
  this._throwIfCancelledBeforeSend(job);
@@ -25353,7 +25614,8 @@ var CursorBridge = class {
25353
25614
  this._throwIfCancelledBeforeSend(job);
25354
25615
  job.responseBaseline = await this._captureSessionResponseBaseline(c);
25355
25616
  const providerErrorBaseline = providerErrorSignature(await this._readProviderError(c));
25356
- const filled = await evalJS(c, exprFill(job.prompt));
25617
+ const filled = await this._fillPrompt(c, job.prompt, job);
25618
+ if (filled === "NO_INPUT") await this._throwChatPanelUnavailableAfterNoInput(c);
25357
25619
  if (filled === "NO_INPUT" || filled === "EXEC_FAIL") {
25358
25620
  throw cursorSessionError("SESSION_INPUT_FAILED", "failed to enter the continued task");
25359
25621
  }
@@ -26197,6 +26459,7 @@ var CursorBridge = class {
26197
26459
  resultUnavailable: job.resultUnavailable,
26198
26460
  terminalEvidence: job.terminalEvidence,
26199
26461
  providerError: job.providerError,
26462
+ uiDiagnostic: job.uiDiagnostic,
26200
26463
  sendState: job.sendState,
26201
26464
  reservationScope: job.reservationScope,
26202
26465
  reservationHeld: this.activeParallel.has(job.id),
@@ -26412,6 +26675,21 @@ async function ensureBridgeCursor(targetBridge, reason) {
26412
26675
  }
26413
26676
  return r;
26414
26677
  }
26678
+ function toolErrorResult(error2) {
26679
+ const message = error2 instanceof Error ? error2.message : String(error2);
26680
+ if (error2 && error2.uiDiagnostic) {
26681
+ const payload = {
26682
+ error: { code: error2.code || error2.uiDiagnostic.code || "CURSOR_BRIDGE_ERROR", message },
26683
+ uiDiagnostic: error2.uiDiagnostic
26684
+ };
26685
+ return {
26686
+ content: [{ type: "text", text: JSON.stringify(payload, null, 2) }],
26687
+ structuredContent: payload,
26688
+ isError: true
26689
+ };
26690
+ }
26691
+ return { content: [{ type: "text", text: `Error: ${message}` }], isError: true };
26692
+ }
26415
26693
  server.setRequestHandler(ListToolsRequestSchema, async () => ({
26416
26694
  tools: buildToolDefinitions(bridge)
26417
26695
  }));
@@ -26513,7 +26791,7 @@ server.setRequestHandler(CallToolRequestSchema, async (request2) => {
26513
26791
  }
26514
26792
  throw new Error(`Unknown tool: ${name}`);
26515
26793
  } catch (error2) {
26516
- return { content: [{ type: "text", text: `Error: ${error2 instanceof Error ? error2.message : String(error2)}` }], isError: true };
26794
+ return toolErrorResult(error2);
26517
26795
  }
26518
26796
  });
26519
26797
  async function main() {
@@ -26553,6 +26831,7 @@ export {
26553
26831
  EXPR_MODEL_PICKER_ROWS,
26554
26832
  EXPR_MODEL_PICKER_TRIGGER,
26555
26833
  EXPR_PAGE_CAPABILITIES,
26834
+ EXPR_PREPARE_INPUT,
26556
26835
  EXPR_PROVIDER_ERROR,
26557
26836
  EXPR_VISIBLE,
26558
26837
  EXPR_VISIBLE_COMPOSER,
@@ -26560,16 +26839,16 @@ export {
26560
26839
  bridge,
26561
26840
  buildContextEnginePrompt,
26562
26841
  buildToolDefinitions,
26842
+ classifyChatPanelDiagnostic,
26563
26843
  classifyParallelTerminalIcon,
26844
+ createChatPanelUnavailableError,
26564
26845
  createProviderError,
26565
26846
  cursorStartupBehavior,
26566
26847
  exprClickBoundComposerStop,
26567
26848
  exprClickSelectedAgentStop,
26568
26849
  exprCreateAgentForWorkspace,
26569
- exprFill,
26570
26850
  exprInspectWorkspaceRepository,
26571
26851
  exprOpenAgent,
26572
- isBlankAgentsWindow,
26573
26852
  isConfirmedCompletedReply,
26574
26853
  isDurablyRegisteredParallelEntry,
26575
26854
  isSessionTurnReplyReady,
@@ -26597,6 +26876,7 @@ export {
26597
26876
  shouldRecoverNormalAgentsPresentation,
26598
26877
  shouldScheduleParallelOriginRestore,
26599
26878
  summarizeCdpPages,
26879
+ toolErrorResult,
26600
26880
  uncertainSubmissionReservationScope,
26601
26881
  updateStableEntryObservation
26602
26882
  };
@@ -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.10",
13
+ packageVersion: "0.1.12",
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.10",
3
+ "version": "0.1.12",
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.8.0"
50
+ "embeddedProductVersion": "5.8.2"
51
51
  }
52
52
  }