@sideboard-ai/core 0.1.51 → 0.1.52

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 (37) hide show
  1. package/dist/{agents-HIEJL3UV.js → agents-ON6RKKND.js} +1 -1
  2. package/dist/{agents-5ROTZNCX.js → agents-YKSS6VBO.js} +1 -1
  3. package/dist/{chunk-7EUWSBWR.js → chunk-6QTZVJ7A.js} +5 -3
  4. package/dist/chunk-B3SJXYIJ.js +24 -0
  5. package/dist/{chunk-5ZPSH7VI.js → chunk-D3METLRW.js} +5 -3
  6. package/dist/{chunk-ZH5QZ4CR.js → chunk-DZFH2KLT.js} +280 -7
  7. package/dist/chunk-FKOIHGKV.js +21 -0
  8. package/dist/{chunk-E4VVEKAM.js → chunk-GNML24AW.js} +2 -2
  9. package/dist/{chunk-EOYDCKQC.js → chunk-HLEX5AQ6.js} +4 -0
  10. package/dist/{chunk-K3WMKGFY.js → chunk-LRLKJM3O.js} +2 -1
  11. package/dist/chunk-N5PM7HGQ.js +103 -0
  12. package/dist/chunk-QTUESPAW.js +101 -0
  13. package/dist/{chunk-O6W3P7V3.js → chunk-TSRXOSVD.js} +4 -0
  14. package/dist/{chunk-F4Q3IM6V.js → chunk-UEAHMGHW.js} +2 -1
  15. package/dist/{chunk-XRSAGVRW.js → chunk-XOU6HNQJ.js} +245 -7
  16. package/dist/{chunk-O5DOO7DP.js → chunk-XX5BB7NV.js} +3 -3
  17. package/dist/{chunk-QN7XNQAT.js → chunk-YDXQ72MD.js} +2 -2
  18. package/dist/{chunk-YFJ4FG2P.js → chunk-YOWIYAVA.js} +3 -3
  19. package/dist/{coordinator-prompt-7HHJRO7B.js → coordinator-prompt-6FXVTSFN.js} +4 -3
  20. package/dist/{coordinator-prompt-WD7FAMA2.js → coordinator-prompt-S6JZD5EF.js} +4 -3
  21. package/dist/{global-workspace-OJEPGDXA.js → global-workspace-EV4G2WMQ.js} +5 -4
  22. package/dist/{global-workspace-ECYN2MKL.js → global-workspace-MSX2K27Y.js} +5 -4
  23. package/dist/index.cjs +1288 -140
  24. package/dist/index.d.cts +388 -15
  25. package/dist/index.d.ts +388 -15
  26. package/dist/index.js +801 -84
  27. package/dist/mcp/run-stdio.cjs +1059 -132
  28. package/dist/mcp/run-stdio.js +628 -73
  29. package/dist/plan-file-6O7G4VPQ.js +23 -0
  30. package/dist/plan-file-PHVKUAEE.js +25 -0
  31. package/dist/{thread-store-XICUWFNM.js → thread-store-GHOADGL2.js} +1 -1
  32. package/dist/{thread-store-OV2X6PYO.js → thread-store-UJIGMI5J.js} +1 -1
  33. package/dist/{workspaces-MUU7RGVV.js → workspaces-3RQQZQRO.js} +6 -5
  34. package/dist/{workspaces-ZWOOFZUV.js → workspaces-AYTBR6KQ.js} +6 -5
  35. package/dist/{worktree-DVNDMWZ7.js → worktree-5KEQWSAF.js} +5 -2
  36. package/dist/{worktree-GDV56MX4.js → worktree-RWGL7FUV.js} +5 -2
  37. package/package.json +1 -1
@@ -0,0 +1,101 @@
1
+ import {
2
+ ATTACHMENTS_DIR,
3
+ LEGACY_ATTACHMENTS_DIR,
4
+ attachmentsGitignoreBody
5
+ } from "./chunk-FKOIHGKV.js";
6
+
7
+ // src/plan/plan-file.ts
8
+ import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
9
+ import { dirname, join } from "path";
10
+
11
+ // src/plan/plan-present.ts
12
+ var PLAN_FILE_REL = `${ATTACHMENTS_DIR}/plan.md`;
13
+ var PLAN_FILE_NAME = "plan.md";
14
+ var LEGACY_PLAN_FILE_REL = ".sideboard/plan.md";
15
+ function asRecord(v) {
16
+ return v != null && typeof v === "object" && !Array.isArray(v) ? v : null;
17
+ }
18
+ function isPresentPlanToolName(name) {
19
+ if (!name) return false;
20
+ return /present_plan$/i.test(name) || /^mcp__sideboard__present_plan$/i.test(name);
21
+ }
22
+ function extractPresentedPlan(parts) {
23
+ if (!parts?.length) return null;
24
+ for (let i = parts.length - 1; i >= 0; i--) {
25
+ const p = parts[i];
26
+ if (p.type !== "tool" || !isPresentPlanToolName(p.name)) continue;
27
+ const input = asRecord(p.input) ?? {};
28
+ const content = typeof input.content === "string" ? input.content : typeof input.plan === "string" ? input.plan : typeof input.markdown === "string" ? input.markdown : "";
29
+ if (!content.trim()) continue;
30
+ const title = typeof input.title === "string" && input.title.trim() ? input.title.trim() : "Plan";
31
+ const path = typeof input.path === "string" && input.path.trim() ? input.path.trim() : PLAN_FILE_REL;
32
+ return { title, content: content.trim(), path, source: "present_plan" };
33
+ }
34
+ return null;
35
+ }
36
+ function resolvePlanMarkdown(opts) {
37
+ const fromTool = extractPresentedPlan(opts.parts);
38
+ if (fromTool) return fromTool;
39
+ const file = opts.fileContent?.trim();
40
+ if (file) {
41
+ return {
42
+ title: "Plan",
43
+ content: file,
44
+ path: PLAN_FILE_REL,
45
+ source: "exit_plan"
46
+ };
47
+ }
48
+ const text = opts.text?.trim();
49
+ if (text && text.length >= 80) {
50
+ return {
51
+ title: "Plan",
52
+ content: text,
53
+ path: PLAN_FILE_REL,
54
+ source: "text"
55
+ };
56
+ }
57
+ return null;
58
+ }
59
+
60
+ // src/plan/plan-file.ts
61
+ function ensureAttachmentsGitignore(worktreePath) {
62
+ const gitignoreAbs = join(worktreePath, ATTACHMENTS_DIR, ".gitignore");
63
+ if (existsSync(gitignoreAbs)) return;
64
+ mkdirSync(dirname(gitignoreAbs), { recursive: true });
65
+ writeFileSync(gitignoreAbs, attachmentsGitignoreBody(), "utf8");
66
+ }
67
+ function planFileAbs(worktreePath) {
68
+ return join(worktreePath, PLAN_FILE_REL);
69
+ }
70
+ function readTextIfPresent(abs) {
71
+ if (!existsSync(abs)) return null;
72
+ try {
73
+ const content = readFileSync(abs, "utf8");
74
+ return content.trim() ? content : null;
75
+ } catch {
76
+ return null;
77
+ }
78
+ }
79
+ function readPlanFile(worktreePath) {
80
+ return readTextIfPresent(planFileAbs(worktreePath)) ?? readTextIfPresent(join(worktreePath, `${LEGACY_ATTACHMENTS_DIR}/plan.md`)) ?? readTextIfPresent(join(worktreePath, LEGACY_PLAN_FILE_REL));
81
+ }
82
+ function writePlanFile(worktreePath, content) {
83
+ ensureAttachmentsGitignore(worktreePath);
84
+ const abs = planFileAbs(worktreePath);
85
+ mkdirSync(dirname(abs), { recursive: true });
86
+ const body = content.trimEnd() + (content.endsWith("\n") ? "" : "\n");
87
+ writeFileSync(abs, body, "utf8");
88
+ return PLAN_FILE_REL;
89
+ }
90
+
91
+ export {
92
+ PLAN_FILE_REL,
93
+ PLAN_FILE_NAME,
94
+ LEGACY_PLAN_FILE_REL,
95
+ isPresentPlanToolName,
96
+ extractPresentedPlan,
97
+ resolvePlanMarkdown,
98
+ planFileAbs,
99
+ readPlanFile,
100
+ writePlanFile
101
+ };
@@ -39,6 +39,8 @@ function normalizeThread(raw) {
39
39
  agentPid: raw.agentPid ?? null,
40
40
  attachments: Array.isArray(raw.attachments) ? raw.attachments : [],
41
41
  prTitle: raw.prTitle ?? null,
42
+ stackId: raw.stackId ?? null,
43
+ stackLayer: raw.stackLayer ?? null,
42
44
  userSetTitle: Boolean(raw.userSetTitle),
43
45
  activeRuns: Array.isArray(raw.activeRuns) ? raw.activeRuns : [],
44
46
  quotaResumeAt: raw.quotaResumeAt ?? null,
@@ -63,6 +65,8 @@ function createEmptyThread(partial) {
63
65
  activeRuns: partial.activeRuns ?? [],
64
66
  prUrl: partial.prUrl ?? null,
65
67
  prTitle: partial.prTitle ?? null,
68
+ stackId: partial.stackId ?? null,
69
+ stackLayer: partial.stackLayer ?? null,
66
70
  userSetTitle: partial.userSetTitle ?? false,
67
71
  messages: partial.messages ?? [],
68
72
  attachments: partial.attachments ?? [],
@@ -2,7 +2,7 @@
2
2
 
3
3
  import {
4
4
  resolveGithubRepoSlug
5
- } from "./chunk-XRSAGVRW.js";
5
+ } from "./chunk-XOU6HNQJ.js";
6
6
  import {
7
7
  globalAgentCwd,
8
8
  sideboardReposDir
@@ -44,6 +44,7 @@ var COORDINATOR_TOOL_PLAYBOOK = [
44
44
  "Discover:",
45
45
  "- list_workspaces \u2014 registered repos (path + github slug when known)",
46
46
  "- list_branches / list_prs / list_issues \u2014 pass repoPath from list_workspaces (issues: Linear API or GitHub Issues)",
47
+ "- get_pr_stack / open_pr_stack_layers / add_stack_layer / create_pr_stack \u2014 GitHub stacked PRs (`gh stack`); one worktree per layer",
47
48
  "- list_models \u2014 only when you need a specific model (rare); otherwise leave model unset = Auto",
48
49
  "- list_threads / get_thread \u2014 fleet status (what is going on)",
49
50
  "Workspaces:",
@@ -1,8 +1,11 @@
1
1
  #!/usr/bin/env node
2
2
 
3
+ import {
4
+ isWorkspaceScratchPath
5
+ } from "./chunk-B3SJXYIJ.js";
3
6
  import {
4
7
  listThreads
5
- } from "./chunk-EOYDCKQC.js";
8
+ } from "./chunk-HLEX5AQ6.js";
6
9
  import {
7
10
  gh,
8
11
  git,
@@ -965,6 +968,178 @@ function buildMergeGateChecks(gate, opts = {}) {
965
968
  return rows;
966
969
  }
967
970
 
971
+ // src/git/stack.ts
972
+ var cachedStatus = null;
973
+ var STATUS_TTL_MS = 6e4;
974
+ async function detectGhStack(cwd) {
975
+ const now = Date.now();
976
+ if (cachedStatus && now - cachedStatus.at < STATUS_TTL_MS) {
977
+ return cachedStatus.status;
978
+ }
979
+ const probe = await gh(["stack", "view", "--help"], cwd, { reject: false });
980
+ if (probe.exitCode === 0) {
981
+ const status2 = { available: true };
982
+ cachedStatus = { at: now, status: status2 };
983
+ return status2;
984
+ }
985
+ const err = `${probe.stderr}
986
+ ${probe.stdout}`;
987
+ const reason = /official extension|extension install|github\/gh-stack/i.test(err) ? "Install with: gh extension install github/gh-stack" : err.trim() || "gh stack is not available";
988
+ const status = { available: false, reason };
989
+ cachedStatus = { at: now, status };
990
+ return status;
991
+ }
992
+ function str(v) {
993
+ return typeof v === "string" ? v : v == null ? "" : String(v);
994
+ }
995
+ function num(v) {
996
+ if (typeof v === "number" && Number.isFinite(v)) return v;
997
+ if (typeof v === "string" && v.trim() && Number.isFinite(Number(v))) {
998
+ return Number(v);
999
+ }
1000
+ return null;
1001
+ }
1002
+ function parseGhStackViewJson(raw) {
1003
+ let data;
1004
+ try {
1005
+ data = JSON.parse(raw);
1006
+ } catch {
1007
+ return null;
1008
+ }
1009
+ if (!Array.isArray(data.branches) || data.branches.length === 0) return null;
1010
+ const trunk = str(data.trunk) || "main";
1011
+ const currentBranch2 = str(data.currentBranch);
1012
+ const stackNumber = num(data.stackNumber) ?? num(data.number);
1013
+ const layers = [];
1014
+ for (let i = 0; i < data.branches.length; i++) {
1015
+ const b = data.branches[i];
1016
+ if (!b || typeof b !== "object") continue;
1017
+ const name = str(b.name);
1018
+ if (!name) continue;
1019
+ const pr = b.pr && typeof b.pr === "object" ? b.pr : null;
1020
+ layers.push({
1021
+ position: i + 1,
1022
+ branchName: name,
1023
+ headSha: str(b.head) || void 0,
1024
+ baseSha: str(b.base) || void 0,
1025
+ isCurrent: Boolean(b.isCurrent) || name === currentBranch2,
1026
+ isMerged: Boolean(b.isMerged),
1027
+ isQueued: Boolean(b.isQueued),
1028
+ needsRebase: Boolean(b.needsRebase),
1029
+ prNumber: pr ? num(pr.number) : null,
1030
+ prUrl: pr && str(pr.url) ? str(pr.url) : null,
1031
+ prState: pr && str(pr.state) ? str(pr.state).toUpperCase() : null,
1032
+ title: pr && str(pr.title) ? str(pr.title) : void 0
1033
+ });
1034
+ }
1035
+ if (!layers.length) return null;
1036
+ let currentIndex = layers.findIndex((l) => l.isCurrent);
1037
+ if (currentIndex < 0 && currentBranch2) {
1038
+ currentIndex = layers.findIndex((l) => l.branchName === currentBranch2);
1039
+ }
1040
+ const { readyToMerge, blockedReason } = stackMergeReadiness(layers, currentIndex);
1041
+ return {
1042
+ stackNumber,
1043
+ trunk,
1044
+ currentBranch: currentBranch2 || layers[currentIndex]?.branchName || layers[0].branchName,
1045
+ layers,
1046
+ currentIndex,
1047
+ readyToMerge,
1048
+ blockedReason
1049
+ };
1050
+ }
1051
+ function stackMergeReadiness(layers, throughIndex) {
1052
+ if (throughIndex < 0 || throughIndex >= layers.length) {
1053
+ return { readyToMerge: false, blockedReason: "Not on a stack layer" };
1054
+ }
1055
+ for (let i = 0; i <= throughIndex; i++) {
1056
+ const layer = layers[i];
1057
+ if (layer.isMerged) continue;
1058
+ if (!layer.prNumber) {
1059
+ return {
1060
+ readyToMerge: false,
1061
+ blockedReason: `Layer ${layer.branchName} has no pull request yet`
1062
+ };
1063
+ }
1064
+ if (layer.needsRebase) {
1065
+ return {
1066
+ readyToMerge: false,
1067
+ blockedReason: `PR #${layer.prNumber} needs rebase`
1068
+ };
1069
+ }
1070
+ const state = (layer.prState ?? "").toUpperCase();
1071
+ if (state && state !== "OPEN" && state !== "QUEUED") {
1072
+ return {
1073
+ readyToMerge: false,
1074
+ blockedReason: `PR #${layer.prNumber} is ${state}`
1075
+ };
1076
+ }
1077
+ }
1078
+ return { readyToMerge: true, blockedReason: null };
1079
+ }
1080
+ async function getPrStack(cwd) {
1081
+ const status = await detectGhStack(cwd);
1082
+ if (!status.available) return null;
1083
+ const result = await gh(["stack", "view", "--json"], cwd, { reject: false });
1084
+ if (result.exitCode === 2) return null;
1085
+ if (result.exitCode !== 0) {
1086
+ if (/not in a stack|no stack/i.test(`${result.stderr}
1087
+ ${result.stdout}`)) {
1088
+ return null;
1089
+ }
1090
+ if (result.exitCode === 9) return null;
1091
+ return null;
1092
+ }
1093
+ const json = result.stdout.trim();
1094
+ if (!json) return null;
1095
+ return parseGhStackViewJson(json);
1096
+ }
1097
+ async function mergePrStack(cwd, opts) {
1098
+ const status = await detectGhStack(cwd);
1099
+ if (!status.available) {
1100
+ throw new Error(status.reason);
1101
+ }
1102
+ const method = opts.method ?? "squash";
1103
+ const methodFlag = method === "rebase" ? "--rebase" : method === "merge" ? "--merge" : "--squash";
1104
+ const args = [
1105
+ "stack",
1106
+ "merge",
1107
+ String(opts.through),
1108
+ "--yes",
1109
+ methodFlag
1110
+ ];
1111
+ const { exitCode, stderr, stdout } = await gh(args, cwd, { reject: false });
1112
+ if (exitCode !== 0) {
1113
+ throw new Error(stderr.trim() || stdout.trim() || "gh stack merge failed");
1114
+ }
1115
+ return { stdout };
1116
+ }
1117
+ async function initPrStack(cwd, branches, opts) {
1118
+ if (!branches.length) throw new Error("initPrStack requires at least one branch name");
1119
+ const status = await detectGhStack(cwd);
1120
+ if (!status.available) throw new Error(status.reason);
1121
+ const args = ["stack", "init"];
1122
+ if (opts?.base) args.push("--base", opts.base);
1123
+ args.push(...branches);
1124
+ const { exitCode, stderr, stdout } = await gh(args, cwd, { reject: false });
1125
+ if (exitCode !== 0) {
1126
+ throw new Error(stderr.trim() || stdout.trim() || "gh stack init failed");
1127
+ }
1128
+ }
1129
+ async function addPrStackLayer(cwd, branchName) {
1130
+ if (!branchName.trim()) throw new Error("branch name required");
1131
+ const status = await detectGhStack(cwd);
1132
+ if (!status.available) throw new Error(status.reason);
1133
+ const { exitCode, stderr, stdout } = await gh(
1134
+ ["stack", "add", branchName.trim()],
1135
+ cwd,
1136
+ { reject: false }
1137
+ );
1138
+ if (exitCode !== 0) {
1139
+ throw new Error(stderr.trim() || stdout.trim() || "gh stack add failed");
1140
+ }
1141
+ }
1142
+
968
1143
  // src/git/worktree.ts
969
1144
  async function lookupGithubGraphqlReset(cwd) {
970
1145
  const result = await gh(["api", "rate_limit"], cwd, { reject: false });
@@ -1641,6 +1816,52 @@ ${add.stdout}`;
1641
1816
  await ensureGhPreferOrigin(worktreePath);
1642
1817
  return { branchName, worktreePath };
1643
1818
  }
1819
+ async function createExistingBranchWorktree(opts) {
1820
+ const branchName = opts.branchName.trim();
1821
+ if (!branchName) throw new Error("branch name required");
1822
+ const worktreePath = join(worktreesRoot(opts.repoPath), opts.slug);
1823
+ if (existsSync(worktreePath)) {
1824
+ throw new Error(`Worktree already exists at ${worktreePath}`);
1825
+ }
1826
+ await ensureGhPreferOrigin(opts.repoPath);
1827
+ await git(["fetch", "origin", "--prune"], opts.repoPath, { reject: false });
1828
+ if (!branchName.startsWith("origin/") && !branchName.startsWith("refs/")) {
1829
+ await git(["fetch", "origin", branchName], opts.repoPath, { reject: false });
1830
+ }
1831
+ const existing = await listWorktrees(opts.repoPath);
1832
+ const already = existing.find((w) => w.branch === branchName);
1833
+ if (already?.path) {
1834
+ throw new Error(
1835
+ `Branch ${branchName} is already checked out at ${already.path}`
1836
+ );
1837
+ }
1838
+ const startPoint = await resolveWorktreeStartPoint(opts.repoPath, branchName);
1839
+ const add = await git(
1840
+ ["worktree", "add", worktreePath, startPoint],
1841
+ opts.repoPath,
1842
+ { reject: false }
1843
+ );
1844
+ if (add.exitCode !== 0) {
1845
+ const retry = await git(
1846
+ ["worktree", "add", worktreePath, branchName],
1847
+ opts.repoPath,
1848
+ { reject: false }
1849
+ );
1850
+ if (retry.exitCode !== 0) {
1851
+ throw new Error(
1852
+ `Failed to create worktree for ${branchName}: ${retry.stderr.trim() || add.stderr.trim() || retry.stdout.trim() || add.stdout.trim() || `exit ${add.exitCode}`}`
1853
+ );
1854
+ }
1855
+ }
1856
+ const head = await git(["rev-parse", "--abbrev-ref", "HEAD"], worktreePath, {
1857
+ reject: false
1858
+ });
1859
+ if (head.stdout.trim() === "HEAD" || head.stdout.trim() !== branchName) {
1860
+ await git(["checkout", "-B", branchName], worktreePath, { reject: false });
1861
+ }
1862
+ await ensureGhPreferOrigin(worktreePath);
1863
+ return { branchName, worktreePath };
1864
+ }
1644
1865
  async function removeWorktree(repoPath, worktreePath, opts) {
1645
1866
  await git(["worktree", "remove", "--force", worktreePath], repoPath, {
1646
1867
  reject: false
@@ -1680,8 +1901,7 @@ async function isDirty(worktreePath) {
1680
1901
  return false;
1681
1902
  }
1682
1903
  function isSideboardScratchPath(relativePath) {
1683
- const p = relativePath.replace(/\\/g, "/").replace(/^\.\//, "").replace(/\/$/, "");
1684
- return p === ".sideboard/attachments" || p.startsWith(".sideboard/attachments/");
1904
+ return isWorkspaceScratchPath(relativePath);
1685
1905
  }
1686
1906
  function porcelainStatusPath(line) {
1687
1907
  const rest = line.length >= 3 ? line.slice(3) : "";
@@ -1709,7 +1929,7 @@ async function pushBranch(worktreePath, branchName) {
1709
1929
  }
1710
1930
  async function mergePr(cwd, selector, opts) {
1711
1931
  const slug = await resolveGithubRepoSlug(cwd);
1712
- const viewArgs = ["pr", "view", selector, "--json", "url,state,isDraft"];
1932
+ const viewArgs = ["pr", "view", selector, "--json", "url,state,isDraft,number"];
1713
1933
  if (slug) viewArgs.push("--repo", slug);
1714
1934
  const before = await gh(viewArgs, cwd, { reject: false });
1715
1935
  if (before.exitCode !== 0 || !before.stdout.trim()) {
@@ -1717,16 +1937,29 @@ async function mergePr(cwd, selector, opts) {
1717
1937
  }
1718
1938
  let url = "";
1719
1939
  let isDraft = false;
1940
+ let prNumber = null;
1720
1941
  try {
1721
1942
  const parsed = JSON.parse(before.stdout);
1722
1943
  url = String(parsed.url ?? "");
1723
1944
  isDraft = Boolean(parsed.isDraft);
1945
+ prNumber = typeof parsed.number === "number" && Number.isFinite(parsed.number) ? parsed.number : null;
1724
1946
  if (String(parsed.state ?? "").toUpperCase() === "MERGED") {
1725
1947
  return { url, state: "MERGED" };
1726
1948
  }
1727
1949
  } catch {
1728
1950
  throw new Error("Could not parse pull request details");
1729
1951
  }
1952
+ const stack = await getPrStack(cwd);
1953
+ const stackLayer = stack && prNumber != null ? stack.layers.find((l) => l.prNumber === prNumber) : null;
1954
+ if (stack && stackLayer && prNumber != null) {
1955
+ const throughIndex = stack.layers.findIndex((l) => l.prNumber === prNumber);
1956
+ const gate = stackMergeReadiness(stack.layers, throughIndex);
1957
+ if (!gate.readyToMerge) {
1958
+ throw new Error(gate.blockedReason || "Stack is not ready to merge");
1959
+ }
1960
+ await mergePrStack(cwd, { through: prNumber, method: opts?.method ?? "squash" });
1961
+ return { url, state: "MERGED" };
1962
+ }
1730
1963
  if (isDraft) {
1731
1964
  const readyArgs = ["pr", "ready", selector];
1732
1965
  if (slug) readyArgs.push("--repo", slug);
@@ -1748,10 +1981,10 @@ async function mergePr(cwd, selector, opts) {
1748
1981
  const after = await gh(viewArgs, cwd, { reject: false });
1749
1982
  if (after.exitCode === 0 && after.stdout.trim()) {
1750
1983
  try {
1751
- const parsed = JSON.parse(after.stdout);
1984
+ const parsed = after.stdout ? JSON.parse(after.stdout) : null;
1752
1985
  return {
1753
- url: String(parsed.url ?? url),
1754
- state: String(parsed.state ?? "MERGED")
1986
+ url: String(parsed?.url ?? url),
1987
+ state: String(parsed?.state ?? "MERGED")
1755
1988
  };
1756
1989
  } catch {
1757
1990
  }
@@ -1901,6 +2134,10 @@ export {
1901
2134
  worktreeDisplayLabel,
1902
2135
  worktreeDisplayLabelForGroup,
1903
2136
  formatGhLandError,
2137
+ detectGhStack,
2138
+ getPrStack,
2139
+ initPrStack,
2140
+ addPrStackLayer,
1904
2141
  slugify,
1905
2142
  resolveRepoRoot,
1906
2143
  parseGithubSlugFromRemoteUrl,
@@ -1922,6 +2159,7 @@ export {
1922
2159
  fetchPrHead,
1923
2160
  resolveWorktreeStartPoint,
1924
2161
  createThreadWorktree,
2162
+ createExistingBranchWorktree,
1925
2163
  removeWorktree,
1926
2164
  listWorktrees,
1927
2165
  isDirty,
@@ -3,18 +3,18 @@ import {
3
3
  } from "./chunk-GI7E5733.js";
4
4
  import {
5
5
  ensureGlobalCoordinatorCwd
6
- } from "./chunk-K3WMKGFY.js";
6
+ } from "./chunk-LRLKJM3O.js";
7
7
  import {
8
8
  allocateTeamName,
9
9
  takenSlugsFromThread,
10
10
  teamSlugFromName
11
- } from "./chunk-ZH5QZ4CR.js";
11
+ } from "./chunk-DZFH2KLT.js";
12
12
  import {
13
13
  createEmptyThread,
14
14
  listThreads,
15
15
  updateThread,
16
16
  writeThread
17
- } from "./chunk-O6W3P7V3.js";
17
+ } from "./chunk-TSRXOSVD.js";
18
18
  import {
19
19
  globalAgentCwd
20
20
  } from "./chunk-M37RITA6.js";
@@ -2,11 +2,11 @@
2
2
 
3
3
  import {
4
4
  isGlobalRepoPath
5
- } from "./chunk-YFJ4FG2P.js";
5
+ } from "./chunk-YOWIYAVA.js";
6
6
  import {
7
7
  ensureGhPreferOrigin,
8
8
  resolveRepoRoot
9
- } from "./chunk-XRSAGVRW.js";
9
+ } from "./chunk-XOU6HNQJ.js";
10
10
  import {
11
11
  appDataDir
12
12
  } from "./chunk-7MV3RXSC.js";
@@ -5,18 +5,18 @@ import {
5
5
  } from "./chunk-S2LL5HA4.js";
6
6
  import {
7
7
  ensureGlobalCoordinatorCwd
8
- } from "./chunk-F4Q3IM6V.js";
8
+ } from "./chunk-UEAHMGHW.js";
9
9
  import {
10
10
  allocateTeamName,
11
11
  takenSlugsFromThread,
12
12
  teamSlugFromName
13
- } from "./chunk-XRSAGVRW.js";
13
+ } from "./chunk-XOU6HNQJ.js";
14
14
  import {
15
15
  createEmptyThread,
16
16
  listThreads,
17
17
  updateThread,
18
18
  writeThread
19
- } from "./chunk-EOYDCKQC.js";
19
+ } from "./chunk-HLEX5AQ6.js";
20
20
  import {
21
21
  globalAgentCwd
22
22
  } from "./chunk-7MV3RXSC.js";
@@ -8,9 +8,10 @@ import {
8
8
  enrichWorkspacesWithGithub,
9
9
  ensureGlobalCoordinatorCwd,
10
10
  formatWorkspaceInventory
11
- } from "./chunk-F4Q3IM6V.js";
12
- import "./chunk-XRSAGVRW.js";
13
- import "./chunk-EOYDCKQC.js";
11
+ } from "./chunk-UEAHMGHW.js";
12
+ import "./chunk-XOU6HNQJ.js";
13
+ import "./chunk-B3SJXYIJ.js";
14
+ import "./chunk-HLEX5AQ6.js";
14
15
  import "./chunk-ZNM4MAN4.js";
15
16
  import "./chunk-KGZBYWZ3.js";
16
17
  import "./chunk-7MV3RXSC.js";
@@ -6,9 +6,10 @@ import {
6
6
  enrichWorkspacesWithGithub,
7
7
  ensureGlobalCoordinatorCwd,
8
8
  formatWorkspaceInventory
9
- } from "./chunk-K3WMKGFY.js";
10
- import "./chunk-ZH5QZ4CR.js";
11
- import "./chunk-O6W3P7V3.js";
9
+ } from "./chunk-LRLKJM3O.js";
10
+ import "./chunk-DZFH2KLT.js";
11
+ import "./chunk-FKOIHGKV.js";
12
+ import "./chunk-TSRXOSVD.js";
12
13
  import "./chunk-77WWLBCI.js";
13
14
  import "./chunk-M37RITA6.js";
14
15
  import "./chunk-7LNGIP3X.js";
@@ -13,11 +13,12 @@ import {
13
13
  orchestrationTitleNeedsSoccerNickname,
14
14
  orchestratorSessionPoisonedByBuiltins,
15
15
  takenTeamSlugsForOrchestration
16
- } from "./chunk-YFJ4FG2P.js";
16
+ } from "./chunk-YOWIYAVA.js";
17
17
  import "./chunk-S2LL5HA4.js";
18
- import "./chunk-F4Q3IM6V.js";
19
- import "./chunk-XRSAGVRW.js";
20
- import "./chunk-EOYDCKQC.js";
18
+ import "./chunk-UEAHMGHW.js";
19
+ import "./chunk-XOU6HNQJ.js";
20
+ import "./chunk-B3SJXYIJ.js";
21
+ import "./chunk-HLEX5AQ6.js";
21
22
  import "./chunk-ZNM4MAN4.js";
22
23
  import "./chunk-KGZBYWZ3.js";
23
24
  import {
@@ -11,11 +11,12 @@ import {
11
11
  orchestrationTitleNeedsSoccerNickname,
12
12
  orchestratorSessionPoisonedByBuiltins,
13
13
  takenTeamSlugsForOrchestration
14
- } from "./chunk-O5DOO7DP.js";
14
+ } from "./chunk-XX5BB7NV.js";
15
15
  import "./chunk-GI7E5733.js";
16
- import "./chunk-K3WMKGFY.js";
17
- import "./chunk-ZH5QZ4CR.js";
18
- import "./chunk-O6W3P7V3.js";
16
+ import "./chunk-LRLKJM3O.js";
17
+ import "./chunk-DZFH2KLT.js";
18
+ import "./chunk-FKOIHGKV.js";
19
+ import "./chunk-TSRXOSVD.js";
19
20
  import "./chunk-77WWLBCI.js";
20
21
  import {
21
22
  globalAgentCwd