@h-rig/runtime 0.0.6-alpha.3 → 0.0.6-alpha.30
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/bin/rig-agent-dispatch.js +1165 -785
- package/dist/bin/rig-agent.js +458 -389
- package/dist/src/control-plane/agent-wrapper.js +1191 -504
- package/dist/src/control-plane/authority-files.js +12 -6
- package/dist/src/control-plane/harness-main.js +2186 -1786
- package/dist/src/control-plane/hooks/completion-verification.js +2084 -1019
- package/dist/src/control-plane/hooks/inject-context.js +193 -139
- package/dist/src/control-plane/hooks/submodule-branch.js +603 -545
- package/dist/src/control-plane/hooks/task-runtime-start.js +603 -545
- package/dist/src/control-plane/materialize-task-config.js +64 -8
- package/dist/src/control-plane/native/git-ops.js +90 -64
- package/dist/src/control-plane/native/harness-cli.js +1989 -682
- package/dist/src/control-plane/native/pr-automation.js +1657 -54
- package/dist/src/control-plane/native/pr-review-gate.js +1455 -0
- package/dist/src/control-plane/native/repo-ops.js +3 -0
- package/dist/src/control-plane/native/run-ops.js +39 -13
- package/dist/src/control-plane/native/task-ops.js +1819 -527
- package/dist/src/control-plane/native/validator.js +163 -109
- package/dist/src/control-plane/native/verifier.js +1616 -323
- package/dist/src/control-plane/native/workspace-ops.js +12 -6
- package/dist/src/control-plane/pi-sessiond/bin.js +793 -0
- package/dist/src/control-plane/pi-sessiond/client.js +41 -0
- package/dist/src/control-plane/pi-sessiond/event-hub.js +59 -0
- package/dist/src/control-plane/pi-sessiond/extension-ui-context.js +198 -0
- package/dist/src/control-plane/pi-sessiond/launcher.js +173 -0
- package/dist/src/control-plane/pi-sessiond/server.js +802 -0
- package/dist/src/control-plane/pi-sessiond/session-service.js +540 -0
- package/dist/src/control-plane/pi-sessiond/types.js +1 -0
- package/dist/src/control-plane/plugin-host-context.js +54 -0
- package/dist/src/control-plane/runtime/image/fingerprint-sidecar.js +3 -0
- package/dist/src/control-plane/runtime/image/index.js +3 -0
- package/dist/src/control-plane/runtime/image-fingerprint-sidecar.js +3 -0
- package/dist/src/control-plane/runtime/image.js +3 -0
- package/dist/src/control-plane/runtime/index.js +517 -722
- package/dist/src/control-plane/runtime/isolation/home.js +28 -6
- package/dist/src/control-plane/runtime/isolation/index.js +541 -461
- package/dist/src/control-plane/runtime/isolation/runner.js +28 -6
- package/dist/src/control-plane/runtime/isolation/shared.js +9 -6
- package/dist/src/control-plane/runtime/isolation.js +541 -461
- package/dist/src/control-plane/runtime/plugin-mode.js +3 -27
- package/dist/src/control-plane/runtime/queue.js +458 -385
- package/dist/src/control-plane/runtime/snapshot/task-run.js +3 -0
- package/dist/src/control-plane/runtime/task-run-snapshot.js +3 -0
- package/dist/src/control-plane/skill-materializer.js +46 -0
- package/dist/src/control-plane/tasks/source-aware-task-config-source.js +14 -2
- package/dist/src/control-plane/tasks/source-lifecycle.js +86 -32
- package/dist/src/index.js +27 -298
- package/dist/src/layout.js +12 -7
- package/dist/src/local-server.js +20 -14
- package/native/darwin-arm64/rig-git +0 -0
- package/native/darwin-arm64/rig-git.build-manifest.json +1 -1
- package/native/darwin-arm64/rig-shell +0 -0
- package/native/darwin-arm64/rig-shell.build-manifest.json +1 -1
- package/native/darwin-arm64/rig-tools +0 -0
- package/native/darwin-arm64/rig-tools.build-manifest.json +1 -1
- package/native/darwin-arm64/runtime-native.dylib +0 -0
- package/package.json +8 -6
- package/dist/src/control-plane/runtime/plugins.js +0 -1131
- package/dist/src/plugins.js +0 -329
|
@@ -300,6 +300,50 @@ function safeReadJson(path) {
|
|
|
300
300
|
var MARKER_PLUGIN = "_rigPlugin", MARKER_HOOK_ID = "_rigHookId";
|
|
301
301
|
var init_hook_materializer = () => {};
|
|
302
302
|
|
|
303
|
+
// packages/runtime/src/control-plane/skill-materializer.ts
|
|
304
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync2, readdirSync, rmSync, writeFileSync as writeFileSync2 } from "fs";
|
|
305
|
+
import { resolve as resolve2 } from "path";
|
|
306
|
+
import { loadSkill } from "@rig/skill-loader";
|
|
307
|
+
function skillDirName(id) {
|
|
308
|
+
return id.replace(/[^a-zA-Z0-9._-]+/g, "-");
|
|
309
|
+
}
|
|
310
|
+
async function materializeSkills(projectRoot, entries) {
|
|
311
|
+
const skillsRoot = resolve2(projectRoot, ".pi", "skills");
|
|
312
|
+
if (existsSync3(skillsRoot)) {
|
|
313
|
+
for (const name of readdirSync(skillsRoot)) {
|
|
314
|
+
const dir = resolve2(skillsRoot, name);
|
|
315
|
+
if (existsSync3(resolve2(dir, MARKER_FILENAME))) {
|
|
316
|
+
rmSync(dir, { recursive: true, force: true });
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
const written = [];
|
|
321
|
+
for (const { pluginName, skill } of entries) {
|
|
322
|
+
const sourcePath = resolve2(projectRoot, skill.path);
|
|
323
|
+
if (!existsSync3(sourcePath)) {
|
|
324
|
+
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${sourcePath} does not exist`);
|
|
325
|
+
continue;
|
|
326
|
+
}
|
|
327
|
+
let body;
|
|
328
|
+
try {
|
|
329
|
+
await loadSkill(sourcePath);
|
|
330
|
+
body = readFileSync2(sourcePath, "utf-8");
|
|
331
|
+
} catch (err) {
|
|
332
|
+
console.warn(`[plugin-host] skill "${skill.id}" from plugin "${pluginName}" not materialized: ${err instanceof Error ? err.message : err}`);
|
|
333
|
+
continue;
|
|
334
|
+
}
|
|
335
|
+
const dir = resolve2(skillsRoot, skillDirName(skill.id));
|
|
336
|
+
mkdirSync2(dir, { recursive: true });
|
|
337
|
+
writeFileSync2(resolve2(dir, "SKILL.md"), body, "utf-8");
|
|
338
|
+
writeFileSync2(resolve2(dir, MARKER_FILENAME), `${JSON.stringify({ plugin: pluginName, skillId: skill.id }, null, 2)}
|
|
339
|
+
`, "utf-8");
|
|
340
|
+
written.push({ id: skill.id, pluginName, directory: dir });
|
|
341
|
+
}
|
|
342
|
+
return written;
|
|
343
|
+
}
|
|
344
|
+
var MARKER_FILENAME = ".rig-plugin";
|
|
345
|
+
var init_skill_materializer = () => {};
|
|
346
|
+
|
|
303
347
|
// packages/runtime/src/control-plane/plugin-host-context.ts
|
|
304
348
|
var exports_plugin_host_context = {};
|
|
305
349
|
__export(exports_plugin_host_context, {
|
|
@@ -342,6 +386,17 @@ async function buildPluginHostContext(projectRoot) {
|
|
|
342
386
|
} catch (err) {
|
|
343
387
|
console.warn(`[plugin-host] hook materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
344
388
|
}
|
|
389
|
+
try {
|
|
390
|
+
const skillEntries = config.plugins.flatMap((plugin) => (plugin.contributes?.skills ?? []).map((skill) => ({
|
|
391
|
+
pluginName: plugin.name,
|
|
392
|
+
skill
|
|
393
|
+
})));
|
|
394
|
+
if (skillEntries.length > 0) {
|
|
395
|
+
await materializeSkills(projectRoot, skillEntries);
|
|
396
|
+
}
|
|
397
|
+
} catch (err) {
|
|
398
|
+
console.warn(`[plugin-host] skill materialization failed: ${err instanceof Error ? err.message : err}`);
|
|
399
|
+
}
|
|
345
400
|
return {
|
|
346
401
|
config,
|
|
347
402
|
pluginHost,
|
|
@@ -357,13 +412,14 @@ var init_plugin_host_context = __esm(() => {
|
|
|
357
412
|
init_registry();
|
|
358
413
|
init_runtime_registration();
|
|
359
414
|
init_hook_materializer();
|
|
415
|
+
init_skill_materializer();
|
|
360
416
|
});
|
|
361
417
|
|
|
362
418
|
// packages/runtime/src/control-plane/materialize-task-config.ts
|
|
363
|
-
import { existsSync as
|
|
364
|
-
import { dirname as dirname2, resolve as
|
|
419
|
+
import { existsSync as existsSync4, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync3 } from "fs";
|
|
420
|
+
import { dirname as dirname2, resolve as resolve3 } from "path";
|
|
365
421
|
async function materializePluginHostTaskConfig(projectRoot) {
|
|
366
|
-
const hasConfig =
|
|
422
|
+
const hasConfig = existsSync4(resolve3(projectRoot, "rig.config.ts")) || existsSync4(resolve3(projectRoot, "rig.config.json"));
|
|
367
423
|
if (!hasConfig)
|
|
368
424
|
return null;
|
|
369
425
|
const { buildPluginHostContext: buildPluginHostContext2 } = await Promise.resolve().then(() => (init_plugin_host_context(), exports_plugin_host_context));
|
|
@@ -383,8 +439,8 @@ async function materializePluginHostTaskConfig(projectRoot) {
|
|
|
383
439
|
const tasks = await source.list();
|
|
384
440
|
if (tasks.length === 0)
|
|
385
441
|
return null;
|
|
386
|
-
const configPath =
|
|
387
|
-
const existing =
|
|
442
|
+
const configPath = resolve3(projectRoot, ".rig", "task-config.json");
|
|
443
|
+
const existing = existsSync4(configPath) ? safeJsonRead(configPath) : {};
|
|
388
444
|
const merged = { ...existing };
|
|
389
445
|
let syncedCount = 0;
|
|
390
446
|
for (const task of tasks) {
|
|
@@ -400,8 +456,8 @@ async function materializePluginHostTaskConfig(projectRoot) {
|
|
|
400
456
|
merged[id] = synthesizeEntry(t, ctx.config.taskSource);
|
|
401
457
|
syncedCount += 1;
|
|
402
458
|
}
|
|
403
|
-
|
|
404
|
-
|
|
459
|
+
mkdirSync3(dirname2(configPath), { recursive: true });
|
|
460
|
+
writeFileSync3(configPath, `${JSON.stringify(merged, null, 2)}
|
|
405
461
|
`, "utf-8");
|
|
406
462
|
return { configPath, syncedCount };
|
|
407
463
|
}
|
|
@@ -442,7 +498,7 @@ function materializedTaskSource(taskSource) {
|
|
|
442
498
|
}
|
|
443
499
|
function safeJsonRead(path) {
|
|
444
500
|
try {
|
|
445
|
-
const parsed = JSON.parse(
|
|
501
|
+
const parsed = JSON.parse(readFileSync3(path, "utf-8"));
|
|
446
502
|
return parsed && typeof parsed === "object" && !Array.isArray(parsed) ? parsed : {};
|
|
447
503
|
} catch {
|
|
448
504
|
return {};
|
|
@@ -311,6 +311,9 @@ function getScopeRules() {
|
|
|
311
311
|
return activeRules;
|
|
312
312
|
}
|
|
313
313
|
|
|
314
|
+
// packages/runtime/src/control-plane/skill-materializer.ts
|
|
315
|
+
import { loadSkill } from "@rig/skill-loader";
|
|
316
|
+
|
|
314
317
|
// packages/runtime/src/control-plane/tasks/source-aware-task-config-source.ts
|
|
315
318
|
var STATUS_LABELS = new Set(["ready", "blocked", "in-progress", "under-review", "failed", "cancelled"]);
|
|
316
319
|
|
|
@@ -1365,6 +1368,30 @@ function sourceTaskConfigCandidates(projectRoot) {
|
|
|
1365
1368
|
|
|
1366
1369
|
// packages/runtime/src/binary-run.ts
|
|
1367
1370
|
var runtimeBinaryBuildQueue = Promise.resolve();
|
|
1371
|
+
// packages/runtime/src/control-plane/native/pr-review-gate.ts
|
|
1372
|
+
function strictMergeHeadShaFromGate(result, prUrl) {
|
|
1373
|
+
if (!result.approved) {
|
|
1374
|
+
throw new Error(`Refusing to merge ${prUrl}: strict merge gate is not approved.`);
|
|
1375
|
+
}
|
|
1376
|
+
if (result.evidence.prUrl !== prUrl) {
|
|
1377
|
+
throw new Error(`Refusing to merge ${prUrl}: strict merge gate evidence belongs to ${result.evidence.prUrl}.`);
|
|
1378
|
+
}
|
|
1379
|
+
const headSha = result.evidence.headSha?.trim();
|
|
1380
|
+
if (!headSha) {
|
|
1381
|
+
throw new Error(`Refusing to merge ${prUrl}: strict merge gate did not provide a current head SHA.`);
|
|
1382
|
+
}
|
|
1383
|
+
if (!/^[0-9a-f]{40}$/i.test(headSha)) {
|
|
1384
|
+
throw new Error(`Refusing to merge ${prUrl}: strict merge gate head is not a raw 40-character commit SHA.`);
|
|
1385
|
+
}
|
|
1386
|
+
if (!result.evidence.greptile.fresh || result.evidence.greptile.currentHeadSha !== headSha) {
|
|
1387
|
+
throw new Error(`Refusing to merge ${prUrl}: strict merge gate approval is not tied to head ${headSha}.`);
|
|
1388
|
+
}
|
|
1389
|
+
if (result.evidence.greptile.mapping !== "score-5-of-5" && result.evidence.greptile.mapping !== "explicit-approved") {
|
|
1390
|
+
throw new Error(`Refusing to merge ${prUrl}: strict merge gate mapping is ${result.evidence.greptile.mapping}.`);
|
|
1391
|
+
}
|
|
1392
|
+
return headSha;
|
|
1393
|
+
}
|
|
1394
|
+
|
|
1368
1395
|
// packages/runtime/src/control-plane/provider/runtime-instructions.ts
|
|
1369
1396
|
var CLAUDE_ROUTER_TOOL_NAMES = [
|
|
1370
1397
|
"`mcp__rig_runtime_tools__read`",
|
|
@@ -1575,12 +1602,12 @@ var TASK_ARTIFACT_STAGE_FALLBACK = new Set([
|
|
|
1575
1602
|
"task-result.json",
|
|
1576
1603
|
"validation-summary.json"
|
|
1577
1604
|
]);
|
|
1578
|
-
function resolveHostRigBinDir(root) {
|
|
1579
|
-
return resolve11(root, ".rig", "bin");
|
|
1580
|
-
}
|
|
1581
1605
|
function isRuntimeGatewayGitPath(candidate) {
|
|
1582
1606
|
return /\/\.rig\/bin\/git$/.test(candidate.replace(/\\/g, "/"));
|
|
1583
1607
|
}
|
|
1608
|
+
function isRuntimeGatewayGhPath(candidate) {
|
|
1609
|
+
return /\/\.rig\/bin\/gh$/.test(candidate.replace(/\\/g, "/"));
|
|
1610
|
+
}
|
|
1584
1611
|
function resolveOptionalMonorepoRoot(projectRoot) {
|
|
1585
1612
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
1586
1613
|
if (runtimeWorkspace && existsSync9(resolve11(runtimeWorkspace, ".git"))) {
|
|
@@ -1615,6 +1642,9 @@ function resolveGitBinary(projectRoot) {
|
|
|
1615
1642
|
}
|
|
1616
1643
|
return "git";
|
|
1617
1644
|
}
|
|
1645
|
+
function escapeRegExp(value) {
|
|
1646
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1647
|
+
}
|
|
1618
1648
|
function safeCurrentTaskId(projectRoot) {
|
|
1619
1649
|
try {
|
|
1620
1650
|
const taskId = currentTaskId(projectRoot);
|
|
@@ -1828,10 +1858,11 @@ function gitOpenPr(options) {
|
|
|
1828
1858
|
"",
|
|
1829
1859
|
"## Task",
|
|
1830
1860
|
`- beads: ${taskId || "n/a"}`,
|
|
1861
|
+
...defaultPrRunLines(taskId, repoNameWithOwner),
|
|
1831
1862
|
"",
|
|
1832
1863
|
"## Review",
|
|
1833
1864
|
"- Completion verification will run validation, verifier review, and PR policy checks.",
|
|
1834
|
-
"- When repository policy allows it, Rig
|
|
1865
|
+
"- When repository policy allows it, Rig attempts an immediate strict-gated, head-locked merge after approval."
|
|
1835
1866
|
].join(`
|
|
1836
1867
|
`);
|
|
1837
1868
|
const preCheck = runCapture2(withGhRepo([gh, "pr", "list", "--state", "merged", "--head", branch, "--json", "url,mergedAt", "--jq", ".[0]"], repoNameWithOwner), repoRoot);
|
|
@@ -1919,6 +1950,30 @@ function gitOpenPr(options) {
|
|
|
1919
1950
|
}
|
|
1920
1951
|
return result;
|
|
1921
1952
|
}
|
|
1953
|
+
function defaultPrRunLines(taskId, repoNameWithOwner) {
|
|
1954
|
+
const lines = [];
|
|
1955
|
+
const runId = process.env.RIG_SERVER_RUN_ID?.trim();
|
|
1956
|
+
if (runId) {
|
|
1957
|
+
lines.push(`- Run: ${runId}`);
|
|
1958
|
+
}
|
|
1959
|
+
const closeout = defaultPrCloseoutLine(taskId, repoNameWithOwner);
|
|
1960
|
+
if (closeout) {
|
|
1961
|
+
lines.push(`- ${closeout}`);
|
|
1962
|
+
}
|
|
1963
|
+
return lines;
|
|
1964
|
+
}
|
|
1965
|
+
function defaultPrCloseoutLine(taskId, repoNameWithOwner) {
|
|
1966
|
+
const sourceIssueId = loadRuntimeContextFromEnv()?.sourceTask?.sourceIssueId;
|
|
1967
|
+
if (sourceIssueId) {
|
|
1968
|
+
const match = sourceIssueId.match(/^([^#]+)#(\d+)$/);
|
|
1969
|
+
if (match?.[1] && match[2]) {
|
|
1970
|
+
const sourceRepo = match[1];
|
|
1971
|
+
const issueNumber = match[2];
|
|
1972
|
+
return sourceRepo.toLowerCase() === repoNameWithOwner.toLowerCase() ? `Closes #${issueNumber}` : `Closes ${sourceRepo}#${issueNumber}`;
|
|
1973
|
+
}
|
|
1974
|
+
}
|
|
1975
|
+
return /^\d+$/.test(taskId) ? `Closes #${taskId}` : "";
|
|
1976
|
+
}
|
|
1922
1977
|
function resolveTaskBranchRef(projectRoot, taskId) {
|
|
1923
1978
|
return `rig/${resolveTaskBranchId(projectRoot, taskId)}`;
|
|
1924
1979
|
}
|
|
@@ -2003,61 +2058,45 @@ function gitMergePr(options) {
|
|
|
2003
2058
|
return { status: "already-merged", url: options.pr.url };
|
|
2004
2059
|
}
|
|
2005
2060
|
if (state !== "OPEN") {
|
|
2006
|
-
throw new Error(`Cannot
|
|
2061
|
+
throw new Error(`Cannot merge PR ${options.pr.url}: state is ${state}.`);
|
|
2007
2062
|
}
|
|
2008
2063
|
if (isDraft) {
|
|
2009
|
-
throw new Error(`Cannot
|
|
2064
|
+
throw new Error(`Cannot merge draft PR ${options.pr.url}.`);
|
|
2010
2065
|
}
|
|
2066
|
+
const strictGateHeadSha = strictMergeHeadShaFromGate(options.strictGate, options.pr.url);
|
|
2011
2067
|
const mergeArgs = withGhRepo([gh, "pr", "merge", options.pr.url], repoNameWithOwner);
|
|
2012
2068
|
const method = options.method || "squash";
|
|
2013
2069
|
mergeArgs.push(method === "merge" ? "--merge" : method === "rebase" ? "--rebase" : "--squash");
|
|
2070
|
+
mergeArgs.push("--match-head-commit", strictGateHeadSha);
|
|
2014
2071
|
if (options.deleteBranch !== false) {
|
|
2015
2072
|
mergeArgs.push("--delete-branch");
|
|
2016
2073
|
}
|
|
2017
|
-
const
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
}
|
|
2031
|
-
adminMergeArgs.push("--admin");
|
|
2032
|
-
const adminMerge = runCapture2(adminMergeArgs, repoRoot);
|
|
2033
|
-
if (adminMerge.exitCode === 0) {
|
|
2034
|
-
const postAdminMergeState = readPrViewState(gh, repoRoot, repoNameWithOwner, options.pr.url);
|
|
2035
|
-
if (postAdminMergeState.state === "MERGED" || postAdminMergeState.mergedAt) {
|
|
2036
|
-
console.log(`Merged PR (${options.pr.repoLabel}) with admin fallback: ${options.pr.url}`);
|
|
2037
|
-
return { status: "merged", url: options.pr.url };
|
|
2038
|
-
}
|
|
2039
|
-
throw new Error(`Admin merge command succeeded for PR ${options.pr.url} in ${options.pr.repoLabel}, but GitHub still reports it open.`);
|
|
2040
|
-
}
|
|
2041
|
-
const adminMergeMessage = `${adminMerge.stderr}
|
|
2042
|
-
${adminMerge.stdout}`.trim();
|
|
2043
|
-
if (!/admin|administrator|permission|not permitted|not allowed/i.test(adminMergeMessage)) {
|
|
2044
|
-
throw new Error(`Failed to admin-merge PR ${options.pr.url} in ${options.pr.repoLabel}: ${adminMergeMessage}`);
|
|
2045
|
-
}
|
|
2074
|
+
const directMerge = runCapture2(mergeArgs, repoRoot);
|
|
2075
|
+
if (directMerge.exitCode === 0) {
|
|
2076
|
+
console.log(`Merged PR (${options.pr.repoLabel}): ${options.pr.url}`);
|
|
2077
|
+
return { status: "merged", url: options.pr.url };
|
|
2078
|
+
}
|
|
2079
|
+
const postDirectState = readPrViewState(gh, repoRoot, repoNameWithOwner, options.pr.url);
|
|
2080
|
+
if (canAdminMergeApprovedPr(postDirectState)) {
|
|
2081
|
+
const adminMergeArgs = [...mergeArgs, "--admin"];
|
|
2082
|
+
const adminMerge = runCapture2(adminMergeArgs, repoRoot);
|
|
2083
|
+
if (adminMerge.exitCode === 0) {
|
|
2084
|
+
const postAdminMergeState = readPrViewState(gh, repoRoot, repoNameWithOwner, options.pr.url);
|
|
2085
|
+
if (postAdminMergeState.state === "MERGED" || postAdminMergeState.mergedAt) {
|
|
2086
|
+
console.log(`Merged PR (${options.pr.repoLabel}) with admin fallback: ${options.pr.url}`);
|
|
2087
|
+
return { status: "merged", url: options.pr.url };
|
|
2046
2088
|
}
|
|
2047
|
-
|
|
2048
|
-
|
|
2089
|
+
throw new Error(`Admin merge command succeeded for PR ${options.pr.url} in ${options.pr.repoLabel}, but GitHub still reports it open.`);
|
|
2090
|
+
}
|
|
2091
|
+
const adminMergeMessage = `${adminMerge.stderr}
|
|
2092
|
+
${adminMerge.stdout}`.trim();
|
|
2093
|
+
if (!/admin|administrator|permission|not permitted|not allowed/i.test(adminMergeMessage)) {
|
|
2094
|
+
throw new Error(`Failed to admin-merge PR ${options.pr.url} in ${options.pr.repoLabel}: ${adminMergeMessage}`);
|
|
2049
2095
|
}
|
|
2050
|
-
throw new Error(`Auto-merge command succeeded for PR ${options.pr.url} in ${options.pr.repoLabel}, but GitHub did not report a merged or auto-merge-enabled state.`);
|
|
2051
|
-
}
|
|
2052
|
-
const autoMergeMessage = `${autoMerge.stderr}
|
|
2053
|
-
${autoMerge.stdout}`.trim();
|
|
2054
|
-
const autoMergeUnsupported = /auto.?merge.*(not enabled|not allowed|disabled|unsupported)|enablePullRequestAutoMerge|Auto merge is not allowed/i.test(autoMergeMessage);
|
|
2055
|
-
if (!autoMergeUnsupported) {
|
|
2056
|
-
throw new Error(`Failed to auto-merge PR ${options.pr.url} in ${options.pr.repoLabel}: ${autoMergeMessage}`);
|
|
2057
2096
|
}
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2097
|
+
const directMergeMessage = `${directMerge.stderr}
|
|
2098
|
+
${directMerge.stdout}`.trim();
|
|
2099
|
+
throw new Error(`Failed to merge PR ${options.pr.url} in ${options.pr.repoLabel}: ${directMergeMessage}`);
|
|
2061
2100
|
}
|
|
2062
2101
|
function assertPrHasNoGitConflicts(prState, repoLabel, baseRef) {
|
|
2063
2102
|
const mergeable = prState.mergeable.toUpperCase();
|
|
@@ -2169,32 +2208,19 @@ function resolveGithubCliBinary(projectRoot) {
|
|
|
2169
2208
|
if (explicit) {
|
|
2170
2209
|
candidates.add(explicit);
|
|
2171
2210
|
}
|
|
2211
|
+
for (const candidate of ["/usr/bin/gh", "/opt/homebrew/bin/gh", "/usr/local/bin/gh"]) {
|
|
2212
|
+
candidates.add(candidate);
|
|
2213
|
+
}
|
|
2172
2214
|
const explicitPathEntries = (process.env.PATH || "").split(":").map((entry) => entry.trim()).filter(Boolean);
|
|
2173
2215
|
for (const entry of explicitPathEntries) {
|
|
2174
2216
|
candidates.add(resolve11(entry, "gh"));
|
|
2175
2217
|
}
|
|
2176
|
-
const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim();
|
|
2177
|
-
if (hostProjectRoot) {
|
|
2178
|
-
candidates.add(resolve11(resolveHostRigBinDir(hostProjectRoot), "gh"));
|
|
2179
|
-
}
|
|
2180
|
-
candidates.add(resolve11(resolveHostRigBinDir(projectRoot), "gh"));
|
|
2181
|
-
const runtimeContext = loadRuntimeContextFromEnv();
|
|
2182
|
-
if (runtimeContext?.binDir) {
|
|
2183
|
-
candidates.add(resolve11(runtimeContext.binDir, "gh"));
|
|
2184
|
-
}
|
|
2185
|
-
const runtimeHome = process.env.RIG_RUNTIME_HOME?.trim();
|
|
2186
|
-
if (runtimeHome) {
|
|
2187
|
-
candidates.add(resolve11(runtimeHome, "bin", "gh"));
|
|
2188
|
-
}
|
|
2189
|
-
for (const candidate of ["/opt/homebrew/bin/gh", "/usr/local/bin/gh", "/usr/bin/gh"]) {
|
|
2190
|
-
candidates.add(candidate);
|
|
2191
|
-
}
|
|
2192
2218
|
const bunResolved = Bun.which("gh");
|
|
2193
2219
|
if (bunResolved) {
|
|
2194
2220
|
candidates.add(bunResolved);
|
|
2195
2221
|
}
|
|
2196
2222
|
for (const candidate of candidates) {
|
|
2197
|
-
if (candidate && existsSync9(candidate)) {
|
|
2223
|
+
if (candidate && existsSync9(candidate) && !isRuntimeGatewayGhPath(candidate)) {
|
|
2198
2224
|
return candidate;
|
|
2199
2225
|
}
|
|
2200
2226
|
}
|