@sideboard-ai/core 0.1.324 → 0.1.325

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 (83) hide show
  1. package/dist/{abletime-5ZY3ZUUO.js → abletime-M7STTMZT.js} +6 -5
  2. package/dist/{abletime-CU2UPMJF.js → abletime-VL234MCP.js} +5 -4
  3. package/dist/{abletime-oauth-7EOSBEFM.js → abletime-oauth-LMMGMAPA.js} +3 -3
  4. package/dist/{abletime-oauth-4TTCR3CT.js → abletime-oauth-P4ZFBEAL.js} +3 -3
  5. package/dist/{abletime-rest-3TG4G7LW.js → abletime-rest-DLV7EIWS.js} +3 -3
  6. package/dist/{abletime-rest-KOKE7V4B.js → abletime-rest-GOI7HELR.js} +3 -3
  7. package/dist/agents/claude-runner.cjs +59 -22
  8. package/dist/agents/claude-runner.js +39 -16
  9. package/dist/agents/cursor-runner.cjs +96 -31
  10. package/dist/agents/cursor-runner.js +74 -24
  11. package/dist/{agents-YK65UDLT.js → agents-LDRM3BTY.js} +9 -8
  12. package/dist/{agents-LUSTCMDN.js → agents-MBIEAETM.js} +12 -11
  13. package/dist/{app-settings-I5HM5RMP.js → app-settings-E7DMMEKC.js} +1 -1
  14. package/dist/{app-settings-XIF4EC4K.js → app-settings-UQHUNOLV.js} +1 -1
  15. package/dist/{chunk-INBUV7HY.js → chunk-2UP3XD2D.js} +2 -2
  16. package/dist/{chunk-EQ52JR3Q.js → chunk-5MXLDDYF.js} +1 -1
  17. package/dist/{chunk-NCHOTN3C.js → chunk-5YCKATG6.js} +4 -3
  18. package/dist/{chunk-BYUCNIXK.js → chunk-7G27TB4M.js} +6 -6
  19. package/dist/chunk-7LUOLYFM.js +1445 -0
  20. package/dist/{chunk-Y3WREIPQ.js → chunk-A76MKMSF.js} +12 -210
  21. package/dist/{chunk-JE3JLHMO.js → chunk-APKUI4BP.js} +3 -3
  22. package/dist/{chunk-FR3SAYUL.js → chunk-AQEKPJWU.js} +5 -5
  23. package/dist/{chunk-QOS4465Y.js → chunk-BOFYI6LC.js} +1 -1
  24. package/dist/{chunk-FUFNMUNR.js → chunk-BTF3ATST.js} +7 -8
  25. package/dist/{chunk-OIHRC2ZJ.js → chunk-CI4M54LS.js} +22 -2
  26. package/dist/chunk-DBKHL7NC.js +214 -0
  27. package/dist/{chunk-ROOZDDFA.js → chunk-EO6ZFLG6.js} +7 -8
  28. package/dist/chunk-EZR6W4B3.js +1259 -0
  29. package/dist/{chunk-MZIZTSR2.js → chunk-F65JMKUR.js} +2 -2
  30. package/dist/chunk-F6GE7V3Q.js +216 -0
  31. package/dist/{chunk-7MQSYPAY.js → chunk-GNLKBS3U.js} +206 -188
  32. package/dist/{chunk-EKU7FQVG.js → chunk-H36GKGU2.js} +2 -2
  33. package/dist/{chunk-7D5QIU3N.js → chunk-HG6KS7OT.js} +294 -265
  34. package/dist/chunk-MBT6WDAB.js +28 -0
  35. package/dist/{chunk-JH5SMVM5.js → chunk-MFMDZAA6.js} +262 -233
  36. package/dist/{chunk-7PVT73H6.js → chunk-NWGINMEA.js} +12 -210
  37. package/dist/{chunk-QIC2JXHW.js → chunk-OOXRMTU6.js} +1 -1
  38. package/dist/{chunk-5XNT6BCG.js → chunk-OPXEJJBM.js} +1 -1
  39. package/dist/chunk-OYRN356W.js +80 -0
  40. package/dist/chunk-PPTJMBUY.js +25 -0
  41. package/dist/{chunk-B4CDSSRN.js → chunk-Q3FHTGIW.js} +2 -0
  42. package/dist/{chunk-EJ66LEKH.js → chunk-RZJTGBXY.js} +22 -2
  43. package/dist/{chunk-DF5BM5OY.js → chunk-SACHHTBJ.js} +207 -186
  44. package/dist/{chunk-5GDJSFCT.js → chunk-SK6NYGPD.js} +2 -2
  45. package/dist/{chunk-74OPNF7U.js → chunk-SQQBU7Z6.js} +2 -2
  46. package/dist/{chunk-Q3YJZPQI.js → chunk-SS6CYGLF.js} +3 -3
  47. package/dist/{chunk-YDUHLWI5.js → chunk-SUZOPJZC.js} +21 -7
  48. package/dist/{chunk-ZHGMRBSC.js → chunk-U5WO6MEB.js} +3 -3
  49. package/dist/{chunk-NXUN4U5P.js → chunk-VAFQS4D2.js} +2 -2
  50. package/dist/chunk-W3ZLE4PO.js +77 -0
  51. package/dist/{chunk-RR4WCGNB.js → chunk-WYEST76H.js} +7 -7
  52. package/dist/{chunk-ODH3XHMI.js → chunk-ZEUMWHOH.js} +5 -5
  53. package/dist/{chunk-ZIRQZUZY.js → chunk-ZHDXLDLA.js} +3 -3
  54. package/dist/{chunk-IFWGG2M2.js → chunk-ZSHS46V5.js} +2 -0
  55. package/dist/{conductor-JFABMXDA.js → conductor-D4KFZF54.js} +6 -6
  56. package/dist/{conductor-SPZOTC7W.js → conductor-KB7L7NQN.js} +7 -7
  57. package/dist/{coordinator-prompt-K66RGNWK.js → coordinator-prompt-OBXEC63K.js} +4 -4
  58. package/dist/{coordinator-prompt-Z6UFHFDH.js → coordinator-prompt-SUO4FRY3.js} +4 -4
  59. package/dist/{cursor-recover-TEBFKAZ4.js → cursor-recover-7F46PAJ5.js} +1 -1
  60. package/dist/{cursor-recover-OWPQUHFH.js → cursor-recover-BDIAZIE3.js} +1 -1
  61. package/dist/{global-workspace-A6UO6PJV.js → global-workspace-UHU2FXTY.js} +4 -4
  62. package/dist/{global-workspace-RHEO55B4.js → global-workspace-Z2SURNHA.js} +4 -4
  63. package/dist/index.cjs +21112 -20864
  64. package/dist/index.d.cts +25 -9
  65. package/dist/index.d.ts +25 -9
  66. package/dist/index.js +343 -1678
  67. package/dist/linear-HFUOUJ5H.js +67 -0
  68. package/dist/linear-SIHEBU3X.js +69 -0
  69. package/dist/linear-list-63I7QUC6.js +6 -0
  70. package/dist/linear-list-JFV3EES6.js +8 -0
  71. package/dist/mcp/run-stdio.cjs +15654 -15398
  72. package/dist/mcp/run-stdio.js +67 -1247
  73. package/dist/{optional-cli-RMMS5L6F.js → optional-cli-U2GUA2X6.js} +3 -3
  74. package/dist/{optional-cli-Y3Z3GIPZ.js → optional-cli-ULDP3O5S.js} +4 -4
  75. package/dist/{orchestrator-7VTAUY24.js → orchestrator-3H4KNGPN.js} +15 -13
  76. package/dist/{orchestrator-2O6OJQLX.js → orchestrator-6ROMEWBP.js} +14 -12
  77. package/dist/{thread-store-3F7GR64A.js → thread-store-4ZN3DS2W.js} +1 -1
  78. package/dist/{thread-store-JRSL4HQY.js → thread-store-IC4BQXDW.js} +1 -1
  79. package/dist/{workspaces-NRKEXOYR.js → workspaces-MG5JHRKW.js} +4 -4
  80. package/dist/{workspaces-42E6AGXD.js → workspaces-QJNKEGEM.js} +4 -4
  81. package/dist/{worktree-ZDA2UJ7C.js → worktree-KSJPTHGZ.js} +3 -3
  82. package/dist/{worktree-4NGXCCUO.js → worktree-MYJYUHZM.js} +3 -3
  83. package/package.json +1 -1
@@ -19,12 +19,13 @@ import {
19
19
  toAbleTimeIssueInfo,
20
20
  updateAbleTimeTask,
21
21
  verifyAbleTimeConnection
22
- } from "./chunk-Y3WREIPQ.js";
23
- import "./chunk-NXUN4U5P.js";
24
- import "./chunk-FR3SAYUL.js";
25
- import "./chunk-2GPQZZLY.js";
22
+ } from "./chunk-A76MKMSF.js";
23
+ import "./chunk-VAFQS4D2.js";
24
+ import "./chunk-AQEKPJWU.js";
25
+ import "./chunk-F6GE7V3Q.js";
26
26
  import "./chunk-N2WW62LF.js";
27
- import "./chunk-OIHRC2ZJ.js";
27
+ import "./chunk-2GPQZZLY.js";
28
+ import "./chunk-CI4M54LS.js";
28
29
  import "./chunk-NSTQ6QKD.js";
29
30
  import "./chunk-WWUABK6B.js";
30
31
  import "./chunk-FJZWM2ON.js";
@@ -17,12 +17,13 @@ import {
17
17
  toAbleTimeIssueInfo,
18
18
  updateAbleTimeTask,
19
19
  verifyAbleTimeConnection
20
- } from "./chunk-7PVT73H6.js";
21
- import "./chunk-EKU7FQVG.js";
22
- import "./chunk-ODH3XHMI.js";
20
+ } from "./chunk-NWGINMEA.js";
21
+ import "./chunk-DBKHL7NC.js";
22
+ import "./chunk-H36GKGU2.js";
23
+ import "./chunk-ZEUMWHOH.js";
23
24
  import "./chunk-JAT3JFOS.js";
24
25
  import "./chunk-6K64FJDD.js";
25
- import "./chunk-EJ66LEKH.js";
26
+ import "./chunk-RZJTGBXY.js";
26
27
  import "./chunk-77WWLBCI.js";
27
28
  import "./chunk-4TR3HZFT.js";
28
29
  import "./chunk-WDRMZKVB.js";
@@ -20,10 +20,10 @@ import {
20
20
  parseAbleTimeOAuthCallbackUrl,
21
21
  resolveAbleTimeOAuthHost,
22
22
  startAbleTimeOAuth
23
- } from "./chunk-Q3YJZPQI.js";
24
- import "./chunk-ODH3XHMI.js";
23
+ } from "./chunk-SS6CYGLF.js";
24
+ import "./chunk-ZEUMWHOH.js";
25
25
  import "./chunk-JAT3JFOS.js";
26
- import "./chunk-EJ66LEKH.js";
26
+ import "./chunk-RZJTGBXY.js";
27
27
  import "./chunk-77WWLBCI.js";
28
28
  import "./chunk-4TR3HZFT.js";
29
29
  import "./chunk-WDRMZKVB.js";
@@ -3,7 +3,7 @@
3
3
  import {
4
4
  DEFAULT_ABLETIME_HOST,
5
5
  normalizeAbleTimeHost
6
- } from "./chunk-FR3SAYUL.js";
6
+ } from "./chunk-AQEKPJWU.js";
7
7
  import {
8
8
  httpFetch
9
9
  } from "./chunk-2GPQZZLY.js";
@@ -12,7 +12,7 @@ import {
12
12
  getAbleTimeHost,
13
13
  loadAppSettings,
14
14
  saveAbleTimeConnection
15
- } from "./chunk-OIHRC2ZJ.js";
15
+ } from "./chunk-CI4M54LS.js";
16
16
  import "./chunk-NSTQ6QKD.js";
17
17
  import "./chunk-WWUABK6B.js";
18
18
  import "./chunk-FJZWM2ON.js";
@@ -288,7 +288,7 @@ async function startAbleTimeOAuth(opts) {
288
288
  persistAbleTimeTokens(data, { host });
289
289
  const token = data.access_token.trim();
290
290
  try {
291
- const { getAbleTimeOrientation } = await import("./abletime-5ZY3ZUUO.js");
291
+ const { getAbleTimeOrientation } = await import("./abletime-M7STTMZT.js");
292
292
  const orientation = await getAbleTimeOrientation({ token, host });
293
293
  return saveAbleTimeConnection({
294
294
  accessToken: token,
@@ -7,10 +7,10 @@ import {
7
7
  callAbleTimeRestTool,
8
8
  looksLikeAbleTimeUlid,
9
9
  textFromAbleTimeDoc
10
- } from "./chunk-NXUN4U5P.js";
11
- import "./chunk-FR3SAYUL.js";
10
+ } from "./chunk-VAFQS4D2.js";
11
+ import "./chunk-AQEKPJWU.js";
12
12
  import "./chunk-2GPQZZLY.js";
13
- import "./chunk-OIHRC2ZJ.js";
13
+ import "./chunk-CI4M54LS.js";
14
14
  import "./chunk-NSTQ6QKD.js";
15
15
  import "./chunk-WWUABK6B.js";
16
16
  import "./chunk-FJZWM2ON.js";
@@ -5,10 +5,10 @@ import {
5
5
  callAbleTimeRestTool,
6
6
  looksLikeAbleTimeUlid,
7
7
  textFromAbleTimeDoc
8
- } from "./chunk-EKU7FQVG.js";
9
- import "./chunk-ODH3XHMI.js";
8
+ } from "./chunk-H36GKGU2.js";
9
+ import "./chunk-ZEUMWHOH.js";
10
10
  import "./chunk-JAT3JFOS.js";
11
- import "./chunk-EJ66LEKH.js";
11
+ import "./chunk-RZJTGBXY.js";
12
12
  import "./chunk-77WWLBCI.js";
13
13
  import "./chunk-4TR3HZFT.js";
14
14
  import "./chunk-WDRMZKVB.js";
@@ -166,6 +166,8 @@ function agentRuntimeLooksLive(meta = readAgentRuntimeMetadata()) {
166
166
  // src/agent-rpc/client.ts
167
167
  var AgentRpcClient = class {
168
168
  ws = null;
169
+ /** In-flight connect. Concurrent call()s must share it or each opens a socket. */
170
+ connecting = null;
169
171
  pending = /* @__PURE__ */ new Map();
170
172
  nextId = 1;
171
173
  url;
@@ -208,10 +210,10 @@ var AgentRpcClient = class {
208
210
  url.searchParams.set(AGENT_RPC_TOKEN_QUERY, this.authToken);
209
211
  return url.toString();
210
212
  }
211
- async ensureSocket() {
212
- if (this.ws && this.ws.readyState === import_ws.WebSocket.OPEN) return this.ws;
213
+ ensureSocket() {
214
+ if (this.ws && this.ws.readyState === import_ws.WebSocket.OPEN) return Promise.resolve(this.ws);
215
+ if (this.connecting) return this.connecting;
213
216
  const ws = new import_ws.WebSocket(this.socketUrl());
214
- this.ws = ws;
215
217
  ws.on("message", (data) => this.onFrame(data.toString()));
216
218
  ws.on("error", (err) => this.drop(ws, err));
217
219
  ws.on("close", () => this.drop(ws, new Error("Agent RPC socket closed")));
@@ -224,11 +226,16 @@ var AgentRpcClient = class {
224
226
  )
225
227
  );
226
228
  });
227
- await new Promise((resolve, reject) => {
229
+ let settled = false;
230
+ const pending = new Promise((resolve, reject) => {
228
231
  const fail = (err) => {
232
+ if (settled) return;
233
+ settled = true;
234
+ if (this.connecting === pending) this.connecting = null;
229
235
  const message = err.message.includes("401") ? "Unauthorized" : err.message;
230
236
  reject(message === err.message ? err : new Error(message));
231
237
  };
238
+ const failClose = () => fail(new Error("Agent RPC socket closed"));
232
239
  ws.once("unexpected-response", (_req, res) => {
233
240
  fail(
234
241
  new Error(
@@ -237,15 +244,22 @@ var AgentRpcClient = class {
237
244
  );
238
245
  });
239
246
  ws.once("error", fail);
247
+ ws.once("close", failClose);
240
248
  ws.once("open", () => {
241
249
  ws.off("error", fail);
242
- resolve();
250
+ ws.off("close", failClose);
251
+ settled = true;
252
+ this.ws = ws;
253
+ this.connecting = null;
254
+ resolve(ws);
243
255
  });
244
256
  });
245
- return ws;
257
+ this.connecting = pending;
258
+ return pending;
246
259
  }
247
260
  drop(ws, err) {
248
- if (this.ws === ws) this.ws = null;
261
+ if (this.ws !== ws) return;
262
+ this.ws = null;
249
263
  if (this.pending.size === 0) return;
250
264
  this.failAll(err);
251
265
  }
@@ -485,6 +499,31 @@ async function claudePermissionResult(input) {
485
499
  }
486
500
  }
487
501
 
502
+ // src/agents/claude-query-options.ts
503
+ function buildClaudeSdkQueryOptions(req, mcpServers, abortController) {
504
+ const options = {
505
+ cwd: req.cwd,
506
+ pathToClaudeCodeExecutable: req.claudePath,
507
+ permissionMode: req.permissionMode,
508
+ ...req.permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {},
509
+ allowedTools: req.allowedTools,
510
+ mcpServers,
511
+ includePartialMessages: true,
512
+ strictMcpConfig: true,
513
+ systemPrompt: {
514
+ type: "preset",
515
+ preset: "claude_code",
516
+ ...req.systemPrompt ? { append: req.systemPrompt } : {}
517
+ },
518
+ abortController
519
+ };
520
+ if (req.sessionId) options.resume = req.sessionId;
521
+ if (req.model) options.model = req.model;
522
+ if (req.effort) options.effort = req.effort;
523
+ if (req.chrome) options.extraArgs = { chrome: null };
524
+ return options;
525
+ }
526
+
488
527
  // src/agents/claude-runner.ts
489
528
  dropNestedElectronEnvFromProcess();
490
529
  function emit(value) {
@@ -533,21 +572,17 @@ async function main() {
533
572
  for (const [name, spec] of Object.entries(req.mcpServers ?? {})) {
534
573
  mcpServers[name] = spec;
535
574
  }
575
+ const abortController = new AbortController();
576
+ let stopped = false;
577
+ const onStop = () => {
578
+ stopped = true;
579
+ abortController.abort();
580
+ setTimeout(() => process.exit(130), 3e3).unref();
581
+ };
582
+ process.once("SIGTERM", onStop);
583
+ process.once("SIGINT", onStop);
536
584
  try {
537
- const options = {
538
- cwd: req.cwd,
539
- pathToClaudeCodeExecutable: req.claudePath,
540
- permissionMode: req.permissionMode,
541
- ...req.permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {},
542
- allowedTools: req.allowedTools,
543
- mcpServers,
544
- includePartialMessages: true
545
- };
546
- if (req.sessionId) options.resume = req.sessionId;
547
- if (req.model) options.model = req.model;
548
- if (req.systemPrompt) options.appendSystemPrompt = req.systemPrompt;
549
- if (req.effort) options.effort = req.effort;
550
- if (req.chrome) options.chrome = true;
585
+ const options = buildClaudeSdkQueryOptions(req, mcpServers, abortController);
551
586
  options.canUseTool = (toolName, toolInput, toolOpts) => claudePermissionResult({
552
587
  permissionMode: req.permissionMode,
553
588
  threadId: process.env.SIDEBOARD_THREAD_ID?.trim() || "",
@@ -558,11 +593,13 @@ async function main() {
558
593
  options: toolOpts,
559
594
  rpc: req.agentRpc
560
595
  });
561
- options.settingSources = [];
562
596
  for await (const message of sdk.query({ prompt: req.prompt, options })) {
563
597
  emit(message);
564
598
  }
599
+ if (stopped) process.exitCode = 130;
565
600
  } finally {
601
+ process.off("SIGTERM", onStop);
602
+ process.off("SIGINT", onStop);
566
603
  exec.close();
567
604
  }
568
605
  }
@@ -9,7 +9,7 @@ import {
9
9
  AgentRpcClient,
10
10
  PILOT_TOOL_DESCRIPTIONS,
11
11
  createPilotRpcExecutors
12
- } from "../chunk-YDUHLWI5.js";
12
+ } from "../chunk-SUZOPJZC.js";
13
13
  import {
14
14
  dropNestedElectronEnvFromProcess
15
15
  } from "../chunk-4TR3HZFT.js";
@@ -131,6 +131,31 @@ async function claudePermissionResult(input) {
131
131
  }
132
132
  }
133
133
 
134
+ // src/agents/claude-query-options.ts
135
+ function buildClaudeSdkQueryOptions(req, mcpServers, abortController) {
136
+ const options = {
137
+ cwd: req.cwd,
138
+ pathToClaudeCodeExecutable: req.claudePath,
139
+ permissionMode: req.permissionMode,
140
+ ...req.permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {},
141
+ allowedTools: req.allowedTools,
142
+ mcpServers,
143
+ includePartialMessages: true,
144
+ strictMcpConfig: true,
145
+ systemPrompt: {
146
+ type: "preset",
147
+ preset: "claude_code",
148
+ ...req.systemPrompt ? { append: req.systemPrompt } : {}
149
+ },
150
+ abortController
151
+ };
152
+ if (req.sessionId) options.resume = req.sessionId;
153
+ if (req.model) options.model = req.model;
154
+ if (req.effort) options.effort = req.effort;
155
+ if (req.chrome) options.extraArgs = { chrome: null };
156
+ return options;
157
+ }
158
+
134
159
  // src/agents/claude-runner.ts
135
160
  dropNestedElectronEnvFromProcess();
136
161
  function emit(value) {
@@ -179,21 +204,17 @@ async function main() {
179
204
  for (const [name, spec] of Object.entries(req.mcpServers ?? {})) {
180
205
  mcpServers[name] = spec;
181
206
  }
207
+ const abortController = new AbortController();
208
+ let stopped = false;
209
+ const onStop = () => {
210
+ stopped = true;
211
+ abortController.abort();
212
+ setTimeout(() => process.exit(130), 3e3).unref();
213
+ };
214
+ process.once("SIGTERM", onStop);
215
+ process.once("SIGINT", onStop);
182
216
  try {
183
- const options = {
184
- cwd: req.cwd,
185
- pathToClaudeCodeExecutable: req.claudePath,
186
- permissionMode: req.permissionMode,
187
- ...req.permissionMode === "bypassPermissions" ? { allowDangerouslySkipPermissions: true } : {},
188
- allowedTools: req.allowedTools,
189
- mcpServers,
190
- includePartialMessages: true
191
- };
192
- if (req.sessionId) options.resume = req.sessionId;
193
- if (req.model) options.model = req.model;
194
- if (req.systemPrompt) options.appendSystemPrompt = req.systemPrompt;
195
- if (req.effort) options.effort = req.effort;
196
- if (req.chrome) options.chrome = true;
217
+ const options = buildClaudeSdkQueryOptions(req, mcpServers, abortController);
197
218
  options.canUseTool = (toolName, toolInput, toolOpts) => claudePermissionResult({
198
219
  permissionMode: req.permissionMode,
199
220
  threadId: process.env.SIDEBOARD_THREAD_ID?.trim() || "",
@@ -204,11 +225,13 @@ async function main() {
204
225
  options: toolOpts,
205
226
  rpc: req.agentRpc
206
227
  });
207
- options.settingSources = [];
208
228
  for await (const message of sdk.query({ prompt: req.prompt, options })) {
209
229
  emit(message);
210
230
  }
231
+ if (stopped) process.exitCode = 130;
211
232
  } finally {
233
+ process.off("SIGTERM", onStop);
234
+ process.off("SIGINT", onStop);
212
235
  exec.close();
213
236
  }
214
237
  }
@@ -359,10 +359,20 @@ async function acquireCursorCatalogLock(storeDir) {
359
359
  try {
360
360
  return await import_proper_lockfile.default.lock(lockPath, {
361
361
  retries: { retries: 40, minTimeout: 50, maxTimeout: 500 },
362
- stale: 5e3,
363
- update: 2e3
362
+ // Repair rewrites run_events.ndjson synchronously while holding the lock.
363
+ // A 5s stale window treats that stall as a dead owner and throws from a
364
+ // timer, which kills the runner mid-turn.
365
+ stale: 3e4,
366
+ update: 1e4,
367
+ onCompromised: (err) => {
368
+ console.error(`[sideboard] cursor catalog lock compromised: ${err.message}`);
369
+ }
364
370
  });
365
- } catch {
371
+ } catch (err) {
372
+ const message = err instanceof Error ? err.message : String(err);
373
+ console.error(
374
+ `[sideboard] cursor catalog lock not acquired (${message}); continuing without the lock`
375
+ );
366
376
  return async () => {
367
377
  };
368
378
  }
@@ -695,7 +705,7 @@ function extractJsonErrorMessage(obj) {
695
705
  const candidates = [
696
706
  typeof obj.message === "string" ? obj.message : null,
697
707
  typeof obj.error === "string" ? obj.error : null,
698
- nested && typeof nested.message === "string" ? nested.message : null,
708
+ nested && typeof nested.message === "string" ? nested.message : typeof nested?.data?.message === "string" ? nested.data.message : null,
699
709
  typeof obj.result === "string" ? obj.result : null,
700
710
  typeof obj.detail === "string" ? obj.detail : null
701
711
  ];
@@ -800,8 +810,8 @@ function isUnresumableCursorSession(err) {
800
810
  if (name === "AgentNotFoundError") return true;
801
811
  const lower = cursorErrorMessage(err).toLowerCase();
802
812
  if (!lower) return false;
803
- return /corrupt local agent checkpoint/.test(lower) || /missing root blob/.test(lower) || /\bagent\b.{0,120}\bnot found\b/.test(lower) || // Shared JSONL last-write-wins: `Run run-… not found for agent agent-…`
804
- /\brun\b.{0,80}\bnot found for agent\b/.test(lower) || /cannot resume/.test(lower);
813
+ return /corrupt local agent checkpoint/.test(lower) || /missing root blob/.test(lower) || /\bagent\s+agent-[\w-]+\s+not found\b/.test(lower) || // Shared JSONL last-write-wins: `Run run-… not found for agent agent-…`
814
+ /\brun\s+run-[\w-]+\s+not found for agent\b/.test(lower) || /cannot resume/.test(lower);
805
815
  }
806
816
  function cursorSessionRecoveryMessage(err, agentId) {
807
817
  const detail = cursorErrorMessage(err) || "unresumable session";
@@ -842,13 +852,20 @@ async function retryOnceOnRetryableCursorError(fn, onRetry, delayMs = CURSOR_RET
842
852
  return fn();
843
853
  }
844
854
  }
845
- function cursorSendOptions(mcpServers) {
846
- const opts = { local: { force: true } };
855
+ function cursorSendOptions(mcpServers, mode) {
856
+ const opts = {
857
+ local: { force: true }
858
+ };
859
+ if (mode) opts.mode = mode;
847
860
  if (mcpServers && typeof mcpServers === "object" && Object.keys(mcpServers).length > 0) {
848
861
  opts.mcpServers = mcpServers;
849
862
  }
850
863
  return opts;
851
864
  }
865
+ function cursorDisallowedTools(planMode) {
866
+ if (planMode) return ["read", "shell", "edit", "write", "delete", "task"];
867
+ return ["read"];
868
+ }
852
869
  function withCursorLocalHangGuards(local) {
853
870
  return { ...local, enableAgentRetries: false };
854
871
  }
@@ -889,6 +906,30 @@ async function* iterateUntilIdle(iterable, idleMs, onIdle, activity) {
889
906
  throw err;
890
907
  }
891
908
  }
909
+ function exitWhenFlushed(code) {
910
+ let pending = 2;
911
+ let exited = false;
912
+ const finish = () => {
913
+ pending -= 1;
914
+ if (pending > 0 || exited) return;
915
+ exited = true;
916
+ process.exit(code);
917
+ };
918
+ const flush = (stream) => {
919
+ if (stream.writableEnded) {
920
+ finish();
921
+ return;
922
+ }
923
+ stream.write("", finish);
924
+ };
925
+ flush(process.stdout);
926
+ flush(process.stderr);
927
+ setTimeout(() => {
928
+ if (exited) return;
929
+ exited = true;
930
+ process.exit(code);
931
+ }, 1e3).unref();
932
+ }
892
933
 
893
934
  // src/agents/sliced-file-read.ts
894
935
  var import_node_fs15 = require("fs");
@@ -1105,6 +1146,8 @@ function agentRuntimeLooksLive(meta = readAgentRuntimeMetadata()) {
1105
1146
  // src/agent-rpc/client.ts
1106
1147
  var AgentRpcClient = class {
1107
1148
  ws = null;
1149
+ /** In-flight connect. Concurrent call()s must share it or each opens a socket. */
1150
+ connecting = null;
1108
1151
  pending = /* @__PURE__ */ new Map();
1109
1152
  nextId = 1;
1110
1153
  url;
@@ -1147,10 +1190,10 @@ var AgentRpcClient = class {
1147
1190
  url.searchParams.set(AGENT_RPC_TOKEN_QUERY, this.authToken);
1148
1191
  return url.toString();
1149
1192
  }
1150
- async ensureSocket() {
1151
- if (this.ws && this.ws.readyState === import_ws.WebSocket.OPEN) return this.ws;
1193
+ ensureSocket() {
1194
+ if (this.ws && this.ws.readyState === import_ws.WebSocket.OPEN) return Promise.resolve(this.ws);
1195
+ if (this.connecting) return this.connecting;
1152
1196
  const ws = new import_ws.WebSocket(this.socketUrl());
1153
- this.ws = ws;
1154
1197
  ws.on("message", (data) => this.onFrame(data.toString()));
1155
1198
  ws.on("error", (err) => this.drop(ws, err));
1156
1199
  ws.on("close", () => this.drop(ws, new Error("Agent RPC socket closed")));
@@ -1163,11 +1206,16 @@ var AgentRpcClient = class {
1163
1206
  )
1164
1207
  );
1165
1208
  });
1166
- await new Promise((resolve2, reject) => {
1209
+ let settled = false;
1210
+ const pending = new Promise((resolve2, reject) => {
1167
1211
  const fail = (err) => {
1212
+ if (settled) return;
1213
+ settled = true;
1214
+ if (this.connecting === pending) this.connecting = null;
1168
1215
  const message = err.message.includes("401") ? "Unauthorized" : err.message;
1169
1216
  reject(message === err.message ? err : new Error(message));
1170
1217
  };
1218
+ const failClose = () => fail(new Error("Agent RPC socket closed"));
1171
1219
  ws.once("unexpected-response", (_req, res) => {
1172
1220
  fail(
1173
1221
  new Error(
@@ -1176,15 +1224,22 @@ var AgentRpcClient = class {
1176
1224
  );
1177
1225
  });
1178
1226
  ws.once("error", fail);
1227
+ ws.once("close", failClose);
1179
1228
  ws.once("open", () => {
1180
1229
  ws.off("error", fail);
1181
- resolve2();
1230
+ ws.off("close", failClose);
1231
+ settled = true;
1232
+ this.ws = ws;
1233
+ this.connecting = null;
1234
+ resolve2(ws);
1182
1235
  });
1183
1236
  });
1184
- return ws;
1237
+ this.connecting = pending;
1238
+ return pending;
1185
1239
  }
1186
1240
  drop(ws, err) {
1187
- if (this.ws === ws) this.ws = null;
1241
+ if (this.ws !== ws) return;
1242
+ this.ws = null;
1188
1243
  if (this.pending.size === 0) return;
1189
1244
  this.failAll(err);
1190
1245
  }
@@ -1474,13 +1529,14 @@ function guardCursorCustomTool(tool, opts) {
1474
1529
  };
1475
1530
  }
1476
1531
  var NON_RECOVERABLE_RUN_ERROR = /invalid (?:user )?api key|not logged in|not authenticated|unauthorized|credit balance|out of credits|insufficient.?quota|usage limit|you've hit your|too many requests|rate.?limit/;
1532
+ var RECOVERABLE_RUN_ERROR = /premature close|tool execution failed|stream (?:idle|cut ?off|closed)|custom tool|result too (?:large|long)|max(?:imum)? (?:tool )?result/;
1477
1533
  function shouldReturnRunErrorToAgent(detail) {
1478
1534
  const text = detail.trim();
1479
1535
  if (!text) return false;
1480
1536
  if (looksLikeHugeToolResultDump(text) || looksLikeCursorStreamCutOff(text)) return true;
1481
1537
  const head = text.slice(0, 2e3).toLowerCase();
1482
1538
  if (NON_RECOVERABLE_RUN_ERROR.test(head)) return false;
1483
- return true;
1539
+ return RECOVERABLE_RUN_ERROR.test(head);
1484
1540
  }
1485
1541
  function cursorRunErrorRecoveryPrompt(detail) {
1486
1542
  const summary = looksLikeHugeToolResultDump(detail) ? HUGE_TOOL_RESULT_SUMMARY : detail.replace(/\s+/g, " ").trim().slice(0, 400);
@@ -1561,7 +1617,8 @@ function preferredCursorCostCents(cost) {
1561
1617
  }
1562
1618
  function turnCostUsdFromCursorUsage(before, after) {
1563
1619
  if (!after) return void 0;
1564
- const beforeIds = new Set((before?.runs ?? []).map((r) => r.runId));
1620
+ if (before == null) return void 0;
1621
+ const beforeIds = new Set((before.runs ?? []).map((r) => r.runId));
1565
1622
  const newRuns = (after.runs ?? []).filter((r) => !beforeIds.has(r.runId));
1566
1623
  let sum = 0;
1567
1624
  let any = false;
@@ -1573,7 +1630,6 @@ function turnCostUsdFromCursorUsage(before, after) {
1573
1630
  }
1574
1631
  }
1575
1632
  if (any) return sum / 100;
1576
- if (before == null) return void 0;
1577
1633
  const afterCents = preferredCursorCostCents(after.cost);
1578
1634
  if (afterCents == null) return void 0;
1579
1635
  const beforeCents = preferredCursorCostCents(before.cost) ?? 0;
@@ -2010,7 +2066,7 @@ async function main() {
2010
2066
  mode,
2011
2067
  local,
2012
2068
  name: "Sideboard",
2013
- disallowedTools: ["read"],
2069
+ disallowedTools: cursorDisallowedTools(req.planMode),
2014
2070
  ...mcpServers ? { mcpServers } : {}
2015
2071
  };
2016
2072
  const retryTransport = (fn) => retryOnceOnRetryableCursorError(fn, (err) => {
@@ -2023,14 +2079,18 @@ async function main() {
2023
2079
  const { name: _name, ...opts } = createOpts;
2024
2080
  return retryTransport(() => Agent.resume(agentId, opts));
2025
2081
  }
2082
+ function promptForNewSession() {
2083
+ return req.freshPrompt?.trim() || req.prompt;
2084
+ }
2026
2085
  async function openAgent() {
2027
2086
  try {
2028
- return req.agentId ? await resumeAgent(req.agentId) : await createAgent();
2087
+ if (!req.agentId) return { agent: await createAgent(), fresh: true };
2088
+ return { agent: await resumeAgent(req.agentId), fresh: false };
2029
2089
  } catch (err) {
2030
2090
  if (!isUnresumableCursorSession(err)) throw err;
2031
2091
  if (repairCursorCatalogForResume(storeRoot, note) && req.agentId) {
2032
2092
  try {
2033
- return await resumeAgent(req.agentId);
2093
+ return { agent: await resumeAgent(req.agentId), fresh: false };
2034
2094
  } catch (err2) {
2035
2095
  if (!isUnresumableCursorSession(err2)) throw err2;
2036
2096
  }
@@ -2039,7 +2099,7 @@ async function main() {
2039
2099
  type: "stderr",
2040
2100
  data: cursorSessionRecoveryMessage(err, req.agentId)
2041
2101
  });
2042
- return createAgent();
2102
+ return { agent: await createAgent(), fresh: true };
2043
2103
  }
2044
2104
  }
2045
2105
  async function retryAfterBusy(agent) {
@@ -2058,7 +2118,7 @@ async function main() {
2058
2118
  }
2059
2119
  async function sendPrompt(agent, prompt, extra) {
2060
2120
  const sendOpts = {
2061
- ...cursorSendOptions(mcpServers),
2121
+ ...cursorSendOptions(mcpServers, mode),
2062
2122
  ...extra
2063
2123
  };
2064
2124
  try {
@@ -2089,7 +2149,7 @@ async function main() {
2089
2149
  setTimeout(resolve2, 2e3);
2090
2150
  })
2091
2151
  ]).finally(() => {
2092
- void closeCursorCatalogTurn().finally(() => process.exit(1));
2152
+ void closeCursorCatalogTurn().finally(() => exitWhenFlushed(1));
2093
2153
  });
2094
2154
  };
2095
2155
  process.once("SIGTERM", onSignal);
@@ -2175,7 +2235,10 @@ async function main() {
2175
2235
  });
2176
2236
  return 2;
2177
2237
  }
2178
- if (result.status === "cancelled") return 0;
2238
+ if (result.status === "cancelled") {
2239
+ if (streamIdle) return 1;
2240
+ return 0;
2241
+ }
2179
2242
  try {
2180
2243
  const costUsd = await fetchCursorTurnCostUsd(
2181
2244
  (opts) => agent.getUsage(opts),
@@ -2194,14 +2257,16 @@ async function main() {
2194
2257
  }
2195
2258
  }
2196
2259
  try {
2197
- let agent = await openAgent();
2260
+ const opened = await openAgent();
2261
+ let agent = opened.agent;
2262
+ const prompt = opened.fresh ? promptForNewSession() : req.prompt;
2198
2263
  try {
2199
2264
  try {
2200
- return await runTurn(agent);
2265
+ return await runTurn(agent, prompt);
2201
2266
  } catch (err) {
2202
2267
  if (isAgentBusyError(err)) {
2203
2268
  await retryAfterBusy(agent);
2204
- return await runTurn(agent);
2269
+ return await runTurn(agent, prompt);
2205
2270
  }
2206
2271
  if (!isUnresumableCursorSession(err)) throw err;
2207
2272
  const agentId = agent.agentId;
@@ -2220,7 +2285,7 @@ async function main() {
2220
2285
  data: cursorSessionRecoveryMessage(err, agentId)
2221
2286
  });
2222
2287
  agent = await createAgent();
2223
- return await runTurn(agent);
2288
+ return await runTurn(agent, promptForNewSession());
2224
2289
  }
2225
2290
  } finally {
2226
2291
  await agent[Symbol.asyncDispose]().catch(() => void 0);
@@ -2241,9 +2306,9 @@ async function main() {
2241
2306
  }
2242
2307
  }
2243
2308
  main().then(
2244
- (code) => process.exit(code),
2309
+ (code) => exitWhenFlushed(code),
2245
2310
  (err) => {
2246
2311
  emit({ type: "stderr", data: err instanceof Error ? err.message : String(err) });
2247
- process.exit(1);
2312
+ exitWhenFlushed(1);
2248
2313
  }
2249
2314
  );