@sideboard-ai/core 0.1.97 → 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({
@@ -28,13 +28,13 @@ import {
28
28
  resolveCursorModelId,
29
29
  resolveLoginCommand,
30
30
  resolveQuotaFallbackAgent
31
- } from "./chunk-KWNUZ4LR.js";
31
+ } from "./chunk-MBP3XG57.js";
32
32
  import {
33
33
  ORCHESTRATOR_AGENT_KINDS,
34
34
  assertOrchestratorCapableAgent,
35
35
  coerceOrchestratorAgent,
36
36
  isOrchestratorCapableAgent
37
- } from "./chunk-CLGO7TLO.js";
37
+ } from "./chunk-FO67IJTY.js";
38
38
  import "./chunk-XUWDLRAE.js";
39
39
  import "./chunk-QSLE4VEM.js";
40
40
  import {
@@ -32,14 +32,14 @@ import {
32
32
  resolveCursorModelId,
33
33
  resolveLoginCommand,
34
34
  resolveQuotaFallbackAgent
35
- } from "./chunk-WBX46OPD.js";
35
+ } from "./chunk-FYS2BULQ.js";
36
36
  import "./chunk-DKHGWYWR.js";
37
37
  import {
38
38
  ORCHESTRATOR_AGENT_KINDS,
39
39
  assertOrchestratorCapableAgent,
40
40
  coerceOrchestratorAgent,
41
41
  isOrchestratorCapableAgent
42
- } from "./chunk-NR6APJLD.js";
42
+ } from "./chunk-HI2OTFFR.js";
43
43
  import "./chunk-XH2GS2LO.js";
44
44
  import "./chunk-R7BQBSDT.js";
45
45
  import "./chunk-B3SJXYIJ.js";
@@ -209,42 +209,40 @@ function findSlackCoordinator(teamId, userId) {
209
209
  (t) => t.status !== "archived" && t.sourceRef === ref && isSlackCoordinatorThread(t)
210
210
  );
211
211
  }
212
- function ensureSlackCoordinator(teamId, userId, agent) {
212
+ function ensureSlackCoordinator(teamId, userId, agent, opts) {
213
213
  const defaults = resolveThreadDefaults();
214
214
  const desired = assertOrchestratorCapableAgent(agent);
215
215
  const ref = slackCoordinatorSourceRef(teamId, userId);
216
- const existing = findSlackCoordinator(teamId, userId);
217
- if (existing) {
218
- const patch = {};
219
- if (existing.repoPath !== GLOBAL_WORKSPACE_ID) {
220
- patch.repoPath = GLOBAL_WORKSPACE_ID;
221
- patch.worktreePath = globalAgentCwd();
222
- patch.branchName = "global";
223
- }
224
- const hasAgentTurns = existing.messages.some((m) => m.role === "agent");
225
- const canRetarget = !existing.sessionId && !hasAgentTurns && existing.status !== "running" && existing.status !== "queued";
226
- if (canRetarget) {
227
- if (existing.agent !== desired) patch.agent = desired;
228
- if (existing.model !== defaults.model) patch.model = defaults.model;
229
- if (existing.effort !== defaults.effort) patch.effort = defaults.effort;
230
- if (existing.fast !== defaults.fast) patch.fast = defaults.fast;
231
- }
232
- if (Object.keys(patch).length > 0) {
233
- return updateThread(existing.id, patch);
216
+ if (!opts?.forceNew) {
217
+ const existing = findSlackCoordinator(teamId, userId);
218
+ if (existing) {
219
+ const patch = {};
220
+ if (existing.repoPath !== GLOBAL_WORKSPACE_ID) {
221
+ patch.repoPath = GLOBAL_WORKSPACE_ID;
222
+ patch.worktreePath = globalAgentCwd();
223
+ patch.branchName = "global";
224
+ }
225
+ const hasAgentTurns = existing.messages.some((m) => m.role === "agent");
226
+ const canRetarget = !existing.sessionId && !hasAgentTurns && existing.status !== "running" && existing.status !== "queued";
227
+ if (canRetarget) {
228
+ if (existing.agent !== desired) patch.agent = desired;
229
+ if (existing.model !== defaults.model) patch.model = defaults.model;
230
+ if (existing.effort !== defaults.effort) patch.effort = defaults.effort;
231
+ if (existing.fast !== defaults.fast) patch.fast = defaults.fast;
232
+ }
233
+ if (Object.keys(patch).length > 0) {
234
+ return updateThread(existing.id, patch);
235
+ }
236
+ return existing;
234
237
  }
235
- return existing;
236
238
  }
237
- const created = createGlobalChat({
239
+ return createGlobalChat({
238
240
  sourceRef: ref,
239
241
  agent: desired,
240
242
  model: defaults.model,
241
243
  effort: defaults.effort,
242
244
  fast: defaults.fast
243
245
  });
244
- const all = listThreads({ includeArchived: true }).filter(
245
- (t) => t.status !== "archived" && t.sourceRef === ref && isSlackCoordinatorThread(t)
246
- ).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
247
- return all[0] ?? created;
248
246
  }
249
247
  function ensureCloudCoordinator(agent) {
250
248
  const defaults = resolveThreadDefaults();
@@ -307,6 +305,7 @@ export {
307
305
  listGlobalThreads,
308
306
  slackCoordinatorSourceRef,
309
307
  isSlackCoordinatorThread,
308
+ findSlackCoordinator,
310
309
  ensureSlackCoordinator,
311
310
  ensureCloudCoordinator
312
311
  };
@@ -9,7 +9,7 @@ import {
9
9
  } from "./chunk-DKHGWYWR.js";
10
10
  import {
11
11
  isOrchestratorThread
12
- } from "./chunk-NR6APJLD.js";
12
+ } from "./chunk-HI2OTFFR.js";
13
13
  import {
14
14
  codexUnattendedGitConfigArgs,
15
15
  mergeAgentGitAuthEnv,
@@ -1208,7 +1208,7 @@ var claudeAdapter = {
1208
1208
  );
1209
1209
  }
1210
1210
  const mode = permissionMode(thread);
1211
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-3GNPQCLE.js");
1211
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-WMF3BJP5.js");
1212
1212
  const isOrchestrator = isOrchestratorThread2(thread);
1213
1213
  const injectedServers = await buildInjectedMcpServers({
1214
1214
  includeSideboard: true,
@@ -203,42 +203,40 @@ function findSlackCoordinator(teamId, userId) {
203
203
  (t) => t.status !== "archived" && t.sourceRef === ref && isSlackCoordinatorThread(t)
204
204
  );
205
205
  }
206
- function ensureSlackCoordinator(teamId, userId, agent) {
206
+ function ensureSlackCoordinator(teamId, userId, agent, opts) {
207
207
  const defaults = resolveThreadDefaults();
208
208
  const desired = assertOrchestratorCapableAgent(agent);
209
209
  const ref = slackCoordinatorSourceRef(teamId, userId);
210
- const existing = findSlackCoordinator(teamId, userId);
211
- if (existing) {
212
- const patch = {};
213
- if (existing.repoPath !== GLOBAL_WORKSPACE_ID) {
214
- patch.repoPath = GLOBAL_WORKSPACE_ID;
215
- patch.worktreePath = globalAgentCwd();
216
- patch.branchName = "global";
217
- }
218
- const hasAgentTurns = existing.messages.some((m) => m.role === "agent");
219
- const canRetarget = !existing.sessionId && !hasAgentTurns && existing.status !== "running" && existing.status !== "queued";
220
- if (canRetarget) {
221
- if (existing.agent !== desired) patch.agent = desired;
222
- if (existing.model !== defaults.model) patch.model = defaults.model;
223
- if (existing.effort !== defaults.effort) patch.effort = defaults.effort;
224
- if (existing.fast !== defaults.fast) patch.fast = defaults.fast;
225
- }
226
- if (Object.keys(patch).length > 0) {
227
- return updateThread(existing.id, patch);
210
+ if (!opts?.forceNew) {
211
+ const existing = findSlackCoordinator(teamId, userId);
212
+ if (existing) {
213
+ const patch = {};
214
+ if (existing.repoPath !== GLOBAL_WORKSPACE_ID) {
215
+ patch.repoPath = GLOBAL_WORKSPACE_ID;
216
+ patch.worktreePath = globalAgentCwd();
217
+ patch.branchName = "global";
218
+ }
219
+ const hasAgentTurns = existing.messages.some((m) => m.role === "agent");
220
+ const canRetarget = !existing.sessionId && !hasAgentTurns && existing.status !== "running" && existing.status !== "queued";
221
+ if (canRetarget) {
222
+ if (existing.agent !== desired) patch.agent = desired;
223
+ if (existing.model !== defaults.model) patch.model = defaults.model;
224
+ if (existing.effort !== defaults.effort) patch.effort = defaults.effort;
225
+ if (existing.fast !== defaults.fast) patch.fast = defaults.fast;
226
+ }
227
+ if (Object.keys(patch).length > 0) {
228
+ return updateThread(existing.id, patch);
229
+ }
230
+ return existing;
228
231
  }
229
- return existing;
230
232
  }
231
- const created = createGlobalChat({
233
+ return createGlobalChat({
232
234
  sourceRef: ref,
233
235
  agent: desired,
234
236
  model: defaults.model,
235
237
  effort: defaults.effort,
236
238
  fast: defaults.fast
237
239
  });
238
- const all = listThreads({ includeArchived: true }).filter(
239
- (t) => t.status !== "archived" && t.sourceRef === ref && isSlackCoordinatorThread(t)
240
- ).sort((a, b) => a.createdAt.localeCompare(b.createdAt));
241
- return all[0] ?? created;
242
240
  }
243
241
  function ensureCloudCoordinator(agent) {
244
242
  const defaults = resolveThreadDefaults();
@@ -295,6 +293,7 @@ export {
295
293
  listGlobalThreads,
296
294
  slackCoordinatorSourceRef,
297
295
  isSlackCoordinatorThread,
296
+ findSlackCoordinator,
298
297
  ensureSlackCoordinator,
299
298
  ensureCloudCoordinator
300
299
  };
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isOrchestratorThread
3
- } from "./chunk-CLGO7TLO.js";
3
+ } from "./chunk-FO67IJTY.js";
4
4
  import {
5
5
  applyConnectedTeamToCli,
6
6
  brightsyMcpServerName,
@@ -1019,7 +1019,7 @@ var claudeAdapter = {
1019
1019
  );
1020
1020
  }
1021
1021
  const mode = permissionMode(thread);
1022
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-M3OMVDDH.js");
1022
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-RSQXRLT7.js");
1023
1023
  const isOrchestrator = isOrchestratorThread2(thread);
1024
1024
  const injectedServers = await buildInjectedMcpServers({
1025
1025
  includeSideboard: true,
@@ -2,7 +2,7 @@
2
2
 
3
3
  import {
4
4
  isGlobalRepoPath
5
- } from "./chunk-NR6APJLD.js";
5
+ } from "./chunk-HI2OTFFR.js";
6
6
  import {
7
7
  ensureGhPreferOrigin,
8
8
  resolveRepoRoot
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isGlobalRepoPath
3
- } from "./chunk-CLGO7TLO.js";
3
+ } from "./chunk-FO67IJTY.js";
4
4
  import {
5
5
  ensureGhPreferOrigin,
6
6
  resolveRepoRoot
@@ -3,6 +3,7 @@ import {
3
3
  createGlobalChat,
4
4
  ensureCloudCoordinator,
5
5
  ensureSlackCoordinator,
6
+ findSlackCoordinator,
6
7
  healOrchestrationSoccerTitles,
7
8
  isCloudCoordinatorThread,
8
9
  isGlobalRepoPath,
@@ -14,7 +15,7 @@ import {
14
15
  orchestratorSessionPoisonedByBuiltins,
15
16
  slackCoordinatorSourceRef,
16
17
  takenTeamSlugsForOrchestration
17
- } from "./chunk-CLGO7TLO.js";
18
+ } from "./chunk-FO67IJTY.js";
18
19
  import "./chunk-XUWDLRAE.js";
19
20
  import "./chunk-CIRXAYWS.js";
20
21
  import "./chunk-FKOIHGKV.js";
@@ -32,6 +33,7 @@ export {
32
33
  createGlobalChat,
33
34
  ensureCloudCoordinator,
34
35
  ensureSlackCoordinator,
36
+ findSlackCoordinator,
35
37
  globalAgentCwd,
36
38
  healOrchestrationSoccerTitles,
37
39
  isCloudCoordinatorThread,
@@ -5,6 +5,7 @@ import {
5
5
  createGlobalChat,
6
6
  ensureCloudCoordinator,
7
7
  ensureSlackCoordinator,
8
+ findSlackCoordinator,
8
9
  healOrchestrationSoccerTitles,
9
10
  isCloudCoordinatorThread,
10
11
  isGlobalRepoPath,
@@ -16,7 +17,7 @@ import {
16
17
  orchestratorSessionPoisonedByBuiltins,
17
18
  slackCoordinatorSourceRef,
18
19
  takenTeamSlugsForOrchestration
19
- } from "./chunk-NR6APJLD.js";
20
+ } from "./chunk-HI2OTFFR.js";
20
21
  import "./chunk-XH2GS2LO.js";
21
22
  import "./chunk-R7BQBSDT.js";
22
23
  import "./chunk-B3SJXYIJ.js";
@@ -33,6 +34,7 @@ export {
33
34
  createGlobalChat,
34
35
  ensureCloudCoordinator,
35
36
  ensureSlackCoordinator,
37
+ findSlackCoordinator,
36
38
  globalAgentCwd,
37
39
  healOrchestrationSoccerTitles,
38
40
  isCloudCoordinatorThread,