@sideboard-ai/core 0.1.51 → 0.1.53

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 (40) hide show
  1. package/dist/agents/cursor-runner.cjs +43 -4
  2. package/dist/agents/cursor-runner.js +45 -6
  3. package/dist/{agents-HIEJL3UV.js → agents-KP7UJEHJ.js} +1 -1
  4. package/dist/{agents-5ROTZNCX.js → agents-KYACODJ3.js} +2 -2
  5. package/dist/{chunk-5ZPSH7VI.js → chunk-A6HVEMIB.js} +16 -7
  6. package/dist/chunk-B3SJXYIJ.js +24 -0
  7. package/dist/{chunk-7EUWSBWR.js → chunk-BZST4HMJ.js} +21 -6
  8. package/dist/{chunk-ZH5QZ4CR.js → chunk-DZFH2KLT.js} +280 -7
  9. package/dist/chunk-FKOIHGKV.js +21 -0
  10. package/dist/{chunk-E4VVEKAM.js → chunk-GNML24AW.js} +2 -2
  11. package/dist/{chunk-EOYDCKQC.js → chunk-HLEX5AQ6.js} +4 -0
  12. package/dist/{chunk-K3WMKGFY.js → chunk-LRLKJM3O.js} +2 -1
  13. package/dist/chunk-N5PM7HGQ.js +103 -0
  14. package/dist/chunk-QTUESPAW.js +101 -0
  15. package/dist/{chunk-O6W3P7V3.js → chunk-TSRXOSVD.js} +4 -0
  16. package/dist/{chunk-F4Q3IM6V.js → chunk-UEAHMGHW.js} +2 -1
  17. package/dist/{chunk-J5JTEJ5O.js → chunk-VG22SETP.js} +6 -0
  18. package/dist/{chunk-XRSAGVRW.js → chunk-XOU6HNQJ.js} +245 -7
  19. package/dist/{chunk-O5DOO7DP.js → chunk-XX5BB7NV.js} +3 -3
  20. package/dist/{chunk-QN7XNQAT.js → chunk-YDXQ72MD.js} +2 -2
  21. package/dist/{chunk-YFJ4FG2P.js → chunk-YOWIYAVA.js} +3 -3
  22. package/dist/{coordinator-prompt-7HHJRO7B.js → coordinator-prompt-6FXVTSFN.js} +4 -3
  23. package/dist/{coordinator-prompt-WD7FAMA2.js → coordinator-prompt-S6JZD5EF.js} +4 -3
  24. package/dist/{global-workspace-OJEPGDXA.js → global-workspace-EV4G2WMQ.js} +5 -4
  25. package/dist/{global-workspace-ECYN2MKL.js → global-workspace-MSX2K27Y.js} +5 -4
  26. package/dist/index.cjs +1383 -149
  27. package/dist/index.d.cts +389 -15
  28. package/dist/index.d.ts +389 -15
  29. package/dist/index.js +883 -91
  30. package/dist/mcp/run-stdio.cjs +1154 -141
  31. package/dist/mcp/run-stdio.js +709 -79
  32. package/dist/plan-file-6O7G4VPQ.js +23 -0
  33. package/dist/plan-file-PHVKUAEE.js +25 -0
  34. package/dist/{thread-store-XICUWFNM.js → thread-store-GHOADGL2.js} +1 -1
  35. package/dist/{thread-store-OV2X6PYO.js → thread-store-UJIGMI5J.js} +1 -1
  36. package/dist/{workspaces-MUU7RGVV.js → workspaces-3RQQZQRO.js} +6 -5
  37. package/dist/{workspaces-ZWOOFZUV.js → workspaces-AYTBR6KQ.js} +6 -5
  38. package/dist/{worktree-DVNDMWZ7.js → worktree-5KEQWSAF.js} +5 -2
  39. package/dist/{worktree-GDV56MX4.js → worktree-RWGL7FUV.js} +5 -2
  40. package/package.json +1 -1
@@ -171,6 +171,33 @@ function localAgentStore() {
171
171
  (0, import_node_fs3.mkdirSync)(root, { recursive: true });
172
172
  return new import_sdk.JsonlLocalAgentStore(root);
173
173
  }
174
+ function isAgentBusyError(err) {
175
+ if (err instanceof import_sdk.AgentBusyError) return true;
176
+ const message = err instanceof Error ? err.message : String(err);
177
+ return /already has active run/i.test(message);
178
+ }
179
+ async function cancelStaleLocalRuns(agentId, opts) {
180
+ const listed = await import_sdk.Agent.listRuns(agentId, {
181
+ runtime: "local",
182
+ cwd: opts.cwd,
183
+ store: opts.store,
184
+ limit: 20
185
+ });
186
+ let cancelled = 0;
187
+ for (const run of listed.items) {
188
+ if (run.status !== "running") continue;
189
+ try {
190
+ await import_sdk.Agent.cancelRun(run.id, {
191
+ runtime: "local",
192
+ cwd: opts.cwd,
193
+ store: opts.store
194
+ });
195
+ cancelled += 1;
196
+ } catch {
197
+ }
198
+ }
199
+ return cancelled;
200
+ }
174
201
  async function readStdinJson() {
175
202
  const rl = (0, import_node_readline.createInterface)({ input: process.stdin, crlfDelay: Infinity });
176
203
  const chunks = [];
@@ -242,10 +269,22 @@ async function main() {
242
269
  }
243
270
  try {
244
271
  emit({ type: "session_id", data: agent.agentId });
245
- const run = await agent.send(
246
- req.prompt,
247
- mcpServers ? { mcpServers } : void 0
248
- );
272
+ const sendOpts = mcpServers ? { mcpServers } : void 0;
273
+ let run;
274
+ try {
275
+ run = await agent.send(req.prompt, sendOpts);
276
+ } catch (err) {
277
+ if (!isAgentBusyError(err)) throw err;
278
+ const n = await cancelStaleLocalRuns(agent.agentId, {
279
+ cwd: req.cwd,
280
+ store
281
+ });
282
+ emit({
283
+ type: "stderr",
284
+ data: n > 0 ? `Cursor agent had ${n} stale active run(s) \u2014 cancelled and retrying` : "Cursor agent busy \u2014 retrying send"
285
+ });
286
+ run = await agent.send(req.prompt, sendOpts);
287
+ }
249
288
  for await (const msg of run.stream()) {
250
289
  for (const event of cursorSdkMessageToEvents(msg)) {
251
290
  emit(event);
@@ -2,13 +2,13 @@
2
2
  import {
3
3
  cursorSdkMessageToEvents,
4
4
  formatUnknownDetail
5
- } from "../chunk-J5JTEJ5O.js";
5
+ } from "../chunk-VG22SETP.js";
6
6
  import {
7
7
  appDataDir
8
8
  } from "../chunk-M37RITA6.js";
9
9
 
10
10
  // src/agents/cursor-runner.ts
11
- import { Agent, CursorAgentError, JsonlLocalAgentStore } from "@cursor/sdk";
11
+ import { Agent, AgentBusyError, CursorAgentError, JsonlLocalAgentStore } from "@cursor/sdk";
12
12
  import { mkdirSync } from "fs";
13
13
  import { join } from "path";
14
14
  import { createInterface } from "readline";
@@ -35,6 +35,33 @@ function localAgentStore() {
35
35
  mkdirSync(root, { recursive: true });
36
36
  return new JsonlLocalAgentStore(root);
37
37
  }
38
+ function isAgentBusyError(err) {
39
+ if (err instanceof AgentBusyError) return true;
40
+ const message = err instanceof Error ? err.message : String(err);
41
+ return /already has active run/i.test(message);
42
+ }
43
+ async function cancelStaleLocalRuns(agentId, opts) {
44
+ const listed = await Agent.listRuns(agentId, {
45
+ runtime: "local",
46
+ cwd: opts.cwd,
47
+ store: opts.store,
48
+ limit: 20
49
+ });
50
+ let cancelled = 0;
51
+ for (const run of listed.items) {
52
+ if (run.status !== "running") continue;
53
+ try {
54
+ await Agent.cancelRun(run.id, {
55
+ runtime: "local",
56
+ cwd: opts.cwd,
57
+ store: opts.store
58
+ });
59
+ cancelled += 1;
60
+ } catch {
61
+ }
62
+ }
63
+ return cancelled;
64
+ }
38
65
  async function readStdinJson() {
39
66
  const rl = createInterface({ input: process.stdin, crlfDelay: Infinity });
40
67
  const chunks = [];
@@ -106,10 +133,22 @@ async function main() {
106
133
  }
107
134
  try {
108
135
  emit({ type: "session_id", data: agent.agentId });
109
- const run = await agent.send(
110
- req.prompt,
111
- mcpServers ? { mcpServers } : void 0
112
- );
136
+ const sendOpts = mcpServers ? { mcpServers } : void 0;
137
+ let run;
138
+ try {
139
+ run = await agent.send(req.prompt, sendOpts);
140
+ } catch (err) {
141
+ if (!isAgentBusyError(err)) throw err;
142
+ const n = await cancelStaleLocalRuns(agent.agentId, {
143
+ cwd: req.cwd,
144
+ store
145
+ });
146
+ emit({
147
+ type: "stderr",
148
+ data: n > 0 ? `Cursor agent had ${n} stale active run(s) \u2014 cancelled and retrying` : "Cursor agent busy \u2014 retrying send"
149
+ });
150
+ run = await agent.send(req.prompt, sendOpts);
151
+ }
113
152
  for await (const msg of run.stream()) {
114
153
  for (const event of cursorSdkMessageToEvents(msg)) {
115
154
  emit(event);
@@ -30,7 +30,7 @@ import {
30
30
  permissionMode,
31
31
  resolveCursorModelId,
32
32
  resolveQuotaFallbackAgent
33
- } from "./chunk-7EUWSBWR.js";
33
+ } from "./chunk-BZST4HMJ.js";
34
34
  import "./chunk-H6GGDLYS.js";
35
35
  import "./chunk-HBJSHRY2.js";
36
36
  import {
@@ -26,7 +26,7 @@ import {
26
26
  permissionMode,
27
27
  resolveCursorModelId,
28
28
  resolveQuotaFallbackAgent
29
- } from "./chunk-5ZPSH7VI.js";
29
+ } from "./chunk-A6HVEMIB.js";
30
30
  import {
31
31
  ORCHESTRATOR_AGENT_KINDS,
32
32
  assertOrchestratorCapableAgent,
@@ -37,7 +37,7 @@ import "./chunk-BXJ76RHF.js";
37
37
  import {
38
38
  cursorSdkMessageToEvents,
39
39
  parseCursorRunnerLine
40
- } from "./chunk-J5JTEJ5O.js";
40
+ } from "./chunk-VG22SETP.js";
41
41
  import "./chunk-T5QQVXK3.js";
42
42
  import "./chunk-77WWLBCI.js";
43
43
  import "./chunk-M37RITA6.js";
@@ -10,7 +10,7 @@ import {
10
10
  formatUnknownDetail,
11
11
  looksLikeAgentFailureMessage,
12
12
  parseCursorRunnerLine
13
- } from "./chunk-J5JTEJ5O.js";
13
+ } from "./chunk-VG22SETP.js";
14
14
  import {
15
15
  claudeChromeEnabled,
16
16
  loadAppSettings,
@@ -465,7 +465,9 @@ var SIDEBOARD_MCP_ALLOWED_TOOLS = [
465
465
  var SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS = [
466
466
  "mcp__sideboard__present_artifact",
467
467
  "mcp__sideboard__present_schema",
468
- "mcp__sideboard__present_files"
468
+ "mcp__sideboard__present_files",
469
+ "mcp__sideboard__ask_user",
470
+ "mcp__sideboard__present_plan"
469
471
  ];
470
472
  var BRIGHTSY_MCP_ALLOWED_TOOLS = [
471
473
  "mcp__brightsy",
@@ -656,7 +658,7 @@ async function writeInjectedMcpConfig(opts) {
656
658
  }
657
659
 
658
660
  // src/agents/types.ts
659
- var PLAN_MODE_INSTRUCTION = "Plan mode is active and must remain active until the user turns Plan mode off in the UI (or explicitly asks you to implement). Analyze the codebase, search and read files as needed, and produce or refine a clear implementation plan. Do not modify, create, or delete any files. Do not exit plan mode on your own.";
661
+ var PLAN_MODE_INSTRUCTION = "Plan mode is active and must remain active until the user turns Plan mode off in the UI (or Approves / Hands off the plan). Analyze the codebase, search and read files as needed, and produce or refine a clear implementation plan. Do not modify, create, or delete any project files except via Sideboard MCP present_plan (writes .context/attachments/plan.md). When you need a clarifying decision (approach forks, auth choice, scope): (1) first write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it) \u2014 do not leave the user staring at bare labels; (2) then call Sideboard MCP ask_user with the same options, including a description on every option. Sideboard shows questions in the composer and mirrors them in chat. After ask_user, wait for the user's next message with their answers before finalizing the plan. When the plan is ready for approval: (1) call present_plan with the full markdown plan (title + content) so Sideboard saves .context/attachments/plan.md and shows it in chat for Approve / Hand off / Copy; (2) Claude should also call ExitPlanMode after present_plan. Do not skip present_plan \u2014 the plan must be a markdown file, not only chat prose.";
660
662
  function permissionMode(thread) {
661
663
  if (thread.planMode) {
662
664
  return {
@@ -837,7 +839,7 @@ var claudeAdapter = {
837
839
  );
838
840
  }
839
841
  const mode = permissionMode(thread);
840
- const { isOrchestratorThread } = await import("./global-workspace-ECYN2MKL.js");
842
+ const { isOrchestratorThread } = await import("./global-workspace-MSX2K27Y.js");
841
843
  const isOrchestrator = isOrchestratorThread(thread);
842
844
  const injectedServers = await buildInjectedMcpServers({
843
845
  includeSideboard: true,
@@ -1607,6 +1609,7 @@ var opencodeAdapter = {
1607
1609
  }
1608
1610
  },
1609
1611
  async resolveSessionId(worktreePath, cached) {
1612
+ const cachedId = cached?.trim() || null;
1610
1613
  const listed = await run(
1611
1614
  "opencode",
1612
1615
  ["session", "list", "--format", "json"],
@@ -1618,15 +1621,21 @@ var opencodeAdapter = {
1618
1621
  if (Array.isArray(sessions) && sessions.length > 0) {
1619
1622
  const norm = (p) => p.replace(/\/+$/, "");
1620
1623
  const wt = norm(worktreePath);
1621
- const match = sessions.find(
1624
+ const forWorktree = sessions.filter(
1622
1625
  (s) => s.directory && norm(s.directory) === wt || s.path && norm(s.path) === wt
1623
1626
  );
1624
- if (match?.id) return match.id;
1627
+ if (cachedId && forWorktree.some((s) => s.id === cachedId)) {
1628
+ return cachedId;
1629
+ }
1630
+ if (cachedId && sessions.some((s) => s.id === cachedId)) {
1631
+ return cachedId;
1632
+ }
1633
+ return null;
1625
1634
  }
1626
1635
  } catch {
1627
1636
  }
1628
1637
  }
1629
- return cached;
1638
+ return cachedId;
1630
1639
  },
1631
1640
  async buildAttach(thread) {
1632
1641
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
@@ -0,0 +1,24 @@
1
+ #!/usr/bin/env node
2
+
3
+
4
+ // src/paths/workspace-scratch.ts
5
+ var ATTACHMENTS_DIR = ".context/attachments";
6
+ var LEGACY_ATTACHMENTS_DIR = ".sideboard/attachments";
7
+ var ATTACHMENTS_GITIGNORE = `# Sideboard / workspace attachments (local only)
8
+ *
9
+ !.gitignore
10
+ `;
11
+ function attachmentsGitignoreBody() {
12
+ return ATTACHMENTS_GITIGNORE;
13
+ }
14
+ function isWorkspaceScratchPath(relativePath) {
15
+ const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
16
+ return p === ATTACHMENTS_DIR || p.startsWith(`${ATTACHMENTS_DIR}/`) || p === LEGACY_ATTACHMENTS_DIR || p.startsWith(`${LEGACY_ATTACHMENTS_DIR}/`) || p === ".context" || p.startsWith(".context/");
17
+ }
18
+
19
+ export {
20
+ ATTACHMENTS_DIR,
21
+ LEGACY_ATTACHMENTS_DIR,
22
+ attachmentsGitignoreBody,
23
+ isWorkspaceScratchPath
24
+ };
@@ -109,6 +109,11 @@ function summarizeTurnStderr(tail, maxChars = 500) {
109
109
  if (joined.length <= maxChars) return joined;
110
110
  return joined.slice(joined.length - maxChars);
111
111
  }
112
+ function looksLikeInvalidAgentSession(text) {
113
+ const lower = text.trim().toLowerCase();
114
+ if (!lower) return false;
115
+ return /session not found/.test(lower) || /no conversation found/.test(lower) || /conversation .+ not found/.test(lower) || /thread .+ not found/.test(lower) || /unknown session/.test(lower) || /invalid session/.test(lower) || /session .+ (missing|expired|deleted|gone)/.test(lower) || /cannot resume/.test(lower) || /failed to (load|resume|open) session/.test(lower);
116
+ }
112
117
  function looksLikeAgentFailureMessage(text) {
113
118
  const lower = text.trim().toLowerCase();
114
119
  if (!lower) return false;
@@ -534,7 +539,9 @@ var SIDEBOARD_MCP_ALLOWED_TOOLS = [
534
539
  var SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS = [
535
540
  "mcp__sideboard__present_artifact",
536
541
  "mcp__sideboard__present_schema",
537
- "mcp__sideboard__present_files"
542
+ "mcp__sideboard__present_files",
543
+ "mcp__sideboard__ask_user",
544
+ "mcp__sideboard__present_plan"
538
545
  ];
539
546
  var brightsyMcpCommandCache = null;
540
547
  async function resolveBrightsyMcpCommand() {
@@ -718,7 +725,7 @@ function writeMcpServersConfig(servers) {
718
725
  }
719
726
 
720
727
  // src/agents/types.ts
721
- var PLAN_MODE_INSTRUCTION = "Plan mode is active and must remain active until the user turns Plan mode off in the UI (or explicitly asks you to implement). Analyze the codebase, search and read files as needed, and produce or refine a clear implementation plan. Do not modify, create, or delete any files. Do not exit plan mode on your own.";
728
+ var PLAN_MODE_INSTRUCTION = "Plan mode is active and must remain active until the user turns Plan mode off in the UI (or Approves / Hands off the plan). Analyze the codebase, search and read files as needed, and produce or refine a clear implementation plan. Do not modify, create, or delete any project files except via Sideboard MCP present_plan (writes .context/attachments/plan.md). When you need a clarifying decision (approach forks, auth choice, scope): (1) first write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it) \u2014 do not leave the user staring at bare labels; (2) then call Sideboard MCP ask_user with the same options, including a description on every option. Sideboard shows questions in the composer and mirrors them in chat. After ask_user, wait for the user's next message with their answers before finalizing the plan. When the plan is ready for approval: (1) call present_plan with the full markdown plan (title + content) so Sideboard saves .context/attachments/plan.md and shows it in chat for Approve / Hand off / Copy; (2) Claude should also call ExitPlanMode after present_plan. Do not skip present_plan \u2014 the plan must be a markdown file, not only chat prose.";
722
729
  function permissionMode(thread) {
723
730
  if (thread.planMode) {
724
731
  return {
@@ -899,7 +906,7 @@ var claudeAdapter = {
899
906
  );
900
907
  }
901
908
  const mode = permissionMode(thread);
902
- const { isOrchestratorThread } = await import("./global-workspace-OJEPGDXA.js");
909
+ const { isOrchestratorThread } = await import("./global-workspace-EV4G2WMQ.js");
903
910
  const isOrchestrator = isOrchestratorThread(thread);
904
911
  const injectedServers = await buildInjectedMcpServers({
905
912
  includeSideboard: true,
@@ -1764,6 +1771,7 @@ var opencodeAdapter = {
1764
1771
  }
1765
1772
  },
1766
1773
  async resolveSessionId(worktreePath, cached) {
1774
+ const cachedId = cached?.trim() || null;
1767
1775
  const listed = await run(
1768
1776
  "opencode",
1769
1777
  ["session", "list", "--format", "json"],
@@ -1775,15 +1783,21 @@ var opencodeAdapter = {
1775
1783
  if (Array.isArray(sessions) && sessions.length > 0) {
1776
1784
  const norm = (p) => p.replace(/\/+$/, "");
1777
1785
  const wt = norm(worktreePath);
1778
- const match = sessions.find(
1786
+ const forWorktree = sessions.filter(
1779
1787
  (s) => s.directory && norm(s.directory) === wt || s.path && norm(s.path) === wt
1780
1788
  );
1781
- if (match?.id) return match.id;
1789
+ if (cachedId && forWorktree.some((s) => s.id === cachedId)) {
1790
+ return cachedId;
1791
+ }
1792
+ if (cachedId && sessions.some((s) => s.id === cachedId)) {
1793
+ return cachedId;
1794
+ }
1795
+ return null;
1782
1796
  }
1783
1797
  } catch {
1784
1798
  }
1785
1799
  }
1786
- return cached;
1800
+ return cachedId;
1787
1801
  },
1788
1802
  async buildAttach(thread) {
1789
1803
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
@@ -2195,6 +2209,7 @@ function allAdapters() {
2195
2209
  export {
2196
2210
  pushTurnStderr,
2197
2211
  summarizeTurnStderr,
2212
+ looksLikeInvalidAgentSession,
2198
2213
  looksLikeAgentFailureMessage,
2199
2214
  fallbackTurnFailDetail,
2200
2215
  humanizeAgentFailDetail,