pi-cursor-bridge 0.1.17 → 0.2.1
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 +663 -135
- package/dist/cursor-lifecycle-supervisor.mjs +41 -11
- package/extensions/index.ts +1 -1
- package/package.json +2 -2
- package/skills/cursor-delegate/SKILL.md +13 -12
- package/skills/cursor-delegate/references/delegation-contract.md +15 -7
|
@@ -81,7 +81,7 @@ function powershellWindowScript(options) {
|
|
|
81
81
|
` Remove-Item -LiteralPath '${showFlagPath}' -Force -ErrorAction SilentlyContinue`,
|
|
82
82
|
"}"
|
|
83
83
|
].join("\n");
|
|
84
|
-
const apply = lifetime ? lifetimeLoop : loop ? `for ($i = 0; $i -lt ${iterations}; $i++) { ${hideIfAllowed}; Start-Sleep -Milliseconds ${intervalMs} }` : `$changed = [CursorBridgeWindowControl]::Apply(${targetPid}, ${show}); [Console]::Out.Write($changed)`;
|
|
84
|
+
const apply = lifetime ? lifetimeLoop : loop ? `for ($i = 0; $i -lt ${iterations}; $i++) { ${hideIfAllowed}; Start-Sleep -Milliseconds ${intervalMs} }` : `$changed = [CursorBridgeWindowControl]::Apply(${targetPid}, ${show}${options.scope === "agents" ? ", $true" : ""}); [Console]::Out.Write($changed)`;
|
|
85
85
|
return `$ErrorActionPreference = 'Stop'
|
|
86
86
|
Add-Type -TypeDefinition @'
|
|
87
87
|
${WINDOW_CONTROL_TYPE}
|
|
@@ -95,6 +95,8 @@ function setCursorWindowPresentation(options = {}) {
|
|
|
95
95
|
const platform = options.platform || process.platform;
|
|
96
96
|
const action = String(options.action || "").trim().toLowerCase();
|
|
97
97
|
if (!["hide", "show"].includes(action)) throw new Error(`unsupported Cursor window action: ${options.action}`);
|
|
98
|
+
const scope = options.scope ?? "process";
|
|
99
|
+
if (!["process", "agents"].includes(scope)) throw new Error(`unsupported Cursor window scope: ${scope}`);
|
|
98
100
|
if (platform !== "win32") {
|
|
99
101
|
return { supported: false, applied: false, action, reason: `window control is not implemented for ${platform}` };
|
|
100
102
|
}
|
|
@@ -105,12 +107,14 @@ function setCursorWindowPresentation(options = {}) {
|
|
|
105
107
|
}
|
|
106
108
|
const showFlagPath = resolve(options.showFlagPath || join2(dirname(resolveCursorRuntimeFile()), `show-${pid}.flag`));
|
|
107
109
|
try {
|
|
108
|
-
if (
|
|
109
|
-
|
|
110
|
-
|
|
110
|
+
if (scope === "process") {
|
|
111
|
+
if (action === "show") {
|
|
112
|
+
mkdirSync2(dirname(showFlagPath), { recursive: true });
|
|
113
|
+
writeFileSync(showFlagPath, `${pid}
|
|
111
114
|
`, { encoding: "utf8", mode: 384 });
|
|
112
|
-
|
|
113
|
-
|
|
115
|
+
} else {
|
|
116
|
+
rmSync(showFlagPath, { force: true });
|
|
117
|
+
}
|
|
114
118
|
}
|
|
115
119
|
} catch (error) {
|
|
116
120
|
return {
|
|
@@ -124,7 +128,7 @@ function setCursorWindowPresentation(options = {}) {
|
|
|
124
128
|
}
|
|
125
129
|
const run = options.execFileSyncImpl || execFileSync;
|
|
126
130
|
try {
|
|
127
|
-
const script = powershellWindowScript({ pid, action });
|
|
131
|
+
const script = powershellWindowScript({ pid, action, scope });
|
|
128
132
|
const output = run("powershell.exe", [
|
|
129
133
|
"-NoLogo",
|
|
130
134
|
"-NoProfile",
|
|
@@ -140,9 +144,18 @@ function setCursorWindowPresentation(options = {}) {
|
|
|
140
144
|
timeout: Number(options.timeoutMs || 15e3)
|
|
141
145
|
});
|
|
142
146
|
const changedWindows = Number(String(output || "").trim() || 0);
|
|
143
|
-
return {
|
|
147
|
+
return {
|
|
148
|
+
supported: true,
|
|
149
|
+
applied: scope !== "agents" || changedWindows > 0,
|
|
150
|
+
action,
|
|
151
|
+
scope,
|
|
152
|
+
port,
|
|
153
|
+
pid,
|
|
154
|
+
changedWindows,
|
|
155
|
+
...scope === "process" ? { showFlagPath } : {}
|
|
156
|
+
};
|
|
144
157
|
} catch (error) {
|
|
145
|
-
if (action === "show") rmSync(showFlagPath, { force: true });
|
|
158
|
+
if (action === "show" && scope === "process") rmSync(showFlagPath, { force: true });
|
|
146
159
|
return {
|
|
147
160
|
supported: true,
|
|
148
161
|
applied: false,
|
|
@@ -206,6 +219,7 @@ var init_cursor_runtime = __esm({
|
|
|
206
219
|
using System;
|
|
207
220
|
using System.Runtime.InteropServices;
|
|
208
221
|
using System.Text;
|
|
222
|
+
using System.Collections.Generic;
|
|
209
223
|
|
|
210
224
|
public static class CursorBridgeWindowControl {
|
|
211
225
|
[StructLayout(LayoutKind.Sequential)]
|
|
@@ -225,6 +239,7 @@ public static class CursorBridgeWindowControl {
|
|
|
225
239
|
[DllImport("user32.dll", EntryPoint = "IsWindowArranged")] private static extern bool IsWindowArranged(IntPtr hWnd);
|
|
226
240
|
[DllImport("user32.dll")] private static extern bool GetWindowRect(IntPtr hWnd, out RECT rect);
|
|
227
241
|
[DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern int GetWindowTextLengthW(IntPtr hWnd);
|
|
242
|
+
[DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern int GetWindowTextW(IntPtr hWnd, StringBuilder text, int maxCount);
|
|
228
243
|
[DllImport("user32.dll", CharSet = CharSet.Unicode)] private static extern int GetClassNameW(IntPtr hWnd, StringBuilder className, int maxCount);
|
|
229
244
|
[DllImport("user32.dll")] private static extern bool ShowWindowAsync(IntPtr hWnd, int command);
|
|
230
245
|
[DllImport("user32.dll")] private static extern bool SetWindowPos(IntPtr hWnd, IntPtr insertAfter, int x, int y, int width, int height, uint flags);
|
|
@@ -248,7 +263,12 @@ public static class CursorBridgeWindowControl {
|
|
|
248
263
|
}
|
|
249
264
|
|
|
250
265
|
public static int Apply(int expectedProcessId, bool show) {
|
|
266
|
+
return Apply(expectedProcessId, show, false);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
public static int Apply(int expectedProcessId, bool show, bool agentsOnly) {
|
|
251
270
|
int changed = 0;
|
|
271
|
+
List<IntPtr> windows = new List<IntPtr>();
|
|
252
272
|
EnumWindows((hWnd, lParam) => {
|
|
253
273
|
uint processId;
|
|
254
274
|
GetWindowThreadProcessId(hWnd, out processId);
|
|
@@ -256,6 +276,17 @@ public static class CursorBridgeWindowControl {
|
|
|
256
276
|
StringBuilder className = new StringBuilder(256);
|
|
257
277
|
GetClassNameW(hWnd, className, className.Capacity);
|
|
258
278
|
if (!String.Equals(className.ToString(), "Chrome_WidgetWin_1", StringComparison.Ordinal)) return true;
|
|
279
|
+
if (agentsOnly) {
|
|
280
|
+
StringBuilder title = new StringBuilder(GetWindowTextLengthW(hWnd) + 1);
|
|
281
|
+
GetWindowTextW(hWnd, title, title.Capacity);
|
|
282
|
+
if (!String.Equals(title.ToString(), "Cursor Agents", StringComparison.Ordinal)) return true;
|
|
283
|
+
}
|
|
284
|
+
windows.Add(hWnd);
|
|
285
|
+
return true;
|
|
286
|
+
}, IntPtr.Zero);
|
|
287
|
+
// Automatic recovery must never broaden an absent or ambiguous Agents match.
|
|
288
|
+
if (agentsOnly && windows.Count != 1) return 0;
|
|
289
|
+
foreach (IntPtr hWnd in windows) {
|
|
259
290
|
bool visible = IsWindowVisible(hWnd);
|
|
260
291
|
if (show) {
|
|
261
292
|
// SWP_SHOWWINDOW + SWP_NOACTIVATE preserves minimized/maximized/arranged
|
|
@@ -283,8 +314,7 @@ public static class CursorBridgeWindowControl {
|
|
|
283
314
|
if (restored || pulsed || redrawn) changed++;
|
|
284
315
|
}
|
|
285
316
|
if (!show && visible) { if (ShowWindowAsync(hWnd, 0)) changed++; }
|
|
286
|
-
|
|
287
|
-
}, IntPtr.Zero);
|
|
317
|
+
}
|
|
288
318
|
return changed;
|
|
289
319
|
}
|
|
290
320
|
}
|
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.2.1",
|
|
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.2.1",
|
|
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": "
|
|
50
|
+
"embeddedProductVersion": "6.0.1"
|
|
51
51
|
}
|
|
52
52
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: cursor-delegate
|
|
3
|
-
description: "Delegate bounded light-to-medium implementation, investigation, documentation, configuration, testing, and tooling work to Cursor Bridge after the primary agent owns direction and risk boundaries. Also use when the user explicitly asks to create, keep, continue, inspect, or close the same Cursor execution session, including phrases such as '持续会话', '同一个 Cursor 会话', or 'continue the Cursor session'. Generic '继续' is not enough to reuse a session.
|
|
3
|
+
description: "Delegate bounded light-to-medium implementation, investigation, documentation, configuration, testing, and tooling work to Cursor Bridge after the primary agent owns direction and risk boundaries. Also use when the user explicitly asks to create, keep, continue, inspect, or close the same Cursor execution session, including phrases such as '持续会话', '同一个 Cursor 会话', or 'continue the Cursor session'. Generic '继续' is not enough to reuse a session. Poll each turn compactly by task_id, then retrieve its normal terminal reply with detail=result and verify it in the primary agent. Do not use when the user opts out, cursor_do is unavailable or administrator-disabled, or for product direction, architecture decisions, exclusive GUI operations, formal verification verdicts, governance state decisions, or unbounded investigation."
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Cursor Delegate
|
|
@@ -21,11 +21,11 @@ Declare `request_context` for each call: an AI caller uses `sender="model"`; set
|
|
|
21
21
|
|
|
22
22
|
Use this responsibility chain:
|
|
23
23
|
|
|
24
|
-
`primary agent defines purpose, invariants, and risk boundaries -> form a bounded task envelope -> Cursor investigates locally and executes within the envelope ->
|
|
24
|
+
`primary agent defines purpose, invariants, and risk boundaries -> form a bounded task envelope -> Cursor investigates locally and executes within the envelope -> poll compactly and retrieve the normal terminal reply with detail=result -> primary agent inspects the real changes and verifies them`
|
|
25
25
|
|
|
26
26
|
- Decide what should be achieved, why it matters, what must not change, where Cursor may work, and what evidence makes the result acceptable. Do not delegate product direction, architecture boundaries, or state verdicts.
|
|
27
27
|
- Allow Cursor to locate relevant implementation, compare local approaches, and complete code, documentation, configuration, scripts, tests, and tooling inside those boundaries. Do not require the primary agent to pre-solve the task line by line.
|
|
28
|
-
- Once a task has been selected for delegation, normally call `cursor_do` once with `background=true`, then continue non-conflicting primary-agent work. Bridge starts FIFO work in a clean chat automatically.
|
|
28
|
+
- Once a task has been selected for delegation, normally call `cursor_do` once with `background=true`, receive its compact submission receipt, then continue non-conflicting primary-agent work. Bridge starts FIFO work in a clean chat automatically.
|
|
29
29
|
- Prefer `execution=fifo` unless the parallel contract is clearly satisfied.
|
|
30
30
|
- Do not inject a unique completion marker or impose a minimum response length. Rely on task state, stable `task_id` or `agent_id`, and the actual result.
|
|
31
31
|
|
|
@@ -75,7 +75,7 @@ Do not choose parallel execution merely because there are many tasks. When depen
|
|
|
75
75
|
|
|
76
76
|
1. Record the relevant pre-dispatch workspace state so later review can distinguish existing user changes.
|
|
77
77
|
2. Form one independent task envelope per task using [delegation-contract.md](references/delegation-contract.md). Write its narrative instructions in the language of the user's current substantive task unless the user explicitly requests another language. Do not persist an inferred language or replace a clear conversational signal with the host/OS locale.
|
|
78
|
-
3. Call `cursor_do` with `background=true
|
|
78
|
+
3. Call `cursor_do` with `background=true` and save its compact submission receipt. Use `background=false` only when an immediate synchronous full result is required. Use only the documented `session_mode` and `session_id` fields when continuity is explicit; never infer continuity from the visible chat.
|
|
79
79
|
4. Save each returned `task_id`; for persistent work also save `session_id`. Treat `agent_id` as verification evidence, not the continuation handle.
|
|
80
80
|
5. If a parallel submission does not return a usable `agent_id`, stop expanding the parallel batch and use `fifo` or report the ambiguous state.
|
|
81
81
|
|
|
@@ -83,12 +83,13 @@ The envelope may contain a small number of local implementation `open_questions`
|
|
|
83
83
|
|
|
84
84
|
## Collect and verify
|
|
85
85
|
|
|
86
|
-
1. Always query `cursor_status(task_id)` for the exact task. Do not treat the currently visible Cursor chat as task identity.
|
|
86
|
+
1. Always query `cursor_status(task_id)` for the exact task. Its default compact view is for normal polling; use `detail="full"` during progress only when detailed diagnostics are needed. Do not treat the currently visible Cursor chat as task identity.
|
|
87
87
|
2. Treat `submitting`, `running`, and `collecting` as normal in-progress states. More than two minutes is not itself a failure; wait for an explicit terminal state.
|
|
88
|
-
3.
|
|
89
|
-
4.
|
|
90
|
-
5.
|
|
91
|
-
6.
|
|
88
|
+
3. After a terminal state, call `cursor_status(task_id, detail="result")`. It returns the raw complete retained reply without a JSON wrapper and records explicit receipt; check `isError` before treating content as a reply. Repeat result reads remain allowed while the task is retained. Use `detail="full"` when the diagnostic task detail is needed.
|
|
89
|
+
4. Compare Cursor's claimed work with the real diff, `allowed_paths`, and acceptance contract.
|
|
90
|
+
5. When `cursor_status` reports a configured model default, confirm `modelSelection.applied=true` and preserve its configured/effective model and effort fields in any failure report.
|
|
91
|
+
6. Run risk-proportionate verification in the primary agent. Cursor's response alone cannot support a formal pass, verified state, or governance transition.
|
|
92
|
+
7. Record each task as complete, partial, failed, timed out, or ambiguous before summarizing the batch.
|
|
92
93
|
|
|
93
94
|
Report the accepted result in the language of the user's current task. Keep `task_id`, `agent_id`, tool names, states, enum values, paths, commands, hashes, exact permission options, and error/status codes verbatim. If Cursor returned an artifact or report in another language, preserve it and summarize the relevant facts in the current task language.
|
|
94
95
|
|
|
@@ -97,14 +98,14 @@ Read [delegation-contract.md](references/delegation-contract.md) for state inter
|
|
|
97
98
|
## Handle abnormal states
|
|
98
99
|
|
|
99
100
|
- For `needs_attention`, `orphaned`, ambiguous state, or an unbound session, assume the real Cursor Agent may still be running. Preserve path ownership and never resubmit automatically.
|
|
100
|
-
- For a parallel orphan with a bound `agent_id`, first call `cursor_task_control(action=reap)`. This explicitly rechecks and, when possible, resumes monitoring or
|
|
101
|
+
- For a parallel orphan with a bound `agent_id`, first call `cursor_task_control(action=reap)`. This explicitly rechecks and, when possible, resumes monitoring or recovers that task's terminal state. It returns only an action/state summary; after a terminal state, retrieve the normal reply with `cursor_status(task_id, detail="result")` or use `detail="full"` for diagnostics.
|
|
101
102
|
- For an unbound FIFO or any orphan without an `agent_id`, do not call `reap` as if an identity existed. It globally blocks delegation; manually verify Cursor has stopped, then use the explicitly acknowledged `abandon` path.
|
|
102
103
|
- To stop a bound task, use `cursor_task_control(action=cancel, confirm=true, expected_agent_id=<exact id>)`. This includes FIFO tasks that have published an Agent ID. If Stop cannot be confirmed, the reservation remains held.
|
|
103
104
|
- Use `action=abandon` only after manual verification and an explicit user decision to accept the risk. It requires `confirm=true`, a non-empty reason, `acknowledge_may_still_write=true`, and the exact `expected_agent_id` when one is already bound; report that the underlying Agent may still run or write.
|
|
104
|
-
- If Cursor shows a final UI response but Bridge has not collected it, use explicit `reap` against the original bound task. A `terminal_uncollected` result keeps the reservation for retry. Do not add a completion marker, increase a response-length requirement, or submit the same task again.
|
|
105
|
+
- If Cursor shows a final UI response but Bridge has not collected it, use explicit `reap` against the original bound task. A `terminal_uncollected` result keeps the reservation for retry; after recovery reaches a terminal state, retrieve the result through explicit full task status. Do not add a completion marker, increase a response-length requirement, or submit the same task again.
|
|
105
106
|
- Task identity and reservations are process-local. After an MCP/Codex restart, do not claim the old `task_id` is recoverable; inspect Cursor Agent History and workspace changes manually before overlapping work.
|
|
106
107
|
- A ready persistent `session_id` is stored outside the versioned plugin cache and may survive MCP/Codex restart or plugin update. Query `cursor_status(session_id)` before continuing. If it reports `needs_attention`, an expired sender lease, or a missing exact Agent binding, do not resubmit or silently create a replacement session.
|
|
107
|
-
- Use `cursor_session_control(action=reconcile)` to check the exact Agent twice after an interrupted adapter. It may return the session to `ready` only from stable terminal evidence; an interrupted completed reply remains explicitly uncollected.
|
|
108
|
+
- Use `cursor_session_control(action=reconcile)` to check the exact Agent twice after an interrupted adapter. It may return the session to `ready` only from stable terminal evidence; an interrupted completed reply remains explicitly uncollected and `cursor_session_control(action=collect_result)` returns that session reply in full.
|
|
108
109
|
- `cursor_session_control(action=abandon)` is the last resort for an uncertain session and requires `confirm=true`, a non-empty reason, and `acknowledge_may_still_write=true`. It closes only the Bridge mapping and does not prove that Cursor stopped.
|
|
109
110
|
- If a timed-out task changed files, inspect the changes before deciding whether to continue, retry, or revert.
|
|
110
111
|
- If changes exceed `allowed_paths`, stop accepting the result and report the scope violation.
|
|
@@ -21,7 +21,7 @@ Provide every task independently:
|
|
|
21
21
|
| `read_only` | Use `true` for lookup and analysis; use `false` for any file modification. |
|
|
22
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. |
|
|
23
23
|
| `completion_contract` | State the deliverables, validation commands, permitted incomplete items, final report format, and that narrative output should follow the task language. Preserve paths, commands, identifiers, and machine tokens verbatim. |
|
|
24
|
-
| `background` | Default to `true` so the primary agent may continue independent work. |
|
|
24
|
+
| `background` | Default to `true` so the primary agent may continue independent work; it returns a compact submission receipt. Set `false` only to wait synchronously for the full result body. |
|
|
25
25
|
|
|
26
26
|
## Routing contract
|
|
27
27
|
|
|
@@ -65,12 +65,20 @@ Bounded write task:
|
|
|
65
65
|
|
|
66
66
|
For dependent or path-overlapping work, change `execution` to `fifo` and submit the next task only after accepting its predecessor.
|
|
67
67
|
|
|
68
|
+
Compact collection flow:
|
|
69
|
+
|
|
70
|
+
1. After `cursor_do(background=true)`, save the compact receipt's `task_id`.
|
|
71
|
+
2. Poll `cursor_status(task_id)` with its default compact view while the task is active.
|
|
72
|
+
3. Once terminal, call `cursor_status(task_id, detail="result")` to retrieve the raw retained reply and record receipt. It has no JSON wrapper, so check `isError` before treating content as a reply. Use `detail="full"` when task diagnostics are needed; repeat either explicit read is allowed while the task record remains retained.
|
|
73
|
+
|
|
68
74
|
## Identity and collection contract
|
|
69
75
|
|
|
70
76
|
- `task_id` is the stable identity used by the primary agent to query and summarize a task. Save it immediately after dispatch.
|
|
71
77
|
- `agent_id` binds a task to one specific Agents Window session when Bridge publishes it. `parallel_agent` always needs this identity. FIFO may also publish one; if it does not, do not assume a safe Stop target.
|
|
72
|
-
- Determine task state only through `cursor_status(task_id)`, not the currently selected chat or latest visible response.
|
|
73
|
-
- A collected result should include at least task state, summary, changed files, validation performed, failures or blockers, and the raw Cursor response.
|
|
78
|
+
- Determine task state only through `cursor_status(task_id)`, not the currently selected chat or latest visible response. Its default compact view never returns a result body or records receipt.
|
|
79
|
+
- After a terminal state, use `cursor_status(task_id, detail="result")` to retrieve the plain complete retained reply and record explicit receipt. Use `detail="full"` when task diagnostics are needed. A collected result should include at least task state, summary, changed files, validation performed, failures or blockers, and the raw Cursor response.
|
|
80
|
+
- `cursor_task_control` returns an action and compact task-state summary without a result body or implicit receipt. Retrieve a terminal reply afterward with `detail="result"`, or use `detail="full"` for diagnostics.
|
|
81
|
+
- `cursor_session_control(action=collect_result)` always returns the full session reply.
|
|
74
82
|
- Do not require a unique completion marker or minimum response length. Bridge determines completion from Agent state, stopped generation, and response stability.
|
|
75
83
|
|
|
76
84
|
### State table
|
|
@@ -78,15 +86,15 @@ For dependent or path-overlapping work, change `execution` to `fifo` and submit
|
|
|
78
86
|
| State or phase | Primary-agent action |
|
|
79
87
|
|---|---|
|
|
80
88
|
| `queued/submitting/running/collecting` | Keep the original task and continue polling by `task_id`. More than two minutes is not a failure. |
|
|
81
|
-
| `completed` |
|
|
89
|
+
| `completed` | Call `cursor_status(task_id, detail="result")` to read the raw response, then inspect the real diff, allowed paths, and completion contract. Use `detail="full"` when diagnostics are needed. |
|
|
82
90
|
| `failed` | Read the explicit error and determine whether the Cursor Agent actually failed before deciding to rework. |
|
|
83
91
|
| `needs_attention/orphaned` with bound `agent_id` | Preserve path ownership and explicitly call `cursor_task_control(action=reap)` for the same in-memory task. Do not resubmit automatically. |
|
|
84
92
|
| FIFO or unbound orphan | A global reservation blocks all new delegation. If an `agent_id` was published, use targeted `cancel`. Otherwise manually verify Cursor has stopped, then use explicitly acknowledged `abandon`; there is no safe `reap` target. |
|
|
85
|
-
| `terminal_uncollected` | Agent History is stably terminal but the final response extraction failed. Keep the reservation and retry explicit `reap`;
|
|
93
|
+
| `terminal_uncollected` | Agent History is stably terminal but the final response extraction failed. Keep the reservation and retry explicit `reap`; after recovery, use `detail="result"` to retrieve the reply or `detail="full"` for diagnostics. Do not release on one DOM failure. |
|
|
86
94
|
| `cancelled` | The exact Agent Stop action or an unsent queued cancellation was confirmed; the reservation is released. |
|
|
87
95
|
| `abandoned` | The reservation was explicitly released without proof that the underlying Agent stopped. Treat the warning as live risk and inspect workspace changes before any overlapping write. |
|
|
88
96
|
|
|
89
|
-
For an R6-style false negative, continue
|
|
97
|
+
For an R6-style false negative, continue compact polling of the original `task_id` when Agent History already contains a complete final response but automatic collection has not finished. Bridge should retry extraction against the original `agent_id`; once terminal, use `detail="result"` or `detail="full"` for diagnostics. Do not work around collection by requiring a longer reply, injecting a completion marker, or submitting the same task again.
|
|
90
98
|
|
|
91
99
|
## Primary-agent acceptance contract
|
|
92
100
|
|
|
@@ -106,5 +114,5 @@ Cursor's completion statement means only that delegated execution ended; it is n
|
|
|
106
114
|
- Stop automatic integration when parallel tasks conflict and return the batch to primary-agent review.
|
|
107
115
|
- If Agent History or the response DOM is temporarily unreadable, let Bridge wait and retry against the same `agent_id`. Enter `needs_attention` after persistent failure; do not incorrectly mark the task complete or create a duplicate Agent.
|
|
108
116
|
- For a bound orphan, use `reap` before `cancel`. `cancel` requires the exact `expected_agent_id` and only releases after stable Stop evidence. `abandon` requires explicit confirmation, a reason, acknowledgement that the Agent may still write, and the exact `expected_agent_id` when one is bound.
|
|
109
|
-
- `cursor_status` is a pure snapshot. Reconciliation happens only through explicit `cursor_task_control`.
|
|
117
|
+
- Default compact `cursor_status` is a pure snapshot. `cursor_status(task_id, detail="result")` is the normal explicit result-receipt operation; `detail="full"` also records receipt and retains diagnostic detail. Reconciliation still happens only through explicit `cursor_task_control`.
|
|
110
118
|
- Task records and reservations live only for the current Bridge MCP process. After restart, inspect Cursor Agent History and the workspace manually; persistent cross-process task leases are outside the current contract.
|