@h-rig/cli 0.0.6-alpha.1 → 0.0.6-alpha.3
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.js +356 -205
- package/dist/src/commands/_doctor-checks.js +31 -13
- package/dist/src/commands/_operator-view.js +20 -2
- package/dist/src/commands/_preflight.js +25 -7
- package/dist/src/commands/_server-client.js +22 -4
- package/dist/src/commands/_snapshot-upload.js +26 -8
- package/dist/src/commands/doctor.js +31 -13
- package/dist/src/commands/github.js +21 -3
- package/dist/src/commands/init.js +142 -62
- package/dist/src/commands/run.js +26 -8
- package/dist/src/commands/server.js +20 -2
- package/dist/src/commands/setup.js +36 -18
- package/dist/src/commands/task-run-driver.js +77 -5
- package/dist/src/commands/task.js +28 -10
- package/dist/src/commands.js +349 -198
- package/dist/src/index.js +356 -205
- package/package.json +4 -4
package/dist/bin/rig.js
CHANGED
|
@@ -2671,6 +2671,8 @@ function resolveSelectedConnection(projectRoot, options = {}) {
|
|
|
2671
2671
|
|
|
2672
2672
|
// packages/cli/src/commands/_server-client.ts
|
|
2673
2673
|
import { spawnSync } from "child_process";
|
|
2674
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
2675
|
+
import { resolve as resolve9 } from "path";
|
|
2674
2676
|
import { ensureLocalRigServerConnection } from "@rig/runtime/local-server";
|
|
2675
2677
|
var cachedGitHubBearerToken;
|
|
2676
2678
|
function cleanToken(value) {
|
|
@@ -2680,9 +2682,25 @@ function cleanToken(value) {
|
|
|
2680
2682
|
function setGitHubBearerTokenForCurrentProcess(token) {
|
|
2681
2683
|
cachedGitHubBearerToken = cleanToken(token ?? undefined);
|
|
2682
2684
|
}
|
|
2683
|
-
function
|
|
2685
|
+
function readPrivateRemoteSessionToken(projectRoot) {
|
|
2686
|
+
const path = resolve9(projectRoot, ".rig", "state", "github-auth.json");
|
|
2687
|
+
if (!existsSync5(path))
|
|
2688
|
+
return null;
|
|
2689
|
+
try {
|
|
2690
|
+
const parsed = JSON.parse(readFileSync3(path, "utf8"));
|
|
2691
|
+
return cleanToken(typeof parsed.apiSessionToken === "string" ? parsed.apiSessionToken : typeof parsed.sessionToken === "string" ? parsed.sessionToken : undefined);
|
|
2692
|
+
} catch {
|
|
2693
|
+
return null;
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
function readGitHubBearerTokenForRemote(projectRoot) {
|
|
2684
2697
|
if (cachedGitHubBearerToken !== undefined)
|
|
2685
2698
|
return cachedGitHubBearerToken;
|
|
2699
|
+
const privateSession = readPrivateRemoteSessionToken(projectRoot);
|
|
2700
|
+
if (privateSession) {
|
|
2701
|
+
cachedGitHubBearerToken = privateSession;
|
|
2702
|
+
return cachedGitHubBearerToken;
|
|
2703
|
+
}
|
|
2686
2704
|
const envToken = cleanToken(process.env.RIG_GITHUB_TOKEN) ?? cleanToken(process.env.GITHUB_TOKEN) ?? cleanToken(process.env.GH_TOKEN);
|
|
2687
2705
|
if (envToken) {
|
|
2688
2706
|
cachedGitHubBearerToken = envToken;
|
|
@@ -2702,7 +2720,7 @@ async function ensureServerForCli(projectRoot) {
|
|
|
2702
2720
|
if (selected?.connection.kind === "remote") {
|
|
2703
2721
|
return {
|
|
2704
2722
|
baseUrl: selected.connection.baseUrl,
|
|
2705
|
-
authToken: readGitHubBearerTokenForRemote(),
|
|
2723
|
+
authToken: readGitHubBearerTokenForRemote(projectRoot),
|
|
2706
2724
|
connectionKind: "remote"
|
|
2707
2725
|
};
|
|
2708
2726
|
}
|
|
@@ -2809,7 +2827,7 @@ async function postGitHubTokenViaServer(context, token, options = {}) {
|
|
|
2809
2827
|
const payload = await requestServerJson(context, "/api/github/auth/token", {
|
|
2810
2828
|
method: "POST",
|
|
2811
2829
|
headers: { "content-type": "application/json" },
|
|
2812
|
-
body: JSON.stringify({ token, selectedRepo: options.selectedRepo })
|
|
2830
|
+
body: JSON.stringify({ token, selectedRepo: options.selectedRepo, projectRoot: options.projectRoot })
|
|
2813
2831
|
});
|
|
2814
2832
|
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
2815
2833
|
}
|
|
@@ -2830,7 +2848,7 @@ async function registerProjectViaServer(context, input) {
|
|
|
2830
2848
|
return payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
2831
2849
|
}
|
|
2832
2850
|
function sleep(ms) {
|
|
2833
|
-
return new Promise((
|
|
2851
|
+
return new Promise((resolve10) => setTimeout(resolve10, ms));
|
|
2834
2852
|
}
|
|
2835
2853
|
async function switchServerProjectRootViaServer(context, projectRoot, options = {}) {
|
|
2836
2854
|
const switched = await requestServerJson(context, "/api/server/project-root", {
|
|
@@ -2921,9 +2939,9 @@ async function submitTaskRunViaServer(context, input) {
|
|
|
2921
2939
|
}
|
|
2922
2940
|
|
|
2923
2941
|
// packages/cli/src/commands/_pi-install.ts
|
|
2924
|
-
import { existsSync as
|
|
2942
|
+
import { existsSync as existsSync6, readFileSync as readFileSync4, rmSync as rmSync3 } from "fs";
|
|
2925
2943
|
import { homedir as homedir3 } from "os";
|
|
2926
|
-
import { resolve as
|
|
2944
|
+
import { resolve as resolve10 } from "path";
|
|
2927
2945
|
var PI_RIG_PACKAGE_NAME = "@rig/pi-rig";
|
|
2928
2946
|
var LEGACY_PI_RIG_MARKER = `// Managed by Rig. Source package: @rig/pi-rig.
|
|
2929
2947
|
export { default } from '@rig/pi-rig';
|
|
@@ -2938,11 +2956,11 @@ async function defaultCommandRunner(command, options = {}) {
|
|
|
2938
2956
|
return { exitCode, stdout, stderr };
|
|
2939
2957
|
}
|
|
2940
2958
|
function resolvePiRigExtensionPath(homeDir) {
|
|
2941
|
-
return
|
|
2959
|
+
return resolve10(homeDir, ".pi", "agent", "extensions", "pi-rig");
|
|
2942
2960
|
}
|
|
2943
|
-
function resolvePiRigPackageSource(projectRoot, exists =
|
|
2944
|
-
const localPackage =
|
|
2945
|
-
if (exists(
|
|
2961
|
+
function resolvePiRigPackageSource(projectRoot, exists = existsSync6) {
|
|
2962
|
+
const localPackage = resolve10(projectRoot, "packages", "pi-rig");
|
|
2963
|
+
if (exists(resolve10(localPackage, "package.json")))
|
|
2946
2964
|
return localPackage;
|
|
2947
2965
|
return `npm:${PI_RIG_PACKAGE_NAME}`;
|
|
2948
2966
|
}
|
|
@@ -2993,13 +3011,13 @@ async function ensurePiBinaryAvailable(input) {
|
|
|
2993
3011
|
...next.exitCode === 0 ? {} : { error: (next.stderr || next.stdout).trim() || "pi --version failed after install" }
|
|
2994
3012
|
};
|
|
2995
3013
|
}
|
|
2996
|
-
function removeManagedLegacyPiRigBridge(homeDir, exists =
|
|
3014
|
+
function removeManagedLegacyPiRigBridge(homeDir, exists = existsSync6) {
|
|
2997
3015
|
const extensionPath = resolvePiRigExtensionPath(homeDir);
|
|
2998
|
-
const indexPath =
|
|
3016
|
+
const indexPath = resolve10(extensionPath, "index.ts");
|
|
2999
3017
|
if (!exists(indexPath))
|
|
3000
3018
|
return;
|
|
3001
3019
|
try {
|
|
3002
|
-
const content =
|
|
3020
|
+
const content = readFileSync4(indexPath, "utf8");
|
|
3003
3021
|
if (content === LEGACY_PI_RIG_MARKER || content.includes("Managed by Rig. Source package: @rig/pi-rig")) {
|
|
3004
3022
|
rmSync3(extensionPath, { recursive: true, force: true });
|
|
3005
3023
|
}
|
|
@@ -3015,13 +3033,13 @@ async function checkPiRigInstall(input = {}) {
|
|
|
3015
3033
|
piRig: { ok: true, label: "pi-rig global extension", detail: extensionPath }
|
|
3016
3034
|
};
|
|
3017
3035
|
}
|
|
3018
|
-
const exists = input.exists ??
|
|
3036
|
+
const exists = input.exists ?? existsSync6;
|
|
3019
3037
|
const runner = input.commandRunner ?? defaultCommandRunner;
|
|
3020
3038
|
const piResult = await safeRun(runner, ["pi", "--version"]);
|
|
3021
3039
|
const piListResult = piResult.exitCode === 0 ? await safeRun(runner, ["pi", "list"]) : { exitCode: 1, stdout: "", stderr: "" };
|
|
3022
3040
|
const listedPiRig = piListResult.exitCode === 0 && piListContainsPiRig(`${piListResult.stdout}
|
|
3023
3041
|
${piListResult.stderr}`);
|
|
3024
|
-
const legacyBridge = exists(
|
|
3042
|
+
const legacyBridge = exists(resolve10(extensionPath, "index.ts"));
|
|
3025
3043
|
const hasPiRig = listedPiRig;
|
|
3026
3044
|
return {
|
|
3027
3045
|
extensionPath,
|
|
@@ -3359,7 +3377,7 @@ async function executeQueue(context, args) {
|
|
|
3359
3377
|
}
|
|
3360
3378
|
|
|
3361
3379
|
// packages/cli/src/commands/agent.ts
|
|
3362
|
-
import { resolve as
|
|
3380
|
+
import { resolve as resolve12 } from "path";
|
|
3363
3381
|
import {
|
|
3364
3382
|
agentId,
|
|
3365
3383
|
cleanupAgentRuntime,
|
|
@@ -3369,8 +3387,8 @@ import {
|
|
|
3369
3387
|
} from "@rig/runtime/control-plane/runtime/isolation";
|
|
3370
3388
|
|
|
3371
3389
|
// packages/cli/src/commands/_authority-runs.ts
|
|
3372
|
-
import { existsSync as
|
|
3373
|
-
import { resolve as
|
|
3390
|
+
import { existsSync as existsSync7 } from "fs";
|
|
3391
|
+
import { resolve as resolve11 } from "path";
|
|
3374
3392
|
import {
|
|
3375
3393
|
readAuthorityRun,
|
|
3376
3394
|
readJsonlFile as readJsonlFile2,
|
|
@@ -3392,8 +3410,8 @@ function normalizeRuntimeAdapter(value) {
|
|
|
3392
3410
|
return "claude-code";
|
|
3393
3411
|
}
|
|
3394
3412
|
function readLatestBeadRecord(projectRoot, taskId) {
|
|
3395
|
-
const issuesPath =
|
|
3396
|
-
if (!
|
|
3413
|
+
const issuesPath = resolve11(resolveControlPlaneMonorepoRoot(projectRoot), ".beads", "issues.jsonl");
|
|
3414
|
+
if (!existsSync7(issuesPath)) {
|
|
3397
3415
|
return null;
|
|
3398
3416
|
}
|
|
3399
3417
|
let latest = null;
|
|
@@ -3460,7 +3478,7 @@ function upsertAgentAuthorityRun(projectRoot, input) {
|
|
|
3460
3478
|
} else if ("errorText" in next) {
|
|
3461
3479
|
delete next.errorText;
|
|
3462
3480
|
}
|
|
3463
|
-
writeJsonFile3(
|
|
3481
|
+
writeJsonFile3(resolve11(resolveAuthorityRunDir(projectRoot, input.runId), "run.json"), next);
|
|
3464
3482
|
return next;
|
|
3465
3483
|
}
|
|
3466
3484
|
|
|
@@ -3581,10 +3599,10 @@ async function executeAgent(context, args) {
|
|
|
3581
3599
|
status: "running",
|
|
3582
3600
|
startedAt: createdAt,
|
|
3583
3601
|
worktreePath: runtime.workspaceDir,
|
|
3584
|
-
artifactRoot:
|
|
3602
|
+
artifactRoot: resolve12(runtime.workspaceDir, "artifacts", taskId),
|
|
3585
3603
|
logRoot: runtime.logsDir,
|
|
3586
|
-
sessionPath:
|
|
3587
|
-
sessionLogPath:
|
|
3604
|
+
sessionPath: resolve12(runtime.sessionDir, "session.json"),
|
|
3605
|
+
sessionLogPath: resolve12(runtime.logsDir, "agent-stdout.log"),
|
|
3588
3606
|
pid: process.pid
|
|
3589
3607
|
});
|
|
3590
3608
|
const result = await runInAgentRuntime({
|
|
@@ -3604,10 +3622,10 @@ async function executeAgent(context, args) {
|
|
|
3604
3622
|
startedAt: createdAt,
|
|
3605
3623
|
completedAt: failedAt,
|
|
3606
3624
|
worktreePath: runtime.workspaceDir,
|
|
3607
|
-
artifactRoot:
|
|
3625
|
+
artifactRoot: resolve12(runtime.workspaceDir, "artifacts", taskId),
|
|
3608
3626
|
logRoot: runtime.logsDir,
|
|
3609
|
-
sessionPath:
|
|
3610
|
-
sessionLogPath:
|
|
3627
|
+
sessionPath: resolve12(runtime.sessionDir, "session.json"),
|
|
3628
|
+
sessionLogPath: resolve12(runtime.logsDir, "agent-stdout.log"),
|
|
3611
3629
|
pid: process.pid,
|
|
3612
3630
|
errorText: result.stderr ? result.stderr.trim() : `Agent runtime command failed (${result.exitCode})`
|
|
3613
3631
|
});
|
|
@@ -3624,10 +3642,10 @@ ${result.stderr.trim()}` : ""}`, result.exitCode);
|
|
|
3624
3642
|
startedAt: createdAt,
|
|
3625
3643
|
completedAt,
|
|
3626
3644
|
worktreePath: runtime.workspaceDir,
|
|
3627
|
-
artifactRoot:
|
|
3645
|
+
artifactRoot: resolve12(runtime.workspaceDir, "artifacts", taskId),
|
|
3628
3646
|
logRoot: runtime.logsDir,
|
|
3629
|
-
sessionPath:
|
|
3630
|
-
sessionLogPath:
|
|
3647
|
+
sessionPath: resolve12(runtime.sessionDir, "session.json"),
|
|
3648
|
+
sessionLogPath: resolve12(runtime.logsDir, "agent-stdout.log"),
|
|
3631
3649
|
pid: process.pid
|
|
3632
3650
|
});
|
|
3633
3651
|
return {
|
|
@@ -3701,7 +3719,7 @@ ${result.stderr.trim()}` : ""}`, result.exitCode);
|
|
|
3701
3719
|
import {
|
|
3702
3720
|
chmodSync,
|
|
3703
3721
|
copyFileSync as copyFileSync2,
|
|
3704
|
-
existsSync as
|
|
3722
|
+
existsSync as existsSync8,
|
|
3705
3723
|
mkdirSync as mkdirSync6,
|
|
3706
3724
|
readdirSync,
|
|
3707
3725
|
readlinkSync,
|
|
@@ -3711,7 +3729,7 @@ import {
|
|
|
3711
3729
|
unlinkSync
|
|
3712
3730
|
} from "fs";
|
|
3713
3731
|
import { homedir as homedir4 } from "os";
|
|
3714
|
-
import { resolve as
|
|
3732
|
+
import { resolve as resolve13 } from "path";
|
|
3715
3733
|
import { buildBinary as buildBinary2 } from "@rig/runtime/control-plane/runtime/isolation";
|
|
3716
3734
|
import {
|
|
3717
3735
|
computeRuntimeImageFingerprint,
|
|
@@ -3730,13 +3748,13 @@ async function runQuietBinaryProbe(binaryPath, args, cwd) {
|
|
|
3730
3748
|
|
|
3731
3749
|
// packages/cli/src/commands/dist.ts
|
|
3732
3750
|
function collectRigValidatorBuildTargets(input) {
|
|
3733
|
-
const validatorsRoot =
|
|
3734
|
-
if (!
|
|
3751
|
+
const validatorsRoot = resolve13(input.hostProjectRoot, "packages/runtime/src/control-plane/validators");
|
|
3752
|
+
if (!existsSync8(validatorsRoot))
|
|
3735
3753
|
return [];
|
|
3736
3754
|
const targets = [];
|
|
3737
3755
|
const categories = readdirSync(validatorsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
|
|
3738
3756
|
for (const category of categories) {
|
|
3739
|
-
const categoryDir =
|
|
3757
|
+
const categoryDir = resolve13(validatorsRoot, category.name);
|
|
3740
3758
|
for (const entry of readdirSync(categoryDir, { withFileTypes: true })) {
|
|
3741
3759
|
if (!entry.isFile() || !entry.name.endsWith(".ts"))
|
|
3742
3760
|
continue;
|
|
@@ -3745,7 +3763,7 @@ function collectRigValidatorBuildTargets(input) {
|
|
|
3745
3763
|
continue;
|
|
3746
3764
|
targets.push({
|
|
3747
3765
|
source: `packages/runtime/src/control-plane/validators/${category.name}/${entry.name}`,
|
|
3748
|
-
dest:
|
|
3766
|
+
dest: resolve13(input.imageDir, `bin/validators/${category.name}-${check}`),
|
|
3749
3767
|
cwd: input.hostProjectRoot
|
|
3750
3768
|
});
|
|
3751
3769
|
}
|
|
@@ -3754,16 +3772,16 @@ function collectRigValidatorBuildTargets(input) {
|
|
|
3754
3772
|
}
|
|
3755
3773
|
async function findLatestDistBinary(projectRoot) {
|
|
3756
3774
|
const distRoot = resolveControlPlaneHostDistDir(projectRoot);
|
|
3757
|
-
if (!
|
|
3775
|
+
if (!existsSync8(distRoot)) {
|
|
3758
3776
|
return null;
|
|
3759
3777
|
}
|
|
3760
3778
|
const entries = readdirSync(distRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory() && entry.name.startsWith("rig-")).map((entry) => ({
|
|
3761
3779
|
name: entry.name,
|
|
3762
|
-
mtimeMs: statSync(
|
|
3780
|
+
mtimeMs: statSync(resolve13(distRoot, entry.name)).mtimeMs
|
|
3763
3781
|
})).sort((a, b) => b.mtimeMs - a.mtimeMs || b.name.localeCompare(a.name));
|
|
3764
3782
|
for (const { name } of entries) {
|
|
3765
|
-
const candidate =
|
|
3766
|
-
if (
|
|
3783
|
+
const candidate = resolve13(distRoot, name, "bin", "rig");
|
|
3784
|
+
if (existsSync8(candidate) && await isRunnableRigBinary(candidate, projectRoot)) {
|
|
3767
3785
|
return candidate;
|
|
3768
3786
|
}
|
|
3769
3787
|
}
|
|
@@ -3775,7 +3793,7 @@ async function isRunnableRigBinary(binaryPath, projectRoot) {
|
|
|
3775
3793
|
async function runDistDoctor(projectRoot) {
|
|
3776
3794
|
const bunPath = Bun.which("bun");
|
|
3777
3795
|
const rigPath = Bun.which("rig");
|
|
3778
|
-
const userBinDir =
|
|
3796
|
+
const userBinDir = resolve13(homedir4(), ".local/bin");
|
|
3779
3797
|
const userBinInPath = (process.env.PATH || "").split(":").filter(Boolean).includes(userBinDir);
|
|
3780
3798
|
let rigRunnable = false;
|
|
3781
3799
|
if (rigPath) {
|
|
@@ -3823,15 +3841,15 @@ async function executeDist(context, args) {
|
|
|
3823
3841
|
let source = await findLatestDistBinary(context.projectRoot);
|
|
3824
3842
|
let buildDir = null;
|
|
3825
3843
|
if (!source) {
|
|
3826
|
-
buildDir =
|
|
3844
|
+
buildDir = resolve13(resolveControlPlaneHostDistDir(context.projectRoot), `rig-install-${Date.now()}`);
|
|
3827
3845
|
await context.runCommand(["bun", "run", "packages/cli/bin/build-rig-binaries.ts", "--output-dir", buildDir]);
|
|
3828
|
-
source =
|
|
3846
|
+
source = resolve13(buildDir, "bin", "rig");
|
|
3829
3847
|
}
|
|
3830
|
-
if (!
|
|
3848
|
+
if (!existsSync8(source)) {
|
|
3831
3849
|
throw new CliError2(`Unable to locate rig binary at ${source}.`, 2);
|
|
3832
3850
|
}
|
|
3833
|
-
const installedPath =
|
|
3834
|
-
if (
|
|
3851
|
+
const installedPath = resolve13(installDir, "rig");
|
|
3852
|
+
if (existsSync8(installedPath)) {
|
|
3835
3853
|
unlinkSync(installedPath);
|
|
3836
3854
|
}
|
|
3837
3855
|
copyFileSync2(source, installedPath);
|
|
@@ -3873,22 +3891,22 @@ async function executeDist(context, args) {
|
|
|
3873
3891
|
requireNoExtraArgs(rest, "bun run rig dist rebuild-agent");
|
|
3874
3892
|
const fp = await computeRuntimeImageFingerprint(context.projectRoot);
|
|
3875
3893
|
const currentId = computeRuntimeImageId(fp);
|
|
3876
|
-
const imagesDir =
|
|
3894
|
+
const imagesDir = resolve13(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "images");
|
|
3877
3895
|
mkdirSync6(imagesDir, { recursive: true });
|
|
3878
3896
|
let pruned = 0;
|
|
3879
3897
|
for (const entry of readdirSync(imagesDir, { withFileTypes: true })) {
|
|
3880
3898
|
if (entry.isDirectory() && entry.name !== currentId) {
|
|
3881
|
-
rmSync4(
|
|
3899
|
+
rmSync4(resolve13(imagesDir, entry.name), { recursive: true, force: true });
|
|
3882
3900
|
pruned++;
|
|
3883
3901
|
}
|
|
3884
3902
|
}
|
|
3885
3903
|
if (pruned > 0 && context.outputMode === "text") {
|
|
3886
3904
|
console.log(`Pruned ${pruned} stale image(s).`);
|
|
3887
3905
|
}
|
|
3888
|
-
const imageDir =
|
|
3889
|
-
mkdirSync6(
|
|
3890
|
-
mkdirSync6(
|
|
3891
|
-
mkdirSync6(
|
|
3906
|
+
const imageDir = resolve13(imagesDir, currentId);
|
|
3907
|
+
mkdirSync6(resolve13(imageDir, "bin/hooks"), { recursive: true });
|
|
3908
|
+
mkdirSync6(resolve13(imageDir, "bin/plugins"), { recursive: true });
|
|
3909
|
+
mkdirSync6(resolve13(imageDir, "bin/validators"), { recursive: true });
|
|
3892
3910
|
const hookNames = [
|
|
3893
3911
|
"scope-guard",
|
|
3894
3912
|
"import-guard",
|
|
@@ -3902,25 +3920,25 @@ async function executeDist(context, args) {
|
|
|
3902
3920
|
];
|
|
3903
3921
|
const targets = [];
|
|
3904
3922
|
const hostProjectRoot = process.env.RIG_HOST_PROJECT_ROOT?.trim() || context.projectRoot;
|
|
3905
|
-
targets.push({ source: "packages/runtime/bin/rig-agent.ts", dest:
|
|
3906
|
-
targets.push({ source: "packages/runtime/bin/rig-agent-dispatch.ts", dest:
|
|
3923
|
+
targets.push({ source: "packages/runtime/bin/rig-agent.ts", dest: resolve13(imageDir, "bin/rig-agent"), cwd: hostProjectRoot });
|
|
3924
|
+
targets.push({ source: "packages/runtime/bin/rig-agent-dispatch.ts", dest: resolve13(resolveControlPlaneHostBinDir(context.projectRoot), "rig-agent"), cwd: hostProjectRoot });
|
|
3907
3925
|
for (const hookName of hookNames) {
|
|
3908
3926
|
const src = `packages/runtime/src/control-plane/hooks/${hookName}.ts`;
|
|
3909
|
-
targets.push({ source: src, dest:
|
|
3910
|
-
targets.push({ source: src, dest:
|
|
3927
|
+
targets.push({ source: src, dest: resolve13(imageDir, `bin/hooks/${hookName}`), cwd: hostProjectRoot });
|
|
3928
|
+
targets.push({ source: src, dest: resolve13(resolveControlPlaneHostBinDir(context.projectRoot), `hooks/${hookName}`), cwd: hostProjectRoot });
|
|
3911
3929
|
}
|
|
3912
|
-
const pluginsDir =
|
|
3913
|
-
const binPluginsDir =
|
|
3914
|
-
const validatorsRoot =
|
|
3915
|
-
const binValidatorsDir =
|
|
3930
|
+
const pluginsDir = resolve13(context.projectRoot, "rig/plugins");
|
|
3931
|
+
const binPluginsDir = resolve13(resolveControlPlaneHostBinDir(context.projectRoot), "plugins");
|
|
3932
|
+
const validatorsRoot = resolve13(hostProjectRoot, "packages/runtime/src/control-plane/validators");
|
|
3933
|
+
const binValidatorsDir = resolve13(resolveControlPlaneHostBinDir(context.projectRoot), "validators");
|
|
3916
3934
|
mkdirSync6(binPluginsDir, { recursive: true });
|
|
3917
3935
|
mkdirSync6(binValidatorsDir, { recursive: true });
|
|
3918
|
-
if (
|
|
3936
|
+
if (existsSync8(pluginsDir)) {
|
|
3919
3937
|
for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
|
|
3920
3938
|
const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
|
|
3921
3939
|
if (!m)
|
|
3922
3940
|
continue;
|
|
3923
|
-
targets.push({ source: `rig/plugins/${entry.name}`, dest:
|
|
3941
|
+
targets.push({ source: `rig/plugins/${entry.name}`, dest: resolve13(imageDir, `bin/plugins/${m[1]}`), cwd: context.projectRoot });
|
|
3924
3942
|
}
|
|
3925
3943
|
}
|
|
3926
3944
|
targets.push(...collectRigValidatorBuildTargets({ contextProjectRoot: context.projectRoot, hostProjectRoot, imageDir }));
|
|
@@ -3931,17 +3949,17 @@ async function executeDist(context, args) {
|
|
|
3931
3949
|
const isValidator = dest.includes("/bin/validators/");
|
|
3932
3950
|
await buildBinary2(source, dest, cwd, isValidator ? { AGENT_BUN_PATH: Bun.which("bun") || "bun" } : { AGENT_PROJECT_ROOT: context.projectRoot });
|
|
3933
3951
|
}
|
|
3934
|
-
if (
|
|
3952
|
+
if (existsSync8(pluginsDir)) {
|
|
3935
3953
|
for (const entry of readdirSync(pluginsDir, { withFileTypes: true })) {
|
|
3936
3954
|
const m = entry.name.match(/^(.+)\.plugin\.(ts|js|mjs|cjs)$/);
|
|
3937
3955
|
if (!m)
|
|
3938
3956
|
continue;
|
|
3939
3957
|
const pluginName = m[1];
|
|
3940
|
-
const imageBin =
|
|
3958
|
+
const imageBin = resolve13(imageDir, `bin/plugins/${pluginName}`);
|
|
3941
3959
|
if (!pluginName)
|
|
3942
3960
|
continue;
|
|
3943
|
-
const symlinkPath =
|
|
3944
|
-
if (
|
|
3961
|
+
const symlinkPath = resolve13(binPluginsDir, pluginName);
|
|
3962
|
+
if (existsSync8(imageBin)) {
|
|
3945
3963
|
try {
|
|
3946
3964
|
unlinkSync(symlinkPath);
|
|
3947
3965
|
} catch {}
|
|
@@ -3949,10 +3967,10 @@ async function executeDist(context, args) {
|
|
|
3949
3967
|
}
|
|
3950
3968
|
}
|
|
3951
3969
|
}
|
|
3952
|
-
if (
|
|
3970
|
+
if (existsSync8(validatorsRoot)) {
|
|
3953
3971
|
const categories = readdirSync(validatorsRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
|
|
3954
3972
|
for (const category of categories) {
|
|
3955
|
-
const categoryDir =
|
|
3973
|
+
const categoryDir = resolve13(validatorsRoot, category.name);
|
|
3956
3974
|
for (const entry of readdirSync(categoryDir, { withFileTypes: true })) {
|
|
3957
3975
|
if (!entry.isFile() || !entry.name.endsWith(".ts"))
|
|
3958
3976
|
continue;
|
|
@@ -3960,9 +3978,9 @@ async function executeDist(context, args) {
|
|
|
3960
3978
|
if (!check || check === "index" || check === "shared")
|
|
3961
3979
|
continue;
|
|
3962
3980
|
const validatorName = `${category.name}-${check}`;
|
|
3963
|
-
const imageBin =
|
|
3964
|
-
const symlinkPath =
|
|
3965
|
-
if (
|
|
3981
|
+
const imageBin = resolve13(imageDir, `bin/validators/${validatorName}`);
|
|
3982
|
+
const symlinkPath = resolve13(binValidatorsDir, validatorName);
|
|
3983
|
+
if (existsSync8(imageBin)) {
|
|
3966
3984
|
try {
|
|
3967
3985
|
unlinkSync(symlinkPath);
|
|
3968
3986
|
} catch {}
|
|
@@ -3971,18 +3989,18 @@ async function executeDist(context, args) {
|
|
|
3971
3989
|
}
|
|
3972
3990
|
}
|
|
3973
3991
|
}
|
|
3974
|
-
const agentsDir =
|
|
3975
|
-
if (
|
|
3992
|
+
const agentsDir = resolve13(resolveControlPlaneMonorepoRuntimeDir(context.projectRoot), "agents");
|
|
3993
|
+
if (existsSync8(agentsDir)) {
|
|
3976
3994
|
let relinkCount = 0;
|
|
3977
3995
|
for (const agentEntry of readdirSync(agentsDir, { withFileTypes: true })) {
|
|
3978
3996
|
if (!agentEntry.isDirectory())
|
|
3979
3997
|
continue;
|
|
3980
|
-
const agentBinDir =
|
|
3981
|
-
if (!
|
|
3998
|
+
const agentBinDir = resolve13(agentsDir, agentEntry.name, "worktree", ".rig", "bin");
|
|
3999
|
+
if (!existsSync8(agentBinDir))
|
|
3982
4000
|
continue;
|
|
3983
4001
|
const walkDir = (dir) => {
|
|
3984
4002
|
for (const entry of readdirSync(dir, { withFileTypes: true })) {
|
|
3985
|
-
const fullPath =
|
|
4003
|
+
const fullPath = resolve13(dir, entry.name);
|
|
3986
4004
|
if (entry.isDirectory()) {
|
|
3987
4005
|
walkDir(fullPath);
|
|
3988
4006
|
} else if (entry.isSymbolicLink()) {
|
|
@@ -4016,7 +4034,7 @@ async function executeDist(context, args) {
|
|
|
4016
4034
|
|
|
4017
4035
|
// packages/cli/src/commands/inbox.ts
|
|
4018
4036
|
import { writeFileSync as writeFileSync4 } from "fs";
|
|
4019
|
-
import { resolve as
|
|
4037
|
+
import { resolve as resolve14 } from "path";
|
|
4020
4038
|
import {
|
|
4021
4039
|
listAuthorityRuns,
|
|
4022
4040
|
readJsonlFile as readJsonlFile3,
|
|
@@ -4033,7 +4051,7 @@ async function executeInbox(context, args) {
|
|
|
4033
4051
|
pending = task.rest;
|
|
4034
4052
|
requireNoExtraArgs(pending, "bun run rig inbox approvals [--run <id>] [--task <id>]");
|
|
4035
4053
|
const runs = listAuthorityRuns(context.projectRoot).filter((entry) => (!run.value || entry.runId === run.value) && (!task.value || entry.taskId === task.value));
|
|
4036
|
-
const approvals = runs.flatMap((entry) => readJsonlFile3(
|
|
4054
|
+
const approvals = runs.flatMap((entry) => readJsonlFile3(resolve14(resolveAuthorityRunDir2(context.projectRoot, entry.runId), "approvals.jsonl")).map((record) => ({
|
|
4037
4055
|
runId: entry.runId,
|
|
4038
4056
|
record
|
|
4039
4057
|
})));
|
|
@@ -4061,7 +4079,7 @@ async function executeInbox(context, args) {
|
|
|
4061
4079
|
if (decision.value !== "approve" && decision.value !== "reject") {
|
|
4062
4080
|
throw new CliError2("decision must be approve or reject.");
|
|
4063
4081
|
}
|
|
4064
|
-
const approvalsPath =
|
|
4082
|
+
const approvalsPath = resolve14(resolveAuthorityRunDir2(context.projectRoot, run.value), "approvals.jsonl");
|
|
4065
4083
|
const approvals = readJsonlFile3(approvalsPath);
|
|
4066
4084
|
const resolvedAt = new Date().toISOString();
|
|
4067
4085
|
const next = approvals.map((entry) => entry.requestId === request.value || entry.id === request.value ? { ...entry, status: "resolved", decision: decision.value, note: note3.value ?? null, resolvedAt } : entry);
|
|
@@ -4078,7 +4096,7 @@ async function executeInbox(context, args) {
|
|
|
4078
4096
|
pending = task.rest;
|
|
4079
4097
|
requireNoExtraArgs(pending, "bun run rig inbox inputs [--run <id>] [--task <id>]");
|
|
4080
4098
|
const runs = listAuthorityRuns(context.projectRoot).filter((entry) => (!run.value || entry.runId === run.value) && (!task.value || entry.taskId === task.value));
|
|
4081
|
-
const requests = runs.flatMap((entry) => readJsonlFile3(
|
|
4099
|
+
const requests = runs.flatMap((entry) => readJsonlFile3(resolve14(resolveAuthorityRunDir2(context.projectRoot, entry.runId), "user-input.jsonl")).map((record) => ({
|
|
4082
4100
|
runId: entry.runId,
|
|
4083
4101
|
record
|
|
4084
4102
|
})));
|
|
@@ -4120,7 +4138,7 @@ async function executeInbox(context, args) {
|
|
|
4120
4138
|
const [key, ...restValue] = entry.split("=");
|
|
4121
4139
|
return [key, restValue.join("=")];
|
|
4122
4140
|
}));
|
|
4123
|
-
const requestsPath =
|
|
4141
|
+
const requestsPath = resolve14(resolveAuthorityRunDir2(context.projectRoot, run.value), "user-input.jsonl");
|
|
4124
4142
|
const requests = readJsonlFile3(requestsPath);
|
|
4125
4143
|
const resolvedAt = new Date().toISOString();
|
|
4126
4144
|
const next = requests.map((entry) => entry.requestId === request.value || entry.id === request.value ? { ...entry, status: "resolved", answers: parsedAnswers, respondedAt: resolvedAt, resolvedAt } : entry);
|
|
@@ -4135,14 +4153,14 @@ async function executeInbox(context, args) {
|
|
|
4135
4153
|
}
|
|
4136
4154
|
|
|
4137
4155
|
// packages/cli/src/commands/init.ts
|
|
4138
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
4156
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync10, mkdirSync as mkdirSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync5 } from "fs";
|
|
4139
4157
|
import { spawnSync as spawnSync2 } from "child_process";
|
|
4140
|
-
import { resolve as
|
|
4158
|
+
import { resolve as resolve17 } from "path";
|
|
4141
4159
|
import { buildRigInitConfigSource } from "@rig/core";
|
|
4142
4160
|
|
|
4143
4161
|
// packages/cli/src/commands/_snapshot-upload.ts
|
|
4144
4162
|
import { mkdir, readdir, readFile, writeFile } from "fs/promises";
|
|
4145
|
-
import { dirname as dirname2, resolve as
|
|
4163
|
+
import { dirname as dirname2, resolve as resolve15, relative, sep } from "path";
|
|
4146
4164
|
var SNAPSHOT_ARCHIVE_VERSION = 1;
|
|
4147
4165
|
var SNAPSHOT_ARCHIVE_CONTENT_TYPE = "application/vnd.rig.snapshot+json";
|
|
4148
4166
|
var DEFAULT_EXCLUDED_DIRECTORIES = new Set([
|
|
@@ -4164,15 +4182,15 @@ function assertManifestPath(root, relativePath) {
|
|
|
4164
4182
|
if (!relativePath || relativePath.startsWith("/") || relativePath.includes("\x00")) {
|
|
4165
4183
|
throw new Error(`Invalid snapshot path: ${relativePath}`);
|
|
4166
4184
|
}
|
|
4167
|
-
const resolved =
|
|
4185
|
+
const resolved = resolve15(root, relativePath);
|
|
4168
4186
|
const relativeToRoot = relative(root, resolved);
|
|
4169
|
-
if (relativeToRoot.startsWith("..") || relativeToRoot === ".." ||
|
|
4187
|
+
if (relativeToRoot.startsWith("..") || relativeToRoot === ".." || resolve15(relativeToRoot) === resolved) {
|
|
4170
4188
|
throw new Error(`Snapshot path escapes project root: ${relativePath}`);
|
|
4171
4189
|
}
|
|
4172
4190
|
return resolved;
|
|
4173
4191
|
}
|
|
4174
4192
|
async function buildSnapshotUploadManifest(projectRoot, options = {}) {
|
|
4175
|
-
const root =
|
|
4193
|
+
const root = resolve15(projectRoot);
|
|
4176
4194
|
const excludedDirectories = [...new Set([
|
|
4177
4195
|
...DEFAULT_EXCLUDED_DIRECTORIES,
|
|
4178
4196
|
...options.excludedDirectories ?? []
|
|
@@ -4184,7 +4202,7 @@ async function buildSnapshotUploadManifest(projectRoot, options = {}) {
|
|
|
4184
4202
|
for (const entry of entries) {
|
|
4185
4203
|
if (entry.isDirectory() && excludedSet.has(entry.name))
|
|
4186
4204
|
continue;
|
|
4187
|
-
const fullPath =
|
|
4205
|
+
const fullPath = resolve15(dir, entry.name);
|
|
4188
4206
|
if (entry.isDirectory()) {
|
|
4189
4207
|
await visit(fullPath);
|
|
4190
4208
|
continue;
|
|
@@ -4232,8 +4250,8 @@ async function uploadSnapshotArchiveViaServer(context, input) {
|
|
|
4232
4250
|
}
|
|
4233
4251
|
|
|
4234
4252
|
// packages/cli/src/commands/_doctor-checks.ts
|
|
4235
|
-
import { existsSync as
|
|
4236
|
-
import { resolve as
|
|
4253
|
+
import { existsSync as existsSync9, readFileSync as readFileSync5 } from "fs";
|
|
4254
|
+
import { resolve as resolve16 } from "path";
|
|
4237
4255
|
import { isSupportedBunVersion, MIN_SUPPORTED_BUN_VERSION } from "@rig/runtime/control-plane/setup-version";
|
|
4238
4256
|
function check(id, label, status, detail, remediation) {
|
|
4239
4257
|
return {
|
|
@@ -4273,11 +4291,11 @@ function repoSlugFromConfig(config) {
|
|
|
4273
4291
|
function loadFallbackConfig(projectRoot) {
|
|
4274
4292
|
const candidates = ["rig.config.ts", "rig.config.mts", "rig.config.json"];
|
|
4275
4293
|
for (const name of candidates) {
|
|
4276
|
-
const path =
|
|
4277
|
-
if (!
|
|
4294
|
+
const path = resolve16(projectRoot, name);
|
|
4295
|
+
if (!existsSync9(path))
|
|
4278
4296
|
continue;
|
|
4279
4297
|
try {
|
|
4280
|
-
const source =
|
|
4298
|
+
const source = readFileSync5(path, "utf8");
|
|
4281
4299
|
if (name.endsWith(".json"))
|
|
4282
4300
|
return JSON.parse(source);
|
|
4283
4301
|
const owner = source.match(/owner\s*:\s*["']([^"']+)["']/)?.[1];
|
|
@@ -4356,7 +4374,7 @@ async function runRigDoctorChecks(options) {
|
|
|
4356
4374
|
checks.push(check("bun", `bun >= ${MIN_SUPPORTED_BUN_VERSION}`, isSupportedBunVersion(bunVersion) ? "pass" : "fail", `found ${bunVersion}`, `Install Bun ${MIN_SUPPORTED_BUN_VERSION} or newer.`), check("git", "git", which("git") ? "pass" : "fail", which("git") ?? undefined, "Install git and ensure it is on PATH."), check("jq", "jq", which("jq") ? "pass" : "warn", which("jq") ?? undefined, "Install jq (for example `brew install jq`)."));
|
|
4357
4375
|
const loadedConfig = await loadConfig(projectRoot).catch(() => null);
|
|
4358
4376
|
const config = loadedConfig ?? loadFallbackConfig(projectRoot);
|
|
4359
|
-
const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) =>
|
|
4377
|
+
const hasConfigFile = ["rig.config.ts", "rig.config.mts", "rig.config.json"].some((name) => existsSync9(resolve16(projectRoot, name)));
|
|
4360
4378
|
checks.push(config ? check("config", "rig.config loadable", "pass") : check("config", "rig.config loadable", hasConfigFile ? "fail" : "fail", hasConfigFile ? "config file exists but failed to load" : "missing rig.config.ts/json", "Run `rig init` or fix the config error."));
|
|
4361
4379
|
const taskSourceKind = config?.taskSource?.kind;
|
|
4362
4380
|
checks.push(taskSourceKind ? check("task-source", "task source configured", "pass", taskSourceKind) : check("task-source", "task source configured", "fail", "missing taskSource", "Configure taskSource in rig.config.ts."));
|
|
@@ -4451,10 +4469,10 @@ function countDoctorFailures(checks) {
|
|
|
4451
4469
|
}
|
|
4452
4470
|
|
|
4453
4471
|
// packages/cli/src/commands/init.ts
|
|
4454
|
-
var
|
|
4472
|
+
var RIG_CONFIG_PACKAGE_DIST_TAG = "latest";
|
|
4455
4473
|
var RIG_CONFIG_DEV_DEPENDENCIES = {
|
|
4456
|
-
"@rig/core": `npm:@h-rig/core@${
|
|
4457
|
-
"@rig/standard-plugin": `npm:@h-rig/standard-plugin@${
|
|
4474
|
+
"@rig/core": `npm:@h-rig/core@${RIG_CONFIG_PACKAGE_DIST_TAG}`,
|
|
4475
|
+
"@rig/standard-plugin": `npm:@h-rig/standard-plugin@${RIG_CONFIG_PACKAGE_DIST_TAG}`
|
|
4458
4476
|
};
|
|
4459
4477
|
function parseRepoSlugFromRemote(remoteUrl) {
|
|
4460
4478
|
const trimmed = remoteUrl.trim();
|
|
@@ -4474,20 +4492,20 @@ function parseRepoSlug(value) {
|
|
|
4474
4492
|
return { owner: match[1], repo: match[2], slug: `${match[1]}/${match[2]}` };
|
|
4475
4493
|
}
|
|
4476
4494
|
function ensureRigPrivateDirs(projectRoot) {
|
|
4477
|
-
const rigDir =
|
|
4478
|
-
mkdirSync7(
|
|
4479
|
-
mkdirSync7(
|
|
4480
|
-
mkdirSync7(
|
|
4481
|
-
mkdirSync7(
|
|
4482
|
-
mkdirSync7(
|
|
4483
|
-
const taskConfigPath =
|
|
4484
|
-
if (!
|
|
4495
|
+
const rigDir = resolve17(projectRoot, ".rig");
|
|
4496
|
+
mkdirSync7(resolve17(rigDir, "state"), { recursive: true });
|
|
4497
|
+
mkdirSync7(resolve17(rigDir, "logs"), { recursive: true });
|
|
4498
|
+
mkdirSync7(resolve17(rigDir, "runs"), { recursive: true });
|
|
4499
|
+
mkdirSync7(resolve17(rigDir, "tmp"), { recursive: true });
|
|
4500
|
+
mkdirSync7(resolve17(projectRoot, "artifacts"), { recursive: true });
|
|
4501
|
+
const taskConfigPath = resolve17(rigDir, "task-config.json");
|
|
4502
|
+
if (!existsSync10(taskConfigPath))
|
|
4485
4503
|
writeFileSync5(taskConfigPath, `{}
|
|
4486
4504
|
`, "utf-8");
|
|
4487
4505
|
}
|
|
4488
4506
|
function ensureGitignoreEntries(projectRoot) {
|
|
4489
|
-
const path =
|
|
4490
|
-
const existing =
|
|
4507
|
+
const path = resolve17(projectRoot, ".gitignore");
|
|
4508
|
+
const existing = existsSync10(path) ? readFileSync6(path, "utf8") : "";
|
|
4491
4509
|
const entries = [".rig/state/", ".rig/logs/", ".rig/runs/", ".rig/tmp/"];
|
|
4492
4510
|
const missing = entries.filter((entry) => !existing.split(/\r?\n/).includes(entry));
|
|
4493
4511
|
if (missing.length === 0)
|
|
@@ -4500,14 +4518,14 @@ function ensureGitignoreEntries(projectRoot) {
|
|
|
4500
4518
|
`, "utf8");
|
|
4501
4519
|
}
|
|
4502
4520
|
function ensureRigConfigPackageDependencies(projectRoot) {
|
|
4503
|
-
const path =
|
|
4504
|
-
const existing =
|
|
4521
|
+
const path = resolve17(projectRoot, "package.json");
|
|
4522
|
+
const existing = existsSync10(path) ? JSON.parse(readFileSync6(path, "utf8")) : {};
|
|
4505
4523
|
const devDependencies = existing.devDependencies && typeof existing.devDependencies === "object" && !Array.isArray(existing.devDependencies) ? { ...existing.devDependencies } : {};
|
|
4506
4524
|
for (const [name, spec] of Object.entries(RIG_CONFIG_DEV_DEPENDENCIES)) {
|
|
4507
4525
|
devDependencies[name] = spec;
|
|
4508
4526
|
}
|
|
4509
4527
|
const next = {
|
|
4510
|
-
...
|
|
4528
|
+
...existsSync10(path) ? existing : { name: "rig-project", private: true },
|
|
4511
4529
|
devDependencies
|
|
4512
4530
|
};
|
|
4513
4531
|
writeFileSync5(path, `${JSON.stringify(next, null, 2)}
|
|
@@ -4577,15 +4595,54 @@ async function promptSelect(prompts, options) {
|
|
|
4577
4595
|
throw new CliError2("Init cancelled.", 1);
|
|
4578
4596
|
return String(value);
|
|
4579
4597
|
}
|
|
4580
|
-
|
|
4598
|
+
function sleep2(ms) {
|
|
4599
|
+
return new Promise((resolve18) => setTimeout(resolve18, ms));
|
|
4600
|
+
}
|
|
4601
|
+
function positiveIntFromEnv(name, fallback) {
|
|
4602
|
+
const value = Number.parseInt(process.env[name] ?? "", 10);
|
|
4603
|
+
return Number.isFinite(value) && value >= 0 ? value : fallback;
|
|
4604
|
+
}
|
|
4605
|
+
function apiSessionTokenFrom(payload) {
|
|
4606
|
+
if (!payload || typeof payload !== "object" || Array.isArray(payload))
|
|
4607
|
+
return null;
|
|
4608
|
+
const token = payload.apiSessionToken;
|
|
4609
|
+
return typeof token === "string" && token.trim() ? token.trim() : null;
|
|
4610
|
+
}
|
|
4611
|
+
function writeRemoteGitHubAuthState(projectRoot, input) {
|
|
4612
|
+
writeFileSync5(resolve17(projectRoot, ".rig", "state", "github-auth.json"), `${JSON.stringify({
|
|
4613
|
+
authenticated: true,
|
|
4614
|
+
source: input.source,
|
|
4615
|
+
storedOnServer: true,
|
|
4616
|
+
selectedRepo: input.selectedRepo,
|
|
4617
|
+
...input.apiSessionToken ? { apiSessionToken: input.apiSessionToken } : {},
|
|
4618
|
+
updatedAt: new Date().toISOString()
|
|
4619
|
+
}, null, 2)}
|
|
4620
|
+
`, "utf8");
|
|
4621
|
+
}
|
|
4622
|
+
async function pollDeviceAuthUntilComplete(context, pollId, firstPayload) {
|
|
4581
4623
|
if (typeof pollId !== "string" || !pollId.trim())
|
|
4582
4624
|
return null;
|
|
4583
|
-
const
|
|
4584
|
-
|
|
4585
|
-
|
|
4586
|
-
|
|
4587
|
-
|
|
4588
|
-
|
|
4625
|
+
const intervalSeconds = typeof firstPayload.interval === "number" && Number.isFinite(firstPayload.interval) && firstPayload.interval > 0 ? firstPayload.interval : 5;
|
|
4626
|
+
const timeoutMs = positiveIntFromEnv("RIG_DEVICE_AUTH_POLL_TIMEOUT_MS", 300000);
|
|
4627
|
+
const intervalMs = positiveIntFromEnv("RIG_DEVICE_AUTH_POLL_INTERVAL_MS", Math.max(1000, intervalSeconds * 1000));
|
|
4628
|
+
const deadline = Date.now() + timeoutMs;
|
|
4629
|
+
let last = null;
|
|
4630
|
+
do {
|
|
4631
|
+
const payload = await requestServerJson(context, "/api/github/auth/device/poll", {
|
|
4632
|
+
method: "POST",
|
|
4633
|
+
headers: { "content-type": "application/json" },
|
|
4634
|
+
body: JSON.stringify({ pollId })
|
|
4635
|
+
}).catch(() => null);
|
|
4636
|
+
last = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : null;
|
|
4637
|
+
const status = typeof last?.status === "string" ? last.status : null;
|
|
4638
|
+
if (status === "signed-in" || status === "expired" || status === "cancelled" || status === "failed") {
|
|
4639
|
+
return last;
|
|
4640
|
+
}
|
|
4641
|
+
if (timeoutMs <= 0)
|
|
4642
|
+
return last;
|
|
4643
|
+
await sleep2(intervalMs);
|
|
4644
|
+
} while (Date.now() < deadline);
|
|
4645
|
+
return last;
|
|
4589
4646
|
}
|
|
4590
4647
|
async function runControlPlaneInit(context, options) {
|
|
4591
4648
|
const projectRoot = context.projectRoot;
|
|
@@ -4608,9 +4665,9 @@ async function runControlPlaneInit(context, options) {
|
|
|
4608
4665
|
});
|
|
4609
4666
|
ensureRigPrivateDirs(projectRoot);
|
|
4610
4667
|
ensureGitignoreEntries(projectRoot);
|
|
4611
|
-
const configTsPath =
|
|
4612
|
-
const configJsonPath =
|
|
4613
|
-
const configExists =
|
|
4668
|
+
const configTsPath = resolve17(projectRoot, "rig.config.ts");
|
|
4669
|
+
const configJsonPath = resolve17(projectRoot, "rig.config.json");
|
|
4670
|
+
const configExists = existsSync10(configTsPath) || existsSync10(configJsonPath);
|
|
4614
4671
|
if (!options.privateStateOnly) {
|
|
4615
4672
|
if (configExists && !options.repair) {
|
|
4616
4673
|
if (context.outputMode !== "json")
|
|
@@ -4626,7 +4683,7 @@ async function runControlPlaneInit(context, options) {
|
|
|
4626
4683
|
}
|
|
4627
4684
|
ensureRigConfigPackageDependencies(projectRoot);
|
|
4628
4685
|
}
|
|
4629
|
-
writeFileSync5(
|
|
4686
|
+
writeFileSync5(resolve17(projectRoot, ".rig", "state", "project-link.json"), `${JSON.stringify({ repoSlug: repo.slug, connection: connectionAlias, linkedAt: new Date().toISOString() }, null, 2)}
|
|
4630
4687
|
`, "utf8");
|
|
4631
4688
|
const checkout = checkoutForInit(projectRoot, serverKind, options.remoteCheckout);
|
|
4632
4689
|
let uploadedSnapshot = null;
|
|
@@ -4648,10 +4705,14 @@ async function runControlPlaneInit(context, options) {
|
|
|
4648
4705
|
const token = authMethod === "gh" && !options.githubToken ? readGhAuthToken() : options.githubToken?.trim();
|
|
4649
4706
|
if (token) {
|
|
4650
4707
|
githubAuth = await postGitHubTokenViaServer(context, token, { selectedRepo: repo.slug });
|
|
4651
|
-
|
|
4708
|
+
const apiSessionToken = apiSessionTokenFrom(githubAuth);
|
|
4709
|
+
setGitHubBearerTokenForCurrentProcess(apiSessionToken ?? token);
|
|
4652
4710
|
if (serverKind === "remote") {
|
|
4653
|
-
|
|
4654
|
-
|
|
4711
|
+
writeRemoteGitHubAuthState(projectRoot, {
|
|
4712
|
+
source: authMethod === "gh" ? "gh" : "init-token",
|
|
4713
|
+
selectedRepo: repo.slug,
|
|
4714
|
+
apiSessionToken
|
|
4715
|
+
});
|
|
4655
4716
|
}
|
|
4656
4717
|
} else if (authMethod === "device") {
|
|
4657
4718
|
const payload = await requestServerJson(context, "/api/github/auth/device/start", {
|
|
@@ -4660,9 +4721,22 @@ async function runControlPlaneInit(context, options) {
|
|
|
4660
4721
|
body: JSON.stringify({ repoSlug: repo.slug })
|
|
4661
4722
|
});
|
|
4662
4723
|
deviceAuth = payload && typeof payload === "object" && !Array.isArray(payload) ? payload : {};
|
|
4663
|
-
|
|
4664
|
-
|
|
4724
|
+
if (context.outputMode !== "json") {
|
|
4725
|
+
const verificationUri = String(deviceAuth.verificationUri ?? deviceAuth.verification_uri ?? deviceAuth.verification_uri_complete ?? "the verification URL returned by the server");
|
|
4726
|
+
const userCode = String(deviceAuth.userCode ?? deviceAuth.user_code ?? "the returned user code");
|
|
4727
|
+
console.log(`GitHub device flow: open ${verificationUri} and enter ${userCode}. Waiting for authorization...`);
|
|
4728
|
+
}
|
|
4729
|
+
const completed = await pollDeviceAuthUntilComplete(context, deviceAuth.pollId, deviceAuth);
|
|
4730
|
+
if (completed) {
|
|
4731
|
+
const apiSessionToken = apiSessionTokenFrom(completed);
|
|
4732
|
+
if (apiSessionToken) {
|
|
4733
|
+
setGitHubBearerTokenForCurrentProcess(apiSessionToken);
|
|
4734
|
+
if (serverKind === "remote") {
|
|
4735
|
+
writeRemoteGitHubAuthState(projectRoot, { source: "device", selectedRepo: repo.slug, apiSessionToken });
|
|
4736
|
+
}
|
|
4737
|
+
}
|
|
4665
4738
|
deviceAuth = { ...deviceAuth, poll: completed, completed: completed.status === "signed-in" };
|
|
4739
|
+
}
|
|
4666
4740
|
}
|
|
4667
4741
|
let remoteCheckoutPreparation = null;
|
|
4668
4742
|
if (serverKind === "remote" && options.remoteCheckout?.kind !== "uploaded-snapshot") {
|
|
@@ -4682,6 +4756,12 @@ async function runControlPlaneInit(context, options) {
|
|
|
4682
4756
|
});
|
|
4683
4757
|
const checkoutPath = typeof checkout.path === "string" ? checkout.path : null;
|
|
4684
4758
|
const serverRootSwitch = serverKind === "remote" && checkoutPath ? await switchServerProjectRootViaServer(context, checkoutPath) : null;
|
|
4759
|
+
if (serverRootSwitch && token) {
|
|
4760
|
+
githubAuth = await postGitHubTokenViaServer(context, token, { selectedRepo: repo.slug, projectRoot: checkoutPath ?? undefined });
|
|
4761
|
+
const apiSessionToken = apiSessionTokenFrom(githubAuth);
|
|
4762
|
+
setGitHubBearerTokenForCurrentProcess(apiSessionToken ?? token);
|
|
4763
|
+
writeRemoteGitHubAuthState(projectRoot, { source: authMethod === "gh" ? "gh" : "init-token", selectedRepo: repo.slug, apiSessionToken });
|
|
4764
|
+
}
|
|
4685
4765
|
const activeProjectRegistration = serverRootSwitch ? await registerProjectViaServer(context, { repoSlug: repo.slug, checkout }) : null;
|
|
4686
4766
|
const pi = serverKind === "remote" ? await ensureRemotePiRigInstalled({ requestJson: (pathname, init) => requestServerJson(context, pathname, init) }).catch((error) => ({
|
|
4687
4767
|
remote: true,
|
|
@@ -4791,7 +4871,7 @@ function parseInitOptions(args) {
|
|
|
4791
4871
|
async function runInteractiveControlPlaneInit(context, prompts) {
|
|
4792
4872
|
prompts.intro?.("Initialize a Rig control-plane project");
|
|
4793
4873
|
const projectRoot = context.projectRoot;
|
|
4794
|
-
const existingConfig =
|
|
4874
|
+
const existingConfig = existsSync10(resolve17(projectRoot, "rig.config.ts")) || existsSync10(resolve17(projectRoot, "rig.config.json"));
|
|
4795
4875
|
let repair = false;
|
|
4796
4876
|
let privateStateOnly = false;
|
|
4797
4877
|
if (existingConfig) {
|
|
@@ -4891,7 +4971,7 @@ async function runInteractiveControlPlaneInit(context, prompts) {
|
|
|
4891
4971
|
});
|
|
4892
4972
|
const details = result.details && typeof result.details === "object" && !Array.isArray(result.details) ? result.details : {};
|
|
4893
4973
|
const deviceAuth = details.deviceAuth && typeof details.deviceAuth === "object" && !Array.isArray(details.deviceAuth) ? details.deviceAuth : null;
|
|
4894
|
-
const deviceMessage = deviceAuth ? ` GitHub device flow: open ${String(deviceAuth.verification_uri ?? deviceAuth.verification_uri_complete ?? "the verification URL returned by the server")} and enter ${String(deviceAuth.user_code ?? "the returned user code")}.` : "";
|
|
4974
|
+
const deviceMessage = deviceAuth ? ` GitHub device flow: open ${String(deviceAuth.verificationUri ?? deviceAuth.verification_uri ?? deviceAuth.verification_uri_complete ?? "the verification URL returned by the server")} and enter ${String(deviceAuth.userCode ?? deviceAuth.user_code ?? "the returned user code")}.` : "";
|
|
4895
4975
|
prompts.outro?.(`Rig project initialized.${deviceMessage} Next: rig doctor && rig task list`);
|
|
4896
4976
|
return result;
|
|
4897
4977
|
}
|
|
@@ -5053,8 +5133,8 @@ async function executeDoctor(context, args) {
|
|
|
5053
5133
|
}
|
|
5054
5134
|
|
|
5055
5135
|
// packages/cli/src/commands/_run-driver-helpers.ts
|
|
5056
|
-
import { readFileSync as
|
|
5057
|
-
import { resolve as
|
|
5136
|
+
import { readFileSync as readFileSync7 } from "fs";
|
|
5137
|
+
import { resolve as resolve18 } from "path";
|
|
5058
5138
|
import {
|
|
5059
5139
|
appendJsonlRecord as appendJsonlRecord2,
|
|
5060
5140
|
readAuthorityRun as readAuthorityRun2,
|
|
@@ -5074,7 +5154,7 @@ function patchAuthorityRun(projectRoot, runId, patch) {
|
|
|
5074
5154
|
...patch,
|
|
5075
5155
|
updatedAt: new Date().toISOString()
|
|
5076
5156
|
};
|
|
5077
|
-
writeJsonFile4(
|
|
5157
|
+
writeJsonFile4(resolve18(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), next);
|
|
5078
5158
|
return next;
|
|
5079
5159
|
}
|
|
5080
5160
|
function touchAuthorityRun(projectRoot, runId) {
|
|
@@ -5082,21 +5162,21 @@ function touchAuthorityRun(projectRoot, runId) {
|
|
|
5082
5162
|
if (!current) {
|
|
5083
5163
|
return;
|
|
5084
5164
|
}
|
|
5085
|
-
writeJsonFile4(
|
|
5165
|
+
writeJsonFile4(resolve18(resolveAuthorityRunDir3(projectRoot, runId), "run.json"), {
|
|
5086
5166
|
...current,
|
|
5087
5167
|
updatedAt: new Date().toISOString()
|
|
5088
5168
|
});
|
|
5089
5169
|
}
|
|
5090
5170
|
function appendRunTimeline(projectRoot, runId, value) {
|
|
5091
|
-
appendJsonlRecord2(
|
|
5171
|
+
appendJsonlRecord2(resolve18(resolveAuthorityRunDir3(projectRoot, runId), "timeline.jsonl"), value);
|
|
5092
5172
|
touchAuthorityRun(projectRoot, runId);
|
|
5093
5173
|
}
|
|
5094
5174
|
function appendRunLog(projectRoot, runId, value) {
|
|
5095
|
-
appendJsonlRecord2(
|
|
5175
|
+
appendJsonlRecord2(resolve18(resolveAuthorityRunDir3(projectRoot, runId), "logs.jsonl"), value);
|
|
5096
5176
|
touchAuthorityRun(projectRoot, runId);
|
|
5097
5177
|
}
|
|
5098
5178
|
function appendRunAction(projectRoot, runId, value) {
|
|
5099
|
-
appendJsonlRecord2(
|
|
5179
|
+
appendJsonlRecord2(resolve18(resolveAuthorityRunDir3(projectRoot, runId), "timeline.jsonl"), {
|
|
5100
5180
|
id: value.id,
|
|
5101
5181
|
type: "action",
|
|
5102
5182
|
actionType: value.actionType,
|
|
@@ -5167,7 +5247,7 @@ function buildRunPrompt(input) {
|
|
|
5167
5247
|
})();
|
|
5168
5248
|
const scopeText = (() => {
|
|
5169
5249
|
try {
|
|
5170
|
-
const parsed = JSON.parse(
|
|
5250
|
+
const parsed = JSON.parse(readFileSync7(resolveControlPlaneTaskConfigPath(input.projectRoot), "utf8"));
|
|
5171
5251
|
const entry = parsed[input.taskId] ?? {};
|
|
5172
5252
|
const scope = Array.isArray(entry.scope) ? entry.scope.filter((item) => typeof item === "string") : [];
|
|
5173
5253
|
const validation = Array.isArray(entry.validation) ? entry.validation.filter((item) => typeof item === "string") : [];
|
|
@@ -5280,8 +5360,8 @@ function renderSourceScopeValidation(task, validation) {
|
|
|
5280
5360
|
}
|
|
5281
5361
|
|
|
5282
5362
|
// packages/cli/src/commands/inspect.ts
|
|
5283
|
-
import { existsSync as
|
|
5284
|
-
import { resolve as
|
|
5363
|
+
import { existsSync as existsSync11, readFileSync as readFileSync8 } from "fs";
|
|
5364
|
+
import { resolve as resolve19 } from "path";
|
|
5285
5365
|
import {
|
|
5286
5366
|
listAuthorityRuns as listAuthorityRuns2,
|
|
5287
5367
|
readAuthorityRun as readAuthorityRun3,
|
|
@@ -5302,8 +5382,8 @@ async function executeInspect(context, args) {
|
|
|
5302
5382
|
if (!latestRun) {
|
|
5303
5383
|
throw new CliError2(`No runs found for ${requiredTask}.`);
|
|
5304
5384
|
}
|
|
5305
|
-
const logsPath =
|
|
5306
|
-
if (!
|
|
5385
|
+
const logsPath = resolve19(resolveAuthorityRunDir4(context.projectRoot, latestRun.runId), "logs.jsonl");
|
|
5386
|
+
if (!existsSync11(logsPath)) {
|
|
5307
5387
|
throw new CliError2(`No logs found for run ${latestRun.runId}.`);
|
|
5308
5388
|
}
|
|
5309
5389
|
await context.runCommand(["cat", logsPath]);
|
|
@@ -5313,7 +5393,7 @@ async function executeInspect(context, args) {
|
|
|
5313
5393
|
const { value: task, rest: remaining } = takeOption(rest, "--task");
|
|
5314
5394
|
requireNoExtraArgs(remaining, "bun run rig inspect artifacts --task <beads-id>");
|
|
5315
5395
|
const requiredTask = requireTask(task, "bun run rig inspect artifacts --task <beads-id>");
|
|
5316
|
-
const artifactRoot = resolveTaskArtifactDirs(context.projectRoot, requiredTask).find((path) =>
|
|
5396
|
+
const artifactRoot = resolveTaskArtifactDirs(context.projectRoot, requiredTask).find((path) => existsSync11(path));
|
|
5317
5397
|
if (!artifactRoot) {
|
|
5318
5398
|
throw new CliError2(`No artifacts found for ${requiredTask}.`);
|
|
5319
5399
|
}
|
|
@@ -5370,10 +5450,10 @@ async function executeInspect(context, args) {
|
|
|
5370
5450
|
case "failures": {
|
|
5371
5451
|
requireNoExtraArgs(rest, "bun run rig inspect failures");
|
|
5372
5452
|
const failed = resolveHarnessPaths2(context.projectRoot).failedApproachesPath;
|
|
5373
|
-
if (!
|
|
5453
|
+
if (!existsSync11(failed)) {
|
|
5374
5454
|
console.log("No failures recorded.");
|
|
5375
5455
|
} else {
|
|
5376
|
-
process.stdout.write(
|
|
5456
|
+
process.stdout.write(readFileSync8(failed, "utf-8"));
|
|
5377
5457
|
}
|
|
5378
5458
|
return { ok: true, group: "inspect", command };
|
|
5379
5459
|
}
|
|
@@ -5390,11 +5470,11 @@ async function executeInspect(context, args) {
|
|
|
5390
5470
|
return { ok: true, group: "inspect", command };
|
|
5391
5471
|
case "audit": {
|
|
5392
5472
|
requireNoExtraArgs(rest, "bun run rig inspect audit");
|
|
5393
|
-
const auditPath =
|
|
5394
|
-
if (!
|
|
5473
|
+
const auditPath = resolve19(resolveHarnessPaths2(context.projectRoot).logsDir, "audit.jsonl");
|
|
5474
|
+
if (!existsSync11(auditPath)) {
|
|
5395
5475
|
console.log("No audit log found.");
|
|
5396
5476
|
} else {
|
|
5397
|
-
const lines =
|
|
5477
|
+
const lines = readFileSync8(auditPath, "utf-8").split(/\r?\n/).filter(Boolean).slice(-20);
|
|
5398
5478
|
for (const line of lines) {
|
|
5399
5479
|
console.log(line);
|
|
5400
5480
|
}
|
|
@@ -6023,8 +6103,8 @@ async function executeRemote(context, args) {
|
|
|
6023
6103
|
}
|
|
6024
6104
|
|
|
6025
6105
|
// packages/cli/src/commands/run.ts
|
|
6026
|
-
import { existsSync as
|
|
6027
|
-
import { resolve as
|
|
6106
|
+
import { existsSync as existsSync12, readFileSync as readFileSync9 } from "fs";
|
|
6107
|
+
import { resolve as resolve20 } from "path";
|
|
6028
6108
|
import { createInterface as createInterface2 } from "readline/promises";
|
|
6029
6109
|
import {
|
|
6030
6110
|
listAuthorityRuns as listAuthorityRuns3,
|
|
@@ -6303,7 +6383,7 @@ async function executeRun(context, args) {
|
|
|
6303
6383
|
if (!run.value) {
|
|
6304
6384
|
throw new CliError2("run timeline requires --run <id>.");
|
|
6305
6385
|
}
|
|
6306
|
-
const timelinePath =
|
|
6386
|
+
const timelinePath = resolve20(resolveAuthorityRunDir5(context.projectRoot, run.value), "timeline.jsonl");
|
|
6307
6387
|
const printEvents = () => {
|
|
6308
6388
|
const events2 = readJsonlFile4(timelinePath);
|
|
6309
6389
|
if (context.outputMode === "text") {
|
|
@@ -6315,12 +6395,12 @@ async function executeRun(context, args) {
|
|
|
6315
6395
|
};
|
|
6316
6396
|
const events = printEvents();
|
|
6317
6397
|
if (follow.value && context.outputMode === "text") {
|
|
6318
|
-
let lastLength =
|
|
6398
|
+
let lastLength = existsSync12(timelinePath) ? readFileSync9(timelinePath, "utf8").length : 0;
|
|
6319
6399
|
while (true) {
|
|
6320
6400
|
await Bun.sleep(1000);
|
|
6321
|
-
if (!
|
|
6401
|
+
if (!existsSync12(timelinePath))
|
|
6322
6402
|
continue;
|
|
6323
|
-
const next =
|
|
6403
|
+
const next = readFileSync9(timelinePath, "utf8");
|
|
6324
6404
|
if (next.length <= lastLength)
|
|
6325
6405
|
continue;
|
|
6326
6406
|
const delta = next.slice(lastLength);
|
|
@@ -6606,10 +6686,10 @@ async function executeServer(context, args, options) {
|
|
|
6606
6686
|
}
|
|
6607
6687
|
|
|
6608
6688
|
// packages/cli/src/commands/task.ts
|
|
6609
|
-
import { readFileSync as
|
|
6689
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
6610
6690
|
import { spawnSync as spawnSync4 } from "child_process";
|
|
6611
6691
|
import { createInterface as createInterface4 } from "readline/promises";
|
|
6612
|
-
import { resolve as
|
|
6692
|
+
import { resolve as resolve21 } from "path";
|
|
6613
6693
|
import {
|
|
6614
6694
|
taskArtifactDir,
|
|
6615
6695
|
taskArtifacts,
|
|
@@ -6940,7 +7020,7 @@ async function executeTask(context, args, options) {
|
|
|
6940
7020
|
const fileFlag = takeOption(rest.slice(1), "--file");
|
|
6941
7021
|
let content;
|
|
6942
7022
|
if (fileFlag.value) {
|
|
6943
|
-
content =
|
|
7023
|
+
content = readFileSync10(resolve21(context.projectRoot, fileFlag.value), "utf-8");
|
|
6944
7024
|
} else {
|
|
6945
7025
|
content = await readStdin();
|
|
6946
7026
|
}
|
|
@@ -7161,8 +7241,8 @@ async function executeTask(context, args, options) {
|
|
|
7161
7241
|
}
|
|
7162
7242
|
|
|
7163
7243
|
// packages/cli/src/commands/task-run-driver.ts
|
|
7164
|
-
import { copyFileSync as copyFileSync3, existsSync as
|
|
7165
|
-
import { resolve as
|
|
7244
|
+
import { copyFileSync as copyFileSync3, existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync11, statSync as statSync2, writeFileSync as writeFileSync6 } from "fs";
|
|
7245
|
+
import { resolve as resolve22 } from "path";
|
|
7166
7246
|
import { spawn as spawn2, spawnSync as spawnSync5 } from "child_process";
|
|
7167
7247
|
import { createInterface as createLineInterface } from "readline";
|
|
7168
7248
|
import { loadConfig as loadConfig2 } from "@rig/core/load-config";
|
|
@@ -7196,7 +7276,24 @@ import {
|
|
|
7196
7276
|
commitRunChanges,
|
|
7197
7277
|
runPrAutomation
|
|
7198
7278
|
} from "@rig/runtime/control-plane/native/pr-automation";
|
|
7279
|
+
function looksLikeGitHubToken(value) {
|
|
7280
|
+
const token = value?.trim();
|
|
7281
|
+
if (!token)
|
|
7282
|
+
return false;
|
|
7283
|
+
return /^(gh[opusr]_|github_pat_)/.test(token);
|
|
7284
|
+
}
|
|
7285
|
+
function githubBridgeEnv(token) {
|
|
7286
|
+
const clean = token?.trim();
|
|
7287
|
+
if (!clean)
|
|
7288
|
+
return {};
|
|
7289
|
+
return {
|
|
7290
|
+
RIG_GITHUB_TOKEN: clean,
|
|
7291
|
+
GITHUB_TOKEN: clean,
|
|
7292
|
+
GH_TOKEN: clean
|
|
7293
|
+
};
|
|
7294
|
+
}
|
|
7199
7295
|
function buildPiRigBridgeEnv(input) {
|
|
7296
|
+
const githubToken = input.githubToken?.trim() || (looksLikeGitHubToken(input.authToken) ? input.authToken.trim() : "");
|
|
7200
7297
|
return {
|
|
7201
7298
|
RIG_PROJECT_ROOT: input.projectRoot,
|
|
7202
7299
|
PROJECT_RIG_ROOT: input.projectRoot,
|
|
@@ -7206,7 +7303,7 @@ function buildPiRigBridgeEnv(input) {
|
|
|
7206
7303
|
RIG_RUNTIME_ADAPTER: "pi",
|
|
7207
7304
|
...input.serverUrl ? { RIG_SERVER_URL: input.serverUrl } : {},
|
|
7208
7305
|
...input.authToken ? { RIG_AUTH_TOKEN: input.authToken } : {},
|
|
7209
|
-
...
|
|
7306
|
+
...githubBridgeEnv(githubToken)
|
|
7210
7307
|
};
|
|
7211
7308
|
}
|
|
7212
7309
|
function runGitSync(cwd, args, input) {
|
|
@@ -7228,12 +7325,12 @@ function copyUntrackedDirtyFiles(sourceRoot, targetRoot) {
|
|
|
7228
7325
|
return 0;
|
|
7229
7326
|
let copied = 0;
|
|
7230
7327
|
for (const relativePath of listed.stdout.split("\x00").filter(Boolean)) {
|
|
7231
|
-
const sourcePath =
|
|
7232
|
-
const targetPath =
|
|
7328
|
+
const sourcePath = resolve22(sourceRoot, relativePath);
|
|
7329
|
+
const targetPath = resolve22(targetRoot, relativePath);
|
|
7233
7330
|
try {
|
|
7234
7331
|
if (!statSync2(sourcePath).isFile())
|
|
7235
7332
|
continue;
|
|
7236
|
-
mkdirSync8(
|
|
7333
|
+
mkdirSync8(resolve22(targetPath, ".."), { recursive: true });
|
|
7237
7334
|
copyFileSync3(sourcePath, targetPath);
|
|
7238
7335
|
copied += 1;
|
|
7239
7336
|
} catch {}
|
|
@@ -7267,6 +7364,14 @@ function buildTaskRunReviewEnv(config) {
|
|
|
7267
7364
|
...review?.provider ? { AI_REVIEW_PROVIDER: review.provider } : {}
|
|
7268
7365
|
};
|
|
7269
7366
|
}
|
|
7367
|
+
function buildDirtyBaselineHandshakeEnv(input) {
|
|
7368
|
+
if (input.baselineMode !== "dirty-snapshot")
|
|
7369
|
+
return { RIG_BASELINE_MODE: input.baselineMode ?? "head" };
|
|
7370
|
+
return {
|
|
7371
|
+
RIG_BASELINE_MODE: "dirty-snapshot",
|
|
7372
|
+
RIG_DIRTY_BASELINE_READY_FILE: resolve22(input.projectRoot, ".rig", "runs", input.runId, "dirty-baseline.ready.json")
|
|
7373
|
+
};
|
|
7374
|
+
}
|
|
7270
7375
|
function positiveInt(value, fallback) {
|
|
7271
7376
|
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
|
|
7272
7377
|
}
|
|
@@ -7375,9 +7480,9 @@ function createCommandRunner(binary) {
|
|
|
7375
7480
|
const stderrChunks = [];
|
|
7376
7481
|
child.stdout.on("data", (chunk) => stdoutChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
|
|
7377
7482
|
child.stderr.on("data", (chunk) => stderrChunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk))));
|
|
7378
|
-
return await new Promise((
|
|
7379
|
-
child.once("error", (error) =>
|
|
7380
|
-
child.once("close", (code) =>
|
|
7483
|
+
return await new Promise((resolve23) => {
|
|
7484
|
+
child.once("error", (error) => resolve23({ exitCode: 1, stderr: error.message }));
|
|
7485
|
+
child.once("close", (code) => resolve23({
|
|
7381
7486
|
exitCode: code ?? 1,
|
|
7382
7487
|
stdout: Buffer.concat(stdoutChunks).toString("utf8"),
|
|
7383
7488
|
stderr: Buffer.concat(stderrChunks).toString("utf8")
|
|
@@ -7573,7 +7678,7 @@ function summarizeValidationFailure(projectRoot, taskId2) {
|
|
|
7573
7678
|
return null;
|
|
7574
7679
|
}
|
|
7575
7680
|
for (const artifactDir of resolveTaskArtifactDirs2(projectRoot, taskId2)) {
|
|
7576
|
-
const summary = readJsonFile3(
|
|
7681
|
+
const summary = readJsonFile3(resolve22(artifactDir, "validation-summary.json"), null);
|
|
7577
7682
|
if (!summary || summary.status !== "fail") {
|
|
7578
7683
|
continue;
|
|
7579
7684
|
}
|
|
@@ -7654,9 +7759,9 @@ function readTaskRunAcceptedArtifactState(input) {
|
|
|
7654
7759
|
if (!input.taskId || !input.workspaceDir) {
|
|
7655
7760
|
return { accepted: false, reason: null };
|
|
7656
7761
|
}
|
|
7657
|
-
const artifactDir =
|
|
7658
|
-
const reviewStatusPath =
|
|
7659
|
-
const taskResultPath =
|
|
7762
|
+
const artifactDir = resolve22(input.workspaceDir, "artifacts", input.taskId);
|
|
7763
|
+
const reviewStatusPath = resolve22(artifactDir, "review-status.txt");
|
|
7764
|
+
const taskResultPath = resolve22(artifactDir, "task-result.json");
|
|
7660
7765
|
const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
|
|
7661
7766
|
if (reviewStatus !== "APPROVED") {
|
|
7662
7767
|
return { accepted: false, reason: null };
|
|
@@ -7693,12 +7798,12 @@ function resolveTaskRunRetryContext(input) {
|
|
|
7693
7798
|
if (!input.taskId || !input.workspaceDir) {
|
|
7694
7799
|
return { shouldRetry: false, failureDetail: null, nextPrompt: null };
|
|
7695
7800
|
}
|
|
7696
|
-
const artifactDir =
|
|
7697
|
-
const reviewStatePath =
|
|
7698
|
-
const reviewFeedbackPath =
|
|
7699
|
-
const reviewStatusPath =
|
|
7700
|
-
const failedApproachesPath =
|
|
7701
|
-
const validationSummaryPath =
|
|
7801
|
+
const artifactDir = resolve22(input.workspaceDir, "artifacts", input.taskId);
|
|
7802
|
+
const reviewStatePath = resolve22(artifactDir, "review-state.json");
|
|
7803
|
+
const reviewFeedbackPath = resolve22(artifactDir, "review-feedback.md");
|
|
7804
|
+
const reviewStatusPath = resolve22(artifactDir, "review-status.txt");
|
|
7805
|
+
const failedApproachesPath = resolve22(input.workspaceDir, ".rig", "state", "failed_approaches.md");
|
|
7806
|
+
const validationSummaryPath = resolve22(artifactDir, "validation-summary.json");
|
|
7702
7807
|
const reviewState = readJsonFile3(reviewStatePath, null);
|
|
7703
7808
|
const reviewStatus = readTaskRunReviewStatus(reviewStatusPath);
|
|
7704
7809
|
const reviewRejected = isTaskRunReviewRejected(reviewState);
|
|
@@ -7753,11 +7858,11 @@ function summarizeTaskRunReviewFailure(reviewState) {
|
|
|
7753
7858
|
return "Completion verification rejected the task. Read review-feedback.md for required fixes.";
|
|
7754
7859
|
}
|
|
7755
7860
|
function readTaskRunReviewStatus(reviewStatusPath) {
|
|
7756
|
-
if (!
|
|
7861
|
+
if (!existsSync13(reviewStatusPath)) {
|
|
7757
7862
|
return null;
|
|
7758
7863
|
}
|
|
7759
7864
|
try {
|
|
7760
|
-
const status =
|
|
7865
|
+
const status = readFileSync11(reviewStatusPath, "utf8").trim().toUpperCase();
|
|
7761
7866
|
return status === "APPROVED" || status === "REJECTED" ? status : null;
|
|
7762
7867
|
} catch {
|
|
7763
7868
|
return null;
|
|
@@ -7841,7 +7946,7 @@ function stringArrayField(record, key) {
|
|
|
7841
7946
|
async function executeRigOwnedTaskRun(context, input) {
|
|
7842
7947
|
const runtimeTaskId = input.taskId?.trim() || `adhoc-${input.runId}`;
|
|
7843
7948
|
const sourceTask = readRunSourceTaskContract(context.projectRoot, input.runId, input.taskId);
|
|
7844
|
-
|
|
7949
|
+
let prompt = buildRunPrompt({
|
|
7845
7950
|
projectRoot: context.projectRoot,
|
|
7846
7951
|
taskId: input.taskId,
|
|
7847
7952
|
fallbackTitle: input.title,
|
|
@@ -7941,7 +8046,22 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
7941
8046
|
const loadedAutomationConfig = await loadTaskRunAutomationConfig(context.projectRoot);
|
|
7942
8047
|
const automationConfig = input.prMode ? { ...loadedAutomationConfig ?? {}, pr: { ...loadedAutomationConfig?.pr ?? {}, mode: input.prMode } } : loadedAutomationConfig;
|
|
7943
8048
|
const planningClassification = classifyPlanningNeed({ config: automationConfig, sourceTask });
|
|
7944
|
-
|
|
8049
|
+
const planningArtifactPath = resolve22("artifacts", runtimeTaskId, "implementation-plan.md");
|
|
8050
|
+
const persistedPlanning = {
|
|
8051
|
+
...planningClassification,
|
|
8052
|
+
classifier: input.runtimeAdapter === "pi" ? "pi-rig-structured-policy" : "rig-structured-policy",
|
|
8053
|
+
artifactPath: planningClassification.planningRequired ? planningArtifactPath : null,
|
|
8054
|
+
classifiedAt: new Date().toISOString()
|
|
8055
|
+
};
|
|
8056
|
+
mkdirSync8(resolve22(context.projectRoot, ".rig", "runs", input.runId), { recursive: true });
|
|
8057
|
+
writeFileSync6(resolve22(context.projectRoot, ".rig", "runs", input.runId, "planning-classification.json"), `${JSON.stringify(persistedPlanning, null, 2)}
|
|
8058
|
+
`, "utf8");
|
|
8059
|
+
patchAuthorityRun(context.projectRoot, input.runId, { planning: persistedPlanning });
|
|
8060
|
+
prompt = `${prompt}
|
|
8061
|
+
|
|
8062
|
+
Rig planning classification:
|
|
8063
|
+
${JSON.stringify(persistedPlanning, null, 2)}
|
|
8064
|
+
${planningClassification.planningRequired ? `Before implementing, write a concise implementation plan to ${planningArtifactPath}. Treat that plan artifact as required acceptance evidence for the Plan stage.` : "Planning is not required for this run; briefly state why before implementation."}`;
|
|
7945
8065
|
if (input.runtimeAdapter === "pi") {
|
|
7946
8066
|
for (const stage of ["Connect", "GitHub/task sync", "Prepare workspace", "Launch Pi", "Plan", "Implement"]) {
|
|
7947
8067
|
appendPiStageLog({
|
|
@@ -8008,6 +8128,7 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
8008
8128
|
...sourceTask ? { RIG_SOURCE_TASK_JSON: JSON.stringify(sourceTask) } : {}
|
|
8009
8129
|
};
|
|
8010
8130
|
Object.assign(childEnv, buildTaskRunReviewEnv(automationConfig));
|
|
8131
|
+
Object.assign(childEnv, buildDirtyBaselineHandshakeEnv({ projectRoot: context.projectRoot, runId: input.runId, baselineMode: input.baselineMode }));
|
|
8011
8132
|
const automationLimits = resolveTaskRunAutomationLimits(automationConfig);
|
|
8012
8133
|
const maxAttempts = automationLimits.maxValidationAttempts;
|
|
8013
8134
|
const promoteToValidating = (detail) => {
|
|
@@ -8062,22 +8183,29 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
8062
8183
|
patchAuthorityRun(context.projectRoot, input.runId, {
|
|
8063
8184
|
status: "running",
|
|
8064
8185
|
worktreePath: latestRuntimeWorkspace,
|
|
8065
|
-
artifactRoot: latestRuntimeWorkspace && input.taskId ?
|
|
8186
|
+
artifactRoot: latestRuntimeWorkspace && input.taskId ? resolve22(latestRuntimeWorkspace, "artifacts", input.taskId) : null,
|
|
8066
8187
|
logRoot: latestLogsDir,
|
|
8067
|
-
sessionPath: latestSessionDir ?
|
|
8068
|
-
sessionLogPath: latestLogsDir ?
|
|
8188
|
+
sessionPath: latestSessionDir ? resolve22(latestSessionDir, "session.json") : null,
|
|
8189
|
+
sessionLogPath: latestLogsDir ? resolve22(latestLogsDir, "agent-stdout.log") : null,
|
|
8069
8190
|
branch: runtimeId
|
|
8070
8191
|
});
|
|
8071
8192
|
if (!dirtyBaselineApplied && input.baselineMode === "dirty-snapshot" && latestRuntimeWorkspace) {
|
|
8072
8193
|
dirtyBaselineApplied = true;
|
|
8073
8194
|
const dirty = applyDirtyBaselineSnapshot({ sourceRoot: context.projectRoot, targetRoot: latestRuntimeWorkspace });
|
|
8195
|
+
const readyFile = childEnv.RIG_DIRTY_BASELINE_READY_FILE;
|
|
8196
|
+
if (readyFile) {
|
|
8197
|
+
mkdirSync8(resolve22(readyFile, ".."), { recursive: true });
|
|
8198
|
+
writeFileSync6(readyFile, `${JSON.stringify({ ...dirty, workspaceDir: latestRuntimeWorkspace, appliedAt: new Date().toISOString() }, null, 2)}
|
|
8199
|
+
`, "utf8");
|
|
8200
|
+
}
|
|
8074
8201
|
appendRunLog(context.projectRoot, input.runId, {
|
|
8075
8202
|
id: `log:${input.runId}:dirty-baseline`,
|
|
8076
8203
|
title: "Dirty baseline snapshot",
|
|
8077
8204
|
detail: dirty.detail,
|
|
8078
8205
|
tone: dirty.applied ? "tool" : "info",
|
|
8079
8206
|
status: dirty.applied ? "completed" : "skipped",
|
|
8080
|
-
createdAt: new Date().toISOString()
|
|
8207
|
+
createdAt: new Date().toISOString(),
|
|
8208
|
+
payload: readyFile ? { readyFile } : undefined
|
|
8081
8209
|
});
|
|
8082
8210
|
emitServerRunEvent({ type: "log", runId: input.runId, title: "Dirty baseline snapshot" });
|
|
8083
8211
|
}
|
|
@@ -8344,7 +8472,7 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
8344
8472
|
let acceptedArtifactObservedAt = null;
|
|
8345
8473
|
let acceptedArtifactPollTimer = null;
|
|
8346
8474
|
let acceptedArtifactKillTimer = null;
|
|
8347
|
-
const attemptExit = await new Promise((
|
|
8475
|
+
const attemptExit = await new Promise((resolve23) => {
|
|
8348
8476
|
let settled = false;
|
|
8349
8477
|
const settle = (result) => {
|
|
8350
8478
|
if (settled)
|
|
@@ -8352,7 +8480,7 @@ async function executeRigOwnedTaskRun(context, input) {
|
|
|
8352
8480
|
settled = true;
|
|
8353
8481
|
if (acceptedArtifactPollTimer)
|
|
8354
8482
|
clearInterval(acceptedArtifactPollTimer);
|
|
8355
|
-
|
|
8483
|
+
resolve23(result);
|
|
8356
8484
|
};
|
|
8357
8485
|
const pollAcceptedArtifacts = () => {
|
|
8358
8486
|
const artifactState = readTaskRunAcceptedArtifactState({
|
|
@@ -8549,6 +8677,29 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
8549
8677
|
});
|
|
8550
8678
|
throw new CliError2(terminalFailureDetail, exit.code ?? 1);
|
|
8551
8679
|
}
|
|
8680
|
+
if (planningClassification.planningRequired) {
|
|
8681
|
+
const planWorkspace = latestRuntimeWorkspace ?? context.projectRoot;
|
|
8682
|
+
const expectedPlanPath = resolve22(planWorkspace, planningArtifactPath);
|
|
8683
|
+
if (!existsSync13(expectedPlanPath)) {
|
|
8684
|
+
const failedAt = new Date().toISOString();
|
|
8685
|
+
const failureDetail = `Planning was required (${planningClassification.reason}) but ${planningArtifactPath} was not written before implementation completed.`;
|
|
8686
|
+
patchAuthorityRun(context.projectRoot, input.runId, {
|
|
8687
|
+
status: "needs_attention",
|
|
8688
|
+
completedAt: failedAt,
|
|
8689
|
+
errorText: failureDetail
|
|
8690
|
+
});
|
|
8691
|
+
appendRunLog(context.projectRoot, input.runId, {
|
|
8692
|
+
id: `log:${input.runId}:plan-artifact-missing`,
|
|
8693
|
+
title: "Required plan artifact missing",
|
|
8694
|
+
detail: failureDetail,
|
|
8695
|
+
tone: "error",
|
|
8696
|
+
status: "needs_attention",
|
|
8697
|
+
createdAt: failedAt
|
|
8698
|
+
});
|
|
8699
|
+
emitServerRunEvent({ type: "failed", runId: input.runId, error: failureDetail });
|
|
8700
|
+
throw new CliError2(failureDetail, 1);
|
|
8701
|
+
}
|
|
8702
|
+
}
|
|
8552
8703
|
const runPiPrFeedbackFix = async (message2) => {
|
|
8553
8704
|
appendPiStageLog({
|
|
8554
8705
|
projectRoot: context.projectRoot,
|
|
@@ -8606,9 +8757,9 @@ Failed to update task source for ${input.taskId ?? runtimeTaskId} to failed: ${e
|
|
|
8606
8757
|
});
|
|
8607
8758
|
emitServerRunEvent({ type: "log", runId: input.runId, title: "Pi PR feedback fix stderr" });
|
|
8608
8759
|
});
|
|
8609
|
-
const exitCode = await new Promise((
|
|
8610
|
-
child.once("error", () =>
|
|
8611
|
-
child.once("close", (code) =>
|
|
8760
|
+
const exitCode = await new Promise((resolve23) => {
|
|
8761
|
+
child.once("error", () => resolve23(1));
|
|
8762
|
+
child.once("close", (code) => resolve23(code ?? 1));
|
|
8612
8763
|
});
|
|
8613
8764
|
if (exitCode !== 0) {
|
|
8614
8765
|
throw new Error(`Pi PR feedback fix failed with exit code ${exitCode}.`);
|
|
@@ -8727,8 +8878,8 @@ async function executeTest(context, args) {
|
|
|
8727
8878
|
}
|
|
8728
8879
|
|
|
8729
8880
|
// packages/cli/src/commands/setup.ts
|
|
8730
|
-
import { existsSync as
|
|
8731
|
-
import { resolve as
|
|
8881
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync9, readdirSync as readdirSync2, writeFileSync as writeFileSync7 } from "fs";
|
|
8882
|
+
import { resolve as resolve23 } from "path";
|
|
8732
8883
|
import { createPluginHost } from "@rig/core";
|
|
8733
8884
|
import {
|
|
8734
8885
|
isSupportedBunVersion as isSupportedBunVersion2,
|
|
@@ -8791,9 +8942,9 @@ function runSetupInit(projectRoot) {
|
|
|
8791
8942
|
mkdirSync9(stateDir, { recursive: true });
|
|
8792
8943
|
mkdirSync9(logsDir, { recursive: true });
|
|
8793
8944
|
mkdirSync9(artifactsDir, { recursive: true });
|
|
8794
|
-
const failuresPath =
|
|
8795
|
-
if (!
|
|
8796
|
-
|
|
8945
|
+
const failuresPath = resolve23(stateDir, "failed_approaches.md");
|
|
8946
|
+
if (!existsSync14(failuresPath)) {
|
|
8947
|
+
writeFileSync7(failuresPath, `# Failed Approaches
|
|
8797
8948
|
|
|
8798
8949
|
`, "utf-8");
|
|
8799
8950
|
}
|
|
@@ -8810,18 +8961,18 @@ async function runSetupCheck(projectRoot) {
|
|
|
8810
8961
|
}
|
|
8811
8962
|
async function runSetupPreflight(projectRoot) {
|
|
8812
8963
|
await runSetupCheck(projectRoot);
|
|
8813
|
-
const validationRoot =
|
|
8814
|
-
if (
|
|
8964
|
+
const validationRoot = resolve23(resolveControlPlaneDefinitionRoot(projectRoot), "validation");
|
|
8965
|
+
if (existsSync14(validationRoot)) {
|
|
8815
8966
|
const validators = readdirSync2(validationRoot, { withFileTypes: true }).filter((entry) => entry.isDirectory());
|
|
8816
8967
|
for (const validator of validators) {
|
|
8817
|
-
const script =
|
|
8818
|
-
if (
|
|
8968
|
+
const script = resolve23(validationRoot, validator.name, "validate.sh");
|
|
8969
|
+
if (existsSync14(script)) {
|
|
8819
8970
|
console.log(`OK: validator script ${script}`);
|
|
8820
8971
|
}
|
|
8821
8972
|
}
|
|
8822
8973
|
}
|
|
8823
|
-
const hooksRoot =
|
|
8824
|
-
if (
|
|
8974
|
+
const hooksRoot = resolve23(resolveControlPlaneDefinitionRoot(projectRoot), "hooks");
|
|
8975
|
+
if (existsSync14(hooksRoot)) {
|
|
8825
8976
|
const hooks = readdirSync2(hooksRoot).filter((name) => name.endsWith(".sh"));
|
|
8826
8977
|
for (const hook of hooks) {
|
|
8827
8978
|
console.log(`OK: hook ${hook}`);
|
|
@@ -9198,8 +9349,8 @@ async function executeGroup(context, group, args) {
|
|
|
9198
9349
|
}
|
|
9199
9350
|
}
|
|
9200
9351
|
// packages/cli/src/launcher.ts
|
|
9201
|
-
import { existsSync as
|
|
9202
|
-
import { resolve as
|
|
9352
|
+
import { existsSync as existsSync15 } from "fs";
|
|
9353
|
+
import { resolve as resolve24 } from "path";
|
|
9203
9354
|
import { loadDotEnvSecrets } from "@rig/runtime/baked-secrets";
|
|
9204
9355
|
import { RIG_DEFINITION_DIRNAME, RIG_STATE_DIRNAME, resolveNearestRigProjectRoot } from "@rig/runtime/layout";
|
|
9205
9356
|
function parsePolicyMode(value) {
|
|
@@ -9212,7 +9363,7 @@ function parsePolicyMode(value) {
|
|
|
9212
9363
|
throw new Error(`Invalid --policy-mode value: ${value}. Use off|observe|enforce.`);
|
|
9213
9364
|
}
|
|
9214
9365
|
function hasRigProjectMarker(candidate) {
|
|
9215
|
-
return
|
|
9366
|
+
return existsSync15(resolve24(candidate, RIG_DEFINITION_DIRNAME)) || existsSync15(resolve24(candidate, RIG_STATE_DIRNAME)) || existsSync15(resolve24(candidate, "rig.config.ts")) || existsSync15(resolve24(candidate, "rig.config.json"));
|
|
9216
9367
|
}
|
|
9217
9368
|
function resolveProjectRoot({
|
|
9218
9369
|
envProjectRoot,
|
|
@@ -9221,17 +9372,17 @@ function resolveProjectRoot({
|
|
|
9221
9372
|
cwd = process.cwd()
|
|
9222
9373
|
}) {
|
|
9223
9374
|
if (envProjectRoot) {
|
|
9224
|
-
return
|
|
9375
|
+
return resolve24(cwd, envProjectRoot);
|
|
9225
9376
|
}
|
|
9226
9377
|
const fallbackImportDir = importDir ?? cwd;
|
|
9227
|
-
const candidates = [cwd,
|
|
9378
|
+
const candidates = [cwd, resolve24(execPath, "..", ".."), resolve24(fallbackImportDir, "..")];
|
|
9228
9379
|
for (const candidate of candidates) {
|
|
9229
9380
|
const nearest = resolveNearestRigProjectRoot(candidate);
|
|
9230
9381
|
if (hasRigProjectMarker(nearest)) {
|
|
9231
9382
|
return nearest;
|
|
9232
9383
|
}
|
|
9233
9384
|
}
|
|
9234
|
-
return
|
|
9385
|
+
return resolve24(cwd);
|
|
9235
9386
|
}
|
|
9236
9387
|
function normalizeCliErrorCode(message2, isCliError) {
|
|
9237
9388
|
if (message2.startsWith("Invalid --policy-mode value:")) {
|
|
@@ -9298,7 +9449,7 @@ async function runRigCli(module, options = {}) {
|
|
|
9298
9449
|
runId: context.runId,
|
|
9299
9450
|
outcome,
|
|
9300
9451
|
eventsFile: context.eventBus.getEventsFile(),
|
|
9301
|
-
policyFile:
|
|
9452
|
+
policyFile: resolve24(projectRoot, "rig", "policy", "policy.json"),
|
|
9302
9453
|
policyMode: context.policyMode ?? policyMode ?? module.loadPolicy(projectRoot).mode
|
|
9303
9454
|
}, null, 2));
|
|
9304
9455
|
}
|