@sideboard-ai/core 0.1.115 → 0.1.117

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 (42) hide show
  1. package/dist/agents/cursor-runner.cjs +96 -60
  2. package/dist/agents/cursor-runner.js +10 -9
  3. package/dist/{agents-3X3EFCQY.js → agents-GUEKGV7V.js} +6 -6
  4. package/dist/{agents-AHAFC6FR.js → agents-OCGAZCKT.js} +5 -5
  5. package/dist/{chunk-66XTXHR3.js → chunk-4CDCTYTM.js} +61 -11
  6. package/dist/{chunk-XOYQ7LNQ.js → chunk-4NAW5BAQ.js} +3 -3
  7. package/dist/{chunk-4OJMZ6P2.js → chunk-4WV7C7WP.js} +3 -3
  8. package/dist/{chunk-DCNR7NAL.js → chunk-5X7GRP5W.js} +49 -24
  9. package/dist/{chunk-MZ6HJ7VL.js → chunk-74YJHND6.js} +48 -23
  10. package/dist/{chunk-ZRCX43LS.js → chunk-BKVDZV7X.js} +2 -2
  11. package/dist/{chunk-A4VZXJEJ.js → chunk-HPAWHIZ3.js} +4 -1
  12. package/dist/{chunk-SLU5JVKD.js → chunk-NZBDVBCP.js} +23 -2
  13. package/dist/{chunk-KYOTBZ6S.js → chunk-RG737OWT.js} +4 -1
  14. package/dist/{chunk-K3TIQXOH.js → chunk-U3IVCVLH.js} +2 -2
  15. package/dist/{chunk-FZCIQYNQ.js → chunk-VGPLXQIH.js} +1 -1
  16. package/dist/chunk-VHX673DI.js +32 -0
  17. package/dist/{chunk-ZMROW673.js → chunk-WCU3FHEI.js} +1 -1
  18. package/dist/{chunk-7WC5UWEB.js → chunk-X3NIPGQT.js} +1 -1
  19. package/dist/{chunk-ZYEFCSZJ.js → chunk-XTZQL7OU.js} +1 -1
  20. package/dist/{chunk-C6OBY6IC.js → chunk-YJ2WV5TZ.js} +54 -10
  21. package/dist/{coordinator-prompt-4KCALEKD.js → coordinator-prompt-QMV6YEP5.js} +3 -3
  22. package/dist/{coordinator-prompt-FML4I5AR.js → coordinator-prompt-XCBHAOGE.js} +3 -3
  23. package/dist/cursor-recover-NOQYOFRF.js +76 -0
  24. package/dist/{cursor-recover-JBTIDARH.js → cursor-recover-QSLWEZNA.js} +12 -7
  25. package/dist/{global-workspace-CSWABOG5.js → global-workspace-SBKXKQFS.js} +4 -4
  26. package/dist/{global-workspace-H4YNASM6.js → global-workspace-Z37MNYU6.js} +4 -4
  27. package/dist/index.cjs +369 -240
  28. package/dist/index.d.cts +13 -1
  29. package/dist/index.d.ts +13 -1
  30. package/dist/index.js +14 -10
  31. package/dist/mcp/run-stdio.cjs +359 -237
  32. package/dist/mcp/run-stdio.js +9 -9
  33. package/dist/{orchestrator-GKLYKLRC.js → orchestrator-4PKR6AZJ.js} +7 -7
  34. package/dist/{orchestrator-TXASYNHT.js → orchestrator-MKTZYWTI.js} +8 -8
  35. package/dist/{thread-store-OEALWU7Y.js → thread-store-JR235AWK.js} +3 -1
  36. package/dist/{thread-store-LPTBVW5C.js → thread-store-PMH3BMB6.js} +3 -1
  37. package/dist/{workspaces-HJ3EVATC.js → workspaces-C3TJJFY3.js} +5 -5
  38. package/dist/{workspaces-QG6PGFQR.js → workspaces-M4OICPWF.js} +5 -5
  39. package/dist/{worktree-IW3BX26B.js → worktree-7AEKZSEX.js} +2 -2
  40. package/dist/{worktree-OTFQO2W7.js → worktree-MRSTQ32S.js} +2 -2
  41. package/package.json +1 -1
  42. package/dist/cursor-recover-ZUJG6XRQ.js +0 -42
@@ -17,13 +17,13 @@ import {
17
17
  resolveQuotaFallbackAgent,
18
18
  stripBrightsyNdjsonNoise,
19
19
  toolDescription
20
- } from "./chunk-C6OBY6IC.js";
20
+ } from "./chunk-YJ2WV5TZ.js";
21
21
  import {
22
22
  addWorkspace,
23
23
  ensureWorkspace,
24
24
  removeWorkspace,
25
25
  syncWorkspacesFromThreads
26
- } from "./chunk-K3TIQXOH.js";
26
+ } from "./chunk-U3IVCVLH.js";
27
27
  import {
28
28
  assertOrchestratorCapableAgent,
29
29
  coerceOrchestratorAgent,
@@ -36,14 +36,14 @@ import {
36
36
  isOrchestratorThread,
37
37
  isSlackCoordinatorThread,
38
38
  orchestratorSessionPoisonedByBuiltins
39
- } from "./chunk-4OJMZ6P2.js";
39
+ } from "./chunk-4WV7C7WP.js";
40
40
  import {
41
41
  SLACK_REPLY_FORMATTING,
42
42
  coordinatorSystemPrompt,
43
43
  coordinatorTurnReminder,
44
44
  enrichWorkspacesWithGithub,
45
45
  ensureGlobalCoordinatorCwd
46
- } from "./chunk-7WC5UWEB.js";
46
+ } from "./chunk-X3NIPGQT.js";
47
47
  import {
48
48
  extractPresentedPlan,
49
49
  readPlanFile,
@@ -63,7 +63,7 @@ import {
63
63
  shouldRetryFailedAgentTurn,
64
64
  summarizeTurnStderr,
65
65
  turnFailChatText
66
- } from "./chunk-SLU5JVKD.js";
66
+ } from "./chunk-NZBDVBCP.js";
67
67
  import {
68
68
  releaseCaffeinateHoldForThread
69
69
  } from "./chunk-DCOZABNT.js";
@@ -109,7 +109,7 @@ import {
109
109
  threadDisplayLabel,
110
110
  withRepoGitLock,
111
111
  worktreeNameFromPath
112
- } from "./chunk-FZCIQYNQ.js";
112
+ } from "./chunk-VGPLXQIH.js";
113
113
  import {
114
114
  ATTACHMENTS_DIR,
115
115
  LEGACY_ATTACHMENTS_DIR,
@@ -145,7 +145,7 @@ import {
145
145
  updateThread,
146
146
  withThreadLock,
147
147
  writeThread
148
- } from "./chunk-A4VZXJEJ.js";
148
+ } from "./chunk-HPAWHIZ3.js";
149
149
  import {
150
150
  appDataDir,
151
151
  findConventionSetup,
@@ -755,9 +755,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
755
755
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
756
756
  );
757
757
  }
758
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-CSWABOG5.js");
758
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-SBKXKQFS.js");
759
759
  if (isGlobalThread2(thread)) {
760
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-4KCALEKD.js");
760
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-QMV6YEP5.js");
761
761
  ensureGlobalCoordinatorCwd2(
762
762
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
763
763
  );
@@ -2455,7 +2455,7 @@ async function createThread(input, _onSetupLine) {
2455
2455
  return readThread(thread.id) ?? thread;
2456
2456
  }
2457
2457
  async function listLinearIssues(agent, repoPath) {
2458
- const { getAdapter: getAdapter2 } = await import("./agents-3X3EFCQY.js");
2458
+ const { getAdapter: getAdapter2 } = await import("./agents-GUEKGV7V.js");
2459
2459
  await requireAgent(agent, { requireLinear: true });
2460
2460
  const adapter = getAdapter2(agent);
2461
2461
  if (!adapter.listLinearIssues) {
@@ -2551,7 +2551,7 @@ function noteTurnLiveEvent(threadId, event) {
2551
2551
  buffers.delete(threadId);
2552
2552
  return;
2553
2553
  }
2554
- const immediate = event.type === "tool_use" || event.type === "tool_result";
2554
+ const immediate = event.type === "tool_use" || event.type === "tool_result" && !event.partial;
2555
2555
  if (immediate) flush(threadId);
2556
2556
  else scheduleFlush(threadId);
2557
2557
  }
@@ -2591,6 +2591,21 @@ function clearTurnLive(threadId) {
2591
2591
  }
2592
2592
  }
2593
2593
 
2594
+ // src/orchestrator/reconcile-heal.ts
2595
+ var RECONCILE_HEAL_MIN_MS = 2e3;
2596
+ var SKIP = /* @__PURE__ */ new Set([
2597
+ "stdout",
2598
+ "thinking",
2599
+ "usage",
2600
+ "stderr",
2601
+ "tool_result"
2602
+ ]);
2603
+ function shouldReadThreadToHealReconcile(eventType, lastCheckAt, now) {
2604
+ if (SKIP.has(eventType)) return false;
2605
+ if (lastCheckAt != null && now - lastCheckAt < RECONCILE_HEAL_MIN_MS) return false;
2606
+ return true;
2607
+ }
2608
+
2594
2609
  // src/threads/fork-worktree.ts
2595
2610
  function requireThread2(idOrRef) {
2596
2611
  const thread = findThreadByRef(idOrRef) ?? null;
@@ -2836,7 +2851,7 @@ async function adoptThread(input) {
2836
2851
  messages: input.messages ?? []
2837
2852
  });
2838
2853
  writeThread(thread);
2839
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-QG6PGFQR.js");
2854
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-M4OICPWF.js");
2840
2855
  await ensureWorkspace2(repoPath);
2841
2856
  return thread;
2842
2857
  }
@@ -4743,14 +4758,15 @@ function formatArtifactDirective() {
4743
4758
  return [
4744
4759
  "Sideboard side column (desktop UI):",
4745
4760
  "claude.ai\u2019s \u201CArtifact\u201D tool does NOT exist in Claude Code. That is expected.",
4761
+ "Do not unprompted-duplicate a payload. Chat markdown (including tables) already renders in the transcript \u2014 do not also call present_schema with those same rows just to display them. If the user asks for an editable / interactive table, call present_schema even if markdown already showed the data. Do not also call present_artifact for a document you already fenced in chat.",
4746
4762
  "Documents (HTML/SVG/markdown):",
4747
4763
  "1) Emit a fenced code block tagged `html` (preferred), `svg`, or `markdown` with the FULL document \u2014 Sideboard opens a side column. Example:",
4748
4764
  "```html",
4749
4765
  "<!DOCTYPE html><html><head><title>Demo</title></head><body><h1>Hi</h1></body></html>",
4750
4766
  "```",
4751
- "2) Or call Sideboard MCP `present_artifact` with title, type (html|svg|markdown), and content.",
4767
+ "2) Or call Sideboard MCP `present_artifact` with title, type (html|svg|markdown), and content \u2014 not both a fence and this tool for the same body.",
4752
4768
  "CMS / JSON Schema forms & tables (Brightsy or any schema+schemaUi source):",
4753
- "3) Call Sideboard MCP `present_schema` with title, mode (table|form), and either:",
4769
+ "3) Call Sideboard MCP `present_schema` when the user needs to filter, edit, publish, or persist rows \u2014 including after you already showed a markdown table, if they then ask for an editable table. If they only need to read the data, a markdown table is enough. When you do call it, pass title, mode (table|form), and either:",
4754
4770
  " - datasource=brightsy + resource_id (record type UUID) after fetching types via Brightsy MCP, or",
4755
4771
  " - datasource=inline + resource: { id, title, schema, schemaUi } and optional records/record.",
4756
4772
  "Files / media browser (CMS file manager column):",
@@ -4759,11 +4775,11 @@ function formatArtifactDirective() {
4759
4775
  "Multiple-choice questions:",
4760
4776
  "5) Call Sideboard MCP `ask_user` only when work is blocked on choosing among a few concrete options (approach forks, which API, auth vs cookies). First write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it). Include a description on every option. After calling, stop and wait for their next message with answers. If you are asking a real multiple-choice, use ask_user rather than chat bullets so Sideboard shows the composer picker.",
4761
4777
  "Do not call ask_user for greetings, check-ins, \u201Chello\u201D, open-ended how-can-I-help, or to invent a menu of possible next tasks \u2014 reply in chat. If one option is the obvious default, proceed without asking.",
4762
- "Never say artifacts, CMS UI, or the Files column are unavailable. Prefer present_schema for list/edit/publish; present_files for storage UI; html fences for standalone pages; ask_user only for those blocked predefined-option questions."
4778
+ "Never say artifacts, CMS UI, or the Files column are unavailable. present_schema is for interactive list/edit/publish (use it when they ask to edit, even if chat already had a markdown table); present_files for storage UI; html fences for standalone pages; ask_user only for those blocked predefined-option questions."
4763
4779
  ].join("\n");
4764
4780
  }
4765
4781
  function formatUiReminder() {
4766
- return "Sideboard UI: html fence or present_artifact / present_schema / present_files; ask_user only for a real multiple-choice (not hellos or \u201Cwhat next?\u201D) \u2014 reply in chat. Do not say artifacts/CMS UI are unavailable.";
4782
+ return "Sideboard UI: markdown table is enough to read data; present_schema if they ask to edit/filter (even after markdown); present_files for the file manager. html fence or present_artifact, not both for the same document. ask_user only for a real multiple-choice (not hellos or \u201Cwhat next?\u201D) \u2014 reply in chat. Do not say artifacts/CMS UI are unavailable.";
4767
4783
  }
4768
4784
  var FILES_BY_AGENT = {
4769
4785
  claude: [
@@ -5108,7 +5124,7 @@ function formatScheduledPrompt(name, prompt) {
5108
5124
  ${prompt}`;
5109
5125
  }
5110
5126
  async function defaultDeps() {
5111
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-TXASYNHT.js");
5127
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-MKTZYWTI.js");
5112
5128
  const orch = getOrchestrator2();
5113
5129
  return {
5114
5130
  findThread: (id) => findThreadByRef(id),
@@ -5242,6 +5258,8 @@ var Orchestrator = class {
5242
5258
  draining = /* @__PURE__ */ new Set();
5243
5259
  /** Threads past setStatus(running) but not yet in activeTurns (spawn in flight). */
5244
5260
  startingTurns = /* @__PURE__ */ new Set();
5261
+ /** Last sync thread-file read for false-stop heal (throttled per thread). */
5262
+ lastReconcileHealAt = /* @__PURE__ */ new Map();
5245
5263
  /**
5246
5264
  * Threads intentionally force-stopped. Prevents runTurn from re-asserting
5247
5265
  * `running` after spawn, and from overwriting `stopped` with idle/error when
@@ -5839,7 +5857,13 @@ var Orchestrator = class {
5839
5857
  if (event.type === "stderr" && typeof event.data === "string") {
5840
5858
  pushTurnStderr(stderrTail, event.data);
5841
5859
  }
5842
- if (event.type !== "stdout" && event.type !== "thinking") {
5860
+ const now = Date.now();
5861
+ if (shouldReadThreadToHealReconcile(
5862
+ event.type,
5863
+ this.lastReconcileHealAt.get(threadId),
5864
+ now
5865
+ )) {
5866
+ this.lastReconcileHealAt.set(threadId, now);
5843
5867
  const live = readThread(threadId);
5844
5868
  if (live?.lastError?.includes("reconciled on startup") && (this.activeTurns.has(threadId) || this.startingTurns.has(threadId))) {
5845
5869
  setStatus(threadId, "running");
@@ -5879,11 +5903,12 @@ var Orchestrator = class {
5879
5903
  if (this.requireThread(threadId).agent === "cursor" && exitCode !== 0 && !assistantText && parts.length === 0) {
5880
5904
  const sessionId = result.sessionId || this.requireThread(threadId).sessionId || "";
5881
5905
  if (sessionId) {
5882
- const { recoverFinishedCursorRun } = await import("./cursor-recover-ZUJG6XRQ.js");
5906
+ const { recoverFinishedCursorRun } = await import("./cursor-recover-QSLWEZNA.js");
5883
5907
  for (let i = 0; i < 8; i++) {
5884
5908
  const recovered = recoverFinishedCursorRun({
5885
5909
  agentId: sessionId,
5886
- startedAfterMs: turnStartedAt - 5e3
5910
+ startedAfterMs: turnStartedAt - 5e3,
5911
+ threadId
5887
5912
  });
5888
5913
  if (recovered?.result) {
5889
5914
  assistantText = recovered.result;
@@ -6856,7 +6881,7 @@ var Orchestrator = class {
6856
6881
  this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
6857
6882
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
6858
6883
  try {
6859
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-QG6PGFQR.js");
6884
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-M4OICPWF.js");
6860
6885
  await ensureWorkspace2(thread.repoPath);
6861
6886
  } catch {
6862
6887
  }
@@ -6910,7 +6935,7 @@ var Orchestrator = class {
6910
6935
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
6911
6936
  );
6912
6937
  }
6913
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-IW3BX26B.js");
6938
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-7AEKZSEX.js");
6914
6939
  const slug = thread.worktreePath.split("/").pop();
6915
6940
  const dest = thread.worktreePath;
6916
6941
  await withRepoGitLock(thread.repoPath, async () => {
@@ -7018,7 +7043,7 @@ async function startOrchestration(opts) {
7018
7043
  sourceRef: "default",
7019
7044
  ...createOpts
7020
7045
  }).catch(async () => {
7021
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-IW3BX26B.js");
7046
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-7AEKZSEX.js");
7022
7047
  const repo = await resolveRepoRoot2(repoPath);
7023
7048
  const def = await resolveDefaultBranch2(repo);
7024
7049
  return orch.createThread({
@@ -7028,7 +7053,7 @@ async function startOrchestration(opts) {
7028
7053
  repoPath: repo
7029
7054
  });
7030
7055
  });
7031
- const { updateThread: upd } = await import("./thread-store-OEALWU7Y.js");
7056
+ const { updateThread: upd } = await import("./thread-store-JR235AWK.js");
7032
7057
  const updated = upd(thread.id, {
7033
7058
  sourceType: "orchestration",
7034
7059
  sourceRef: goal
@@ -28,13 +28,13 @@ import {
28
28
  summarizeTurnStderr,
29
29
  toolDescription,
30
30
  turnFailChatText
31
- } from "./chunk-66XTXHR3.js";
31
+ } from "./chunk-4CDCTYTM.js";
32
32
  import {
33
33
  addWorkspace,
34
34
  ensureWorkspace,
35
35
  removeWorkspace,
36
36
  syncWorkspacesFromThreads
37
- } from "./chunk-ZRCX43LS.js";
37
+ } from "./chunk-BKVDZV7X.js";
38
38
  import {
39
39
  extractPresentedPlan,
40
40
  readPlanFile,
@@ -55,14 +55,14 @@ import {
55
55
  isOrchestratorThread,
56
56
  isSlackCoordinatorThread,
57
57
  orchestratorSessionPoisonedByBuiltins
58
- } from "./chunk-XOYQ7LNQ.js";
58
+ } from "./chunk-4NAW5BAQ.js";
59
59
  import {
60
60
  SLACK_REPLY_FORMATTING,
61
61
  coordinatorSystemPrompt,
62
62
  coordinatorTurnReminder,
63
63
  enrichWorkspacesWithGithub,
64
64
  ensureGlobalCoordinatorCwd
65
- } from "./chunk-ZYEFCSZJ.js";
65
+ } from "./chunk-XTZQL7OU.js";
66
66
  import {
67
67
  addPrStackLayer,
68
68
  allocateTeamName,
@@ -105,7 +105,7 @@ import {
105
105
  threadDisplayLabel,
106
106
  withRepoGitLock,
107
107
  worktreeNameFromPath
108
- } from "./chunk-ZMROW673.js";
108
+ } from "./chunk-WCU3FHEI.js";
109
109
  import {
110
110
  ATTACHMENTS_DIR,
111
111
  LEGACY_ATTACHMENTS_DIR,
@@ -122,7 +122,7 @@ import {
122
122
  updateThread,
123
123
  withThreadLock,
124
124
  writeThread
125
- } from "./chunk-KYOTBZ6S.js";
125
+ } from "./chunk-RG737OWT.js";
126
126
  import {
127
127
  clearStaleIndexLocks,
128
128
  enrichPathWithNpmGlobalBin,
@@ -742,9 +742,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
742
742
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
743
743
  );
744
744
  }
745
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-H4YNASM6.js");
745
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-Z37MNYU6.js");
746
746
  if (isGlobalThread2(thread)) {
747
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-FML4I5AR.js");
747
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-XCBHAOGE.js");
748
748
  ensureGlobalCoordinatorCwd2(
749
749
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
750
750
  );
@@ -2410,7 +2410,7 @@ async function createThread(input, _onSetupLine) {
2410
2410
  return readThread(thread.id) ?? thread;
2411
2411
  }
2412
2412
  async function listLinearIssues(agent, repoPath) {
2413
- const { getAdapter: getAdapter2 } = await import("./agents-AHAFC6FR.js");
2413
+ const { getAdapter: getAdapter2 } = await import("./agents-OCGAZCKT.js");
2414
2414
  await requireAgent(agent, { requireLinear: true });
2415
2415
  const adapter = getAdapter2(agent);
2416
2416
  if (!adapter.listLinearIssues) {
@@ -2506,7 +2506,7 @@ function noteTurnLiveEvent(threadId, event) {
2506
2506
  buffers.delete(threadId);
2507
2507
  return;
2508
2508
  }
2509
- const immediate = event.type === "tool_use" || event.type === "tool_result";
2509
+ const immediate = event.type === "tool_use" || event.type === "tool_result" && !event.partial;
2510
2510
  if (immediate) flush(threadId);
2511
2511
  else scheduleFlush(threadId);
2512
2512
  }
@@ -2546,6 +2546,21 @@ function clearTurnLive(threadId) {
2546
2546
  }
2547
2547
  }
2548
2548
 
2549
+ // src/orchestrator/reconcile-heal.ts
2550
+ var RECONCILE_HEAL_MIN_MS = 2e3;
2551
+ var SKIP = /* @__PURE__ */ new Set([
2552
+ "stdout",
2553
+ "thinking",
2554
+ "usage",
2555
+ "stderr",
2556
+ "tool_result"
2557
+ ]);
2558
+ function shouldReadThreadToHealReconcile(eventType, lastCheckAt, now) {
2559
+ if (SKIP.has(eventType)) return false;
2560
+ if (lastCheckAt != null && now - lastCheckAt < RECONCILE_HEAL_MIN_MS) return false;
2561
+ return true;
2562
+ }
2563
+
2549
2564
  // src/threads/fork-worktree.ts
2550
2565
  function requireThread2(idOrRef) {
2551
2566
  const thread = findThreadByRef(idOrRef) ?? null;
@@ -2791,7 +2806,7 @@ async function adoptThread(input) {
2791
2806
  messages: input.messages ?? []
2792
2807
  });
2793
2808
  writeThread(thread);
2794
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-HJ3EVATC.js");
2809
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-C3TJJFY3.js");
2795
2810
  await ensureWorkspace2(repoPath);
2796
2811
  return thread;
2797
2812
  }
@@ -4646,14 +4661,15 @@ function formatArtifactDirective() {
4646
4661
  return [
4647
4662
  "Sideboard side column (desktop UI):",
4648
4663
  "claude.ai\u2019s \u201CArtifact\u201D tool does NOT exist in Claude Code. That is expected.",
4664
+ "Do not unprompted-duplicate a payload. Chat markdown (including tables) already renders in the transcript \u2014 do not also call present_schema with those same rows just to display them. If the user asks for an editable / interactive table, call present_schema even if markdown already showed the data. Do not also call present_artifact for a document you already fenced in chat.",
4649
4665
  "Documents (HTML/SVG/markdown):",
4650
4666
  "1) Emit a fenced code block tagged `html` (preferred), `svg`, or `markdown` with the FULL document \u2014 Sideboard opens a side column. Example:",
4651
4667
  "```html",
4652
4668
  "<!DOCTYPE html><html><head><title>Demo</title></head><body><h1>Hi</h1></body></html>",
4653
4669
  "```",
4654
- "2) Or call Sideboard MCP `present_artifact` with title, type (html|svg|markdown), and content.",
4670
+ "2) Or call Sideboard MCP `present_artifact` with title, type (html|svg|markdown), and content \u2014 not both a fence and this tool for the same body.",
4655
4671
  "CMS / JSON Schema forms & tables (Brightsy or any schema+schemaUi source):",
4656
- "3) Call Sideboard MCP `present_schema` with title, mode (table|form), and either:",
4672
+ "3) Call Sideboard MCP `present_schema` when the user needs to filter, edit, publish, or persist rows \u2014 including after you already showed a markdown table, if they then ask for an editable table. If they only need to read the data, a markdown table is enough. When you do call it, pass title, mode (table|form), and either:",
4657
4673
  " - datasource=brightsy + resource_id (record type UUID) after fetching types via Brightsy MCP, or",
4658
4674
  " - datasource=inline + resource: { id, title, schema, schemaUi } and optional records/record.",
4659
4675
  "Files / media browser (CMS file manager column):",
@@ -4662,11 +4678,11 @@ function formatArtifactDirective() {
4662
4678
  "Multiple-choice questions:",
4663
4679
  "5) Call Sideboard MCP `ask_user` only when work is blocked on choosing among a few concrete options (approach forks, which API, auth vs cookies). First write a short chat message that explains the decision and what each option means (tradeoffs, when to pick it). Include a description on every option. After calling, stop and wait for their next message with answers. If you are asking a real multiple-choice, use ask_user rather than chat bullets so Sideboard shows the composer picker.",
4664
4680
  "Do not call ask_user for greetings, check-ins, \u201Chello\u201D, open-ended how-can-I-help, or to invent a menu of possible next tasks \u2014 reply in chat. If one option is the obvious default, proceed without asking.",
4665
- "Never say artifacts, CMS UI, or the Files column are unavailable. Prefer present_schema for list/edit/publish; present_files for storage UI; html fences for standalone pages; ask_user only for those blocked predefined-option questions."
4681
+ "Never say artifacts, CMS UI, or the Files column are unavailable. present_schema is for interactive list/edit/publish (use it when they ask to edit, even if chat already had a markdown table); present_files for storage UI; html fences for standalone pages; ask_user only for those blocked predefined-option questions."
4666
4682
  ].join("\n");
4667
4683
  }
4668
4684
  function formatUiReminder() {
4669
- return "Sideboard UI: html fence or present_artifact / present_schema / present_files; ask_user only for a real multiple-choice (not hellos or \u201Cwhat next?\u201D) \u2014 reply in chat. Do not say artifacts/CMS UI are unavailable.";
4685
+ return "Sideboard UI: markdown table is enough to read data; present_schema if they ask to edit/filter (even after markdown); present_files for the file manager. html fence or present_artifact, not both for the same document. ask_user only for a real multiple-choice (not hellos or \u201Cwhat next?\u201D) \u2014 reply in chat. Do not say artifacts/CMS UI are unavailable.";
4670
4686
  }
4671
4687
 
4672
4688
  // src/threads/sync-branch.ts
@@ -4937,7 +4953,7 @@ function formatScheduledPrompt(name, prompt) {
4937
4953
  ${prompt}`;
4938
4954
  }
4939
4955
  async function defaultDeps() {
4940
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-GKLYKLRC.js");
4956
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-4PKR6AZJ.js");
4941
4957
  const orch = getOrchestrator2();
4942
4958
  return {
4943
4959
  findThread: (id) => findThreadByRef(id),
@@ -5071,6 +5087,8 @@ var Orchestrator = class {
5071
5087
  draining = /* @__PURE__ */ new Set();
5072
5088
  /** Threads past setStatus(running) but not yet in activeTurns (spawn in flight). */
5073
5089
  startingTurns = /* @__PURE__ */ new Set();
5090
+ /** Last sync thread-file read for false-stop heal (throttled per thread). */
5091
+ lastReconcileHealAt = /* @__PURE__ */ new Map();
5074
5092
  /**
5075
5093
  * Threads intentionally force-stopped. Prevents runTurn from re-asserting
5076
5094
  * `running` after spawn, and from overwriting `stopped` with idle/error when
@@ -5668,7 +5686,13 @@ var Orchestrator = class {
5668
5686
  if (event.type === "stderr" && typeof event.data === "string") {
5669
5687
  pushTurnStderr(stderrTail, event.data);
5670
5688
  }
5671
- if (event.type !== "stdout" && event.type !== "thinking") {
5689
+ const now = Date.now();
5690
+ if (shouldReadThreadToHealReconcile(
5691
+ event.type,
5692
+ this.lastReconcileHealAt.get(threadId),
5693
+ now
5694
+ )) {
5695
+ this.lastReconcileHealAt.set(threadId, now);
5672
5696
  const live = readThread(threadId);
5673
5697
  if (live?.lastError?.includes("reconciled on startup") && (this.activeTurns.has(threadId) || this.startingTurns.has(threadId))) {
5674
5698
  setStatus(threadId, "running");
@@ -5708,11 +5732,12 @@ var Orchestrator = class {
5708
5732
  if (this.requireThread(threadId).agent === "cursor" && exitCode !== 0 && !assistantText && parts.length === 0) {
5709
5733
  const sessionId = result.sessionId || this.requireThread(threadId).sessionId || "";
5710
5734
  if (sessionId) {
5711
- const { recoverFinishedCursorRun } = await import("./cursor-recover-JBTIDARH.js");
5735
+ const { recoverFinishedCursorRun } = await import("./cursor-recover-NOQYOFRF.js");
5712
5736
  for (let i = 0; i < 8; i++) {
5713
5737
  const recovered = recoverFinishedCursorRun({
5714
5738
  agentId: sessionId,
5715
- startedAfterMs: turnStartedAt - 5e3
5739
+ startedAfterMs: turnStartedAt - 5e3,
5740
+ threadId
5716
5741
  });
5717
5742
  if (recovered?.result) {
5718
5743
  assistantText = recovered.result;
@@ -6685,7 +6710,7 @@ var Orchestrator = class {
6685
6710
  this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
6686
6711
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
6687
6712
  try {
6688
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-HJ3EVATC.js");
6713
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-C3TJJFY3.js");
6689
6714
  await ensureWorkspace2(thread.repoPath);
6690
6715
  } catch {
6691
6716
  }
@@ -6739,7 +6764,7 @@ var Orchestrator = class {
6739
6764
  `Cowboy checkout missing: ${thread.worktreePath}. Re-add the project folder, then restore.`
6740
6765
  );
6741
6766
  }
6742
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-OTFQO2W7.js");
6767
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-MRSTQ32S.js");
6743
6768
  const slug = thread.worktreePath.split("/").pop();
6744
6769
  const dest = thread.worktreePath;
6745
6770
  await withRepoGitLock(thread.repoPath, async () => {
@@ -6847,7 +6872,7 @@ async function startOrchestration(opts) {
6847
6872
  sourceRef: "default",
6848
6873
  ...createOpts
6849
6874
  }).catch(async () => {
6850
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-OTFQO2W7.js");
6875
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-MRSTQ32S.js");
6851
6876
  const repo = await resolveRepoRoot2(repoPath);
6852
6877
  const def = await resolveDefaultBranch2(repo);
6853
6878
  return orch.createThread({
@@ -6857,7 +6882,7 @@ async function startOrchestration(opts) {
6857
6882
  repoPath: repo
6858
6883
  });
6859
6884
  });
6860
- const { updateThread: upd } = await import("./thread-store-LPTBVW5C.js");
6885
+ const { updateThread: upd } = await import("./thread-store-PMH3BMB6.js");
6861
6886
  const updated = upd(thread.id, {
6862
6887
  sourceType: "orchestration",
6863
6888
  sourceRef: goal
@@ -2,11 +2,11 @@
2
2
 
3
3
  import {
4
4
  isGlobalRepoPath
5
- } from "./chunk-XOYQ7LNQ.js";
5
+ } from "./chunk-4NAW5BAQ.js";
6
6
  import {
7
7
  ensureGhPreferOrigin,
8
8
  resolveRepoRoot
9
- } from "./chunk-ZMROW673.js";
9
+ } from "./chunk-WCU3FHEI.js";
10
10
  import {
11
11
  appDataDir
12
12
  } from "./chunk-BD2ICC4D.js";
@@ -17,6 +17,7 @@ import {
17
17
  writeFileSync,
18
18
  readdirSync
19
19
  } from "fs";
20
+ import { basename } from "path";
20
21
  import lockfile from "proper-lockfile";
21
22
  function nowIso() {
22
23
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -119,7 +120,8 @@ function writeThread(thread) {
119
120
  function idPath(id) {
120
121
  return id;
121
122
  }
122
- function isThreadRecordFile(name) {
123
+ function isThreadRecordFile(nameOrPath) {
124
+ const name = basename(nameOrPath);
123
125
  return name.endsWith(".json") && !name.endsWith(".live.json");
124
126
  }
125
127
  function listThreads(opts) {
@@ -178,6 +180,7 @@ export {
178
180
  withThreadLock,
179
181
  readThread,
180
182
  writeThread,
183
+ isThreadRecordFile,
181
184
  listThreads,
182
185
  deleteThreadRecord,
183
186
  updateThread,
@@ -130,7 +130,7 @@ function summarizeTurnStderr(tail, maxChars = 500) {
130
130
  function looksLikeInvalidAgentSession(text) {
131
131
  const lower = text.trim().toLowerCase();
132
132
  if (!lower) return false;
133
- 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) || /corrupt local agent checkpoint/.test(lower) || /missing root blob/.test(lower) || /\bagent\b.{0,120}\bnot found\b/.test(lower);
133
+ 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) || /corrupt local agent checkpoint/.test(lower) || /missing root blob/.test(lower) || /\bagent\b.{0,120}\bnot found\b/.test(lower) || /\brun\b.{0,80}\bnot found for agent\b/.test(lower);
134
134
  }
135
135
  function looksLikeRetryableRunnerCrash(text) {
136
136
  if (looksLikeAgentFailureMessage(text)) return false;
@@ -585,7 +585,7 @@ function cursorSdkMessageToEvents(msg) {
585
585
  if (msg.type === "tool_call" && msg.call_id && msg.name) {
586
586
  const normalized = normalizeCursorToolCall(msg.name, msg.args);
587
587
  if (msg.status === "running") {
588
- return [
588
+ const events = [
589
589
  {
590
590
  type: "tool_use",
591
591
  id: msg.call_id,
@@ -593,6 +593,16 @@ function cursorSdkMessageToEvents(msg) {
593
593
  input: normalized.input
594
594
  }
595
595
  ];
596
+ const live = unwrapCursorToolResult(msg.result);
597
+ if (live) {
598
+ events.push({
599
+ type: "tool_result",
600
+ id: msg.call_id,
601
+ content: live,
602
+ partial: true
603
+ });
604
+ }
605
+ return events;
596
606
  }
597
607
  if (msg.status === "completed" || msg.status === "error") {
598
608
  return [
@@ -653,6 +663,17 @@ function nestedUpdateToEvents(update, parentId) {
653
663
  isError: cursorToolResultIsError(void 0, update.toolCall.result),
654
664
  parentId
655
665
  });
666
+ } else {
667
+ const live = unwrapCursorToolResult(update.toolCall.result);
668
+ if (live) {
669
+ events.push({
670
+ type: "tool_result",
671
+ id: update.callId,
672
+ content: live,
673
+ partial: true,
674
+ parentId
675
+ });
676
+ }
656
677
  }
657
678
  return events;
658
679
  }
@@ -19,6 +19,7 @@ import {
19
19
  writeFileSync,
20
20
  readdirSync
21
21
  } from "fs";
22
+ import { basename } from "path";
22
23
  import lockfile from "proper-lockfile";
23
24
  function nowIso() {
24
25
  return (/* @__PURE__ */ new Date()).toISOString();
@@ -121,7 +122,8 @@ function writeThread(thread) {
121
122
  function idPath(id) {
122
123
  return id;
123
124
  }
124
- function isThreadRecordFile(name) {
125
+ function isThreadRecordFile(nameOrPath) {
126
+ const name = basename(nameOrPath);
125
127
  return name.endsWith(".json") && !name.endsWith(".live.json");
126
128
  }
127
129
  function listThreads(opts) {
@@ -180,6 +182,7 @@ export {
180
182
  withThreadLock,
181
183
  readThread,
182
184
  writeThread,
185
+ isThreadRecordFile,
183
186
  listThreads,
184
187
  deleteThreadRecord,
185
188
  updateThread,
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  isGlobalRepoPath
3
- } from "./chunk-4OJMZ6P2.js";
3
+ } from "./chunk-4WV7C7WP.js";
4
4
  import {
5
5
  ensureGhPreferOrigin,
6
6
  resolveRepoRoot
7
- } from "./chunk-FZCIQYNQ.js";
7
+ } from "./chunk-VGPLXQIH.js";
8
8
  import {
9
9
  appDataDir
10
10
  } from "./chunk-QZQEXME2.js";
@@ -7,7 +7,7 @@ import {
7
7
  } from "./chunk-4NR5FL46.js";
8
8
  import {
9
9
  listThreads
10
- } from "./chunk-A4VZXJEJ.js";
10
+ } from "./chunk-HPAWHIZ3.js";
11
11
  import {
12
12
  worktreesRoot
13
13
  } from "./chunk-QZQEXME2.js";
@@ -0,0 +1,32 @@
1
+ import {
2
+ appDataDir
3
+ } from "./chunk-QZQEXME2.js";
4
+
5
+ // src/agents/cursor-store.ts
6
+ import { join } from "path";
7
+ var CURSOR_SDK_STORE_DIR = "cursor-sdk-store";
8
+ function cursorSdkStoreDir(threadId) {
9
+ const root = join(appDataDir(), CURSOR_SDK_STORE_DIR);
10
+ const id = sanitizeCursorStoreSegment(threadId);
11
+ if (!id) return root;
12
+ return join(root, "threads", id);
13
+ }
14
+ function cursorSdkRunsNdjsonPath(threadId) {
15
+ return join(cursorSdkStoreDir(threadId), "runs.ndjson");
16
+ }
17
+ function cursorSdkRunsNdjsonSearchPaths(threadId) {
18
+ const scoped = cursorSdkRunsNdjsonPath(threadId);
19
+ const shared = cursorSdkRunsNdjsonPath(null);
20
+ if (!threadId || !sanitizeCursorStoreSegment(threadId) || scoped === shared) {
21
+ return [shared];
22
+ }
23
+ return [scoped, shared];
24
+ }
25
+ function sanitizeCursorStoreSegment(threadId) {
26
+ return (threadId ?? "").trim().replace(/[^a-zA-Z0-9._-]/g, "_");
27
+ }
28
+
29
+ export {
30
+ cursorSdkStoreDir,
31
+ cursorSdkRunsNdjsonSearchPaths
32
+ };
@@ -5,7 +5,7 @@ import {
5
5
  } from "./chunk-B3SJXYIJ.js";
6
6
  import {
7
7
  listThreads
8
- } from "./chunk-KYOTBZ6S.js";
8
+ } from "./chunk-RG737OWT.js";
9
9
  import {
10
10
  gh,
11
11
  git,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveGithubRepoSlug
3
- } from "./chunk-FZCIQYNQ.js";
3
+ } from "./chunk-VGPLXQIH.js";
4
4
  import {
5
5
  resolveThreadDefaults
6
6
  } from "./chunk-4NR5FL46.js";
@@ -2,7 +2,7 @@
2
2
 
3
3
  import {
4
4
  resolveGithubRepoSlug
5
- } from "./chunk-ZMROW673.js";
5
+ } from "./chunk-WCU3FHEI.js";
6
6
  import {
7
7
  resolveThreadDefaults
8
8
  } from "./chunk-SGEVS5SY.js";