pi-cursor-bridge 0.1.11 → 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.1+codex.20260903121439",
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
@@ -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.8.1. 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.
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)
@@ -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.1";
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);
@@ -22963,10 +22963,7 @@ function createChatPanelUnavailableError(snapshot) {
22963
22963
  error2.uiDiagnostic = uiDiagnostic;
22964
22964
  return error2;
22965
22965
  }
22966
- function exprFill(text) {
22967
- const js = JSON.stringify(text);
22968
- 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';})()`;
22969
- }
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';})()`;
22970
22967
  var EXPR_SNAP = `(function(){
22971
22968
  const md=[...document.querySelectorAll('.markdown-root,.aichat-container [class*=markdown]')]
22972
22969
  .filter(e=>e.offsetParent!==null&&!e.closest('.ui-model-picker__trigger,[class*=model-picker]'));
@@ -22977,14 +22974,17 @@ var EXPR_SNAP = `(function(){
22977
22974
  ${INPUT_PICKER_BODY}
22978
22975
  const input=pickInput();
22979
22976
  const inputText=String(input&&(input.innerText||input.textContent)||'').trim();
22980
- 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});
22981
22981
  })()`;
22982
22982
  var EXPR_CLICK_SEND = `(function(){${INPUT_PICKER_BODY}
22983
22983
  const input=pickInput();if(!input)return 'NO_INPUT';
22984
- const composer=input.closest('.composer-bar')||input.parentElement;
22984
+ const composer=input.closest('.composer-bar,.ui-prompt-input,.agent-prompt-input-root')||input.parentElement;
22985
22985
  if(!composer)return 'NO_COMPOSER';
22986
- const buttons=[...composer.querySelectorAll('button.ui-prompt-input-submit-button[data-state="send"],button[aria-label="Send"]')]
22987
- .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);
22988
22988
  if(buttons.length!==1)return buttons.length?'AMBIGUOUS_SEND':'NO_SEND';
22989
22989
  buttons[0].click();return 'CLICKED';
22990
22990
  })()`;
@@ -23102,7 +23102,7 @@ function exprClickBoundComposerStop(agentId) {
23102
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)});})()`;
23103
23103
  var MODEL_PICKER_VISIBLE_BODY = `
23104
23104
  const visible=(node)=>!!(node&&(node.offsetParent!==null||(node.getClientRects&&node.getClientRects().length>0)));
23105
- 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);
23106
23106
  const composer=composers[composers.length-1]||document;
23107
23107
  `;
23108
23108
  var EXPR_MODEL_PICKER_TRIGGER = `(function(){
@@ -23158,15 +23158,23 @@ function selectModelPickerRow(rows, requested, kind = "model") {
23158
23158
  const candidates = (Array.isArray(rows) ? rows : []).filter((row) => row && row.disabled !== true && (kind === "any" || row.kind === kind)).map((row) => {
23159
23159
  const normalized = normalizeModelPickerText(row.text);
23160
23160
  let score = normalized === wanted ? 1e3 : 0;
23161
- if (!score && normalized.startsWith(wanted)) score = 800;
23162
- if (!score && wanted.startsWith(normalized)) score = 700;
23163
- 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
+ }
23164
23166
  return { row, score, distance: Math.abs(normalized.length - wanted.length) };
23165
23167
  }).filter((entry) => entry.score > 0).sort((a, b) => b.score - a.score || a.distance - b.distance);
23166
23168
  if (candidates.length === 0) return null;
23167
23169
  if (candidates.length > 1 && candidates[0].score === candidates[1].score && candidates[0].distance === candidates[1].distance) return null;
23168
23170
  return candidates[0].row;
23169
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
+ }
23170
23178
  var WORKSPACE_SECTION_BODY = `
23171
23179
  const headText=(el)=>String(el&&(el.innerText||el.textContent)||'').trim();
23172
23180
  const isNewAgentButton=(node)=>{
@@ -24821,7 +24829,7 @@ var CursorBridge = class {
24821
24829
  this._throwIfCancelledBeforeSend(options);
24822
24830
  await this._applyModelPreference(c, options.modelPreference, options);
24823
24831
  this._throwIfCancelledBeforeSend(options);
24824
- const filled = await evalJS(c, exprFill(prompt));
24832
+ const filled = await this._fillPrompt(c, prompt, options);
24825
24833
  if (filled === "NO_INPUT") await this._throwChatPanelUnavailableAfterNoInput(c);
24826
24834
  if (filled === "NO_INPUT" || filled === "EXEC_FAIL") throw new Error("Failed to enter the query because the input state was invalid");
24827
24835
  await sleep2(450);
@@ -24941,25 +24949,83 @@ var CursorBridge = class {
24941
24949
  modelRow = selectModelPickerRow(expanded && expanded.rows, requestedModel, "model");
24942
24950
  return { snapshot: expanded, modelRow };
24943
24951
  }
24944
- async _selectedEffortRow(c, modelRow, effort) {
24945
- let snapshot = await this._readModelPickerRows(c);
24946
- let effortRow = selectModelPickerRow(snapshot.rows, cursorEffortUiValue(effort), "parameter");
24947
- if (!effortRow) {
24948
- snapshot = await this._openModelPickerControl(c, snapshot, "effort_control");
24949
- 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 };
24950
25005
  }
24951
- if (effortRow) return effortRow;
25006
+ this._throwIfCancelledBeforeSend(job);
25007
+ attempts.push("model_hover");
24952
25008
  await this._hoverModelPickerPoint(c, modelRow);
24953
- await sleep2(400);
24954
- snapshot = await this._readModelPickerRows(c);
24955
- effortRow = selectModelPickerRow(snapshot.rows, cursorEffortUiValue(effort), "parameter");
24956
- 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");
24957
25014
  await this._clickModelPickerPoint(c, modelRow);
24958
- await sleep2(350);
24959
- snapshot = await this._readModelPickerRows(c);
24960
- effortRow = selectModelPickerRow(snapshot.rows, cursorEffortUiValue(effort), "parameter");
25015
+ result = await this._waitForModelPickerMatch(c, requested, "parameter", job, { timeoutMs: 1100 });
24961
25016
  }
24962
- 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;
24963
25029
  }
24964
25030
  async _applyModelPreference(c, preference, job) {
24965
25031
  if (!preference) {
@@ -24968,63 +25034,167 @@ var CursorBridge = class {
24968
25034
  }
24969
25035
  const requestedModel = String(preference.model || "").trim();
24970
25036
  const requestedEffort = preference.effort ? normalizeCursorModelEffort(preference.effort, "") : null;
24971
- const opened = await this._openModelPicker(c);
24972
- let located = await this._findModelPickerModel(c, opened, requestedModel);
24973
- let modelRow = located.modelRow;
24974
- if (!modelRow) {
24975
- throw new Error(`Configured Cursor model is unavailable or ambiguous: ${requestedModel}`);
24976
- }
24977
- let selectedEffortRow = null;
24978
- if (requestedEffort && modelRow.hasSubmenu) {
24979
- selectedEffortRow = await this._selectedEffortRow(c, modelRow, requestedEffort);
24980
- if (!selectedEffortRow) {
24981
- throw new Error(`Cursor model ${requestedModel} does not expose effort ${requestedEffort}`);
24982
- }
24983
- if (!selectedEffortRow.selected || !modelRow.selected) {
24984
- await this._clickModelPickerPoint(c, selectedEffortRow);
24985
- await sleep2(550);
24986
- }
24987
- } else if (!modelRow.selected) {
24988
- await this._clickModelPickerPoint(c, modelRow);
24989
- await sleep2(550);
24990
- }
24991
- let trigger = await this._readModelPickerTrigger(c);
24992
- if (!trigger.found || !normalizeModelPickerText(trigger.text).includes(normalizeModelPickerText(requestedModel))) {
24993
- const reopened = await this._openModelPicker(c);
24994
- located = await this._findModelPickerModel(c, reopened, requestedModel);
24995
- const selected = selectModelPickerRow(located.snapshot.rows.filter((row) => row.selected), requestedModel, "model");
24996
- if (!selected) throw new Error(`Cursor did not confirm configured model ${requestedModel}`);
24997
- modelRow = selected;
24998
- }
25037
+ let modelRow = null;
24999
25038
  let effectiveEffort = null;
25000
- if (requestedEffort) {
25001
- const reopened = await this._openModelPicker(c);
25002
- 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);
25003
25043
  modelRow = located.modelRow;
25004
- if (!modelRow) throw new Error(`Cursor model row disappeared while applying effort: ${requestedModel}`);
25005
- let effortRow = await this._selectedEffortRow(c, modelRow, requestedEffort);
25006
- if (!effortRow) {
25007
- 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
+ );
25008
25051
  }
25009
- if (!effortRow.selected) {
25010
- await this._clickModelPickerPoint(c, effortRow);
25011
- 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);
25012
25095
  }
25013
- trigger = await this._readModelPickerTrigger(c);
25014
- const detailMatches = normalizeModelPickerText(`${trigger.detail || ""} ${trigger.text || ""}`).includes(normalizeModelPickerText(requestedEffort));
25015
- if (!detailMatches) {
25016
- const verify = await this._openModelPicker(c);
25017
- const verifiedModel = await this._findModelPickerModel(c, verify, requestedModel);
25018
- const selectedModel = verifiedModel.modelRow;
25019
- 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
+ }
25020
25132
  if (!effortRow || !effortRow.selected) {
25021
- 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
+ );
25022
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;
25192
+ }
25193
+ if (primaryError.modelSelection) primaryError.modelSelection.cleanupError = message;
25194
+ if (job && job.modelSelection) job.modelSelection.cleanupError = message;
25023
25195
  }
25024
- effectiveEffort = requestedEffort;
25025
25196
  }
25026
- await this._closeModelPicker(c);
25027
- trigger = await this._readModelPickerTrigger(c);
25197
+ const trigger = await this._readModelPickerTrigger(c);
25028
25198
  const result = {
25029
25199
  configured: true,
25030
25200
  applied: true,
@@ -25203,6 +25373,38 @@ var CursorBridge = class {
25203
25373
  }
25204
25374
  }
25205
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
+ }
25206
25408
  async _confirmSubmission(c, baselineCount = 0, providerErrorBaseline = "") {
25207
25409
  const accepted = async () => {
25208
25410
  await this._throwIfNewProviderError(c, providerErrorBaseline);
@@ -25292,7 +25494,7 @@ var CursorBridge = class {
25292
25494
  this._throwIfCancelledBeforeSend(job);
25293
25495
  await this._applyModelPreference(c, job.modelPreference, job);
25294
25496
  this._throwIfCancelledBeforeSend(job);
25295
- const filled = await evalJS(c, exprFill(job.prompt));
25497
+ const filled = await this._fillPrompt(c, job.prompt, job);
25296
25498
  if (filled === "NO_INPUT") await this._throwChatPanelUnavailableAfterNoInput(c);
25297
25499
  if (filled === "NO_INPUT" || filled === "EXEC_FAIL") throw new Error("Failed to enter the parallel_agent task");
25298
25500
  await sleep2(350);
@@ -25412,7 +25614,7 @@ var CursorBridge = class {
25412
25614
  this._throwIfCancelledBeforeSend(job);
25413
25615
  job.responseBaseline = await this._captureSessionResponseBaseline(c);
25414
25616
  const providerErrorBaseline = providerErrorSignature(await this._readProviderError(c));
25415
- const filled = await evalJS(c, exprFill(job.prompt));
25617
+ const filled = await this._fillPrompt(c, job.prompt, job);
25416
25618
  if (filled === "NO_INPUT") await this._throwChatPanelUnavailableAfterNoInput(c);
25417
25619
  if (filled === "NO_INPUT" || filled === "EXEC_FAIL") {
25418
25620
  throw cursorSessionError("SESSION_INPUT_FAILED", "failed to enter the continued task");
@@ -26629,6 +26831,7 @@ export {
26629
26831
  EXPR_MODEL_PICKER_ROWS,
26630
26832
  EXPR_MODEL_PICKER_TRIGGER,
26631
26833
  EXPR_PAGE_CAPABILITIES,
26834
+ EXPR_PREPARE_INPUT,
26632
26835
  EXPR_PROVIDER_ERROR,
26633
26836
  EXPR_VISIBLE,
26634
26837
  EXPR_VISIBLE_COMPOSER,
@@ -26644,7 +26847,6 @@ export {
26644
26847
  exprClickBoundComposerStop,
26645
26848
  exprClickSelectedAgentStop,
26646
26849
  exprCreateAgentForWorkspace,
26647
- exprFill,
26648
26850
  exprInspectWorkspaceRepository,
26649
26851
  exprOpenAgent,
26650
26852
  isConfirmedCompletedReply,
@@ -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.11",
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.11",
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.1"
50
+ "embeddedProductVersion": "5.8.2"
51
51
  }
52
52
  }