@sideboard-ai/core 0.1.39 → 0.1.42

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.
@@ -198,18 +198,35 @@ async function main() {
198
198
  const store = localAgentStore();
199
199
  const local = { cwd: req.cwd, store };
200
200
  try {
201
- const agent = req.agentId ? await import_sdk.Agent.resume(req.agentId, {
202
- apiKey,
203
- model,
204
- mode,
205
- local
206
- }) : await import_sdk.Agent.create({
207
- apiKey,
208
- model,
209
- mode,
210
- local,
211
- name: "Sideboard"
212
- });
201
+ let agent;
202
+ try {
203
+ agent = req.agentId ? await import_sdk.Agent.resume(req.agentId, {
204
+ apiKey,
205
+ model,
206
+ mode,
207
+ local
208
+ }) : await import_sdk.Agent.create({
209
+ apiKey,
210
+ model,
211
+ mode,
212
+ local,
213
+ name: "Sideboard"
214
+ });
215
+ } catch (err) {
216
+ const message = err instanceof Error ? err.message : String(err);
217
+ if (!req.agentId || !/not found/i.test(message)) throw err;
218
+ emit({
219
+ type: "stderr",
220
+ data: `Cursor agent ${req.agentId} not found \u2014 starting a new session`
221
+ });
222
+ agent = await import_sdk.Agent.create({
223
+ apiKey,
224
+ model,
225
+ mode,
226
+ local,
227
+ name: "Sideboard"
228
+ });
229
+ }
213
230
  try {
214
231
  emit({ type: "session_id", data: agent.agentId });
215
232
  const run = await agent.send(req.prompt);
@@ -62,18 +62,35 @@ async function main() {
62
62
  const store = localAgentStore();
63
63
  const local = { cwd: req.cwd, store };
64
64
  try {
65
- const agent = req.agentId ? await Agent.resume(req.agentId, {
66
- apiKey,
67
- model,
68
- mode,
69
- local
70
- }) : await Agent.create({
71
- apiKey,
72
- model,
73
- mode,
74
- local,
75
- name: "Sideboard"
76
- });
65
+ let agent;
66
+ try {
67
+ agent = req.agentId ? await Agent.resume(req.agentId, {
68
+ apiKey,
69
+ model,
70
+ mode,
71
+ local
72
+ }) : await Agent.create({
73
+ apiKey,
74
+ model,
75
+ mode,
76
+ local,
77
+ name: "Sideboard"
78
+ });
79
+ } catch (err) {
80
+ const message = err instanceof Error ? err.message : String(err);
81
+ if (!req.agentId || !/not found/i.test(message)) throw err;
82
+ emit({
83
+ type: "stderr",
84
+ data: `Cursor agent ${req.agentId} not found \u2014 starting a new session`
85
+ });
86
+ agent = await Agent.create({
87
+ apiKey,
88
+ model,
89
+ mode,
90
+ local,
91
+ name: "Sideboard"
92
+ });
93
+ }
77
94
  try {
78
95
  emit({ type: "session_id", data: agent.agentId });
79
96
  const run = await agent.send(req.prompt);
@@ -21,7 +21,7 @@ import {
21
21
  opencodeAdapter,
22
22
  permissionMode,
23
23
  resolveCursorModelId
24
- } from "./chunk-BEXVE7LX.js";
24
+ } from "./chunk-SX2R2PCE.js";
25
25
  import "./chunk-ILQK4P5R.js";
26
26
  import {
27
27
  cursorSdkMessageToEvents,
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  isGlobalRepoPath
3
- } from "./chunk-IS3AGU33.js";
3
+ } from "./chunk-6TZSJMXF.js";
4
4
  import {
5
5
  ensureGhPreferOrigin,
6
6
  resolveRepoRoot
7
- } from "./chunk-XBEQI5H4.js";
7
+ } from "./chunk-VA2U5EQH.js";
8
8
  import {
9
9
  appDataDir
10
10
  } from "./chunk-M37RITA6.js";
@@ -26,6 +26,7 @@ function normalizeThread(raw) {
26
26
  planMode: Boolean(raw.planMode),
27
27
  autonomy: raw.autonomy ?? "default",
28
28
  lastError: raw.lastError ?? null,
29
+ agentPid: raw.agentPid ?? null,
29
30
  attachments: Array.isArray(raw.attachments) ? raw.attachments : [],
30
31
  prTitle: raw.prTitle ?? null,
31
32
  userSetTitle: Boolean(raw.userSetTitle),
@@ -61,7 +62,8 @@ function createEmptyThread(partial) {
61
62
  worktreePath: partial.worktreePath,
62
63
  repoPath: partial.repoPath,
63
64
  agent: partial.agent,
64
- lastError: null
65
+ lastError: null,
66
+ agentPid: null
65
67
  };
66
68
  }
67
69
  async function withThreadLock(id, fn) {
@@ -1,17 +1,17 @@
1
1
  import {
2
2
  ensureGlobalCoordinatorCwd
3
- } from "./chunk-PTASB7SJ.js";
3
+ } from "./chunk-UPMGXM4X.js";
4
4
  import {
5
5
  allocateTeamName,
6
6
  takenSlugsFromThread,
7
7
  teamSlugFromName
8
- } from "./chunk-XBEQI5H4.js";
8
+ } from "./chunk-VA2U5EQH.js";
9
9
  import {
10
10
  createEmptyThread,
11
11
  listThreads,
12
12
  updateThread,
13
13
  writeThread
14
- } from "./chunk-HYRHI3QU.js";
14
+ } from "./chunk-5UIKSPDD.js";
15
15
  import {
16
16
  globalAgentCwd
17
17
  } from "./chunk-M37RITA6.js";
@@ -3,7 +3,7 @@ import {
3
3
  ensureWorkspace,
4
4
  removeWorkspace,
5
5
  syncWorkspacesFromThreads
6
- } from "./chunk-FVGRUZHI.js";
6
+ } from "./chunk-44LYDJFB.js";
7
7
  import {
8
8
  GLOBAL_WORKSPACE_ID,
9
9
  createGlobalChat,
@@ -13,19 +13,19 @@ import {
13
13
  isGlobalThread,
14
14
  isOrchestratorThread,
15
15
  orchestratorSessionPoisonedByBuiltins
16
- } from "./chunk-IS3AGU33.js";
16
+ } from "./chunk-6TZSJMXF.js";
17
17
  import {
18
18
  coordinatorSystemPrompt,
19
19
  coordinatorTurnReminder,
20
20
  enrichWorkspacesWithGithub,
21
21
  ensureGlobalCoordinatorCwd
22
- } from "./chunk-PTASB7SJ.js";
22
+ } from "./chunk-UPMGXM4X.js";
23
23
  import {
24
24
  PLAN_MODE_INSTRUCTION,
25
25
  allAdapters,
26
26
  getAdapter,
27
27
  parseBrightsyCliLine
28
- } from "./chunk-BEXVE7LX.js";
28
+ } from "./chunk-SX2R2PCE.js";
29
29
  import {
30
30
  fallbackTurnFailDetail,
31
31
  formatTurnExitError,
@@ -71,7 +71,7 @@ import {
71
71
  takenSlugsFromThread,
72
72
  threadDisplayLabel,
73
73
  worktreeNameFromPath
74
- } from "./chunk-XBEQI5H4.js";
74
+ } from "./chunk-VA2U5EQH.js";
75
75
  import {
76
76
  appendMessage,
77
77
  createEmptyThread,
@@ -83,7 +83,7 @@ import {
83
83
  updateThread,
84
84
  withThreadLock,
85
85
  writeThread
86
- } from "./chunk-HYRHI3QU.js";
86
+ } from "./chunk-5UIKSPDD.js";
87
87
  import {
88
88
  loadRepoSettings,
89
89
  loadWorkspaceSettings,
@@ -459,9 +459,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
459
459
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
460
460
  );
461
461
  }
462
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-QSRP25HQ.js");
462
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-4GVWSCEX.js");
463
463
  if (isGlobalThread2(thread)) {
464
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-WIYQVMOG.js");
464
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-FAILHO4J.js");
465
465
  ensureGlobalCoordinatorCwd2();
466
466
  }
467
467
  const adapter = getAdapter(thread.agent);
@@ -631,6 +631,31 @@ function formatWorktreeDirective(thread, opts) {
631
631
  "- Prefer a draft PR first: `gh pr create --draft -R <origin-owner/name>` (or update via `gh pr edit -R \u2026`) once the change set is coherent. Resolve `<origin-owner/name>` with `git remote get-url origin` in this worktree \u2014 never from `upstream`. Mark ready for review only when asked. Title/body must reflect the change purpose, not the worktree name."
632
632
  );
633
633
  }
634
+ lines.push("");
635
+ lines.push(
636
+ "Short git requests from the Sideboard UI are complete instructions \u2014 expand them using the rules above without asking for clarification:"
637
+ );
638
+ lines.push(
639
+ '- "Commit and push." \u2192 commit any uncommitted work with a purpose-stating message, then push to origin (updates an existing PR if one is linked).'
640
+ );
641
+ lines.push(
642
+ '- "Commit, push, and open a draft PR." \u2192 commit, push, then create a draft PR with `gh pr create --draft -R \u2026` (title/body from the change purpose).'
643
+ );
644
+ lines.push(
645
+ '- "Commit, push, and open a PR in the browser." \u2192 commit, push, then `gh pr create --web -R \u2026`.'
646
+ );
647
+ lines.push(
648
+ '- "Fix CI: <name>." \u2192 investigate that failing check, fix it, commit, and push.'
649
+ );
650
+ lines.push(
651
+ '- "Update the branch." / "Fix merge conflicts." \u2192 sync with the PR base (merge or rebase), resolve conflicts carefully, commit, and push until the PR is mergeable.'
652
+ );
653
+ lines.push(
654
+ '- "Address review comments." \u2192 read PR review feedback, make the requested changes, commit, and push.'
655
+ );
656
+ lines.push(
657
+ '- "Merge PR." \u2192 merge this thread\'s open pull request with `gh pr merge` (respect repo defaults / squash vs merge); do not force-push main/master.'
658
+ );
634
659
  return lines.join("\n");
635
660
  }
636
661
  function formatArtifactDirective() {
@@ -2614,7 +2639,7 @@ async function createThread(input, onSetupLine) {
2614
2639
  return readThread(thread.id) ?? thread;
2615
2640
  }
2616
2641
  async function listLinearIssues(agent, repoPath) {
2617
- const { getAdapter: getAdapter2 } = await import("./agents-DDW4NBBW.js");
2642
+ const { getAdapter: getAdapter2 } = await import("./agents-T6XHC5OV.js");
2618
2643
  await requireAgent(agent, { requireLinear: true });
2619
2644
  const adapter = getAdapter2(agent);
2620
2645
  if (!adapter.listLinearIssues) {
@@ -2834,7 +2859,7 @@ async function adoptThread(input) {
2834
2859
  messages: input.messages ?? []
2835
2860
  });
2836
2861
  writeThread(thread);
2837
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-DMYWHVJC.js");
2862
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-Z7CSL4O6.js");
2838
2863
  await ensureWorkspace2(repoPath);
2839
2864
  return thread;
2840
2865
  }
@@ -3296,6 +3321,15 @@ async function syncThreadBranchFromGit(threadId) {
3296
3321
  }
3297
3322
 
3298
3323
  // src/orchestrator/orchestrator.ts
3324
+ function isPidAlive(pid) {
3325
+ if (!Number.isFinite(pid) || pid <= 0) return false;
3326
+ try {
3327
+ process.kill(pid, 0);
3328
+ return true;
3329
+ } catch {
3330
+ return false;
3331
+ }
3332
+ }
3299
3333
  var Orchestrator = class {
3300
3334
  events = new EventEmitter();
3301
3335
  processes = /* @__PURE__ */ new Map();
@@ -3332,8 +3366,18 @@ var Orchestrator = class {
3332
3366
  isStaleRunningThread(threadId, status) {
3333
3367
  return status === "running" && !this.activeTurns.has(threadId) && !this.startingTurns.has(threadId);
3334
3368
  }
3369
+ /**
3370
+ * Cross-process guard: another Sideboard process (MCP stdio) may call reconcile
3371
+ * while the desktop still owns a live agent child. Never reclaim those.
3372
+ */
3373
+ shouldReclaimRunningThread(thread) {
3374
+ if (!this.isStaleRunningThread(thread.id, thread.status)) return false;
3375
+ const pid = thread.agentPid;
3376
+ if (typeof pid === "number" && pid > 0 && isPidAlive(pid)) return false;
3377
+ return true;
3378
+ }
3335
3379
  async reconcile(repoPath, opts) {
3336
- const reclaimStaleTurns = opts?.reclaimStaleTurns !== false;
3380
+ const reclaimStaleTurns = opts?.reclaimStaleTurns === true;
3337
3381
  healOrchestrationSoccerTitles();
3338
3382
  for (const thread of listThreads({ includeArchived: true })) {
3339
3383
  if (thread.status === "archived") continue;
@@ -3349,7 +3393,7 @@ var Orchestrator = class {
3349
3393
  if (Object.keys(heal).length) {
3350
3394
  updateThread(thread.id, heal);
3351
3395
  }
3352
- if (reclaimStaleTurns && this.isStaleRunningThread(thread.id, thread.status)) {
3396
+ if (reclaimStaleTurns && this.shouldReclaimRunningThread(thread)) {
3353
3397
  setStatus(thread.id, "stopped", "Process died (reconciled on startup)");
3354
3398
  this.emit({ type: "status_changed", threadId: thread.id, status: "stopped" });
3355
3399
  }
@@ -3360,7 +3404,7 @@ var Orchestrator = class {
3360
3404
  this.emit({ type: "status_changed", threadId: thread.id, status: "broken" });
3361
3405
  continue;
3362
3406
  }
3363
- if (reclaimStaleTurns && this.isStaleRunningThread(thread.id, thread.status)) {
3407
+ if (reclaimStaleTurns && this.shouldReclaimRunningThread(thread)) {
3364
3408
  setStatus(thread.id, "stopped", "Process died (reconciled on startup)");
3365
3409
  this.emit({ type: "status_changed", threadId: thread.id, status: "stopped" });
3366
3410
  }
@@ -3542,6 +3586,11 @@ var Orchestrator = class {
3542
3586
  await new Promise((r) => setTimeout(r, 100));
3543
3587
  continue;
3544
3588
  }
3589
+ const livePid = thread.agentPid;
3590
+ if (typeof livePid === "number" && livePid > 0 && isPidAlive(livePid)) {
3591
+ await new Promise((r) => setTimeout(r, 200));
3592
+ continue;
3593
+ }
3545
3594
  const prompt = thread.queue[0];
3546
3595
  const remaining = thread.queue.slice(1);
3547
3596
  updateThread(threadId, { queue: remaining });
@@ -3685,10 +3734,18 @@ var Orchestrator = class {
3685
3734
  if (event.type === "stderr" && typeof event.data === "string") {
3686
3735
  pushTurnStderr(stderrTail, event.data);
3687
3736
  }
3737
+ const live = readThread(threadId);
3738
+ if (live?.lastError?.includes("reconciled on startup") && (this.activeTurns.has(threadId) || this.startingTurns.has(threadId))) {
3739
+ setStatus(threadId, "running");
3740
+ this.emit({ type: "status_changed", threadId, status: "running" });
3741
+ }
3688
3742
  }
3689
3743
  );
3690
3744
  this.activeTurns.set(threadId, handle);
3691
3745
  this.startingTurns.delete(threadId);
3746
+ if (typeof handle.pid === "number" && handle.pid > 0) {
3747
+ updateThread(threadId, { agentPid: handle.pid });
3748
+ }
3692
3749
  if (this.stoppedTurns.has(threadId)) {
3693
3750
  handle.kill();
3694
3751
  } else {
@@ -3708,20 +3765,41 @@ var Orchestrator = class {
3708
3765
  if (result.sessionId) {
3709
3766
  updateThread(threadId, { sessionId: result.sessionId });
3710
3767
  }
3711
- const assistantText = result.assistantText.trim();
3712
- const failureOnlyMessage = result.exitCode !== 0 && looksLikeAgentFailureMessage(assistantText) && !result.parts.some((p) => p.type === "tool" || p.type === "thinking");
3713
- if (!failureOnlyMessage && (assistantText || result.parts.length > 0)) {
3768
+ let assistantText = result.assistantText.trim();
3769
+ let parts = result.parts;
3770
+ let usage = result.usage ?? void 0;
3771
+ let exitCode = result.exitCode;
3772
+ if (this.requireThread(threadId).agent === "cursor" && exitCode !== 0 && !assistantText && parts.length === 0) {
3773
+ const sessionId = result.sessionId || this.requireThread(threadId).sessionId || "";
3774
+ if (sessionId) {
3775
+ const { recoverFinishedCursorRun } = await import("./cursor-recover-L5PNQUDT.js");
3776
+ for (let i = 0; i < 8; i++) {
3777
+ const recovered = recoverFinishedCursorRun({
3778
+ agentId: sessionId,
3779
+ startedAfterMs: turnStartedAt - 5e3
3780
+ });
3781
+ if (recovered?.result) {
3782
+ assistantText = recovered.result;
3783
+ exitCode = 0;
3784
+ break;
3785
+ }
3786
+ await new Promise((r) => setTimeout(r, 500));
3787
+ }
3788
+ }
3789
+ }
3790
+ const failureOnlyMessage = exitCode !== 0 && looksLikeAgentFailureMessage(assistantText) && !parts.some((p) => p.type === "tool" || p.type === "thinking");
3791
+ if (!failureOnlyMessage && (assistantText || parts.length > 0)) {
3714
3792
  appendMessage(threadId, {
3715
3793
  role: "agent",
3716
3794
  text: assistantText,
3717
- parts: result.parts.length > 0 ? result.parts : void 0,
3795
+ parts: parts.length > 0 ? parts : void 0,
3718
3796
  durationMs: Math.max(0, Date.now() - turnStartedAt),
3719
- usage: result.usage ?? void 0,
3797
+ usage,
3720
3798
  ts: (/* @__PURE__ */ new Date()).toISOString()
3721
3799
  });
3722
3800
  }
3723
3801
  const afterTurn = this.requireThread(threadId);
3724
- if (afterTurn.planMode && afterTurn.agent === "claude" && result.parts.some(
3802
+ if (afterTurn.planMode && afterTurn.agent === "claude" && parts.some(
3725
3803
  (p) => p.type === "tool" && /exitplanmode/i.test(p.name)
3726
3804
  )) {
3727
3805
  updateThread(threadId, { sessionId: null });
@@ -3730,22 +3808,22 @@ var Orchestrator = class {
3730
3808
  if (this.stoppedTurns.has(threadId)) {
3731
3809
  setStatus(threadId, "stopped");
3732
3810
  this.emit({ type: "status_changed", threadId, status: "stopped" });
3733
- this.emit({ type: "turn_finished", threadId, exitCode: result.exitCode });
3811
+ this.emit({ type: "turn_finished", threadId, exitCode });
3734
3812
  } else {
3735
3813
  const lastStderr = summarizeTurnStderr(stderrTail);
3736
- const detail = lastStderr || (result.exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
3737
- const failDetail = formatTurnExitError(result.exitCode, detail);
3814
+ const detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
3815
+ const failDetail = formatTurnExitError(exitCode, detail);
3738
3816
  setStatus(
3739
3817
  threadId,
3740
- result.exitCode === 0 ? "idle" : "error",
3741
- result.exitCode === 0 ? null : failDetail
3818
+ exitCode === 0 ? "idle" : "error",
3819
+ exitCode === 0 ? null : failDetail
3742
3820
  );
3743
3821
  this.emit({
3744
3822
  type: "status_changed",
3745
3823
  threadId,
3746
- status: result.exitCode === 0 ? "idle" : "error"
3824
+ status: exitCode === 0 ? "idle" : "error"
3747
3825
  });
3748
- this.emit({ type: "turn_finished", threadId, exitCode: result.exitCode });
3826
+ this.emit({ type: "turn_finished", threadId, exitCode });
3749
3827
  }
3750
3828
  } catch (err) {
3751
3829
  const message = err instanceof Error ? err.message : String(err);
@@ -3766,6 +3844,10 @@ var Orchestrator = class {
3766
3844
  this.processes.delete(`${threadId}:agent`);
3767
3845
  this.stoppedTurns.delete(threadId);
3768
3846
  this.runningCount = Math.max(0, this.runningCount - 1);
3847
+ try {
3848
+ updateThread(threadId, { agentPid: null });
3849
+ } catch {
3850
+ }
3769
3851
  }
3770
3852
  }
3771
3853
  /**
@@ -4339,7 +4421,7 @@ var Orchestrator = class {
4339
4421
  return setStatus(thread.id, "idle");
4340
4422
  }
4341
4423
  if (!existsSync11(thread.worktreePath)) {
4342
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-37FBII5A.js");
4424
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-M3DTPYBW.js");
4343
4425
  const { execa: execa6 } = await import("execa");
4344
4426
  const slug = thread.worktreePath.split("/").pop();
4345
4427
  const dest = thread.worktreePath;
@@ -4422,7 +4504,7 @@ async function startOrchestration(opts) {
4422
4504
  sourceRef: "default",
4423
4505
  ...createOpts
4424
4506
  }).catch(async () => {
4425
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-37FBII5A.js");
4507
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-M3DTPYBW.js");
4426
4508
  const repo = await resolveRepoRoot2(repoPath);
4427
4509
  const def = await resolveDefaultBranch2(repo);
4428
4510
  return createThread({
@@ -4432,7 +4514,7 @@ async function startOrchestration(opts) {
4432
4514
  repoPath: repo
4433
4515
  });
4434
4516
  });
4435
- const { updateThread: upd } = await import("./thread-store-UNPZNIFW.js");
4517
+ const { updateThread: upd } = await import("./thread-store-WPLT3IXM.js");
4436
4518
  const updated = upd(thread.id, {
4437
4519
  sourceType: "orchestration",
4438
4520
  sourceRef: goal
@@ -5115,6 +5197,7 @@ export {
5115
5197
  worktreeCleanupSettings,
5116
5198
  applyThreadIntoMain,
5117
5199
  cloneRepoIntoSideboard,
5200
+ isPidAlive,
5118
5201
  Orchestrator,
5119
5202
  getOrchestrator,
5120
5203
  startOrchestration,
@@ -798,7 +798,7 @@ var claudeAdapter = {
798
798
  );
799
799
  }
800
800
  const mode = permissionMode(thread);
801
- const { isOrchestratorThread } = await import("./global-workspace-QSRP25HQ.js");
801
+ const { isOrchestratorThread } = await import("./global-workspace-4GVWSCEX.js");
802
802
  const isOrchestrator = isOrchestratorThread(thread);
803
803
  const injectedServers = await buildInjectedMcpServers({
804
804
  includeSideboard: true,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  resolveGithubRepoSlug
3
- } from "./chunk-XBEQI5H4.js";
3
+ } from "./chunk-VA2U5EQH.js";
4
4
  import {
5
5
  globalAgentCwd,
6
6
  sideboardReposDir
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  listThreads
3
- } from "./chunk-HYRHI3QU.js";
3
+ } from "./chunk-5UIKSPDD.js";
4
4
  import {
5
5
  worktreesRoot
6
6
  } from "./chunk-M37RITA6.js";
@@ -6,9 +6,9 @@ import {
6
6
  enrichWorkspacesWithGithub,
7
7
  ensureGlobalCoordinatorCwd,
8
8
  formatWorkspaceInventory
9
- } from "./chunk-PTASB7SJ.js";
10
- import "./chunk-XBEQI5H4.js";
11
- import "./chunk-HYRHI3QU.js";
9
+ } from "./chunk-UPMGXM4X.js";
10
+ import "./chunk-VA2U5EQH.js";
11
+ import "./chunk-5UIKSPDD.js";
12
12
  import "./chunk-M37RITA6.js";
13
13
  import "./chunk-AJ6ROGD7.js";
14
14
  export {
@@ -0,0 +1,42 @@
1
+ import {
2
+ appDataDir
3
+ } from "./chunk-M37RITA6.js";
4
+
5
+ // src/agents/cursor-recover.ts
6
+ import { existsSync, readFileSync } from "fs";
7
+ import { join } from "path";
8
+ function recoverFinishedCursorRun(opts) {
9
+ const agentId = opts.agentId.trim();
10
+ if (!agentId) return null;
11
+ const runsPath = join(appDataDir(), "cursor-sdk-store", "runs.ndjson");
12
+ if (!existsSync(runsPath)) return null;
13
+ try {
14
+ const lines = readFileSync(runsPath, "utf8").split("\n");
15
+ let best = null;
16
+ for (const line of lines) {
17
+ const trimmed = line.trim();
18
+ if (!trimmed) continue;
19
+ let row;
20
+ try {
21
+ row = JSON.parse(trimmed);
22
+ } catch {
23
+ continue;
24
+ }
25
+ if (row.agentId !== agentId) continue;
26
+ if (row.status !== "finished") continue;
27
+ if (typeof row.result !== "string" || !row.result.trim()) continue;
28
+ const endedAt = typeof row.endedAt === "number" ? row.endedAt : 0;
29
+ const createdAt = typeof row.createdAt === "number" ? row.createdAt : 0;
30
+ if (createdAt < opts.startedAfterMs && endedAt < opts.startedAfterMs) continue;
31
+ if (!best || endedAt >= best.endedAt) {
32
+ best = { runId: row.runId || "", result: row.result.trim(), endedAt };
33
+ }
34
+ }
35
+ return best;
36
+ } catch {
37
+ return null;
38
+ }
39
+ }
40
+ export {
41
+ recoverFinishedCursorRun
42
+ };
@@ -11,10 +11,10 @@ import {
11
11
  orchestrationTitleNeedsSoccerNickname,
12
12
  orchestratorSessionPoisonedByBuiltins,
13
13
  takenTeamSlugsForOrchestration
14
- } from "./chunk-IS3AGU33.js";
15
- import "./chunk-PTASB7SJ.js";
16
- import "./chunk-XBEQI5H4.js";
17
- import "./chunk-HYRHI3QU.js";
14
+ } from "./chunk-6TZSJMXF.js";
15
+ import "./chunk-UPMGXM4X.js";
16
+ import "./chunk-VA2U5EQH.js";
17
+ import "./chunk-5UIKSPDD.js";
18
18
  import {
19
19
  globalAgentCwd
20
20
  } from "./chunk-M37RITA6.js";