@sideboard-ai/core 0.1.175 → 0.1.176

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.
@@ -12,6 +12,7 @@ import {
12
12
  getAgentSetupInfo,
13
13
  installAgent,
14
14
  installNpmGlobalPackage,
15
+ isCursorApiKeyConfigured,
15
16
  isCursorAutoModel,
16
17
  isSessionQuotaLimit,
17
18
  listAgentSetupInfo,
@@ -31,8 +32,8 @@ import {
31
32
  resolveLoginCommand,
32
33
  resolveQuotaFallbackAgent,
33
34
  whichOnPath
34
- } from "./chunk-QTJ2ERA6.js";
35
- import "./chunk-NA7P3SZL.js";
35
+ } from "./chunk-NIB6BTC6.js";
36
+ import "./chunk-3ZFGZ7RT.js";
36
37
  import "./chunk-7JIYKYLL.js";
37
38
  import "./chunk-6K64FJDD.js";
38
39
  import "./chunk-IEEAVWAP.js";
@@ -87,6 +88,7 @@ export {
87
88
  installAgent,
88
89
  installNpmGlobalPackage,
89
90
  isConductorBundledCli,
91
+ isCursorApiKeyConfigured,
90
92
  isCursorAutoModel,
91
93
  isOrchestratorCapableAgent,
92
94
  isSessionQuotaLimit,
@@ -15,6 +15,7 @@ import {
15
15
  getAgentSetupInfo,
16
16
  installAgent,
17
17
  installNpmGlobalPackage,
18
+ isCursorApiKeyConfigured,
18
19
  isCursorAutoModel,
19
20
  isSessionQuotaLimit,
20
21
  listAgentSetupInfo,
@@ -37,11 +38,11 @@ import {
37
38
  resolveQuotaFallbackAgent,
38
39
  turnCostUsdFromCursorUsage,
39
40
  whichOnPath
40
- } from "./chunk-ZXHV3NHY.js";
41
+ } from "./chunk-W44EKPIR.js";
41
42
  import "./chunk-HVIEYTUK.js";
42
43
  import "./chunk-Y4MIXGPA.js";
43
44
  import "./chunk-VKQGAWHY.js";
44
- import "./chunk-TNOLCU5B.js";
45
+ import "./chunk-FJWQCZ74.js";
45
46
  import "./chunk-7O53GXTA.js";
46
47
  import "./chunk-D6JWYJ4P.js";
47
48
  import "./chunk-LZQULFIT.js";
@@ -86,6 +87,7 @@ export {
86
87
  installAgent,
87
88
  installNpmGlobalPackage,
88
89
  isConductorBundledCli,
90
+ isCursorApiKeyConfigured,
89
91
  isCursorAutoModel,
90
92
  isOrchestratorCapableAgent,
91
93
  isSessionQuotaLimit,
@@ -390,7 +390,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
390
390
  "Workspaces:",
391
391
  "- add_workspace / remove_workspace \u2014 register or unregister a git repo",
392
392
  "Worktree threads (chats):",
393
- "- create_thread \u2014 create a worktree + chat from branch | pr | ticket (appears on Home). Do not create a second worktree for a ticket, PR, or named branch that already has one \u2014 that call returns the live thread (alreadyStarted=true). Creating from the default branch still opens a new isolated worktree. Pass repoPath + parentThreadId; omit agent and model so Sideboard applies Settings \u2192 Default agent, model & effort (never pass your own agent or agent=cursor). If the repo has a setup script, Sideboard runs it in the background (does not block send_to_thread). Nested Codex (you are Codex and the child is Codex) deadlocks \u2014 omit agent; Sideboard coerces that case",
393
+ "- create_thread \u2014 create a worktree + chat from branch | pr | ticket (appears on Home). Do not create a second worktree for a ticket, PR, or named branch that already has one \u2014 that call returns the live thread (alreadyStarted=true). Creating from the default branch still opens a new isolated worktree. Pass repoPath + parentThreadId; omit agent and model so Sideboard applies Settings \u2192 Default agent, model & effort (never pass your own agent or agent=cursor). If the repo has a setup script, Sideboard runs it in the background (does not block send_to_thread). Nested Codex (you are Codex and the child would be Codex) can deadlock on ~/.codex locks \u2014 omit agent; Sideboard switches the child to Cursor when a CURSOR_API_KEY is set, otherwise keeps the Account default",
394
394
  "- start_board_card \u2014 same as create_thread for a ticket/PR/named branch (attaches issue text when resolvable). Then send_to_thread.",
395
395
  "- 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.",
396
396
  "- 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.",
@@ -405,9 +405,9 @@ var COORDINATOR_TOOL_PLAYBOOK = [
405
405
  "- get_diff \u2014 compact diff summary",
406
406
  "- get_pr_checks \u2014 snapshot of a worktree thread's PR checks (null = no PR). Use this to inspect status. If the user gave a goal, the worktree agent watches with `gh pr checks --watch` \u2014 do not poll for the human.",
407
407
  '- request_review \u2014 open a Review chat tab on a worktree thread (attaches .claude/skills/review/SKILL.md when present, else .context/review.md copied from .sideboard/review.md / stock; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id',
408
- "- ask_git \u2014 commit & push, open a draft PR, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If ask_git / get_thread lastError says the GraphQL/PR body is too long, the branch is already pushed \u2014 send_to_thread so the worktree agent runs `gh pr create --body-file` with a short description. Do not invent SSH or auth failures from that error. If the user gave a goal (Greptile 5/5, CI green), send_to_thread that goal so the worktree agent enters the watch-fix-push loop \u2014 do not tell the human to poll.",
408
+ "- ask_git \u2014 commit & push, open a draft PR, mark ready for review, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If ask_git / get_thread lastError says the GraphQL/PR body is too long, the branch is already pushed \u2014 send_to_thread so the worktree agent runs `gh pr create --body-file` with a short description. Do not invent SSH or auth failures from that error. If the user gave a goal (Greptile 5/5, CI green), send_to_thread that goal so the worktree agent enters the watch-fix-push loop \u2014 do not tell the human to poll.",
409
409
  '- Merge (`ask_git` action=merge / send_to_thread "Merge PR.") only when the user explicitly asked to merge that PR. Do not merge because the work looks done, CI is green, or a typical flow includes it.',
410
- '- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Merge the remote branch (main) into your branch and resolve conflicts. Then, commit and push your changes.", "Merge PR." (draft PRs: `gh pr create --draft -R <origin-owner/name>` using the workspace `github:` slug \u2014 never upstream). Never run git/gh from this orchestration cwd, and never merge the PR yourself.',
410
+ '- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Ready for review.", "Merge the remote branch (main) into your branch and resolve conflicts. Then, commit and push your changes.", "Merge PR." (draft PRs: `gh pr create --draft -R <origin-owner/name>` using the workspace `github:` slug \u2014 never upstream). Never run git/gh from this orchestration cwd, and never merge the PR yourself.',
411
411
  "Process guides:",
412
412
  "- Long child jobs (pack, test, deploy, anything that may run more than ~30s): workers always have `/long-running` (Sideboard product skill). Tell them to detach and wait; they may `stop_job` if it hangs or is doing the wrong thing; do not ask the human to poll.",
413
413
  "- Recurring multi-item / fan-out: if the child worktree has `.claude/skills/graph-engineering/SKILL.md`, tell the worker to follow it (`/graph-engineering`). Judge first; state on disk; grow the rulebook; do not patch three threads.",
@@ -532,7 +532,7 @@ function ensureGlobalCoordinatorCwd(opts) {
532
532
  "When creating threads, pass `repoPath` from `list_workspaces` (or the path you just registered).",
533
533
  orchId ? `Pass parentThreadId="${orchId}" (or omit it). Never invent another parentThreadId.` : "Pass `parentThreadId` for children (this chat's id from the turn reminder).",
534
534
  "Omit `agent` / `model` on `create_thread`. Sideboard applies Settings \u2192 Default agent, model & effort. Do not pass your own agent or `agent=cursor` \u2014 those are ignored.",
535
- "Never pass `agent=codex` when you yourself are Codex \u2014 nested Codex deadlocks on shared ~/.codex locks. Omit agent; Sideboard applies Account defaults (and coerces only that nested-Codex case).",
535
+ "Never pass `agent=codex` when you yourself are Codex \u2014 nested Codex can deadlock on shared ~/.codex locks. Omit agent; Sideboard applies Account defaults, and switches that nested-Codex case to Cursor only when a CURSOR_API_KEY is configured.",
536
536
  "Typical flow (Home board): list_board \u2192 create_thread (sourceType=ticket|pr|branch) \u2192 send_to_thread \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft \u2192 wait_for_turn. Merge only if the user explicitly asked (`ask_git` merge).",
537
537
  "Typical flow (branch / explicit source): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
538
538
  "Typical flow (find work): list_workspaces \u2192 pick repo(s) matching account / project context \u2192 Sideboard list_issues / linear_* (tickets) or list_prs(queue=review) (reviews) \u2192 show the options. Never wait on Claude Linear MCP. Only create_thread + send_to_thread when they asked to start (e.g. \u201Cfind me work and start it\u201D) \u2014 then wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
@@ -24,7 +24,7 @@ import {
24
24
  stripBrightsyNdjsonNoise,
25
25
  sumUsageList,
26
26
  toolDescription
27
- } from "./chunk-QTJ2ERA6.js";
27
+ } from "./chunk-NIB6BTC6.js";
28
28
  import {
29
29
  SLACK_REPLY_FORMATTING,
30
30
  addWorkspace,
@@ -47,7 +47,7 @@ import {
47
47
  stageAbsolutePathsAsAttachments,
48
48
  stageBuffersAsAttachments,
49
49
  syncWorkspacesFromThreads
50
- } from "./chunk-NA7P3SZL.js";
50
+ } from "./chunk-3ZFGZ7RT.js";
51
51
  import {
52
52
  addPrStackLayer,
53
53
  allocateTeamName,
@@ -466,7 +466,7 @@ async function continueSourceThread(threadId, prompt) {
466
466
  await continueOnReply(threadId, prompt);
467
467
  return;
468
468
  }
469
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-PDEU75EE.js");
469
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-GDKEVLFK.js");
470
470
  await getOrchestrator2().send(threadId, prompt);
471
471
  } catch {
472
472
  }
@@ -800,9 +800,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
800
800
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
801
801
  );
802
802
  }
803
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-KPROJ54C.js");
803
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-3HIWNQ3B.js");
804
804
  if (isGlobalThread2(thread)) {
805
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-7OHKB5WV.js");
805
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-PRM5ARWG.js");
806
806
  ensureGlobalCoordinatorCwd2(
807
807
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
808
808
  );
@@ -997,6 +997,7 @@ var AGENT_GIT_ACTIONS = [
997
997
  "create-draft",
998
998
  "create-web",
999
999
  "resolve-conflicts",
1000
+ "ready-for-review",
1000
1001
  "merge"
1001
1002
  ];
1002
1003
  function agentGitPrompt(action, opts) {
@@ -1012,6 +1013,8 @@ function agentGitPrompt(action, opts) {
1012
1013
  const named = base ? ` (${base})` : "";
1013
1014
  return `Merge the remote branch${named} into your branch and resolve conflicts. Then, commit and push your changes.`;
1014
1015
  }
1016
+ case "ready-for-review":
1017
+ return "Ready for review.";
1015
1018
  case "merge":
1016
1019
  return "Merge PR.";
1017
1020
  }
@@ -1027,6 +1030,8 @@ function gitActionExpansion(action, base) {
1027
1030
  return "Commit, push, then `gh pr create --web -R <origin-owner/name>`.";
1028
1031
  case "resolve-conflicts":
1029
1032
  return `Fetch the PR base${base ? ` (\`${base}\`)` : ""}, merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
1033
+ case "ready-for-review":
1034
+ return "This phrase is the explicit ask to mark this thread's draft pull request ready for review on GitHub (`gh pr ready -R <origin-owner/name>` or `gh pr ready`). Update title/body if the purpose drifted. Do not merge.";
1030
1035
  case "merge":
1031
1036
  return "This phrase is the explicit ask to merge this thread's open pull request on GitHub. If `gh stack view` shows a stack, use `gh stack merge`; otherwise `gh pr merge` (respect repo defaults / squash vs merge). Do not force-push main/master or merge locally into the main checkout.";
1032
1037
  }
@@ -3782,7 +3787,7 @@ async function createThread(input, _onSetupLine) {
3782
3787
  return readThread(thread.id) ?? thread;
3783
3788
  }
3784
3789
  async function listLinearIssues(agent, repoPath) {
3785
- const { getAdapter: getAdapter2 } = await import("./agents-AWSFDB47.js");
3790
+ const { getAdapter: getAdapter2 } = await import("./agents-544IX5KA.js");
3786
3791
  await requireAgent(agent, { requireLinear: true });
3787
3792
  const adapter = getAdapter2(agent);
3788
3793
  if (!adapter.listLinearIssues) {
@@ -4204,7 +4209,7 @@ async function adoptThread(input) {
4204
4209
  messages: input.messages ?? []
4205
4210
  });
4206
4211
  writeThread(thread);
4207
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-TEBTNS2M.js");
4212
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-ULHYXM4Y.js");
4208
4213
  await ensureWorkspace2(repoPath);
4209
4214
  const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-X54WSOXM.js");
4210
4215
  await ensureWorktreeSideboardIgnored2(input.worktreePath);
@@ -5998,7 +6003,7 @@ function formatWorktreeDirective(thread, opts) {
5998
6003
  );
5999
6004
  }
6000
6005
  lines.push(
6001
- '- Sideboard git buttons send short phrases ("Commit and push.", "Merge PR.", \u2026) with their meaning attached \u2014 act on them without asking for clarification. If the user gives a goal (Greptile 5/5, CI green, until checks pass), you get the watch-fix-push playbook with that request.'
6006
+ '- Sideboard git buttons send short phrases ("Commit and push.", "Ready for review.", "Merge PR.", \u2026) with their meaning attached \u2014 act on them without asking for clarification. If the user gives a goal (Greptile 5/5, CI green, until checks pass), you get the watch-fix-push playbook with that request.'
6002
6007
  );
6003
6008
  lines.push("");
6004
6009
  lines.push(formatProcessGuideDirective({ worktreePath: thread.worktreePath }));
@@ -6686,7 +6691,7 @@ function formatScheduledPrompt(name, prompt) {
6686
6691
  ${prompt}`;
6687
6692
  }
6688
6693
  async function defaultDeps() {
6689
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-PDEU75EE.js");
6694
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-GDKEVLFK.js");
6690
6695
  const orch = getOrchestrator2();
6691
6696
  return {
6692
6697
  findThread: (id) => findThreadByRef(id),
@@ -8604,7 +8609,7 @@ var Orchestrator = class {
8604
8609
  "ask_git targets a worktree agent thread (not the orchestrator). Pass a child/worktree thread ref."
8605
8610
  );
8606
8611
  }
8607
- if (action === "merge" && !thread.prUrl) {
8612
+ if ((action === "merge" || action === "ready-for-review") && !thread.prUrl) {
8608
8613
  throw new Error(
8609
8614
  "No pull request linked. Ask the worktree agent to open a draft PR first (ask_git create-draft)."
8610
8615
  );
@@ -8772,7 +8777,7 @@ var Orchestrator = class {
8772
8777
  this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
8773
8778
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
8774
8779
  try {
8775
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-TEBTNS2M.js");
8780
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-ULHYXM4Y.js");
8776
8781
  await ensureWorkspace2(thread.repoPath);
8777
8782
  } catch {
8778
8783
  }
@@ -345,7 +345,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
345
345
  "Workspaces:",
346
346
  "- add_workspace / remove_workspace \u2014 register or unregister a git repo",
347
347
  "Worktree threads (chats):",
348
- "- create_thread \u2014 create a worktree + chat from branch | pr | ticket (appears on Home). Do not create a second worktree for a ticket, PR, or named branch that already has one \u2014 that call returns the live thread (alreadyStarted=true). Creating from the default branch still opens a new isolated worktree. Pass repoPath + parentThreadId; omit agent and model so Sideboard applies Settings \u2192 Default agent, model & effort (never pass your own agent or agent=cursor). If the repo has a setup script, Sideboard runs it in the background (does not block send_to_thread). Nested Codex (you are Codex and the child is Codex) deadlocks \u2014 omit agent; Sideboard coerces that case",
348
+ "- create_thread \u2014 create a worktree + chat from branch | pr | ticket (appears on Home). Do not create a second worktree for a ticket, PR, or named branch that already has one \u2014 that call returns the live thread (alreadyStarted=true). Creating from the default branch still opens a new isolated worktree. Pass repoPath + parentThreadId; omit agent and model so Sideboard applies Settings \u2192 Default agent, model & effort (never pass your own agent or agent=cursor). If the repo has a setup script, Sideboard runs it in the background (does not block send_to_thread). Nested Codex (you are Codex and the child would be Codex) can deadlock on ~/.codex locks \u2014 omit agent; Sideboard switches the child to Cursor when a CURSOR_API_KEY is set, otherwise keeps the Account default",
349
349
  "- start_board_card \u2014 same as create_thread for a ticket/PR/named branch (attaches issue text when resolvable). Then send_to_thread.",
350
350
  "- 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.",
351
351
  "- 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.",
@@ -360,9 +360,9 @@ var COORDINATOR_TOOL_PLAYBOOK = [
360
360
  "- get_diff \u2014 compact diff summary",
361
361
  "- get_pr_checks \u2014 snapshot of a worktree thread's PR checks (null = no PR). Use this to inspect status. If the user gave a goal, the worktree agent watches with `gh pr checks --watch` \u2014 do not poll for the human.",
362
362
  '- request_review \u2014 open a Review chat tab on a worktree thread (attaches .claude/skills/review/SKILL.md when present, else .context/review.md copied from .sideboard/review.md / stock; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id',
363
- "- ask_git \u2014 commit & push, open a draft PR, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If ask_git / get_thread lastError says the GraphQL/PR body is too long, the branch is already pushed \u2014 send_to_thread so the worktree agent runs `gh pr create --body-file` with a short description. Do not invent SSH or auth failures from that error. If the user gave a goal (Greptile 5/5, CI green), send_to_thread that goal so the worktree agent enters the watch-fix-push loop \u2014 do not tell the human to poll.",
363
+ "- ask_git \u2014 commit & push, open a draft PR, mark ready for review, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If ask_git / get_thread lastError says the GraphQL/PR body is too long, the branch is already pushed \u2014 send_to_thread so the worktree agent runs `gh pr create --body-file` with a short description. Do not invent SSH or auth failures from that error. If the user gave a goal (Greptile 5/5, CI green), send_to_thread that goal so the worktree agent enters the watch-fix-push loop \u2014 do not tell the human to poll.",
364
364
  '- Merge (`ask_git` action=merge / send_to_thread "Merge PR.") only when the user explicitly asked to merge that PR. Do not merge because the work looks done, CI is green, or a typical flow includes it.',
365
- '- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Merge the remote branch (main) into your branch and resolve conflicts. Then, commit and push your changes.", "Merge PR." (draft PRs: `gh pr create --draft -R <origin-owner/name>` using the workspace `github:` slug \u2014 never upstream). Never run git/gh from this orchestration cwd, and never merge the PR yourself.',
365
+ '- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Ready for review.", "Merge the remote branch (main) into your branch and resolve conflicts. Then, commit and push your changes.", "Merge PR." (draft PRs: `gh pr create --draft -R <origin-owner/name>` using the workspace `github:` slug \u2014 never upstream). Never run git/gh from this orchestration cwd, and never merge the PR yourself.',
366
366
  "Process guides:",
367
367
  "- Long child jobs (pack, test, deploy, anything that may run more than ~30s): workers always have `/long-running` (Sideboard product skill). Tell them to detach and wait; they may `stop_job` if it hangs or is doing the wrong thing; do not ask the human to poll.",
368
368
  "- Recurring multi-item / fan-out: if the child worktree has `.claude/skills/graph-engineering/SKILL.md`, tell the worker to follow it (`/graph-engineering`). Judge first; state on disk; grow the rulebook; do not patch three threads.",
@@ -487,7 +487,7 @@ function ensureGlobalCoordinatorCwd(opts) {
487
487
  "When creating threads, pass `repoPath` from `list_workspaces` (or the path you just registered).",
488
488
  orchId ? `Pass parentThreadId="${orchId}" (or omit it). Never invent another parentThreadId.` : "Pass `parentThreadId` for children (this chat's id from the turn reminder).",
489
489
  "Omit `agent` / `model` on `create_thread`. Sideboard applies Settings \u2192 Default agent, model & effort. Do not pass your own agent or `agent=cursor` \u2014 those are ignored.",
490
- "Never pass `agent=codex` when you yourself are Codex \u2014 nested Codex deadlocks on shared ~/.codex locks. Omit agent; Sideboard applies Account defaults (and coerces only that nested-Codex case).",
490
+ "Never pass `agent=codex` when you yourself are Codex \u2014 nested Codex can deadlock on shared ~/.codex locks. Omit agent; Sideboard applies Account defaults, and switches that nested-Codex case to Cursor only when a CURSOR_API_KEY is configured.",
491
491
  "Typical flow (Home board): list_board \u2192 create_thread (sourceType=ticket|pr|branch) \u2192 send_to_thread \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft \u2192 wait_for_turn. Merge only if the user explicitly asked (`ask_git` merge).",
492
492
  "Typical flow (branch / explicit source): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
493
493
  "Typical flow (find work): list_workspaces \u2192 pick repo(s) matching account / project context \u2192 Sideboard list_issues / linear_* (tickets) or list_prs(queue=review) (reviews) \u2192 show the options. Never wait on Claude Linear MCP. Only create_thread + send_to_thread when they asked to start (e.g. \u201Cfind me work and start it\u201D) \u2014 then wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
@@ -33,7 +33,7 @@ import {
33
33
  summarizeTurnStderr,
34
34
  toolDescription,
35
35
  turnFailChatText
36
- } from "./chunk-ZXHV3NHY.js";
36
+ } from "./chunk-W44EKPIR.js";
37
37
  import {
38
38
  extractPresentedPlan,
39
39
  readPlanFile,
@@ -64,7 +64,7 @@ import {
64
64
  stageAbsolutePathsAsAttachments,
65
65
  stageBuffersAsAttachments,
66
66
  syncWorkspacesFromThreads
67
- } from "./chunk-TNOLCU5B.js";
67
+ } from "./chunk-FJWQCZ74.js";
68
68
  import {
69
69
  addPrStackLayer,
70
70
  allocateTeamName,
@@ -401,7 +401,7 @@ async function continueSourceThread(threadId, prompt) {
401
401
  await continueOnReply(threadId, prompt);
402
402
  return;
403
403
  }
404
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-QSNGJ2ER.js");
404
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-2KZD7N4X.js");
405
405
  await getOrchestrator2().send(threadId, prompt);
406
406
  } catch {
407
407
  }
@@ -794,9 +794,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
794
794
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
795
795
  );
796
796
  }
797
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-WSQNEALF.js");
797
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-J737XNUX.js");
798
798
  if (isGlobalThread2(thread)) {
799
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-XCQCGUED.js");
799
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-BE2FERYE.js");
800
800
  ensureGlobalCoordinatorCwd2(
801
801
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
802
802
  );
@@ -991,6 +991,7 @@ var AGENT_GIT_ACTIONS = [
991
991
  "create-draft",
992
992
  "create-web",
993
993
  "resolve-conflicts",
994
+ "ready-for-review",
994
995
  "merge"
995
996
  ];
996
997
  function agentGitPrompt(action, opts) {
@@ -1006,6 +1007,8 @@ function agentGitPrompt(action, opts) {
1006
1007
  const named = base ? ` (${base})` : "";
1007
1008
  return `Merge the remote branch${named} into your branch and resolve conflicts. Then, commit and push your changes.`;
1008
1009
  }
1010
+ case "ready-for-review":
1011
+ return "Ready for review.";
1009
1012
  case "merge":
1010
1013
  return "Merge PR.";
1011
1014
  }
@@ -1021,6 +1024,8 @@ function gitActionExpansion(action, base) {
1021
1024
  return "Commit, push, then `gh pr create --web -R <origin-owner/name>`.";
1022
1025
  case "resolve-conflicts":
1023
1026
  return `Fetch the PR base${base ? ` (\`${base}\`)` : ""}, merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
1027
+ case "ready-for-review":
1028
+ return "This phrase is the explicit ask to mark this thread's draft pull request ready for review on GitHub (`gh pr ready -R <origin-owner/name>` or `gh pr ready`). Update title/body if the purpose drifted. Do not merge.";
1024
1029
  case "merge":
1025
1030
  return "This phrase is the explicit ask to merge this thread's open pull request on GitHub. If `gh stack view` shows a stack, use `gh stack merge`; otherwise `gh pr merge` (respect repo defaults / squash vs merge). Do not force-push main/master or merge locally into the main checkout.";
1026
1031
  }
@@ -4063,7 +4068,7 @@ async function adoptThread(input) {
4063
4068
  messages: input.messages ?? []
4064
4069
  });
4065
4070
  writeThread(thread);
4066
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-P66DGCZE.js");
4071
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-DR4UNOQC.js");
4067
4072
  await ensureWorkspace2(repoPath);
4068
4073
  const { ensureWorktreeSideboardIgnored: ensureWorktreeSideboardIgnored2 } = await import("./worktree-exclude-N5X5I422.js");
4069
4074
  await ensureWorktreeSideboardIgnored2(input.worktreePath);
@@ -5844,7 +5849,7 @@ function formatWorktreeDirective(thread, opts) {
5844
5849
  );
5845
5850
  }
5846
5851
  lines.push(
5847
- '- Sideboard git buttons send short phrases ("Commit and push.", "Merge PR.", \u2026) with their meaning attached \u2014 act on them without asking for clarification. If the user gives a goal (Greptile 5/5, CI green, until checks pass), you get the watch-fix-push playbook with that request.'
5852
+ '- Sideboard git buttons send short phrases ("Commit and push.", "Ready for review.", "Merge PR.", \u2026) with their meaning attached \u2014 act on them without asking for clarification. If the user gives a goal (Greptile 5/5, CI green, until checks pass), you get the watch-fix-push playbook with that request.'
5848
5853
  );
5849
5854
  lines.push("");
5850
5855
  lines.push(formatProcessGuideDirective({ worktreePath: thread.worktreePath }));
@@ -6339,7 +6344,7 @@ function formatScheduledPrompt(name, prompt) {
6339
6344
  ${prompt}`;
6340
6345
  }
6341
6346
  async function defaultDeps() {
6342
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-QSNGJ2ER.js");
6347
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-2KZD7N4X.js");
6343
6348
  const orch = getOrchestrator2();
6344
6349
  return {
6345
6350
  findThread: (id) => findThreadByRef(id),
@@ -8257,7 +8262,7 @@ var Orchestrator = class {
8257
8262
  "ask_git targets a worktree agent thread (not the orchestrator). Pass a child/worktree thread ref."
8258
8263
  );
8259
8264
  }
8260
- if (action === "merge" && !thread.prUrl) {
8265
+ if ((action === "merge" || action === "ready-for-review") && !thread.prUrl) {
8261
8266
  throw new Error(
8262
8267
  "No pull request linked. Ask the worktree agent to open a draft PR first (ask_git create-draft)."
8263
8268
  );
@@ -8425,7 +8430,7 @@ var Orchestrator = class {
8425
8430
  this.emit({ type: "status_changed", threadId: archived.id, status: "archived" });
8426
8431
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
8427
8432
  try {
8428
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-P66DGCZE.js");
8433
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-DR4UNOQC.js");
8429
8434
  await ensureWorkspace2(thread.repoPath);
8430
8435
  } catch {
8431
8436
  }
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  isOrchestratorThread
3
- } from "./chunk-NA7P3SZL.js";
3
+ } from "./chunk-3ZFGZ7RT.js";
4
4
  import {
5
5
  codexUnattendedGitConfigArgs,
6
6
  mergeAgentGitAuthEnv,
@@ -1898,7 +1898,7 @@ var claudeAdapter = {
1898
1898
  );
1899
1899
  }
1900
1900
  const mode = permissionMode(thread);
1901
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-KPROJ54C.js");
1901
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-3HIWNQ3B.js");
1902
1902
  const isOrchestrator = isOrchestratorThread2(thread);
1903
1903
  const injectedServers = await buildInjectedMcpServers({
1904
1904
  includeSideboard: true,
@@ -2684,6 +2684,9 @@ function resolveCursorApiKey() {
2684
2684
  if (fromEnv) return fromEnv;
2685
2685
  return (loadAppSettings().environment.CURSOR_API_KEY || "").trim();
2686
2686
  }
2687
+ function isCursorApiKeyConfigured() {
2688
+ return Boolean(resolveCursorApiKey());
2689
+ }
2687
2690
  function isCursorAutoModel(model) {
2688
2691
  const id = (model ?? "").trim().toLowerCase();
2689
2692
  return !id || id === "default" || id === "auto";
@@ -3700,6 +3703,7 @@ export {
3700
3703
  userMcpNamesToDisable,
3701
3704
  listCodexModels,
3702
3705
  codexAdapter,
3706
+ isCursorApiKeyConfigured,
3703
3707
  isCursorAutoModel,
3704
3708
  resolveCursorModelId,
3705
3709
  listCursorModels,
@@ -11,7 +11,7 @@ import {
11
11
  } from "./chunk-Y4MIXGPA.js";
12
12
  import {
13
13
  isOrchestratorThread
14
- } from "./chunk-TNOLCU5B.js";
14
+ } from "./chunk-FJWQCZ74.js";
15
15
  import {
16
16
  codexUnattendedGitConfigArgs,
17
17
  mergeAgentGitAuthEnv,
@@ -2342,7 +2342,7 @@ var claudeAdapter = {
2342
2342
  );
2343
2343
  }
2344
2344
  const mode = permissionMode(thread);
2345
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-WSQNEALF.js");
2345
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-J737XNUX.js");
2346
2346
  const isOrchestrator = isOrchestratorThread2(thread);
2347
2347
  const injectedServers = await buildInjectedMcpServers({
2348
2348
  includeSideboard: true,
@@ -3337,6 +3337,9 @@ function resolveCursorApiKey() {
3337
3337
  if (fromEnv) return fromEnv;
3338
3338
  return (loadAppSettings().environment.CURSOR_API_KEY || "").trim();
3339
3339
  }
3340
+ function isCursorApiKeyConfigured() {
3341
+ return Boolean(resolveCursorApiKey());
3342
+ }
3340
3343
  function isCursorAutoModel(model) {
3341
3344
  const id = (model ?? "").trim().toLowerCase();
3342
3345
  return !id || id === "default" || id === "auto";
@@ -4327,6 +4330,7 @@ export {
4327
4330
  turnCostUsdFromCursorUsage,
4328
4331
  cursorSdkMessageToEvents,
4329
4332
  parseCursorRunnerLine,
4333
+ isCursorApiKeyConfigured,
4330
4334
  isCursorAutoModel,
4331
4335
  resolveCursorModelId,
4332
4336
  listCursorModels,
@@ -9,7 +9,7 @@ import {
9
9
  enrichWorkspacesWithGithub,
10
10
  ensureGlobalCoordinatorCwd,
11
11
  formatWorkspaceInventory
12
- } from "./chunk-TNOLCU5B.js";
12
+ } from "./chunk-FJWQCZ74.js";
13
13
  import "./chunk-7O53GXTA.js";
14
14
  import "./chunk-D6JWYJ4P.js";
15
15
  import "./chunk-LZQULFIT.js";
@@ -7,7 +7,7 @@ import {
7
7
  enrichWorkspacesWithGithub,
8
8
  ensureGlobalCoordinatorCwd,
9
9
  formatWorkspaceInventory
10
- } from "./chunk-NA7P3SZL.js";
10
+ } from "./chunk-3ZFGZ7RT.js";
11
11
  import "./chunk-7JIYKYLL.js";
12
12
  import "./chunk-6K64FJDD.js";
13
13
  import "./chunk-J7LQVLFQ.js";
@@ -15,7 +15,7 @@ import {
15
15
  orchestratorSessionPoisonedByBuiltins,
16
16
  slackCoordinatorSourceRef,
17
17
  takenTeamSlugsForOrchestration
18
- } from "./chunk-NA7P3SZL.js";
18
+ } from "./chunk-3ZFGZ7RT.js";
19
19
  import "./chunk-7JIYKYLL.js";
20
20
  import "./chunk-6K64FJDD.js";
21
21
  import "./chunk-J7LQVLFQ.js";
@@ -17,7 +17,7 @@ import {
17
17
  orchestratorSessionPoisonedByBuiltins,
18
18
  slackCoordinatorSourceRef,
19
19
  takenTeamSlugsForOrchestration
20
- } from "./chunk-TNOLCU5B.js";
20
+ } from "./chunk-FJWQCZ74.js";
21
21
  import "./chunk-7O53GXTA.js";
22
22
  import "./chunk-D6JWYJ4P.js";
23
23
  import "./chunk-LZQULFIT.js";
package/dist/index.cjs CHANGED
@@ -7685,7 +7685,7 @@ function ensureGlobalCoordinatorCwd(opts) {
7685
7685
  "When creating threads, pass `repoPath` from `list_workspaces` (or the path you just registered).",
7686
7686
  orchId ? `Pass parentThreadId="${orchId}" (or omit it). Never invent another parentThreadId.` : "Pass `parentThreadId` for children (this chat's id from the turn reminder).",
7687
7687
  "Omit `agent` / `model` on `create_thread`. Sideboard applies Settings \u2192 Default agent, model & effort. Do not pass your own agent or `agent=cursor` \u2014 those are ignored.",
7688
- "Never pass `agent=codex` when you yourself are Codex \u2014 nested Codex deadlocks on shared ~/.codex locks. Omit agent; Sideboard applies Account defaults (and coerces only that nested-Codex case).",
7688
+ "Never pass `agent=codex` when you yourself are Codex \u2014 nested Codex can deadlock on shared ~/.codex locks. Omit agent; Sideboard applies Account defaults, and switches that nested-Codex case to Cursor only when a CURSOR_API_KEY is configured.",
7689
7689
  "Typical flow (Home board): list_board \u2192 create_thread (sourceType=ticket|pr|branch) \u2192 send_to_thread \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft \u2192 wait_for_turn. Merge only if the user explicitly asked (`ask_git` merge).",
7690
7690
  "Typical flow (branch / explicit source): list_workspaces \u2192 list_branches|list_prs|list_issues \u2192 create_thread \u2192 send_to_thread \u2192 wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
7691
7691
  "Typical flow (find work): list_workspaces \u2192 pick repo(s) matching account / project context \u2192 Sideboard list_issues / linear_* (tickets) or list_prs(queue=review) (reviews) \u2192 show the options. Never wait on Claude Linear MCP. Only create_thread + send_to_thread when they asked to start (e.g. \u201Cfind me work and start it\u201D) \u2014 then wait_for_turn (loop while stillRunning) \u2192 ask_git create-draft.",
@@ -7762,7 +7762,7 @@ var init_coordinator_prompt = __esm({
7762
7762
  "Workspaces:",
7763
7763
  "- add_workspace / remove_workspace \u2014 register or unregister a git repo",
7764
7764
  "Worktree threads (chats):",
7765
- "- create_thread \u2014 create a worktree + chat from branch | pr | ticket (appears on Home). Do not create a second worktree for a ticket, PR, or named branch that already has one \u2014 that call returns the live thread (alreadyStarted=true). Creating from the default branch still opens a new isolated worktree. Pass repoPath + parentThreadId; omit agent and model so Sideboard applies Settings \u2192 Default agent, model & effort (never pass your own agent or agent=cursor). If the repo has a setup script, Sideboard runs it in the background (does not block send_to_thread). Nested Codex (you are Codex and the child is Codex) deadlocks \u2014 omit agent; Sideboard coerces that case",
7765
+ "- create_thread \u2014 create a worktree + chat from branch | pr | ticket (appears on Home). Do not create a second worktree for a ticket, PR, or named branch that already has one \u2014 that call returns the live thread (alreadyStarted=true). Creating from the default branch still opens a new isolated worktree. Pass repoPath + parentThreadId; omit agent and model so Sideboard applies Settings \u2192 Default agent, model & effort (never pass your own agent or agent=cursor). If the repo has a setup script, Sideboard runs it in the background (does not block send_to_thread). Nested Codex (you are Codex and the child would be Codex) can deadlock on ~/.codex locks \u2014 omit agent; Sideboard switches the child to Cursor when a CURSOR_API_KEY is set, otherwise keeps the Account default",
7766
7766
  "- start_board_card \u2014 same as create_thread for a ticket/PR/named branch (attaches issue text when resolvable). Then send_to_thread.",
7767
7767
  "- 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.",
7768
7768
  "- 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.",
@@ -7777,9 +7777,9 @@ var init_coordinator_prompt = __esm({
7777
7777
  "- get_diff \u2014 compact diff summary",
7778
7778
  "- get_pr_checks \u2014 snapshot of a worktree thread's PR checks (null = no PR). Use this to inspect status. If the user gave a goal, the worktree agent watches with `gh pr checks --watch` \u2014 do not poll for the human.",
7779
7779
  '- request_review \u2014 open a Review chat tab on a worktree thread (attaches .claude/skills/review/SKILL.md when present, else .context/review.md copied from .sideboard/review.md / stock; sends "Review changes in this workspace."); then wait_for_turn (loop while stillRunning) / get_turn_result on the returned id',
7780
- "- ask_git \u2014 commit & push, open a draft PR, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If ask_git / get_thread lastError says the GraphQL/PR body is too long, the branch is already pushed \u2014 send_to_thread so the worktree agent runs `gh pr create --body-file` with a short description. Do not invent SSH or auth failures from that error. If the user gave a goal (Greptile 5/5, CI green), send_to_thread that goal so the worktree agent enters the watch-fix-push loop \u2014 do not tell the human to poll.",
7780
+ "- ask_git \u2014 commit & push, open a draft PR, mark ready for review, resolve conflicts, or merge. When the worktree is clean, Sideboard pushes / opens the PR itself. When dirty, it queues the worktree agent \u2014 then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If ask_git / get_thread lastError says the GraphQL/PR body is too long, the branch is already pushed \u2014 send_to_thread so the worktree agent runs `gh pr create --body-file` with a short description. Do not invent SSH or auth failures from that error. If the user gave a goal (Greptile 5/5, CI green), send_to_thread that goal so the worktree agent enters the watch-fix-push loop \u2014 do not tell the human to poll.",
7781
7781
  '- Merge (`ask_git` action=merge / send_to_thread "Merge PR.") only when the user explicitly asked to merge that PR. Do not merge because the work looks done, CI is green, or a typical flow includes it.',
7782
- '- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Merge the remote branch (main) into your branch and resolve conflicts. Then, commit and push your changes.", "Merge PR." (draft PRs: `gh pr create --draft -R <origin-owner/name>` using the workspace `github:` slug \u2014 never upstream). Never run git/gh from this orchestration cwd, and never merge the PR yourself.',
7782
+ '- Or send_to_thread with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Ready for review.", "Merge the remote branch (main) into your branch and resolve conflicts. Then, commit and push your changes.", "Merge PR." (draft PRs: `gh pr create --draft -R <origin-owner/name>` using the workspace `github:` slug \u2014 never upstream). Never run git/gh from this orchestration cwd, and never merge the PR yourself.',
7783
7783
  "Process guides:",
7784
7784
  "- Long child jobs (pack, test, deploy, anything that may run more than ~30s): workers always have `/long-running` (Sideboard product skill). Tell them to detach and wait; they may `stop_job` if it hangs or is doing the wrong thing; do not ask the human to poll.",
7785
7785
  "- Recurring multi-item / fan-out: if the child worktree has `.claude/skills/graph-engineering/SKILL.md`, tell the worker to follow it (`/graph-engineering`). Judge first; state on disk; grow the rulebook; do not patch three threads.",
@@ -12747,6 +12747,9 @@ function resolveCursorApiKey() {
12747
12747
  if (fromEnv) return fromEnv;
12748
12748
  return (loadAppSettings().environment.CURSOR_API_KEY || "").trim();
12749
12749
  }
12750
+ function isCursorApiKeyConfigured() {
12751
+ return Boolean(resolveCursorApiKey());
12752
+ }
12750
12753
  function isCursorAutoModel(model) {
12751
12754
  const id = (model ?? "").trim().toLowerCase();
12752
12755
  return !id || id === "default" || id === "auto";
@@ -13770,6 +13773,7 @@ __export(agents_exports, {
13770
13773
  installAgent: () => installAgent,
13771
13774
  installNpmGlobalPackage: () => installNpmGlobalPackage,
13772
13775
  isConductorBundledCli: () => isConductorBundledCli,
13776
+ isCursorApiKeyConfigured: () => isCursorApiKeyConfigured,
13773
13777
  isCursorAutoModel: () => isCursorAutoModel,
13774
13778
  isOrchestratorCapableAgent: () => isOrchestratorCapableAgent,
13775
13779
  isSessionQuotaLimit: () => isSessionQuotaLimit,
@@ -14208,6 +14212,8 @@ function agentGitPrompt(action, opts) {
14208
14212
  const named = base ? ` (${base})` : "";
14209
14213
  return `Merge the remote branch${named} into your branch and resolve conflicts. Then, commit and push your changes.`;
14210
14214
  }
14215
+ case "ready-for-review":
14216
+ return "Ready for review.";
14211
14217
  case "merge":
14212
14218
  return "Merge PR.";
14213
14219
  }
@@ -14222,6 +14228,8 @@ function gitActionExpansion(action, base) {
14222
14228
  return "Commit, push, then `gh pr create --web -R <origin-owner/name>`.";
14223
14229
  case "resolve-conflicts":
14224
14230
  return `Fetch the PR base${base ? ` (\`${base}\`)` : ""}, merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
14231
+ case "ready-for-review":
14232
+ return "This phrase is the explicit ask to mark this thread's draft pull request ready for review on GitHub (`gh pr ready -R <origin-owner/name>` or `gh pr ready`). Update title/body if the purpose drifted. Do not merge.";
14225
14233
  case "merge":
14226
14234
  return "This phrase is the explicit ask to merge this thread's open pull request on GitHub. If `gh stack view` shows a stack, use `gh stack merge`; otherwise `gh pr merge` (respect repo defaults / squash vs merge). Do not force-push main/master or merge locally into the main checkout.";
14227
14235
  }
@@ -14264,6 +14272,7 @@ var init_agent_git_actions = __esm({
14264
14272
  "create-draft",
14265
14273
  "create-web",
14266
14274
  "resolve-conflicts",
14275
+ "ready-for-review",
14267
14276
  "merge"
14268
14277
  ];
14269
14278
  RESOLVE_CONFLICTS_RE = /^Merge the remote branch(?: \(([^)]+)\))? into your branch and resolve conflicts\. Then, commit and push your changes\.$/;
@@ -19829,7 +19838,7 @@ function formatWorktreeDirective(thread, opts) {
19829
19838
  );
19830
19839
  }
19831
19840
  lines.push(
19832
- '- Sideboard git buttons send short phrases ("Commit and push.", "Merge PR.", \u2026) with their meaning attached \u2014 act on them without asking for clarification. If the user gives a goal (Greptile 5/5, CI green, until checks pass), you get the watch-fix-push playbook with that request.'
19841
+ '- Sideboard git buttons send short phrases ("Commit and push.", "Ready for review.", "Merge PR.", \u2026) with their meaning attached \u2014 act on them without asking for clarification. If the user gives a goal (Greptile 5/5, CI green, until checks pass), you get the watch-fix-push playbook with that request.'
19833
19842
  );
19834
19843
  lines.push("");
19835
19844
  lines.push(formatProcessGuideDirective({ worktreePath: thread.worktreePath }));
@@ -22473,7 +22482,7 @@ var init_orchestrator = __esm({
22473
22482
  "ask_git targets a worktree agent thread (not the orchestrator). Pass a child/worktree thread ref."
22474
22483
  );
22475
22484
  }
22476
- if (action === "merge" && !thread.prUrl) {
22485
+ if ((action === "merge" || action === "ready-for-review") && !thread.prUrl) {
22477
22486
  throw new Error(
22478
22487
  "No pull request linked. Ask the worktree agent to open a draft PR first (ask_git create-draft)."
22479
22488
  );
@@ -23288,6 +23297,7 @@ __export(index_exports, {
23288
23297
  isCloudCoordinatorThread: () => isCloudCoordinatorThread,
23289
23298
  isConductorBundledCli: () => isConductorBundledCli,
23290
23299
  isCowboyThread: () => isCowboyThread,
23300
+ isCursorApiKeyConfigured: () => isCursorApiKeyConfigured,
23291
23301
  isCursorAutoModel: () => isCursorAutoModel,
23292
23302
  isDefaultishSourceRef: () => isDefaultishSourceRef,
23293
23303
  isDesktopHostAlive: () => isDesktopHostAlive,
@@ -27192,11 +27202,13 @@ async function getHomeBoardInputs(workspaces, opts) {
27192
27202
  init_home_board();
27193
27203
 
27194
27204
  // src/mcp/create-thread-agent.ts
27205
+ init_cursor();
27195
27206
  function resolveOrchCreateThreadOptions(input) {
27196
27207
  const { resolveNewThreadOptions: resolveNewThreadOptions2 } = input;
27197
27208
  const account = resolveNewThreadOptions2({});
27198
27209
  const requested = input.requestedAgent;
27199
27210
  const parent = input.parentAgent ?? void 0;
27211
+ const cursorReady = input.cursorReady ?? isCursorApiKeyConfigured();
27200
27212
  let agent = account.agent;
27201
27213
  let ignoredAgent;
27202
27214
  let honorRequestedModel = false;
@@ -27211,7 +27223,7 @@ function resolveOrchCreateThreadOptions(input) {
27211
27223
  }
27212
27224
  }
27213
27225
  let coercedFrom;
27214
- if (agent === "codex" && parent === "codex") {
27226
+ if (agent === "codex" && parent === "codex" && cursorReady) {
27215
27227
  coercedFrom = requested ?? "codex";
27216
27228
  agent = "cursor";
27217
27229
  }
@@ -27227,7 +27239,7 @@ function resolveOrchCreateThreadOptions(input) {
27227
27239
  }
27228
27240
  function orchCreateThreadAgentNote(input) {
27229
27241
  if (input.coercedFrom) {
27230
- return `Avoid nested Codex under a Codex orchestrator \u2014 used Account default agent=${input.agent}`;
27242
+ return `Avoid nested Codex under a Codex orchestrator \u2014 used agent=${input.agent}`;
27231
27243
  }
27232
27244
  if (input.ignoredAgent) {
27233
27245
  return `Ignored agent=${input.ignoredAgent} \u2014 used Account default agent=${input.agent}`;
@@ -27997,11 +28009,11 @@ async function startMcpServer() {
27997
28009
  );
27998
28010
  server.tool(
27999
28011
  "ask_git",
28000
- "Commit & push, open a draft PR, resolve conflicts, or merge \u2014 same actions as the desktop git buttons. When the worktree is clean, Sideboard pushes / opens the PR itself (HTTPS via `gh` even when origin is SSH / Settings \u2192 Git is SSH). When dirty, queues the worktree agent to commit; then wait_for_turn (loop while stillRunning). Do not start a checks loop on a plain push \u2014 only if the user gave a goal (Greptile 5/5, CI green). Pass a worktree thread ref (not the orchestrator). action=merge only when the user explicitly asked to merge that PR. Do not run git or gh from the orchestration cwd. If this tool errors that the GraphQL/PR body is too long, the branch is already pushed \u2014 have the worktree agent retry `gh pr create --body-file` with a short description (GitHub limit 65,536 characters). Do not invent SSH/auth failures from that error.",
28012
+ "Commit & push, open a draft PR, mark ready for review, resolve conflicts, or merge \u2014 same actions as the desktop git buttons. When the worktree is clean, Sideboard pushes / opens the PR itself (HTTPS via `gh` even when origin is SSH / Settings \u2192 Git is SSH). When dirty, queues the worktree agent to commit; then wait_for_turn (loop while stillRunning). Do not start a checks loop on a plain push \u2014 only if the user gave a goal (Greptile 5/5, CI green). Pass a worktree thread ref (not the orchestrator). action=ready-for-review and action=merge only when the user explicitly asked (or clicked the desktop button). Do not run git or gh from the orchestration cwd. If this tool errors that the GraphQL/PR body is too long, the branch is already pushed \u2014 have the worktree agent retry `gh pr create --body-file` with a short description (GitHub limit 65,536 characters). Do not invent SSH/auth failures from that error.",
28001
28013
  {
28002
28014
  ref: import_zod8.z.string().describe("Worktree thread id/ref"),
28003
28015
  action: import_zod8.z.enum(AGENT_GIT_ACTIONS).describe(
28004
- "commit-push | create-draft | create-web | resolve-conflicts | merge"
28016
+ "commit-push | create-draft | create-web | resolve-conflicts | ready-for-review | merge"
28005
28017
  )
28006
28018
  },
28007
28019
  async ({ ref, action }) => {
@@ -31063,6 +31075,7 @@ init_outbound_watch();
31063
31075
  isCloudCoordinatorThread,
31064
31076
  isConductorBundledCli,
31065
31077
  isCowboyThread,
31078
+ isCursorApiKeyConfigured,
31066
31079
  isCursorAutoModel,
31067
31080
  isDefaultishSourceRef,
31068
31081
  isDesktopHostAlive,