@sideboard-ai/core 0.1.52 → 0.1.56

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 (30) hide show
  1. package/dist/agents/cursor-runner.cjs +126 -11
  2. package/dist/agents/cursor-runner.js +45 -6
  3. package/dist/{agents-YKSS6VBO.js → agents-2YYWW723.js} +3 -3
  4. package/dist/{agents-ON6RKKND.js → agents-AQFEFKBL.js} +2 -2
  5. package/dist/{app-settings-LZP632KI.js → app-settings-2LQNRTBE.js} +3 -1
  6. package/dist/{app-settings-7XVDQJ7F.js → app-settings-73DI4B6T.js} +3 -1
  7. package/dist/{chunk-J5JTEJ5O.js → chunk-3WJAUKIL.js} +89 -7
  8. package/dist/{chunk-GNML24AW.js → chunk-5DMYULLC.js} +1 -1
  9. package/dist/{chunk-D3METLRW.js → chunk-7F454EE2.js} +96 -14
  10. package/dist/{chunk-6QTZVJ7A.js → chunk-C3J4GDW4.js} +188 -24
  11. package/dist/{chunk-HBJSHRY2.js → chunk-C4BCC5X5.js} +17 -1
  12. package/dist/{chunk-T5QQVXK3.js → chunk-DIOF73S2.js} +17 -1
  13. package/dist/{chunk-UEAHMGHW.js → chunk-DQJ5D42H.js} +16 -2
  14. package/dist/{chunk-YOWIYAVA.js → chunk-EBWEKG52.js} +36 -11
  15. package/dist/{chunk-XX5BB7NV.js → chunk-S42XDFKF.js} +36 -11
  16. package/dist/{chunk-LRLKJM3O.js → chunk-UA5NDAHL.js} +16 -2
  17. package/dist/{chunk-YDXQ72MD.js → chunk-V2DUTUNC.js} +1 -1
  18. package/dist/{coordinator-prompt-S6JZD5EF.js → coordinator-prompt-ICF36NUQ.js} +2 -1
  19. package/dist/{coordinator-prompt-6FXVTSFN.js → coordinator-prompt-RBKUNRPR.js} +2 -1
  20. package/dist/{global-workspace-EV4G2WMQ.js → global-workspace-667XLBW6.js} +3 -2
  21. package/dist/{global-workspace-MSX2K27Y.js → global-workspace-S7VLWPWG.js} +3 -2
  22. package/dist/index.cjs +395 -61
  23. package/dist/index.d.cts +25 -2
  24. package/dist/index.d.ts +25 -2
  25. package/dist/index.js +164 -43
  26. package/dist/mcp/run-stdio.cjs +389 -57
  27. package/dist/mcp/run-stdio.js +164 -44
  28. package/dist/{workspaces-AYTBR6KQ.js → workspaces-FPJJXXAE.js} +4 -3
  29. package/dist/{workspaces-3RQQZQRO.js → workspaces-LYIDE2VR.js} +4 -3
  30. package/package.json +1 -1
package/dist/index.cjs CHANGED
@@ -416,6 +416,7 @@ __export(app_settings_exports, {
416
416
  orchestrationQuotaOnLimit: () => orchestrationQuotaOnLimit,
417
417
  resolveClaudeExecutable: () => resolveClaudeExecutable,
418
418
  resolveEffectiveIssueSource: () => resolveEffectiveIssueSource,
419
+ resolveNewThreadOptions: () => resolveNewThreadOptions,
419
420
  resolveThreadDefaults: () => resolveThreadDefaults,
420
421
  saveAppSettings: () => saveAppSettings,
421
422
  updateAdvancedSettings: () => updateAdvancedSettings,
@@ -708,6 +709,16 @@ function resolveThreadDefaults(settings = loadAppSettings()) {
708
709
  fast: getDefaultFast(settings)
709
710
  };
710
711
  }
712
+ function resolveNewThreadOptions(overrides = {}, settings = loadAppSettings()) {
713
+ const defaults = resolveThreadDefaults(settings);
714
+ const effort = overrides.effort === void 0 || overrides.effort === null ? defaults.effort : normalizeThinkingEffort(overrides.effort) ?? defaults.effort;
715
+ return {
716
+ agent: overrides.agent ?? defaults.agent,
717
+ model: overrides.model === void 0 ? defaults.model : overrides.model?.trim() || null,
718
+ effort,
719
+ fast: overrides.fast === void 0 || overrides.fast === null ? defaults.fast : Boolean(overrides.fast)
720
+ };
721
+ }
711
722
  function isLinearConnected(settings = loadAppSettings()) {
712
723
  return Boolean(settings.integrations.linearApiKey?.trim());
713
724
  }
@@ -727,7 +738,12 @@ function brightsyCloudConnectEnabled(settings = loadAppSettings()) {
727
738
  return Boolean(settings.brightsy.cloudConnectEnabled);
728
739
  }
729
740
  function brightsyCloudConnectAgent(settings = loadAppSettings()) {
730
- return settings.brightsy.cloudConnectAgent ?? "claude";
741
+ const fallback = settings.brightsy.cloudConnectAgent && CLOUD_CONNECT_AGENTS.has(settings.brightsy.cloudConnectAgent) ? settings.brightsy.cloudConnectAgent : "claude";
742
+ const preferred = getDefaultAgent(settings);
743
+ if (CLOUD_CONNECT_AGENTS.has(preferred)) {
744
+ return preferred;
745
+ }
746
+ return fallback;
731
747
  }
732
748
  function updateAdvancedSettings(patch) {
733
749
  const current = loadAppSettings();
@@ -3512,6 +3528,11 @@ function coordinatorGreenfieldPlaybook(reposDir) {
3512
3528
  "- Do coding work in the child worktree thread, not by editing files in this home cwd."
3513
3529
  ].join("\n");
3514
3530
  }
3531
+ function accountDefaultsPlaybookLine() {
3532
+ const d = resolveThreadDefaults();
3533
+ const model = d.model?.trim() || "Auto";
3534
+ return `- Account defaults for create_thread (omit agent/model to use these): agent=${d.agent}, model=${model}, effort=${d.effort}`;
3535
+ }
3515
3536
  function coordinatorTurnReminder(opts) {
3516
3537
  const goal = opts.goal?.trim();
3517
3538
  return [
@@ -3521,6 +3542,7 @@ function coordinatorTurnReminder(opts) {
3521
3542
  "- Registered workspaces / child threads are the fleet you manage via Sideboard MCP.",
3522
3543
  `- Parent thread id (pass as parentThreadId when creating children): ${opts.parentId}`,
3523
3544
  goal ? `- Goal / title: ${goal}` : null,
3545
+ accountDefaultsPlaybookLine(),
3524
3546
  `- For "what's going on": call list_threads (and list_workspaces if needed). Summarize fleet status \u2014 do not ls/git-status this synthetic home.`,
3525
3547
  "- Existing repo: create_thread on a repoPath \u2192 send_to_thread \u2192 wait_for_turn.",
3526
3548
  "- New repo: Bash (clone or gh repo create under ~/sideboard/repos/<name>) \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 draft PR.",
@@ -3543,9 +3565,12 @@ function ensureGlobalCoordinatorCwd() {
3543
3565
  "",
3544
3566
  COORDINATOR_TOOL_PLAYBOOK,
3545
3567
  "",
3568
+ accountDefaultsPlaybookLine(),
3569
+ "",
3546
3570
  coordinatorGreenfieldPlaybook(reposDir),
3547
3571
  "",
3548
3572
  "When creating threads, pass `repoPath` from `list_workspaces` (or the path you just registered) and `parentThreadId` for children.",
3573
+ "Omit `agent` / `model` on `create_thread` unless you have a reason to override Account defaults.",
3549
3574
  "Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn.",
3550
3575
  "Typical flow (new app): Bash create/clone under repos dir \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn \u2192 draft PR via worktree agent.",
3551
3576
  "Always ask worktree agents to open draft PRs (`send_to_thread` + `gh pr create --draft -R <origin>`); never open PRs from the orchestrator."
@@ -3571,8 +3596,10 @@ function coordinatorSystemPrompt(opts) {
3571
3596
  "You operate across ALL registered workspaces below.",
3572
3597
  "You have no project git home \u2014 this process cwd is synthetic and empty on purpose.",
3573
3598
  COORDINATOR_TOOL_PLAYBOOK,
3599
+ accountDefaultsPlaybookLine(),
3574
3600
  coordinatorGreenfieldPlaybook(reposDir),
3575
3601
  "When creating threads, pass the correct repoPath for the target workspace and parentThreadId for children.",
3602
+ "Omit agent/model on create_thread unless you need to override Account defaults.",
3576
3603
  "Typical flow (existing): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread (implement) \u2192 wait_for_turn \u2192 send_to_thread (ask for `gh pr create --draft -R <origin-owner/name>` using the workspace github slug) \u2192 wait_for_turn. Never target upstream. Never open PRs from the orchestrator.",
3577
3604
  "Typical flow (new app): Bash under repos dir (clone or gh repo create) \u2192 add_workspace \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn \u2192 draft PR via worktree agent.",
3578
3605
  `Goal: ${opts.goal}`,
@@ -3588,6 +3615,7 @@ var init_coordinator_prompt = __esm({
3588
3615
  import_node_fs6 = require("fs");
3589
3616
  import_node_path7 = require("path");
3590
3617
  init_worktree();
3618
+ init_app_settings();
3591
3619
  init_paths();
3592
3620
  COORDINATOR_TOOL_PLAYBOOK = [
3593
3621
  "Role: you oversee Sideboard worktree agents across registered repos. You do not live inside one of those worktrees.",
@@ -3596,12 +3624,12 @@ var init_coordinator_prompt = __esm({
3596
3624
  "- list_workspaces \u2014 registered repos (path + github slug when known)",
3597
3625
  "- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces (issues: Linear API or GitHub Issues)",
3598
3626
  "- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
3599
- "- list_models \u2014 only when you need a specific model (rare); otherwise leave model unset = Auto",
3627
+ "- list_models \u2014 only when you need a specific model (rare); otherwise omit model so Account defaults apply",
3600
3628
  "- list_threads / get_thread \u2014 fleet status (what is going on)",
3601
3629
  "Workspaces:",
3602
3630
  "- add_workspace / remove_workspace \u2014 register or unregister a git repo",
3603
3631
  "Worktree threads (chats):",
3604
- "- create_thread \u2014 create a worktree + chat from branch | pr | ticket; pass repoPath + parentThreadId",
3632
+ "- create_thread \u2014 create a worktree + chat from branch | pr | ticket; pass repoPath + parentThreadId; omit agent and model to use Sideboard Account defaults (Settings \u2192 Default agent, model & effort)",
3605
3633
  "- fork_worktree \u2014 fork a worktree chat into a NEW git worktree + chat (transcript attached); optional agent; leave model unset (Auto) unless you have a reason. Not for orchestration chats.",
3606
3634
  "- fork_chat \u2014 fork a worktree chat (same worktree tab) OR a Global orchestration chat (new orchestration tab); optional agent; leave model unset (Auto) unless you have a reason. Remote coordinators: use this to continue another orchestration chat on a different agent after session limits.",
3607
3635
  "- send_to_thread \u2014 queue a prompt (start/continue a chat turn); pass force_stop: true to interrupt mid-turn / clear stale queued prompts before replacing with a new request",
@@ -3701,7 +3729,13 @@ function createGlobalChat(opts) {
3701
3729
  const explicit = opts.title?.trim();
3702
3730
  const title = explicit && explicit !== CLOUD_ORCHESTRATOR_GOAL ? explicit : allocateTeamName(takenTeamSlugsForOrchestration()).name;
3703
3731
  const sourceRef = opts.sourceRef?.trim() || (isCloud ? CLOUD_ORCHESTRATOR_GOAL : title);
3704
- const agent = assertOrchestratorCapableAgent(opts.agent);
3732
+ const resolved = resolveNewThreadOptions({
3733
+ agent: opts.agent,
3734
+ model: opts.model,
3735
+ effort: opts.effort,
3736
+ fast: opts.fast
3737
+ });
3738
+ const agent = assertOrchestratorCapableAgent(resolved.agent);
3705
3739
  const thread = createEmptyThread({
3706
3740
  title,
3707
3741
  // Stick nicknames the same way chat tabs do (avoid later sync overwrites).
@@ -3713,9 +3747,9 @@ function createGlobalChat(opts) {
3713
3747
  repoPath: GLOBAL_WORKSPACE_ID,
3714
3748
  agent,
3715
3749
  autonomy: opts.autonomy ?? "default",
3716
- model: opts.model ?? null,
3717
- effort: opts.effort ?? "high",
3718
- fast: Boolean(opts.fast),
3750
+ model: resolved.model,
3751
+ effort: resolved.effort,
3752
+ fast: resolved.fast,
3719
3753
  planMode: Boolean(opts.planMode),
3720
3754
  attachments: opts.attachments ?? [],
3721
3755
  parentThreadId: opts.parentThreadId ?? null,
@@ -3748,20 +3782,35 @@ function findCloudCoordinator() {
3748
3782
  );
3749
3783
  }
3750
3784
  function ensureCloudCoordinator(agent) {
3785
+ const defaults = resolveThreadDefaults();
3786
+ const desired = assertOrchestratorCapableAgent(agent);
3751
3787
  const existing = findCloudCoordinator();
3752
3788
  if (existing) {
3789
+ const patch = {};
3753
3790
  if (existing.repoPath !== GLOBAL_WORKSPACE_ID) {
3754
- return updateThread(existing.id, {
3755
- repoPath: GLOBAL_WORKSPACE_ID,
3756
- worktreePath: globalAgentCwd(),
3757
- branchName: "global"
3758
- });
3791
+ patch.repoPath = GLOBAL_WORKSPACE_ID;
3792
+ patch.worktreePath = globalAgentCwd();
3793
+ patch.branchName = "global";
3794
+ }
3795
+ const hasAgentTurns = existing.messages.some((m) => m.role === "agent");
3796
+ const canRetarget = !existing.sessionId && !hasAgentTurns && existing.status !== "running" && existing.status !== "queued";
3797
+ if (canRetarget) {
3798
+ if (existing.agent !== desired) patch.agent = desired;
3799
+ if (existing.model !== defaults.model) patch.model = defaults.model;
3800
+ if (existing.effort !== defaults.effort) patch.effort = defaults.effort;
3801
+ if (existing.fast !== defaults.fast) patch.fast = defaults.fast;
3802
+ }
3803
+ if (Object.keys(patch).length > 0) {
3804
+ return updateThread(existing.id, patch);
3759
3805
  }
3760
3806
  return existing;
3761
3807
  }
3762
3808
  const created = createGlobalChat({
3763
3809
  sourceRef: CLOUD_ORCHESTRATOR_GOAL,
3764
- agent
3810
+ agent: desired,
3811
+ model: defaults.model,
3812
+ effort: defaults.effort,
3813
+ fast: defaults.fast
3765
3814
  });
3766
3815
  const all = listThreads({ includeArchived: true }).filter(
3767
3816
  (t) => t.status !== "archived" && isCloudCoordinatorThread(t)
@@ -3776,6 +3825,7 @@ var init_global_workspace = __esm({
3776
3825
  init_orchestrator_capable();
3777
3826
  init_teams();
3778
3827
  init_coordinator_prompt();
3828
+ init_app_settings();
3779
3829
  init_paths();
3780
3830
  init_thread_store();
3781
3831
  GLOBAL_WORKSPACE_ID = "__global__";
@@ -4316,6 +4366,11 @@ function summarizeTurnStderr(tail, maxChars = 500) {
4316
4366
  if (joined.length <= maxChars) return joined;
4317
4367
  return joined.slice(joined.length - maxChars);
4318
4368
  }
4369
+ function looksLikeInvalidAgentSession(text) {
4370
+ const lower = text.trim().toLowerCase();
4371
+ if (!lower) return false;
4372
+ 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);
4373
+ }
4319
4374
  function looksLikeAgentFailureMessage(text) {
4320
4375
  const lower = text.trim().toLowerCase();
4321
4376
  if (!lower) return false;
@@ -4953,6 +5008,7 @@ function toCodexMcpConfigArgs(servers) {
4953
5008
  args.push("-c", `${prefix}.env.${key}=${JSON.stringify(value)}`);
4954
5009
  }
4955
5010
  }
5011
+ args.push("-c", `${prefix}.default_tools_approval_mode=${JSON.stringify("approve")}`);
4956
5012
  }
4957
5013
  return args;
4958
5014
  }
@@ -5468,6 +5524,32 @@ function codexConfigHasNetworkAccess() {
5468
5524
  }
5469
5525
  return false;
5470
5526
  }
5527
+ function unwrapCodexMcpResult(result) {
5528
+ if (result == null) return void 0;
5529
+ if (typeof result === "string") return result;
5530
+ if (typeof result !== "object") return String(result);
5531
+ const rec = result;
5532
+ if (Array.isArray(rec.content)) {
5533
+ const texts = [];
5534
+ for (const item of rec.content) {
5535
+ if (!item || typeof item !== "object") continue;
5536
+ const text = item.text;
5537
+ if (typeof text === "string") texts.push(text);
5538
+ }
5539
+ if (texts.length) return texts.join("\n");
5540
+ }
5541
+ try {
5542
+ return JSON.stringify(result);
5543
+ } catch {
5544
+ return String(result);
5545
+ }
5546
+ }
5547
+ function asRecord(value) {
5548
+ if (value && typeof value === "object" && !Array.isArray(value)) {
5549
+ return value;
5550
+ }
5551
+ return void 0;
5552
+ }
5471
5553
  var import_node_fs12, import_node_os7, import_node_path12, CODEX_PROMPT_ARG_MAX, FALLBACK_CODEX_MODELS, cachedCodexModels, CODEX_MODEL_CACHE_MS, codexAdapter;
5472
5554
  var init_codex = __esm({
5473
5555
  "src/agents/codex.ts"() {
@@ -5580,15 +5662,49 @@ var init_codex = __esm({
5580
5662
  }
5581
5663
  if (typeof obj.item === "object" && obj.item !== null) {
5582
5664
  const item = obj.item;
5583
- if (item.type === "error") {
5665
+ const itemType = item.type ?? item.item_type;
5666
+ if (itemType === "error") {
5584
5667
  const detail = item.message?.trim() || extractJsonErrorMessage(obj) || "Codex item error";
5585
5668
  return { type: "stderr", data: detail };
5586
5669
  }
5587
- if (item.type === "agent_message" && item.text) {
5670
+ if (itemType === "agent_message" && item.text) {
5588
5671
  return { type: "stdout", data: item.text };
5589
5672
  }
5673
+ if (itemType === "mcp_tool_call" && item.id && item.server && item.tool) {
5674
+ const name = `mcp__${item.server}__${item.tool}`;
5675
+ const input = asRecord(item.arguments);
5676
+ const events = [
5677
+ { type: "tool_use", id: item.id, name, input }
5678
+ ];
5679
+ const finished = type === "item.completed" || item.status === "completed" || item.status === "failed";
5680
+ if (finished) {
5681
+ const errMsg = item.error && typeof item.error.message === "string" ? item.error.message : void 0;
5682
+ events.push({
5683
+ type: "tool_result",
5684
+ id: item.id,
5685
+ content: unwrapCodexMcpResult(item.result) ?? errMsg,
5686
+ isError: item.status === "failed" || Boolean(errMsg)
5687
+ });
5688
+ }
5689
+ return events.length === 1 ? events[0] : events;
5690
+ }
5691
+ if (itemType === "command_execution" && item.id) {
5692
+ const input = item.command ? { command: item.command } : void 0;
5693
+ const events = [
5694
+ { type: "tool_use", id: item.id, name: "Bash", input }
5695
+ ];
5696
+ if (type === "item.completed" || item.status === "completed" || item.status === "failed") {
5697
+ events.push({
5698
+ type: "tool_result",
5699
+ id: item.id,
5700
+ content: item.aggregated_output,
5701
+ isError: item.status === "failed"
5702
+ });
5703
+ }
5704
+ return events.length === 1 ? events[0] : events;
5705
+ }
5590
5706
  if (item.status === "failed") {
5591
- const detail = item.message?.trim() || extractJsonErrorMessage(item) || `Codex ${item.type ?? "item"} failed`;
5707
+ const detail = item.message?.trim() || extractJsonErrorMessage(item) || `Codex ${itemType ?? "item"} failed`;
5592
5708
  return { type: "stderr", data: detail };
5593
5709
  }
5594
5710
  }
@@ -5674,6 +5790,75 @@ function usageFromCursor(usage) {
5674
5790
  cacheWriteTokens: usage.cacheWriteTokens ? Number(usage.cacheWriteTokens) : void 0
5675
5791
  };
5676
5792
  }
5793
+ function asRecord2(value) {
5794
+ if (value && typeof value === "object" && !Array.isArray(value)) {
5795
+ return value;
5796
+ }
5797
+ return void 0;
5798
+ }
5799
+ function normalizeCursorToolCall(name, args) {
5800
+ const raw = asRecord2(args);
5801
+ const toolName = typeof raw?.toolName === "string" && raw.toolName.trim() ? raw.toolName.trim() : null;
5802
+ const looksLikeMcp = name === "mcp" || toolName != null && (typeof raw?.providerIdentifier === "string" || asRecord2(raw?.args) != null);
5803
+ if (looksLikeMcp && toolName) {
5804
+ const providerRaw = typeof raw.providerIdentifier === "string" && raw.providerIdentifier.trim() ? raw.providerIdentifier.trim() : "sideboard";
5805
+ const provider = providerRaw.replace(/[^a-zA-Z0-9_-]/g, "_");
5806
+ const nested = asRecord2(raw.args);
5807
+ return {
5808
+ name: `mcp__${provider}__${toolName}`,
5809
+ input: nested ?? { toolName }
5810
+ };
5811
+ }
5812
+ return { name, input: raw };
5813
+ }
5814
+ function unwrapCursorToolResult(result) {
5815
+ if (result == null) return void 0;
5816
+ if (typeof result === "string") return result;
5817
+ const rec = asRecord2(result);
5818
+ if (!rec) {
5819
+ try {
5820
+ return JSON.stringify(result);
5821
+ } catch {
5822
+ return String(result);
5823
+ }
5824
+ }
5825
+ const collectTexts = (items) => {
5826
+ const texts = [];
5827
+ for (const item of items) {
5828
+ const row = asRecord2(item);
5829
+ if (!row) continue;
5830
+ if (typeof row.text === "string") {
5831
+ texts.push(row.text);
5832
+ continue;
5833
+ }
5834
+ const nested = asRecord2(row.text);
5835
+ if (typeof nested?.text === "string") texts.push(nested.text);
5836
+ }
5837
+ return texts;
5838
+ };
5839
+ const value = asRecord2(rec.value);
5840
+ if (value && Array.isArray(value.content)) {
5841
+ const texts = collectTexts(value.content);
5842
+ if (texts.length) return texts.join("\n");
5843
+ }
5844
+ if (Array.isArray(rec.content)) {
5845
+ const texts = collectTexts(rec.content);
5846
+ if (texts.length) return texts.join("\n");
5847
+ }
5848
+ try {
5849
+ return JSON.stringify(result);
5850
+ } catch {
5851
+ return String(result);
5852
+ }
5853
+ }
5854
+ function cursorToolResultIsError(status, result) {
5855
+ if (status === "error") return true;
5856
+ const rec = asRecord2(result);
5857
+ if (!rec) return false;
5858
+ if (rec.status === "error") return true;
5859
+ const value = asRecord2(rec.value);
5860
+ return value?.isError === true;
5861
+ }
5677
5862
  function cursorSdkMessageToEvents(msg) {
5678
5863
  if (!msg?.type) return [];
5679
5864
  if (msg.type === "system" && msg.agent_id) {
@@ -5688,35 +5873,42 @@ function cursorSdkMessageToEvents(msg) {
5688
5873
  if (block?.type === "text" && block.text) {
5689
5874
  out.push({ type: "stdout", data: block.text });
5690
5875
  } else if (block?.type === "tool_use" && block.id && block.name) {
5876
+ const normalized = normalizeCursorToolCall(block.name, block.input);
5691
5877
  out.push({
5692
5878
  type: "tool_use",
5693
5879
  id: block.id,
5694
- name: block.name,
5695
- input: block.input && typeof block.input === "object" ? block.input : void 0
5880
+ name: normalized.name,
5881
+ input: normalized.input
5696
5882
  });
5697
5883
  }
5698
5884
  }
5699
5885
  return out;
5700
5886
  }
5701
5887
  if (msg.type === "tool_call" && msg.call_id && msg.name) {
5888
+ const normalized = normalizeCursorToolCall(msg.name, msg.args);
5702
5889
  if (msg.status === "running") {
5703
5890
  return [
5704
5891
  {
5705
5892
  type: "tool_use",
5706
5893
  id: msg.call_id,
5707
- name: msg.name,
5708
- input: msg.args && typeof msg.args === "object" ? msg.args : void 0
5894
+ name: normalized.name,
5895
+ input: normalized.input
5709
5896
  }
5710
5897
  ];
5711
5898
  }
5712
5899
  if (msg.status === "completed" || msg.status === "error") {
5713
- const content = typeof msg.result === "string" ? msg.result : msg.result != null ? JSON.stringify(msg.result) : void 0;
5714
5900
  return [
5901
+ {
5902
+ type: "tool_use",
5903
+ id: msg.call_id,
5904
+ name: normalized.name,
5905
+ input: normalized.input
5906
+ },
5715
5907
  {
5716
5908
  type: "tool_result",
5717
5909
  id: msg.call_id,
5718
- content,
5719
- isError: msg.status === "error"
5910
+ content: unwrapCursorToolResult(msg.result),
5911
+ isError: cursorToolResultIsError(msg.status, msg.result)
5720
5912
  }
5721
5913
  ];
5722
5914
  }
@@ -6086,17 +6278,31 @@ var init_opencode = __esm({
6086
6278
  return { type: "stderr", data: detail };
6087
6279
  }
6088
6280
  const sid = typeof obj.sessionID === "string" && obj.sessionID || typeof obj.sessionId === "string" && obj.sessionId || typeof obj.session_id === "string" && obj.session_id;
6089
- if (sid) return { type: "session_id", data: sid };
6281
+ if (sid && (!obj.type || obj.type === "step_start" || obj.type === "session")) {
6282
+ return { type: "session_id", data: sid };
6283
+ }
6090
6284
  if (obj.type === "text") {
6091
6285
  const text = obj.part?.text ?? obj.text;
6092
6286
  if (text) return { type: "stdout", data: text };
6093
6287
  }
6094
6288
  if (obj.type === "tool_use") {
6095
6289
  const part = obj.part;
6096
- const id = part?.id ?? obj.id ?? `tool-${Date.now()}`;
6097
- const name = part?.name ?? part?.tool ?? obj.name ?? obj.tool ?? "tool";
6098
- const input = part?.input ?? obj.input;
6099
- return { type: "tool_use", id, name, input };
6290
+ const id = part?.callID ?? part?.id ?? obj.id ?? `tool-${Date.now()}`;
6291
+ const name = part?.tool ?? part?.name ?? obj.tool ?? obj.name ?? "tool";
6292
+ const state = part?.state;
6293
+ const input = (state?.input && typeof state.input === "object" ? state.input : void 0) ?? part?.input ?? obj.input;
6294
+ const events = [{ type: "tool_use", id, name, input }];
6295
+ const output = state?.output;
6296
+ if (output != null || state?.status === "completed" || state?.status === "error") {
6297
+ const content = typeof output === "string" ? output : output != null ? JSON.stringify(output) : formatUnknownDetail(state?.error) || void 0;
6298
+ events.push({
6299
+ type: "tool_result",
6300
+ id,
6301
+ content,
6302
+ isError: state?.status === "error" || state?.status === "failed"
6303
+ });
6304
+ }
6305
+ return events.length === 1 ? events[0] : events;
6100
6306
  }
6101
6307
  if (obj.type === "tool_result") {
6102
6308
  const part = obj.part;
@@ -6124,6 +6330,7 @@ var init_opencode = __esm({
6124
6330
  }
6125
6331
  },
6126
6332
  async resolveSessionId(worktreePath, cached) {
6333
+ const cachedId = cached?.trim() || null;
6127
6334
  const listed = await run(
6128
6335
  "opencode",
6129
6336
  ["session", "list", "--format", "json"],
@@ -6135,15 +6342,21 @@ var init_opencode = __esm({
6135
6342
  if (Array.isArray(sessions) && sessions.length > 0) {
6136
6343
  const norm = (p) => p.replace(/\/+$/, "");
6137
6344
  const wt = norm(worktreePath);
6138
- const match = sessions.find(
6345
+ const forWorktree = sessions.filter(
6139
6346
  (s) => s.directory && norm(s.directory) === wt || s.path && norm(s.path) === wt
6140
6347
  );
6141
- if (match?.id) return match.id;
6348
+ if (cachedId && forWorktree.some((s) => s.id === cachedId)) {
6349
+ return cachedId;
6350
+ }
6351
+ if (cachedId && sessions.some((s) => s.id === cachedId)) {
6352
+ return cachedId;
6353
+ }
6354
+ return null;
6142
6355
  }
6143
6356
  } catch {
6144
6357
  }
6145
6358
  }
6146
- return cached;
6359
+ return cachedId;
6147
6360
  },
6148
6361
  async buildAttach(thread) {
6149
6362
  const sessionId = await this.resolveSessionId(thread.worktreePath, thread.sessionId);
@@ -6642,7 +6855,7 @@ var init_agents = __esm({
6642
6855
  });
6643
6856
 
6644
6857
  // src/plan/plan-present.ts
6645
- function asRecord2(v) {
6858
+ function asRecord4(v) {
6646
6859
  return v != null && typeof v === "object" && !Array.isArray(v) ? v : null;
6647
6860
  }
6648
6861
  function isPresentPlanToolName(name) {
@@ -6654,7 +6867,7 @@ function extractPresentedPlan(parts) {
6654
6867
  for (let i = parts.length - 1; i >= 0; i--) {
6655
6868
  const p = parts[i];
6656
6869
  if (p.type !== "tool" || !isPresentPlanToolName(p.name)) continue;
6657
- const input = asRecord2(p.input) ?? {};
6870
+ const input = asRecord4(p.input) ?? {};
6658
6871
  const content = typeof input.content === "string" ? input.content : typeof input.plan === "string" ? input.plan : typeof input.markdown === "string" ? input.markdown : "";
6659
6872
  if (!content.trim()) continue;
6660
6873
  const title = typeof input.title === "string" && input.title.trim() ? input.title.trim() : "Plan";
@@ -7136,6 +7349,7 @@ __export(index_exports, {
7136
7349
  resolveFilesToCopy: () => resolveFilesToCopy,
7137
7350
  resolveGhAuthToken: () => resolveGhAuthToken,
7138
7351
  resolveGithubRepoSlug: () => resolveGithubRepoSlug,
7352
+ resolveNewThreadOptions: () => resolveNewThreadOptions,
7139
7353
  resolvePlanMarkdown: () => resolvePlanMarkdown,
7140
7354
  resolvePrSelector: () => resolvePrSelector,
7141
7355
  resolveQuotaFallbackAgent: () => resolveQuotaFallbackAgent,
@@ -7414,7 +7628,7 @@ init_agents();
7414
7628
  init_orchestrator_capable();
7415
7629
 
7416
7630
  // src/agents/message-parts.ts
7417
- function asRecord(input) {
7631
+ function asRecord3(input) {
7418
7632
  if (input && typeof input === "object" && !Array.isArray(input)) {
7419
7633
  return input;
7420
7634
  }
@@ -7549,7 +7763,7 @@ function applyAgentEvent(parts, event) {
7549
7763
  return next;
7550
7764
  }
7551
7765
  if (event.type === "tool_use") {
7552
- const input = asRecord(event.input);
7766
+ const input = asRecord3(event.input);
7553
7767
  const diff = diffFromInput(input);
7554
7768
  const existing = parts.findIndex((p) => p.type === "tool" && p.id === event.id);
7555
7769
  if (existing >= 0) {
@@ -7583,9 +7797,25 @@ function applyAgentEvent(parts, event) {
7583
7797
  ];
7584
7798
  }
7585
7799
  if (event.type === "tool_result") {
7586
- const next = parts.map((p) => {
7587
- if (p.type !== "tool" || p.id !== event.id) return p;
7588
- const fromResult = parseDiffStat(event.content);
7800
+ const existing = parts.findIndex((p) => p.type === "tool" && p.id === event.id);
7801
+ const fromResult = parseDiffStat(event.content);
7802
+ if (existing < 0) {
7803
+ return [
7804
+ ...parts,
7805
+ {
7806
+ type: "tool",
7807
+ id: event.id,
7808
+ name: "tool",
7809
+ description: "tool",
7810
+ status: event.isError ? "error" : "done",
7811
+ result: event.content,
7812
+ ...fromResult.additions != null ? { additions: fromResult.additions } : {},
7813
+ ...fromResult.deletions != null ? { deletions: fromResult.deletions } : {}
7814
+ }
7815
+ ];
7816
+ }
7817
+ return parts.map((p, i) => {
7818
+ if (i !== existing || p.type !== "tool") return p;
7589
7819
  return {
7590
7820
  ...p,
7591
7821
  status: event.isError ? "error" : "done",
@@ -7594,7 +7824,6 @@ function applyAgentEvent(parts, event) {
7594
7824
  ...fromResult.deletions != null ? { deletions: fromResult.deletions } : {}
7595
7825
  };
7596
7826
  });
7597
- return next;
7598
7827
  }
7599
7828
  return parts;
7600
7829
  }
@@ -9862,10 +10091,17 @@ async function confirmLand(thread, opts) {
9862
10091
  // src/threads/create.ts
9863
10092
  var import_node_fs20 = require("fs");
9864
10093
  init_worktree();
10094
+ init_app_settings();
9865
10095
  init_thread_store();
9866
10096
  init_workspaces();
9867
10097
  async function createThread(input, _onSetupLine) {
9868
- await requireAgent(input.agent);
10098
+ const resolved = resolveNewThreadOptions({
10099
+ agent: input.agent,
10100
+ model: input.model,
10101
+ effort: input.effort,
10102
+ fast: input.fast
10103
+ });
10104
+ await requireAgent(resolved.agent);
9869
10105
  const repoPath = await resolveRepoRoot(input.repoPath);
9870
10106
  if (!(0, import_node_fs20.existsSync)(repoPath)) {
9871
10107
  throw new Error(`Repo not found: ${repoPath}`);
@@ -9908,11 +10144,11 @@ async function createThread(input, _onSetupLine) {
9908
10144
  branchName,
9909
10145
  worktreePath,
9910
10146
  repoPath,
9911
- agent: input.agent,
10147
+ agent: resolved.agent,
9912
10148
  autonomy: input.autonomy ?? "default",
9913
- model: input.model ?? null,
9914
- effort: input.effort ?? "high",
9915
- fast: Boolean(input.fast),
10149
+ model: resolved.model,
10150
+ effort: resolved.effort,
10151
+ fast: resolved.fast,
9916
10152
  planMode: Boolean(input.planMode),
9917
10153
  attachments: input.attachments ?? [],
9918
10154
  sourceIsFork,
@@ -11570,21 +11806,30 @@ var Orchestrator = class {
11570
11806
  return findThreadByRef(idOrRef) ?? readThread(idOrRef);
11571
11807
  }
11572
11808
  async createThread(input) {
11573
- let thread = await createThread(input);
11809
+ const thread = await createThread(input);
11574
11810
  this.emit({ type: "status_changed", threadId: thread.id, status: thread.status });
11575
- await this.runSetupAfterCreate(thread.id);
11811
+ void this.finishCreateThread(thread.id, input.prompt?.trim() || void 0);
11812
+ return thread;
11813
+ }
11814
+ async finishCreateThread(threadId, prompt) {
11815
+ await this.runSetupAfterCreate(threadId);
11576
11816
  const { autoRunAfterSetupEnabled: autoRunAfterSetupEnabled2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
11577
11817
  if (autoRunAfterSetupEnabled2()) {
11578
11818
  try {
11579
- await this.startDev(thread.id);
11819
+ await this.startDev(threadId);
11580
11820
  } catch {
11581
11821
  }
11582
11822
  }
11583
- const prompt = input.prompt?.trim();
11584
11823
  if (prompt) {
11585
- thread = await this.send(thread.id, prompt);
11824
+ try {
11825
+ await this.send(threadId, prompt);
11826
+ } catch (err) {
11827
+ const message = err instanceof Error ? err.message : String(err);
11828
+ updateThread(threadId, {
11829
+ lastError: `First prompt failed: ${message}`
11830
+ });
11831
+ }
11586
11832
  }
11587
- return thread;
11588
11833
  }
11589
11834
  /** Run workspace setup after a new worktree is created (no-op if none configured). */
11590
11835
  async runSetupAfterCreate(threadId) {
@@ -11600,7 +11845,7 @@ var Orchestrator = class {
11600
11845
  }
11601
11846
  }
11602
11847
  listWorkspaces() {
11603
- const fromThreads = listThreads({ includeArchived: false }).map((t) => t.repoPath);
11848
+ const fromThreads = listThreads({ includeArchived: true }).map((t) => t.repoPath);
11604
11849
  return syncWorkspacesFromThreads(fromThreads);
11605
11850
  }
11606
11851
  async addWorkspace(repoPath) {
@@ -11930,8 +12175,73 @@ var Orchestrator = class {
11930
12175
  }
11931
12176
  }
11932
12177
  }
11933
- const lastStderr = summarizeTurnStderr(stderrTail);
11934
- const detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
12178
+ let lastStderr = summarizeTurnStderr(stderrTail);
12179
+ let detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
12180
+ if (exitCode !== 0 && !assistantText && parts.length === 0 && !this.stoppedTurns.has(threadId) && looksLikeInvalidAgentSession(detail) && this.requireThread(threadId).sessionId && this.requireThread(threadId).agent !== "cursor" && this.requireThread(threadId).agent !== "brightsy") {
12181
+ updateThread(threadId, { sessionId: null });
12182
+ pushTurnStderr(
12183
+ stderrTail,
12184
+ "Agent session missing \u2014 starting a fresh session"
12185
+ );
12186
+ this.emit({
12187
+ type: "turn_output",
12188
+ threadId,
12189
+ event: {
12190
+ type: "stderr",
12191
+ data: "Agent session missing \u2014 starting a fresh session"
12192
+ }
12193
+ });
12194
+ const retryThread = this.requireThread(threadId);
12195
+ const prior = retryThread.messages.slice(0, -1);
12196
+ const retrySeed = buildSessionSeed(prior);
12197
+ const retryInstructions = retryThread.agent === "claude" ? null : formatAgentInstructions(
12198
+ loadAgentInstructions(retryThread.worktreePath, retryThread.agent)
12199
+ );
12200
+ const retryPrefix = [
12201
+ coordinatorDirective,
12202
+ worktreeDirective,
12203
+ artifactDirective,
12204
+ renameBranchDirective,
12205
+ retryInstructions,
12206
+ retrySeed
12207
+ ].filter(Boolean).join("\n\n---\n\n");
12208
+ const retryHandle = await spawnAgentTurn(
12209
+ retryThread,
12210
+ { cachedPrefix: retryPrefix, prompt: agentPrompt },
12211
+ (event) => {
12212
+ this.emit({ type: "turn_output", threadId, event });
12213
+ if (event.type === "session_id") {
12214
+ updateThread(threadId, { sessionId: event.data });
12215
+ }
12216
+ if (event.type === "stderr" && typeof event.data === "string") {
12217
+ pushTurnStderr(stderrTail, event.data);
12218
+ }
12219
+ }
12220
+ );
12221
+ this.activeTurns.set(threadId, retryHandle);
12222
+ if (typeof retryHandle.pid === "number" && retryHandle.pid > 0) {
12223
+ updateThread(threadId, { agentPid: retryHandle.pid });
12224
+ }
12225
+ this.processes.set(`${threadId}:agent`, {
12226
+ kind: "agent",
12227
+ pid: retryHandle.pid,
12228
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
12229
+ kill: retryHandle.kill
12230
+ });
12231
+ if (this.stoppedTurns.has(threadId)) {
12232
+ retryHandle.kill();
12233
+ }
12234
+ const retryResult = await retryHandle.done;
12235
+ if (retryResult.sessionId) {
12236
+ updateThread(threadId, { sessionId: retryResult.sessionId });
12237
+ }
12238
+ assistantText = retryResult.assistantText.trim();
12239
+ parts = retryResult.parts;
12240
+ usage = retryResult.usage ?? void 0;
12241
+ exitCode = retryResult.exitCode;
12242
+ lastStderr = summarizeTurnStderr(stderrTail);
12243
+ detail = lastStderr || (exitCode !== 0 ? fallbackTurnFailDetail(assistantText) : "");
12244
+ }
11935
12245
  let chatText = assistantText;
11936
12246
  if (exitCode !== 0 && !chatText && looksLikeAgentFailureMessage(detail)) {
11937
12247
  chatText = humanizeAgentFailDetail(detail);
@@ -12635,7 +12945,15 @@ var Orchestrator = class {
12635
12945
  }
12636
12946
  await removeWorktree(thread.repoPath, thread.worktreePath);
12637
12947
  }
12638
- return setStatus(thread.id, "archived");
12948
+ const archived = setStatus(thread.id, "archived");
12949
+ if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
12950
+ try {
12951
+ const { ensureWorkspace: ensureWorkspace2 } = await Promise.resolve().then(() => (init_workspaces(), workspaces_exports));
12952
+ await ensureWorkspace2(thread.repoPath);
12953
+ } catch {
12954
+ }
12955
+ }
12956
+ return archived;
12639
12957
  }
12640
12958
  async purge(threadRef, opts) {
12641
12959
  const thread = this.requireThread(threadRef);
@@ -12780,7 +13098,7 @@ async function startOrchestration(opts) {
12780
13098
  init_workspace_scratch();
12781
13099
 
12782
13100
  // src/plan/ask-user.ts
12783
- function asRecord3(v) {
13101
+ function asRecord5(v) {
12784
13102
  return v != null && typeof v === "object" && !Array.isArray(v) ? v : null;
12785
13103
  }
12786
13104
  function parseOptions(raw) {
@@ -12791,7 +13109,7 @@ function parseOptions(raw) {
12791
13109
  out.push({ label: item.trim() });
12792
13110
  continue;
12793
13111
  }
12794
- const o = asRecord3(item);
13112
+ const o = asRecord5(item);
12795
13113
  if (!o) continue;
12796
13114
  const label = typeof o.label === "string" ? o.label.trim() : typeof o.text === "string" ? o.text.trim() : typeof o.title === "string" ? o.title.trim() : "";
12797
13115
  if (!label) continue;
@@ -12801,7 +13119,7 @@ function parseOptions(raw) {
12801
13119
  return out;
12802
13120
  }
12803
13121
  function parseOneQuestion(raw) {
12804
- const o = asRecord3(raw);
13122
+ const o = asRecord5(raw);
12805
13123
  if (!o) return null;
12806
13124
  const question = typeof o.question === "string" ? o.question.trim() : typeof o.text === "string" ? o.text.trim() : typeof o.prompt === "string" ? o.prompt.trim() : "";
12807
13125
  if (!question) return null;
@@ -12812,7 +13130,7 @@ function parseOneQuestion(raw) {
12812
13130
  return { question, header, multiSelect, options };
12813
13131
  }
12814
13132
  function parsePlanQuestionsInput(input) {
12815
- const root = asRecord3(input);
13133
+ const root = asRecord5(input);
12816
13134
  if (!root) return [];
12817
13135
  const list = Array.isArray(root.questions) ? root.questions : Array.isArray(root.question) ? root.question : root.question || root.prompt ? [root] : [];
12818
13136
  const out = [];
@@ -13104,13 +13422,19 @@ async function startMcpServer() {
13104
13422
  return { content: [{ type: "text", text: JSON.stringify(payload) }] };
13105
13423
  }
13106
13424
  );
13425
+ const { resolveNewThreadOptions: resolveNewThreadOptions2, resolveThreadDefaults: resolveThreadDefaults2 } = await Promise.resolve().then(() => (init_app_settings(), app_settings_exports));
13426
+ const accountDefaults = resolveThreadDefaults2();
13427
+ const accountDefaultsHint = `Account defaults: agent=${accountDefaults.agent}, model=${accountDefaults.model?.trim() || "Auto"}, effort=${accountDefaults.effort}`;
13107
13428
  server.tool(
13108
13429
  "create_thread",
13109
- "Create a new worktree thread (chat) from branch, pr, or ticket. Pass repoPath from list_workspaces and parentThreadId when spawning from an orchestrator. Then use send_to_thread to chat.",
13430
+ `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.`,
13110
13431
  {
13111
13432
  sourceType: import_zod.z.enum(["branch", "pr", "ticket"]),
13112
13433
  sourceRef: import_zod.z.string(),
13113
- agent: import_zod.z.enum(["claude", "codex", "opencode", "brightsy", "cursor"]),
13434
+ agent: import_zod.z.enum(["claude", "codex", "opencode", "brightsy", "cursor"]).optional().describe(`Omit to use Account default agent (${accountDefaults.agent})`),
13435
+ model: import_zod.z.string().nullable().optional().describe(
13436
+ `Usually omit to use Account default model (${accountDefaults.model?.trim() || "Auto"}). Pass null only to force Auto / agent-default.`
13437
+ ),
13114
13438
  repoPath: import_zod.z.string(),
13115
13439
  title: import_zod.z.string().optional(),
13116
13440
  parentThreadId: import_zod.z.string().optional()
@@ -13130,10 +13454,17 @@ async function startMcpServer() {
13130
13454
  };
13131
13455
  }
13132
13456
  }
13457
+ const opts = resolveNewThreadOptions2({
13458
+ agent: args.agent,
13459
+ model: args.model
13460
+ });
13133
13461
  const thread = await orch.createThread({
13134
13462
  sourceType: args.sourceType,
13135
13463
  sourceRef: args.sourceRef,
13136
- agent: args.agent,
13464
+ agent: opts.agent,
13465
+ model: opts.model,
13466
+ effort: opts.effort,
13467
+ fast: opts.fast,
13137
13468
  repoPath: args.repoPath,
13138
13469
  title: args.title,
13139
13470
  parentThreadId: args.parentThreadId ?? null
@@ -13147,6 +13478,8 @@ async function startMcpServer() {
13147
13478
  title: thread.title,
13148
13479
  branchName: thread.branchName,
13149
13480
  worktreePath: thread.worktreePath,
13481
+ agent: thread.agent,
13482
+ model: thread.model,
13150
13483
  status: thread.status,
13151
13484
  link: `sideboard://thread/${thread.id}`
13152
13485
  })
@@ -14421,6 +14754,7 @@ init_injected_mcp();
14421
14754
  resolveFilesToCopy,
14422
14755
  resolveGhAuthToken,
14423
14756
  resolveGithubRepoSlug,
14757
+ resolveNewThreadOptions,
14424
14758
  resolvePlanMarkdown,
14425
14759
  resolvePrSelector,
14426
14760
  resolveQuotaFallbackAgent,