@sideboard-ai/core 0.1.68 → 0.1.71
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-PE3RHQS5.js → agents-GB7XL2LI.js} +6 -5
- package/dist/{agents-JBD7IAGK.js → agents-TCAK3MXN.js} +6 -5
- package/dist/{app-settings-ONKMFSEJ.js → app-settings-3TLA2EJ7.js} +16 -1
- package/dist/{app-settings-GJVZGU3M.js → app-settings-P42Z3VOB.js} +16 -1
- package/dist/caffeinate-hold-BEJIYPJ7.js +107 -0
- package/dist/caffeinate-hold-KLC6SABD.js +14 -0
- package/dist/{chunk-DPDGMMGI.js → chunk-3CY6WJ7O.js} +2 -2
- package/dist/{chunk-ROXEENBT.js → chunk-57ROTAFD.js} +62 -3
- package/dist/{chunk-N5LMEP65.js → chunk-7NCIHRAU.js} +22 -4
- package/dist/{chunk-OICHV4DH.js → chunk-DGPUAZA4.js} +62 -3
- package/dist/{chunk-VX6ACNXS.js → chunk-H2IXNFQ2.js} +22 -4
- package/dist/chunk-JAWEDVVA.js +106 -0
- package/dist/chunk-JT7R45JB.js +20 -0
- package/dist/{chunk-EEBDVLDK.js → chunk-MF2YMEGD.js} +61 -9
- package/dist/{chunk-47RBLBRK.js → chunk-NG7S3OPX.js} +10 -4
- package/dist/chunk-NSTQ6QKD.js +23 -0
- package/dist/{chunk-REKGFVUX.js → chunk-OE7YBB5X.js} +61 -9
- package/dist/{chunk-BPOTVI5J.js → chunk-PTJJIQK7.js} +472 -18
- package/dist/{chunk-6Q7H6SMX.js → chunk-S25IHL5H.js} +10 -4
- package/dist/{chunk-QQC2D4MY.js → chunk-UH57WVFP.js} +2 -2
- package/dist/{chunk-MHR4OGZ4.js → chunk-W7YOTDVO.js} +493 -18
- package/dist/{coordinator-prompt-YZYZ5P6P.js → coordinator-prompt-2J4PIMUF.js} +6 -3
- package/dist/{coordinator-prompt-HD6IMCKS.js → coordinator-prompt-QYYG2IBB.js} +6 -3
- package/dist/{global-workspace-Z6GF7D2K.js → global-workspace-KHIFQUUM.js} +11 -4
- package/dist/{global-workspace-7P5NG3JZ.js → global-workspace-SVRYNJZA.js} +11 -4
- package/dist/index.cjs +4184 -850
- package/dist/index.d.cts +543 -21
- package/dist/index.d.ts +543 -21
- package/dist/index.js +3285 -748
- package/dist/mcp/run-stdio.cjs +1995 -482
- package/dist/mcp/run-stdio.js +943 -151
- package/dist/{workspaces-BWJNGEE6.js → workspaces-AHFTHVBT.js} +6 -5
- package/dist/{workspaces-O6EZGKQK.js → workspaces-SVQIEVIZ.js} +6 -5
- package/dist/{worktree-VDXLUOWR.js → worktree-KWXHMKRN.js} +1 -1
- package/dist/{worktree-ZPSKEZFE.js → worktree-VOCH3WS3.js} +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import {
|
|
2
|
+
writePrivateFile
|
|
3
|
+
} from "./chunk-JT7R45JB.js";
|
|
4
|
+
import {
|
|
5
|
+
appDataDir
|
|
6
|
+
} from "./chunk-M37RITA6.js";
|
|
7
|
+
|
|
8
|
+
// src/store/caffeinate-hold.ts
|
|
9
|
+
import { spawn } from "child_process";
|
|
10
|
+
import { existsSync, readFileSync, unlinkSync } from "fs";
|
|
11
|
+
import { join } from "path";
|
|
12
|
+
var hooks = {};
|
|
13
|
+
function setCaffeinateHoldHooks(next) {
|
|
14
|
+
hooks = next;
|
|
15
|
+
}
|
|
16
|
+
function caffeinateHoldPath() {
|
|
17
|
+
return join(appDataDir(), "caffeinate-hold.json");
|
|
18
|
+
}
|
|
19
|
+
function processAlive(pid) {
|
|
20
|
+
if (hooks.processAlive) return hooks.processAlive(pid);
|
|
21
|
+
try {
|
|
22
|
+
process.kill(pid, 0);
|
|
23
|
+
return true;
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function killPid(pid) {
|
|
29
|
+
if (hooks.kill) {
|
|
30
|
+
hooks.kill(pid);
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
process.kill(pid, "SIGTERM");
|
|
35
|
+
} catch {
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
function readHold() {
|
|
39
|
+
const path = caffeinateHoldPath();
|
|
40
|
+
if (!existsSync(path)) return null;
|
|
41
|
+
try {
|
|
42
|
+
const parsed = JSON.parse(readFileSync(path, "utf8"));
|
|
43
|
+
if (typeof parsed?.pid === "number" && parsed.pid > 0) return parsed;
|
|
44
|
+
} catch {
|
|
45
|
+
}
|
|
46
|
+
return null;
|
|
47
|
+
}
|
|
48
|
+
function writeHold(pid) {
|
|
49
|
+
writePrivateFile(caffeinateHoldPath(), `${JSON.stringify({ pid })}
|
|
50
|
+
`);
|
|
51
|
+
}
|
|
52
|
+
function clearHold() {
|
|
53
|
+
try {
|
|
54
|
+
unlinkSync(caffeinateHoldPath());
|
|
55
|
+
} catch {
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
function getCaffeinateHold() {
|
|
59
|
+
const platform = hooks.platform ?? process.platform;
|
|
60
|
+
const hold = readHold();
|
|
61
|
+
if (!hold) {
|
|
62
|
+
return { held: false, pid: null, running: false, platform };
|
|
63
|
+
}
|
|
64
|
+
const running = processAlive(hold.pid);
|
|
65
|
+
if (!running) {
|
|
66
|
+
clearHold();
|
|
67
|
+
return { held: false, pid: null, running: false, platform };
|
|
68
|
+
}
|
|
69
|
+
return { held: true, pid: hold.pid, running: true, platform };
|
|
70
|
+
}
|
|
71
|
+
function setCaffeinateHold(enabled) {
|
|
72
|
+
const platform = hooks.platform ?? process.platform;
|
|
73
|
+
const current = getCaffeinateHold();
|
|
74
|
+
if (!enabled) {
|
|
75
|
+
if (current.pid) killPid(current.pid);
|
|
76
|
+
clearHold();
|
|
77
|
+
return { held: false, pid: null, running: false, platform };
|
|
78
|
+
}
|
|
79
|
+
if (current.running && current.pid) return current;
|
|
80
|
+
if (platform !== "darwin") {
|
|
81
|
+
return { held: false, pid: null, running: false, platform };
|
|
82
|
+
}
|
|
83
|
+
const spawnImpl = hooks.spawn ?? spawn;
|
|
84
|
+
const child = spawnImpl("caffeinate", ["-dimsu"], {
|
|
85
|
+
detached: true,
|
|
86
|
+
stdio: "ignore"
|
|
87
|
+
});
|
|
88
|
+
const pid = child.pid;
|
|
89
|
+
if (!pid) {
|
|
90
|
+
try {
|
|
91
|
+
child.kill();
|
|
92
|
+
} catch {
|
|
93
|
+
}
|
|
94
|
+
return { held: false, pid: null, running: false, platform };
|
|
95
|
+
}
|
|
96
|
+
child.unref();
|
|
97
|
+
writeHold(pid);
|
|
98
|
+
return { held: true, pid, running: true, platform };
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export {
|
|
102
|
+
setCaffeinateHoldHooks,
|
|
103
|
+
caffeinateHoldPath,
|
|
104
|
+
getCaffeinateHold,
|
|
105
|
+
setCaffeinateHold
|
|
106
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
// src/store/private-file.ts
|
|
2
|
+
import { chmodSync, mkdirSync, writeFileSync } from "fs";
|
|
3
|
+
import { dirname } from "path";
|
|
4
|
+
var PRIVATE_FILE_MODE = 384;
|
|
5
|
+
function writePrivateFile(path, contents) {
|
|
6
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
7
|
+
writeFileSync(path, contents, { encoding: "utf8", mode: PRIVATE_FILE_MODE });
|
|
8
|
+
chmodOwnerOnly(path);
|
|
9
|
+
}
|
|
10
|
+
function chmodOwnerOnly(path) {
|
|
11
|
+
try {
|
|
12
|
+
chmodSync(path, PRIVATE_FILE_MODE);
|
|
13
|
+
} catch {
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
writePrivateFile,
|
|
19
|
+
chmodOwnerOnly
|
|
20
|
+
};
|
|
@@ -887,6 +887,10 @@ function formatIpcInvokeError(err) {
|
|
|
887
887
|
}
|
|
888
888
|
|
|
889
889
|
// src/git/pr-gates.ts
|
|
890
|
+
function prIsInMergeQueue(gate) {
|
|
891
|
+
if (gate.isInMergeQueue) return true;
|
|
892
|
+
return (gate.mergeStateStatus ?? "").toUpperCase() === "QUEUED";
|
|
893
|
+
}
|
|
890
894
|
function buildMergeGateChecks(gate, opts = {}) {
|
|
891
895
|
const rows = [];
|
|
892
896
|
const base = gate.baseRefName?.trim() || "the base branch";
|
|
@@ -896,7 +900,8 @@ function buildMergeGateChecks(gate, opts = {}) {
|
|
|
896
900
|
const review = (gate.reviewDecision ?? "").toUpperCase();
|
|
897
901
|
const suppressBlocked = opts.suppressGenericBlocked !== false;
|
|
898
902
|
const conflicting = mergeable === "CONFLICTING" || mergeState === "DIRTY";
|
|
899
|
-
|
|
903
|
+
const inQueue = prIsInMergeQueue(gate);
|
|
904
|
+
if (conflicting && !inQueue) {
|
|
900
905
|
rows.push({
|
|
901
906
|
name: "Merge conflicts",
|
|
902
907
|
state: mergeable === "CONFLICTING" ? "CONFLICTING" : mergeState || "DIRTY",
|
|
@@ -908,6 +913,18 @@ function buildMergeGateChecks(gate, opts = {}) {
|
|
|
908
913
|
workflow: "mergeability",
|
|
909
914
|
kind: "mergeability"
|
|
910
915
|
});
|
|
916
|
+
} else if (inQueue) {
|
|
917
|
+
rows.push({
|
|
918
|
+
name: "Merge queue",
|
|
919
|
+
state: "QUEUED",
|
|
920
|
+
bucket: "pending",
|
|
921
|
+
startedAt: null,
|
|
922
|
+
completedAt: null,
|
|
923
|
+
link,
|
|
924
|
+
description: `This pull request is in the GitHub merge queue for ${base}.`,
|
|
925
|
+
workflow: "mergeability",
|
|
926
|
+
kind: "mergeability"
|
|
927
|
+
});
|
|
911
928
|
} else if (mergeState === "BEHIND") {
|
|
912
929
|
rows.push({
|
|
913
930
|
name: "Branch behind",
|
|
@@ -1441,10 +1458,21 @@ async function fetchPrMergeGate(cwd, selector, slug) {
|
|
|
1441
1458
|
"view",
|
|
1442
1459
|
selector,
|
|
1443
1460
|
"--json",
|
|
1444
|
-
"mergeable,mergeStateStatus,reviewDecision,baseRefName,url"
|
|
1461
|
+
"mergeable,mergeStateStatus,reviewDecision,baseRefName,url,isInMergeQueue"
|
|
1445
1462
|
];
|
|
1446
1463
|
if (slug) args.push("--repo", slug);
|
|
1447
|
-
|
|
1464
|
+
let { stdout, exitCode, stderr } = await gh(args, cwd, { reject: false });
|
|
1465
|
+
if (exitCode !== 0 && isUnknownJsonField(stderr, "isInMergeQueue")) {
|
|
1466
|
+
const retry = [
|
|
1467
|
+
"pr",
|
|
1468
|
+
"view",
|
|
1469
|
+
selector,
|
|
1470
|
+
"--json",
|
|
1471
|
+
"mergeable,mergeStateStatus,reviewDecision,baseRefName,url"
|
|
1472
|
+
];
|
|
1473
|
+
if (slug) retry.push("--repo", slug);
|
|
1474
|
+
({ stdout, exitCode, stderr } = await gh(retry, cwd, { reject: false }));
|
|
1475
|
+
}
|
|
1448
1476
|
if (exitCode !== 0 || !stdout.trim()) {
|
|
1449
1477
|
if (/no pull requests found/i.test(stderr)) return null;
|
|
1450
1478
|
return null;
|
|
@@ -1456,12 +1484,22 @@ async function fetchPrMergeGate(cwd, selector, slug) {
|
|
|
1456
1484
|
mergeStateStatus: typeof view.mergeStateStatus === "string" && view.mergeStateStatus ? view.mergeStateStatus : null,
|
|
1457
1485
|
reviewDecision: typeof view.reviewDecision === "string" && view.reviewDecision ? view.reviewDecision : null,
|
|
1458
1486
|
baseRefName: typeof view.baseRefName === "string" && view.baseRefName ? view.baseRefName : null,
|
|
1459
|
-
url: typeof view.url === "string" && view.url ? view.url : null
|
|
1487
|
+
url: typeof view.url === "string" && view.url ? view.url : null,
|
|
1488
|
+
isInMergeQueue: parseInMergeQueue(view)
|
|
1460
1489
|
};
|
|
1461
1490
|
} catch {
|
|
1462
1491
|
return null;
|
|
1463
1492
|
}
|
|
1464
1493
|
}
|
|
1494
|
+
function isUnknownJsonField(stderr, field) {
|
|
1495
|
+
return new RegExp(`unknown json field[^\\n]*${field}`, "i").test(stderr);
|
|
1496
|
+
}
|
|
1497
|
+
function parseInMergeQueue(view) {
|
|
1498
|
+
return prIsInMergeQueue({
|
|
1499
|
+
isInMergeQueue: view.isInMergeQueue === true,
|
|
1500
|
+
mergeStateStatus: typeof view.mergeStateStatus === "string" ? view.mergeStateStatus : null
|
|
1501
|
+
});
|
|
1502
|
+
}
|
|
1465
1503
|
async function detectLocalMergeConflicts(cwd, baseRefName) {
|
|
1466
1504
|
const baseName = (baseRefName?.trim() || await resolveDefaultBranch(cwd)).replace(
|
|
1467
1505
|
/^origin\//,
|
|
@@ -1522,7 +1560,8 @@ async function getPrChecks(cwd, selector) {
|
|
|
1522
1560
|
const mergeable = (gate?.mergeable ?? "").toUpperCase();
|
|
1523
1561
|
const mergeState = (gate?.mergeStateStatus ?? "").toUpperCase();
|
|
1524
1562
|
const alreadyConflicting = mergeable === "CONFLICTING" || mergeState === "DIRTY";
|
|
1525
|
-
const
|
|
1563
|
+
const inQueue = gate ? prIsInMergeQueue(gate) : false;
|
|
1564
|
+
const needsLocalProbe = !alreadyConflicting && !inQueue;
|
|
1526
1565
|
if (needsLocalProbe) {
|
|
1527
1566
|
try {
|
|
1528
1567
|
const local = await detectLocalMergeConflicts(cwd, gate?.baseRefName ?? null);
|
|
@@ -1533,7 +1572,8 @@ async function getPrChecks(cwd, selector) {
|
|
|
1533
1572
|
mergeStateStatus: "DIRTY",
|
|
1534
1573
|
reviewDecision: gate?.reviewDecision ?? null,
|
|
1535
1574
|
baseRefName: local.base,
|
|
1536
|
-
url: gate?.url ?? null
|
|
1575
|
+
url: gate?.url ?? null,
|
|
1576
|
+
isInMergeQueue: false
|
|
1537
1577
|
};
|
|
1538
1578
|
const ciFailed2 = ciChecks.some((c) => c.bucket === "fail");
|
|
1539
1579
|
const review2 = (gate.reviewDecision ?? "").toUpperCase();
|
|
@@ -1577,10 +1617,21 @@ async function getPrMeta(cwd, selector) {
|
|
|
1577
1617
|
"view",
|
|
1578
1618
|
selector,
|
|
1579
1619
|
"--json",
|
|
1580
|
-
"number,title,url,state,isDraft,reviewDecision,baseRefName,headRefName"
|
|
1620
|
+
"number,title,url,state,isDraft,reviewDecision,baseRefName,headRefName,isInMergeQueue,mergeStateStatus"
|
|
1581
1621
|
];
|
|
1582
1622
|
if (slug) viewArgs.push("--repo", slug);
|
|
1583
|
-
|
|
1623
|
+
let { stdout, exitCode, stderr } = await gh(viewArgs, cwd, { reject: false });
|
|
1624
|
+
if (exitCode !== 0 && isUnknownJsonField(stderr, "isInMergeQueue")) {
|
|
1625
|
+
const retry = [
|
|
1626
|
+
"pr",
|
|
1627
|
+
"view",
|
|
1628
|
+
selector,
|
|
1629
|
+
"--json",
|
|
1630
|
+
"number,title,url,state,isDraft,reviewDecision,baseRefName,headRefName,mergeStateStatus"
|
|
1631
|
+
];
|
|
1632
|
+
if (slug) retry.push("--repo", slug);
|
|
1633
|
+
({ stdout, exitCode, stderr } = await gh(retry, cwd, { reject: false }));
|
|
1634
|
+
}
|
|
1584
1635
|
if (exitCode !== 0 || !stdout.trim()) {
|
|
1585
1636
|
if (/no pull requests found/i.test(stderr)) return null;
|
|
1586
1637
|
return null;
|
|
@@ -1595,7 +1646,8 @@ async function getPrMeta(cwd, selector) {
|
|
|
1595
1646
|
isDraft: Boolean(view.isDraft),
|
|
1596
1647
|
reviewDecision: typeof view.reviewDecision === "string" && view.reviewDecision ? view.reviewDecision : null,
|
|
1597
1648
|
baseRefName: String(view.baseRefName ?? ""),
|
|
1598
|
-
headRefName: String(view.headRefName ?? "")
|
|
1649
|
+
headRefName: String(view.headRefName ?? ""),
|
|
1650
|
+
isInMergeQueue: parseInMergeQueue(view)
|
|
1599
1651
|
};
|
|
1600
1652
|
} catch {
|
|
1601
1653
|
return null;
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-VROPG6QF.js";
|
|
10
10
|
import {
|
|
11
11
|
isOrchestratorThread
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-DGPUAZA4.js";
|
|
13
13
|
import {
|
|
14
14
|
enrichPathWithNpmGlobalBin,
|
|
15
15
|
isConductorBundledCli,
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
loadAppSettings,
|
|
23
23
|
resolveAgentExecutable,
|
|
24
24
|
resolveClaudeExecutable
|
|
25
|
-
} from "./chunk-
|
|
25
|
+
} from "./chunk-PTJJIQK7.js";
|
|
26
26
|
import {
|
|
27
27
|
appDataDir
|
|
28
28
|
} from "./chunk-7MV3RXSC.js";
|
|
@@ -580,7 +580,13 @@ var SIDEBOARD_ARTIFACT_MCP_ALLOWED_TOOLS = [
|
|
|
580
580
|
"mcp__sideboard__present_schema",
|
|
581
581
|
"mcp__sideboard__present_files",
|
|
582
582
|
"mcp__sideboard__ask_user",
|
|
583
|
-
"mcp__sideboard__present_plan"
|
|
583
|
+
"mcp__sideboard__present_plan",
|
|
584
|
+
"mcp__sideboard__list_teams",
|
|
585
|
+
"mcp__sideboard__slack_list_channels",
|
|
586
|
+
"mcp__sideboard__slack_list_users",
|
|
587
|
+
"mcp__sideboard__slack_search",
|
|
588
|
+
"mcp__sideboard__slack_read",
|
|
589
|
+
"mcp__sideboard__slack_post"
|
|
584
590
|
];
|
|
585
591
|
var brightsyMcpCommandCache = null;
|
|
586
592
|
async function resolveBrightsyMcpCommand() {
|
|
@@ -1000,7 +1006,7 @@ var claudeAdapter = {
|
|
|
1000
1006
|
);
|
|
1001
1007
|
}
|
|
1002
1008
|
const mode = permissionMode(thread);
|
|
1003
|
-
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-
|
|
1009
|
+
const { isOrchestratorThread: isOrchestratorThread2 } = await import("./global-workspace-KHIFQUUM.js");
|
|
1004
1010
|
const isOrchestrator = isOrchestratorThread2(thread);
|
|
1005
1011
|
const injectedServers = await buildInjectedMcpServers({
|
|
1006
1012
|
includeSideboard: true,
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
// src/store/private-file.ts
|
|
5
|
+
import { chmodSync, mkdirSync, writeFileSync } from "fs";
|
|
6
|
+
import { dirname } from "path";
|
|
7
|
+
var PRIVATE_FILE_MODE = 384;
|
|
8
|
+
function writePrivateFile(path, contents) {
|
|
9
|
+
mkdirSync(dirname(path), { recursive: true });
|
|
10
|
+
writeFileSync(path, contents, { encoding: "utf8", mode: PRIVATE_FILE_MODE });
|
|
11
|
+
chmodOwnerOnly(path);
|
|
12
|
+
}
|
|
13
|
+
function chmodOwnerOnly(path) {
|
|
14
|
+
try {
|
|
15
|
+
chmodSync(path, PRIVATE_FILE_MODE);
|
|
16
|
+
} catch {
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export {
|
|
21
|
+
writePrivateFile,
|
|
22
|
+
chmodOwnerOnly
|
|
23
|
+
};
|
|
@@ -882,6 +882,10 @@ function formatGhLandError(raw, opts) {
|
|
|
882
882
|
}
|
|
883
883
|
|
|
884
884
|
// src/git/pr-gates.ts
|
|
885
|
+
function prIsInMergeQueue(gate) {
|
|
886
|
+
if (gate.isInMergeQueue) return true;
|
|
887
|
+
return (gate.mergeStateStatus ?? "").toUpperCase() === "QUEUED";
|
|
888
|
+
}
|
|
885
889
|
function buildMergeGateChecks(gate, opts = {}) {
|
|
886
890
|
const rows = [];
|
|
887
891
|
const base = gate.baseRefName?.trim() || "the base branch";
|
|
@@ -891,7 +895,8 @@ function buildMergeGateChecks(gate, opts = {}) {
|
|
|
891
895
|
const review = (gate.reviewDecision ?? "").toUpperCase();
|
|
892
896
|
const suppressBlocked = opts.suppressGenericBlocked !== false;
|
|
893
897
|
const conflicting = mergeable === "CONFLICTING" || mergeState === "DIRTY";
|
|
894
|
-
|
|
898
|
+
const inQueue = prIsInMergeQueue(gate);
|
|
899
|
+
if (conflicting && !inQueue) {
|
|
895
900
|
rows.push({
|
|
896
901
|
name: "Merge conflicts",
|
|
897
902
|
state: mergeable === "CONFLICTING" ? "CONFLICTING" : mergeState || "DIRTY",
|
|
@@ -903,6 +908,18 @@ function buildMergeGateChecks(gate, opts = {}) {
|
|
|
903
908
|
workflow: "mergeability",
|
|
904
909
|
kind: "mergeability"
|
|
905
910
|
});
|
|
911
|
+
} else if (inQueue) {
|
|
912
|
+
rows.push({
|
|
913
|
+
name: "Merge queue",
|
|
914
|
+
state: "QUEUED",
|
|
915
|
+
bucket: "pending",
|
|
916
|
+
startedAt: null,
|
|
917
|
+
completedAt: null,
|
|
918
|
+
link,
|
|
919
|
+
description: `This pull request is in the GitHub merge queue for ${base}.`,
|
|
920
|
+
workflow: "mergeability",
|
|
921
|
+
kind: "mergeability"
|
|
922
|
+
});
|
|
906
923
|
} else if (mergeState === "BEHIND") {
|
|
907
924
|
rows.push({
|
|
908
925
|
name: "Branch behind",
|
|
@@ -1408,10 +1425,21 @@ async function fetchPrMergeGate(cwd, selector, slug) {
|
|
|
1408
1425
|
"view",
|
|
1409
1426
|
selector,
|
|
1410
1427
|
"--json",
|
|
1411
|
-
"mergeable,mergeStateStatus,reviewDecision,baseRefName,url"
|
|
1428
|
+
"mergeable,mergeStateStatus,reviewDecision,baseRefName,url,isInMergeQueue"
|
|
1412
1429
|
];
|
|
1413
1430
|
if (slug) args.push("--repo", slug);
|
|
1414
|
-
|
|
1431
|
+
let { stdout, exitCode, stderr } = await gh(args, cwd, { reject: false });
|
|
1432
|
+
if (exitCode !== 0 && isUnknownJsonField(stderr, "isInMergeQueue")) {
|
|
1433
|
+
const retry = [
|
|
1434
|
+
"pr",
|
|
1435
|
+
"view",
|
|
1436
|
+
selector,
|
|
1437
|
+
"--json",
|
|
1438
|
+
"mergeable,mergeStateStatus,reviewDecision,baseRefName,url"
|
|
1439
|
+
];
|
|
1440
|
+
if (slug) retry.push("--repo", slug);
|
|
1441
|
+
({ stdout, exitCode, stderr } = await gh(retry, cwd, { reject: false }));
|
|
1442
|
+
}
|
|
1415
1443
|
if (exitCode !== 0 || !stdout.trim()) {
|
|
1416
1444
|
if (/no pull requests found/i.test(stderr)) return null;
|
|
1417
1445
|
return null;
|
|
@@ -1423,12 +1451,22 @@ async function fetchPrMergeGate(cwd, selector, slug) {
|
|
|
1423
1451
|
mergeStateStatus: typeof view.mergeStateStatus === "string" && view.mergeStateStatus ? view.mergeStateStatus : null,
|
|
1424
1452
|
reviewDecision: typeof view.reviewDecision === "string" && view.reviewDecision ? view.reviewDecision : null,
|
|
1425
1453
|
baseRefName: typeof view.baseRefName === "string" && view.baseRefName ? view.baseRefName : null,
|
|
1426
|
-
url: typeof view.url === "string" && view.url ? view.url : null
|
|
1454
|
+
url: typeof view.url === "string" && view.url ? view.url : null,
|
|
1455
|
+
isInMergeQueue: parseInMergeQueue(view)
|
|
1427
1456
|
};
|
|
1428
1457
|
} catch {
|
|
1429
1458
|
return null;
|
|
1430
1459
|
}
|
|
1431
1460
|
}
|
|
1461
|
+
function isUnknownJsonField(stderr, field) {
|
|
1462
|
+
return new RegExp(`unknown json field[^\\n]*${field}`, "i").test(stderr);
|
|
1463
|
+
}
|
|
1464
|
+
function parseInMergeQueue(view) {
|
|
1465
|
+
return prIsInMergeQueue({
|
|
1466
|
+
isInMergeQueue: view.isInMergeQueue === true,
|
|
1467
|
+
mergeStateStatus: typeof view.mergeStateStatus === "string" ? view.mergeStateStatus : null
|
|
1468
|
+
});
|
|
1469
|
+
}
|
|
1432
1470
|
async function detectLocalMergeConflicts(cwd, baseRefName) {
|
|
1433
1471
|
const baseName = (baseRefName?.trim() || await resolveDefaultBranch(cwd)).replace(
|
|
1434
1472
|
/^origin\//,
|
|
@@ -1489,7 +1527,8 @@ async function getPrChecks(cwd, selector) {
|
|
|
1489
1527
|
const mergeable = (gate?.mergeable ?? "").toUpperCase();
|
|
1490
1528
|
const mergeState = (gate?.mergeStateStatus ?? "").toUpperCase();
|
|
1491
1529
|
const alreadyConflicting = mergeable === "CONFLICTING" || mergeState === "DIRTY";
|
|
1492
|
-
const
|
|
1530
|
+
const inQueue = gate ? prIsInMergeQueue(gate) : false;
|
|
1531
|
+
const needsLocalProbe = !alreadyConflicting && !inQueue;
|
|
1493
1532
|
if (needsLocalProbe) {
|
|
1494
1533
|
try {
|
|
1495
1534
|
const local = await detectLocalMergeConflicts(cwd, gate?.baseRefName ?? null);
|
|
@@ -1500,7 +1539,8 @@ async function getPrChecks(cwd, selector) {
|
|
|
1500
1539
|
mergeStateStatus: "DIRTY",
|
|
1501
1540
|
reviewDecision: gate?.reviewDecision ?? null,
|
|
1502
1541
|
baseRefName: local.base,
|
|
1503
|
-
url: gate?.url ?? null
|
|
1542
|
+
url: gate?.url ?? null,
|
|
1543
|
+
isInMergeQueue: false
|
|
1504
1544
|
};
|
|
1505
1545
|
const ciFailed2 = ciChecks.some((c) => c.bucket === "fail");
|
|
1506
1546
|
const review2 = (gate.reviewDecision ?? "").toUpperCase();
|
|
@@ -1544,10 +1584,21 @@ async function getPrMeta(cwd, selector) {
|
|
|
1544
1584
|
"view",
|
|
1545
1585
|
selector,
|
|
1546
1586
|
"--json",
|
|
1547
|
-
"number,title,url,state,isDraft,reviewDecision,baseRefName,headRefName"
|
|
1587
|
+
"number,title,url,state,isDraft,reviewDecision,baseRefName,headRefName,isInMergeQueue,mergeStateStatus"
|
|
1548
1588
|
];
|
|
1549
1589
|
if (slug) viewArgs.push("--repo", slug);
|
|
1550
|
-
|
|
1590
|
+
let { stdout, exitCode, stderr } = await gh(viewArgs, cwd, { reject: false });
|
|
1591
|
+
if (exitCode !== 0 && isUnknownJsonField(stderr, "isInMergeQueue")) {
|
|
1592
|
+
const retry = [
|
|
1593
|
+
"pr",
|
|
1594
|
+
"view",
|
|
1595
|
+
selector,
|
|
1596
|
+
"--json",
|
|
1597
|
+
"number,title,url,state,isDraft,reviewDecision,baseRefName,headRefName,mergeStateStatus"
|
|
1598
|
+
];
|
|
1599
|
+
if (slug) retry.push("--repo", slug);
|
|
1600
|
+
({ stdout, exitCode, stderr } = await gh(retry, cwd, { reject: false }));
|
|
1601
|
+
}
|
|
1551
1602
|
if (exitCode !== 0 || !stdout.trim()) {
|
|
1552
1603
|
if (/no pull requests found/i.test(stderr)) return null;
|
|
1553
1604
|
return null;
|
|
@@ -1562,7 +1613,8 @@ async function getPrMeta(cwd, selector) {
|
|
|
1562
1613
|
isDraft: Boolean(view.isDraft),
|
|
1563
1614
|
reviewDecision: typeof view.reviewDecision === "string" && view.reviewDecision ? view.reviewDecision : null,
|
|
1564
1615
|
baseRefName: String(view.baseRefName ?? ""),
|
|
1565
|
-
headRefName: String(view.headRefName ?? "")
|
|
1616
|
+
headRefName: String(view.headRefName ?? ""),
|
|
1617
|
+
isInMergeQueue: parseInMergeQueue(view)
|
|
1566
1618
|
};
|
|
1567
1619
|
} catch {
|
|
1568
1620
|
return null;
|