@h-rig/runtime 0.0.6-alpha.3 → 0.0.6-alpha.5
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 +73 -14
- package/dist/bin/rig-agent.js +39 -25
- package/dist/src/control-plane/agent-wrapper.js +73 -14
- package/dist/src/control-plane/harness-main.js +39 -25
- package/dist/src/control-plane/hooks/completion-verification.js +36 -22
- package/dist/src/control-plane/hooks/inject-context.js +2 -2
- package/dist/src/control-plane/hooks/submodule-branch.js +7 -3
- package/dist/src/control-plane/hooks/task-runtime-start.js +7 -3
- package/dist/src/control-plane/native/git-ops.js +34 -20
- package/dist/src/control-plane/native/harness-cli.js +39 -25
- 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 +4 -4
- 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 +18 -9
- package/dist/src/control-plane/runtime/isolation/home.js +11 -6
- package/dist/src/control-plane/runtime/isolation/index.js +18 -9
- package/dist/src/control-plane/runtime/isolation/runner.js +11 -6
- package/dist/src/control-plane/runtime/isolation/shared.js +9 -6
- package/dist/src/control-plane/runtime/isolation.js +18 -9
- package/dist/src/control-plane/runtime/queue.js +18 -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/package.json +6 -6
|
@@ -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,
|
|
@@ -8481,7 +8497,11 @@ async function ensureAgentRuntime(options) {
|
|
|
8481
8497
|
mkdirSync18(runtime.binDir, { recursive: true });
|
|
8482
8498
|
mkdirSync18(workspaceLayout.distDir, { recursive: true });
|
|
8483
8499
|
prepareRuntimeWorkspace(options.projectRoot, workspaceDir);
|
|
8484
|
-
|
|
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
|
+
}
|
|
8485
8505
|
const ctx = {
|
|
8486
8506
|
runtimeId: options.id,
|
|
8487
8507
|
taskId: options.taskId,
|
|
@@ -9193,7 +9213,8 @@ async function runAgentWrapper(options = {}) {
|
|
|
9193
9213
|
taskId,
|
|
9194
9214
|
mode: "worktree",
|
|
9195
9215
|
provider,
|
|
9196
|
-
taskRecordReader: taskRecordReaderFromEnv(taskId)
|
|
9216
|
+
taskRecordReader: taskRecordReaderFromEnv(taskId),
|
|
9217
|
+
preserveTaskArtifacts: process.env.RIG_RUN_RESUME === "1" || process.env.RIG_RUNTIME_ARTIFACT_CLEANUP === "preserve"
|
|
9197
9218
|
});
|
|
9198
9219
|
emitWrapperEvent("runtime.provision.completed", {
|
|
9199
9220
|
runtimeId: runtime.id,
|
|
@@ -9356,12 +9377,16 @@ function buildProviderArgs(provider, runtime, argv) {
|
|
|
9356
9377
|
}
|
|
9357
9378
|
if (provider === "pi") {
|
|
9358
9379
|
const piArgs = [...argv];
|
|
9380
|
+
const piProvider = cliOptionValue(piArgs, "--provider") || process.env.RIG_PI_PROVIDER?.trim() || "openai-codex";
|
|
9359
9381
|
if (!hasCliOption(piArgs, "--provider")) {
|
|
9360
|
-
piArgs.unshift(
|
|
9382
|
+
piArgs.unshift(piProvider);
|
|
9361
9383
|
piArgs.unshift("--provider");
|
|
9362
9384
|
}
|
|
9363
|
-
|
|
9364
|
-
|
|
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));
|
|
9365
9390
|
piArgs.unshift("--model");
|
|
9366
9391
|
}
|
|
9367
9392
|
return piArgs;
|
|
@@ -9429,6 +9454,38 @@ function resolveProvider() {
|
|
|
9429
9454
|
function hasCliOption(argv, option) {
|
|
9430
9455
|
return argv.some((arg) => arg === option || arg.startsWith(`${option}=`));
|
|
9431
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
|
+
}
|
|
9432
9489
|
function providerBinary(provider) {
|
|
9433
9490
|
if (provider === "codex") {
|
|
9434
9491
|
return Bun.which("codex") || "codex";
|
|
@@ -9548,7 +9605,9 @@ async function updateTaskSourceAfterRun(projectRoot, taskId, runtime) {
|
|
|
9548
9605
|
} catch (error) {
|
|
9549
9606
|
let fallbackUpdated = false;
|
|
9550
9607
|
try {
|
|
9551
|
-
|
|
9608
|
+
const sourceIssueId = loadRuntimeContextFromEnv()?.sourceTask?.sourceIssueId;
|
|
9609
|
+
fallbackUpdated = updateGithubIssueTaskBySourceIssueId(sourceIssueId, taskId, { status: "closed", comment });
|
|
9610
|
+
fallbackUpdated = updateSourceAwareTaskConfigTask(projectRoot, taskId, { status: "closed", comment }) || fallbackUpdated;
|
|
9552
9611
|
} catch (fallbackError) {
|
|
9553
9612
|
console.error(`[rig-agent] Source-aware compatibility update also failed for ${taskId}: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`);
|
|
9554
9613
|
}
|
package/dist/bin/rig-agent.js
CHANGED
|
@@ -4421,8 +4421,8 @@ function githubStatusFor(issue) {
|
|
|
4421
4421
|
return "open";
|
|
4422
4422
|
}
|
|
4423
4423
|
function selectedGitHubEnv() {
|
|
4424
|
-
const token = process.env.RIG_GITHUB_SELECTED_TOKEN?.trim()
|
|
4425
|
-
return { GH_TOKEN: token, GITHUB_TOKEN: token };
|
|
4424
|
+
const token = process.env.RIG_GITHUB_SELECTED_TOKEN?.trim() || process.env.RIG_GITHUB_TOKEN?.trim() || "";
|
|
4425
|
+
return { GH_TOKEN: token, GITHUB_TOKEN: token, RIG_GITHUB_TOKEN: token };
|
|
4426
4426
|
}
|
|
4427
4427
|
function ghSpawnOptions() {
|
|
4428
4428
|
return { encoding: "utf-8", env: { ...process.env, ...selectedGitHubEnv() } };
|
|
@@ -6389,7 +6389,7 @@ This file records approaches that did not work.
|
|
|
6389
6389
|
`, "utf-8");
|
|
6390
6390
|
}
|
|
6391
6391
|
const content = readFileSync12(failedPath, "utf-8");
|
|
6392
|
-
const attempts = (content.match(new RegExp(`^## ${
|
|
6392
|
+
const attempts = (content.match(new RegExp(`^## ${escapeRegExp(activeTask)}\\b`, "gm")) || []).length + 1;
|
|
6393
6393
|
appendFileSync(failedPath, `
|
|
6394
6394
|
## ${activeTask} - Attempt ${attempts} (${nowIso()})
|
|
6395
6395
|
|
|
@@ -6885,7 +6885,7 @@ function printArtifactSection(path, header) {
|
|
|
6885
6885
|
process.stdout.write(readFileSync12(path, "utf-8"));
|
|
6886
6886
|
console.log("");
|
|
6887
6887
|
}
|
|
6888
|
-
function
|
|
6888
|
+
function escapeRegExp(value) {
|
|
6889
6889
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6890
6890
|
}
|
|
6891
6891
|
function changedFilesForTask(projectRoot, taskId, scoped) {
|
|
@@ -6914,12 +6914,12 @@ var TASK_ARTIFACT_STAGE_FALLBACK = new Set([
|
|
|
6914
6914
|
"task-result.json",
|
|
6915
6915
|
"validation-summary.json"
|
|
6916
6916
|
]);
|
|
6917
|
-
function resolveHostRigBinDir(root) {
|
|
6918
|
-
return resolve26(root, ".rig", "bin");
|
|
6919
|
-
}
|
|
6920
6917
|
function isRuntimeGatewayGitPath(candidate) {
|
|
6921
6918
|
return /\/\.rig\/bin\/git$/.test(candidate.replace(/\\/g, "/"));
|
|
6922
6919
|
}
|
|
6920
|
+
function isRuntimeGatewayGhPath(candidate) {
|
|
6921
|
+
return /\/\.rig\/bin\/gh$/.test(candidate.replace(/\\/g, "/"));
|
|
6922
|
+
}
|
|
6923
6923
|
function resolveOptionalMonorepoRoot(projectRoot) {
|
|
6924
6924
|
const runtimeWorkspace = process.env.RIG_TASK_WORKSPACE?.trim();
|
|
6925
6925
|
if (runtimeWorkspace && existsSync22(resolve26(runtimeWorkspace, ".git"))) {
|
|
@@ -6954,6 +6954,9 @@ function resolveGitBinary(projectRoot) {
|
|
|
6954
6954
|
}
|
|
6955
6955
|
return "git";
|
|
6956
6956
|
}
|
|
6957
|
+
function escapeRegExp2(value) {
|
|
6958
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
6959
|
+
}
|
|
6957
6960
|
function safeCurrentTaskId(projectRoot) {
|
|
6958
6961
|
try {
|
|
6959
6962
|
const taskId = currentTaskId(projectRoot);
|
|
@@ -7167,6 +7170,7 @@ function gitOpenPr(options) {
|
|
|
7167
7170
|
"",
|
|
7168
7171
|
"## Task",
|
|
7169
7172
|
`- beads: ${taskId || "n/a"}`,
|
|
7173
|
+
...defaultPrRunLines(taskId, repoNameWithOwner),
|
|
7170
7174
|
"",
|
|
7171
7175
|
"## Review",
|
|
7172
7176
|
"- Completion verification will run validation, verifier review, and PR policy checks.",
|
|
@@ -7258,6 +7262,29 @@ function gitOpenPr(options) {
|
|
|
7258
7262
|
}
|
|
7259
7263
|
return result;
|
|
7260
7264
|
}
|
|
7265
|
+
function defaultPrRunLines(taskId, repoNameWithOwner) {
|
|
7266
|
+
const lines = [];
|
|
7267
|
+
const runId = process.env.RIG_SERVER_RUN_ID?.trim();
|
|
7268
|
+
if (runId) {
|
|
7269
|
+
lines.push(`- Run: ${runId}`);
|
|
7270
|
+
}
|
|
7271
|
+
const closeout = defaultPrCloseoutLine(taskId, repoNameWithOwner);
|
|
7272
|
+
if (closeout) {
|
|
7273
|
+
lines.push(`- ${closeout}`);
|
|
7274
|
+
}
|
|
7275
|
+
return lines;
|
|
7276
|
+
}
|
|
7277
|
+
function defaultPrCloseoutLine(taskId, repoNameWithOwner) {
|
|
7278
|
+
const sourceIssueId = loadRuntimeContextFromEnv()?.sourceTask?.sourceIssueId;
|
|
7279
|
+
if (sourceIssueId) {
|
|
7280
|
+
const match = sourceIssueId.match(/^([^#]+)#(\d+)$/);
|
|
7281
|
+
if (match) {
|
|
7282
|
+
const [, sourceRepo, issueNumber] = match;
|
|
7283
|
+
return sourceRepo.toLowerCase() === repoNameWithOwner.toLowerCase() ? `Closes #${issueNumber}` : `Closes ${sourceRepo}#${issueNumber}`;
|
|
7284
|
+
}
|
|
7285
|
+
}
|
|
7286
|
+
return /^\d+$/.test(taskId) ? `Closes #${taskId}` : "";
|
|
7287
|
+
}
|
|
7261
7288
|
function readPrViewState(gh, repoRoot, repoNameWithOwner, prUrl) {
|
|
7262
7289
|
const view = runCapture2(withGhRepo([
|
|
7263
7290
|
gh,
|
|
@@ -7383,32 +7410,19 @@ function resolveGithubCliBinary(projectRoot) {
|
|
|
7383
7410
|
if (explicit) {
|
|
7384
7411
|
candidates.add(explicit);
|
|
7385
7412
|
}
|
|
7413
|
+
for (const candidate of ["/usr/bin/gh", "/opt/homebrew/bin/gh", "/usr/local/bin/gh"]) {
|
|
7414
|
+
candidates.add(candidate);
|
|
7415
|
+
}
|
|
7386
7416
|
const explicitPathEntries = (process.env.PATH || "").split(":").map((entry) => entry.trim()).filter(Boolean);
|
|
7387
7417
|
for (const entry of explicitPathEntries) {
|
|
7388
7418
|
candidates.add(resolve26(entry, "gh"));
|
|
7389
7419
|
}
|
|
7390
|
-
const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim();
|
|
7391
|
-
if (hostProjectRoot) {
|
|
7392
|
-
candidates.add(resolve26(resolveHostRigBinDir(hostProjectRoot), "gh"));
|
|
7393
|
-
}
|
|
7394
|
-
candidates.add(resolve26(resolveHostRigBinDir(projectRoot), "gh"));
|
|
7395
|
-
const runtimeContext = loadRuntimeContextFromEnv();
|
|
7396
|
-
if (runtimeContext?.binDir) {
|
|
7397
|
-
candidates.add(resolve26(runtimeContext.binDir, "gh"));
|
|
7398
|
-
}
|
|
7399
|
-
const runtimeHome = process.env.RIG_RUNTIME_HOME?.trim();
|
|
7400
|
-
if (runtimeHome) {
|
|
7401
|
-
candidates.add(resolve26(runtimeHome, "bin", "gh"));
|
|
7402
|
-
}
|
|
7403
|
-
for (const candidate of ["/opt/homebrew/bin/gh", "/usr/local/bin/gh", "/usr/bin/gh"]) {
|
|
7404
|
-
candidates.add(candidate);
|
|
7405
|
-
}
|
|
7406
7420
|
const bunResolved = Bun.which("gh");
|
|
7407
7421
|
if (bunResolved) {
|
|
7408
7422
|
candidates.add(bunResolved);
|
|
7409
7423
|
}
|
|
7410
7424
|
for (const candidate of candidates) {
|
|
7411
|
-
if (candidate && existsSync22(candidate)) {
|
|
7425
|
+
if (candidate && existsSync22(candidate) && !isRuntimeGatewayGhPath(candidate)) {
|
|
7412
7426
|
return candidate;
|
|
7413
7427
|
}
|
|
7414
7428
|
}
|
|
@@ -7561,7 +7575,7 @@ function inferRepositoryDefaultBase(projectRoot, repoRoot, repoNameWithOwner, re
|
|
|
7561
7575
|
const remote = remoteName || "origin";
|
|
7562
7576
|
const symbolic = runCapture2(gitCmd(projectRoot, repoRoot, "symbolic-ref", "--short", `refs/remotes/${remote}/HEAD`), projectRoot);
|
|
7563
7577
|
if (symbolic.exitCode === 0) {
|
|
7564
|
-
const ref = symbolic.stdout.trim().replace(new RegExp(`^${
|
|
7578
|
+
const ref = symbolic.stdout.trim().replace(new RegExp(`^${escapeRegExp2(remote)}/`), "");
|
|
7565
7579
|
if (ref && ref !== "HEAD") {
|
|
7566
7580
|
return ref;
|
|
7567
7581
|
}
|
|
@@ -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,
|
|
@@ -8481,7 +8497,11 @@ async function ensureAgentRuntime(options) {
|
|
|
8481
8497
|
mkdirSync18(runtime.binDir, { recursive: true });
|
|
8482
8498
|
mkdirSync18(workspaceLayout.distDir, { recursive: true });
|
|
8483
8499
|
prepareRuntimeWorkspace(options.projectRoot, workspaceDir);
|
|
8484
|
-
|
|
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
|
+
}
|
|
8485
8505
|
const ctx = {
|
|
8486
8506
|
runtimeId: options.id,
|
|
8487
8507
|
taskId: options.taskId,
|
|
@@ -9193,7 +9213,8 @@ async function runAgentWrapper(options = {}) {
|
|
|
9193
9213
|
taskId,
|
|
9194
9214
|
mode: "worktree",
|
|
9195
9215
|
provider,
|
|
9196
|
-
taskRecordReader: taskRecordReaderFromEnv(taskId)
|
|
9216
|
+
taskRecordReader: taskRecordReaderFromEnv(taskId),
|
|
9217
|
+
preserveTaskArtifacts: process.env.RIG_RUN_RESUME === "1" || process.env.RIG_RUNTIME_ARTIFACT_CLEANUP === "preserve"
|
|
9197
9218
|
});
|
|
9198
9219
|
emitWrapperEvent("runtime.provision.completed", {
|
|
9199
9220
|
runtimeId: runtime.id,
|
|
@@ -9356,12 +9377,16 @@ function buildProviderArgs(provider, runtime, argv) {
|
|
|
9356
9377
|
}
|
|
9357
9378
|
if (provider === "pi") {
|
|
9358
9379
|
const piArgs = [...argv];
|
|
9380
|
+
const piProvider = cliOptionValue(piArgs, "--provider") || process.env.RIG_PI_PROVIDER?.trim() || "openai-codex";
|
|
9359
9381
|
if (!hasCliOption(piArgs, "--provider")) {
|
|
9360
|
-
piArgs.unshift(
|
|
9382
|
+
piArgs.unshift(piProvider);
|
|
9361
9383
|
piArgs.unshift("--provider");
|
|
9362
9384
|
}
|
|
9363
|
-
|
|
9364
|
-
|
|
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));
|
|
9365
9390
|
piArgs.unshift("--model");
|
|
9366
9391
|
}
|
|
9367
9392
|
return piArgs;
|
|
@@ -9429,6 +9454,38 @@ function resolveProvider() {
|
|
|
9429
9454
|
function hasCliOption(argv, option) {
|
|
9430
9455
|
return argv.some((arg) => arg === option || arg.startsWith(`${option}=`));
|
|
9431
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
|
+
}
|
|
9432
9489
|
function providerBinary(provider) {
|
|
9433
9490
|
if (provider === "codex") {
|
|
9434
9491
|
return Bun.which("codex") || "codex";
|
|
@@ -9548,7 +9605,9 @@ async function updateTaskSourceAfterRun(projectRoot, taskId, runtime) {
|
|
|
9548
9605
|
} catch (error) {
|
|
9549
9606
|
let fallbackUpdated = false;
|
|
9550
9607
|
try {
|
|
9551
|
-
|
|
9608
|
+
const sourceIssueId = loadRuntimeContextFromEnv()?.sourceTask?.sourceIssueId;
|
|
9609
|
+
fallbackUpdated = updateGithubIssueTaskBySourceIssueId(sourceIssueId, taskId, { status: "closed", comment });
|
|
9610
|
+
fallbackUpdated = updateSourceAwareTaskConfigTask(projectRoot, taskId, { status: "closed", comment }) || fallbackUpdated;
|
|
9552
9611
|
} catch (fallbackError) {
|
|
9553
9612
|
console.error(`[rig-agent] Source-aware compatibility update also failed for ${taskId}: ${fallbackError instanceof Error ? fallbackError.message : String(fallbackError)}`);
|
|
9554
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() } };
|
|
@@ -5461,7 +5461,7 @@ This file records approaches that did not work.
|
|
|
5461
5461
|
`, "utf-8");
|
|
5462
5462
|
}
|
|
5463
5463
|
const content = readFileSync10(failedPath, "utf-8");
|
|
5464
|
-
const attempts = (content.match(new RegExp(`^## ${
|
|
5464
|
+
const attempts = (content.match(new RegExp(`^## ${escapeRegExp(activeTask)}\\b`, "gm")) || []).length + 1;
|
|
5465
5465
|
appendFileSync(failedPath, `
|
|
5466
5466
|
## ${activeTask} - Attempt ${attempts} (${nowIso()})
|
|
5467
5467
|
|
|
@@ -5960,7 +5960,7 @@ function printArtifactSection(path, header) {
|
|
|
5960
5960
|
process.stdout.write(readFileSync10(path, "utf-8"));
|
|
5961
5961
|
console.log("");
|
|
5962
5962
|
}
|
|
5963
|
-
function
|
|
5963
|
+
function escapeRegExp(value) {
|
|
5964
5964
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5965
5965
|
}
|
|
5966
5966
|
function changedFilesForTask(projectRoot, taskId, scoped) {
|
|
@@ -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);
|
|
@@ -6242,6 +6245,7 @@ function gitOpenPr(options) {
|
|
|
6242
6245
|
"",
|
|
6243
6246
|
"## Task",
|
|
6244
6247
|
`- beads: ${taskId || "n/a"}`,
|
|
6248
|
+
...defaultPrRunLines(taskId, repoNameWithOwner),
|
|
6245
6249
|
"",
|
|
6246
6250
|
"## Review",
|
|
6247
6251
|
"- Completion verification will run validation, verifier review, and PR policy checks.",
|
|
@@ -6333,6 +6337,29 @@ function gitOpenPr(options) {
|
|
|
6333
6337
|
}
|
|
6334
6338
|
return result;
|
|
6335
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
|
+
}
|
|
6336
6363
|
function readPrViewState(gh, repoRoot, repoNameWithOwner, prUrl) {
|
|
6337
6364
|
const view = runCapture2(withGhRepo([
|
|
6338
6365
|
gh,
|
|
@@ -6483,32 +6510,19 @@ function resolveGithubCliBinary(projectRoot) {
|
|
|
6483
6510
|
if (explicit) {
|
|
6484
6511
|
candidates.add(explicit);
|
|
6485
6512
|
}
|
|
6513
|
+
for (const candidate of ["/usr/bin/gh", "/opt/homebrew/bin/gh", "/usr/local/bin/gh"]) {
|
|
6514
|
+
candidates.add(candidate);
|
|
6515
|
+
}
|
|
6486
6516
|
const explicitPathEntries = (process.env.PATH || "").split(":").map((entry) => entry.trim()).filter(Boolean);
|
|
6487
6517
|
for (const entry of explicitPathEntries) {
|
|
6488
6518
|
candidates.add(resolve24(entry, "gh"));
|
|
6489
6519
|
}
|
|
6490
|
-
const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim();
|
|
6491
|
-
if (hostProjectRoot) {
|
|
6492
|
-
candidates.add(resolve24(resolveHostRigBinDir(hostProjectRoot), "gh"));
|
|
6493
|
-
}
|
|
6494
|
-
candidates.add(resolve24(resolveHostRigBinDir(projectRoot), "gh"));
|
|
6495
|
-
const runtimeContext = loadRuntimeContextFromEnv();
|
|
6496
|
-
if (runtimeContext?.binDir) {
|
|
6497
|
-
candidates.add(resolve24(runtimeContext.binDir, "gh"));
|
|
6498
|
-
}
|
|
6499
|
-
const runtimeHome = process.env.RIG_RUNTIME_HOME?.trim();
|
|
6500
|
-
if (runtimeHome) {
|
|
6501
|
-
candidates.add(resolve24(runtimeHome, "bin", "gh"));
|
|
6502
|
-
}
|
|
6503
|
-
for (const candidate of ["/opt/homebrew/bin/gh", "/usr/local/bin/gh", "/usr/bin/gh"]) {
|
|
6504
|
-
candidates.add(candidate);
|
|
6505
|
-
}
|
|
6506
6520
|
const bunResolved = Bun.which("gh");
|
|
6507
6521
|
if (bunResolved) {
|
|
6508
6522
|
candidates.add(bunResolved);
|
|
6509
6523
|
}
|
|
6510
6524
|
for (const candidate of candidates) {
|
|
6511
|
-
if (candidate && existsSync21(candidate)) {
|
|
6525
|
+
if (candidate && existsSync21(candidate) && !isRuntimeGatewayGhPath(candidate)) {
|
|
6512
6526
|
return candidate;
|
|
6513
6527
|
}
|
|
6514
6528
|
}
|
|
@@ -6661,7 +6675,7 @@ function inferRepositoryDefaultBase(projectRoot, repoRoot, repoNameWithOwner, re
|
|
|
6661
6675
|
const remote = remoteName || "origin";
|
|
6662
6676
|
const symbolic = runCapture2(gitCmd(projectRoot, repoRoot, "symbolic-ref", "--short", `refs/remotes/${remote}/HEAD`), projectRoot);
|
|
6663
6677
|
if (symbolic.exitCode === 0) {
|
|
6664
|
-
const ref = symbolic.stdout.trim().replace(new RegExp(`^${
|
|
6678
|
+
const ref = symbolic.stdout.trim().replace(new RegExp(`^${escapeRegExp2(remote)}/`), "");
|
|
6665
6679
|
if (ref && ref !== "HEAD") {
|
|
6666
6680
|
return ref;
|
|
6667
6681
|
}
|