@sideboard-ai/core 0.1.98 → 0.1.99

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.
@@ -203,6 +203,34 @@ function cursorSendOptions(mcpServers) {
203
203
  function withCursorLocalHangGuards(local) {
204
204
  return { ...local, enableAgentRetries: false };
205
205
  }
206
+ var CURSOR_STREAM_IDLE_MS = 18e4;
207
+ async function* iterateUntilIdle(iterable, idleMs, onIdle) {
208
+ const iterator = iterable[Symbol.asyncIterator]();
209
+ try {
210
+ while (true) {
211
+ let idleTimer;
212
+ const next = iterator.next();
213
+ const raced = await Promise.race([
214
+ next.then((result) => ({ kind: "item", result })),
215
+ new Promise((resolve) => {
216
+ idleTimer = setTimeout(() => resolve({ kind: "idle" }), idleMs);
217
+ idleTimer.unref?.();
218
+ })
219
+ ]);
220
+ if (idleTimer) clearTimeout(idleTimer);
221
+ if (raced.kind === "idle") {
222
+ onIdle?.();
223
+ void iterator.return?.();
224
+ return;
225
+ }
226
+ if (raced.result.done) return;
227
+ yield raced.result.value;
228
+ }
229
+ } catch (err) {
230
+ void iterator.return?.();
231
+ throw err;
232
+ }
233
+ }
206
234
 
207
235
  // src/agents/error-detail.ts
208
236
  function formatUnknownDetail(err) {
@@ -601,14 +629,31 @@ async function main() {
601
629
  const run2 = await sendPrompt(agent);
602
630
  liveRun = run2;
603
631
  const stream = createAgentStreamCoalescer(emit);
632
+ let streamIdle = false;
604
633
  try {
605
- for await (const msg of run2.stream()) {
634
+ for await (const msg of iterateUntilIdle(
635
+ run2.stream(),
636
+ CURSOR_STREAM_IDLE_MS,
637
+ () => {
638
+ streamIdle = true;
639
+ emit({
640
+ type: "stderr",
641
+ data: "Cursor stream idle \u2014 finishing the turn (SDK stream did not close)"
642
+ });
643
+ void cancelLiveRun();
644
+ }
645
+ )) {
606
646
  for (const event of cursorSdkMessageToEvents(msg)) {
607
647
  stream.push(event);
608
648
  }
609
649
  }
610
650
  stream.flush();
611
- const result = await run2.wait();
651
+ const result = streamIdle ? await Promise.race([
652
+ run2.wait(),
653
+ new Promise((resolve) => {
654
+ setTimeout(() => resolve({ status: "cancelled" }), 5e3);
655
+ })
656
+ ]) : await run2.wait();
612
657
  if (result.status === "error") {
613
658
  const detail = formatUnknownDetail(result.error);
614
659
  emit({
@@ -56,6 +56,34 @@ function cursorSendOptions(mcpServers) {
56
56
  function withCursorLocalHangGuards(local) {
57
57
  return { ...local, enableAgentRetries: false };
58
58
  }
59
+ var CURSOR_STREAM_IDLE_MS = 18e4;
60
+ async function* iterateUntilIdle(iterable, idleMs, onIdle) {
61
+ const iterator = iterable[Symbol.asyncIterator]();
62
+ try {
63
+ while (true) {
64
+ let idleTimer;
65
+ const next = iterator.next();
66
+ const raced = await Promise.race([
67
+ next.then((result) => ({ kind: "item", result })),
68
+ new Promise((resolve) => {
69
+ idleTimer = setTimeout(() => resolve({ kind: "idle" }), idleMs);
70
+ idleTimer.unref?.();
71
+ })
72
+ ]);
73
+ if (idleTimer) clearTimeout(idleTimer);
74
+ if (raced.kind === "idle") {
75
+ onIdle?.();
76
+ void iterator.return?.();
77
+ return;
78
+ }
79
+ if (raced.result.done) return;
80
+ yield raced.result.value;
81
+ }
82
+ } catch (err) {
83
+ void iterator.return?.();
84
+ throw err;
85
+ }
86
+ }
59
87
 
60
88
  // src/agents/cursor-runner.ts
61
89
  dropNestedElectronEnvFromProcess();
@@ -215,14 +243,31 @@ async function main() {
215
243
  const run = await sendPrompt(agent);
216
244
  liveRun = run;
217
245
  const stream = createAgentStreamCoalescer(emit);
246
+ let streamIdle = false;
218
247
  try {
219
- for await (const msg of run.stream()) {
248
+ for await (const msg of iterateUntilIdle(
249
+ run.stream(),
250
+ CURSOR_STREAM_IDLE_MS,
251
+ () => {
252
+ streamIdle = true;
253
+ emit({
254
+ type: "stderr",
255
+ data: "Cursor stream idle \u2014 finishing the turn (SDK stream did not close)"
256
+ });
257
+ void cancelLiveRun();
258
+ }
259
+ )) {
220
260
  for (const event of cursorSdkMessageToEvents(msg)) {
221
261
  stream.push(event);
222
262
  }
223
263
  }
224
264
  stream.flush();
225
- const result = await run.wait();
265
+ const result = streamIdle ? await Promise.race([
266
+ run.wait(),
267
+ new Promise((resolve) => {
268
+ setTimeout(() => resolve({ status: "cancelled" }), 5e3);
269
+ })
270
+ ]) : await run.wait();
226
271
  if (result.status === "error") {
227
272
  const detail = formatUnknownDetail(result.error);
228
273
  emit({