@sideboard-ai/core 0.1.270 → 0.1.271

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 (25) hide show
  1. package/dist/{agents-G3JTULM2.js → agents-LAFFXBBZ.js} +2 -2
  2. package/dist/{agents-XRXJCAWJ.js → agents-ZCO37SKG.js} +2 -2
  3. package/dist/{chunk-GZXKUUJO.js → chunk-2QUILREI.js} +1 -1
  4. package/dist/{chunk-3VBS6MES.js → chunk-ADWNK2JH.js} +2 -2
  5. package/dist/{chunk-HSRN2CSL.js → chunk-BNIGN5JX.js} +44 -14
  6. package/dist/{chunk-2XIRV7FS.js → chunk-JLDJGGCL.js} +2 -2
  7. package/dist/{chunk-X7RP3TQB.js → chunk-M7626KJO.js} +2 -2
  8. package/dist/{chunk-DB7MVDYS.js → chunk-PTNGMA5C.js} +1 -1
  9. package/dist/{chunk-4ECDIKAS.js → chunk-RQR25LUB.js} +2 -2
  10. package/dist/{chunk-ZSGSVFWD.js → chunk-VC24GQN4.js} +45 -15
  11. package/dist/{conductor-NRKTEN5X.js → conductor-JA3A4NAI.js} +2 -2
  12. package/dist/{conductor-MLM5NGTP.js → conductor-POUIKR5A.js} +2 -2
  13. package/dist/{coordinator-prompt-BKRQDZFT.js → coordinator-prompt-4KVA6XUX.js} +1 -1
  14. package/dist/{coordinator-prompt-4GHKCVRH.js → coordinator-prompt-MVUHFNSC.js} +1 -1
  15. package/dist/{global-workspace-EEWJOMED.js → global-workspace-34Z2IWYQ.js} +1 -1
  16. package/dist/{global-workspace-EWFL4HPW.js → global-workspace-FR7QTLPK.js} +1 -1
  17. package/dist/index.cjs +51 -10
  18. package/dist/index.js +19 -8
  19. package/dist/mcp/run-stdio.cjs +38 -8
  20. package/dist/mcp/run-stdio.js +4 -4
  21. package/dist/{orchestrator-6ZQ2CYS4.js → orchestrator-OPWMDMTK.js} +4 -4
  22. package/dist/{orchestrator-MA3MHYIM.js → orchestrator-VDNZQIGA.js} +4 -4
  23. package/dist/{workspaces-F33Z4CEY.js → workspaces-2JBDUMM6.js} +1 -1
  24. package/dist/{workspaces-SLP24Z3S.js → workspaces-5GERYHDJ.js} +1 -1
  25. package/package.json +1 -1
@@ -47,10 +47,10 @@ import {
47
47
  resolveLoginCommand,
48
48
  resolveQuotaFallbackAgent,
49
49
  whichOnPath
50
- } from "./chunk-3VBS6MES.js";
50
+ } from "./chunk-ADWNK2JH.js";
51
51
  import "./chunk-GWFVCCJZ.js";
52
52
  import "./chunk-FAGK33E2.js";
53
- import "./chunk-DB7MVDYS.js";
53
+ import "./chunk-PTNGMA5C.js";
54
54
  import "./chunk-USBZ7PH4.js";
55
55
  import "./chunk-FWNL62VA.js";
56
56
  import "./chunk-2P4XKWV2.js";
@@ -56,12 +56,12 @@ import {
56
56
  resolveQuotaFallbackAgent,
57
57
  turnCostUsdFromCursorUsage,
58
58
  whichOnPath
59
- } from "./chunk-2XIRV7FS.js";
59
+ } from "./chunk-JLDJGGCL.js";
60
60
  import "./chunk-TQRSVE7D.js";
61
61
  import "./chunk-P2BSMNHB.js";
62
62
  import "./chunk-VKQGAWHY.js";
63
63
  import "./chunk-UKSJO36E.js";
64
- import "./chunk-GZXKUUJO.js";
64
+ import "./chunk-2QUILREI.js";
65
65
  import "./chunk-NWE3NOWQ.js";
66
66
  import "./chunk-N2WW62LF.js";
67
67
  import "./chunk-DD67JWTN.js";
@@ -373,7 +373,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
373
373
  '- request_review \u2014 run a Review on a worktree thread. Reuses the only unused idle agent when the checkout has a single chat with no messages; otherwise opens a Review tab (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. The review stays in that chat so they can read it and type next steps \u2014 do not tell the child to comment or update the PR or ticket.',
374
374
  "- ask_git \u2014 commit & push, open a draft PR, mark ready for review, resolve conflicts, or merge \u2014 same prompts as the desktop git buttons (Resolve, Create PR, \u2026). Always steers the worktree agent; then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If the user gave a goal (Greptile 5/5, CI green), send_to_chat that goal so the worktree agent enters the watch-fix-push loop \u2014 do not tell the human to poll.",
375
375
  '- Merge (`ask_git` action=merge / send_to_chat "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.',
376
- '- Or send_to_chat 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 --assignee @me -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.',
376
+ '- Or send_to_chat with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Ready for review.", "Merge PR." Prefer ask_git resolve-conflicts (it names the actual PR base \u2014 not always main) over paraphrasing. (draft PRs: `gh pr create --draft --assignee @me -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.',
377
377
  "Process guides:",
378
378
  "- 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.",
379
379
  "- 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.",
@@ -12,7 +12,7 @@ import {
12
12
  } from "./chunk-FAGK33E2.js";
13
13
  import {
14
14
  isOrchestratorThread
15
- } from "./chunk-DB7MVDYS.js";
15
+ } from "./chunk-PTNGMA5C.js";
16
16
  import {
17
17
  codexUnattendedGitConfigArgs,
18
18
  mergeAgentGitAuthEnv,
@@ -1745,7 +1745,7 @@ var claudeAdapter = {
1745
1745
  );
1746
1746
  }
1747
1747
  const mode = permissionMode(thread);
1748
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-EEWJOMED.js");
1748
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-34Z2IWYQ.js");
1749
1749
  const isOrchestrator = isOrchestratorThread2(thread);
1750
1750
  const rpc = worktreeAgentRpc(isOrchestrator);
1751
1751
  const injectedServers = await buildInjectedMcpServers({
@@ -21,7 +21,7 @@ import {
21
21
  parseSessionQuotaResetAt,
22
22
  planModeTurnInstruction,
23
23
  resolveQuotaFallbackAgent
24
- } from "./chunk-2XIRV7FS.js";
24
+ } from "./chunk-JLDJGGCL.js";
25
25
  import {
26
26
  REVIEW_TAB_TITLE,
27
27
  applyWorktreePkgCacheEnv,
@@ -58,7 +58,7 @@ import {
58
58
  worktreeDevProcessKey,
59
59
  worktreeRunProcessKey,
60
60
  worktreeSetupProcessKey
61
- } from "./chunk-4ECDIKAS.js";
61
+ } from "./chunk-RQR25LUB.js";
62
62
  import {
63
63
  applyAgentEvent,
64
64
  clipAgentEventForPaint,
@@ -105,7 +105,7 @@ import {
105
105
  stageAbsolutePathsAsAttachments,
106
106
  stageBuffersAsAttachments,
107
107
  syncWorkspacesFromThreads
108
- } from "./chunk-GZXKUUJO.js";
108
+ } from "./chunk-2QUILREI.js";
109
109
  import {
110
110
  addPrStackLayer,
111
111
  agentNicknameFromWorktreePath,
@@ -485,9 +485,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
485
485
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
486
486
  );
487
487
  }
488
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-EWFL4HPW.js");
488
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-FR7QTLPK.js");
489
489
  if (isGlobalThread2(thread)) {
490
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-4GHKCVRH.js");
490
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-MVUHFNSC.js");
491
491
  ensureGlobalCoordinatorCwd2(
492
492
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
493
493
  );
@@ -655,6 +655,14 @@ var AGENT_GIT_ACTIONS = [
655
655
  "ready-for-review",
656
656
  "merge"
657
657
  ];
658
+ function namedPrBase(prBase) {
659
+ const base = prBase?.trim().replace(/^refs\/heads\//, "").replace(/^origin\//, "");
660
+ return base || null;
661
+ }
662
+ function isMainishPrBase(base) {
663
+ const n = base.toLowerCase();
664
+ return n === "main" || n === "master";
665
+ }
658
666
  function agentGitPrompt(action, opts) {
659
667
  switch (action) {
660
668
  case "commit-push":
@@ -664,14 +672,19 @@ function agentGitPrompt(action, opts) {
664
672
  case "create-web":
665
673
  return "Commit, push, and open a PR in the browser.";
666
674
  case "resolve-conflicts": {
667
- const base = opts?.prBase?.trim().replace(/^refs\/heads\//, "");
675
+ const base = namedPrBase(opts?.prBase);
668
676
  const named = base ? ` (${base})` : "";
669
677
  return `Merge the remote branch${named} into your branch and resolve conflicts. Then, commit and push your changes.`;
670
678
  }
671
679
  case "ready-for-review":
672
680
  return "Ready for review.";
673
- case "merge":
681
+ case "merge": {
682
+ const base = namedPrBase(opts?.prBase);
683
+ if (base && !isMainishPrBase(base)) {
684
+ return `Merge PR into ${base}.`;
685
+ }
674
686
  return "Merge PR.";
687
+ }
675
688
  }
676
689
  }
677
690
  function resolveSidebarGitPrompt(action, opts) {
@@ -688,6 +701,7 @@ function resolveSidebarGitPrompt(action, opts) {
688
701
  return agentGitPrompt(action, opts);
689
702
  }
690
703
  var RESOLVE_CONFLICTS_RE = /^Merge the remote branch(?: \(([^)]+)\))? into your branch and resolve conflicts\. Then, commit and push your changes\.$/;
704
+ var MERGE_INTO_RE = /^Merge PR into (.+)\.$/;
691
705
  function gitActionExpansion(action, base) {
692
706
  switch (action) {
693
707
  case "commit-push":
@@ -697,10 +711,19 @@ function gitActionExpansion(action, base) {
697
711
  case "create-web":
698
712
  return "Commit, push, then `gh pr create --web --assignee @me -R <origin-owner/name>`. Use a different `--assignee` only if the user named someone else.";
699
713
  case "resolve-conflicts":
700
- return `Fetch the PR base${base ? ` (\`${base}\`)` : ""}, merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
714
+ if (base && !isMainishPrBase(base)) {
715
+ return `Fetch \`origin/${base}\` (this PR's base \u2014 not main/master), merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable. Do not merge origin/main.`;
716
+ }
717
+ if (base) {
718
+ return `Fetch the PR base (\`${base}\`), merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
719
+ }
720
+ return "Look up this PR's base with `gh pr view --json baseRefName` and merge that remote branch into this branch (do not assume main). Resolve conflicts carefully, then commit and push until the PR is mergeable.";
701
721
  case "ready-for-review":
702
722
  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.";
703
723
  case "merge":
724
+ if (base && !isMainishPrBase(base)) {
725
+ return `This phrase is the explicit ask to merge this thread's open pull request into \`${base}\` on GitHub with \`gh pr merge\` (respect repo defaults / squash vs merge). This PR targets \`${base}\`, not main \u2014 do not use \`gh stack merge\` and do not retarget or merge into main/master. Do not force-push main/master or merge locally into the main checkout.`;
726
+ }
704
727
  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.";
705
728
  }
706
729
  }
@@ -722,6 +745,13 @@ function expandCanonicalGitRequest(prompt) {
722
745
  base = m[1] ?? null;
723
746
  }
724
747
  }
748
+ if (!action) {
749
+ const m = MERGE_INTO_RE.exec(trimmed);
750
+ if (m) {
751
+ action = "merge";
752
+ base = m[1]?.trim() || null;
753
+ }
754
+ }
725
755
  let expansion = action ? gitActionExpansion(action, base) : null;
726
756
  if (!expansion && trimmed === "Address review comments.") {
727
757
  expansion = "Read the PR review feedback (`gh pr view --comments`, `gh api` review comments), make the requested changes, commit, and push.";
@@ -2750,7 +2780,7 @@ async function adoptThread(input) {
2750
2780
  messages: input.messages ?? []
2751
2781
  });
2752
2782
  writeThread(thread);
2753
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-SLP24Z3S.js");
2783
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-5GERYHDJ.js");
2754
2784
  await ensureWorkspace2(repoPath);
2755
2785
  const { ensureWorktreeSideboardIgnored } = await import("./worktree-exclude-5N2KTYIT.js");
2756
2786
  await ensureWorktreeSideboardIgnored(input.worktreePath);
@@ -5237,7 +5267,7 @@ function formatScheduledPrompt(name, prompt) {
5237
5267
  ${prompt}`;
5238
5268
  }
5239
5269
  async function defaultDeps() {
5240
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-MA3MHYIM.js");
5270
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-VDNZQIGA.js");
5241
5271
  const orch = getOrchestrator2();
5242
5272
  return {
5243
5273
  findThread: (id) => findThreadByRef(id),
@@ -7779,10 +7809,10 @@ var Orchestrator = class {
7779
7809
  );
7780
7810
  }
7781
7811
  let prBase;
7782
- if (action === "resolve-conflicts") {
7812
+ if (action === "resolve-conflicts" || action === "merge") {
7783
7813
  try {
7784
- const details = await this.getPrDetails(threadRef);
7785
- prBase = details?.baseRefName?.trim() || void 0;
7814
+ const meta = await this.getPrMeta(threadRef);
7815
+ prBase = meta?.baseRefName?.trim() || void 0;
7786
7816
  } catch {
7787
7817
  }
7788
7818
  }
@@ -7924,7 +7954,7 @@ var Orchestrator = class {
7924
7954
  this.enforceHistoryRetention();
7925
7955
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
7926
7956
  try {
7927
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-SLP24Z3S.js");
7957
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-5GERYHDJ.js");
7928
7958
  await ensureWorkspace2(thread.repoPath);
7929
7959
  } catch {
7930
7960
  }
@@ -24,7 +24,7 @@ import {
24
24
  } from "./chunk-UKSJO36E.js";
25
25
  import {
26
26
  isOrchestratorThread
27
- } from "./chunk-GZXKUUJO.js";
27
+ } from "./chunk-2QUILREI.js";
28
28
  import {
29
29
  codexUnattendedGitConfigArgs,
30
30
  mergeAgentGitAuthEnv,
@@ -2010,7 +2010,7 @@ var claudeAdapter = {
2010
2010
  );
2011
2011
  }
2012
2012
  const mode = permissionMode(thread);
2013
- const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-EWFL4HPW.js");
2013
+ const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-FR7QTLPK.js");
2014
2014
  const isOrchestrator = isOrchestratorThread2(thread);
2015
2015
  const rpc = worktreeAgentRpc(isOrchestrator);
2016
2016
  const injectedServers = await buildInjectedMcpServers({
@@ -8,7 +8,7 @@ import {
8
8
  isGlobalThread,
9
9
  isOrchestratorThread,
10
10
  isSlackCoordinatorThread
11
- } from "./chunk-DB7MVDYS.js";
11
+ } from "./chunk-PTNGMA5C.js";
12
12
  import {
13
13
  allocateTeamName,
14
14
  mergeAgentGitAuthEnv,
@@ -1628,7 +1628,7 @@ var PORT_RANGE_SIZE = 10;
1628
1628
  var RECLAIM_RETRY_DELAY_MS = 40;
1629
1629
  var RECLAIM_TRIES = 8;
1630
1630
  async function killReclaimable(ports, worktreePath, signal) {
1631
- const { killListenersOnPorts: killListenersOnPorts2, killStaleWorktreeListeners: killStaleWorktreeListeners2 } = await import("./conductor-MLM5NGTP.js");
1631
+ const { killListenersOnPorts: killListenersOnPorts2, killStaleWorktreeListeners: killStaleWorktreeListeners2 } = await import("./conductor-POUIKR5A.js");
1632
1632
  if (worktreePath) killStaleWorktreeListeners2(ports, worktreePath, signal);
1633
1633
  else killListenersOnPorts2(ports);
1634
1634
  }
@@ -418,7 +418,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
418
418
  '- request_review \u2014 run a Review on a worktree thread. Reuses the only unused idle agent when the checkout has a single chat with no messages; otherwise opens a Review tab (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. The review stays in that chat so they can read it and type next steps \u2014 do not tell the child to comment or update the PR or ticket.',
419
419
  "- ask_git \u2014 commit & push, open a draft PR, mark ready for review, resolve conflicts, or merge \u2014 same prompts as the desktop git buttons (Resolve, Create PR, \u2026). Always steers the worktree agent; then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If the user gave a goal (Greptile 5/5, CI green), send_to_chat that goal so the worktree agent enters the watch-fix-push loop \u2014 do not tell the human to poll.",
420
420
  '- Merge (`ask_git` action=merge / send_to_chat "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.',
421
- '- Or send_to_chat 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 --assignee @me -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.',
421
+ '- Or send_to_chat with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Ready for review.", "Merge PR." Prefer ask_git resolve-conflicts (it names the actual PR base \u2014 not always main) over paraphrasing. (draft PRs: `gh pr create --draft --assignee @me -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.',
422
422
  "Process guides:",
423
423
  "- 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.",
424
424
  "- 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.",
@@ -11,7 +11,7 @@ import {
11
11
  isGlobalThread,
12
12
  isOrchestratorThread,
13
13
  isSlackCoordinatorThread
14
- } from "./chunk-GZXKUUJO.js";
14
+ } from "./chunk-2QUILREI.js";
15
15
  import {
16
16
  allocateTeamName,
17
17
  mergeAgentGitAuthEnv,
@@ -1572,7 +1572,7 @@ var PORT_RANGE_SIZE = 10;
1572
1572
  var RECLAIM_RETRY_DELAY_MS = 40;
1573
1573
  var RECLAIM_TRIES = 8;
1574
1574
  async function killReclaimable(ports, worktreePath, signal) {
1575
- const { killListenersOnPorts: killListenersOnPorts2, killStaleWorktreeListeners: killStaleWorktreeListeners2 } = await import("./conductor-NRKTEN5X.js");
1575
+ const { killListenersOnPorts: killListenersOnPorts2, killStaleWorktreeListeners: killStaleWorktreeListeners2 } = await import("./conductor-JA3A4NAI.js");
1576
1576
  if (worktreePath) killStaleWorktreeListeners2(ports, worktreePath, signal);
1577
1577
  else killListenersOnPorts2(ports);
1578
1578
  }
@@ -7,7 +7,7 @@ import {
7
7
  parseSessionQuotaResetAt,
8
8
  planModeTurnInstruction,
9
9
  resolveQuotaFallbackAgent
10
- } from "./chunk-3VBS6MES.js";
10
+ } from "./chunk-ADWNK2JH.js";
11
11
  import {
12
12
  REVIEW_TAB_TITLE,
13
13
  applyWorktreePkgCacheEnv,
@@ -44,7 +44,7 @@ import {
44
44
  worktreeDevProcessKey,
45
45
  worktreeRunProcessKey,
46
46
  worktreeSetupProcessKey
47
- } from "./chunk-X7RP3TQB.js";
47
+ } from "./chunk-M7626KJO.js";
48
48
  import {
49
49
  applyAgentEvent,
50
50
  clipAgentEventForPaint,
@@ -88,7 +88,7 @@ import {
88
88
  stageAbsolutePathsAsAttachments,
89
89
  stageBuffersAsAttachments,
90
90
  syncWorkspacesFromThreads
91
- } from "./chunk-DB7MVDYS.js";
91
+ } from "./chunk-PTNGMA5C.js";
92
92
  import {
93
93
  addPrStackLayer,
94
94
  agentNicknameFromWorktreePath,
@@ -437,9 +437,9 @@ async function spawnAgentTurn(thread, input, onEvent) {
437
437
  `Cannot spawn ${thread.agent}: thread ${thread.id} has no worktreePath`
438
438
  );
439
439
  }
440
- const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-EEWJOMED.js");
440
+ const { isGlobalThread: isGlobalThread2 } = await import("./global-workspace-34Z2IWYQ.js");
441
441
  if (isGlobalThread2(thread)) {
442
- const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-BKRQDZFT.js");
442
+ const { ensureGlobalCoordinatorCwd: ensureGlobalCoordinatorCwd2 } = await import("./coordinator-prompt-4KVA6XUX.js");
443
443
  ensureGlobalCoordinatorCwd2(
444
444
  isOrchestratorThread(thread) ? { orchestratorThreadId: thread.id } : void 0
445
445
  );
@@ -607,6 +607,14 @@ var AGENT_GIT_ACTIONS = [
607
607
  "ready-for-review",
608
608
  "merge"
609
609
  ];
610
+ function namedPrBase(prBase) {
611
+ const base = prBase?.trim().replace(/^refs\/heads\//, "").replace(/^origin\//, "");
612
+ return base || null;
613
+ }
614
+ function isMainishPrBase(base) {
615
+ const n = base.toLowerCase();
616
+ return n === "main" || n === "master";
617
+ }
610
618
  function agentGitPrompt(action, opts) {
611
619
  switch (action) {
612
620
  case "commit-push":
@@ -616,14 +624,19 @@ function agentGitPrompt(action, opts) {
616
624
  case "create-web":
617
625
  return "Commit, push, and open a PR in the browser.";
618
626
  case "resolve-conflicts": {
619
- const base = opts?.prBase?.trim().replace(/^refs\/heads\//, "");
627
+ const base = namedPrBase(opts?.prBase);
620
628
  const named = base ? ` (${base})` : "";
621
629
  return `Merge the remote branch${named} into your branch and resolve conflicts. Then, commit and push your changes.`;
622
630
  }
623
631
  case "ready-for-review":
624
632
  return "Ready for review.";
625
- case "merge":
633
+ case "merge": {
634
+ const base = namedPrBase(opts?.prBase);
635
+ if (base && !isMainishPrBase(base)) {
636
+ return `Merge PR into ${base}.`;
637
+ }
626
638
  return "Merge PR.";
639
+ }
627
640
  }
628
641
  }
629
642
  function resolveSidebarGitPrompt(action, opts) {
@@ -640,6 +653,7 @@ function resolveSidebarGitPrompt(action, opts) {
640
653
  return agentGitPrompt(action, opts);
641
654
  }
642
655
  var RESOLVE_CONFLICTS_RE = /^Merge the remote branch(?: \(([^)]+)\))? into your branch and resolve conflicts\. Then, commit and push your changes\.$/;
656
+ var MERGE_INTO_RE = /^Merge PR into (.+)\.$/;
643
657
  function gitActionExpansion(action, base) {
644
658
  switch (action) {
645
659
  case "commit-push":
@@ -649,10 +663,19 @@ function gitActionExpansion(action, base) {
649
663
  case "create-web":
650
664
  return "Commit, push, then `gh pr create --web --assignee @me -R <origin-owner/name>`. Use a different `--assignee` only if the user named someone else.";
651
665
  case "resolve-conflicts":
652
- return `Fetch the PR base${base ? ` (\`${base}\`)` : ""}, merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
666
+ if (base && !isMainishPrBase(base)) {
667
+ return `Fetch \`origin/${base}\` (this PR's base \u2014 not main/master), merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable. Do not merge origin/main.`;
668
+ }
669
+ if (base) {
670
+ return `Fetch the PR base (\`${base}\`), merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
671
+ }
672
+ return "Look up this PR's base with `gh pr view --json baseRefName` and merge that remote branch into this branch (do not assume main). Resolve conflicts carefully, then commit and push until the PR is mergeable.";
653
673
  case "ready-for-review":
654
674
  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.";
655
675
  case "merge":
676
+ if (base && !isMainishPrBase(base)) {
677
+ return `This phrase is the explicit ask to merge this thread's open pull request into \`${base}\` on GitHub with \`gh pr merge\` (respect repo defaults / squash vs merge). This PR targets \`${base}\`, not main \u2014 do not use \`gh stack merge\` and do not retarget or merge into main/master. Do not force-push main/master or merge locally into the main checkout.`;
678
+ }
656
679
  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.";
657
680
  }
658
681
  }
@@ -674,6 +697,13 @@ function expandCanonicalGitRequest(prompt) {
674
697
  base = m[1] ?? null;
675
698
  }
676
699
  }
700
+ if (!action) {
701
+ const m = MERGE_INTO_RE.exec(trimmed);
702
+ if (m) {
703
+ action = "merge";
704
+ base = m[1]?.trim() || null;
705
+ }
706
+ }
677
707
  let expansion = action ? gitActionExpansion(action, base) : null;
678
708
  if (!expansion && trimmed === "Address review comments.") {
679
709
  expansion = "Read the PR review feedback (`gh pr view --comments`, `gh api` review comments), make the requested changes, commit, and push.";
@@ -2376,7 +2406,7 @@ async function createThread(input, _onSetupLine) {
2376
2406
  return readThread(thread.id) ?? thread;
2377
2407
  }
2378
2408
  async function listLinearIssues(agent, repoPath) {
2379
- const { getAdapter: getAdapter2 } = await import("./agents-G3JTULM2.js");
2409
+ const { getAdapter: getAdapter2 } = await import("./agents-LAFFXBBZ.js");
2380
2410
  await requireAgent(agent, { requireLinear: true });
2381
2411
  const adapter = getAdapter2(agent);
2382
2412
  if (!adapter.listLinearIssues) {
@@ -2883,7 +2913,7 @@ async function adoptThread(input) {
2883
2913
  messages: input.messages ?? []
2884
2914
  });
2885
2915
  writeThread(thread);
2886
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-F33Z4CEY.js");
2916
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-2JBDUMM6.js");
2887
2917
  await ensureWorkspace2(repoPath);
2888
2918
  const { ensureWorktreeSideboardIgnored } = await import("./worktree-exclude-RXZPTCNH.js");
2889
2919
  await ensureWorktreeSideboardIgnored(input.worktreePath);
@@ -5576,7 +5606,7 @@ function formatScheduledPrompt(name, prompt) {
5576
5606
  ${prompt}`;
5577
5607
  }
5578
5608
  async function defaultDeps() {
5579
- const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-6ZQ2CYS4.js");
5609
+ const { getOrchestrator: getOrchestrator2, startOrchestration: startOrchestration2 } = await import("./orchestrator-OPWMDMTK.js");
5580
5610
  const orch = getOrchestrator2();
5581
5611
  return {
5582
5612
  findThread: (id) => findThreadByRef(id),
@@ -8118,10 +8148,10 @@ var Orchestrator = class {
8118
8148
  );
8119
8149
  }
8120
8150
  let prBase;
8121
- if (action === "resolve-conflicts") {
8151
+ if (action === "resolve-conflicts" || action === "merge") {
8122
8152
  try {
8123
- const details = await this.getPrDetails(threadRef);
8124
- prBase = details?.baseRefName?.trim() || void 0;
8153
+ const meta = await this.getPrMeta(threadRef);
8154
+ prBase = meta?.baseRefName?.trim() || void 0;
8125
8155
  } catch {
8126
8156
  }
8127
8157
  }
@@ -8263,7 +8293,7 @@ var Orchestrator = class {
8263
8293
  this.enforceHistoryRetention();
8264
8294
  if (thread.repoPath && !isGlobalRepoPath(thread.repoPath)) {
8265
8295
  try {
8266
- const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-F33Z4CEY.js");
8296
+ const { ensureWorkspace: ensureWorkspace2 } = await import("./workspaces-2JBDUMM6.js");
8267
8297
  await ensureWorkspace2(thread.repoPath);
8268
8298
  } catch {
8269
8299
  }
@@ -33,9 +33,9 @@ import {
33
33
  tryReservePort,
34
34
  tryReservePorts,
35
35
  worktreeRunPortsPath
36
- } from "./chunk-4ECDIKAS.js";
36
+ } from "./chunk-RQR25LUB.js";
37
37
  import "./chunk-UKSJO36E.js";
38
- import "./chunk-GZXKUUJO.js";
38
+ import "./chunk-2QUILREI.js";
39
39
  import "./chunk-NWE3NOWQ.js";
40
40
  import "./chunk-N2WW62LF.js";
41
41
  import "./chunk-DD67JWTN.js";
@@ -31,9 +31,9 @@ import {
31
31
  tryReservePort,
32
32
  tryReservePorts,
33
33
  worktreeRunPortsPath
34
- } from "./chunk-X7RP3TQB.js";
34
+ } from "./chunk-M7626KJO.js";
35
35
  import "./chunk-FAGK33E2.js";
36
- import "./chunk-DB7MVDYS.js";
36
+ import "./chunk-PTNGMA5C.js";
37
37
  import "./chunk-USBZ7PH4.js";
38
38
  import "./chunk-FWNL62VA.js";
39
39
  import "./chunk-2P4XKWV2.js";
@@ -7,7 +7,7 @@ import {
7
7
  enrichWorkspacesWithGithub,
8
8
  ensureGlobalCoordinatorCwd,
9
9
  formatWorkspaceInventory
10
- } from "./chunk-DB7MVDYS.js";
10
+ } from "./chunk-PTNGMA5C.js";
11
11
  import "./chunk-USBZ7PH4.js";
12
12
  import "./chunk-FWNL62VA.js";
13
13
  import "./chunk-2P4XKWV2.js";
@@ -9,7 +9,7 @@ import {
9
9
  enrichWorkspacesWithGithub,
10
10
  ensureGlobalCoordinatorCwd,
11
11
  formatWorkspaceInventory
12
- } from "./chunk-GZXKUUJO.js";
12
+ } from "./chunk-2QUILREI.js";
13
13
  import "./chunk-NWE3NOWQ.js";
14
14
  import "./chunk-N2WW62LF.js";
15
15
  import "./chunk-DD67JWTN.js";
@@ -18,7 +18,7 @@ import {
18
18
  remoteCoordinatorSourceRef,
19
19
  slackCoordinatorSourceRef,
20
20
  takenTeamSlugsForOrchestration
21
- } from "./chunk-DB7MVDYS.js";
21
+ } from "./chunk-PTNGMA5C.js";
22
22
  import "./chunk-USBZ7PH4.js";
23
23
  import "./chunk-FWNL62VA.js";
24
24
  import "./chunk-2P4XKWV2.js";
@@ -20,7 +20,7 @@ import {
20
20
  remoteCoordinatorSourceRef,
21
21
  slackCoordinatorSourceRef,
22
22
  takenTeamSlugsForOrchestration
23
- } from "./chunk-GZXKUUJO.js";
23
+ } from "./chunk-2QUILREI.js";
24
24
  import "./chunk-NWE3NOWQ.js";
25
25
  import "./chunk-N2WW62LF.js";
26
26
  import "./chunk-DD67JWTN.js";
package/dist/index.cjs CHANGED
@@ -11423,7 +11423,7 @@ var init_coordinator_prompt = __esm({
11423
11423
  '- request_review \u2014 run a Review on a worktree thread. Reuses the only unused idle agent when the checkout has a single chat with no messages; otherwise opens a Review tab (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. The review stays in that chat so they can read it and type next steps \u2014 do not tell the child to comment or update the PR or ticket.',
11424
11424
  "- ask_git \u2014 commit & push, open a draft PR, mark ready for review, resolve conflicts, or merge \u2014 same prompts as the desktop git buttons (Resolve, Create PR, \u2026). Always steers the worktree agent; then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If the user gave a goal (Greptile 5/5, CI green), send_to_chat that goal so the worktree agent enters the watch-fix-push loop \u2014 do not tell the human to poll.",
11425
11425
  '- Merge (`ask_git` action=merge / send_to_chat "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.',
11426
- '- Or send_to_chat 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 --assignee @me -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.',
11426
+ '- Or send_to_chat with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Ready for review.", "Merge PR." Prefer ask_git resolve-conflicts (it names the actual PR base \u2014 not always main) over paraphrasing. (draft PRs: `gh pr create --draft --assignee @me -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.',
11427
11427
  "Process guides:",
11428
11428
  "- 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.",
11429
11429
  "- 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.",
@@ -17852,6 +17852,14 @@ var init_spawn = __esm({
17852
17852
  });
17853
17853
 
17854
17854
  // src/git/agent-git-actions.ts
17855
+ function namedPrBase(prBase) {
17856
+ const base = prBase?.trim().replace(/^refs\/heads\//, "").replace(/^origin\//, "");
17857
+ return base || null;
17858
+ }
17859
+ function isMainishPrBase(base) {
17860
+ const n = base.toLowerCase();
17861
+ return n === "main" || n === "master";
17862
+ }
17855
17863
  function agentGitPrompt(action, opts) {
17856
17864
  switch (action) {
17857
17865
  case "commit-push":
@@ -17861,14 +17869,19 @@ function agentGitPrompt(action, opts) {
17861
17869
  case "create-web":
17862
17870
  return "Commit, push, and open a PR in the browser.";
17863
17871
  case "resolve-conflicts": {
17864
- const base = opts?.prBase?.trim().replace(/^refs\/heads\//, "");
17872
+ const base = namedPrBase(opts?.prBase);
17865
17873
  const named = base ? ` (${base})` : "";
17866
17874
  return `Merge the remote branch${named} into your branch and resolve conflicts. Then, commit and push your changes.`;
17867
17875
  }
17868
17876
  case "ready-for-review":
17869
17877
  return "Ready for review.";
17870
- case "merge":
17878
+ case "merge": {
17879
+ const base = namedPrBase(opts?.prBase);
17880
+ if (base && !isMainishPrBase(base)) {
17881
+ return `Merge PR into ${base}.`;
17882
+ }
17871
17883
  return "Merge PR.";
17884
+ }
17872
17885
  }
17873
17886
  }
17874
17887
  function resolveSidebarGitPrompt(action, opts) {
@@ -17893,10 +17906,19 @@ function gitActionExpansion(action, base) {
17893
17906
  case "create-web":
17894
17907
  return "Commit, push, then `gh pr create --web --assignee @me -R <origin-owner/name>`. Use a different `--assignee` only if the user named someone else.";
17895
17908
  case "resolve-conflicts":
17896
- return `Fetch the PR base${base ? ` (\`${base}\`)` : ""}, merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
17909
+ if (base && !isMainishPrBase(base)) {
17910
+ return `Fetch \`origin/${base}\` (this PR's base \u2014 not main/master), merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable. Do not merge origin/main.`;
17911
+ }
17912
+ if (base) {
17913
+ return `Fetch the PR base (\`${base}\`), merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
17914
+ }
17915
+ return "Look up this PR's base with `gh pr view --json baseRefName` and merge that remote branch into this branch (do not assume main). Resolve conflicts carefully, then commit and push until the PR is mergeable.";
17897
17916
  case "ready-for-review":
17898
17917
  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.";
17899
17918
  case "merge":
17919
+ if (base && !isMainishPrBase(base)) {
17920
+ return `This phrase is the explicit ask to merge this thread's open pull request into \`${base}\` on GitHub with \`gh pr merge\` (respect repo defaults / squash vs merge). This PR targets \`${base}\`, not main \u2014 do not use \`gh stack merge\` and do not retarget or merge into main/master. Do not force-push main/master or merge locally into the main checkout.`;
17921
+ }
17900
17922
  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.";
17901
17923
  }
17902
17924
  }
@@ -17918,6 +17940,13 @@ function expandCanonicalGitRequest(prompt) {
17918
17940
  base = m[1] ?? null;
17919
17941
  }
17920
17942
  }
17943
+ if (!action) {
17944
+ const m = MERGE_INTO_RE.exec(trimmed);
17945
+ if (m) {
17946
+ action = "merge";
17947
+ base = m[1]?.trim() || null;
17948
+ }
17949
+ }
17921
17950
  let expansion = action ? gitActionExpansion(action, base) : null;
17922
17951
  if (!expansion && trimmed === "Address review comments.") {
17923
17952
  expansion = "Read the PR review feedback (`gh pr view --comments`, `gh api` review comments), make the requested changes, commit, and push.";
@@ -17929,7 +17958,7 @@ function expandCanonicalGitRequest(prompt) {
17929
17958
 
17930
17959
  (Sideboard git request \u2014 do not ask for clarification: ${expansion})`;
17931
17960
  }
17932
- var AGENT_GIT_ACTIONS, RESOLVE_CONFLICTS_RE, FIX_CI_RE;
17961
+ var AGENT_GIT_ACTIONS, RESOLVE_CONFLICTS_RE, MERGE_INTO_RE, FIX_CI_RE;
17933
17962
  var init_agent_git_actions = __esm({
17934
17963
  "src/git/agent-git-actions.ts"() {
17935
17964
  "use strict";
@@ -17942,6 +17971,7 @@ var init_agent_git_actions = __esm({
17942
17971
  "merge"
17943
17972
  ];
17944
17973
  RESOLVE_CONFLICTS_RE = /^Merge the remote branch(?: \(([^)]+)\))? into your branch and resolve conflicts\. Then, commit and push your changes\.$/;
17974
+ MERGE_INTO_RE = /^Merge PR into (.+)\.$/;
17945
17975
  FIX_CI_RE = /^Fix CI: .+\.$/;
17946
17976
  }
17947
17977
  });
@@ -28635,10 +28665,10 @@ var init_orchestrator = __esm({
28635
28665
  );
28636
28666
  }
28637
28667
  let prBase;
28638
- if (action === "resolve-conflicts") {
28668
+ if (action === "resolve-conflicts" || action === "merge") {
28639
28669
  try {
28640
- const details = await this.getPrDetails(threadRef);
28641
- prBase = details?.baseRefName?.trim() || void 0;
28670
+ const meta = await this.getPrMeta(threadRef);
28671
+ prBase = meta?.baseRefName?.trim() || void 0;
28642
28672
  } catch {
28643
28673
  }
28644
28674
  }
@@ -39640,7 +39670,19 @@ async function startRelayServer(opts) {
39640
39670
  }
39641
39671
  });
39642
39672
  });
39643
- const wss = new import_ws6.WebSocketServer({ server: httpServer, path: SLACK_RELAY_DESKTOP_PATH });
39673
+ const wss = new import_ws6.WebSocketServer({ noServer: true });
39674
+ const remoteWss = new import_ws6.WebSocketServer({ noServer: true });
39675
+ httpServer.on("upgrade", (req, socket, head) => {
39676
+ const pathname = (req.url ?? "/").split("?")[0];
39677
+ const target = pathname === SLACK_RELAY_DESKTOP_PATH ? wss : pathname === REMOTE_RELAY_PATH ? remoteWss : null;
39678
+ if (!target) {
39679
+ socket.destroy();
39680
+ return;
39681
+ }
39682
+ target.handleUpgrade(req, socket, head, (ws) => {
39683
+ target.emit("connection", ws, req);
39684
+ });
39685
+ });
39644
39686
  wss.on("connection", (ws, _req) => {
39645
39687
  const socket = {
39646
39688
  send: (data) => {
@@ -39671,7 +39713,6 @@ async function startRelayServer(opts) {
39671
39713
  hub.detachSocket(socket);
39672
39714
  });
39673
39715
  });
39674
- const remoteWss = new import_ws6.WebSocketServer({ server: httpServer, path: REMOTE_RELAY_PATH });
39675
39716
  remoteWss.on("connection", (ws) => {
39676
39717
  const socket = {
39677
39718
  send: (data) => {
package/dist/index.js CHANGED
@@ -173,7 +173,7 @@ import {
173
173
  worktreeBoardStatus,
174
174
  worktreeCleanupSettings,
175
175
  writeWorktreeFile
176
- } from "./chunk-ZSGSVFWD.js";
176
+ } from "./chunk-VC24GQN4.js";
177
177
  import {
178
178
  BASE_ALLOWED_TOOLS,
179
179
  BRIGHTSY_MCP_ALLOWED_TOOLS,
@@ -263,7 +263,7 @@ import {
263
263
  whichOnPath,
264
264
  worktreeMcpToolNames,
265
265
  writeInjectedMcpConfig
266
- } from "./chunk-3VBS6MES.js";
266
+ } from "./chunk-ADWNK2JH.js";
267
267
  import {
268
268
  brightsyMcpServerName,
269
269
  connectBrightsyTeam,
@@ -380,7 +380,7 @@ import {
380
380
  waitForTurnToolResult,
381
381
  worktreeRunPortsPath,
382
382
  wrapReviewSkillMarkdown
383
- } from "./chunk-X7RP3TQB.js";
383
+ } from "./chunk-M7626KJO.js";
384
384
  import {
385
385
  STDERR_EVENT_MAX_CHARS,
386
386
  STDOUT_EVENT_MAX_CHARS,
@@ -557,7 +557,7 @@ import {
557
557
  stageBuffersAsAttachments,
558
558
  syncWorkspacesFromThreads,
559
559
  takenTeamSlugsForOrchestration
560
- } from "./chunk-DB7MVDYS.js";
560
+ } from "./chunk-PTNGMA5C.js";
561
561
  import {
562
562
  FAMOUS_SOCCER_TEAMS,
563
563
  GITHUB_PR_BODY_MAX_CHARS,
@@ -5139,7 +5139,7 @@ async function handleJobStop(params, _ctx) {
5139
5139
  return stopDetachedJob(jobCwd(rec), id, reason ? { reason } : void 0);
5140
5140
  }
5141
5141
  async function defaultTurnWait(ref, timeoutMs) {
5142
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-6ZQ2CYS4.js");
5142
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-OPWMDMTK.js");
5143
5143
  const orch = getOrchestrator2();
5144
5144
  const thread = await orch.waitForTurn(ref, timeoutMs, {
5145
5145
  resolveIfStillRunning: true
@@ -10274,7 +10274,19 @@ async function startRelayServer(opts) {
10274
10274
  }
10275
10275
  });
10276
10276
  });
10277
- const wss = new WebSocketServer2({ server: httpServer, path: SLACK_RELAY_DESKTOP_PATH });
10277
+ const wss = new WebSocketServer2({ noServer: true });
10278
+ const remoteWss = new WebSocketServer2({ noServer: true });
10279
+ httpServer.on("upgrade", (req, socket, head) => {
10280
+ const pathname = (req.url ?? "/").split("?")[0];
10281
+ const target = pathname === SLACK_RELAY_DESKTOP_PATH ? wss : pathname === REMOTE_RELAY_PATH ? remoteWss : null;
10282
+ if (!target) {
10283
+ socket.destroy();
10284
+ return;
10285
+ }
10286
+ target.handleUpgrade(req, socket, head, (ws) => {
10287
+ target.emit("connection", ws, req);
10288
+ });
10289
+ });
10278
10290
  wss.on("connection", (ws, _req) => {
10279
10291
  const socket = {
10280
10292
  send: (data) => {
@@ -10305,7 +10317,6 @@ async function startRelayServer(opts) {
10305
10317
  hub.detachSocket(socket);
10306
10318
  });
10307
10319
  });
10308
- const remoteWss = new WebSocketServer2({ server: httpServer, path: REMOTE_RELAY_PATH });
10309
10320
  remoteWss.on("connection", (ws) => {
10310
10321
  const socket = {
10311
10322
  send: (data) => {
@@ -10458,7 +10469,7 @@ async function continueSourceThread(threadId, prompt) {
10458
10469
  await continueOnReply(threadId, prompt);
10459
10470
  return;
10460
10471
  }
10461
- const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-6ZQ2CYS4.js");
10472
+ const { getOrchestrator: getOrchestrator2 } = await import("./orchestrator-OPWMDMTK.js");
10462
10473
  await getOrchestrator2().send(threadId, prompt);
10463
10474
  } catch {
10464
10475
  }
@@ -9752,7 +9752,7 @@ var init_coordinator_prompt = __esm({
9752
9752
  '- request_review \u2014 run a Review on a worktree thread. Reuses the only unused idle agent when the checkout has a single chat with no messages; otherwise opens a Review tab (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. The review stays in that chat so they can read it and type next steps \u2014 do not tell the child to comment or update the PR or ticket.',
9753
9753
  "- ask_git \u2014 commit & push, open a draft PR, mark ready for review, resolve conflicts, or merge \u2014 same prompts as the desktop git buttons (Resolve, Create PR, \u2026). Always steers the worktree agent; then wait_for_turn (loop while stillRunning). Prefer this over paraphrasing. If the user gave a goal (Greptile 5/5, CI green), send_to_chat that goal so the worktree agent enters the watch-fix-push loop \u2014 do not tell the human to poll.",
9754
9754
  '- Merge (`ask_git` action=merge / send_to_chat "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.',
9755
- '- Or send_to_chat 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 --assignee @me -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.',
9755
+ '- Or send_to_chat with those exact phrases: "Commit and push.", "Commit, push, and open a draft PR.", "Ready for review.", "Merge PR." Prefer ask_git resolve-conflicts (it names the actual PR base \u2014 not always main) over paraphrasing. (draft PRs: `gh pr create --draft --assignee @me -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.',
9756
9756
  "Process guides:",
9757
9757
  "- 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.",
9758
9758
  "- 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.",
@@ -14756,6 +14756,14 @@ var init_spawn = __esm({
14756
14756
  });
14757
14757
 
14758
14758
  // src/git/agent-git-actions.ts
14759
+ function namedPrBase(prBase) {
14760
+ const base = prBase?.trim().replace(/^refs\/heads\//, "").replace(/^origin\//, "");
14761
+ return base || null;
14762
+ }
14763
+ function isMainishPrBase(base) {
14764
+ const n = base.toLowerCase();
14765
+ return n === "main" || n === "master";
14766
+ }
14759
14767
  function agentGitPrompt(action, opts) {
14760
14768
  switch (action) {
14761
14769
  case "commit-push":
@@ -14765,14 +14773,19 @@ function agentGitPrompt(action, opts) {
14765
14773
  case "create-web":
14766
14774
  return "Commit, push, and open a PR in the browser.";
14767
14775
  case "resolve-conflicts": {
14768
- const base = opts?.prBase?.trim().replace(/^refs\/heads\//, "");
14776
+ const base = namedPrBase(opts?.prBase);
14769
14777
  const named = base ? ` (${base})` : "";
14770
14778
  return `Merge the remote branch${named} into your branch and resolve conflicts. Then, commit and push your changes.`;
14771
14779
  }
14772
14780
  case "ready-for-review":
14773
14781
  return "Ready for review.";
14774
- case "merge":
14782
+ case "merge": {
14783
+ const base = namedPrBase(opts?.prBase);
14784
+ if (base && !isMainishPrBase(base)) {
14785
+ return `Merge PR into ${base}.`;
14786
+ }
14775
14787
  return "Merge PR.";
14788
+ }
14776
14789
  }
14777
14790
  }
14778
14791
  function resolveSidebarGitPrompt(action, opts) {
@@ -14797,10 +14810,19 @@ function gitActionExpansion(action, base) {
14797
14810
  case "create-web":
14798
14811
  return "Commit, push, then `gh pr create --web --assignee @me -R <origin-owner/name>`. Use a different `--assignee` only if the user named someone else.";
14799
14812
  case "resolve-conflicts":
14800
- return `Fetch the PR base${base ? ` (\`${base}\`)` : ""}, merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
14813
+ if (base && !isMainishPrBase(base)) {
14814
+ return `Fetch \`origin/${base}\` (this PR's base \u2014 not main/master), merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable. Do not merge origin/main.`;
14815
+ }
14816
+ if (base) {
14817
+ return `Fetch the PR base (\`${base}\`), merge it into this branch, resolve conflicts carefully, then commit and push until the PR is mergeable.`;
14818
+ }
14819
+ return "Look up this PR's base with `gh pr view --json baseRefName` and merge that remote branch into this branch (do not assume main). Resolve conflicts carefully, then commit and push until the PR is mergeable.";
14801
14820
  case "ready-for-review":
14802
14821
  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.";
14803
14822
  case "merge":
14823
+ if (base && !isMainishPrBase(base)) {
14824
+ return `This phrase is the explicit ask to merge this thread's open pull request into \`${base}\` on GitHub with \`gh pr merge\` (respect repo defaults / squash vs merge). This PR targets \`${base}\`, not main \u2014 do not use \`gh stack merge\` and do not retarget or merge into main/master. Do not force-push main/master or merge locally into the main checkout.`;
14825
+ }
14804
14826
  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.";
14805
14827
  }
14806
14828
  }
@@ -14822,6 +14844,13 @@ function expandCanonicalGitRequest(prompt) {
14822
14844
  base = m[1] ?? null;
14823
14845
  }
14824
14846
  }
14847
+ if (!action) {
14848
+ const m = MERGE_INTO_RE.exec(trimmed);
14849
+ if (m) {
14850
+ action = "merge";
14851
+ base = m[1]?.trim() || null;
14852
+ }
14853
+ }
14825
14854
  let expansion = action ? gitActionExpansion(action, base) : null;
14826
14855
  if (!expansion && trimmed === "Address review comments.") {
14827
14856
  expansion = "Read the PR review feedback (`gh pr view --comments`, `gh api` review comments), make the requested changes, commit, and push.";
@@ -14833,7 +14862,7 @@ function expandCanonicalGitRequest(prompt) {
14833
14862
 
14834
14863
  (Sideboard git request \u2014 do not ask for clarification: ${expansion})`;
14835
14864
  }
14836
- var AGENT_GIT_ACTIONS, RESOLVE_CONFLICTS_RE, FIX_CI_RE;
14865
+ var AGENT_GIT_ACTIONS, RESOLVE_CONFLICTS_RE, MERGE_INTO_RE, FIX_CI_RE;
14837
14866
  var init_agent_git_actions = __esm({
14838
14867
  "src/git/agent-git-actions.ts"() {
14839
14868
  "use strict";
@@ -14846,6 +14875,7 @@ var init_agent_git_actions = __esm({
14846
14875
  "merge"
14847
14876
  ];
14848
14877
  RESOLVE_CONFLICTS_RE = /^Merge the remote branch(?: \(([^)]+)\))? into your branch and resolve conflicts\. Then, commit and push your changes\.$/;
14878
+ MERGE_INTO_RE = /^Merge PR into (.+)\.$/;
14849
14879
  FIX_CI_RE = /^Fix CI: .+\.$/;
14850
14880
  }
14851
14881
  });
@@ -26658,10 +26688,10 @@ var init_orchestrator = __esm({
26658
26688
  );
26659
26689
  }
26660
26690
  let prBase;
26661
- if (action === "resolve-conflicts") {
26691
+ if (action === "resolve-conflicts" || action === "merge") {
26662
26692
  try {
26663
- const details = await this.getPrDetails(threadRef);
26664
- prBase = details?.baseRefName?.trim() || void 0;
26693
+ const meta = await this.getPrMeta(threadRef);
26694
+ prBase = meta?.baseRefName?.trim() || void 0;
26665
26695
  } catch {
26666
26696
  }
26667
26697
  }
@@ -52,7 +52,7 @@ import {
52
52
  sliceRunLogOutput,
53
53
  syncBoardPins,
54
54
  updateSchedule
55
- } from "../chunk-HSRN2CSL.js";
55
+ } from "../chunk-BNIGN5JX.js";
56
56
  import "../chunk-LX5R5JOR.js";
57
57
  import {
58
58
  PRESENT_PLAN_REQUIRES_PLAN_MODE,
@@ -71,7 +71,7 @@ import {
71
71
  sideboardMcpProfile,
72
72
  trustSystemCertificates,
73
73
  worktreeMcpToolNames
74
- } from "../chunk-2XIRV7FS.js";
74
+ } from "../chunk-JLDJGGCL.js";
75
75
  import "../chunk-TQRSVE7D.js";
76
76
  import "../chunk-P2BSMNHB.js";
77
77
  import {
@@ -86,7 +86,7 @@ import {
86
86
  threadsSharingWorktree,
87
87
  waitForDetachedJob,
88
88
  waitForTurnToolResult
89
- } from "../chunk-4ECDIKAS.js";
89
+ } from "../chunk-RQR25LUB.js";
90
90
  import {
91
91
  clipToolResultForStore,
92
92
  isInternalAgentStatusText,
@@ -97,7 +97,7 @@ import {
97
97
  isCloudCoordinatorThread,
98
98
  isOrchestratorThread,
99
99
  listWorkspaces
100
- } from "../chunk-GZXKUUJO.js";
100
+ } from "../chunk-2QUILREI.js";
101
101
  import {
102
102
  canonicalizeRepoPath,
103
103
  formatGhLandError,
@@ -9,14 +9,14 @@ import {
9
9
  resolveSendFollowUp,
10
10
  startOrchestration,
11
11
  waitForPidExit
12
- } from "./chunk-ZSGSVFWD.js";
13
- import "./chunk-3VBS6MES.js";
12
+ } from "./chunk-VC24GQN4.js";
13
+ import "./chunk-ADWNK2JH.js";
14
14
  import "./chunk-GWFVCCJZ.js";
15
- import "./chunk-X7RP3TQB.js";
15
+ import "./chunk-M7626KJO.js";
16
16
  import "./chunk-FAGK33E2.js";
17
17
  import "./chunk-7H655NEW.js";
18
18
  import "./chunk-PGPSIEMW.js";
19
- import "./chunk-DB7MVDYS.js";
19
+ import "./chunk-PTNGMA5C.js";
20
20
  import "./chunk-USBZ7PH4.js";
21
21
  import "./chunk-FWNL62VA.js";
22
22
  import "./chunk-2P4XKWV2.js";
@@ -11,17 +11,17 @@ import {
11
11
  resolveSendFollowUp,
12
12
  startOrchestration,
13
13
  waitForPidExit
14
- } from "./chunk-HSRN2CSL.js";
14
+ } from "./chunk-BNIGN5JX.js";
15
15
  import "./chunk-LX5R5JOR.js";
16
16
  import "./chunk-4GK32AYX.js";
17
17
  import "./chunk-5DZUWGKV.js";
18
- import "./chunk-2XIRV7FS.js";
18
+ import "./chunk-JLDJGGCL.js";
19
19
  import "./chunk-TQRSVE7D.js";
20
20
  import "./chunk-P2BSMNHB.js";
21
21
  import "./chunk-VKQGAWHY.js";
22
- import "./chunk-4ECDIKAS.js";
22
+ import "./chunk-RQR25LUB.js";
23
23
  import "./chunk-UKSJO36E.js";
24
- import "./chunk-GZXKUUJO.js";
24
+ import "./chunk-2QUILREI.js";
25
25
  import "./chunk-NWE3NOWQ.js";
26
26
  import "./chunk-N2WW62LF.js";
27
27
  import "./chunk-DD67JWTN.js";
@@ -5,7 +5,7 @@ import {
5
5
  primaryCheckoutFromLinkedWorktree,
6
6
  removeWorkspace,
7
7
  syncWorkspacesFromThreads
8
- } from "./chunk-DB7MVDYS.js";
8
+ } from "./chunk-PTNGMA5C.js";
9
9
  import "./chunk-USBZ7PH4.js";
10
10
  import "./chunk-FWNL62VA.js";
11
11
  import "./chunk-2P4XKWV2.js";
@@ -7,7 +7,7 @@ import {
7
7
  primaryCheckoutFromLinkedWorktree,
8
8
  removeWorkspace,
9
9
  syncWorkspacesFromThreads
10
- } from "./chunk-GZXKUUJO.js";
10
+ } from "./chunk-2QUILREI.js";
11
11
  import "./chunk-NWE3NOWQ.js";
12
12
  import "./chunk-N2WW62LF.js";
13
13
  import "./chunk-DD67JWTN.js";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sideboard-ai/core",
3
- "version": "0.1.270",
3
+ "version": "0.1.271",
4
4
  "description": "Sideboard core — orchestration, agents, git worktrees, MCP server",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",