@sideboard-ai/core 0.1.57 → 0.1.60

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 (39) hide show
  1. package/dist/{agents-2YYWW723.js → agents-B2723EOF.js} +4 -4
  2. package/dist/{agents-AQFEFKBL.js → agents-EADRAAPG.js} +4 -4
  3. package/dist/{app-settings-2LQNRTBE.js → app-settings-TBHTJWLQ.js} +1 -1
  4. package/dist/{app-settings-73DI4B6T.js → app-settings-YBNZ4XSR.js} +1 -1
  5. package/dist/{chunk-5DMYULLC.js → chunk-2P2UK7E7.js} +2 -2
  6. package/dist/{chunk-7LNGIP3X.js → chunk-73AT5K4A.js} +15 -3
  7. package/dist/{chunk-DIOF73S2.js → chunk-75QR74KM.js} +7 -2
  8. package/dist/{chunk-EBWEKG52.js → chunk-CHGOMFTA.js} +3 -3
  9. package/dist/{chunk-C4BCC5X5.js → chunk-FGNBTFRD.js} +7 -2
  10. package/dist/{chunk-H6GGDLYS.js → chunk-JB2H7E7V.js} +1 -1
  11. package/dist/{chunk-BXJ76RHF.js → chunk-MBAL5FE6.js} +4 -4
  12. package/dist/{chunk-XOU6HNQJ.js → chunk-MFGGIRUA.js} +39 -13
  13. package/dist/{chunk-S42XDFKF.js → chunk-MLAST5BB.js} +3 -3
  14. package/dist/{chunk-C3J4GDW4.js → chunk-MX7UH5AT.js} +76 -60
  15. package/dist/{chunk-DQJ5D42H.js → chunk-NTYRBRE7.js} +44 -13
  16. package/dist/{chunk-DZFH2KLT.js → chunk-P7EQUFB6.js} +39 -13
  17. package/dist/{chunk-V2DUTUNC.js → chunk-QJBC4BRK.js} +2 -2
  18. package/dist/{chunk-ZNM4MAN4.js → chunk-RIWUU7FO.js} +15 -3
  19. package/dist/{chunk-UA5NDAHL.js → chunk-XWPKLRB3.js} +44 -13
  20. package/dist/{chunk-7F454EE2.js → chunk-ZXDOI6IH.js} +76 -53
  21. package/dist/{connected-teams-ONC4666A.js → connected-teams-MKIYKOYA.js} +2 -2
  22. package/dist/{connected-teams-2ANNZCP5.js → connected-teams-RSL4VB3X.js} +2 -2
  23. package/dist/{coordinator-prompt-RBKUNRPR.js → coordinator-prompt-4P23VVFC.js} +4 -4
  24. package/dist/{coordinator-prompt-ICF36NUQ.js → coordinator-prompt-LNWHZ64D.js} +4 -4
  25. package/dist/{global-workspace-667XLBW6.js → global-workspace-BHT4XUAA.js} +5 -5
  26. package/dist/{global-workspace-S7VLWPWG.js → global-workspace-TMMAVRVW.js} +5 -5
  27. package/dist/index.cjs +303 -115
  28. package/dist/index.d.cts +15 -6
  29. package/dist/index.d.ts +15 -6
  30. package/dist/index.js +157 -64
  31. package/dist/mcp/run-stdio.cjs +303 -126
  32. package/dist/mcp/run-stdio.js +156 -68
  33. package/dist/{run-ZJKYHXGN.js → run-GPSVV5OH.js} +1 -1
  34. package/dist/{run-H3IMNOYN.js → run-HZTBWGQR.js} +1 -1
  35. package/dist/{workspaces-FPJJXXAE.js → workspaces-3GO3EDQG.js} +6 -6
  36. package/dist/{workspaces-LYIDE2VR.js → workspaces-GFPGDGCS.js} +6 -6
  37. package/dist/{worktree-5KEQWSAF.js → worktree-3L2G6PCM.js} +2 -2
  38. package/dist/{worktree-RWGL7FUV.js → worktree-GBLHEFHR.js} +2 -2
  39. package/package.json +1 -1
package/dist/index.d.cts CHANGED
@@ -855,6 +855,8 @@ declare function run(file: string, args: string[], opts?: {
855
855
  cwd?: string;
856
856
  reject?: boolean;
857
857
  env?: Record<string, string>;
858
+ /** Kill the child after this many ms (execa `timeout`). */
859
+ timeoutMs?: number;
858
860
  }): Promise<{
859
861
  stdout: string;
860
862
  stderr: string;
@@ -865,6 +867,8 @@ declare function git(args: string[], cwd: string, opts?: {
865
867
  env?: Record<string, string>;
866
868
  /** Passed as `git -c key=value` (e.g. authenticated HTTPS via http.extraHeader). */
867
869
  config?: Record<string, string>;
870
+ /** Kill after this many ms — critical for MCP so a stuck fetch cannot pin the stdio server. */
871
+ timeoutMs?: number;
868
872
  }): Promise<{
869
873
  stdout: string;
870
874
  stderr: string;
@@ -872,6 +876,7 @@ declare function git(args: string[], cwd: string, opts?: {
872
876
  }>;
873
877
  declare function gh(args: string[], cwd: string, opts?: {
874
878
  reject?: boolean;
879
+ timeoutMs?: number;
875
880
  }): Promise<{
876
881
  stdout: string;
877
882
  stderr: string;
@@ -1274,10 +1279,10 @@ interface AgentAdapter {
1274
1279
  }>>;
1275
1280
  }
1276
1281
  declare const 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.";
1277
- declare function permissionMode(thread: Pick<Thread, 'autonomy' | 'planMode'>): {
1282
+ declare function permissionMode(thread: Pick<Thread, 'autonomy' | 'planMode' | 'sourceType'>): {
1278
1283
  claude: string;
1279
1284
  opencodePermission: string;
1280
- codexSandbox: 'read-only' | 'workspace-write';
1285
+ codexSandbox: 'read-only' | 'workspace-write' | 'danger-full-access';
1281
1286
  };
1282
1287
 
1283
1288
  /**
@@ -1606,7 +1611,7 @@ declare function formatAgentInstructions(files: AgentInstructionFile[]): string
1606
1611
  declare function withAgentInstructions(prompt: string, files: AgentInstructionFile[]): string;
1607
1612
 
1608
1613
  declare function detectAgents(): Promise<AgentStatus[]>;
1609
- declare function requireAgent(agent: AgentStatus['agent'], opts?: {
1614
+ declare function requireAgent(agent: AgentKind, opts?: {
1610
1615
  requireLinear?: boolean;
1611
1616
  }): Promise<AgentStatus>;
1612
1617
 
@@ -2505,7 +2510,7 @@ declare const REVIEW_REQUEST_PATH = ".context/attachments/Review request.md";
2505
2510
  declare const LEGACY_REVIEW_REQUEST_PATH = ".sideboard/attachments/Review request.md";
2506
2511
  declare const REVIEW_REQUEST_NAME = "Review request.md";
2507
2512
  /** Short chat message — guidelines live in the attached review file. */
2508
- declare const REVIEW_REQUEST_PREFILL = "Review.";
2513
+ declare const REVIEW_REQUEST_PREFILL = "Review changes in this workspace.";
2509
2514
  type ReviewGuidelinesSource = 'repo' | 'local' | 'stock';
2510
2515
  interface ResolvedReviewGuidelines {
2511
2516
  path: string;
@@ -2550,7 +2555,7 @@ interface RequestReviewResult {
2550
2555
  }
2551
2556
  type SendFn = (threadRef: string, prompt: string) => Promise<Thread>;
2552
2557
  /**
2553
- * Open a fresh "Review" chat tab, attach resolved guidelines, send "Review."
2558
+ * Open a fresh "Review" chat tab, attach resolved guidelines, send the review prefill.
2554
2559
  */
2555
2560
  declare function requestReview(threadRef: string, send: SendFn): Promise<RequestReviewResult>;
2556
2561
 
@@ -2675,8 +2680,12 @@ declare function coordinatorTurnReminder(opts: {
2675
2680
  /**
2676
2681
  * Write durable CLAUDE.md / AGENTS.md into the global synthetic cwd so Claude
2677
2682
  * (and other agents that load AGENTS.md) keep orchestrator identity on resume.
2683
+ * When `orchestratorThreadId` is set, embed that uuid so Codex/Claude resume
2684
+ * cannot invent a stale parentThreadId.
2678
2685
  */
2679
- declare function ensureGlobalCoordinatorCwd(): string;
2686
+ declare function ensureGlobalCoordinatorCwd(opts?: {
2687
+ orchestratorThreadId?: string | null;
2688
+ }): string;
2680
2689
  declare function coordinatorSystemPrompt(opts: {
2681
2690
  goal: string;
2682
2691
  parentId: string;
package/dist/index.d.ts CHANGED
@@ -855,6 +855,8 @@ declare function run(file: string, args: string[], opts?: {
855
855
  cwd?: string;
856
856
  reject?: boolean;
857
857
  env?: Record<string, string>;
858
+ /** Kill the child after this many ms (execa `timeout`). */
859
+ timeoutMs?: number;
858
860
  }): Promise<{
859
861
  stdout: string;
860
862
  stderr: string;
@@ -865,6 +867,8 @@ declare function git(args: string[], cwd: string, opts?: {
865
867
  env?: Record<string, string>;
866
868
  /** Passed as `git -c key=value` (e.g. authenticated HTTPS via http.extraHeader). */
867
869
  config?: Record<string, string>;
870
+ /** Kill after this many ms — critical for MCP so a stuck fetch cannot pin the stdio server. */
871
+ timeoutMs?: number;
868
872
  }): Promise<{
869
873
  stdout: string;
870
874
  stderr: string;
@@ -872,6 +876,7 @@ declare function git(args: string[], cwd: string, opts?: {
872
876
  }>;
873
877
  declare function gh(args: string[], cwd: string, opts?: {
874
878
  reject?: boolean;
879
+ timeoutMs?: number;
875
880
  }): Promise<{
876
881
  stdout: string;
877
882
  stderr: string;
@@ -1274,10 +1279,10 @@ interface AgentAdapter {
1274
1279
  }>>;
1275
1280
  }
1276
1281
  declare const 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.";
1277
- declare function permissionMode(thread: Pick<Thread, 'autonomy' | 'planMode'>): {
1282
+ declare function permissionMode(thread: Pick<Thread, 'autonomy' | 'planMode' | 'sourceType'>): {
1278
1283
  claude: string;
1279
1284
  opencodePermission: string;
1280
- codexSandbox: 'read-only' | 'workspace-write';
1285
+ codexSandbox: 'read-only' | 'workspace-write' | 'danger-full-access';
1281
1286
  };
1282
1287
 
1283
1288
  /**
@@ -1606,7 +1611,7 @@ declare function formatAgentInstructions(files: AgentInstructionFile[]): string
1606
1611
  declare function withAgentInstructions(prompt: string, files: AgentInstructionFile[]): string;
1607
1612
 
1608
1613
  declare function detectAgents(): Promise<AgentStatus[]>;
1609
- declare function requireAgent(agent: AgentStatus['agent'], opts?: {
1614
+ declare function requireAgent(agent: AgentKind, opts?: {
1610
1615
  requireLinear?: boolean;
1611
1616
  }): Promise<AgentStatus>;
1612
1617
 
@@ -2505,7 +2510,7 @@ declare const REVIEW_REQUEST_PATH = ".context/attachments/Review request.md";
2505
2510
  declare const LEGACY_REVIEW_REQUEST_PATH = ".sideboard/attachments/Review request.md";
2506
2511
  declare const REVIEW_REQUEST_NAME = "Review request.md";
2507
2512
  /** Short chat message — guidelines live in the attached review file. */
2508
- declare const REVIEW_REQUEST_PREFILL = "Review.";
2513
+ declare const REVIEW_REQUEST_PREFILL = "Review changes in this workspace.";
2509
2514
  type ReviewGuidelinesSource = 'repo' | 'local' | 'stock';
2510
2515
  interface ResolvedReviewGuidelines {
2511
2516
  path: string;
@@ -2550,7 +2555,7 @@ interface RequestReviewResult {
2550
2555
  }
2551
2556
  type SendFn = (threadRef: string, prompt: string) => Promise<Thread>;
2552
2557
  /**
2553
- * Open a fresh "Review" chat tab, attach resolved guidelines, send "Review."
2558
+ * Open a fresh "Review" chat tab, attach resolved guidelines, send the review prefill.
2554
2559
  */
2555
2560
  declare function requestReview(threadRef: string, send: SendFn): Promise<RequestReviewResult>;
2556
2561
 
@@ -2675,8 +2680,12 @@ declare function coordinatorTurnReminder(opts: {
2675
2680
  /**
2676
2681
  * Write durable CLAUDE.md / AGENTS.md into the global synthetic cwd so Claude
2677
2682
  * (and other agents that load AGENTS.md) keep orchestrator identity on resume.
2683
+ * When `orchestratorThreadId` is set, embed that uuid so Codex/Claude resume
2684
+ * cannot invent a stale parentThreadId.
2678
2685
  */
2679
- declare function ensureGlobalCoordinatorCwd(): string;
2686
+ declare function ensureGlobalCoordinatorCwd(opts?: {
2687
+ orchestratorThreadId?: string | null;
2688
+ }): string;
2680
2689
  declare function coordinatorSystemPrompt(opts: {
2681
2690
  goal: string;
2682
2691
  parentId: string;
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  listWorkspaces,
5
5
  removeWorkspace,
6
6
  syncWorkspacesFromThreads
7
- } from "./chunk-5DMYULLC.js";
7
+ } from "./chunk-2P2UK7E7.js";
8
8
  import {
9
9
  CLOUD_COORDINATOR_BUSY_REPLY,
10
10
  CLOUD_COORDINATOR_STOPPED_REPLY,
@@ -24,7 +24,7 @@ import {
24
24
  orchestratorSessionPoisonedByBuiltins,
25
25
  parseForceStopMessage,
26
26
  takenTeamSlugsForOrchestration
27
- } from "./chunk-S42XDFKF.js";
27
+ } from "./chunk-MLAST5BB.js";
28
28
  import {
29
29
  BRIGHTSY_MCP_ALLOWED_TOOLS,
30
30
  CLAUDE_MODEL_CATALOG,
@@ -70,7 +70,7 @@ import {
70
70
  resolveQuotaFallbackAgent,
71
71
  sanitizeMcpServerName,
72
72
  writeInjectedMcpConfig
73
- } from "./chunk-7F454EE2.js";
73
+ } from "./chunk-ZXDOI6IH.js";
74
74
  import {
75
75
  ORCHESTRATOR_AGENT_KINDS,
76
76
  assertOrchestratorCapableAgent,
@@ -88,7 +88,7 @@ import {
88
88
  loadBrightsyConfig,
89
89
  saveBrightsyConfig,
90
90
  switchBrightsyAccount
91
- } from "./chunk-BXJ76RHF.js";
91
+ } from "./chunk-MBAL5FE6.js";
92
92
  import {
93
93
  LEGACY_PLAN_FILE_REL,
94
94
  PLAN_FILE_NAME,
@@ -118,7 +118,7 @@ import {
118
118
  enrichWorkspacesWithGithub,
119
119
  ensureGlobalCoordinatorCwd,
120
120
  formatWorkspaceInventory
121
- } from "./chunk-UA5NDAHL.js";
121
+ } from "./chunk-XWPKLRB3.js";
122
122
  import {
123
123
  HARNESS_ENV_KEYS,
124
124
  appSettingsPath,
@@ -157,7 +157,7 @@ import {
157
157
  updateClaudeSettings,
158
158
  updateDefaultsSettings,
159
159
  updateIntegrationsSettings
160
- } from "./chunk-DIOF73S2.js";
160
+ } from "./chunk-75QR74KM.js";
161
161
  import {
162
162
  FAMOUS_SOCCER_TEAMS,
163
163
  addPrStackLayer,
@@ -220,7 +220,7 @@ import {
220
220
  worktreeDisplayLabel,
221
221
  worktreeDisplayLabelForGroup,
222
222
  worktreeNameFromPath
223
- } from "./chunk-DZFH2KLT.js";
223
+ } from "./chunk-P7EQUFB6.js";
224
224
  import {
225
225
  ATTACHMENTS_DIR,
226
226
  LEGACY_ATTACHMENTS_DIR,
@@ -277,7 +277,7 @@ import {
277
277
  git,
278
278
  resolveGhAuthToken,
279
279
  run
280
- } from "./chunk-7LNGIP3X.js";
280
+ } from "./chunk-73AT5K4A.js";
281
281
 
282
282
  // src/integrations/github.ts
283
283
  async function getGitHubStatus() {
@@ -706,10 +706,12 @@ async function spawnAgentTurn(thread, input, onEvent) {
706
706
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
707
707
  );
708
708
  }
709
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-S7VLWPWG.js");
709
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-TMMAVRVW.js");
710
710
  if (isGlobalThread2(thread)) {
711
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-ICF36NUQ.js");
712
- ensureGlobalCoordinatorCwd2();
711
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-LNWHZ64D.js");
712
+ ensureGlobalCoordinatorCwd2(
713
+ isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
714
+ );
713
715
  }
714
716
  if (isOrchestratorThread(thread)) {
715
717
  assertOrchestratorCapableAgent(thread.agent);
@@ -995,9 +997,21 @@ async function detectAgents() {
995
997
  ensureAgentPath();
996
998
  return Promise.all(allAdapters().map((a) => a.detect()));
997
999
  }
1000
+ var REQUIRE_AGENT_TIMEOUT_MS = 8e3;
998
1001
  async function requireAgent(agent, opts) {
999
- const status = (await detectAgents()).find((s) => s.agent === agent);
1000
- if (!status) throw new Error(`Unknown agent: ${agent}`);
1002
+ ensureAgentPath();
1003
+ const status = await Promise.race([
1004
+ getAdapter(agent).detect(),
1005
+ new Promise((_, reject) => {
1006
+ setTimeout(() => {
1007
+ reject(
1008
+ new Error(
1009
+ `${agent} detect timed out after ${REQUIRE_AGENT_TIMEOUT_MS / 1e3}s`
1010
+ )
1011
+ );
1012
+ }, REQUIRE_AGENT_TIMEOUT_MS);
1013
+ })
1014
+ ]);
1001
1015
  if (!status.installed || !status.authenticated) {
1002
1016
  throw new Error(status.reason ?? `${agent} is not available`);
1003
1017
  }
@@ -2827,7 +2841,7 @@ async function previewLand(thread) {
2827
2841
  const target = await resolveDefaultBranch(thread.repoPath);
2828
2842
  if (thread.branchName === target || thread.branchName === "main" || thread.branchName === "master") {
2829
2843
  }
2830
- const { stdout: head } = await import("./run-ZJKYHXGN.js").then(
2844
+ const { stdout: head } = await import("./run-GPSVV5OH.js").then(
2831
2845
  ({ git: git2 }) => git2(["rev-parse", "--abbrev-ref", "HEAD"], thread.worktreePath)
2832
2846
  );
2833
2847
  const current = head.trim();
@@ -2866,7 +2880,7 @@ async function confirmLand(thread, opts) {
2866
2880
  if (preview.dirty) {
2867
2881
  committed = await commitAll(thread.worktreePath, meta.commitMessage);
2868
2882
  }
2869
- const { git: git2 } = await import("./run-ZJKYHXGN.js");
2883
+ const { git: git2 } = await import("./run-GPSVV5OH.js");
2870
2884
  const { stdout: headOut } = await git2(
2871
2885
  ["rev-parse", "--abbrev-ref", "HEAD"],
2872
2886
  thread.worktreePath,
@@ -2964,7 +2978,7 @@ async function createThread(input, _onSetupLine) {
2964
2978
  return readThread(thread.id) ?? thread;
2965
2979
  }
2966
2980
  async function listLinearIssues(agent, repoPath) {
2967
- const { getAdapter: getAdapter2 } = await import("./agents-2YYWW723.js");
2981
+ const { getAdapter: getAdapter2 } = await import("./agents-B2723EOF.js");
2968
2982
  await requireAgent(agent, { requireLinear: true });
2969
2983
  const adapter = getAdapter2(agent);
2970
2984
  if (!adapter.listLinearIssues) {
@@ -3490,7 +3504,7 @@ async function adoptThread(input) {
3490
3504
  throw new Error(`Worktree not found: ${input.worktreePath}`);
3491
3505
  }
3492
3506
  const repoPath = await resolveRepoRoot(input.worktreePath);
3493
- const { stdout: branch } = await import("./run-ZJKYHXGN.js").then(
3507
+ const { stdout: branch } = await import("./run-GPSVV5OH.js").then(
3494
3508
  ({ git: git2 }) => git2(["rev-parse", "--abbrev-ref", "HEAD"], input.worktreePath)
3495
3509
  );
3496
3510
  const thread = createEmptyThread({
@@ -3505,7 +3519,7 @@ async function adoptThread(input) {
3505
3519
  messages: input.messages ?? []
3506
3520
  });
3507
3521
  writeThread(thread);
3508
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-FPJJXXAE.js");
3522
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-3GO3EDQG.js");
3509
3523
  await ensureWorkspace2(repoPath);
3510
3524
  return thread;
3511
3525
  }
@@ -4066,7 +4080,7 @@ var REPO_REVIEW_NAME = "review.md";
4066
4080
  var REVIEW_REQUEST_PATH = `${ATTACHMENTS_DIR}/Review request.md`;
4067
4081
  var LEGACY_REVIEW_REQUEST_PATH = `${LEGACY_ATTACHMENTS_DIR}/Review request.md`;
4068
4082
  var REVIEW_REQUEST_NAME = "Review request.md";
4069
- var REVIEW_REQUEST_PREFILL = "Review.";
4083
+ var REVIEW_REQUEST_PREFILL = "Review changes in this workspace.";
4070
4084
  var LEGACY_REVIEW_TEMPLATE_MARKERS = [
4071
4085
  "You are acting as a reviewer for a proposed code change made by another engineer.",
4072
4086
  "HOW MANY FINDINGS TO RETURN:"
@@ -4442,7 +4456,7 @@ var Orchestrator = class {
4442
4456
  orphans: orphans.map((o) => ({ path: o.path, repoPath: o.repoPath }))
4443
4457
  });
4444
4458
  }
4445
- const { autoCleanupOrphansEnabled: autoCleanupOrphansEnabled2 } = await import("./app-settings-2LQNRTBE.js");
4459
+ const { autoCleanupOrphansEnabled: autoCleanupOrphansEnabled2 } = await import("./app-settings-TBHTJWLQ.js");
4446
4460
  if (autoCleanupOrphansEnabled2() && shouldRunWorktreeCleanup() && orphans.length > 0) {
4447
4461
  await cleanupOrphanWorktrees({ repoPaths });
4448
4462
  }
@@ -4599,7 +4613,7 @@ var Orchestrator = class {
4599
4613
  }
4600
4614
  async finishCreateThread(threadId, prompt) {
4601
4615
  await this.runSetupAfterCreate(threadId);
4602
- const { autoRunAfterSetupEnabled: autoRunAfterSetupEnabled2 } = await import("./app-settings-2LQNRTBE.js");
4616
+ const { autoRunAfterSetupEnabled: autoRunAfterSetupEnabled2 } = await import("./app-settings-TBHTJWLQ.js");
4603
4617
  if (autoRunAfterSetupEnabled2()) {
4604
4618
  try {
4605
4619
  await this.startDev(threadId);
@@ -4870,7 +4884,7 @@ var Orchestrator = class {
4870
4884
  });
4871
4885
  const artifactDirective = isBrightsy ? null : formatArtifactDirective();
4872
4886
  const settings = loadWorkspaceSettings(fresh.worktreePath, fresh.repoPath);
4873
- const { autoRenameBranchEnabled: autoRenameBranchEnabled2 } = await import("./app-settings-2LQNRTBE.js");
4887
+ const { autoRenameBranchEnabled: autoRenameBranchEnabled2 } = await import("./app-settings-TBHTJWLQ.js");
4874
4888
  const renameBranchDirective = !isBrightsy && !isOrchestration && autoRenameBranchEnabled2() ? formatRenameBranchDirective(fresh, {
4875
4889
  customPrompt: settings?.prompts?.renameBranch
4876
4890
  }) : null;
@@ -4882,7 +4896,9 @@ var Orchestrator = class {
4882
4896
  }
4883
4897
  let coordinatorDirective = null;
4884
4898
  if (isOrchestration) {
4885
- if (isGlobalThread(fresh)) ensureGlobalCoordinatorCwd();
4899
+ if (isGlobalThread(fresh)) {
4900
+ ensureGlobalCoordinatorCwd({ orchestratorThreadId: fresh.id });
4901
+ }
4886
4902
  if (!fresh.sessionId) {
4887
4903
  const inventory = await enrichWorkspacesWithGithub(this.listWorkspaces());
4888
4904
  coordinatorDirective = coordinatorSystemPrompt({
@@ -5739,7 +5755,7 @@ var Orchestrator = class {
5739
5755
  const archived = setStatus(thread.id, "archived");
5740
5756
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
5741
5757
  try {
5742
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-FPJJXXAE.js");
5758
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-3GO3EDQG.js");
5743
5759
  await ensureWorkspace2(thread.repoPath);
5744
5760
  } catch {
5745
5761
  }
@@ -5760,7 +5776,7 @@ var Orchestrator = class {
5760
5776
  await runArchiveScript(thread.repoPath, thread.worktreePath);
5761
5777
  } catch {
5762
5778
  }
5763
- const { deleteBranchOnPurgeEnabled: deleteBranchOnPurgeEnabled2 } = await import("./app-settings-2LQNRTBE.js");
5779
+ const { deleteBranchOnPurgeEnabled: deleteBranchOnPurgeEnabled2 } = await import("./app-settings-TBHTJWLQ.js");
5764
5780
  const deleteBranch = opts?.deleteBranch ?? deleteBranchOnPurgeEnabled2();
5765
5781
  await removeWorktree(thread.repoPath, thread.worktreePath, {
5766
5782
  deleteBranch: deleteBranch ? thread.branchName : void 0
@@ -5779,7 +5795,7 @@ var Orchestrator = class {
5779
5795
  return setStatus(thread.id, "idle");
5780
5796
  }
5781
5797
  if (!existsSync13(thread.worktreePath)) {
5782
- const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-RWGL7FUV.js");
5798
+ const { createThreadWorktree: createThreadWorktree2 } = await import("./worktree-GBLHEFHR.js");
5783
5799
  const { execa: execa6 } = await import("execa");
5784
5800
  const slug = thread.worktreePath.split("/").pop();
5785
5801
  const dest = thread.worktreePath;
@@ -5864,7 +5880,7 @@ async function startOrchestration(opts) {
5864
5880
  sourceRef: "default",
5865
5881
  ...createOpts
5866
5882
  }).catch(async () => {
5867
- const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-RWGL7FUV.js");
5883
+ const { resolveDefaultBranch: resolveDefaultBranch2, resolveRepoRoot: resolveRepoRoot2 } = await import("./worktree-GBLHEFHR.js");
5868
5884
  const repo = await resolveRepoRoot2(repoPath);
5869
5885
  const def = await resolveDefaultBranch2(repo);
5870
5886
  return createThread({
@@ -5999,14 +6015,39 @@ function mcpArchiveBlockedReason(thread) {
5999
6015
 
6000
6016
  // src/mcp/server.ts
6001
6017
  var MAX_ORCH_THREADS = 5;
6018
+ var CREATE_THREAD_TIMEOUT_MS = 9e4;
6019
+ function withTimeout(promise, ms, label) {
6020
+ return new Promise((resolve, reject) => {
6021
+ const timer = setTimeout(() => {
6022
+ reject(new Error(`${label} timed out after ${Math.round(ms / 1e3)}s`));
6023
+ }, ms);
6024
+ promise.then(
6025
+ (value) => {
6026
+ clearTimeout(timer);
6027
+ resolve(value);
6028
+ },
6029
+ (err) => {
6030
+ clearTimeout(timer);
6031
+ reject(err);
6032
+ }
6033
+ );
6034
+ });
6035
+ }
6002
6036
  async function startMcpServer() {
6003
6037
  const orch = getOrchestrator();
6004
6038
  try {
6005
- const { maxConcurrentAgents: maxConcurrentAgents2 } = await import("./app-settings-2LQNRTBE.js");
6039
+ const { maxConcurrentAgents: maxConcurrentAgents2 } = await import("./app-settings-TBHTJWLQ.js");
6006
6040
  orch.setMaxConcurrent(maxConcurrentAgents2());
6007
6041
  } catch {
6008
6042
  }
6009
- await orch.reconcile(void 0, { reclaimStaleTurns: false, drainQueues: false });
6043
+ try {
6044
+ await orch.reconcile(void 0, { reclaimStaleTurns: false, drainQueues: false });
6045
+ } catch (err) {
6046
+ console.error(
6047
+ "[sideboard-mcp] reconcile on boot failed (continuing):",
6048
+ err instanceof Error ? err.message : err
6049
+ );
6050
+ }
6010
6051
  const server = new McpServer({
6011
6052
  name: "sideboard",
6012
6053
  version: "0.1.0"
@@ -6206,12 +6247,12 @@ async function startMcpServer() {
6206
6247
  return { content: [{ type: "text", text: JSON.stringify(payload) }] };
6207
6248
  }
6208
6249
  );
6209
- const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await import("./app-settings-2LQNRTBE.js");
6250
+ const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await import("./app-settings-TBHTJWLQ.js");
6210
6251
  const accountDefaults = resolveThreadDefaults2();
6211
6252
  const accountDefaultsHint = `Account defaults: agent=${accountDefaults.agent}, model=${accountDefaults.model?.trim() || "Auto"}, effort=${accountDefaults.effort}`;
6212
6253
  server.tool(
6213
6254
  "create_thread",
6214
- `Create a new worktree thread (chat) from branch, pr, or ticket. Pass repoPath from list_workspaces and parentThreadId when spawning from an orchestrator. Prefer omitting agent/model so Sideboard applies ${accountDefaultsHint}. Then use send_to_thread to chat.`,
6255
+ `Create a new worktree thread (chat) from branch, pr, or ticket. Pass repoPath from list_workspaces. From an orchestration chat, omit parentThreadId (Sideboard binds the child to this chat) or pass the exact id from the turn reminder \u2014 never invent a uuid. Prefer omitting agent/model so Sideboard applies ${accountDefaultsHint}. Then use send_to_thread to chat.`,
6215
6256
  {
6216
6257
  sourceType: z.enum(["branch", "pr", "ticket"]),
6217
6258
  sourceRef: z.string(),
@@ -6221,11 +6262,31 @@ async function startMcpServer() {
6221
6262
  ),
6222
6263
  repoPath: z.string(),
6223
6264
  title: z.string().optional(),
6224
- parentThreadId: z.string().optional()
6265
+ parentThreadId: z.string().optional().describe(
6266
+ "Orchestration: omit (preferred) or pass YOUR chat id from the turn reminder / AGENTS.md. Do not invent uuids."
6267
+ )
6225
6268
  },
6226
6269
  async (args) => {
6227
- if (args.parentThreadId) {
6228
- const children = orch.getThreads(true).filter((t) => t.parentThreadId === args.parentThreadId);
6270
+ const envParentId = process.env.SIDEBOARD_ORCHESTRATOR_THREAD_ID?.trim() || "";
6271
+ let parentId = args.parentThreadId?.trim() || "";
6272
+ let parent = parentId ? orch.getThread(parentId) : null;
6273
+ let parentCorrectedFrom;
6274
+ if (envParentId) {
6275
+ const envParent = orch.getThread(envParentId);
6276
+ if (envParent) {
6277
+ if (parentId && parentId !== envParentId) parentCorrectedFrom = parentId;
6278
+ else if (!parentId) parentCorrectedFrom = void 0;
6279
+ parentId = envParentId;
6280
+ parent = envParent;
6281
+ }
6282
+ }
6283
+ if (parentId && !parent) {
6284
+ parentCorrectedFrom = parentId;
6285
+ parentId = "";
6286
+ parent = null;
6287
+ }
6288
+ if (parentId) {
6289
+ const children = orch.getThreads(true).filter((t) => t.parentThreadId === parentId);
6229
6290
  if (children.length >= MAX_ORCH_THREADS) {
6230
6291
  return {
6231
6292
  content: [
@@ -6238,38 +6299,70 @@ async function startMcpServer() {
6238
6299
  };
6239
6300
  }
6240
6301
  }
6302
+ let agentArg = args.agent;
6303
+ let agentCoercedFrom;
6304
+ const resolvedProbe = resolveNewThreadOptions2({ agent: agentArg }).agent;
6305
+ if (resolvedProbe === "codex") {
6306
+ agentCoercedFrom = agentArg ?? "codex";
6307
+ const accountAgent = resolveNewThreadOptions2({}).agent;
6308
+ agentArg = accountAgent !== "codex" ? accountAgent : "cursor";
6309
+ }
6241
6310
  const opts = resolveNewThreadOptions2({
6242
- agent: args.agent,
6311
+ agent: agentArg,
6243
6312
  model: args.model
6244
6313
  });
6245
- const thread = await orch.createThread({
6246
- sourceType: args.sourceType,
6247
- sourceRef: args.sourceRef,
6248
- agent: opts.agent,
6249
- model: opts.model,
6250
- effort: opts.effort,
6251
- fast: opts.fast,
6252
- repoPath: args.repoPath,
6253
- title: args.title,
6254
- parentThreadId: args.parentThreadId ?? null
6255
- });
6256
- return {
6257
- content: [
6258
- {
6259
- type: "text",
6260
- text: JSON.stringify({
6261
- id: thread.id,
6262
- title: thread.title,
6263
- branchName: thread.branchName,
6264
- worktreePath: thread.worktreePath,
6265
- agent: thread.agent,
6266
- model: thread.model,
6267
- status: thread.status,
6268
- link: `sideboard://thread/${thread.id}`
6269
- })
6270
- }
6271
- ]
6272
- };
6314
+ try {
6315
+ const thread = await withTimeout(
6316
+ orch.createThread({
6317
+ sourceType: args.sourceType,
6318
+ sourceRef: args.sourceRef,
6319
+ agent: opts.agent,
6320
+ model: opts.model,
6321
+ effort: opts.effort,
6322
+ fast: opts.fast,
6323
+ repoPath: args.repoPath,
6324
+ title: args.title,
6325
+ parentThreadId: parentId || null
6326
+ }),
6327
+ CREATE_THREAD_TIMEOUT_MS,
6328
+ "create_thread"
6329
+ );
6330
+ const parentNote = parentCorrectedFrom ? parentId ? `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; nested under ${parentId}` : `Ignored unknown/stale parentThreadId ${parentCorrectedFrom}; created without parent` : void 0;
6331
+ return {
6332
+ content: [
6333
+ {
6334
+ type: "text",
6335
+ text: JSON.stringify({
6336
+ id: thread.id,
6337
+ title: thread.title,
6338
+ branchName: thread.branchName,
6339
+ worktreePath: thread.worktreePath,
6340
+ agent: thread.agent,
6341
+ model: thread.model,
6342
+ status: thread.status,
6343
+ link: `sideboard://thread/${thread.id}`,
6344
+ parentThreadId: thread.parentThreadId,
6345
+ ...agentCoercedFrom ? {
6346
+ agentCoercedFrom,
6347
+ note: `Avoid nested Codex under a Codex orchestrator \u2014 used Account default agent=${thread.agent}`
6348
+ } : {},
6349
+ ...parentCorrectedFrom ? { parentCorrectedFrom, parentNote } : {}
6350
+ })
6351
+ }
6352
+ ]
6353
+ };
6354
+ } catch (err) {
6355
+ const message = err instanceof Error ? err.message : String(err);
6356
+ return {
6357
+ content: [
6358
+ {
6359
+ type: "text",
6360
+ text: `create_thread failed: ${message}`
6361
+ }
6362
+ ],
6363
+ isError: true
6364
+ };
6365
+ }
6273
6366
  }
6274
6367
  );
6275
6368
  server.tool(
@@ -6450,7 +6543,7 @@ async function startMcpServer() {
6450
6543
  );
6451
6544
  server.tool(
6452
6545
  "request_review",
6453
- 'Start a merge-readiness Review on a worktree agent thread (same as the desktop Review button). Opens a new Review chat tab, attaches .sideboard/review.md when present (else local Review request.md / stock template), and sends "Review." Expect Approve / Approve with nits / Request changes / Needs more information. Pass a worktree thread ref \u2014 not the orchestrator. Then wait_for_turn / get_turn_result on the returned review tab id.',
6546
+ 'Start a merge-readiness Review on a worktree agent thread (same as the desktop Review button). Opens a new Review chat tab, attaches .sideboard/review.md when present (else local Review request.md / stock template), and sends "Review changes in this workspace." Expect Approve / Approve with nits / Request changes / Needs more information. Pass a worktree thread ref \u2014 not the orchestrator. Then wait_for_turn / get_turn_result on the returned review tab id.',
6454
6547
  { ref: z.string().describe("Worktree thread id/ref to review") },
6455
6548
  async ({ ref }) => {
6456
6549
  try {