@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.
- package/dist/{agents-HIEJL3UV.js → agents-ON6RKKND.js} +1 -1
- package/dist/{agents-5ROTZNCX.js → agents-YKSS6VBO.js} +1 -1
- package/dist/{chunk-7EUWSBWR.js → chunk-6QTZVJ7A.js} +5 -3
- package/dist/chunk-B3SJXYIJ.js +24 -0
- package/dist/{chunk-5ZPSH7VI.js → chunk-D3METLRW.js} +5 -3
- package/dist/{chunk-ZH5QZ4CR.js → chunk-DZFH2KLT.js} +280 -7
- package/dist/chunk-FKOIHGKV.js +21 -0
- package/dist/{chunk-E4VVEKAM.js → chunk-GNML24AW.js} +2 -2
- package/dist/{chunk-EOYDCKQC.js → chunk-HLEX5AQ6.js} +4 -0
- package/dist/{chunk-K3WMKGFY.js → chunk-LRLKJM3O.js} +2 -1
- package/dist/chunk-N5PM7HGQ.js +103 -0
- package/dist/chunk-QTUESPAW.js +101 -0
- package/dist/{chunk-O6W3P7V3.js → chunk-TSRXOSVD.js} +4 -0
- package/dist/{chunk-F4Q3IM6V.js → chunk-UEAHMGHW.js} +2 -1
- package/dist/{chunk-XRSAGVRW.js → chunk-XOU6HNQJ.js} +245 -7
- package/dist/{chunk-O5DOO7DP.js → chunk-XX5BB7NV.js} +3 -3
- package/dist/{chunk-QN7XNQAT.js → chunk-YDXQ72MD.js} +2 -2
- package/dist/{chunk-YFJ4FG2P.js → chunk-YOWIYAVA.js} +3 -3
- package/dist/{coordinator-prompt-7HHJRO7B.js → coordinator-prompt-6FXVTSFN.js} +4 -3
- package/dist/{coordinator-prompt-WD7FAMA2.js → coordinator-prompt-S6JZD5EF.js} +4 -3
- package/dist/{global-workspace-OJEPGDXA.js → global-workspace-EV4G2WMQ.js} +5 -4
- package/dist/{global-workspace-ECYN2MKL.js → global-workspace-MSX2K27Y.js} +5 -4
- package/dist/index.cjs +1288 -140
- package/dist/index.d.cts +388 -15
- package/dist/index.d.ts +388 -15
- package/dist/index.js +801 -84
- package/dist/mcp/run-stdio.cjs +1059 -132
- package/dist/mcp/run-stdio.js +628 -73
- package/dist/plan-file-6O7G4VPQ.js +23 -0
- package/dist/plan-file-PHVKUAEE.js +25 -0
- package/dist/{thread-store-XICUWFNM.js → thread-store-GHOADGL2.js} +1 -1
- package/dist/{thread-store-OV2X6PYO.js → thread-store-UJIGMI5J.js} +1 -1
- package/dist/{workspaces-MUU7RGVV.js → workspaces-3RQQZQRO.js} +6 -5
- package/dist/{workspaces-ZWOOFZUV.js → workspaces-AYTBR6KQ.js} +6 -5
- package/dist/{worktree-DVNDMWZ7.js → worktree-5KEQWSAF.js} +5 -2
- package/dist/{worktree-GDV56MX4.js → worktree-RWGL7FUV.js} +5 -2
- 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-
|
|
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-
|
|
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
|
-
|
|
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
|
|
1754
|
-
state: String(parsed
|
|
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-
|
|
6
|
+
} from "./chunk-LRLKJM3O.js";
|
|
7
7
|
import {
|
|
8
8
|
allocateTeamName,
|
|
9
9
|
takenSlugsFromThread,
|
|
10
10
|
teamSlugFromName
|
|
11
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-DZFH2KLT.js";
|
|
12
12
|
import {
|
|
13
13
|
createEmptyThread,
|
|
14
14
|
listThreads,
|
|
15
15
|
updateThread,
|
|
16
16
|
writeThread
|
|
17
|
-
} from "./chunk-
|
|
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-
|
|
5
|
+
} from "./chunk-YOWIYAVA.js";
|
|
6
6
|
import {
|
|
7
7
|
ensureGhPreferOrigin,
|
|
8
8
|
resolveRepoRoot
|
|
9
|
-
} from "./chunk-
|
|
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-
|
|
8
|
+
} from "./chunk-UEAHMGHW.js";
|
|
9
9
|
import {
|
|
10
10
|
allocateTeamName,
|
|
11
11
|
takenSlugsFromThread,
|
|
12
12
|
teamSlugFromName
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-XOU6HNQJ.js";
|
|
14
14
|
import {
|
|
15
15
|
createEmptyThread,
|
|
16
16
|
listThreads,
|
|
17
17
|
updateThread,
|
|
18
18
|
writeThread
|
|
19
|
-
} from "./chunk-
|
|
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-
|
|
12
|
-
import "./chunk-
|
|
13
|
-
import "./chunk-
|
|
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-
|
|
10
|
-
import "./chunk-
|
|
11
|
-
import "./chunk-
|
|
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-
|
|
16
|
+
} from "./chunk-YOWIYAVA.js";
|
|
17
17
|
import "./chunk-S2LL5HA4.js";
|
|
18
|
-
import "./chunk-
|
|
19
|
-
import "./chunk-
|
|
20
|
-
import "./chunk-
|
|
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-
|
|
14
|
+
} from "./chunk-XX5BB7NV.js";
|
|
15
15
|
import "./chunk-GI7E5733.js";
|
|
16
|
-
import "./chunk-
|
|
17
|
-
import "./chunk-
|
|
18
|
-
import "./chunk-
|
|
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
|