subharness 0.0.4 → 0.0.5

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.
Files changed (188) hide show
  1. package/README.md +36 -6
  2. package/dist/adapters/claude-process.d.ts +3 -0
  3. package/dist/adapters/claude-process.js +11 -1
  4. package/dist/adapters/claude-process.js.map +1 -1
  5. package/dist/adapters/claude-result.d.ts +2 -0
  6. package/dist/adapters/claude-result.js +22 -0
  7. package/dist/adapters/claude-result.js.map +1 -0
  8. package/dist/adapters/claude.js +30 -11
  9. package/dist/adapters/claude.js.map +1 -1
  10. package/dist/adapters/codex.js +4 -1
  11. package/dist/adapters/codex.js.map +1 -1
  12. package/dist/adapters/copilot-permissions.d.ts +26 -0
  13. package/dist/adapters/copilot-permissions.js +121 -0
  14. package/dist/adapters/copilot-permissions.js.map +1 -0
  15. package/dist/adapters/copilot-tools.d.ts +12 -0
  16. package/dist/adapters/copilot-tools.js +61 -0
  17. package/dist/adapters/copilot-tools.js.map +1 -0
  18. package/dist/adapters/copilot.d.ts +108 -0
  19. package/dist/adapters/copilot.js +819 -0
  20. package/dist/adapters/copilot.js.map +1 -0
  21. package/dist/adapters/cursor-cli-approvals.d.ts +2 -0
  22. package/dist/adapters/cursor-cli-approvals.js +83 -0
  23. package/dist/adapters/cursor-cli-approvals.js.map +1 -0
  24. package/dist/adapters/cursor-cli-model.d.ts +4 -0
  25. package/dist/adapters/cursor-cli-model.js +64 -0
  26. package/dist/adapters/cursor-cli-model.js.map +1 -0
  27. package/dist/adapters/cursor-cli-session.d.ts +32 -0
  28. package/dist/adapters/cursor-cli-session.js +316 -0
  29. package/dist/adapters/cursor-cli-session.js.map +1 -0
  30. package/dist/adapters/cursor-cli-tools.d.ts +20 -0
  31. package/dist/adapters/cursor-cli-tools.js +181 -0
  32. package/dist/adapters/cursor-cli-tools.js.map +1 -0
  33. package/dist/adapters/cursor-cli.d.ts +2 -0
  34. package/dist/adapters/cursor-cli.js +306 -0
  35. package/dist/adapters/cursor-cli.js.map +1 -0
  36. package/dist/adapters/cursor-model.d.ts +7 -0
  37. package/dist/adapters/cursor-model.js +67 -0
  38. package/dist/adapters/cursor-model.js.map +1 -0
  39. package/dist/adapters/cursor-rpc.d.ts +42 -0
  40. package/dist/adapters/cursor-rpc.js +271 -0
  41. package/dist/adapters/cursor-rpc.js.map +1 -0
  42. package/dist/adapters/cursor-session.d.ts +4 -0
  43. package/dist/adapters/cursor-session.js +327 -0
  44. package/dist/adapters/cursor-session.js.map +1 -0
  45. package/dist/adapters/cursor-startup.d.ts +16 -0
  46. package/dist/adapters/cursor-startup.js +74 -0
  47. package/dist/adapters/cursor-startup.js.map +1 -0
  48. package/dist/adapters/cursor-tools.d.ts +11 -0
  49. package/dist/adapters/cursor-tools.js +49 -0
  50. package/dist/adapters/cursor-tools.js.map +1 -0
  51. package/dist/adapters/cursor.d.ts +6 -0
  52. package/dist/adapters/cursor.js +17 -0
  53. package/dist/adapters/cursor.js.map +1 -0
  54. package/dist/adapters/fx-auth.d.ts +12 -2
  55. package/dist/adapters/fx-auth.js +51 -61
  56. package/dist/adapters/fx-auth.js.map +1 -1
  57. package/dist/adapters/fx-profile.d.ts +8 -0
  58. package/dist/adapters/fx-profile.js +101 -0
  59. package/dist/adapters/fx-profile.js.map +1 -0
  60. package/dist/adapters/fx-rpc.d.ts +2 -0
  61. package/dist/adapters/fx-rpc.js +30 -4
  62. package/dist/adapters/fx-rpc.js.map +1 -1
  63. package/dist/adapters/fx-status.d.ts +2 -0
  64. package/dist/adapters/fx-status.js +96 -0
  65. package/dist/adapters/fx-status.js.map +1 -0
  66. package/dist/adapters/fx.js +28 -12
  67. package/dist/adapters/fx.js.map +1 -1
  68. package/dist/adapters/opencode-access.d.ts +13 -0
  69. package/dist/adapters/opencode-access.js +76 -0
  70. package/dist/adapters/opencode-access.js.map +1 -0
  71. package/dist/adapters/opencode-config.d.ts +11 -0
  72. package/dist/adapters/opencode-config.js +238 -0
  73. package/dist/adapters/opencode-config.js.map +1 -0
  74. package/dist/adapters/opencode-http.d.ts +28 -0
  75. package/dist/adapters/opencode-http.js +297 -0
  76. package/dist/adapters/opencode-http.js.map +1 -0
  77. package/dist/adapters/opencode-tools.d.ts +19 -0
  78. package/dist/adapters/opencode-tools.js +127 -0
  79. package/dist/adapters/opencode-tools.js.map +1 -0
  80. package/dist/adapters/opencode.d.ts +2 -0
  81. package/dist/adapters/opencode.js +569 -0
  82. package/dist/adapters/opencode.js.map +1 -0
  83. package/dist/adapters/rpc.d.ts +3 -0
  84. package/dist/adapters/rpc.js +45 -4
  85. package/dist/adapters/rpc.js.map +1 -1
  86. package/dist/adapters/types.d.ts +5 -0
  87. package/dist/adapters/types.js.map +1 -1
  88. package/dist/approvals/types.d.ts +1 -1
  89. package/dist/approvals/types.js.map +1 -1
  90. package/dist/cli/args.d.ts +1 -1
  91. package/dist/cli/args.js +4 -1
  92. package/dist/cli/args.js.map +1 -1
  93. package/dist/cli/dashboard-client.js +1 -1
  94. package/dist/cli/dashboard-client.js.map +1 -1
  95. package/dist/cli/dashboard-controller.d.ts +7 -0
  96. package/dist/cli/dashboard-controller.js +27 -0
  97. package/dist/cli/dashboard-controller.js.map +1 -0
  98. package/dist/cli/dashboard-detail-view.d.ts +1 -1
  99. package/dist/cli/dashboard-detail-view.js +3 -4
  100. package/dist/cli/dashboard-detail-view.js.map +1 -1
  101. package/dist/cli/dashboard-history-view.js.map +1 -1
  102. package/dist/cli/dashboard-input.d.ts +1 -1
  103. package/dist/cli/dashboard-input.js +11 -1
  104. package/dist/cli/dashboard-input.js.map +1 -1
  105. package/dist/cli/dashboard-layout.js +3 -3
  106. package/dist/cli/dashboard-layout.js.map +1 -1
  107. package/dist/cli/dashboard-renderer.js.map +1 -1
  108. package/dist/cli/dashboard-style.js +2 -2
  109. package/dist/cli/dashboard-style.js.map +1 -1
  110. package/dist/cli/dashboard.d.ts +2 -2
  111. package/dist/cli/dashboard.js +7 -32
  112. package/dist/cli/dashboard.js.map +1 -1
  113. package/dist/cli/help.d.ts +1 -1
  114. package/dist/cli/help.js +30 -12
  115. package/dist/cli/help.js.map +1 -1
  116. package/dist/cli/main.js +5 -1
  117. package/dist/cli/main.js.map +1 -1
  118. package/dist/config/access-provenance.d.ts +10 -0
  119. package/dist/config/access-provenance.js +31 -0
  120. package/dist/config/access-provenance.js.map +1 -0
  121. package/dist/config/access.d.ts +12 -2
  122. package/dist/config/access.js +125 -27
  123. package/dist/config/access.js.map +1 -1
  124. package/dist/config/loader.js +1 -0
  125. package/dist/config/loader.js.map +1 -1
  126. package/dist/config/oidc.js +4 -2
  127. package/dist/config/oidc.js.map +1 -1
  128. package/dist/config/project.js +2 -1
  129. package/dist/config/project.js.map +1 -1
  130. package/dist/config/resolve-access.js +24 -10
  131. package/dist/config/resolve-access.js.map +1 -1
  132. package/dist/index.d.ts +2 -2
  133. package/dist/index.js +1 -1
  134. package/dist/index.js.map +1 -1
  135. package/dist/process-diagnostics.d.ts +2 -0
  136. package/dist/process-diagnostics.js +11 -0
  137. package/dist/process-diagnostics.js.map +1 -0
  138. package/dist/runtime/access-errors.d.ts +4 -0
  139. package/dist/runtime/access-errors.js +25 -0
  140. package/dist/runtime/access-errors.js.map +1 -0
  141. package/dist/runtime/approval-registry.js +1 -1
  142. package/dist/runtime/approval-registry.js.map +1 -1
  143. package/dist/runtime/client.js +54 -14
  144. package/dist/runtime/client.js.map +1 -1
  145. package/dist/runtime/dashboard-sanitize.d.ts +2 -0
  146. package/dist/runtime/dashboard-sanitize.js +7 -0
  147. package/dist/runtime/dashboard-sanitize.js.map +1 -0
  148. package/dist/runtime/dashboard.d.ts +1 -1
  149. package/dist/runtime/dashboard.js +2 -3
  150. package/dist/runtime/dashboard.js.map +1 -1
  151. package/dist/runtime/definition.js +11 -1
  152. package/dist/runtime/definition.js.map +1 -1
  153. package/dist/runtime/select-native.js +26 -8
  154. package/dist/runtime/select-native.js.map +1 -1
  155. package/dist/runtime/worker-client.js +38 -13
  156. package/dist/runtime/worker-client.js.map +1 -1
  157. package/dist/sdk/definitions.d.ts +4 -1
  158. package/dist/sdk/definitions.js +16 -2
  159. package/dist/sdk/definitions.js.map +1 -1
  160. package/dist/sdk/permission-validation.js +10 -1
  161. package/dist/sdk/permission-validation.js.map +1 -1
  162. package/dist/sdk/types.d.ts +29 -1
  163. package/dist/sdk/types.js.map +1 -1
  164. package/package.json +4 -1
  165. package/sdk/access-config.md +58 -4
  166. package/sdk/adapter-contract.md +5 -3
  167. package/sdk/additional-harnesses.md +43 -0
  168. package/sdk/agent-skill.md +2 -2
  169. package/sdk/agent.md +5 -3
  170. package/sdk/approvals.md +3 -1
  171. package/sdk/authentication.md +1 -1
  172. package/sdk/cli/dashboard-design.md +6 -0
  173. package/sdk/cli/index.md +9 -6
  174. package/sdk/cli/output.md +3 -1
  175. package/sdk/config.md +1 -1
  176. package/sdk/copilot.md +53 -0
  177. package/sdk/cursor.md +68 -0
  178. package/sdk/diagnostics.md +29 -0
  179. package/sdk/distribution.md +1 -1
  180. package/sdk/evals.md +1 -1
  181. package/sdk/fx.md +50 -5
  182. package/sdk/harnesses.md +13 -13
  183. package/sdk/index.md +3 -2
  184. package/sdk/opencode.md +57 -0
  185. package/sdk/permissions.md +4 -2
  186. package/sdk/project-team.md +2 -0
  187. package/sdk/tools.md +1 -1
  188. package/sdk/v1-runtime.md +3 -3
@@ -0,0 +1,271 @@
1
+ import { spawn } from "node:child_process";
2
+ import { AgentError } from "../errors.js";
3
+ const MAX_FRAME_BYTES = 16 * 1024 * 1024;
4
+ const CONTROL_TIMEOUT_MS = 15_000;
5
+ const GRACEFUL_CLOSE_MS = 100;
6
+ const TERM_CLOSE_MS = 250;
7
+ const KILL_CLOSE_MS = 1_000;
8
+ const protocolError = () => new AgentError("PROTOCOL_ERROR", "Cursor returned invalid ACP protocol data.");
9
+ const closedError = () => new AgentError("SESSION_CLOSED", "The Cursor ACP transport is closed.");
10
+ const cancellationError = () => new AgentError("CANCELLATION_FAILED", "Cursor ACP process termination could not be confirmed.");
11
+ export class CursorRpcNativeError extends AgentError {
12
+ nativeCode;
13
+ constructor(nativeCode) {
14
+ super("NATIVE_ERROR", "Cursor ACP request failed.");
15
+ this.nativeCode = nativeCode;
16
+ this.name = "CursorRpcNativeError";
17
+ }
18
+ }
19
+ const validId = (value) => typeof value === "string" || (typeof value === "number" && Number.isFinite(value));
20
+ function validEnvelope(value) {
21
+ if (!value || typeof value !== "object" || Array.isArray(value))
22
+ return false;
23
+ const message = value;
24
+ if (message.jsonrpc !== "2.0")
25
+ return false;
26
+ const hasId = Object.hasOwn(message, "id");
27
+ const hasMethod = Object.hasOwn(message, "method");
28
+ const hasResult = Object.hasOwn(message, "result");
29
+ const hasError = Object.hasOwn(message, "error");
30
+ if (hasMethod) {
31
+ return typeof message.method === "string" && (!hasId || validId(message.id)) && !hasResult && !hasError;
32
+ }
33
+ if (!hasId || !validId(message.id) || hasResult === hasError || Object.hasOwn(message, "params"))
34
+ return false;
35
+ if (!hasError)
36
+ return true;
37
+ const error = message.error;
38
+ return !!error && typeof error === "object" && !Array.isArray(error)
39
+ && Number.isInteger(error.code)
40
+ && typeof error.message === "string";
41
+ }
42
+ /** Newline-delimited JSON-RPC 2.0 transport for Cursor's native ACP process. */
43
+ export class CursorRpc {
44
+ child;
45
+ pending = new Map();
46
+ sequence = 0;
47
+ buffer = "";
48
+ started = false;
49
+ closing = false;
50
+ closed = false;
51
+ closePromise;
52
+ failure;
53
+ failureHandler = () => { };
54
+ onMessage = () => { };
55
+ constructor(executable, args, cwd, env) {
56
+ if (process.platform === "win32") {
57
+ throw new AgentError("UNSUPPORTED_OPTION", "Cursor subscription access is supported only on macOS and Linux.");
58
+ }
59
+ this.child = spawn(executable, args, { cwd, env, detached: true, stdio: ["pipe", "pipe", "pipe"] });
60
+ this.child.once("spawn", () => { this.started = true; });
61
+ this.child.stdout.setEncoding("utf8");
62
+ this.child.stdout.on("data", chunk => this.read(chunk));
63
+ this.child.stderr.resume();
64
+ this.child.stdin.on("error", () => this.handleInputFailure());
65
+ this.child.stdin.on("close", () => this.handleInputFailure());
66
+ this.child.once("error", () => {
67
+ this.fail(new AgentError("HARNESS_UNAVAILABLE", "Cannot start the Cursor ACP executable."));
68
+ void this.close().catch(() => { });
69
+ });
70
+ this.child.once("close", () => this.handleExit());
71
+ }
72
+ request(method, params, timeoutMs) {
73
+ if (this.failure)
74
+ return Promise.reject(this.failure);
75
+ if (this.closing)
76
+ return Promise.reject(closedError());
77
+ const timeout = timeoutMs ?? (method === "session/prompt" ? undefined : CONTROL_TIMEOUT_MS);
78
+ if (timeout !== undefined && (!Number.isSafeInteger(timeout) || timeout <= 0)) {
79
+ return Promise.reject(new AgentError("INVALID_ARGUMENT", "Cursor ACP request timeout must be a positive safe integer."));
80
+ }
81
+ const id = ++this.sequence;
82
+ return new Promise((resolve, reject) => {
83
+ const pending = { resolve, reject };
84
+ if (timeout !== undefined) {
85
+ pending.timer = setTimeout(() => {
86
+ if (!this.pending.delete(id))
87
+ return;
88
+ reject(new AgentError("HARNESS_FAILED", "Cursor ACP request timed out."));
89
+ }, timeout);
90
+ pending.timer.unref();
91
+ }
92
+ this.pending.set(id, pending);
93
+ try {
94
+ this.send({ id, method, params });
95
+ }
96
+ catch (error) {
97
+ this.pending.delete(id);
98
+ if (pending.timer)
99
+ clearTimeout(pending.timer);
100
+ reject(error);
101
+ }
102
+ });
103
+ }
104
+ send(envelope) {
105
+ if (this.failure)
106
+ throw this.failure;
107
+ if (this.closing)
108
+ throw closedError();
109
+ let frame;
110
+ try {
111
+ frame = JSON.stringify({ jsonrpc: "2.0", ...envelope });
112
+ if (Buffer.byteLength(frame, "utf8") > MAX_FRAME_BYTES || !validEnvelope(JSON.parse(frame)))
113
+ throw protocolError();
114
+ }
115
+ catch {
116
+ throw protocolError();
117
+ }
118
+ try {
119
+ this.child.stdin.write(`${frame}\n`);
120
+ }
121
+ catch {
122
+ const error = new AgentError("HARNESS_FAILED", "The Cursor ACP input connection closed.");
123
+ this.fail(error);
124
+ void this.close().catch(() => { });
125
+ throw error;
126
+ }
127
+ }
128
+ setFailureHandler(handler) {
129
+ this.failureHandler = handler;
130
+ if (this.failure)
131
+ handler(this.failure);
132
+ }
133
+ close() {
134
+ this.closePromise ??= this.closeOwnedProcess();
135
+ return this.closePromise;
136
+ }
137
+ async closeOwnedProcess() {
138
+ this.closing = true;
139
+ this.rejectPending(this.failure ?? closedError());
140
+ if (!this.closed) {
141
+ try {
142
+ this.child.stdin.end();
143
+ }
144
+ catch { }
145
+ }
146
+ if (await this.waitForRetirement(GRACEFUL_CLOSE_MS))
147
+ return;
148
+ this.signal("SIGTERM");
149
+ if (await this.waitForRetirement(TERM_CLOSE_MS))
150
+ return;
151
+ this.signal("SIGKILL");
152
+ if (await this.waitForRetirement(KILL_CLOSE_MS))
153
+ return;
154
+ const error = cancellationError();
155
+ this.fail(error);
156
+ throw error;
157
+ }
158
+ signal(signal) {
159
+ try {
160
+ if (this.child.pid !== undefined)
161
+ process.kill(-this.child.pid, signal);
162
+ }
163
+ catch { }
164
+ }
165
+ async waitForRetirement(timeoutMs) {
166
+ const deadline = Date.now() + timeoutMs;
167
+ while (Date.now() < deadline) {
168
+ if (this.retired())
169
+ return true;
170
+ await new Promise(resolve => setTimeout(resolve, 10));
171
+ }
172
+ return this.retired();
173
+ }
174
+ retired() {
175
+ if (!this.closed)
176
+ return false;
177
+ if (this.child.pid === undefined)
178
+ return true;
179
+ try {
180
+ process.kill(-this.child.pid, 0);
181
+ return false;
182
+ }
183
+ catch (error) {
184
+ return error.code === "ESRCH";
185
+ }
186
+ }
187
+ read(chunk) {
188
+ if (this.failure)
189
+ return;
190
+ this.buffer += chunk;
191
+ let newline;
192
+ while ((newline = this.buffer.indexOf("\n")) >= 0) {
193
+ const line = this.buffer.slice(0, newline);
194
+ this.buffer = this.buffer.slice(newline + 1);
195
+ if (!line.trim())
196
+ continue;
197
+ if (Buffer.byteLength(line, "utf8") > MAX_FRAME_BYTES)
198
+ return this.invalid();
199
+ let message;
200
+ try {
201
+ message = JSON.parse(line);
202
+ }
203
+ catch {
204
+ return this.invalid();
205
+ }
206
+ if (!validEnvelope(message))
207
+ return this.invalid();
208
+ if (typeof message.method === "string") {
209
+ try {
210
+ this.onMessage(message);
211
+ }
212
+ catch {
213
+ this.fail(new AgentError("HARNESS_FAILED", "Cursor ACP message handling failed."));
214
+ void this.close().catch(() => { });
215
+ }
216
+ continue;
217
+ }
218
+ if (typeof message.id !== "number")
219
+ continue;
220
+ const pending = this.pending.get(message.id);
221
+ if (!pending)
222
+ continue;
223
+ this.pending.delete(message.id);
224
+ if (pending.timer)
225
+ clearTimeout(pending.timer);
226
+ if (Object.hasOwn(message, "error")) {
227
+ const nativeCode = message.error.code;
228
+ pending.reject(new CursorRpcNativeError(nativeCode));
229
+ }
230
+ else
231
+ pending.resolve(message.result);
232
+ }
233
+ if (Buffer.byteLength(this.buffer, "utf8") > MAX_FRAME_BYTES)
234
+ this.invalid();
235
+ }
236
+ invalid() {
237
+ this.fail(protocolError());
238
+ void this.close().catch(() => { });
239
+ }
240
+ handleInputFailure() {
241
+ if (!this.started || this.closing || this.closed)
242
+ return;
243
+ this.fail(new AgentError("HARNESS_FAILED", "The Cursor ACP input connection closed."));
244
+ void this.close().catch(() => { });
245
+ }
246
+ handleExit() {
247
+ this.closed = true;
248
+ if (this.closing)
249
+ return this.rejectPending(closedError());
250
+ this.fail(this.buffer.trim()
251
+ ? protocolError()
252
+ : new AgentError("HARNESS_FAILED", "Cursor ACP exited before the native operation completed."));
253
+ void this.close().catch(() => { });
254
+ }
255
+ rejectPending(error) {
256
+ for (const pending of this.pending.values()) {
257
+ if (pending.timer)
258
+ clearTimeout(pending.timer);
259
+ pending.reject(error);
260
+ }
261
+ this.pending.clear();
262
+ }
263
+ fail(error) {
264
+ if (this.failure)
265
+ return;
266
+ this.failure = error;
267
+ this.rejectPending(error);
268
+ this.failureHandler(error);
269
+ }
270
+ }
271
+ //# sourceMappingURL=cursor-rpc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cursor-rpc.js","sourceRoot":"","sources":["../../src/adapters/cursor-rpc.ts"],"names":[],"mappings":"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","sourcesContent":["import { spawn, type ChildProcessWithoutNullStreams } from \"node:child_process\";\nimport { AgentError } from \"../errors.js\";\n\nconst MAX_FRAME_BYTES = 16 * 1024 * 1024;\nconst CONTROL_TIMEOUT_MS = 15_000;\nconst GRACEFUL_CLOSE_MS = 100;\nconst TERM_CLOSE_MS = 250;\nconst KILL_CLOSE_MS = 1_000;\nconst protocolError = () => new AgentError(\"PROTOCOL_ERROR\", \"Cursor returned invalid ACP protocol data.\");\nconst closedError = () => new AgentError(\"SESSION_CLOSED\", \"The Cursor ACP transport is closed.\");\nconst cancellationError = () => new AgentError(\"CANCELLATION_FAILED\", \"Cursor ACP process termination could not be confirmed.\");\n\nexport type CursorRpcEnvelope = {\n jsonrpc?: \"2.0\";\n id?: string | number;\n method?: string;\n params?: unknown;\n result?: unknown;\n error?: unknown;\n};\n\nexport class CursorRpcNativeError extends AgentError {\n constructor(public readonly nativeCode: number) {\n super(\"NATIVE_ERROR\", \"Cursor ACP request failed.\");\n this.name = \"CursorRpcNativeError\";\n }\n}\n\ntype Pending = { timer?: NodeJS.Timeout; resolve(value: unknown): void; reject(error: Error): void };\n\nconst validId = (value: unknown): value is string | number =>\n typeof value === \"string\" || (typeof value === \"number\" && Number.isFinite(value));\n\nfunction validEnvelope(value: unknown): value is CursorRpcEnvelope {\n if (!value || typeof value !== \"object\" || Array.isArray(value)) return false;\n const message = value as CursorRpcEnvelope;\n if (message.jsonrpc !== \"2.0\") return false;\n const hasId = Object.hasOwn(message, \"id\");\n const hasMethod = Object.hasOwn(message, \"method\");\n const hasResult = Object.hasOwn(message, \"result\");\n const hasError = Object.hasOwn(message, \"error\");\n if (hasMethod) {\n return typeof message.method === \"string\" && (!hasId || validId(message.id)) && !hasResult && !hasError;\n }\n if (!hasId || !validId(message.id) || hasResult === hasError || Object.hasOwn(message, \"params\")) return false;\n if (!hasError) return true;\n const error = message.error;\n return !!error && typeof error === \"object\" && !Array.isArray(error)\n && Number.isInteger((error as { code?: unknown }).code)\n && typeof (error as { message?: unknown }).message === \"string\";\n}\n\n/** Newline-delimited JSON-RPC 2.0 transport for Cursor's native ACP process. */\nexport class CursorRpc {\n private readonly child: ChildProcessWithoutNullStreams;\n private readonly pending = new Map<number, Pending>();\n private sequence = 0;\n private buffer = \"\";\n private started = false;\n private closing = false;\n private closed = false;\n private closePromise?: Promise<void>;\n private failure?: AgentError;\n private failureHandler: (error: AgentError) => void = () => {};\n onMessage: (message: CursorRpcEnvelope) => void = () => {};\n\n constructor(executable: string, args: string[], cwd: string, env: NodeJS.ProcessEnv) {\n if (process.platform === \"win32\") {\n throw new AgentError(\"UNSUPPORTED_OPTION\", \"Cursor subscription access is supported only on macOS and Linux.\");\n }\n this.child = spawn(executable, args, { cwd, env, detached: true, stdio: [\"pipe\", \"pipe\", \"pipe\"] });\n this.child.once(\"spawn\", () => { this.started = true; });\n this.child.stdout.setEncoding(\"utf8\");\n this.child.stdout.on(\"data\", chunk => this.read(chunk));\n this.child.stderr.resume();\n this.child.stdin.on(\"error\", () => this.handleInputFailure());\n this.child.stdin.on(\"close\", () => this.handleInputFailure());\n this.child.once(\"error\", () => {\n this.fail(new AgentError(\"HARNESS_UNAVAILABLE\", \"Cannot start the Cursor ACP executable.\"));\n void this.close().catch(() => {});\n });\n this.child.once(\"close\", () => this.handleExit());\n }\n\n request(method: string, params: unknown, timeoutMs?: number): Promise<unknown> {\n if (this.failure) return Promise.reject(this.failure);\n if (this.closing) return Promise.reject(closedError());\n const timeout = timeoutMs ?? (method === \"session/prompt\" ? undefined : CONTROL_TIMEOUT_MS);\n if (timeout !== undefined && (!Number.isSafeInteger(timeout) || timeout <= 0)) {\n return Promise.reject(new AgentError(\"INVALID_ARGUMENT\", \"Cursor ACP request timeout must be a positive safe integer.\"));\n }\n const id = ++this.sequence;\n return new Promise((resolve, reject) => {\n const pending: Pending = { resolve, reject };\n if (timeout !== undefined) {\n pending.timer = setTimeout(() => {\n if (!this.pending.delete(id)) return;\n reject(new AgentError(\"HARNESS_FAILED\", \"Cursor ACP request timed out.\"));\n }, timeout);\n pending.timer.unref();\n }\n this.pending.set(id, pending);\n try { this.send({ id, method, params }); }\n catch (error) {\n this.pending.delete(id);\n if (pending.timer) clearTimeout(pending.timer);\n reject(error);\n }\n });\n }\n\n send(envelope: CursorRpcEnvelope): void {\n if (this.failure) throw this.failure;\n if (this.closing) throw closedError();\n let frame: string;\n try {\n frame = JSON.stringify({ jsonrpc: \"2.0\", ...envelope });\n if (Buffer.byteLength(frame, \"utf8\") > MAX_FRAME_BYTES || !validEnvelope(JSON.parse(frame))) throw protocolError();\n } catch {\n throw protocolError();\n }\n try {\n this.child.stdin.write(`${frame}\\n`);\n } catch {\n const error = new AgentError(\"HARNESS_FAILED\", \"The Cursor ACP input connection closed.\");\n this.fail(error);\n void this.close().catch(() => {});\n throw error;\n }\n }\n\n setFailureHandler(handler: (error: AgentError) => void): void {\n this.failureHandler = handler;\n if (this.failure) handler(this.failure);\n }\n\n close(): Promise<void> {\n this.closePromise ??= this.closeOwnedProcess();\n return this.closePromise;\n }\n\n private async closeOwnedProcess(): Promise<void> {\n this.closing = true;\n this.rejectPending(this.failure ?? closedError());\n if (!this.closed) {\n try { this.child.stdin.end(); } catch {}\n }\n if (await this.waitForRetirement(GRACEFUL_CLOSE_MS)) return;\n this.signal(\"SIGTERM\");\n if (await this.waitForRetirement(TERM_CLOSE_MS)) return;\n this.signal(\"SIGKILL\");\n if (await this.waitForRetirement(KILL_CLOSE_MS)) return;\n const error = cancellationError();\n this.fail(error);\n throw error;\n }\n\n private signal(signal: NodeJS.Signals): void {\n try { if (this.child.pid !== undefined) process.kill(-this.child.pid, signal); }\n catch {}\n }\n\n private async waitForRetirement(timeoutMs: number): Promise<boolean> {\n const deadline = Date.now() + timeoutMs;\n while (Date.now() < deadline) {\n if (this.retired()) return true;\n await new Promise(resolve => setTimeout(resolve, 10));\n }\n return this.retired();\n }\n\n private retired(): boolean {\n if (!this.closed) return false;\n if (this.child.pid === undefined) return true;\n try {\n process.kill(-this.child.pid, 0);\n return false;\n } catch (error) {\n return (error as NodeJS.ErrnoException).code === \"ESRCH\";\n }\n }\n\n private read(chunk: string): void {\n if (this.failure) return;\n this.buffer += chunk;\n let newline: number;\n while ((newline = this.buffer.indexOf(\"\\n\")) >= 0) {\n const line = this.buffer.slice(0, newline);\n this.buffer = this.buffer.slice(newline + 1);\n if (!line.trim()) continue;\n if (Buffer.byteLength(line, \"utf8\") > MAX_FRAME_BYTES) return this.invalid();\n let message: unknown;\n try { message = JSON.parse(line); }\n catch { return this.invalid(); }\n if (!validEnvelope(message)) return this.invalid();\n if (typeof message.method === \"string\") {\n try { this.onMessage(message); }\n catch {\n this.fail(new AgentError(\"HARNESS_FAILED\", \"Cursor ACP message handling failed.\"));\n void this.close().catch(() => {});\n }\n continue;\n }\n if (typeof message.id !== \"number\") continue;\n const pending = this.pending.get(message.id);\n if (!pending) continue;\n this.pending.delete(message.id);\n if (pending.timer) clearTimeout(pending.timer);\n if (Object.hasOwn(message, \"error\")) {\n const nativeCode = (message.error as { code: number }).code;\n pending.reject(new CursorRpcNativeError(nativeCode as number));\n }\n else pending.resolve(message.result);\n }\n if (Buffer.byteLength(this.buffer, \"utf8\") > MAX_FRAME_BYTES) this.invalid();\n }\n\n private invalid(): void {\n this.fail(protocolError());\n void this.close().catch(() => {});\n }\n\n private handleInputFailure(): void {\n if (!this.started || this.closing || this.closed) return;\n this.fail(new AgentError(\"HARNESS_FAILED\", \"The Cursor ACP input connection closed.\"));\n void this.close().catch(() => {});\n }\n\n private handleExit(): void {\n this.closed = true;\n if (this.closing) return this.rejectPending(closedError());\n this.fail(this.buffer.trim()\n ? protocolError()\n : new AgentError(\"HARNESS_FAILED\", \"Cursor ACP exited before the native operation completed.\"));\n void this.close().catch(() => {});\n }\n\n private rejectPending(error: AgentError): void {\n for (const pending of this.pending.values()) {\n if (pending.timer) clearTimeout(pending.timer);\n pending.reject(error);\n }\n this.pending.clear();\n }\n\n private fail(error: AgentError): void {\n if (this.failure) return;\n this.failure = error;\n this.rejectPending(error);\n this.failureHandler(error);\n }\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { SDKAgent, SDKModel } from "@cursor/sdk";
2
+ import type { AdapterOptions, NativeSession } from "./types.js";
3
+ import type { CursorTools } from "./cursor-tools.js";
4
+ export declare function createCursorSession(native: SDKAgent, selected: SDKModel, options: AdapterOptions, tools: CursorTools): NativeSession;
@@ -0,0 +1,327 @@
1
+ import { AgentError } from "../errors.js";
2
+ import { cursorTerminalText, isCursorTerminalStatus, validateCursorRunResult } from "./cursor-model.js";
3
+ const NATIVE_STOP_TIMEOUT_MS = 3_000;
4
+ export function createCursorSession(native, selected, options, tools) {
5
+ let closed = false;
6
+ let active;
7
+ let first = true;
8
+ let closing;
9
+ let sessionFailure;
10
+ const refreshTerminal = (current) => {
11
+ if (!current.run || current.terminalStatus)
12
+ return;
13
+ try {
14
+ if (isCursorTerminalStatus(current.run.status))
15
+ current.markTerminal(current.run.status);
16
+ }
17
+ catch { /* A verified status event or result is still required. */ }
18
+ };
19
+ const stopNative = async (current) => {
20
+ await bounded(current.runReady, NATIVE_STOP_TIMEOUT_MS, "Cursor did not expose the active native run for cancellation.");
21
+ if (!current.run) {
22
+ await tools.drain();
23
+ return;
24
+ }
25
+ refreshTerminal(current);
26
+ if (current.terminalStatus) {
27
+ await tools.drain();
28
+ return;
29
+ }
30
+ current.cancellation ??= Promise.resolve().then(() => current.run.cancel());
31
+ void current.cancellation.catch(() => { });
32
+ await tools.drain();
33
+ refreshTerminal(current);
34
+ if (current.terminalStatus)
35
+ return;
36
+ const cancellation = current.cancellation.then(() => ({ kind: "accepted" }), error => ({ kind: "rejected", error }));
37
+ const cancellationOutcome = await bounded(Promise.race([
38
+ cancellation,
39
+ current.terminal.then(() => ({ kind: "terminal" })),
40
+ ]), NATIVE_STOP_TIMEOUT_MS, "Cursor did not confirm the native cancellation request.");
41
+ if (cancellationOutcome.kind === "terminal")
42
+ return;
43
+ if (cancellationOutcome.kind === "rejected") {
44
+ refreshTerminal(current);
45
+ if (!current.terminalStatus)
46
+ throw cancellationOutcome.error instanceof AgentError
47
+ ? cancellationOutcome.error
48
+ : new AgentError("CANCELLATION_FAILED", "Cursor did not confirm native cancellation.");
49
+ return;
50
+ }
51
+ refreshTerminal(current);
52
+ if (!current.terminalStatus) {
53
+ await bounded(current.terminal, NATIVE_STOP_TIMEOUT_MS, "Cursor did not reach a terminal status after cancellation.");
54
+ }
55
+ };
56
+ const requestStop = (current) => {
57
+ if (!current.stopTask) {
58
+ current.stopTask = stopNative(current).catch(error => {
59
+ const failure = error instanceof AgentError && error.code === "CANCELLATION_FAILED"
60
+ ? error
61
+ : new AgentError("CANCELLATION_FAILED", "Cursor did not confirm native cancellation.");
62
+ current.stopFailure = failure;
63
+ sessionFailure = failure;
64
+ tools.stopAdmission();
65
+ throw failure;
66
+ });
67
+ void current.stopTask.catch(() => { });
68
+ }
69
+ current.signalStop();
70
+ return current.stopTask;
71
+ };
72
+ const watchRun = async (current, run) => {
73
+ try {
74
+ for await (const message of run.stream()) {
75
+ observeMessage(current, message);
76
+ }
77
+ refreshTerminal(current);
78
+ if (!current.terminalStatus && !current.interrupted && !current.closing) {
79
+ current.nativeFailure = new AgentError("NATIVE_ERROR", "Cursor native event delivery stopped before terminal completion.");
80
+ tools.stopAdmission();
81
+ void requestStop(current);
82
+ }
83
+ }
84
+ catch {
85
+ refreshTerminal(current);
86
+ if (!current.terminalStatus && !current.interrupted && !current.closing) {
87
+ current.nativeFailure = new AgentError("NATIVE_ERROR", "Cursor native event delivery failed.");
88
+ tools.stopAdmission();
89
+ void requestStop(current);
90
+ }
91
+ }
92
+ };
93
+ const bindRun = (current, run) => {
94
+ current.run = run;
95
+ try {
96
+ current.unsubscribe = run.onDidChangeStatus(status => {
97
+ if (isCursorTerminalStatus(status))
98
+ current.markTerminal(status);
99
+ });
100
+ refreshTerminal(current);
101
+ }
102
+ catch {
103
+ current.nativeFailure = new AgentError("NATIVE_ERROR", "Cursor native status observation failed.");
104
+ }
105
+ current.releaseRun();
106
+ void watchRun(current, run);
107
+ if (current.nativeFailure) {
108
+ tools.stopAdmission();
109
+ void requestStop(current);
110
+ }
111
+ };
112
+ const bindLateRun = (current, run) => {
113
+ current.run = run;
114
+ try {
115
+ current.unsubscribe = run.onDidChangeStatus(status => {
116
+ if (isCursorTerminalStatus(status))
117
+ current.markTerminal(status);
118
+ });
119
+ refreshTerminal(current);
120
+ }
121
+ catch { /* The poisoned session still owns and cancels the late run. */ }
122
+ current.releaseRun();
123
+ current.cancellation ??= Promise.resolve().then(() => run.cancel());
124
+ void current.cancellation.catch(() => { });
125
+ void watchRun(current, run).finally(() => current.unsubscribe?.());
126
+ };
127
+ const stoppedFailure = (current) => {
128
+ if (current.closing)
129
+ return new AgentError("SESSION_CLOSED", "The Cursor session closed during the turn.");
130
+ if (current.interrupted)
131
+ return new AgentError("INTERRUPTED", "The Cursor turn was interrupted.");
132
+ return current.nativeFailure ?? new AgentError("NATIVE_ERROR", "Cursor stopped without a native terminal result.");
133
+ };
134
+ const executeTurn = async (current, prompt) => {
135
+ tools.start();
136
+ try {
137
+ const includeInstructions = first;
138
+ const message = includeInstructions && options.agent.instructions
139
+ ? firstPrompt(options.agent.instructions, prompt)
140
+ : prompt;
141
+ const admission = Promise.resolve().then(() => native.send(message, { model: { id: selected.id } })).then(run => {
142
+ if (current.stopFailure)
143
+ bindLateRun(current, run);
144
+ else
145
+ bindRun(current, run);
146
+ if (includeInstructions)
147
+ first = false;
148
+ return { kind: "run", run };
149
+ }, error => {
150
+ current.releaseRun();
151
+ return { kind: "admission-failure", error };
152
+ });
153
+ const stopped = current.stopSignal.then(async () => {
154
+ try {
155
+ await current.stopTask;
156
+ return { kind: "stopped" };
157
+ }
158
+ catch (error) {
159
+ return { kind: "stop-failure", error };
160
+ }
161
+ });
162
+ const admitted = await Promise.race([admission, stopped]);
163
+ if (admitted.kind === "stop-failure")
164
+ throw admitted.error;
165
+ if (admitted.kind === "stopped")
166
+ throw stoppedFailure(current);
167
+ if (admitted.kind === "admission-failure")
168
+ throw admitted.error;
169
+ const waited = admitted.run.wait().then(result => ({ kind: "result", result }), () => ({ kind: "failure" }));
170
+ const outcome = await Promise.race([waited, stopped]);
171
+ if (outcome.kind === "stop-failure")
172
+ throw outcome.error;
173
+ if (outcome.kind === "stopped")
174
+ throw stoppedFailure(current);
175
+ if (outcome.kind === "failure") {
176
+ current.nativeFailure = new AgentError("NATIVE_ERROR", "Cursor native result delivery failed.");
177
+ tools.stopAdmission();
178
+ await requestStop(current);
179
+ throw stoppedFailure(current);
180
+ }
181
+ validateCursorRunResult(outcome.result);
182
+ current.markTerminal(outcome.result.status);
183
+ if (current.stopTask) {
184
+ await current.stopTask;
185
+ throw stoppedFailure(current);
186
+ }
187
+ return cursorTerminalText(outcome.result, selected);
188
+ }
189
+ catch (error) {
190
+ current.releaseRun();
191
+ if (error instanceof AgentError) {
192
+ if (error.code === "INVALID_CONFIG" || error.code === "CANCELLATION_FAILED")
193
+ sessionFailure = error;
194
+ throw error;
195
+ }
196
+ if (current.closing)
197
+ throw new AgentError("SESSION_CLOSED", "The Cursor session closed during the turn.");
198
+ if (current.interrupted)
199
+ throw new AgentError("INTERRUPTED", "The Cursor turn was interrupted.");
200
+ throw new AgentError("NATIVE_ERROR", "Cursor could not complete the turn.");
201
+ }
202
+ finally {
203
+ current.unsubscribe?.();
204
+ tools.stopAdmission();
205
+ await tools.drain();
206
+ if (active === current && !current.stopFailure)
207
+ active = undefined;
208
+ }
209
+ };
210
+ return {
211
+ async turn(prompt) {
212
+ if (closed)
213
+ throw new AgentError("SESSION_CLOSED", "The Cursor session has closed.");
214
+ if (sessionFailure)
215
+ throw sessionFailure;
216
+ if (active)
217
+ throw new AgentError("SESSION_BUSY", "Cursor already has an active turn.");
218
+ let releaseRun, markTerminal, signalStop;
219
+ const current = {
220
+ runReady: new Promise(resolve => { releaseRun = resolve; }),
221
+ releaseRun: () => releaseRun(),
222
+ terminal: new Promise(resolve => { markTerminal = resolve; }),
223
+ markTerminal(status) {
224
+ if (current.terminalStatus)
225
+ return;
226
+ current.terminalStatus = status;
227
+ markTerminal(status);
228
+ },
229
+ stopSignal: new Promise(resolve => { signalStop = resolve; }),
230
+ signalStop: () => signalStop(),
231
+ completion: undefined,
232
+ interrupted: false,
233
+ closing: false,
234
+ };
235
+ active = current;
236
+ current.completion = executeTurn(current, prompt);
237
+ return await current.completion;
238
+ },
239
+ async steer() { throw new AgentError("UNSUPPORTED_DELIVERY", "Cursor does not expose verified active steering."); },
240
+ async interrupt() {
241
+ const current = active;
242
+ if (!current)
243
+ return;
244
+ current.interrupted = true;
245
+ tools.stopAdmission();
246
+ try {
247
+ await requestStop(current);
248
+ }
249
+ catch (error) {
250
+ throw error instanceof AgentError ? error : new AgentError("CANCELLATION_FAILED", "Cursor did not confirm native cancellation.");
251
+ }
252
+ await current.completion.catch(() => { });
253
+ },
254
+ async resume() { throw new AgentError("RECOVERY_UNSUPPORTED", "Cursor cannot retry failed execution without replaying input."); },
255
+ async close() {
256
+ if (closing)
257
+ return await closing;
258
+ closed = true;
259
+ tools.stopAdmission();
260
+ const current = active;
261
+ if (current)
262
+ current.closing = true;
263
+ closing = (async () => {
264
+ const disposal = Promise.resolve().then(() => native[Symbol.asyncDispose]());
265
+ void disposal.catch(() => { });
266
+ let stopFailure;
267
+ if (current) {
268
+ try {
269
+ await requestStop(current);
270
+ }
271
+ catch (error) {
272
+ stopFailure = error;
273
+ }
274
+ }
275
+ else
276
+ await tools.drain();
277
+ try {
278
+ await bounded(disposal, NATIVE_STOP_TIMEOUT_MS, "Cursor did not confirm native session disposal.");
279
+ }
280
+ catch (error) {
281
+ if (error instanceof AgentError)
282
+ throw error;
283
+ throw new AgentError("CANCELLATION_FAILED", "Cursor did not confirm native session disposal.");
284
+ }
285
+ finally {
286
+ await tools.drain();
287
+ if (active === current)
288
+ active = undefined;
289
+ }
290
+ if (stopFailure)
291
+ throw stopFailure instanceof AgentError
292
+ ? stopFailure
293
+ : new AgentError("CANCELLATION_FAILED", "Cursor did not confirm native cancellation during close.");
294
+ if (current)
295
+ await current.completion.catch(() => { });
296
+ })();
297
+ return await closing;
298
+ },
299
+ };
300
+ }
301
+ function firstPrompt(instructions, prompt) {
302
+ return `<subharness-instructions>\n${instructions}\n</subharness-instructions>\n\n${prompt}`;
303
+ }
304
+ function observeMessage(current, message) {
305
+ if (message.type !== "status")
306
+ return;
307
+ const status = message.status === "FINISHED" ? "finished"
308
+ : message.status === "ERROR" ? "error"
309
+ : message.status === "CANCELLED" || message.status === "EXPIRED" ? "cancelled"
310
+ : undefined;
311
+ if (status)
312
+ current.markTerminal(status);
313
+ }
314
+ async function bounded(promise, milliseconds, message) {
315
+ let timer;
316
+ const timeout = new Promise((_resolve, reject) => {
317
+ timer = setTimeout(() => reject(new AgentError("CANCELLATION_FAILED", message)), milliseconds);
318
+ timer.unref();
319
+ });
320
+ try {
321
+ return await Promise.race([promise, timeout]);
322
+ }
323
+ finally {
324
+ clearTimeout(timer);
325
+ }
326
+ }
327
+ //# sourceMappingURL=cursor-session.js.map