@h-rig/runtime 0.0.6-alpha.1 → 0.0.6-alpha.11
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 +133 -14
- package/dist/bin/rig-agent.js +83 -26
- package/dist/src/control-plane/agent-wrapper.js +133 -14
- package/dist/src/control-plane/harness-main.js +83 -26
- package/dist/src/control-plane/hooks/completion-verification.js +85 -28
- package/dist/src/control-plane/hooks/inject-context.js +2 -2
- package/dist/src/control-plane/hooks/submodule-branch.js +26 -3
- package/dist/src/control-plane/hooks/task-runtime-start.js +26 -3
- package/dist/src/control-plane/native/git-ops.js +81 -24
- package/dist/src/control-plane/native/harness-cli.js +83 -26
- package/dist/src/control-plane/native/pr-automation.js +87 -16
- package/dist/src/control-plane/native/run-ops.js +23 -6
- package/dist/src/control-plane/native/task-ops.js +2 -2
- package/dist/src/control-plane/native/validator.js +2 -2
- package/dist/src/control-plane/native/verifier.js +2 -2
- package/dist/src/control-plane/runtime/index.js +38 -9
- package/dist/src/control-plane/runtime/isolation/home.js +31 -6
- package/dist/src/control-plane/runtime/isolation/index.js +38 -9
- package/dist/src/control-plane/runtime/isolation/runner.js +31 -6
- package/dist/src/control-plane/runtime/isolation/shared.js +9 -6
- package/dist/src/control-plane/runtime/isolation.js +38 -9
- package/dist/src/control-plane/runtime/queue.js +38 -9
- package/dist/src/control-plane/tasks/source-aware-task-config-source.js +14 -2
- package/dist/src/control-plane/tasks/source-lifecycle.js +2 -2
- package/dist/src/index.js +15 -13
- package/dist/src/local-server.js +20 -14
- package/native/darwin-arm64/{bin/rig-git → rig-git} +0 -0
- package/native/darwin-arm64/rig-git.build-manifest.json +4 -0
- package/native/darwin-arm64/{bin/rig-shell → rig-shell} +0 -0
- package/native/darwin-arm64/rig-shell.build-manifest.json +4 -0
- package/native/darwin-arm64/{bin/rig-tools → rig-tools} +0 -0
- package/native/darwin-arm64/rig-tools.build-manifest.json +4 -0
- package/native/darwin-arm64/{lib/runtime-native.dylib → runtime-native.dylib} +0 -0
- package/package.json +6 -6
- package/native/darwin-arm64/lib/runtime-native-darwin-arm64.dylib +0 -0
- package/native/darwin-arm64/manifest.json +0 -1
- package/native/linux-x64/bin/rig-git +0 -0
- package/native/linux-x64/bin/rig-shell +0 -0
- package/native/linux-x64/bin/rig-tools +0 -0
- package/native/linux-x64/lib/runtime-native-linux-x64.so +0 -0
- package/native/linux-x64/lib/runtime-native.so +0 -0
- package/native/linux-x64/manifest.json +0 -1
|
@@ -2951,6 +2951,17 @@ async function readSourceAwareTaskStatus(projectRoot, taskId, options = {}) {
|
|
|
2951
2951
|
return null;
|
|
2952
2952
|
}
|
|
2953
2953
|
}
|
|
2954
|
+
function updateGithubIssueTaskBySourceIssueId(sourceIssueId, taskId, update, options = {}) {
|
|
2955
|
+
const parsed = sourceIssueId?.trim().match(/^([^/]+)\/([^#]+)#(\d+)$/);
|
|
2956
|
+
if (!parsed || parsed[3] !== taskId) {
|
|
2957
|
+
return false;
|
|
2958
|
+
}
|
|
2959
|
+
applyGithubIssueUpdate(options.ghBinary ?? "gh", options.spawn ?? spawnSync, parsed[3], {
|
|
2960
|
+
sourceIssueId: sourceIssueId.trim(),
|
|
2961
|
+
taskSource: { kind: "github-issues", owner: parsed[1], repo: parsed[2] }
|
|
2962
|
+
}, update);
|
|
2963
|
+
return true;
|
|
2964
|
+
}
|
|
2954
2965
|
function updateSourceAwareTaskConfigTask(projectRoot, taskId, update, options = {}) {
|
|
2955
2966
|
const configPath = options.configPath ?? resolve13(projectRoot, ".rig", "task-config.json");
|
|
2956
2967
|
const rawEntry = readRawTaskEntry(configPath, taskId);
|
|
@@ -3306,8 +3317,8 @@ function ensureStatusLabel(bin, repo, spawnFn, label) {
|
|
|
3306
3317
|
}
|
|
3307
3318
|
}
|
|
3308
3319
|
function selectedGitHubEnv() {
|
|
3309
|
-
const token = process.env.RIG_GITHUB_SELECTED_TOKEN?.trim()
|
|
3310
|
-
return { GH_TOKEN: token, GITHUB_TOKEN: token };
|
|
3320
|
+
const token = process.env.RIG_GITHUB_SELECTED_TOKEN?.trim() || process.env.RIG_GITHUB_TOKEN?.trim() || "";
|
|
3321
|
+
return { GH_TOKEN: token, GITHUB_TOKEN: token, RIG_GITHUB_TOKEN: token };
|
|
3311
3322
|
}
|
|
3312
3323
|
function ghSpawnOptions() {
|
|
3313
3324
|
return { encoding: "utf-8", env: { ...process.env, ...selectedGitHubEnv() } };
|
|
@@ -5710,20 +5721,23 @@ function hashProjectPath(workspaceDir) {
|
|
|
5710
5721
|
}
|
|
5711
5722
|
function resolveGithubCliBinaryPath() {
|
|
5712
5723
|
const explicit = process.env.RIG_GH_BIN?.trim();
|
|
5713
|
-
if (explicit && existsSync23(explicit)) {
|
|
5724
|
+
if (explicit && existsSync23(explicit) && !isRuntimeGatewayGhPath(explicit)) {
|
|
5714
5725
|
return explicit;
|
|
5715
5726
|
}
|
|
5716
|
-
const
|
|
5717
|
-
if (bunResolved && existsSync23(bunResolved)) {
|
|
5718
|
-
return bunResolved;
|
|
5719
|
-
}
|
|
5720
|
-
for (const candidate of ["/opt/homebrew/bin/gh", "/usr/local/bin/gh", "/usr/bin/gh"]) {
|
|
5727
|
+
for (const candidate of ["/usr/bin/gh", "/opt/homebrew/bin/gh", "/usr/local/bin/gh"]) {
|
|
5721
5728
|
if (existsSync23(candidate)) {
|
|
5722
5729
|
return candidate;
|
|
5723
5730
|
}
|
|
5724
5731
|
}
|
|
5732
|
+
const bunResolved = Bun.which("gh");
|
|
5733
|
+
if (bunResolved && existsSync23(bunResolved) && !isRuntimeGatewayGhPath(bunResolved)) {
|
|
5734
|
+
return bunResolved;
|
|
5735
|
+
}
|
|
5725
5736
|
return "";
|
|
5726
5737
|
}
|
|
5738
|
+
function isRuntimeGatewayGhPath(candidate) {
|
|
5739
|
+
return /\/\.rig\/bin\/gh$/.test(candidate.replace(/\\/g, "/"));
|
|
5740
|
+
}
|
|
5727
5741
|
async function resolveGithubCliAuthToken(ghBinary = "") {
|
|
5728
5742
|
const gh = ghBinary || resolveGithubCliBinaryPath();
|
|
5729
5743
|
if (!gh) {
|
|
@@ -5824,6 +5838,8 @@ async function runtimeEnv(projectRoot, runtime) {
|
|
|
5824
5838
|
XDG_CACHE_HOME: runtime.cacheDir,
|
|
5825
5839
|
XDG_STATE_HOME: runtime.stateDir,
|
|
5826
5840
|
RIG_AGENT_ID: runtime.id,
|
|
5841
|
+
...process.env.RIG_RUN_ID?.trim() ? { RIG_RUN_ID: process.env.RIG_RUN_ID.trim() } : {},
|
|
5842
|
+
...process.env.RIG_SERVER_RUN_ID?.trim() ? { RIG_SERVER_RUN_ID: process.env.RIG_SERVER_RUN_ID.trim() } : {},
|
|
5827
5843
|
RIG_TASK_ID: runtime.taskId,
|
|
5828
5844
|
RIG_TASK_RUNTIME_ID: runtime.id,
|
|
5829
5845
|
RIG_TASK_WORKSPACE: runtime.workspaceDir,
|
|
@@ -5887,6 +5903,10 @@ async function runtimeEnv(projectRoot, runtime) {
|
|
|
5887
5903
|
env[key] = value;
|
|
5888
5904
|
}
|
|
5889
5905
|
}
|
|
5906
|
+
const rigGithubToken = process.env.RIG_GITHUB_TOKEN?.trim() || "";
|
|
5907
|
+
if (rigGithubToken && !env.GITHUB_TOKEN && !env.GH_TOKEN) {
|
|
5908
|
+
env.GITHUB_TOKEN = rigGithubToken;
|
|
5909
|
+
}
|
|
5890
5910
|
const fallbackGithubToken = !env.GITHUB_TOKEN && !env.GH_TOKEN ? await resolveGithubCliAuthToken(hostGhBinary) : "";
|
|
5891
5911
|
if (fallbackGithubToken) {
|
|
5892
5912
|
env.GITHUB_TOKEN = fallbackGithubToken;
|
|
@@ -5897,6 +5917,13 @@ async function runtimeEnv(projectRoot, runtime) {
|
|
|
5897
5917
|
if (!env.GH_TOKEN && env.GITHUB_TOKEN) {
|
|
5898
5918
|
env.GH_TOKEN = env.GITHUB_TOKEN;
|
|
5899
5919
|
}
|
|
5920
|
+
const gitHubToken = env.GITHUB_TOKEN || env.GH_TOKEN || rigGithubToken;
|
|
5921
|
+
if (gitHubToken) {
|
|
5922
|
+
env.RIG_GITHUB_TOKEN = gitHubToken;
|
|
5923
|
+
env.GITHUB_TOKEN = env.GITHUB_TOKEN || gitHubToken;
|
|
5924
|
+
env.GH_TOKEN = env.GH_TOKEN || gitHubToken;
|
|
5925
|
+
applyGitHubCredentialHelperEnv(env);
|
|
5926
|
+
}
|
|
5900
5927
|
if (!env.GREPTILE_GITHUB_TOKEN && env.GITHUB_TOKEN) {
|
|
5901
5928
|
env.GREPTILE_GITHUB_TOKEN = env.GITHUB_TOKEN;
|
|
5902
5929
|
}
|
|
@@ -5977,12 +6004,21 @@ async function materializeRuntimeCertBundle(runtime) {
|
|
|
5977
6004
|
}
|
|
5978
6005
|
return targetPath;
|
|
5979
6006
|
}
|
|
6007
|
+
function applyGitHubCredentialHelperEnv(env) {
|
|
6008
|
+
env.GIT_TERMINAL_PROMPT = "0";
|
|
6009
|
+
env.GIT_CONFIG_COUNT = "2";
|
|
6010
|
+
env.GIT_CONFIG_KEY_0 = "credential.helper";
|
|
6011
|
+
env.GIT_CONFIG_VALUE_0 = "";
|
|
6012
|
+
env.GIT_CONFIG_KEY_1 = "credential.helper";
|
|
6013
|
+
env.GIT_CONFIG_VALUE_1 = '!f() { test "$1" = get || exit 0; token="${GITHUB_TOKEN:-${GH_TOKEN:-${RIG_GITHUB_TOKEN:-}}}"; test -n "$token" || exit 0; echo username=x-access-token; echo password="$token"; }; f';
|
|
6014
|
+
}
|
|
5980
6015
|
function persistRuntimeSecrets(runtimeRoot, env) {
|
|
5981
6016
|
const secretsPath = resolve25(runtimeRoot, "runtime-secrets.json");
|
|
5982
6017
|
const persisted = {};
|
|
5983
6018
|
for (const key of [
|
|
5984
6019
|
"GITHUB_TOKEN",
|
|
5985
6020
|
"GH_TOKEN",
|
|
6021
|
+
"RIG_GITHUB_TOKEN",
|
|
5986
6022
|
"GREPTILE_GITHUB_TOKEN",
|
|
5987
6023
|
"GREPTILE_API_KEY",
|
|
5988
6024
|
"AI_REVIEW_MODE",
|
|
@@ -8461,7 +8497,11 @@ async function ensureAgentRuntime(options) {
|
|
|
8461
8497
|
mkdirSync18(runtime.binDir, { recursive: true });
|
|
8462
8498
|
mkdirSync18(workspaceLayout.distDir, { recursive: true });
|
|
8463
8499
|
prepareRuntimeWorkspace(options.projectRoot, workspaceDir);
|
|
8464
|
-
|
|
8500
|
+
if (options.preserveTaskArtifacts) {
|
|
8501
|
+
console.log(`[rig-agent] Preserving runtime task artifacts for resume of ${options.taskId}.`);
|
|
8502
|
+
} else {
|
|
8503
|
+
await resetEphemeralTaskArtifacts(workspaceDir, options.taskId);
|
|
8504
|
+
}
|
|
8465
8505
|
const ctx = {
|
|
8466
8506
|
runtimeId: options.id,
|
|
8467
8507
|
taskId: options.taskId,
|
|
@@ -9173,7 +9213,8 @@ async function runAgentWrapper(options = {}) {
|
|
|
9173
9213
|
taskId,
|
|
9174
9214
|
mode: "worktree",
|
|
9175
9215
|
provider,
|
|
9176
|
-
taskRecordReader: taskRecordReaderFromEnv(taskId)
|
|
9216
|
+
taskRecordReader: taskRecordReaderFromEnv(taskId),
|
|
9217
|
+
preserveTaskArtifacts: process.env.RIG_RUN_RESUME === "1" || process.env.RIG_RUNTIME_ARTIFACT_CLEANUP === "preserve"
|
|
9177
9218
|
});
|
|
9178
9219
|
emitWrapperEvent("runtime.provision.completed", {
|
|
9179
9220
|
runtimeId: runtime.id,
|
|
@@ -9193,6 +9234,18 @@ async function runAgentWrapper(options = {}) {
|
|
|
9193
9234
|
console.error(`[rig-agent] Failed to provision runtime: ${error}`);
|
|
9194
9235
|
return 1;
|
|
9195
9236
|
}
|
|
9237
|
+
try {
|
|
9238
|
+
await waitForDirtyBaselineReady(runtime, taskId);
|
|
9239
|
+
} catch (error) {
|
|
9240
|
+
emitWrapperEvent("runtime.baseline.failed", {
|
|
9241
|
+
runtimeId: runtime.id,
|
|
9242
|
+
taskId,
|
|
9243
|
+
workspaceDir: runtime.workspaceDir,
|
|
9244
|
+
error: error instanceof Error ? error.message : String(error)
|
|
9245
|
+
});
|
|
9246
|
+
console.error(`[rig-agent] Failed to apply selected baseline before provider launch: ${error}`);
|
|
9247
|
+
return 1;
|
|
9248
|
+
}
|
|
9196
9249
|
const providerArgs = buildProviderArgs(provider, runtime, argv);
|
|
9197
9250
|
const providerCommand = [providerBinary(provider), ...providerArgs];
|
|
9198
9251
|
emitWrapperEvent("provider.launch", {
|
|
@@ -9324,12 +9377,16 @@ function buildProviderArgs(provider, runtime, argv) {
|
|
|
9324
9377
|
}
|
|
9325
9378
|
if (provider === "pi") {
|
|
9326
9379
|
const piArgs = [...argv];
|
|
9380
|
+
const piProvider = cliOptionValue(piArgs, "--provider") || process.env.RIG_PI_PROVIDER?.trim() || "openai-codex";
|
|
9327
9381
|
if (!hasCliOption(piArgs, "--provider")) {
|
|
9328
|
-
piArgs.unshift(
|
|
9382
|
+
piArgs.unshift(piProvider);
|
|
9329
9383
|
piArgs.unshift("--provider");
|
|
9330
9384
|
}
|
|
9331
|
-
|
|
9332
|
-
|
|
9385
|
+
const model = cliOptionValue(piArgs, "--model") || process.env.RIG_PI_MODEL?.trim() || "gpt-5.5";
|
|
9386
|
+
if (hasCliOption(piArgs, "--model")) {
|
|
9387
|
+
rewriteCliOptionValue(piArgs, "--model", normalizePiModelForProvider(model, piProvider));
|
|
9388
|
+
} else {
|
|
9389
|
+
piArgs.unshift(normalizePiModelForProvider(model, piProvider));
|
|
9333
9390
|
piArgs.unshift("--model");
|
|
9334
9391
|
}
|
|
9335
9392
|
return piArgs;
|
|
@@ -9397,6 +9454,38 @@ function resolveProvider() {
|
|
|
9397
9454
|
function hasCliOption(argv, option) {
|
|
9398
9455
|
return argv.some((arg) => arg === option || arg.startsWith(`${option}=`));
|
|
9399
9456
|
}
|
|
9457
|
+
function cliOptionValue(argv, option) {
|
|
9458
|
+
for (let index = 0;index < argv.length; index += 1) {
|
|
9459
|
+
const arg = argv[index];
|
|
9460
|
+
if (arg === option) {
|
|
9461
|
+
const next = argv[index + 1];
|
|
9462
|
+
return next && !next.startsWith("--") ? next : undefined;
|
|
9463
|
+
}
|
|
9464
|
+
if (arg?.startsWith(`${option}=`)) {
|
|
9465
|
+
return arg.slice(option.length + 1);
|
|
9466
|
+
}
|
|
9467
|
+
}
|
|
9468
|
+
return;
|
|
9469
|
+
}
|
|
9470
|
+
function rewriteCliOptionValue(argv, option, value) {
|
|
9471
|
+
for (let index = 0;index < argv.length; index += 1) {
|
|
9472
|
+
const arg = argv[index];
|
|
9473
|
+
if (arg === option && argv[index + 1] && !argv[index + 1].startsWith("--")) {
|
|
9474
|
+
argv[index + 1] = value;
|
|
9475
|
+
return;
|
|
9476
|
+
}
|
|
9477
|
+
if (arg?.startsWith(`${option}=`)) {
|
|
9478
|
+
argv[index] = `${option}=${value}`;
|
|
9479
|
+
return;
|
|
9480
|
+
}
|
|
9481
|
+
}
|
|
9482
|
+
}
|
|
9483
|
+
function normalizePiModelForProvider(model, provider) {
|
|
9484
|
+
if (provider === "openrouter" && model === "openai-codex/gpt-5.5") {
|
|
9485
|
+
return "openai/gpt-5.5";
|
|
9486
|
+
}
|
|
9487
|
+
return model;
|
|
9488
|
+
}
|
|
9400
9489
|
function providerBinary(provider) {
|
|
9401
9490
|
if (provider === "codex") {
|
|
9402
9491
|
return Bun.which("codex") || "codex";
|
|
@@ -9413,6 +9502,34 @@ function providerBinary(provider) {
|
|
|
9413
9502
|
function emitWrapperEvent(type, payload) {
|
|
9414
9503
|
console.log(`__RIG_WRAPPER_EVENT__${JSON.stringify({ type, payload, at: new Date().toISOString() })}`);
|
|
9415
9504
|
}
|
|
9505
|
+
function sleep(ms) {
|
|
9506
|
+
return new Promise((resolveSleep) => setTimeout(resolveSleep, ms));
|
|
9507
|
+
}
|
|
9508
|
+
async function waitForDirtyBaselineReady(runtime, taskId) {
|
|
9509
|
+
const readyFile = process.env.RIG_DIRTY_BASELINE_READY_FILE?.trim();
|
|
9510
|
+
if (process.env.RIG_BASELINE_MODE !== "dirty-snapshot" || !readyFile)
|
|
9511
|
+
return;
|
|
9512
|
+
const timeoutMs = Number.parseInt(process.env.RIG_DIRTY_BASELINE_TIMEOUT_MS ?? "30000", 10);
|
|
9513
|
+
const deadline = Date.now() + (Number.isFinite(timeoutMs) && timeoutMs > 0 ? timeoutMs : 30000);
|
|
9514
|
+
emitWrapperEvent("runtime.baseline.waiting", {
|
|
9515
|
+
runtimeId: runtime.id,
|
|
9516
|
+
taskId,
|
|
9517
|
+
workspaceDir: runtime.workspaceDir,
|
|
9518
|
+
readyFile
|
|
9519
|
+
});
|
|
9520
|
+
while (!existsSync33(readyFile)) {
|
|
9521
|
+
if (Date.now() >= deadline) {
|
|
9522
|
+
throw new Error(`Timed out waiting for dirty baseline ready file: ${readyFile}`);
|
|
9523
|
+
}
|
|
9524
|
+
await sleep(50);
|
|
9525
|
+
}
|
|
9526
|
+
emitWrapperEvent("runtime.baseline.completed", {
|
|
9527
|
+
runtimeId: runtime.id,
|
|
9528
|
+
taskId,
|
|
9529
|
+
workspaceDir: runtime.workspaceDir,
|
|
9530
|
+
readyFile
|
|
9531
|
+
});
|
|
9532
|
+
}
|
|
9416
9533
|
async function resolveTaskId(projectRoot, monorepoRoot) {
|
|
9417
9534
|
if (process.env.RIG_TASK_ID) {
|
|
9418
9535
|
return process.env.RIG_TASK_ID;
|
|
@@ -9488,7 +9605,9 @@ async function updateTaskSourceAfterRun(projectRoot, taskId, runtime) {
|
|
|
9488
9605
|
} catch (error) {
|
|
9489
9606
|
let fallbackUpdated = false;
|
|
9490
9607
|
try {
|
|
9491
|
-
|
|
9608
|
+
const sourceIssueId = loadRuntimeContextFromEnv()?.sourceTask?.sourceIssueId;
|
|
9609
|
+
fallbackUpdated = updateGithubIssueTaskBySourceIssueId(sourceIssueId, taskId, { status: "closed", comment });
|
|
9610
|
+
fallbackUpdated = updateSourceAwareTaskConfigTask(projectRoot, taskId, { status: "closed", comment }) || fallbackUpdated;
|
|
9492
9611
|
} catch (fallbackError) {
|
|
9493
9612
|
console.error(`[rig-agent] Source-aware compatibility update also failed for ${taskId}: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`);
|
|
9494
9613
|
}
|
|
@@ -1203,8 +1203,8 @@ function githubStatusFor(issue) {
|
|
|
1203
1203
|
return "open";
|
|
1204
1204
|
}
|
|
1205
1205
|
function selectedGitHubEnv() {
|
|
1206
|
-
const token = process.env.RIG_GITHUB_SELECTED_TOKEN?.trim()
|
|
1207
|
-
return { GH_TOKEN: token, GITHUB_TOKEN: token };
|
|
1206
|
+
const token = process.env.RIG_GITHUB_SELECTED_TOKEN?.trim() || process.env.RIG_GITHUB_TOKEN?.trim() || "";
|
|
1207
|
+
return { GH_TOKEN: token, GITHUB_TOKEN: token, RIG_GITHUB_TOKEN: token };
|
|
1208
1208
|
}
|
|
1209
1209
|
function ghSpawnOptions() {
|
|
1210
1210
|
return { encoding: "utf-8", env: { ...process.env, ...selectedGitHubEnv() } };
|
|
@@ -5989,12 +5989,12 @@ var TASK_ARTIFACT_STAGE_FALLBACK = new Set([
|
|
|
5989
5989
|
"task-result.json",
|
|
5990
5990
|
"validation-summary.json"
|
|
5991
5991
|
]);
|
|
5992
|
-
function resolveHostRigBinDir(root) {
|
|
5993
|
-
return resolve24(root, ".rig", "bin");
|
|
5994
|
-
}
|
|
5995
5992
|
function isRuntimeGatewayGitPath(candidate) {
|
|
5996
5993
|
return /\/\.rig\/bin\/git$/.test(candidate.replace(/\\/g, "/"));
|
|
5997
5994
|
}
|
|
5995
|
+
function isRuntimeGatewayGhPath(candidate) {
|
|
5996
|
+
return /\/\.rig\/bin\/gh$/.test(candidate.replace(/\\/g, "/"));
|
|
5997
|
+
}
|
|
5998
5998
|
function resolveOptionalMonorepoRoot(projectRoot) {
|
|
5999
5999
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
6000
6000
|
if (runtimeWorkspace && existsSync21(resolve24(runtimeWorkspace, ".git"))) {
|
|
@@ -6029,6 +6029,9 @@ function resolveGitBinary(projectRoot) {
|
|
|
6029
6029
|
}
|
|
6030
6030
|
return "git";
|
|
6031
6031
|
}
|
|
6032
|
+
function escapeRegExp2(value) {
|
|
6033
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6034
|
+
}
|
|
6032
6035
|
function safeCurrentTaskId(projectRoot) {
|
|
6033
6036
|
try {
|
|
6034
6037
|
const taskId = currentTaskId(projectRoot);
|
|
@@ -6187,17 +6190,15 @@ function gitOpenPr(options) {
|
|
|
6187
6190
|
const target = options.target || (taskId ? "monorepo" : "project");
|
|
6188
6191
|
let repoRoot = options.projectRoot;
|
|
6189
6192
|
let repoLabel = "project-rig";
|
|
6190
|
-
|
|
6193
|
+
const envBase = target === "monorepo" ? process.env.RIG_PR_BASE_MONOREPO?.trim() || "" : process.env.RIG_PR_BASE_PROJECT?.trim() || "";
|
|
6191
6194
|
if (target === "monorepo") {
|
|
6192
6195
|
repoRoot = resolveOptionalMonorepoRoot(options.projectRoot) || resolveMonorepoRoot2(options.projectRoot);
|
|
6193
6196
|
repoLabel = "monorepo";
|
|
6194
|
-
defaultBase = process.env.RIG_PR_BASE_MONOREPO || "main";
|
|
6195
6197
|
if (taskId) {
|
|
6196
6198
|
gitSyncBranch(options.projectRoot, taskId, "monorepo");
|
|
6197
6199
|
}
|
|
6198
6200
|
} else if (taskId) {
|
|
6199
6201
|
gitSyncBranch(options.projectRoot, taskId, "project");
|
|
6200
|
-
defaultBase = inferProjectBase(options.projectRoot, defaultBase);
|
|
6201
6202
|
}
|
|
6202
6203
|
if (!existsSync21(resolve24(repoRoot, ".git"))) {
|
|
6203
6204
|
throw new Error(`Repository not available for open-pr target ${target}: ${repoRoot}`);
|
|
@@ -6206,9 +6207,9 @@ function gitOpenPr(options) {
|
|
|
6206
6207
|
if (!branch || branch === "HEAD") {
|
|
6207
6208
|
throw new Error(`Cannot open PR from detached HEAD in ${repoLabel}. Checkout a branch first.`);
|
|
6208
6209
|
}
|
|
6209
|
-
const base = options.base || defaultBase;
|
|
6210
6210
|
const repoNameWithOwner = resolveRepoNameWithOwner(options.projectRoot, repoRoot);
|
|
6211
6211
|
const networkRemote = resolveNetworkRemoteName(options.projectRoot, repoRoot, repoNameWithOwner);
|
|
6212
|
+
const base = options.base || envBase || inferRepositoryDefaultBase(options.projectRoot, repoRoot, repoNameWithOwner, networkRemote, target === "project" ? inferProjectBase(options.projectRoot, "main") : "main");
|
|
6212
6213
|
refreshRemoteBaseRef(options.projectRoot, repoRoot, base);
|
|
6213
6214
|
let reviewer = (options.reviewer || "").trim();
|
|
6214
6215
|
let reviewerSource = reviewer ? "flag" : undefined;
|
|
@@ -6244,6 +6245,7 @@ function gitOpenPr(options) {
|
|
|
6244
6245
|
"",
|
|
6245
6246
|
"## Task",
|
|
6246
6247
|
`- beads: ${taskId || "n/a"}`,
|
|
6248
|
+
...defaultPrRunLines(taskId, repoNameWithOwner),
|
|
6247
6249
|
"",
|
|
6248
6250
|
"## Review",
|
|
6249
6251
|
"- Completion verification will run validation, verifier review, and PR policy checks.",
|
|
@@ -6335,6 +6337,29 @@ function gitOpenPr(options) {
|
|
|
6335
6337
|
}
|
|
6336
6338
|
return result;
|
|
6337
6339
|
}
|
|
6340
|
+
function defaultPrRunLines(taskId, repoNameWithOwner) {
|
|
6341
|
+
const lines = [];
|
|
6342
|
+
const runId = process.env.RIG_SERVER_RUN_ID?.trim();
|
|
6343
|
+
if (runId) {
|
|
6344
|
+
lines.push(`- Run: ${runId}`);
|
|
6345
|
+
}
|
|
6346
|
+
const closeout = defaultPrCloseoutLine(taskId, repoNameWithOwner);
|
|
6347
|
+
if (closeout) {
|
|
6348
|
+
lines.push(`- ${closeout}`);
|
|
6349
|
+
}
|
|
6350
|
+
return lines;
|
|
6351
|
+
}
|
|
6352
|
+
function defaultPrCloseoutLine(taskId, repoNameWithOwner) {
|
|
6353
|
+
const sourceIssueId = loadRuntimeContextFromEnv()?.sourceTask?.sourceIssueId;
|
|
6354
|
+
if (sourceIssueId) {
|
|
6355
|
+
const match = sourceIssueId.match(/^([^#]+)#(\d+)$/);
|
|
6356
|
+
if (match) {
|
|
6357
|
+
const [, sourceRepo, issueNumber] = match;
|
|
6358
|
+
return sourceRepo.toLowerCase() === repoNameWithOwner.toLowerCase() ? `Closes #${issueNumber}` : `Closes ${sourceRepo}#${issueNumber}`;
|
|
6359
|
+
}
|
|
6360
|
+
}
|
|
6361
|
+
return /^\d+$/.test(taskId) ? `Closes #${taskId}` : "";
|
|
6362
|
+
}
|
|
6338
6363
|
function readPrViewState(gh, repoRoot, repoNameWithOwner, prUrl) {
|
|
6339
6364
|
const view = runCapture2(withGhRepo([
|
|
6340
6365
|
gh,
|
|
@@ -6485,32 +6510,19 @@ function resolveGithubCliBinary(projectRoot) {
|
|
|
6485
6510
|
if (explicit) {
|
|
6486
6511
|
candidates.add(explicit);
|
|
6487
6512
|
}
|
|
6513
|
+
for (const candidate of ["/usr/bin/gh", "/opt/homebrew/bin/gh", "/usr/local/bin/gh"]) {
|
|
6514
|
+
candidates.add(candidate);
|
|
6515
|
+
}
|
|
6488
6516
|
const explicitPathEntries = (process.env.PATH || "").split(":").map((entry) => entry.trim()).filter(Boolean);
|
|
6489
6517
|
for (const entry of explicitPathEntries) {
|
|
6490
6518
|
candidates.add(resolve24(entry, "gh"));
|
|
6491
6519
|
}
|
|
6492
|
-
const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim();
|
|
6493
|
-
if (hostProjectRoot) {
|
|
6494
|
-
candidates.add(resolve24(resolveHostRigBinDir(hostProjectRoot), "gh"));
|
|
6495
|
-
}
|
|
6496
|
-
candidates.add(resolve24(resolveHostRigBinDir(projectRoot), "gh"));
|
|
6497
|
-
const runtimeContext = loadRuntimeContextFromEnv();
|
|
6498
|
-
if (runtimeContext?.binDir) {
|
|
6499
|
-
candidates.add(resolve24(runtimeContext.binDir, "gh"));
|
|
6500
|
-
}
|
|
6501
|
-
const runtimeHome = process.env.RIG_RUNTIME_HOME?.trim();
|
|
6502
|
-
if (runtimeHome) {
|
|
6503
|
-
candidates.add(resolve24(runtimeHome, "bin", "gh"));
|
|
6504
|
-
}
|
|
6505
|
-
for (const candidate of ["/opt/homebrew/bin/gh", "/usr/local/bin/gh", "/usr/bin/gh"]) {
|
|
6506
|
-
candidates.add(candidate);
|
|
6507
|
-
}
|
|
6508
6520
|
const bunResolved = Bun.which("gh");
|
|
6509
6521
|
if (bunResolved) {
|
|
6510
6522
|
candidates.add(bunResolved);
|
|
6511
6523
|
}
|
|
6512
6524
|
for (const candidate of candidates) {
|
|
6513
|
-
if (candidate && existsSync21(candidate)) {
|
|
6525
|
+
if (candidate && existsSync21(candidate) && !isRuntimeGatewayGhPath(candidate)) {
|
|
6514
6526
|
return candidate;
|
|
6515
6527
|
}
|
|
6516
6528
|
}
|
|
@@ -6659,6 +6671,32 @@ function withGhRepo(command, repoNameWithOwner) {
|
|
|
6659
6671
|
}
|
|
6660
6672
|
return [command[0], command[1], command[2], ...ghRepoArgs(repoNameWithOwner), ...command.slice(3)];
|
|
6661
6673
|
}
|
|
6674
|
+
function inferRepositoryDefaultBase(projectRoot, repoRoot, repoNameWithOwner, remoteName, fallback) {
|
|
6675
|
+
const remote = remoteName || "origin";
|
|
6676
|
+
const symbolic = runCapture2(gitCmd(projectRoot, repoRoot, "symbolic-ref", "--short", `refs/remotes/${remote}/HEAD`), projectRoot);
|
|
6677
|
+
if (symbolic.exitCode === 0) {
|
|
6678
|
+
const ref = symbolic.stdout.trim().replace(new RegExp(`^${escapeRegExp2(remote)}/`), "");
|
|
6679
|
+
if (ref && ref !== "HEAD") {
|
|
6680
|
+
return ref;
|
|
6681
|
+
}
|
|
6682
|
+
}
|
|
6683
|
+
const lsRemote = runCapture2(gitCmd(projectRoot, repoRoot, "ls-remote", "--symref", remote, "HEAD"), projectRoot);
|
|
6684
|
+
if (lsRemote.exitCode === 0) {
|
|
6685
|
+
const match = lsRemote.stdout.match(/^ref:\s+refs\/heads\/([^\t\r\n]+)\s+HEAD/m);
|
|
6686
|
+
if (match?.[1]) {
|
|
6687
|
+
return match[1];
|
|
6688
|
+
}
|
|
6689
|
+
}
|
|
6690
|
+
const gh = resolveGithubCliBinary(projectRoot);
|
|
6691
|
+
if (gh && repoNameWithOwner) {
|
|
6692
|
+
const api = runCapture2(withGhRepo([gh, "repo", "view", "--json", "defaultBranchRef", "--jq", ".defaultBranchRef.name"], repoNameWithOwner), repoRoot);
|
|
6693
|
+
const branch = api.exitCode === 0 ? api.stdout.trim() : "";
|
|
6694
|
+
if (branch) {
|
|
6695
|
+
return branch;
|
|
6696
|
+
}
|
|
6697
|
+
}
|
|
6698
|
+
return fallback;
|
|
6699
|
+
}
|
|
6662
6700
|
function inferProjectBase(projectRoot, fallback) {
|
|
6663
6701
|
const containing = runCapture2(gitCmd(projectRoot, projectRoot, "branch", "-r", "--contains", "HEAD"), projectRoot);
|
|
6664
6702
|
if (containing.exitCode !== 0) {
|
|
@@ -7040,6 +7078,10 @@ function runtimeGitEnv(projectRoot) {
|
|
|
7040
7078
|
}
|
|
7041
7079
|
env[key] = value;
|
|
7042
7080
|
}
|
|
7081
|
+
const rigGithubToken = process.env.RIG_GITHUB_TOKEN?.trim() || "";
|
|
7082
|
+
if (rigGithubToken && !env.GITHUB_TOKEN && !env.GH_TOKEN) {
|
|
7083
|
+
env.GITHUB_TOKEN = rigGithubToken;
|
|
7084
|
+
}
|
|
7043
7085
|
if (!env.GITHUB_TOKEN && env.GH_TOKEN) {
|
|
7044
7086
|
env.GITHUB_TOKEN = env.GH_TOKEN;
|
|
7045
7087
|
}
|
|
@@ -7063,6 +7105,13 @@ function runtimeGitEnv(projectRoot) {
|
|
|
7063
7105
|
if (!env.GH_TOKEN && env.GITHUB_TOKEN) {
|
|
7064
7106
|
env.GH_TOKEN = env.GITHUB_TOKEN;
|
|
7065
7107
|
}
|
|
7108
|
+
const gitHubToken = env.GITHUB_TOKEN || env.GH_TOKEN || env.RIG_GITHUB_TOKEN || rigGithubToken;
|
|
7109
|
+
if (gitHubToken) {
|
|
7110
|
+
env.RIG_GITHUB_TOKEN = gitHubToken;
|
|
7111
|
+
env.GITHUB_TOKEN = env.GITHUB_TOKEN || gitHubToken;
|
|
7112
|
+
env.GH_TOKEN = env.GH_TOKEN || gitHubToken;
|
|
7113
|
+
applyGitHubCredentialHelperEnv(env);
|
|
7114
|
+
}
|
|
7066
7115
|
if (runtimeKnownHosts && existsSync21(runtimeKnownHosts)) {
|
|
7067
7116
|
const sshParts = [
|
|
7068
7117
|
"ssh",
|
|
@@ -7079,6 +7128,14 @@ function runtimeGitEnv(projectRoot) {
|
|
|
7079
7128
|
}
|
|
7080
7129
|
return Object.keys(env).length > 0 ? env : undefined;
|
|
7081
7130
|
}
|
|
7131
|
+
function applyGitHubCredentialHelperEnv(env) {
|
|
7132
|
+
env.GIT_TERMINAL_PROMPT = "0";
|
|
7133
|
+
env.GIT_CONFIG_COUNT = "2";
|
|
7134
|
+
env.GIT_CONFIG_KEY_0 = "credential.helper";
|
|
7135
|
+
env.GIT_CONFIG_VALUE_0 = "";
|
|
7136
|
+
env.GIT_CONFIG_KEY_1 = "credential.helper";
|
|
7137
|
+
env.GIT_CONFIG_VALUE_1 = '!f() { test "$1" = get || exit 0; token="${GITHUB_TOKEN:-${GH_TOKEN:-${RIG_GITHUB_TOKEN:-}}}"; test -n "$token" || exit 0; echo username=x-access-token; echo password="$token"; }; f';
|
|
7138
|
+
}
|
|
7082
7139
|
function loadPersistedRuntimeSecrets(runtimeRoot) {
|
|
7083
7140
|
if (!runtimeRoot) {
|
|
7084
7141
|
return {};
|